4 * Copyright (C) International Business Machines Corp., 2002,2005
5 * Author(s): Steve French (sfrench@us.ibm.com)
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <linux/net.h>
23 #include <linux/string.h>
24 #include <linux/list.h>
25 #include <linux/wait.h>
26 #include <linux/ipv6.h>
27 #include <linux/pagemap.h>
28 #include <linux/ctype.h>
29 #include <linux/utsname.h>
30 #include <linux/mempool.h>
31 #include <linux/delay.h>
32 #include <asm/uaccess.h>
33 #include <asm/processor.h>
36 #include "cifsproto.h"
37 #include "cifs_unicode.h"
38 #include "cifs_debug.h"
39 #include "cifs_fs_sb.h"
42 #include "rfc1002pdu.h"
45 #define RFC1001_PORT 139
47 extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
49 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
52 extern mempool_t *cifs_req_poolp;
60 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
61 char *iocharset; /* local code page for mapping to and from Unicode */
62 char source_rfc1001_name[16]; /* netbios name of client */
72 unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
73 unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
74 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
76 unsigned remap:1; /* set to remap seven reserved chars in filenames */
80 unsigned short int port;
83 static int ipv4_connect(struct sockaddr_in *psin_server,
84 struct socket **csocket,
86 static int ipv6_connect(struct sockaddr_in6 *psin_server,
87 struct socket **csocket);
91 * cifs tcp session reconnection
93 * mark tcp session as reconnecting so temporarily locked
94 * mark all smb sessions as reconnecting for tcp session
95 * reconnect tcp session
96 * wake up waiters on reconnection? - (not needed currently)
100 cifs_reconnect(struct TCP_Server_Info *server)
103 struct list_head *tmp;
104 struct cifsSesInfo *ses;
105 struct cifsTconInfo *tcon;
106 struct mid_q_entry * mid_entry;
108 spin_lock(&GlobalMid_Lock);
109 if(server->tcpStatus == CifsExiting) {
110 /* the demux thread will exit normally
111 next time through the loop */
112 spin_unlock(&GlobalMid_Lock);
115 server->tcpStatus = CifsNeedReconnect;
116 spin_unlock(&GlobalMid_Lock);
119 cFYI(1, ("Reconnecting tcp session "));
121 /* before reconnecting the tcp session, mark the smb session (uid)
122 and the tid bad so they are not used until reconnected */
123 read_lock(&GlobalSMBSeslock);
124 list_for_each(tmp, &GlobalSMBSessionList) {
125 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
127 if (ses->server == server) {
128 ses->status = CifsNeedReconnect;
132 /* else tcp and smb sessions need reconnection */
134 list_for_each(tmp, &GlobalTreeConnectionList) {
135 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
136 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
137 tcon->tidStatus = CifsNeedReconnect;
140 read_unlock(&GlobalSMBSeslock);
141 /* do not want to be sending data on a socket we are freeing */
142 down(&server->tcpSem);
143 if(server->ssocket) {
144 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
145 server->ssocket->flags));
146 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
147 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
148 server->ssocket->flags));
149 sock_release(server->ssocket);
150 server->ssocket = NULL;
153 spin_lock(&GlobalMid_Lock);
154 list_for_each(tmp, &server->pending_mid_q) {
155 mid_entry = list_entry(tmp, struct
159 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
160 /* Mark other intransit requests as needing
161 retry so we do not immediately mark the
162 session bad again (ie after we reconnect
163 below) as they timeout too */
164 mid_entry->midState = MID_RETRY_NEEDED;
168 spin_unlock(&GlobalMid_Lock);
171 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
173 if(server->protocolType == IPV6) {
174 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
176 rc = ipv4_connect(&server->addr.sockAddr,
178 server->workstation_RFC1001_name);
181 set_current_state(TASK_INTERRUPTIBLE);
182 schedule_timeout(3 * HZ);
184 atomic_inc(&tcpSesReconnectCount);
185 spin_lock(&GlobalMid_Lock);
186 if(server->tcpStatus != CifsExiting)
187 server->tcpStatus = CifsGood;
188 server->sequence_number = 0;
189 spin_unlock(&GlobalMid_Lock);
190 /* atomic_set(&server->inFlight,0);*/
191 wake_up(&server->response_q);
198 cifs_demultiplex_thread(struct TCP_Server_Info *server)
201 unsigned int pdu_length, total_read;
202 struct smb_hdr *smb_buffer = NULL;
203 struct smb_hdr *bigbuf = NULL;
204 struct smb_hdr *smallbuf = NULL;
205 struct msghdr smb_msg;
207 struct socket *csocket = server->ssocket;
208 struct list_head *tmp;
209 struct cifsSesInfo *ses;
210 struct task_struct *task_to_wake = NULL;
211 struct mid_q_entry *mid_entry;
213 int isLargeBuf = FALSE;
216 allow_signal(SIGKILL);
217 current->flags |= PF_MEMALLOC;
218 server->tsk = current; /* save process info to wake at shutdown */
219 cFYI(1, ("Demultiplex PID: %d", current->pid));
220 write_lock(&GlobalSMBSeslock);
221 atomic_inc(&tcpSesAllocCount);
222 length = tcpSesAllocCount.counter;
223 write_unlock(&GlobalSMBSeslock);
225 mempool_resize(cifs_req_poolp,
226 length + cifs_min_rcv,
230 while (server->tcpStatus != CifsExiting) {
231 if (bigbuf == NULL) {
232 bigbuf = cifs_buf_get();
234 cERROR(1,("No memory for large SMB response"));
236 /* retry will check if exiting */
239 } else if(isLargeBuf) {
240 /* we are reusing a dirtry large buf, clear its start */
241 memset(bigbuf, 0, sizeof (struct smb_hdr));
244 if (smallbuf == NULL) {
245 smallbuf = cifs_small_buf_get();
246 if(smallbuf == NULL) {
247 cERROR(1,("No memory for SMB response"));
249 /* retry will check if exiting */
252 /* beginning of smb buffer is cleared in our buf_get */
253 } else /* if existing small buf clear beginning */
254 memset(smallbuf, 0, sizeof (struct smb_hdr));
257 smb_buffer = smallbuf;
258 iov.iov_base = smb_buffer;
260 smb_msg.msg_control = NULL;
261 smb_msg.msg_controllen = 0;
263 kernel_recvmsg(csocket, &smb_msg,
264 &iov, 1, 4, 0 /* BB see socket.h flags */);
266 if(server->tcpStatus == CifsExiting) {
268 } else if (server->tcpStatus == CifsNeedReconnect) {
269 cFYI(1,("Reconnecting after server stopped responding"));
270 cifs_reconnect(server);
271 cFYI(1,("call to reconnect done"));
272 csocket = server->ssocket;
274 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
275 msleep(1); /* minimum sleep to prevent looping
276 allowing socket to clear and app threads to set
277 tcpStatus CifsNeedReconnect if server hung */
279 } else if (length <= 0) {
280 if(server->tcpStatus == CifsNew) {
281 cFYI(1,("tcp session abended prematurely (after SMBnegprot)"));
282 /* some servers kill the TCP session rather than
283 returning an SMB negprot error, in which
284 case reconnecting here is not going to help,
285 and so simply return error to mount */
288 if(length == -EINTR) {
289 cFYI(1,("cifsd thread killed"));
292 cFYI(1,("Reconnecting after unexpected peek error %d",length));
293 cifs_reconnect(server);
294 csocket = server->ssocket;
295 wake_up(&server->response_q);
297 } else if (length > 3) {
298 pdu_length = ntohl(smb_buffer->smb_buf_length);
299 /* Only read pdu_length after below checks for too short (due
300 to e.g. int overflow) and too long ie beyond end of buf */
301 cFYI(1,("rfc1002 length(big endian)0x%x)",
304 temp = (char *) smb_buffer;
305 if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
306 cFYI(0,("Received 4 byte keep alive packet"));
307 } else if (temp[0] ==
308 (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
309 cFYI(1,("Good RFC 1002 session rsp"));
310 } else if (temp[0] ==
311 (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
312 /* we get this from Windows 98 instead of
313 an error on SMB negprot response */
314 cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
315 if(server->tcpStatus == CifsNew) {
316 /* if nack on negprot (rather than
317 ret of smb negprot error) reconnecting
318 not going to help, ret error to mount */
321 /* give server a second to
322 clean up before reconnect attempt */
324 /* always try 445 first on reconnect
325 since we get NACK on some if we ever
326 connected to port 139 (the NACK is
327 since we do not begin with RFC1001
328 session initialize frame) */
329 server->addr.sockAddr.sin_port =
331 cifs_reconnect(server);
332 csocket = server->ssocket;
333 wake_up(&server->response_q);
336 } else if (temp[0] != (char) 0) {
337 cERROR(1,("Unknown RFC 1002 frame"));
338 cifs_dump_mem(" Received Data: ", temp, length);
339 cifs_reconnect(server);
340 csocket = server->ssocket;
343 if((pdu_length > CIFSMaxBufSize +
344 MAX_CIFS_HDR_SIZE - 4) ||
345 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
347 ("Invalid size SMB length %d and pdu_length %d",
348 length, pdu_length+4));
349 cifs_reconnect(server);
350 csocket = server->ssocket;
351 wake_up(&server->response_q);
353 } else { /* length ok */
354 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
356 memcpy(bigbuf, smallbuf, 4);
360 iov.iov_base = 4 + (char *)smb_buffer;
361 iov.iov_len = pdu_length;
363 total_read < pdu_length;
364 total_read += length) {
365 length = kernel_recvmsg(csocket, &smb_msg,
367 pdu_length - total_read, 0);
370 ("Zero length receive when expecting %d ",
371 pdu_length - total_read));
372 cifs_reconnect(server);
373 csocket = server->ssocket;
374 wake_up(&server->response_q);
378 length += 4; /* account for rfc1002 hdr */
381 dump_smb(smb_buffer, length);
383 (smb_buffer, smb_buffer->Mid, total_read+4)) {
384 cERROR(1, ("Bad SMB Received "));
388 /* BB FIXME - add checkTrans2SMBSecondary() */
391 spin_lock(&GlobalMid_Lock);
392 list_for_each(tmp, &server->pending_mid_q) {
393 mid_entry = list_entry(tmp, struct
397 if ((mid_entry->mid == smb_buffer->Mid)
398 && (mid_entry->midState ==
399 MID_REQUEST_SUBMITTED)
400 && (mid_entry->command ==
401 smb_buffer->Command)) {
402 cFYI(1,("Found Mid 0x%x wake up"
404 task_to_wake = mid_entry->tsk;
405 mid_entry->resp_buf =
407 mid_entry->midState =
408 MID_RESPONSE_RECEIVED;
410 mid_entry->largeBuf = 1;
412 mid_entry->largeBuf = 0;
415 spin_unlock(&GlobalMid_Lock);
421 smb_buffer = NULL; /* will be freed by users thread after he is done */
422 wake_up_process(task_to_wake);
423 } else if (is_valid_oplock_break(smb_buffer) == FALSE) {
424 cERROR(1, ("No task to wake, unknown frame rcvd!"));
425 cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
430 ("Frame less than four bytes received %d bytes long.",
432 cifs_reconnect(server);
433 csocket = server->ssocket;
434 wake_up(&server->response_q);
438 spin_lock(&GlobalMid_Lock);
439 server->tcpStatus = CifsExiting;
441 atomic_set(&server->inFlight, 0);
442 spin_unlock(&GlobalMid_Lock);
443 /* Although there should not be any requests blocked on
444 this queue it can not hurt to be paranoid and try to wake up requests
445 that may haven been blocked when more than 50 at time were on the wire
446 to the same server - they now will see the session is in exit state
447 and get out of SendReceive. */
448 wake_up_all(&server->request_q);
449 /* give those requests time to exit */
452 if(server->ssocket) {
453 sock_release(csocket);
454 server->ssocket = NULL;
456 /* buffer usuallly freed in free_mid - need to free it here on exit */
458 cifs_buf_release(bigbuf);
459 if (smallbuf != NULL)
460 cifs_small_buf_release(smallbuf);
462 read_lock(&GlobalSMBSeslock);
463 if (list_empty(&server->pending_mid_q)) {
464 /* loop through server session structures attached to this and
466 list_for_each(tmp, &GlobalSMBSessionList) {
468 list_entry(tmp, struct cifsSesInfo,
470 if (ses->server == server) {
471 ses->status = CifsExiting;
475 read_unlock(&GlobalSMBSeslock);
477 spin_lock(&GlobalMid_Lock);
478 list_for_each(tmp, &server->pending_mid_q) {
479 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
480 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
482 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
483 task_to_wake = mid_entry->tsk;
485 wake_up_process(task_to_wake);
489 spin_unlock(&GlobalMid_Lock);
490 read_unlock(&GlobalSMBSeslock);
491 /* 1/8th of sec is more than enough time for them to exit */
495 if (list_empty(&server->pending_mid_q)) {
496 /* mpx threads have not exited yet give them
497 at least the smb send timeout time for long ops */
498 cFYI(1, ("Wait for exit from demultiplex thread"));
500 /* if threads still have not exited they are probably never
501 coming home not much else we can do but free the memory */
505 write_lock(&GlobalSMBSeslock);
506 atomic_dec(&tcpSesAllocCount);
507 length = tcpSesAllocCount.counter;
508 write_unlock(&GlobalSMBSeslock);
510 mempool_resize(cifs_req_poolp,
511 length + cifs_min_rcv,
520 cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
524 unsigned int temp_len, i, j;
530 memset(vol->source_rfc1001_name,0x20,15);
531 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
532 /* does not have to be a perfect mapping since the field is
533 informational, only used for servers that do not support
534 port 445 and it can be overridden at mount time */
535 vol->source_rfc1001_name[i] =
536 toupper(system_utsname.nodename[i]);
538 vol->source_rfc1001_name[15] = 0;
540 vol->linux_uid = current->uid; /* current->euid instead? */
541 vol->linux_gid = current->gid;
542 vol->dir_mode = S_IRWXUGO;
543 /* 2767 perms indicate mandatory locking support */
544 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
546 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
552 if(strncmp(options,"sep=",4) == 0) {
553 if(options[4] != 0) {
554 separator[0] = options[4];
557 cFYI(1,("Null separator not allowed"));
561 while ((data = strsep(&options, separator)) != NULL) {
564 if ((value = strchr(data, '=')) != NULL)
567 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
569 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
571 } else if (strnicmp(data, "user", 4) == 0) {
572 if (!value || !*value) {
574 "CIFS: invalid or missing username\n");
575 return 1; /* needs_arg; */
577 if (strnlen(value, 200) < 200) {
578 vol->username = value;
580 printk(KERN_WARNING "CIFS: username too long\n");
583 } else if (strnicmp(data, "pass", 4) == 0) {
585 vol->password = NULL;
587 } else if(value[0] == 0) {
588 /* check if string begins with double comma
589 since that would mean the password really
590 does start with a comma, and would not
591 indicate an empty string */
592 if(value[1] != separator[0]) {
593 vol->password = NULL;
597 temp_len = strlen(value);
598 /* removed password length check, NTLM passwords
599 can be arbitrarily long */
601 /* if comma in password, the string will be
602 prematurely null terminated. Commas in password are
603 specified across the cifs mount interface by a double
604 comma ie ,, and a comma used as in other cases ie ','
605 as a parameter delimiter/separator is single and due
606 to the strsep above is temporarily zeroed. */
608 /* NB: password legally can have multiple commas and
609 the only illegal character in a password is null */
611 if ((value[temp_len] == 0) &&
612 (value[temp_len+1] == separator[0])) {
614 value[temp_len] = separator[0];
615 temp_len+=2; /* move after the second comma */
616 while(value[temp_len] != 0) {
617 if (value[temp_len] == separator[0]) {
618 if (value[temp_len+1] ==
620 /* skip second comma */
623 /* single comma indicating start
630 if(value[temp_len] == 0) {
634 /* point option to start of next parm */
635 options = value + temp_len + 1;
637 /* go from value to value + temp_len condensing
638 double commas to singles. Note that this ends up
639 allocating a few bytes too many, which is ok */
640 vol->password = kcalloc(1, temp_len, GFP_KERNEL);
641 if(vol->password == NULL) {
642 printk("CIFS: no memory for pass\n");
645 for(i=0,j=0;i<temp_len;i++,j++) {
646 vol->password[j] = value[i];
647 if(value[i] == separator[0]
648 && value[i+1] == separator[0]) {
649 /* skip second comma */
653 vol->password[j] = 0;
655 vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
656 if(vol->password == NULL) {
657 printk("CIFS: no memory for pass\n");
660 strcpy(vol->password, value);
662 } else if (strnicmp(data, "ip", 2) == 0) {
663 if (!value || !*value) {
665 } else if (strnlen(value, 35) < 35) {
668 printk(KERN_WARNING "CIFS: ip address too long\n");
671 } else if ((strnicmp(data, "unc", 3) == 0)
672 || (strnicmp(data, "target", 6) == 0)
673 || (strnicmp(data, "path", 4) == 0)) {
674 if (!value || !*value) {
676 "CIFS: invalid path to network resource\n");
677 return 1; /* needs_arg; */
679 if ((temp_len = strnlen(value, 300)) < 300) {
680 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
683 strcpy(vol->UNC,value);
684 if (strncmp(vol->UNC, "//", 2) == 0) {
687 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
689 "CIFS: UNC Path does not begin with // or \\\\ \n");
693 printk(KERN_WARNING "CIFS: UNC name too long\n");
696 } else if ((strnicmp(data, "domain", 3) == 0)
697 || (strnicmp(data, "workgroup", 5) == 0)) {
698 if (!value || !*value) {
699 printk(KERN_WARNING "CIFS: invalid domain name\n");
700 return 1; /* needs_arg; */
702 /* BB are there cases in which a comma can be valid in
703 a domain name and need special handling? */
704 if (strnlen(value, 65) < 65) {
705 vol->domainname = value;
706 cFYI(1, ("Domain name set"));
708 printk(KERN_WARNING "CIFS: domain name too long\n");
711 } else if (strnicmp(data, "iocharset", 9) == 0) {
712 if (!value || !*value) {
713 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
714 return 1; /* needs_arg; */
716 if (strnlen(value, 65) < 65) {
717 if(strnicmp(value,"default",7))
718 vol->iocharset = value;
719 /* if iocharset not set load_nls_default used by caller */
720 cFYI(1, ("iocharset set to %s",value));
722 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
725 } else if (strnicmp(data, "uid", 3) == 0) {
726 if (value && *value) {
728 simple_strtoul(value, &value, 0);
730 } else if (strnicmp(data, "gid", 3) == 0) {
731 if (value && *value) {
733 simple_strtoul(value, &value, 0);
735 } else if (strnicmp(data, "file_mode", 4) == 0) {
736 if (value && *value) {
738 simple_strtoul(value, &value, 0);
740 } else if (strnicmp(data, "dir_mode", 4) == 0) {
741 if (value && *value) {
743 simple_strtoul(value, &value, 0);
745 } else if (strnicmp(data, "dirmode", 4) == 0) {
746 if (value && *value) {
748 simple_strtoul(value, &value, 0);
750 } else if (strnicmp(data, "port", 4) == 0) {
751 if (value && *value) {
753 simple_strtoul(value, &value, 0);
755 } else if (strnicmp(data, "rsize", 5) == 0) {
756 if (value && *value) {
758 simple_strtoul(value, &value, 0);
760 } else if (strnicmp(data, "wsize", 5) == 0) {
761 if (value && *value) {
763 simple_strtoul(value, &value, 0);
765 } else if (strnicmp(data, "sockopt", 5) == 0) {
766 if (value && *value) {
768 simple_strtoul(value, &value, 0);
770 } else if (strnicmp(data, "netbiosname", 4) == 0) {
771 if (!value || !*value || (*value == ' ')) {
772 cFYI(1,("invalid (empty) netbiosname specified"));
774 memset(vol->source_rfc1001_name,0x20,15);
776 /* BB are there cases in which a comma can be
777 valid in this workstation netbios name (and need
778 special handling)? */
780 /* We do not uppercase netbiosname for user */
784 vol->source_rfc1001_name[i] = value[i];
786 /* The string has 16th byte zero still from
787 set at top of the function */
788 if((i==15) && (value[i] != 0))
789 printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
791 } else if (strnicmp(data, "credentials", 4) == 0) {
793 } else if (strnicmp(data, "version", 3) == 0) {
795 } else if (strnicmp(data, "guest",5) == 0) {
797 } else if (strnicmp(data, "rw", 2) == 0) {
799 } else if ((strnicmp(data, "suid", 4) == 0) ||
800 (strnicmp(data, "nosuid", 6) == 0) ||
801 (strnicmp(data, "exec", 4) == 0) ||
802 (strnicmp(data, "noexec", 6) == 0) ||
803 (strnicmp(data, "nodev", 5) == 0) ||
804 (strnicmp(data, "noauto", 6) == 0) ||
805 (strnicmp(data, "dev", 3) == 0)) {
806 /* The mount tool or mount.cifs helper (if present)
807 uses these opts to set flags, and the flags are read
808 by the kernel vfs layer before we get here (ie
809 before read super) so there is no point trying to
810 parse these options again and set anything and it
811 is ok to just ignore them */
813 } else if (strnicmp(data, "ro", 2) == 0) {
815 } else if (strnicmp(data, "hard", 4) == 0) {
817 } else if (strnicmp(data, "soft", 4) == 0) {
819 } else if (strnicmp(data, "perm", 4) == 0) {
821 } else if (strnicmp(data, "noperm", 6) == 0) {
823 } else if (strnicmp(data, "mapchars", 8) == 0) {
825 } else if (strnicmp(data, "nomapchars", 10) == 0) {
827 } else if (strnicmp(data, "setuids", 7) == 0) {
829 } else if (strnicmp(data, "nosetuids", 9) == 0) {
831 } else if (strnicmp(data, "nohard", 6) == 0) {
833 } else if (strnicmp(data, "nosoft", 6) == 0) {
835 } else if (strnicmp(data, "nointr", 6) == 0) {
837 } else if (strnicmp(data, "intr", 4) == 0) {
839 } else if (strnicmp(data, "serverino",7) == 0) {
841 } else if (strnicmp(data, "noserverino",9) == 0) {
843 } else if (strnicmp(data, "acl",3) == 0) {
845 } else if (strnicmp(data, "noacl",5) == 0) {
847 } else if (strnicmp(data, "direct",6) == 0) {
849 } else if (strnicmp(data, "forcedirectio",13) == 0) {
851 } else if (strnicmp(data, "in6_addr",8) == 0) {
852 if (!value || !*value) {
853 vol->in6_addr = NULL;
854 } else if (strnlen(value, 49) == 48) {
855 vol->in6_addr = value;
857 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
860 } else if (strnicmp(data, "noac", 4) == 0) {
861 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
863 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
865 if (vol->UNC == NULL) {
866 if(devname == NULL) {
867 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
870 if ((temp_len = strnlen(devname, 300)) < 300) {
871 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
874 strcpy(vol->UNC,devname);
875 if (strncmp(vol->UNC, "//", 2) == 0) {
878 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
879 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
883 printk(KERN_WARNING "CIFS: UNC name too long\n");
887 if(vol->UNCip == NULL)
888 vol->UNCip = &vol->UNC[2];
893 static struct cifsSesInfo *
894 cifs_find_tcp_session(struct in_addr * target_ip_addr,
895 struct in6_addr *target_ip6_addr,
896 char *userName, struct TCP_Server_Info **psrvTcp)
898 struct list_head *tmp;
899 struct cifsSesInfo *ses;
901 read_lock(&GlobalSMBSeslock);
903 list_for_each(tmp, &GlobalSMBSessionList) {
904 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
906 if((target_ip_addr &&
907 (ses->server->addr.sockAddr.sin_addr.s_addr
908 == target_ip_addr->s_addr)) || (target_ip6_addr
909 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
910 target_ip6_addr,sizeof(*target_ip6_addr)))){
911 /* BB lock server and tcp session and increment use count here?? */
912 *psrvTcp = ses->server; /* found a match on the TCP session */
913 /* BB check if reconnection needed */
915 (ses->userName, userName,
916 MAX_USERNAME_SIZE) == 0){
917 read_unlock(&GlobalSMBSeslock);
918 return ses; /* found exact match on both tcp and SMB sessions */
922 /* else tcp and smb sessions need reconnection */
924 read_unlock(&GlobalSMBSeslock);
928 static struct cifsTconInfo *
929 find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
931 struct list_head *tmp;
932 struct cifsTconInfo *tcon;
934 read_lock(&GlobalSMBSeslock);
935 list_for_each(tmp, &GlobalTreeConnectionList) {
936 cFYI(1, ("Next tcon - "));
937 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
939 if (tcon->ses->server) {
941 (" old ip addr: %x == new ip %x ?",
942 tcon->ses->server->addr.sockAddr.sin_addr.
943 s_addr, new_target_ip_addr));
944 if (tcon->ses->server->addr.sockAddr.sin_addr.
945 s_addr == new_target_ip_addr) {
946 /* BB lock tcon and server and tcp session and increment use count here? */
947 /* found a match on the TCP session */
948 /* BB check if reconnection needed */
949 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
950 tcon->treeName, uncName));
952 (tcon->treeName, uncName,
953 MAX_TREE_SIZE) == 0) {
955 ("Matched UNC, old user: %s == new: %s ?",
956 tcon->treeName, uncName));
958 (tcon->ses->userName,
960 MAX_USERNAME_SIZE) == 0) {
961 read_unlock(&GlobalSMBSeslock);
962 return tcon;/* also matched user (smb session)*/
969 read_unlock(&GlobalSMBSeslock);
974 connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
975 const char *old_path, const struct nls_table *nls_codepage,
978 unsigned char *referrals = NULL;
979 unsigned int num_referrals;
982 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
983 &num_referrals, &referrals, remap);
985 /* BB Add in code to: if valid refrl, if not ip address contact
986 the helper that resolves tcp names, mount to it, try to
987 tcon to it unmount it if fail */
996 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
997 const char *old_path, const struct nls_table *nls_codepage,
998 unsigned int *pnum_referrals,
999 unsigned char ** preferrals, int remap)
1004 *pnum_referrals = 0;
1006 if (pSesInfo->ipc_tid == 0) {
1007 temp_unc = kmalloc(2 /* for slashes */ +
1008 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1009 + 1 + 4 /* slash IPC$ */ + 2,
1011 if (temp_unc == NULL)
1015 strcpy(temp_unc + 2, pSesInfo->serverName);
1016 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1017 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1019 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1023 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
1024 pnum_referrals, nls_codepage, remap);
1029 /* See RFC1001 section 14 on representation of Netbios names */
1030 static void rfc1002mangle(char * target,char * source, unsigned int length)
1034 for(i=0,j=0;i<(length);i++) {
1035 /* mask a nibble at a time and encode */
1036 target[j] = 'A' + (0x0F & (source[i] >> 4));
1037 target[j+1] = 'A' + (0x0F & source[i]);
1045 ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1046 char * netbios_name)
1050 __be16 orig_port = 0;
1052 if(*csocket == NULL) {
1053 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1055 cERROR(1, ("Error %d creating socket",rc));
1059 /* BB other socket options to set KEEPALIVE, NODELAY? */
1060 cFYI(1,("Socket created"));
1061 (*csocket)->sk->sk_allocation = GFP_NOFS;
1065 psin_server->sin_family = AF_INET;
1066 if(psin_server->sin_port) { /* user overrode default port */
1067 rc = (*csocket)->ops->connect(*csocket,
1068 (struct sockaddr *) psin_server,
1069 sizeof (struct sockaddr_in),0);
1075 /* save original port so we can retry user specified port
1076 later if fall back ports fail this time */
1077 orig_port = psin_server->sin_port;
1079 /* do not retry on the same port we just failed on */
1080 if(psin_server->sin_port != htons(CIFS_PORT)) {
1081 psin_server->sin_port = htons(CIFS_PORT);
1083 rc = (*csocket)->ops->connect(*csocket,
1084 (struct sockaddr *) psin_server,
1085 sizeof (struct sockaddr_in),0);
1091 psin_server->sin_port = htons(RFC1001_PORT);
1092 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1093 psin_server, sizeof (struct sockaddr_in),0);
1098 /* give up here - unless we want to retry on different
1099 protocol families some day */
1102 psin_server->sin_port = orig_port;
1103 cFYI(1,("Error %d connecting to server via ipv4",rc));
1104 sock_release(*csocket);
1108 /* Eventually check for other socket options to change from
1109 the default. sock_setsockopt not used because it expects
1110 user space buffer */
1111 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1113 /* send RFC1001 sessinit */
1115 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1116 /* some servers require RFC1001 sessinit before sending
1117 negprot - BB check reconnection in case where second
1118 sessinit is sent but no second negprot */
1119 struct rfc1002_session_packet * ses_init_buf;
1120 struct smb_hdr * smb_buf;
1121 ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
1123 ses_init_buf->trailer.session_req.called_len = 32;
1124 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1125 DEFAULT_CIFS_CALLED_NAME,16);
1126 ses_init_buf->trailer.session_req.calling_len = 32;
1127 /* calling name ends in null (byte 16) from old smb
1129 if(netbios_name && (netbios_name[0] !=0)) {
1130 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1133 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1134 "LINUX_CIFS_CLNT",16);
1136 ses_init_buf->trailer.session_req.scope1 = 0;
1137 ses_init_buf->trailer.session_req.scope2 = 0;
1138 smb_buf = (struct smb_hdr *)ses_init_buf;
1139 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1140 smb_buf->smb_buf_length = 0x81000044;
1141 rc = smb_send(*csocket, smb_buf, 0x44,
1142 (struct sockaddr *)psin_server);
1143 kfree(ses_init_buf);
1145 /* else the negprot may still work without this
1146 even though malloc failed */
1154 ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1158 __be16 orig_port = 0;
1160 if(*csocket == NULL) {
1161 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1163 cERROR(1, ("Error %d creating ipv6 socket",rc));
1167 /* BB other socket options to set KEEPALIVE, NODELAY? */
1168 cFYI(1,("ipv6 Socket created"));
1169 (*csocket)->sk->sk_allocation = GFP_NOFS;
1173 psin_server->sin6_family = AF_INET6;
1175 if(psin_server->sin6_port) { /* user overrode default port */
1176 rc = (*csocket)->ops->connect(*csocket,
1177 (struct sockaddr *) psin_server,
1178 sizeof (struct sockaddr_in6),0);
1184 /* save original port so we can retry user specified port
1185 later if fall back ports fail this time */
1187 orig_port = psin_server->sin6_port;
1188 /* do not retry on the same port we just failed on */
1189 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1190 psin_server->sin6_port = htons(CIFS_PORT);
1192 rc = (*csocket)->ops->connect(*csocket,
1193 (struct sockaddr *) psin_server,
1194 sizeof (struct sockaddr_in6),0);
1200 psin_server->sin6_port = htons(RFC1001_PORT);
1201 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1202 psin_server, sizeof (struct sockaddr_in6),0);
1207 /* give up here - unless we want to retry on different
1208 protocol families some day */
1211 psin_server->sin6_port = orig_port;
1212 cFYI(1,("Error %d connecting to server via ipv6",rc));
1213 sock_release(*csocket);
1217 /* Eventually check for other socket options to change from
1218 the default. sock_setsockopt not used because it expects
1219 user space buffer */
1220 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1226 cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1227 char *mount_data, const char *devname)
1231 int address_type = AF_INET;
1232 struct socket *csocket = NULL;
1233 struct sockaddr_in sin_server;
1234 struct sockaddr_in6 sin_server6;
1235 struct smb_vol volume_info;
1236 struct cifsSesInfo *pSesInfo = NULL;
1237 struct cifsSesInfo *existingCifsSes = NULL;
1238 struct cifsTconInfo *tcon = NULL;
1239 struct TCP_Server_Info *srvTcp = NULL;
1243 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1245 memset(&volume_info,0,sizeof(struct smb_vol));
1246 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1248 kfree(volume_info.UNC);
1249 if(volume_info.password)
1250 kfree(volume_info.password);
1255 if (volume_info.username) {
1256 /* BB fixme parse for domain name here */
1257 cFYI(1, ("Username: %s ", volume_info.username));
1260 cifserror("No username specified ");
1261 /* In userspace mount helper we can get user name from alternate
1262 locations such as env variables and files on disk */
1264 kfree(volume_info.UNC);
1265 if(volume_info.password)
1266 kfree(volume_info.password);
1271 if (volume_info.UNCip && volume_info.UNC) {
1272 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1275 /* not ipv4 address, try ipv6 */
1276 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1278 address_type = AF_INET6;
1280 address_type = AF_INET;
1284 /* we failed translating address */
1286 kfree(volume_info.UNC);
1287 if(volume_info.password)
1288 kfree(volume_info.password);
1293 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1296 } else if (volume_info.UNCip){
1297 /* BB using ip addr as server name connect to the DFS root below */
1298 cERROR(1,("Connecting to DFS root not implemented yet"));
1300 kfree(volume_info.UNC);
1301 if(volume_info.password)
1302 kfree(volume_info.password);
1305 } else /* which servers DFS root would we conect to */ {
1307 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1309 kfree(volume_info.UNC);
1310 if(volume_info.password)
1311 kfree(volume_info.password);
1316 /* this is needed for ASCII cp to Unicode converts */
1317 if(volume_info.iocharset == NULL) {
1318 cifs_sb->local_nls = load_nls_default();
1319 /* load_nls_default can not return null */
1321 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1322 if(cifs_sb->local_nls == NULL) {
1323 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1325 kfree(volume_info.UNC);
1326 if(volume_info.password)
1327 kfree(volume_info.password);
1333 if(address_type == AF_INET)
1334 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1335 NULL /* no ipv6 addr */,
1336 volume_info.username, &srvTcp);
1337 else if(address_type == AF_INET6)
1338 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1339 &sin_server6.sin6_addr,
1340 volume_info.username, &srvTcp);
1343 kfree(volume_info.UNC);
1344 if(volume_info.password)
1345 kfree(volume_info.password);
1352 cFYI(1, ("Existing tcp session with server found "));
1353 } else { /* create socket */
1354 if(volume_info.port)
1355 sin_server.sin_port = htons(volume_info.port);
1357 sin_server.sin_port = 0;
1358 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1361 ("Error connecting to IPv4 socket. Aborting operation"));
1363 sock_release(csocket);
1365 kfree(volume_info.UNC);
1366 if(volume_info.password)
1367 kfree(volume_info.password);
1372 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1373 if (srvTcp == NULL) {
1375 sock_release(csocket);
1377 kfree(volume_info.UNC);
1378 if(volume_info.password)
1379 kfree(volume_info.password);
1383 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1384 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1385 atomic_set(&srvTcp->inFlight,0);
1386 /* BB Add code for ipv6 case too */
1387 srvTcp->ssocket = csocket;
1388 srvTcp->protocolType = IPV4;
1389 init_waitqueue_head(&srvTcp->response_q);
1390 init_waitqueue_head(&srvTcp->request_q);
1391 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1392 /* at this point we are the only ones with the pointer
1393 to the struct since the kernel thread not created yet
1394 so no need to spinlock this init of tcpStatus */
1395 srvTcp->tcpStatus = CifsNew;
1396 init_MUTEX(&srvTcp->tcpSem);
1397 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1398 CLONE_FS | CLONE_FILES | CLONE_VM);
1401 sock_release(csocket);
1403 kfree(volume_info.UNC);
1404 if(volume_info.password)
1405 kfree(volume_info.password);
1410 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
1411 srvTcp->sequence_number = 0;
1415 if (existingCifsSes) {
1416 pSesInfo = existingCifsSes;
1417 cFYI(1, ("Existing smb sess found "));
1418 if(volume_info.password)
1419 kfree(volume_info.password);
1420 /* volume_info.UNC freed at end of function */
1422 cFYI(1, ("Existing smb sess not found "));
1423 pSesInfo = sesInfoAlloc();
1424 if (pSesInfo == NULL)
1427 pSesInfo->server = srvTcp;
1428 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1429 NIPQUAD(sin_server.sin_addr.s_addr));
1433 /* volume_info.password freed at unmount */
1434 if (volume_info.password)
1435 pSesInfo->password = volume_info.password;
1436 if (volume_info.username)
1437 strncpy(pSesInfo->userName,
1438 volume_info.username,MAX_USERNAME_SIZE);
1439 if (volume_info.domainname)
1440 strncpy(pSesInfo->domainName,
1441 volume_info.domainname,MAX_USERNAME_SIZE);
1442 pSesInfo->linux_uid = volume_info.linux_uid;
1443 down(&pSesInfo->sesSem);
1444 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1445 up(&pSesInfo->sesSem);
1447 atomic_inc(&srvTcp->socketUseCount);
1449 if(volume_info.password)
1450 kfree(volume_info.password);
1453 /* search for existing tcon to this server share */
1455 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1456 cifs_sb->rsize = volume_info.rsize;
1458 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1459 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1460 cifs_sb->wsize = volume_info.wsize;
1462 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1463 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1464 cifs_sb->rsize = PAGE_CACHE_SIZE;
1465 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1467 cifs_sb->mnt_uid = volume_info.linux_uid;
1468 cifs_sb->mnt_gid = volume_info.linux_gid;
1469 cifs_sb->mnt_file_mode = volume_info.file_mode;
1470 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1471 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1473 if(volume_info.noperm)
1474 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1475 if(volume_info.setuids)
1476 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1477 if(volume_info.server_ino)
1478 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
1479 if(volume_info.remap)
1480 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
1481 if(volume_info.no_xattr)
1482 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1483 if(volume_info.direct_io) {
1484 cERROR(1,("mounting share using direct i/o"));
1485 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1489 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1490 volume_info.username);
1492 cFYI(1, ("Found match on UNC path "));
1493 /* we can have only one retry value for a connection
1494 to a share so for resources mounted more than once
1495 to the same server share the last value passed in
1496 for the retry flag is used */
1497 tcon->retry = volume_info.retry;
1499 tcon = tconInfoAlloc();
1503 /* check for null share name ie connect to dfs root */
1505 /* BB check if this works for exactly length three strings */
1506 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1507 && (strchr(volume_info.UNC + 3, '/') ==
1509 rc = connect_to_dfs_path(xid, pSesInfo,
1510 "", cifs_sb->local_nls,
1511 cifs_sb->mnt_cifs_flags &
1512 CIFS_MOUNT_MAP_SPECIAL_CHR);
1514 kfree(volume_info.UNC);
1518 rc = CIFSTCon(xid, pSesInfo,
1520 tcon, cifs_sb->local_nls);
1521 cFYI(1, ("CIFS Tcon rc = %d", rc));
1524 atomic_inc(&pSesInfo->inUse);
1525 tcon->retry = volume_info.retry;
1531 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1532 sb->s_maxbytes = (u64) 1 << 63;
1534 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1537 sb->s_time_gran = 100;
1539 /* on error free sesinfo and tcon struct if needed */
1541 /* if session setup failed, use count is zero but
1542 we still need to free cifsd thread */
1543 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1544 spin_lock(&GlobalMid_Lock);
1545 srvTcp->tcpStatus = CifsExiting;
1546 spin_unlock(&GlobalMid_Lock);
1548 send_sig(SIGKILL,srvTcp->tsk,1);
1550 /* If find_unc succeeded then rc == 0 so we can not end */
1551 if (tcon) /* up accidently freeing someone elses tcon struct */
1553 if (existingCifsSes == NULL) {
1555 if ((pSesInfo->server) &&
1556 (pSesInfo->status == CifsGood)) {
1558 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1559 /* if the socketUseCount is now zero */
1560 if((temp_rc == -ESHUTDOWN) &&
1561 (pSesInfo->server->tsk))
1562 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1564 cFYI(1, ("No session or bad tcon"));
1565 sesInfoFree(pSesInfo);
1566 /* pSesInfo = NULL; */
1570 atomic_inc(&tcon->useCount);
1571 cifs_sb->tcon = tcon;
1572 tcon->ses = pSesInfo;
1574 /* do not care if following two calls succeed - informational only */
1575 CIFSSMBQFSDeviceInfo(xid, tcon);
1576 CIFSSMBQFSAttributeInfo(xid, tcon);
1577 if (tcon->ses->capabilities & CAP_UNIX) {
1578 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
1579 if(!volume_info.no_psx_acl) {
1580 if(CIFS_UNIX_POSIX_ACL_CAP &
1581 le64_to_cpu(tcon->fsUnixInfo.Capability))
1582 cFYI(1,("server negotiated posix acl support"));
1583 sb->s_flags |= MS_POSIXACL;
1589 /* volume_info.password is freed above when existing session found
1590 (in which case it is not needed anymore) but when new sesion is created
1591 the password ptr is put in the new session structure (in which case the
1592 password will be freed at unmount time) */
1594 kfree(volume_info.UNC);
1600 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1601 char session_key[CIFS_SESSION_KEY_SIZE],
1602 const struct nls_table *nls_codepage)
1604 struct smb_hdr *smb_buffer;
1605 struct smb_hdr *smb_buffer_response;
1606 SESSION_SETUP_ANDX *pSMB;
1607 SESSION_SETUP_ANDX *pSMBr;
1612 int remaining_words = 0;
1613 int bytes_returned = 0;
1618 cFYI(1, ("In sesssetup "));
1621 user = ses->userName;
1622 domain = ses->domainName;
1623 smb_buffer = cifs_buf_get();
1624 if (smb_buffer == NULL) {
1627 smb_buffer_response = smb_buffer;
1628 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1630 /* send SMBsessionSetup here */
1631 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1632 NULL /* no tCon exists yet */ , 13 /* wct */ );
1634 pSMB->req_no_secext.AndXCommand = 0xFF;
1635 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1636 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1638 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1639 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1641 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1642 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1643 if (ses->capabilities & CAP_UNICODE) {
1644 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1645 capabilities |= CAP_UNICODE;
1647 if (ses->capabilities & CAP_STATUS32) {
1648 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1649 capabilities |= CAP_STATUS32;
1651 if (ses->capabilities & CAP_DFS) {
1652 smb_buffer->Flags2 |= SMBFLG2_DFS;
1653 capabilities |= CAP_DFS;
1655 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1657 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1658 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1660 pSMB->req_no_secext.CaseSensitivePasswordLength =
1661 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1662 bcc_ptr = pByteArea(smb_buffer);
1663 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1664 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1665 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1666 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1668 if (ses->capabilities & CAP_UNICODE) {
1669 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1674 bytes_returned = 0; /* skill null user */
1677 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1679 /* convert number of 16 bit words to bytes */
1680 bcc_ptr += 2 * bytes_returned;
1681 bcc_ptr += 2; /* trailing null */
1684 cifs_strtoUCS((wchar_t *) bcc_ptr,
1685 "CIFS_LINUX_DOM", 32, nls_codepage);
1688 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1690 bcc_ptr += 2 * bytes_returned;
1693 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1695 bcc_ptr += 2 * bytes_returned;
1697 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1699 bcc_ptr += 2 * bytes_returned;
1702 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1704 bcc_ptr += 2 * bytes_returned;
1708 strncpy(bcc_ptr, user, 200);
1709 bcc_ptr += strnlen(user, 200);
1713 if (domain == NULL) {
1714 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1715 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1717 strncpy(bcc_ptr, domain, 64);
1718 bcc_ptr += strnlen(domain, 64);
1722 strcpy(bcc_ptr, "Linux version ");
1723 bcc_ptr += strlen("Linux version ");
1724 strcpy(bcc_ptr, system_utsname.release);
1725 bcc_ptr += strlen(system_utsname.release) + 1;
1726 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1727 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1729 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1730 smb_buffer->smb_buf_length += count;
1731 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
1733 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1734 &bytes_returned, 1);
1736 /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1737 } else if ((smb_buffer_response->WordCount == 3)
1738 || (smb_buffer_response->WordCount == 4)) {
1739 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1740 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1741 if (action & GUEST_LOGIN)
1742 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
1743 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1744 cFYI(1, ("UID = %d ", ses->Suid));
1745 /* response can have either 3 or 4 word count - Samba sends 3 */
1746 bcc_ptr = pByteArea(smb_buffer_response);
1747 if ((pSMBr->resp.hdr.WordCount == 3)
1748 || ((pSMBr->resp.hdr.WordCount == 4)
1749 && (blob_len < pSMBr->resp.ByteCount))) {
1750 if (pSMBr->resp.hdr.WordCount == 4)
1751 bcc_ptr += blob_len;
1753 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1754 if ((long) (bcc_ptr) % 2) {
1756 (BCC(smb_buffer_response) - 1) /2;
1757 bcc_ptr++; /* Unicode strings must be word aligned */
1760 BCC(smb_buffer_response) / 2;
1763 UniStrnlen((wchar_t *) bcc_ptr,
1764 remaining_words - 1);
1765 /* We look for obvious messed up bcc or strings in response so we do not go off
1766 the end since (at least) WIN2K and Windows XP have a major bug in not null
1767 terminating last Unicode string in response */
1768 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
1769 if(ses->serverOS == NULL)
1770 goto sesssetup_nomem;
1771 cifs_strfromUCS_le(ses->serverOS,
1772 (wchar_t *)bcc_ptr, len,nls_codepage);
1773 bcc_ptr += 2 * (len + 1);
1774 remaining_words -= len + 1;
1775 ses->serverOS[2 * len] = 0;
1776 ses->serverOS[1 + (2 * len)] = 0;
1777 if (remaining_words > 0) {
1778 len = UniStrnlen((wchar_t *)bcc_ptr,
1780 ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
1781 if(ses->serverNOS == NULL)
1782 goto sesssetup_nomem;
1783 cifs_strfromUCS_le(ses->serverNOS,
1784 (wchar_t *)bcc_ptr,len,nls_codepage);
1785 bcc_ptr += 2 * (len + 1);
1786 ses->serverNOS[2 * len] = 0;
1787 ses->serverNOS[1 + (2 * len)] = 0;
1788 if(strncmp(ses->serverNOS,
1789 "NT LAN Manager 4",16) == 0) {
1790 cFYI(1,("NT4 server"));
1791 ses->flags |= CIFS_SES_NT4;
1793 remaining_words -= len + 1;
1794 if (remaining_words > 0) {
1795 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
1796 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1798 kcalloc(1, 2*(len+1),GFP_KERNEL);
1799 if(ses->serverDomain == NULL)
1800 goto sesssetup_nomem;
1801 cifs_strfromUCS_le(ses->serverDomain,
1802 (wchar_t *)bcc_ptr,len,nls_codepage);
1803 bcc_ptr += 2 * (len + 1);
1804 ses->serverDomain[2*len] = 0;
1805 ses->serverDomain[1+(2*len)] = 0;
1806 } /* else no more room so create dummy domain string */
1809 kcalloc(1, 2, GFP_KERNEL);
1810 } else { /* no room so create dummy domain and NOS string */
1811 /* if these kcallocs fail not much we
1812 can do, but better to not fail the
1815 kcalloc(1, 2, GFP_KERNEL);
1817 kcalloc(1, 2, GFP_KERNEL);
1819 } else { /* ASCII */
1820 len = strnlen(bcc_ptr, 1024);
1821 if (((long) bcc_ptr + len) - (long)
1822 pByteArea(smb_buffer_response)
1823 <= BCC(smb_buffer_response)) {
1824 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
1825 if(ses->serverOS == NULL)
1826 goto sesssetup_nomem;
1827 strncpy(ses->serverOS,bcc_ptr, len);
1830 bcc_ptr[0] = 0; /* null terminate the string */
1833 len = strnlen(bcc_ptr, 1024);
1834 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
1835 if(ses->serverNOS == NULL)
1836 goto sesssetup_nomem;
1837 strncpy(ses->serverNOS, bcc_ptr, len);
1842 len = strnlen(bcc_ptr, 1024);
1843 ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
1844 if(ses->serverDomain == NULL)
1845 goto sesssetup_nomem;
1846 strncpy(ses->serverDomain, bcc_ptr, len);
1852 ("Variable field of length %d extends beyond end of smb ",
1857 (" Security Blob Length extends beyond end of SMB"));
1861 (" Invalid Word count %d: ",
1862 smb_buffer_response->WordCount));
1865 sesssetup_nomem: /* do not return an error on nomem for the info strings,
1866 since that could make reconnection harder, and
1867 reconnection might be needed to free memory */
1869 cifs_buf_release(smb_buffer);
1875 CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1876 char *SecurityBlob,int SecurityBlobLength,
1877 const struct nls_table *nls_codepage)
1879 struct smb_hdr *smb_buffer;
1880 struct smb_hdr *smb_buffer_response;
1881 SESSION_SETUP_ANDX *pSMB;
1882 SESSION_SETUP_ANDX *pSMBr;
1887 int remaining_words = 0;
1888 int bytes_returned = 0;
1893 cFYI(1, ("In spnego sesssetup "));
1896 user = ses->userName;
1897 domain = ses->domainName;
1899 smb_buffer = cifs_buf_get();
1900 if (smb_buffer == NULL) {
1903 smb_buffer_response = smb_buffer;
1904 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1906 /* send SMBsessionSetup here */
1907 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1908 NULL /* no tCon exists yet */ , 12 /* wct */ );
1909 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
1910 pSMB->req.AndXCommand = 0xFF;
1911 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1912 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1914 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1915 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1917 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1918 CAP_EXTENDED_SECURITY;
1919 if (ses->capabilities & CAP_UNICODE) {
1920 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1921 capabilities |= CAP_UNICODE;
1923 if (ses->capabilities & CAP_STATUS32) {
1924 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1925 capabilities |= CAP_STATUS32;
1927 if (ses->capabilities & CAP_DFS) {
1928 smb_buffer->Flags2 |= SMBFLG2_DFS;
1929 capabilities |= CAP_DFS;
1931 pSMB->req.Capabilities = cpu_to_le32(capabilities);
1933 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
1934 bcc_ptr = pByteArea(smb_buffer);
1935 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
1936 bcc_ptr += SecurityBlobLength;
1938 if (ses->capabilities & CAP_UNICODE) {
1939 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
1944 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
1945 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
1946 bcc_ptr += 2; /* trailing null */
1949 cifs_strtoUCS((wchar_t *) bcc_ptr,
1950 "CIFS_LINUX_DOM", 32, nls_codepage);
1953 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1955 bcc_ptr += 2 * bytes_returned;
1958 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1960 bcc_ptr += 2 * bytes_returned;
1962 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
1964 bcc_ptr += 2 * bytes_returned;
1967 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1969 bcc_ptr += 2 * bytes_returned;
1972 strncpy(bcc_ptr, user, 200);
1973 bcc_ptr += strnlen(user, 200);
1976 if (domain == NULL) {
1977 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1978 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1980 strncpy(bcc_ptr, domain, 64);
1981 bcc_ptr += strnlen(domain, 64);
1985 strcpy(bcc_ptr, "Linux version ");
1986 bcc_ptr += strlen("Linux version ");
1987 strcpy(bcc_ptr, system_utsname.release);
1988 bcc_ptr += strlen(system_utsname.release) + 1;
1989 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1990 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1992 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1993 smb_buffer->smb_buf_length += count;
1994 pSMB->req.ByteCount = cpu_to_le16(count);
1996 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1997 &bytes_returned, 1);
1999 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2000 } else if ((smb_buffer_response->WordCount == 3)
2001 || (smb_buffer_response->WordCount == 4)) {
2002 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2004 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2005 if (action & GUEST_LOGIN)
2006 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2008 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2009 cFYI(1, ("UID = %d ", ses->Suid));
2010 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2012 /* BB Fix below to make endian neutral !! */
2014 if ((pSMBr->resp.hdr.WordCount == 3)
2015 || ((pSMBr->resp.hdr.WordCount == 4)
2017 pSMBr->resp.ByteCount))) {
2018 if (pSMBr->resp.hdr.WordCount == 4) {
2022 ("Security Blob Length %d ",
2026 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2027 if ((long) (bcc_ptr) % 2) {
2029 (BCC(smb_buffer_response)
2031 bcc_ptr++; /* Unicode strings must be word aligned */
2035 (smb_buffer_response) / 2;
2038 UniStrnlen((wchar_t *) bcc_ptr,
2039 remaining_words - 1);
2040 /* We look for obvious messed up bcc or strings in response so we do not go off
2041 the end since (at least) WIN2K and Windows XP have a major bug in not null
2042 terminating last Unicode string in response */
2044 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2045 cifs_strfromUCS_le(ses->serverOS,
2049 bcc_ptr += 2 * (len + 1);
2050 remaining_words -= len + 1;
2051 ses->serverOS[2 * len] = 0;
2052 ses->serverOS[1 + (2 * len)] = 0;
2053 if (remaining_words > 0) {
2054 len = UniStrnlen((wchar_t *)bcc_ptr,
2058 kcalloc(1, 2 * (len + 1),
2060 cifs_strfromUCS_le(ses->serverNOS,
2064 bcc_ptr += 2 * (len + 1);
2065 ses->serverNOS[2 * len] = 0;
2066 ses->serverNOS[1 + (2 * len)] = 0;
2067 remaining_words -= len + 1;
2068 if (remaining_words > 0) {
2069 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2070 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2071 ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
2072 cifs_strfromUCS_le(ses->serverDomain,
2076 bcc_ptr += 2*(len+1);
2077 ses->serverDomain[2*len] = 0;
2078 ses->serverDomain[1+(2*len)] = 0;
2079 } /* else no more room so create dummy domain string */
2082 kcalloc(1, 2,GFP_KERNEL);
2083 } else { /* no room so create dummy domain and NOS string */
2084 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2085 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
2087 } else { /* ASCII */
2089 len = strnlen(bcc_ptr, 1024);
2090 if (((long) bcc_ptr + len) - (long)
2091 pByteArea(smb_buffer_response)
2092 <= BCC(smb_buffer_response)) {
2093 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
2094 strncpy(ses->serverOS, bcc_ptr, len);
2097 bcc_ptr[0] = 0; /* null terminate the string */
2100 len = strnlen(bcc_ptr, 1024);
2101 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2102 strncpy(ses->serverNOS, bcc_ptr, len);
2107 len = strnlen(bcc_ptr, 1024);
2108 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
2109 strncpy(ses->serverDomain, bcc_ptr, len);
2115 ("Variable field of length %d extends beyond end of smb ",
2120 (" Security Blob Length extends beyond end of SMB"));
2123 cERROR(1, ("No session structure passed in."));
2127 (" Invalid Word count %d: ",
2128 smb_buffer_response->WordCount));
2133 cifs_buf_release(smb_buffer);
2139 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2140 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2141 const struct nls_table *nls_codepage)
2143 struct smb_hdr *smb_buffer;
2144 struct smb_hdr *smb_buffer_response;
2145 SESSION_SETUP_ANDX *pSMB;
2146 SESSION_SETUP_ANDX *pSMBr;
2150 int remaining_words = 0;
2151 int bytes_returned = 0;
2153 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2154 PNEGOTIATE_MESSAGE SecurityBlob;
2155 PCHALLENGE_MESSAGE SecurityBlob2;
2156 __u32 negotiate_flags, capabilities;
2159 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2162 domain = ses->domainName;
2163 *pNTLMv2_flag = FALSE;
2164 smb_buffer = cifs_buf_get();
2165 if (smb_buffer == NULL) {
2168 smb_buffer_response = smb_buffer;
2169 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2170 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2172 /* send SMBsessionSetup here */
2173 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2174 NULL /* no tCon exists yet */ , 12 /* wct */ );
2175 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2176 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2178 pSMB->req.AndXCommand = 0xFF;
2179 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2180 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2182 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2183 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2185 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2186 CAP_EXTENDED_SECURITY;
2187 if (ses->capabilities & CAP_UNICODE) {
2188 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2189 capabilities |= CAP_UNICODE;
2191 if (ses->capabilities & CAP_STATUS32) {
2192 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2193 capabilities |= CAP_STATUS32;
2195 if (ses->capabilities & CAP_DFS) {
2196 smb_buffer->Flags2 |= SMBFLG2_DFS;
2197 capabilities |= CAP_DFS;
2199 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2201 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2202 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2203 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2204 SecurityBlob->MessageType = NtLmNegotiate;
2206 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2207 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2208 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2210 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2212 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2213 /* setup pointers to domain name and workstation name */
2214 bcc_ptr += SecurityBlobLength;
2216 SecurityBlob->WorkstationName.Buffer = 0;
2217 SecurityBlob->WorkstationName.Length = 0;
2218 SecurityBlob->WorkstationName.MaximumLength = 0;
2220 if (domain == NULL) {
2221 SecurityBlob->DomainName.Buffer = 0;
2222 SecurityBlob->DomainName.Length = 0;
2223 SecurityBlob->DomainName.MaximumLength = 0;
2226 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2227 strncpy(bcc_ptr, domain, 63);
2228 len = strnlen(domain, 64);
2229 SecurityBlob->DomainName.MaximumLength =
2231 SecurityBlob->DomainName.Buffer =
2232 cpu_to_le32((long) &SecurityBlob->
2234 (long) &SecurityBlob->Signature);
2236 SecurityBlobLength += len;
2237 SecurityBlob->DomainName.Length =
2240 if (ses->capabilities & CAP_UNICODE) {
2241 if ((long) bcc_ptr % 2) {
2247 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2249 bcc_ptr += 2 * bytes_returned;
2251 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2253 bcc_ptr += 2 * bytes_returned;
2254 bcc_ptr += 2; /* null terminate Linux version */
2256 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2258 bcc_ptr += 2 * bytes_returned;
2261 bcc_ptr += 2; /* null terminate network opsys string */
2264 bcc_ptr += 2; /* null domain */
2265 } else { /* ASCII */
2266 strcpy(bcc_ptr, "Linux version ");
2267 bcc_ptr += strlen("Linux version ");
2268 strcpy(bcc_ptr, system_utsname.release);
2269 bcc_ptr += strlen(system_utsname.release) + 1;
2270 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2271 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2272 bcc_ptr++; /* empty domain field */
2275 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2276 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2277 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2278 smb_buffer->smb_buf_length += count;
2279 pSMB->req.ByteCount = cpu_to_le16(count);
2281 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2282 &bytes_returned, 1);
2284 if (smb_buffer_response->Status.CifsError ==
2285 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2289 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2290 } else if ((smb_buffer_response->WordCount == 3)
2291 || (smb_buffer_response->WordCount == 4)) {
2292 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2293 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2295 if (action & GUEST_LOGIN)
2296 cFYI(1, (" Guest login"));
2297 /* Do we want to set anything in SesInfo struct when guest login? */
2299 bcc_ptr = pByteArea(smb_buffer_response);
2300 /* response can have either 3 or 4 word count - Samba sends 3 */
2302 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2303 if (SecurityBlob2->MessageType != NtLmChallenge) {
2305 ("Unexpected NTLMSSP message type received %d",
2306 SecurityBlob2->MessageType));
2308 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2309 cFYI(1, ("UID = %d ", ses->Suid));
2310 if ((pSMBr->resp.hdr.WordCount == 3)
2311 || ((pSMBr->resp.hdr.WordCount == 4)
2313 pSMBr->resp.ByteCount))) {
2315 if (pSMBr->resp.hdr.WordCount == 4) {
2316 bcc_ptr += blob_len;
2318 ("Security Blob Length %d ",
2322 cFYI(1, ("NTLMSSP Challenge rcvd "));
2324 memcpy(ses->server->cryptKey,
2325 SecurityBlob2->Challenge,
2326 CIFS_CRYPTO_KEY_SIZE);
2327 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2328 *pNTLMv2_flag = TRUE;
2330 if((SecurityBlob2->NegotiateFlags &
2331 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2332 || (sign_CIFS_PDUs > 1))
2333 ses->server->secMode |=
2334 SECMODE_SIGN_REQUIRED;
2335 if ((SecurityBlob2->NegotiateFlags &
2336 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2337 ses->server->secMode |=
2338 SECMODE_SIGN_ENABLED;
2340 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2341 if ((long) (bcc_ptr) % 2) {
2343 (BCC(smb_buffer_response)
2345 bcc_ptr++; /* Unicode strings must be word aligned */
2349 (smb_buffer_response) / 2;
2352 UniStrnlen((wchar_t *) bcc_ptr,
2353 remaining_words - 1);
2354 /* We look for obvious messed up bcc or strings in response so we do not go off
2355 the end since (at least) WIN2K and Windows XP have a major bug in not null
2356 terminating last Unicode string in response */
2358 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2359 cifs_strfromUCS_le(ses->serverOS,
2363 bcc_ptr += 2 * (len + 1);
2364 remaining_words -= len + 1;
2365 ses->serverOS[2 * len] = 0;
2366 ses->serverOS[1 + (2 * len)] = 0;
2367 if (remaining_words > 0) {
2368 len = UniStrnlen((wchar_t *)
2373 kcalloc(1, 2 * (len + 1),
2375 cifs_strfromUCS_le(ses->
2381 bcc_ptr += 2 * (len + 1);
2382 ses->serverNOS[2 * len] = 0;
2385 remaining_words -= len + 1;
2386 if (remaining_words > 0) {
2387 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2388 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2413 } /* else no more room so create dummy domain string */
2418 } else { /* no room so create dummy domain and NOS string */
2420 kcalloc(1, 2, GFP_KERNEL);
2422 kcalloc(1, 2, GFP_KERNEL);
2424 } else { /* ASCII */
2425 len = strnlen(bcc_ptr, 1024);
2426 if (((long) bcc_ptr + len) - (long)
2427 pByteArea(smb_buffer_response)
2428 <= BCC(smb_buffer_response)) {
2432 strncpy(ses->serverOS,
2436 bcc_ptr[0] = 0; /* null terminate string */
2439 len = strnlen(bcc_ptr, 1024);
2443 strncpy(ses->serverNOS, bcc_ptr, len);
2448 len = strnlen(bcc_ptr, 1024);
2452 strncpy(ses->serverDomain, bcc_ptr, len);
2458 ("Variable field of length %d extends beyond end of smb ",
2463 (" Security Blob Length extends beyond end of SMB"));
2466 cERROR(1, ("No session structure passed in."));
2470 (" Invalid Word count %d: ",
2471 smb_buffer_response->WordCount));
2476 cifs_buf_release(smb_buffer);
2481 CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2482 char *ntlm_session_key, int ntlmv2_flag,
2483 const struct nls_table *nls_codepage)
2485 struct smb_hdr *smb_buffer;
2486 struct smb_hdr *smb_buffer_response;
2487 SESSION_SETUP_ANDX *pSMB;
2488 SESSION_SETUP_ANDX *pSMBr;
2493 int remaining_words = 0;
2494 int bytes_returned = 0;
2496 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2497 PAUTHENTICATE_MESSAGE SecurityBlob;
2498 __u32 negotiate_flags, capabilities;
2501 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2504 user = ses->userName;
2505 domain = ses->domainName;
2506 smb_buffer = cifs_buf_get();
2507 if (smb_buffer == NULL) {
2510 smb_buffer_response = smb_buffer;
2511 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2512 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2514 /* send SMBsessionSetup here */
2515 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2516 NULL /* no tCon exists yet */ , 12 /* wct */ );
2517 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2518 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2519 pSMB->req.AndXCommand = 0xFF;
2520 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2521 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2523 pSMB->req.hdr.Uid = ses->Suid;
2525 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2526 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2528 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2529 CAP_EXTENDED_SECURITY;
2530 if (ses->capabilities & CAP_UNICODE) {
2531 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2532 capabilities |= CAP_UNICODE;
2534 if (ses->capabilities & CAP_STATUS32) {
2535 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2536 capabilities |= CAP_STATUS32;
2538 if (ses->capabilities & CAP_DFS) {
2539 smb_buffer->Flags2 |= SMBFLG2_DFS;
2540 capabilities |= CAP_DFS;
2542 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2544 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2545 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2546 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2547 SecurityBlob->MessageType = NtLmAuthenticate;
2548 bcc_ptr += SecurityBlobLength;
2550 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2551 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2552 0x80000000 | NTLMSSP_NEGOTIATE_128;
2554 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2556 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2558 /* setup pointers to domain name and workstation name */
2560 SecurityBlob->WorkstationName.Buffer = 0;
2561 SecurityBlob->WorkstationName.Length = 0;
2562 SecurityBlob->WorkstationName.MaximumLength = 0;
2563 SecurityBlob->SessionKey.Length = 0;
2564 SecurityBlob->SessionKey.MaximumLength = 0;
2565 SecurityBlob->SessionKey.Buffer = 0;
2567 SecurityBlob->LmChallengeResponse.Length = 0;
2568 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2569 SecurityBlob->LmChallengeResponse.Buffer = 0;
2571 SecurityBlob->NtChallengeResponse.Length =
2572 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2573 SecurityBlob->NtChallengeResponse.MaximumLength =
2574 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2575 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2576 SecurityBlob->NtChallengeResponse.Buffer =
2577 cpu_to_le32(SecurityBlobLength);
2578 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2579 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2581 if (ses->capabilities & CAP_UNICODE) {
2582 if (domain == NULL) {
2583 SecurityBlob->DomainName.Buffer = 0;
2584 SecurityBlob->DomainName.Length = 0;
2585 SecurityBlob->DomainName.MaximumLength = 0;
2588 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2591 SecurityBlob->DomainName.MaximumLength =
2593 SecurityBlob->DomainName.Buffer =
2594 cpu_to_le32(SecurityBlobLength);
2596 SecurityBlobLength += len;
2597 SecurityBlob->DomainName.Length =
2601 SecurityBlob->UserName.Buffer = 0;
2602 SecurityBlob->UserName.Length = 0;
2603 SecurityBlob->UserName.MaximumLength = 0;
2606 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2609 SecurityBlob->UserName.MaximumLength =
2611 SecurityBlob->UserName.Buffer =
2612 cpu_to_le32(SecurityBlobLength);
2614 SecurityBlobLength += len;
2615 SecurityBlob->UserName.Length =
2619 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2620 SecurityBlob->WorkstationName.Length *= 2;
2621 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2622 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2623 bcc_ptr += SecurityBlob->WorkstationName.Length;
2624 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2625 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2627 if ((long) bcc_ptr % 2) {
2632 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2634 bcc_ptr += 2 * bytes_returned;
2636 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2638 bcc_ptr += 2 * bytes_returned;
2639 bcc_ptr += 2; /* null term version string */
2641 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2643 bcc_ptr += 2 * bytes_returned;
2646 bcc_ptr += 2; /* null terminate network opsys string */
2649 bcc_ptr += 2; /* null domain */
2650 } else { /* ASCII */
2651 if (domain == NULL) {
2652 SecurityBlob->DomainName.Buffer = 0;
2653 SecurityBlob->DomainName.Length = 0;
2654 SecurityBlob->DomainName.MaximumLength = 0;
2657 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2658 strncpy(bcc_ptr, domain, 63);
2659 len = strnlen(domain, 64);
2660 SecurityBlob->DomainName.MaximumLength =
2662 SecurityBlob->DomainName.Buffer =
2663 cpu_to_le32(SecurityBlobLength);
2665 SecurityBlobLength += len;
2666 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2669 SecurityBlob->UserName.Buffer = 0;
2670 SecurityBlob->UserName.Length = 0;
2671 SecurityBlob->UserName.MaximumLength = 0;
2674 strncpy(bcc_ptr, user, 63);
2675 len = strnlen(user, 64);
2676 SecurityBlob->UserName.MaximumLength =
2678 SecurityBlob->UserName.Buffer =
2679 cpu_to_le32(SecurityBlobLength);
2681 SecurityBlobLength += len;
2682 SecurityBlob->UserName.Length = cpu_to_le16(len);
2684 /* BB fill in our workstation name if known BB */
2686 strcpy(bcc_ptr, "Linux version ");
2687 bcc_ptr += strlen("Linux version ");
2688 strcpy(bcc_ptr, system_utsname.release);
2689 bcc_ptr += strlen(system_utsname.release) + 1;
2690 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2691 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2692 bcc_ptr++; /* null domain */
2695 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2696 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2697 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2698 smb_buffer->smb_buf_length += count;
2699 pSMB->req.ByteCount = cpu_to_le16(count);
2701 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2702 &bytes_returned, 1);
2704 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2705 } else if ((smb_buffer_response->WordCount == 3)
2706 || (smb_buffer_response->WordCount == 4)) {
2707 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2709 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2710 if (action & GUEST_LOGIN)
2711 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2712 /* if(SecurityBlob2->MessageType != NtLm??){
2713 cFYI("Unexpected message type on auth response is %d "));
2717 ("Does UID on challenge %d match auth response UID %d ",
2718 ses->Suid, smb_buffer_response->Uid));
2719 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2720 bcc_ptr = pByteArea(smb_buffer_response);
2721 /* response can have either 3 or 4 word count - Samba sends 3 */
2722 if ((pSMBr->resp.hdr.WordCount == 3)
2723 || ((pSMBr->resp.hdr.WordCount == 4)
2725 pSMBr->resp.ByteCount))) {
2726 if (pSMBr->resp.hdr.WordCount == 4) {
2730 ("Security Blob Length %d ",
2735 ("NTLMSSP response to Authenticate "));
2737 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2738 if ((long) (bcc_ptr) % 2) {
2740 (BCC(smb_buffer_response)
2742 bcc_ptr++; /* Unicode strings must be word aligned */
2744 remaining_words = BCC(smb_buffer_response) / 2;
2747 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2748 /* We look for obvious messed up bcc or strings in response so we do not go off
2749 the end since (at least) WIN2K and Windows XP have a major bug in not null
2750 terminating last Unicode string in response */
2752 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2753 cifs_strfromUCS_le(ses->serverOS,
2757 bcc_ptr += 2 * (len + 1);
2758 remaining_words -= len + 1;
2759 ses->serverOS[2 * len] = 0;
2760 ses->serverOS[1 + (2 * len)] = 0;
2761 if (remaining_words > 0) {
2762 len = UniStrnlen((wchar_t *)
2767 kcalloc(1, 2 * (len + 1),
2769 cifs_strfromUCS_le(ses->
2775 bcc_ptr += 2 * (len + 1);
2776 ses->serverNOS[2 * len] = 0;
2777 ses->serverNOS[1+(2*len)] = 0;
2778 remaining_words -= len + 1;
2779 if (remaining_words > 0) {
2780 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2781 /* last string not always null terminated (e.g. for Windows XP & 2000) */
2806 } /* else no more room so create dummy domain string */
2808 ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
2809 } else { /* no room so create dummy domain and NOS string */
2810 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2811 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
2813 } else { /* ASCII */
2814 len = strnlen(bcc_ptr, 1024);
2815 if (((long) bcc_ptr + len) -
2816 (long) pByteArea(smb_buffer_response)
2817 <= BCC(smb_buffer_response)) {
2818 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
2819 strncpy(ses->serverOS,bcc_ptr, len);
2822 bcc_ptr[0] = 0; /* null terminate the string */
2825 len = strnlen(bcc_ptr, 1024);
2826 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
2827 strncpy(ses->serverNOS, bcc_ptr, len);
2832 len = strnlen(bcc_ptr, 1024);
2833 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
2834 strncpy(ses->serverDomain, bcc_ptr, len);
2840 ("Variable field of length %d extends beyond end of smb ",
2845 (" Security Blob Length extends beyond end of SMB"));
2848 cERROR(1, ("No session structure passed in."));
2852 (" Invalid Word count %d: ",
2853 smb_buffer_response->WordCount));
2858 cifs_buf_release(smb_buffer);
2864 CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2865 const char *tree, struct cifsTconInfo *tcon,
2866 const struct nls_table *nls_codepage)
2868 struct smb_hdr *smb_buffer;
2869 struct smb_hdr *smb_buffer_response;
2872 unsigned char *bcc_ptr;
2880 smb_buffer = cifs_buf_get();
2881 if (smb_buffer == NULL) {
2884 smb_buffer_response = smb_buffer;
2886 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
2887 NULL /*no tid */ , 4 /*wct */ );
2888 smb_buffer->Uid = ses->Suid;
2889 pSMB = (TCONX_REQ *) smb_buffer;
2890 pSMBr = (TCONX_RSP *) smb_buffer_response;
2892 pSMB->AndXCommand = 0xFF;
2893 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
2894 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
2895 bcc_ptr = &pSMB->Password[0];
2896 bcc_ptr++; /* skip password */
2898 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2899 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2901 if (ses->capabilities & CAP_STATUS32) {
2902 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2904 if (ses->capabilities & CAP_DFS) {
2905 smb_buffer->Flags2 |= SMBFLG2_DFS;
2907 if (ses->capabilities & CAP_UNICODE) {
2908 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2910 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
2911 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
2912 bcc_ptr += 2; /* skip trailing null */
2913 } else { /* ASCII */
2915 strcpy(bcc_ptr, tree);
2916 bcc_ptr += strlen(tree) + 1;
2918 strcpy(bcc_ptr, "?????");
2919 bcc_ptr += strlen("?????");
2921 count = bcc_ptr - &pSMB->Password[0];
2922 pSMB->hdr.smb_buf_length += count;
2923 pSMB->ByteCount = cpu_to_le16(count);
2925 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
2927 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
2928 /* above now done in SendReceive */
2929 if ((rc == 0) && (tcon != NULL)) {
2930 tcon->tidStatus = CifsGood;
2931 tcon->tid = smb_buffer_response->Tid;
2932 bcc_ptr = pByteArea(smb_buffer_response);
2933 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
2934 /* skip service field (NB: this field is always ASCII) */
2935 bcc_ptr += length + 1;
2936 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
2937 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2938 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
2939 if ((bcc_ptr + (2 * length)) -
2940 pByteArea(smb_buffer_response) <=
2941 BCC(smb_buffer_response)) {
2942 if(tcon->nativeFileSystem)
2943 kfree(tcon->nativeFileSystem);
2944 tcon->nativeFileSystem =
2945 kcalloc(1, length + 2, GFP_KERNEL);
2946 cifs_strfromUCS_le(tcon->nativeFileSystem,
2947 (wchar_t *) bcc_ptr,
2948 length, nls_codepage);
2949 bcc_ptr += 2 * length;
2950 bcc_ptr[0] = 0; /* null terminate the string */
2954 /* else do not bother copying these informational fields */
2956 length = strnlen(bcc_ptr, 1024);
2957 if ((bcc_ptr + length) -
2958 pByteArea(smb_buffer_response) <=
2959 BCC(smb_buffer_response)) {
2960 if(tcon->nativeFileSystem)
2961 kfree(tcon->nativeFileSystem);
2962 tcon->nativeFileSystem =
2963 kcalloc(1, length + 1, GFP_KERNEL);
2964 strncpy(tcon->nativeFileSystem, bcc_ptr,
2967 /* else do not bother copying these informational fields */
2969 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
2970 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
2971 } else if ((rc == 0) && tcon == NULL) {
2972 /* all we need to save for IPC$ connection */
2973 ses->ipc_tid = smb_buffer_response->Tid;
2977 cifs_buf_release(smb_buffer);
2982 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
2986 struct cifsSesInfo *ses = NULL;
2987 struct task_struct *cifsd_task;
2991 if (cifs_sb->tcon) {
2992 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
2993 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
2998 tconInfoFree(cifs_sb->tcon);
2999 if ((ses) && (ses->server)) {
3000 /* save off task so we do not refer to ses later */
3001 cifsd_task = ses->server->tsk;
3002 cFYI(1, ("About to do SMBLogoff "));
3003 rc = CIFSSMBLogoff(xid, ses);
3007 } else if (rc == -ESHUTDOWN) {
3008 cFYI(1,("Waking up socket by sending it signal"));
3010 send_sig(SIGKILL,cifsd_task,1);
3012 } /* else - we have an smb session
3013 left on this socket do not kill cifsd */
3015 cFYI(1, ("No session or bad tcon"));
3018 cifs_sb->tcon = NULL;
3020 set_current_state(TASK_INTERRUPTIBLE);
3021 schedule_timeout(HZ / 2);
3027 return rc; /* BB check if we should always return zero here */
3030 int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3031 struct nls_table * nls_info)
3034 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3035 int ntlmv2_flag = FALSE;
3038 /* what if server changes its buffer size after dropping the session? */
3039 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3040 rc = CIFSSMBNegotiate(xid, pSesInfo);
3041 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3042 rc = CIFSSMBNegotiate(xid, pSesInfo);
3047 spin_lock(&GlobalMid_Lock);
3048 if(pSesInfo->server->tcpStatus != CifsExiting)
3049 pSesInfo->server->tcpStatus = CifsGood;
3052 spin_unlock(&GlobalMid_Lock);
3058 pSesInfo->capabilities = pSesInfo->server->capabilities;
3059 if(linuxExtEnabled == 0)
3060 pSesInfo->capabilities &= (~CAP_UNIX);
3061 /* pSesInfo->sequence_number = 0;*/
3062 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3063 pSesInfo->server->secMode,
3064 pSesInfo->server->capabilities,
3065 pSesInfo->server->timeZone));
3066 if (extended_security
3067 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3068 && (pSesInfo->server->secType == NTLMSSP)) {
3069 cFYI(1, ("New style sesssetup "));
3070 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3071 NULL /* security blob */,
3072 0 /* blob length */,
3074 } else if (extended_security
3075 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3076 && (pSesInfo->server->secType == RawNTLMSSP)) {
3077 cFYI(1, ("NTLMSSP sesssetup "));
3078 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3085 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3086 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3091 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3093 CalcNTLMv2_response(pSesInfo,v2_response);
3095 cifs_calculate_ntlmv2_mac_key(
3096 pSesInfo->server->mac_signing_key,
3097 response, ntlm_session_key, */
3099 /* BB Put dummy sig in SessSetup PDU? */
3106 SMBNTencrypt(pSesInfo->password,
3107 pSesInfo->server->cryptKey,
3111 cifs_calculate_mac_key(
3112 pSesInfo->server->mac_signing_key,
3114 pSesInfo->password);
3116 /* for better security the weaker lanman hash not sent
3117 in AuthSessSetup so we no longer calculate it */
3119 rc = CIFSNTLMSSPAuthSessSetup(xid,
3125 } else { /* old style NTLM 0.12 session setup */
3126 SMBNTencrypt(pSesInfo->password,
3127 pSesInfo->server->cryptKey,
3131 cifs_calculate_mac_key(
3132 pSesInfo->server->mac_signing_key,
3133 ntlm_session_key, pSesInfo->password);
3135 rc = CIFSSessSetup(xid, pSesInfo,
3136 ntlm_session_key, nls_info);
3139 cERROR(1,("Send error in SessSetup = %d",rc));
3141 cFYI(1,("CIFS Session Established successfully"));
3142 pSesInfo->status = CifsGood;