4 * Copyright (C) International Business Machines Corp., 2002,2004
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/version.h>
27 #include <linux/ipv6.h>
28 #include <linux/pagemap.h>
29 #include <linux/ctype.h>
30 #include <linux/utsname.h>
31 #include <asm/uaccess.h>
32 #include <asm/processor.h>
35 #include "cifsproto.h"
36 #include "cifs_unicode.h"
37 #include "cifs_debug.h"
38 #include "cifs_fs_sb.h"
41 #include "rfc1002pdu.h"
44 #define RFC1001_PORT 139
46 extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
48 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
50 extern int cifs_inet_pton(int, const char *, void *dst);
58 char *iocharset; /* local code page for mapping to and from Unicode */
59 char source_rfc1001_name[16]; /* netbios name of client */
70 unsigned short int port;
73 static int ipv4_connect(struct sockaddr_in *psin_server,
74 struct socket **csocket,
76 static int ipv6_connect(struct sockaddr_in6 *psin_server,
77 struct socket **csocket);
81 * cifs tcp session reconnection
83 * mark tcp session as reconnecting so temporarily locked
84 * mark all smb sessions as reconnecting for tcp session
85 * reconnect tcp session
86 * wake up waiters on reconnection? - (not needed currently)
90 cifs_reconnect(struct TCP_Server_Info *server)
93 struct list_head *tmp;
94 struct cifsSesInfo *ses;
95 struct cifsTconInfo *tcon;
96 struct mid_q_entry * mid_entry;
98 spin_lock(&GlobalMid_Lock);
99 if(server->tcpStatus == CifsExiting) {
100 /* the demux thread will exit normally
101 next time through the loop */
102 spin_unlock(&GlobalMid_Lock);
105 server->tcpStatus = CifsNeedReconnect;
106 spin_unlock(&GlobalMid_Lock);
109 cFYI(1, ("Reconnecting tcp session "));
111 /* before reconnecting the tcp session, mark the smb session (uid)
112 and the tid bad so they are not used until reconnected */
113 read_lock(&GlobalSMBSeslock);
114 list_for_each(tmp, &GlobalSMBSessionList) {
115 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
117 if (ses->server == server) {
118 ses->status = CifsNeedReconnect;
122 /* else tcp and smb sessions need reconnection */
124 list_for_each(tmp, &GlobalTreeConnectionList) {
125 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
126 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
127 tcon->tidStatus = CifsNeedReconnect;
130 read_unlock(&GlobalSMBSeslock);
131 /* do not want to be sending data on a socket we are freeing */
132 down(&server->tcpSem);
133 if(server->ssocket) {
134 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
135 server->ssocket->flags));
136 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
137 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
138 server->ssocket->flags));
139 sock_release(server->ssocket);
140 server->ssocket = NULL;
143 spin_lock(&GlobalMid_Lock);
144 list_for_each(tmp, &server->pending_mid_q) {
145 mid_entry = list_entry(tmp, struct
149 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
150 /* Mark other intransit requests as needing retry so
151 we do not immediately mark the session bad again
152 (ie after we reconnect below) as they timeout too */
153 mid_entry->midState = MID_RETRY_NEEDED;
157 spin_unlock(&GlobalMid_Lock);
160 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
162 if(server->protocolType == IPV6) {
163 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
165 rc = ipv4_connect(&server->addr.sockAddr,
167 server->workstation_RFC1001_name);
170 set_current_state(TASK_INTERRUPTIBLE);
171 schedule_timeout(3 * HZ);
173 atomic_inc(&tcpSesReconnectCount);
174 spin_lock(&GlobalMid_Lock);
175 if(server->tcpStatus != CifsExiting)
176 server->tcpStatus = CifsGood;
177 spin_unlock(&GlobalMid_Lock);
178 atomic_set(&server->inFlight,0);
179 wake_up(&server->response_q);
186 cifs_demultiplex_thread(struct TCP_Server_Info *server)
189 unsigned int pdu_length, total_read;
190 struct smb_hdr *smb_buffer = NULL;
191 struct msghdr smb_msg;
192 mm_segment_t temp_fs;
194 struct socket *csocket = server->ssocket;
195 struct list_head *tmp;
196 struct cifsSesInfo *ses;
197 struct task_struct *task_to_wake = NULL;
198 struct mid_q_entry *mid_entry;
202 allow_signal(SIGKILL);
203 current->flags |= PF_MEMALLOC;
204 server->tsk = current; /* save process info to wake at shutdown */
205 cFYI(1, ("Demultiplex PID: %d", current->pid));
207 temp_fs = get_fs(); /* we must turn off socket api parm checking */
210 while (server->tcpStatus != CifsExiting) {
211 if (smb_buffer == NULL)
212 smb_buffer = cifs_buf_get();
214 memset(smb_buffer, 0, sizeof (struct smb_hdr));
216 if (smb_buffer == NULL) {
217 cERROR(1,("Can not get memory for SMB response"));
218 set_current_state(TASK_INTERRUPTIBLE);
219 schedule_timeout(HZ * 3); /* give system time to free memory */
222 iov.iov_base = smb_buffer;
223 iov.iov_len = sizeof (struct smb_hdr) - 1;
224 /* 1 byte less above since wct is not always returned in error cases */
225 smb_msg.msg_iov = &iov;
226 smb_msg.msg_iovlen = 1;
227 smb_msg.msg_control = NULL;
228 smb_msg.msg_controllen = 0;
231 sock_recvmsg(csocket, &smb_msg,
232 sizeof (struct smb_hdr) -
233 1 /* RFC1001 header and SMB header */ ,
234 MSG_PEEK /* flags see socket.h */ );
236 if(server->tcpStatus == CifsExiting) {
238 } else if (server->tcpStatus == CifsNeedReconnect) {
239 cFYI(1,("Reconnecting after server stopped responding"));
240 cifs_reconnect(server);
241 cFYI(1,("call to reconnect done"));
242 csocket = server->ssocket;
244 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
245 set_current_state(TASK_INTERRUPTIBLE);
246 schedule_timeout(1); /* minimum sleep to prevent looping
247 allowing socket to clear and app threads to set
248 tcpStatus CifsNeedReconnect if server hung */
250 } else if (length <= 0) {
251 if(server->tcpStatus == CifsNew) {
252 cFYI(1,("tcp session abended prematurely (after SMBnegprot)"));
253 /* some servers kill tcp session rather than returning
254 smb negprot error in which case reconnecting here is
255 not going to help - return error to mount */
256 spin_lock(&GlobalMid_Lock);
257 server->tcpStatus = CifsExiting;
258 spin_unlock(&GlobalMid_Lock);
259 wake_up(&server->response_q);
263 cFYI(1,("Reconnecting after unexpected peek error %d",length));
264 cifs_reconnect(server);
265 csocket = server->ssocket;
266 wake_up(&server->response_q);
270 pdu_length = 4 + ntohl(smb_buffer->smb_buf_length);
271 /* Ony read pdu_length after below checks for too short (due
272 to e.g. int overflow) and too long ie beyond end of buf */
273 cFYI(1, ("Peek length rcvd: 0x%x beginning 0x%x)", length, pdu_length));
275 temp = (char *) smb_buffer;
277 if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
278 iov.iov_base = smb_buffer;
280 length = sock_recvmsg(csocket, &smb_msg, 4, 0);
281 cFYI(0,("Received 4 byte keep alive packet"));
282 } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
283 iov.iov_base = smb_buffer;
285 length = sock_recvmsg(csocket, &smb_msg, 4, 0);
286 cFYI(1,("Good RFC 1002 session rsp"));
287 } else if ((temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE)
289 /* we get this from Windows 98 instead of error on SMB negprot response */
290 cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
291 if(server->tcpStatus == CifsNew) {
292 /* if nack on negprot (rather than
293 ret of smb negprot error) reconnecting
294 not going to help, ret error to mount */
295 spin_lock(&GlobalMid_Lock);
296 server->tcpStatus = CifsExiting;
297 spin_unlock(&GlobalMid_Lock);
298 /* wake up thread doing negprot */
299 wake_up(&server->response_q);
302 /* give server a second to
303 clean up before reconnect attempt */
304 set_current_state(TASK_INTERRUPTIBLE);
305 schedule_timeout(HZ);
306 /* always try 445 first on reconnect
307 since we get NACK on some if we ever
308 connected to port 139 (the NACK is
309 since we do not begin with RFC1001
310 session initialize frame) */
311 server->addr.sockAddr.sin_port = CIFS_PORT;
312 cifs_reconnect(server);
313 csocket = server->ssocket;
314 wake_up(&server->response_q);
317 } else if (temp[0] != (char) 0) {
318 cERROR(1,("Unknown RFC 1002 frame"));
319 cifs_dump_mem(" Received Data: ", temp, length);
320 cifs_reconnect(server);
321 csocket = server->ssocket;
324 if ((length != sizeof (struct smb_hdr) - 1)
326 CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)
328 sizeof (struct smb_hdr) - 1)
331 (smb_buffer, smb_buffer->Mid))) {
333 ("Invalid size or format for SMB found with length %d and pdu_lenght %d",
334 length, pdu_length));
335 cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
336 /* could we fix this network corruption by finding next
337 smb header (instead of killing the session) and
338 restart reading from next valid SMB found? */
339 cifs_reconnect(server);
340 csocket = server->ssocket;
342 } else { /* length ok */
345 iov.iov_base = smb_buffer;
346 iov.iov_len = pdu_length;
348 total_read < pdu_length;
349 total_read += length) {
350 length = sock_recvmsg(csocket, &smb_msg,
351 pdu_length - total_read, 0);
354 ("Zero length receive when expecting %d ",
355 pdu_length - total_read));
356 cifs_reconnect(server);
357 csocket = server->ssocket;
363 dump_smb(smb_buffer, length);
365 (smb_buffer, smb_buffer->Mid, total_read)) {
366 cERROR(1, ("Bad SMB Received "));
371 spin_lock(&GlobalMid_Lock);
372 list_for_each(tmp, &server->pending_mid_q) {
373 mid_entry = list_entry(tmp, struct
377 if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
379 (" Mid 0x%x matched - waking up ",mid_entry->mid));
380 task_to_wake = mid_entry->tsk;
381 mid_entry->resp_buf =
383 mid_entry->midState =
384 MID_RESPONSE_RECEIVED;
387 spin_unlock(&GlobalMid_Lock);
389 smb_buffer = NULL; /* will be freed by users thread after he is done */
390 wake_up_process(task_to_wake);
391 } else if (is_valid_oplock_break(smb_buffer) == FALSE) {
392 cERROR(1, ("No task to wake, unknown frame rcvd!"));
393 cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
398 ("Frame less than four bytes received %d bytes long.",
401 length = sock_recvmsg(csocket, &smb_msg, length, 0); /* throw away junk frame */
403 (" with junk 0x%x in it ",
404 *(__u32 *) smb_buffer));
408 spin_lock(&GlobalMid_Lock);
409 server->tcpStatus = CifsExiting;
410 spin_unlock(&GlobalMid_Lock);
411 atomic_set(&server->inFlight, 0);
412 /* Although there should not be any requests blocked on
413 this queue it can not hurt to be paranoid and try to wake up requests
414 that may haven been blocked when more than 50 at time were on the wire
415 to the same server - they now will see the session is in exit state
416 and get out of SendReceive. */
417 wake_up_all(&server->request_q);
419 if(server->ssocket) {
420 sock_release(csocket);
421 server->ssocket = NULL;
424 if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */
425 cifs_buf_release(smb_buffer);
427 read_lock(&GlobalSMBSeslock);
428 if (list_empty(&server->pending_mid_q)) {
429 /* loop through server session structures attached to this and mark them dead */
430 list_for_each(tmp, &GlobalSMBSessionList) {
432 list_entry(tmp, struct cifsSesInfo,
434 if (ses->server == server) {
435 ses->status = CifsExiting;
439 read_unlock(&GlobalSMBSeslock);
441 spin_lock(&GlobalMid_Lock);
442 list_for_each(tmp, &server->pending_mid_q) {
443 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
444 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
446 (" Clearing Mid 0x%x - waking up ",mid_entry->mid));
447 task_to_wake = mid_entry->tsk;
449 wake_up_process(task_to_wake);
453 spin_unlock(&GlobalMid_Lock);
454 read_unlock(&GlobalSMBSeslock);
455 set_current_state(TASK_INTERRUPTIBLE);
456 /* 1/8th of sec should be more than enough time for them to exit */
457 schedule_timeout(HZ/8);
460 if (list_empty(&server->pending_mid_q)) {
461 /* mpx threads have not exited yet give them
462 at least the smb send timeout time for long ops */
463 cFYI(1, ("Wait for exit from demultiplex thread"));
464 set_current_state(TASK_INTERRUPTIBLE);
465 schedule_timeout(46 * HZ);
466 /* if threads still have not exited they are probably never
467 coming home not much else we can do but free the memory */
471 cFYI(1, ("About to exit from demultiplex thread"));
476 cifs_kcalloc(size_t size, int type)
479 addr = kmalloc(size, type);
481 memset(addr, 0, size);
486 cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol)
490 unsigned int temp_len, i, j;
496 memset(vol->source_rfc1001_name,0x20,15);
497 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
498 /* does not have to be a perfect mapping since the field is
499 informational, only used for servers that do not support
500 port 445 and it can be overridden at mount time */
501 vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]);
503 vol->source_rfc1001_name[15] = 0;
505 vol->linux_uid = current->uid; /* current->euid instead? */
506 vol->linux_gid = current->gid;
507 vol->dir_mode = S_IRWXUGO;
508 /* 2767 perms indicate mandatory locking support */
509 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
511 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
517 if(strncmp(options,"sep=",4) == 0) {
518 if(options[4] != 0) {
519 separator[0] = options[4];
522 cFYI(1,("Null separator not allowed"));
526 while ((data = strsep(&options, separator)) != NULL) {
529 if ((value = strchr(data, '=')) != NULL)
531 if (strnicmp(data, "user", 4) == 0) {
532 if (!value || !*value) {
534 "CIFS: invalid or missing username\n");
535 return 1; /* needs_arg; */
537 if (strnlen(value, 200) < 200) {
538 vol->username = value;
540 printk(KERN_WARNING "CIFS: username too long\n");
543 } else if (strnicmp(data, "pass", 4) == 0) {
544 if (!value || !*value) {
545 vol->password = NULL;
548 temp_len = strlen(value);
549 /* removed password length check, NTLM passwords
550 can be arbitrarily long */
552 /* if comma in password, the string will be
553 prematurely null terminated. Commas in password are
554 specified across the cifs mount interface by a double
555 comma ie ,, and a comma used as in other cases ie ','
556 as a parameter delimiter/separator is single and due
557 to the strsep above is temporarily zeroed. */
559 /* NB: password legally can have multiple commas and
560 the only illegal character in a password is null */
562 if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) {
564 value[temp_len] = separator[0];
565 temp_len+=2; /* move after the second comma */
566 while(value[temp_len] != 0) {
567 if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) {
568 /* single comma indicating start of next parm */
573 if(value[temp_len] == 0) {
577 /* move options to point to start of next parm */
578 options = value + temp_len + 1;
580 /* go from value to (value + temp_len) condensing double commas to singles */
581 vol->password = cifs_kcalloc(temp_len, GFP_KERNEL);
582 for(i=0,j=0;i<temp_len;i++,j++) {
583 vol->password[j] = value[i];
584 if(value[i] == separator[0] && value[i+1] == separator[0]) {
585 /* skip second comma */
589 /* value[temp_len] is zeroed above so
590 vol->password[temp_len] guaranteed to be null */
592 vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL);
593 strcpy(vol->password, value);
595 } else if (strnicmp(data, "ip", 2) == 0) {
596 if (!value || !*value) {
598 } else if (strnlen(value, 35) < 35) {
601 printk(KERN_WARNING "CIFS: ip address too long\n");
604 } else if ((strnicmp(data, "unc", 3) == 0)
605 || (strnicmp(data, "target", 6) == 0)
606 || (strnicmp(data, "path", 4) == 0)) {
607 if (!value || !*value) {
609 "CIFS: invalid path to network resource\n");
610 return 1; /* needs_arg; */
612 if ((temp_len = strnlen(value, 300)) < 300) {
613 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
616 strcpy(vol->UNC,value);
617 if (strncmp(vol->UNC, "//", 2) == 0) {
620 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
622 "CIFS: UNC Path does not begin with // or \\\\ \n");
626 printk(KERN_WARNING "CIFS: UNC name too long\n");
629 } else if ((strnicmp(data, "domain", 3) == 0)
630 || (strnicmp(data, "workgroup", 5) == 0)) {
631 if (!value || !*value) {
632 printk(KERN_WARNING "CIFS: invalid domain name\n");
633 return 1; /* needs_arg; */
635 /* BB are there cases in which a comma can be valid in
636 a domain name and need special handling? */
637 if (strnlen(value, 65) < 65) {
638 vol->domainname = value;
639 cFYI(1, ("Domain name set"));
641 printk(KERN_WARNING "CIFS: domain name too long\n");
644 } else if (strnicmp(data, "iocharset", 9) == 0) {
645 if (!value || !*value) {
646 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
647 return 1; /* needs_arg; */
649 if (strnlen(value, 65) < 65) {
650 if(strnicmp(value,"default",7))
651 vol->iocharset = value;
652 /* if iocharset not set load_nls_default used by caller */
653 cFYI(1, ("iocharset set to %s",value));
655 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
658 } else if (strnicmp(data, "uid", 3) == 0) {
659 if (value && *value) {
661 simple_strtoul(value, &value, 0);
663 } else if (strnicmp(data, "gid", 3) == 0) {
664 if (value && *value) {
666 simple_strtoul(value, &value, 0);
668 } else if (strnicmp(data, "file_mode", 4) == 0) {
669 if (value && *value) {
671 simple_strtoul(value, &value, 0);
673 } else if (strnicmp(data, "dir_mode", 3) == 0) {
674 if (value && *value) {
676 simple_strtoul(value, &value, 0);
678 } else if (strnicmp(data, "port", 4) == 0) {
679 if (value && *value) {
681 simple_strtoul(value, &value, 0);
683 } else if (strnicmp(data, "rsize", 5) == 0) {
684 if (value && *value) {
686 simple_strtoul(value, &value, 0);
688 } else if (strnicmp(data, "wsize", 5) == 0) {
689 if (value && *value) {
691 simple_strtoul(value, &value, 0);
693 } else if (strnicmp(data, "sockopt", 5) == 0) {
694 if (value && *value) {
696 simple_strtoul(value, &value, 0);
698 } else if (strnicmp(data, "netbiosname", 4) == 0) {
699 if (!value || !*value || (*value == ' ')) {
700 cFYI(1,("invalid (empty) netbiosname specified"));
702 memset(vol->source_rfc1001_name,0x20,15);
704 /* BB are there cases in which a comma can be
705 valid in this workstation netbios name (and need
706 special handling)? */
708 /* We do not uppercase netbiosname for user */
712 vol->source_rfc1001_name[i] = value[i];
714 /* The string has 16th byte zero still from
715 set at top of the function */
716 if((i==15) && (value[i] != 0))
717 printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
719 } else if (strnicmp(data, "version", 3) == 0) {
721 } else if (strnicmp(data, "rw", 2) == 0) {
723 } else if ((strnicmp(data, "suid", 4) == 0) ||
724 (strnicmp(data, "nosuid", 6) == 0) ||
725 (strnicmp(data, "exec", 4) == 0) ||
726 (strnicmp(data, "noexec", 6) == 0) ||
727 (strnicmp(data, "nodev", 5) == 0) ||
728 (strnicmp(data, "noauto", 6) == 0) ||
729 (strnicmp(data, "dev", 3) == 0)) {
730 /* The mount tool or mount.cifs helper (if present)
731 uses these opts to set flags, and the flags are read
732 by the kernel vfs layer before we get here (ie
733 before read super) so there is no point trying to
734 parse these options again and set anything and it
735 is ok to just ignore them */
737 } else if (strnicmp(data, "ro", 2) == 0) {
739 } else if (strnicmp(data, "hard", 4) == 0) {
741 } else if (strnicmp(data, "soft", 4) == 0) {
743 } else if (strnicmp(data, "nohard", 6) == 0) {
745 } else if (strnicmp(data, "nosoft", 6) == 0) {
747 } else if (strnicmp(data, "nointr", 6) == 0) {
749 } else if (strnicmp(data, "intr", 4) == 0) {
751 } else if (strnicmp(data, "noac", 4) == 0) {
752 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
754 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
756 if (vol->UNC == NULL) {
757 if(devname == NULL) {
758 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
761 if ((temp_len = strnlen(devname, 300)) < 300) {
762 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
765 strcpy(vol->UNC,devname);
766 if (strncmp(vol->UNC, "//", 2) == 0) {
769 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
770 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
774 printk(KERN_WARNING "CIFS: UNC name too long\n");
779 vol->UNCip = &vol->UNC[2];
784 static struct cifsSesInfo *
785 cifs_find_tcp_session(__u32 new_target_ip_addr,
786 char *userName, struct TCP_Server_Info **psrvTcp)
788 struct list_head *tmp;
789 struct cifsSesInfo *ses;
792 read_lock(&GlobalSMBSeslock);
793 list_for_each(tmp, &GlobalSMBSessionList) {
794 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
796 if (ses->server->addr.sockAddr.sin_addr.s_addr ==
797 new_target_ip_addr) {
798 /* BB lock server and tcp session and increment use count here?? */
799 *psrvTcp = ses->server; /* found a match on the TCP session */
800 /* BB check if reconnection needed */
802 (ses->userName, userName,
803 MAX_USERNAME_SIZE) == 0){
804 read_unlock(&GlobalSMBSeslock);
805 return ses; /* found exact match on both tcp and SMB sessions */
809 /* else tcp and smb sessions need reconnection */
811 read_unlock(&GlobalSMBSeslock);
815 static struct cifsTconInfo *
816 find_unc(__u32 new_target_ip_addr, char *uncName, char *userName)
818 struct list_head *tmp;
819 struct cifsTconInfo *tcon;
821 read_lock(&GlobalSMBSeslock);
822 list_for_each(tmp, &GlobalTreeConnectionList) {
823 cFYI(1, ("Next tcon - "));
824 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
826 if (tcon->ses->server) {
828 (" old ip addr: %x == new ip %x ?",
829 tcon->ses->server->addr.sockAddr.sin_addr.
830 s_addr, new_target_ip_addr));
831 if (tcon->ses->server->addr.sockAddr.sin_addr.
832 s_addr == new_target_ip_addr) {
833 /* BB lock tcon and server and tcp session and increment use count here? */
834 /* found a match on the TCP session */
835 /* BB check if reconnection needed */
836 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
837 tcon->treeName, uncName));
839 (tcon->treeName, uncName,
840 MAX_TREE_SIZE) == 0) {
842 ("Matched UNC, old user: %s == new: %s ?",
843 tcon->treeName, uncName));
845 (tcon->ses->userName,
847 MAX_USERNAME_SIZE) == 0) {
848 read_unlock(&GlobalSMBSeslock);
849 return tcon;/* also matched user (smb session)*/
856 read_unlock(&GlobalSMBSeslock);
861 connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
862 const char *old_path, const struct nls_table *nls_codepage)
864 unsigned char *referrals = NULL;
865 unsigned int num_referrals;
868 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
869 &num_referrals, &referrals);
871 /* BB Add in code to: if valid refrl, if not ip address contact
872 the helper that resolves tcp names, mount to it, try to
873 tcon to it unmount it if fail */
882 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
883 const char *old_path, const struct nls_table *nls_codepage,
884 unsigned int *pnum_referrals, unsigned char ** preferrals)
891 if (pSesInfo->ipc_tid == 0) {
892 temp_unc = kmalloc(2 /* for slashes */ +
893 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
894 + 1 + 4 /* slash IPC$ */ + 2,
896 if (temp_unc == NULL)
900 strcpy(temp_unc + 2, pSesInfo->serverName);
901 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
902 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
904 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
908 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
909 pnum_referrals, nls_codepage);
914 /* See RFC1001 section 14 on representation of Netbios names */
915 static void rfc1002mangle(char * target,char * source, unsigned int length)
919 for(i=0,j=0;i<(length);i++) {
920 /* mask a nibble at a time and encode */
921 target[j] = 'A' + (0x0F & (source[i] >> 4));
922 target[j+1] = 'A' + (0x0F & source[i]);
930 ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
935 unsigned short int orig_port = 0;
937 if(*csocket == NULL) {
938 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
940 cERROR(1, ("Error %d creating socket",rc));
944 /* BB other socket options to set KEEPALIVE, NODELAY? */
945 cFYI(1,("Socket created"));
946 (*csocket)->sk->sk_allocation = GFP_NOFS;
950 psin_server->sin_family = AF_INET;
951 if(psin_server->sin_port) { /* user overrode default port */
952 rc = (*csocket)->ops->connect(*csocket,
953 (struct sockaddr *) psin_server,
954 sizeof (struct sockaddr_in),0);
960 /* save original port so we can retry user specified port
961 later if fall back ports fail this time */
962 orig_port = psin_server->sin_port;
964 /* do not retry on the same port we just failed on */
965 if(psin_server->sin_port != htons(CIFS_PORT)) {
966 psin_server->sin_port = htons(CIFS_PORT);
968 rc = (*csocket)->ops->connect(*csocket,
969 (struct sockaddr *) psin_server,
970 sizeof (struct sockaddr_in),0);
976 psin_server->sin_port = htons(RFC1001_PORT);
977 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
978 psin_server, sizeof (struct sockaddr_in),0);
983 /* give up here - unless we want to retry on different
984 protocol families some day */
987 psin_server->sin_port = orig_port;
988 cFYI(1,("Error %d connecting to server via ipv4",rc));
989 sock_release(*csocket);
993 /* Eventually check for other socket options to change from
994 the default. sock_setsockopt not used because it expects
996 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
998 /* send RFC1001 sessinit */
1000 if(psin_server->sin_port == htons(139)) {
1001 /* some servers require RFC1001 sessinit before sending
1002 negprot - BB check reconnection in case where second
1003 sessinit is sent but no second negprot */
1004 struct rfc1002_session_packet * ses_init_buf;
1005 struct smb_hdr * smb_buf;
1006 ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
1008 ses_init_buf->trailer.session_req.called_len = 32;
1009 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1010 DEFAULT_CIFS_CALLED_NAME,16);
1011 ses_init_buf->trailer.session_req.calling_len = 32;
1012 /* calling name ends in null (byte 16) from old smb
1014 if(netbios_name && (netbios_name[0] !=0)) {
1015 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1018 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1019 "LINUX_CIFS_CLNT",16);
1021 ses_init_buf->trailer.session_req.scope1 = 0;
1022 ses_init_buf->trailer.session_req.scope2 = 0;
1023 smb_buf = (struct smb_hdr *)ses_init_buf;
1024 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1025 smb_buf->smb_buf_length = 0x81000044;
1026 rc = smb_send(*csocket, smb_buf, 0x44,
1027 (struct sockaddr *)psin_server);
1028 kfree(ses_init_buf);
1030 /* else the negprot may still work without this
1031 even though malloc failed */
1039 ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1044 if(*csocket == NULL) {
1045 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1047 cERROR(1, ("Error %d creating ipv6 socket",rc));
1051 /* BB other socket options to set KEEPALIVE, NODELAY? */
1052 cFYI(1,("ipv6 Socket created"));
1053 (*csocket)->sk->sk_allocation = GFP_NOFS;
1057 psin_server->sin6_family = AF_INET6;
1059 if(psin_server->sin6_port) { /* user overrode default port */
1060 rc = (*csocket)->ops->connect(*csocket,
1061 (struct sockaddr *) psin_server,
1062 sizeof (struct sockaddr_in6),0);
1068 /* do not retry on the same port we just failed on */
1069 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1070 psin_server->sin6_port = htons(CIFS_PORT);
1072 rc = (*csocket)->ops->connect(*csocket,
1073 (struct sockaddr *) psin_server,
1074 sizeof (struct sockaddr_in6),0);
1080 psin_server->sin6_port = htons(RFC1001_PORT);
1081 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1082 psin_server, sizeof (struct sockaddr_in6),0);
1087 /* give up here - unless we want to retry on different
1088 protocol families some day */
1090 cFYI(1,("Error %d connecting to server via ipv6",rc));
1091 sock_release(*csocket);
1095 /* Eventually check for other socket options to change from
1096 the default. sock_setsockopt not used because it expects
1097 user space buffer */
1098 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1104 cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1105 char *mount_data, const char *devname)
1109 struct socket *csocket = NULL;
1110 struct sockaddr_in sin_server;
1111 struct sockaddr_in6 sin_server6;
1112 struct smb_vol volume_info;
1113 struct cifsSesInfo *pSesInfo = NULL;
1114 struct cifsSesInfo *existingCifsSes = NULL;
1115 struct cifsTconInfo *tcon = NULL;
1116 struct TCP_Server_Info *srvTcp = NULL;
1120 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1122 memset(&volume_info,0,sizeof(struct smb_vol));
1123 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1125 kfree(volume_info.UNC);
1126 if(volume_info.password)
1127 kfree(volume_info.password);
1132 if (volume_info.username) {
1133 cFYI(1, ("Username: %s ", volume_info.username));
1136 cifserror("No username specified ");
1137 /* In userspace mount helper we can get user name from alternate
1138 locations such as env variables and files on disk */
1140 kfree(volume_info.UNC);
1141 if(volume_info.password)
1142 kfree(volume_info.password);
1147 if (volume_info.UNCip && volume_info.UNC) {
1148 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1151 /* not ipv4 address, try ipv6 */
1152 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1156 /* we failed translating address */
1158 kfree(volume_info.UNC);
1159 if(volume_info.password)
1160 kfree(volume_info.password);
1165 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1168 } else if (volume_info.UNCip){
1169 /* BB using ip addr as server name connect to the DFS root below */
1170 cERROR(1,("Connecting to DFS root not implemented yet"));
1172 kfree(volume_info.UNC);
1173 if(volume_info.password)
1174 kfree(volume_info.password);
1177 } else /* which servers DFS root would we conect to */ {
1179 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1181 kfree(volume_info.UNC);
1182 if(volume_info.password)
1183 kfree(volume_info.password);
1188 /* this is needed for ASCII cp to Unicode converts */
1189 if(volume_info.iocharset == NULL) {
1190 cifs_sb->local_nls = load_nls_default();
1191 /* load_nls_default can not return null */
1193 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1194 if(cifs_sb->local_nls == NULL) {
1195 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1197 kfree(volume_info.UNC);
1198 if(volume_info.password)
1199 kfree(volume_info.password);
1206 cifs_find_tcp_session(sin_server.sin_addr.s_addr,
1207 volume_info.username, &srvTcp);
1209 cFYI(1, ("Existing tcp session with server found "));
1210 } else { /* create socket */
1211 if(volume_info.port)
1212 sin_server.sin_port = htons(volume_info.port);
1214 sin_server.sin_port = 0;
1215 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1218 ("Error connecting to IPv4 socket. Aborting operation"));
1220 sock_release(csocket);
1222 kfree(volume_info.UNC);
1223 if(volume_info.password)
1224 kfree(volume_info.password);
1229 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1230 if (srvTcp == NULL) {
1232 sock_release(csocket);
1234 kfree(volume_info.UNC);
1235 if(volume_info.password)
1236 kfree(volume_info.password);
1240 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1241 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1242 atomic_set(&srvTcp->inFlight,0);
1243 /* BB Add code for ipv6 case too */
1244 srvTcp->ssocket = csocket;
1245 srvTcp->protocolType = IPV4;
1246 init_waitqueue_head(&srvTcp->response_q);
1247 init_waitqueue_head(&srvTcp->request_q);
1248 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1249 /* at this point we are the only ones with the pointer
1250 to the struct since the kernel thread not created yet
1251 so no need to spinlock this init of tcpStatus */
1252 srvTcp->tcpStatus = CifsNew;
1253 init_MUTEX(&srvTcp->tcpSem);
1254 kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1255 CLONE_FS | CLONE_FILES | CLONE_VM);
1256 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
1260 if (existingCifsSes) {
1261 pSesInfo = existingCifsSes;
1262 cFYI(1, ("Existing smb sess found "));
1263 if(volume_info.password)
1264 kfree(volume_info.password);
1265 /* volume_info.UNC freed at end of function */
1267 cFYI(1, ("Existing smb sess not found "));
1268 pSesInfo = sesInfoAlloc();
1269 if (pSesInfo == NULL)
1272 pSesInfo->server = srvTcp;
1273 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1274 NIPQUAD(sin_server.sin_addr.s_addr));
1278 /* volume_info.password freed at unmount */
1279 if (volume_info.password)
1280 pSesInfo->password = volume_info.password;
1281 if (volume_info.username)
1282 strncpy(pSesInfo->userName,
1283 volume_info.username,MAX_USERNAME_SIZE);
1284 if (volume_info.domainname)
1285 strncpy(pSesInfo->domainName,
1286 volume_info.domainname,MAX_USERNAME_SIZE);
1287 pSesInfo->linux_uid = volume_info.linux_uid;
1288 down(&pSesInfo->sesSem);
1289 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1290 up(&pSesInfo->sesSem);
1292 atomic_inc(&srvTcp->socketUseCount);
1294 if(volume_info.password)
1295 kfree(volume_info.password);
1298 /* search for existing tcon to this server share */
1300 if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
1301 cifs_sb->rsize = volume_info.rsize;
1303 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1304 if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
1305 cifs_sb->wsize = volume_info.wsize;
1307 cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1308 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1309 cifs_sb->rsize = PAGE_CACHE_SIZE;
1310 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1312 cifs_sb->mnt_uid = volume_info.linux_uid;
1313 cifs_sb->mnt_gid = volume_info.linux_gid;
1314 cifs_sb->mnt_file_mode = volume_info.file_mode;
1315 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1316 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1318 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1319 volume_info.username);
1321 cFYI(1, ("Found match on UNC path "));
1322 /* we can have only one retry value for a connection
1323 to a share so for resources mounted more than once
1324 to the same server share the last value passed in
1325 for the retry flag is used */
1326 tcon->retry = volume_info.retry;
1328 tcon = tconInfoAlloc();
1332 /* check for null share name ie connect to dfs root */
1334 /* BB check if this works for exactly length three strings */
1335 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1336 && (strchr(volume_info.UNC + 3, '/') ==
1338 rc = connect_to_dfs_path(xid,
1344 kfree(volume_info.UNC);
1348 rc = CIFSTCon(xid, pSesInfo,
1350 tcon, cifs_sb->local_nls);
1351 cFYI(1, ("CIFS Tcon rc = %d", rc));
1354 atomic_inc(&pSesInfo->inUse);
1355 tcon->retry = volume_info.retry;
1360 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1361 cFYI(0, ("Large files supported "));
1362 sb->s_maxbytes = (u64) 1 << 63;
1364 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1366 /* on error free sesinfo and tcon struct if needed */
1368 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1369 spin_lock(&GlobalMid_Lock);
1370 srvTcp->tcpStatus = CifsExiting;
1371 spin_unlock(&GlobalMid_Lock);
1373 /* If find_unc succeeded then rc == 0 so we can not end */
1374 if (tcon) /* up here accidently freeing someone elses tcon struct */
1376 if (existingCifsSes == 0) {
1378 if (pSesInfo->server) {
1380 CIFSSMBLogoff(xid, pSesInfo);
1381 if(pSesInfo->server->tsk)
1382 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1383 set_current_state(TASK_INTERRUPTIBLE);
1384 schedule_timeout(HZ / 4); /* give captive thread time to exit */
1386 cFYI(1, ("No session or bad tcon"));
1387 sesInfoFree(pSesInfo);
1388 /* pSesInfo = NULL; */
1392 atomic_inc(&tcon->useCount);
1393 cifs_sb->tcon = tcon;
1394 tcon->ses = pSesInfo;
1396 /* do not care if following two calls succeed - informational only */
1397 CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
1398 CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
1399 if (tcon->ses->capabilities & CAP_UNIX)
1400 CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls);
1403 /* volume_info.password is freed above when existing session found
1404 (in which case it is not needed anymore) but when new sesion is created
1405 the password ptr is put in the new session structure (in which case the
1406 password will be freed at unmount time) */
1408 kfree(volume_info.UNC);
1414 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1415 char session_key[CIFS_SESSION_KEY_SIZE],
1416 const struct nls_table *nls_codepage)
1418 struct smb_hdr *smb_buffer;
1419 struct smb_hdr *smb_buffer_response;
1420 SESSION_SETUP_ANDX *pSMB;
1421 SESSION_SETUP_ANDX *pSMBr;
1423 char *user = ses->userName;
1424 char *domain = ses->domainName;
1426 int remaining_words = 0;
1427 int bytes_returned = 0;
1430 cFYI(1, ("In sesssetup "));
1432 smb_buffer = cifs_buf_get();
1433 if (smb_buffer == 0) {
1436 smb_buffer_response = smb_buffer;
1437 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1439 /* send SMBsessionSetup here */
1440 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1441 0 /* no tCon exists yet */ , 13 /* wct */ );
1443 pSMB->req_no_secext.AndXCommand = 0xFF;
1444 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1445 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1447 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1448 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1450 pSMB->req_no_secext.Capabilities =
1451 CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS;
1452 if (ses->capabilities & CAP_UNICODE) {
1453 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1454 pSMB->req_no_secext.Capabilities |= CAP_UNICODE;
1456 if (ses->capabilities & CAP_STATUS32) {
1457 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1458 pSMB->req_no_secext.Capabilities |= CAP_STATUS32;
1460 if (ses->capabilities & CAP_DFS) {
1461 smb_buffer->Flags2 |= SMBFLG2_DFS;
1462 pSMB->req_no_secext.Capabilities |= CAP_DFS;
1464 pSMB->req_no_secext.Capabilities =
1465 cpu_to_le32(pSMB->req_no_secext.Capabilities);
1466 /* pSMB->req_no_secext.CaseInsensitivePasswordLength =
1467 CIFS_SESSION_KEY_SIZE; */
1468 pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
1469 pSMB->req_no_secext.CaseSensitivePasswordLength =
1470 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1471 bcc_ptr = pByteArea(smb_buffer);
1472 /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE);
1473 bcc_ptr += CIFS_SESSION_KEY_SIZE; */
1474 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1475 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1477 if (ses->capabilities & CAP_UNICODE) {
1478 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1483 bytes_returned = 0; /* skill null user */
1486 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1488 bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */
1489 bcc_ptr += 2; /* trailing null */
1492 cifs_strtoUCS((wchar_t *) bcc_ptr,
1493 "CIFS_LINUX_DOM", 32, nls_codepage);
1496 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1498 bcc_ptr += 2 * bytes_returned;
1501 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1503 bcc_ptr += 2 * bytes_returned;
1505 cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
1507 bcc_ptr += 2 * bytes_returned;
1510 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1512 bcc_ptr += 2 * bytes_returned;
1516 strncpy(bcc_ptr, user, 200);
1517 bcc_ptr += strnlen(user, 200);
1521 if (domain == NULL) {
1522 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1523 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1525 strncpy(bcc_ptr, domain, 64);
1526 bcc_ptr += strnlen(domain, 64);
1530 strcpy(bcc_ptr, "Linux version ");
1531 bcc_ptr += strlen("Linux version ");
1532 strcpy(bcc_ptr, UTS_RELEASE);
1533 bcc_ptr += strlen(UTS_RELEASE) + 1;
1534 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1535 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1537 BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1538 smb_buffer->smb_buf_length += BCC(smb_buffer);
1539 BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
1541 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1542 &bytes_returned, 1);
1544 /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1545 } else if ((smb_buffer_response->WordCount == 3)
1546 || (smb_buffer_response->WordCount == 4)) {
1547 pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
1548 if (pSMBr->resp.Action & GUEST_LOGIN)
1549 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
1551 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1552 cFYI(1, ("UID = %d ", ses->Suid));
1553 /* response can have either 3 or 4 word count - Samba sends 3 */
1554 bcc_ptr = pByteArea(smb_buffer_response);
1555 if ((pSMBr->resp.hdr.WordCount == 3)
1556 || ((pSMBr->resp.hdr.WordCount == 4)
1557 && (pSMBr->resp.SecurityBlobLength <
1558 pSMBr->resp.ByteCount))) {
1559 if (pSMBr->resp.hdr.WordCount == 4)
1561 pSMBr->resp.SecurityBlobLength;
1563 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1564 if ((long) (bcc_ptr) % 2) {
1566 (BCC(smb_buffer_response)
1568 bcc_ptr++; /* Unicode strings must be word aligned */
1572 (smb_buffer_response) / 2;
1575 UniStrnlen((wchar_t *) bcc_ptr,
1576 remaining_words - 1);
1577 /* We look for obvious messed up bcc or strings in response so we do not go off
1578 the end since (at least) WIN2K and Windows XP have a major bug in not null
1579 terminating last Unicode string in response */
1580 ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
1581 cifs_strfromUCS_le(ses->serverOS,
1582 (wchar_t *)bcc_ptr, len,nls_codepage);
1583 bcc_ptr += 2 * (len + 1);
1584 remaining_words -= len + 1;
1585 ses->serverOS[2 * len] = 0;
1586 ses->serverOS[1 + (2 * len)] = 0;
1587 if (remaining_words > 0) {
1588 len = UniStrnlen((wchar_t *)bcc_ptr,
1591 ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL);
1592 cifs_strfromUCS_le(ses->serverNOS,
1593 (wchar_t *)bcc_ptr,len,nls_codepage);
1594 bcc_ptr += 2 * (len + 1);
1595 ses->serverNOS[2 * len] = 0;
1596 ses->serverNOS[1 + (2 * len)] = 0;
1597 remaining_words -= len + 1;
1598 if (remaining_words > 0) {
1599 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
1600 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1602 cifs_kcalloc(2*(len+1),GFP_KERNEL);
1603 cifs_strfromUCS_le(ses->serverDomain,
1604 (wchar_t *)bcc_ptr,len,nls_codepage);
1605 bcc_ptr += 2 * (len + 1);
1606 ses->serverDomain[2*len] = 0;
1607 ses->serverDomain[1+(2*len)] = 0;
1608 } /* else no more room so create dummy domain string */
1613 } else { /* no room so create dummy domain and NOS string */
1615 cifs_kcalloc(2, GFP_KERNEL);
1617 cifs_kcalloc(2, GFP_KERNEL);
1619 } else { /* ASCII */
1620 len = strnlen(bcc_ptr, 1024);
1621 if (((long) bcc_ptr + len) - (long)
1622 pByteArea(smb_buffer_response)
1623 <= BCC(smb_buffer_response)) {
1624 ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
1625 strncpy(ses->serverOS,bcc_ptr, len);
1628 bcc_ptr[0] = 0; /* null terminate the string */
1631 len = strnlen(bcc_ptr, 1024);
1632 ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
1633 strncpy(ses->serverNOS, bcc_ptr, len);
1638 len = strnlen(bcc_ptr, 1024);
1639 ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL);
1640 strncpy(ses->serverDomain, bcc_ptr, len);
1646 ("Variable field of length %d extends beyond end of smb ",
1651 (" Security Blob Length extends beyond end of SMB"));
1654 cERROR(1, ("No session structure passed in."));
1658 (" Invalid Word count %d: ",
1659 smb_buffer_response->WordCount));
1664 cifs_buf_release(smb_buffer);
1670 CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1671 char *SecurityBlob,int SecurityBlobLength,
1672 const struct nls_table *nls_codepage)
1674 struct smb_hdr *smb_buffer;
1675 struct smb_hdr *smb_buffer_response;
1676 SESSION_SETUP_ANDX *pSMB;
1677 SESSION_SETUP_ANDX *pSMBr;
1679 char *user = ses->userName;
1680 char *domain = ses->domainName;
1682 int remaining_words = 0;
1683 int bytes_returned = 0;
1686 cFYI(1, ("In spnego sesssetup "));
1688 smb_buffer = cifs_buf_get();
1689 if (smb_buffer == 0) {
1692 smb_buffer_response = smb_buffer;
1693 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1695 /* send SMBsessionSetup here */
1696 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1697 0 /* no tCon exists yet */ , 12 /* wct */ );
1698 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
1699 pSMB->req.AndXCommand = 0xFF;
1700 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1701 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1703 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1704 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1706 pSMB->req.Capabilities =
1707 CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1708 CAP_EXTENDED_SECURITY;
1709 if (ses->capabilities & CAP_UNICODE) {
1710 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1711 pSMB->req.Capabilities |= CAP_UNICODE;
1713 if (ses->capabilities & CAP_STATUS32) {
1714 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1715 pSMB->req.Capabilities |= CAP_STATUS32;
1717 if (ses->capabilities & CAP_DFS) {
1718 smb_buffer->Flags2 |= SMBFLG2_DFS;
1719 pSMB->req.Capabilities |= CAP_DFS;
1721 pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
1723 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
1724 bcc_ptr = pByteArea(smb_buffer);
1725 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
1726 bcc_ptr += SecurityBlobLength;
1728 if (ses->capabilities & CAP_UNICODE) {
1729 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
1734 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
1735 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
1736 bcc_ptr += 2; /* trailing null */
1739 cifs_strtoUCS((wchar_t *) bcc_ptr,
1740 "CIFS_LINUX_DOM", 32, nls_codepage);
1743 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1745 bcc_ptr += 2 * bytes_returned;
1748 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1750 bcc_ptr += 2 * bytes_returned;
1752 cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
1754 bcc_ptr += 2 * bytes_returned;
1757 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1759 bcc_ptr += 2 * bytes_returned;
1762 strncpy(bcc_ptr, user, 200);
1763 bcc_ptr += strnlen(user, 200);
1766 if (domain == NULL) {
1767 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1768 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1770 strncpy(bcc_ptr, domain, 64);
1771 bcc_ptr += strnlen(domain, 64);
1775 strcpy(bcc_ptr, "Linux version ");
1776 bcc_ptr += strlen("Linux version ");
1777 strcpy(bcc_ptr, UTS_RELEASE);
1778 bcc_ptr += strlen(UTS_RELEASE) + 1;
1779 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1780 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1782 BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1783 smb_buffer->smb_buf_length += BCC(smb_buffer);
1784 BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
1786 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1787 &bytes_returned, 1);
1789 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
1790 } else if ((smb_buffer_response->WordCount == 3)
1791 || (smb_buffer_response->WordCount == 4)) {
1792 pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
1793 pSMBr->resp.SecurityBlobLength =
1794 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1795 if (pSMBr->resp.Action & GUEST_LOGIN)
1796 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
1798 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1799 cFYI(1, ("UID = %d ", ses->Suid));
1800 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
1802 /* BB Fix below to make endian neutral !! */
1804 if ((pSMBr->resp.hdr.WordCount == 3)
1805 || ((pSMBr->resp.hdr.WordCount == 4)
1806 && (pSMBr->resp.SecurityBlobLength <
1807 pSMBr->resp.ByteCount))) {
1808 if (pSMBr->resp.hdr.WordCount == 4) {
1810 pSMBr->resp.SecurityBlobLength;
1812 ("Security Blob Length %d ",
1813 pSMBr->resp.SecurityBlobLength));
1816 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1817 if ((long) (bcc_ptr) % 2) {
1819 (BCC(smb_buffer_response)
1821 bcc_ptr++; /* Unicode strings must be word aligned */
1825 (smb_buffer_response) / 2;
1828 UniStrnlen((wchar_t *) bcc_ptr,
1829 remaining_words - 1);
1830 /* We look for obvious messed up bcc or strings in response so we do not go off
1831 the end since (at least) WIN2K and Windows XP have a major bug in not null
1832 terminating last Unicode string in response */
1834 cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
1835 cifs_strfromUCS_le(ses->serverOS,
1839 bcc_ptr += 2 * (len + 1);
1840 remaining_words -= len + 1;
1841 ses->serverOS[2 * len] = 0;
1842 ses->serverOS[1 + (2 * len)] = 0;
1843 if (remaining_words > 0) {
1844 len = UniStrnlen((wchar_t *)bcc_ptr,
1848 cifs_kcalloc(2 * (len + 1),
1850 cifs_strfromUCS_le(ses->serverNOS,
1854 bcc_ptr += 2 * (len + 1);
1855 ses->serverNOS[2 * len] = 0;
1856 ses->serverNOS[1 + (2 * len)] = 0;
1857 remaining_words -= len + 1;
1858 if (remaining_words > 0) {
1859 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
1860 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1861 ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL);
1862 cifs_strfromUCS_le(ses->serverDomain,
1866 bcc_ptr += 2*(len+1);
1867 ses->serverDomain[2*len] = 0;
1868 ses->serverDomain[1+(2*len)] = 0;
1869 } /* else no more room so create dummy domain string */
1872 cifs_kcalloc(2,GFP_KERNEL);
1873 } else { /* no room so create dummy domain and NOS string */
1874 ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
1875 ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
1877 } else { /* ASCII */
1879 len = strnlen(bcc_ptr, 1024);
1880 if (((long) bcc_ptr + len) - (long)
1881 pByteArea(smb_buffer_response)
1882 <= BCC(smb_buffer_response)) {
1883 ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL);
1884 strncpy(ses->serverOS, bcc_ptr, len);
1887 bcc_ptr[0] = 0; /* null terminate the string */
1890 len = strnlen(bcc_ptr, 1024);
1891 ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
1892 strncpy(ses->serverNOS, bcc_ptr, len);
1897 len = strnlen(bcc_ptr, 1024);
1898 ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL);
1899 strncpy(ses->serverDomain, bcc_ptr, len);
1905 ("Variable field of length %d extends beyond end of smb ",
1910 (" Security Blob Length extends beyond end of SMB"));
1913 cERROR(1, ("No session structure passed in."));
1917 (" Invalid Word count %d: ",
1918 smb_buffer_response->WordCount));
1923 cifs_buf_release(smb_buffer);
1929 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
1930 struct cifsSesInfo *ses, int * pNTLMv2_flag,
1931 const struct nls_table *nls_codepage)
1933 struct smb_hdr *smb_buffer;
1934 struct smb_hdr *smb_buffer_response;
1935 SESSION_SETUP_ANDX *pSMB;
1936 SESSION_SETUP_ANDX *pSMBr;
1938 char *domain = ses->domainName;
1940 int remaining_words = 0;
1941 int bytes_returned = 0;
1943 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
1944 PNEGOTIATE_MESSAGE SecurityBlob;
1945 PCHALLENGE_MESSAGE SecurityBlob2;
1947 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
1948 *pNTLMv2_flag = FALSE;
1949 smb_buffer = cifs_buf_get();
1950 if (smb_buffer == 0) {
1953 smb_buffer_response = smb_buffer;
1954 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1955 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
1957 /* send SMBsessionSetup here */
1958 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1959 0 /* no tCon exists yet */ , 12 /* wct */ );
1960 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
1961 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
1963 pSMB->req.AndXCommand = 0xFF;
1964 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1965 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1967 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1968 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1970 pSMB->req.Capabilities =
1971 CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1972 CAP_EXTENDED_SECURITY;
1973 if (ses->capabilities & CAP_UNICODE) {
1974 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1975 pSMB->req.Capabilities |= CAP_UNICODE;
1977 if (ses->capabilities & CAP_STATUS32) {
1978 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1979 pSMB->req.Capabilities |= CAP_STATUS32;
1981 if (ses->capabilities & CAP_DFS) {
1982 smb_buffer->Flags2 |= SMBFLG2_DFS;
1983 pSMB->req.Capabilities |= CAP_DFS;
1985 pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
1987 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
1988 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
1989 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
1990 SecurityBlob->MessageType = NtLmNegotiate;
1991 SecurityBlob->NegotiateFlags =
1992 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
1993 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
1994 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
1996 SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
1998 SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
1999 /* setup pointers to domain name and workstation name */
2000 bcc_ptr += SecurityBlobLength;
2002 SecurityBlob->WorkstationName.Buffer = 0;
2003 SecurityBlob->WorkstationName.Length = 0;
2004 SecurityBlob->WorkstationName.MaximumLength = 0;
2006 if (domain == NULL) {
2007 SecurityBlob->DomainName.Buffer = 0;
2008 SecurityBlob->DomainName.Length = 0;
2009 SecurityBlob->DomainName.MaximumLength = 0;
2011 SecurityBlob->NegotiateFlags |=
2012 NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2013 strncpy(bcc_ptr, domain, 63);
2014 SecurityBlob->DomainName.Length = strnlen(domain, 64);
2015 SecurityBlob->DomainName.MaximumLength =
2016 cpu_to_le16(SecurityBlob->DomainName.Length);
2017 SecurityBlob->DomainName.Buffer =
2018 cpu_to_le32((long) &SecurityBlob->
2020 (long) &SecurityBlob->Signature);
2021 bcc_ptr += SecurityBlob->DomainName.Length;
2022 SecurityBlobLength += SecurityBlob->DomainName.Length;
2023 SecurityBlob->DomainName.Length =
2024 cpu_to_le16(SecurityBlob->DomainName.Length);
2026 if (ses->capabilities & CAP_UNICODE) {
2027 if ((long) bcc_ptr % 2) {
2033 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2035 bcc_ptr += 2 * bytes_returned;
2037 cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
2039 bcc_ptr += 2 * bytes_returned;
2040 bcc_ptr += 2; /* null terminate Linux version */
2042 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2044 bcc_ptr += 2 * bytes_returned;
2047 bcc_ptr += 2; /* null terminate network opsys string */
2050 bcc_ptr += 2; /* null domain */
2051 } else { /* ASCII */
2052 strcpy(bcc_ptr, "Linux version ");
2053 bcc_ptr += strlen("Linux version ");
2054 strcpy(bcc_ptr, UTS_RELEASE);
2055 bcc_ptr += strlen(UTS_RELEASE) + 1;
2056 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2057 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2058 bcc_ptr++; /* empty domain field */
2061 SecurityBlob->NegotiateFlags =
2062 cpu_to_le32(SecurityBlob->NegotiateFlags);
2063 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2064 BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2065 smb_buffer->smb_buf_length += BCC(smb_buffer);
2066 BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
2068 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2069 &bytes_returned, 1);
2071 if (smb_buffer_response->Status.CifsError ==
2072 (NT_STATUS_MORE_PROCESSING_REQUIRED))
2076 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2077 } else if ((smb_buffer_response->WordCount == 3)
2078 || (smb_buffer_response->WordCount == 4)) {
2079 pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
2080 pSMBr->resp.SecurityBlobLength =
2081 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2082 if (pSMBr->resp.Action & GUEST_LOGIN)
2083 cFYI(1, (" Guest login"));
2084 /* Do we want to set anything in SesInfo struct when guest login? */
2086 bcc_ptr = pByteArea(smb_buffer_response);
2087 /* response can have either 3 or 4 word count - Samba sends 3 */
2089 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2090 if (SecurityBlob2->MessageType != NtLmChallenge) {
2092 ("Unexpected NTLMSSP message type received %d",
2093 SecurityBlob2->MessageType));
2095 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2096 cFYI(1, ("UID = %d ", ses->Suid));
2097 if ((pSMBr->resp.hdr.WordCount == 3)
2098 || ((pSMBr->resp.hdr.WordCount == 4)
2099 && (pSMBr->resp.SecurityBlobLength <
2100 pSMBr->resp.ByteCount))) {
2101 if (pSMBr->resp.hdr.WordCount == 4) {
2103 pSMBr->resp.SecurityBlobLength;
2105 ("Security Blob Length %d ",
2106 pSMBr->resp.SecurityBlobLength));
2109 cFYI(1, ("NTLMSSP Challenge rcvd "));
2111 memcpy(ses->server->cryptKey,
2112 SecurityBlob2->Challenge,
2113 CIFS_CRYPTO_KEY_SIZE);
2114 if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2)
2115 *pNTLMv2_flag = TRUE;
2117 if((SecurityBlob2->NegotiateFlags &
2118 NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
2119 || (sign_CIFS_PDUs > 1))
2120 ses->server->secMode |=
2121 SECMODE_SIGN_REQUIRED;
2122 if ((SecurityBlob2->NegotiateFlags &
2123 NTLMSSP_NEGOTIATE_SIGN) && (sign_CIFS_PDUs))
2124 ses->server->secMode |=
2125 SECMODE_SIGN_ENABLED;
2127 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2128 if ((long) (bcc_ptr) % 2) {
2130 (BCC(smb_buffer_response)
2132 bcc_ptr++; /* Unicode strings must be word aligned */
2136 (smb_buffer_response) / 2;
2139 UniStrnlen((wchar_t *) bcc_ptr,
2140 remaining_words - 1);
2141 /* We look for obvious messed up bcc or strings in response so we do not go off
2142 the end since (at least) WIN2K and Windows XP have a major bug in not null
2143 terminating last Unicode string in response */
2145 cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
2146 cifs_strfromUCS_le(ses->serverOS,
2150 bcc_ptr += 2 * (len + 1);
2151 remaining_words -= len + 1;
2152 ses->serverOS[2 * len] = 0;
2153 ses->serverOS[1 + (2 * len)] = 0;
2154 if (remaining_words > 0) {
2155 len = UniStrnlen((wchar_t *)
2160 cifs_kcalloc(2 * (len + 1),
2162 cifs_strfromUCS_le(ses->
2168 bcc_ptr += 2 * (len + 1);
2169 ses->serverNOS[2 * len] = 0;
2172 remaining_words -= len + 1;
2173 if (remaining_words > 0) {
2174 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2175 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2200 } /* else no more room so create dummy domain string */
2205 } else { /* no room so create dummy domain and NOS string */
2207 cifs_kcalloc(2, GFP_KERNEL);
2209 cifs_kcalloc(2, GFP_KERNEL);
2211 } else { /* ASCII */
2212 len = strnlen(bcc_ptr, 1024);
2213 if (((long) bcc_ptr + len) - (long)
2214 pByteArea(smb_buffer_response)
2215 <= BCC(smb_buffer_response)) {
2217 cifs_kcalloc(len + 1,
2219 strncpy(ses->serverOS,
2223 bcc_ptr[0] = 0; /* null terminate string */
2226 len = strnlen(bcc_ptr, 1024);
2228 cifs_kcalloc(len + 1,
2230 strncpy(ses->serverNOS, bcc_ptr, len);
2235 len = strnlen(bcc_ptr, 1024);
2237 cifs_kcalloc(len + 1,
2239 strncpy(ses->serverDomain, bcc_ptr, len);
2245 ("Variable field of length %d extends beyond end of smb ",
2250 (" Security Blob Length extends beyond end of SMB"));
2253 cERROR(1, ("No session structure passed in."));
2257 (" Invalid Word count %d: ",
2258 smb_buffer_response->WordCount));
2263 cifs_buf_release(smb_buffer);
2269 CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2270 char *ntlm_session_key, int ntlmv2_flag,
2271 const struct nls_table *nls_codepage)
2273 struct smb_hdr *smb_buffer;
2274 struct smb_hdr *smb_buffer_response;
2275 SESSION_SETUP_ANDX *pSMB;
2276 SESSION_SETUP_ANDX *pSMBr;
2278 char *user = ses->userName;
2279 char *domain = ses->domainName;
2281 int remaining_words = 0;
2282 int bytes_returned = 0;
2284 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2285 PAUTHENTICATE_MESSAGE SecurityBlob;
2287 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2289 smb_buffer = cifs_buf_get();
2290 if (smb_buffer == 0) {
2293 smb_buffer_response = smb_buffer;
2294 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2295 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2297 /* send SMBsessionSetup here */
2298 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2299 0 /* no tCon exists yet */ , 12 /* wct */ );
2300 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2301 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2302 pSMB->req.AndXCommand = 0xFF;
2303 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2304 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2306 pSMB->req.hdr.Uid = ses->Suid;
2308 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2309 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2311 pSMB->req.Capabilities =
2312 CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2313 CAP_EXTENDED_SECURITY;
2314 if (ses->capabilities & CAP_UNICODE) {
2315 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2316 pSMB->req.Capabilities |= CAP_UNICODE;
2318 if (ses->capabilities & CAP_STATUS32) {
2319 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2320 pSMB->req.Capabilities |= CAP_STATUS32;
2322 if (ses->capabilities & CAP_DFS) {
2323 smb_buffer->Flags2 |= SMBFLG2_DFS;
2324 pSMB->req.Capabilities |= CAP_DFS;
2326 pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
2328 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2329 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2330 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2331 SecurityBlob->MessageType = NtLmAuthenticate;
2332 bcc_ptr += SecurityBlobLength;
2333 SecurityBlob->NegotiateFlags =
2334 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2335 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2336 0x80000000 | NTLMSSP_NEGOTIATE_128;
2338 SecurityBlob->NegotiateFlags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2340 SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
2342 /* setup pointers to domain name and workstation name */
2344 SecurityBlob->WorkstationName.Buffer = 0;
2345 SecurityBlob->WorkstationName.Length = 0;
2346 SecurityBlob->WorkstationName.MaximumLength = 0;
2347 SecurityBlob->SessionKey.Length = 0;
2348 SecurityBlob->SessionKey.MaximumLength = 0;
2349 SecurityBlob->SessionKey.Buffer = 0;
2351 SecurityBlob->LmChallengeResponse.Length = 0;
2352 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2353 SecurityBlob->LmChallengeResponse.Buffer = 0;
2355 SecurityBlob->NtChallengeResponse.Length =
2356 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2357 SecurityBlob->NtChallengeResponse.MaximumLength =
2358 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2359 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2360 SecurityBlob->NtChallengeResponse.Buffer =
2361 cpu_to_le32(SecurityBlobLength);
2362 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2363 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2365 if (ses->capabilities & CAP_UNICODE) {
2366 if (domain == NULL) {
2367 SecurityBlob->DomainName.Buffer = 0;
2368 SecurityBlob->DomainName.Length = 0;
2369 SecurityBlob->DomainName.MaximumLength = 0;
2371 SecurityBlob->DomainName.Length =
2372 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2374 SecurityBlob->DomainName.Length *= 2;
2375 SecurityBlob->DomainName.MaximumLength =
2376 cpu_to_le16(SecurityBlob->DomainName.Length);
2377 SecurityBlob->DomainName.Buffer =
2378 cpu_to_le32(SecurityBlobLength);
2379 bcc_ptr += SecurityBlob->DomainName.Length;
2380 SecurityBlobLength += SecurityBlob->DomainName.Length;
2381 SecurityBlob->DomainName.Length =
2382 cpu_to_le16(SecurityBlob->DomainName.Length);
2385 SecurityBlob->UserName.Buffer = 0;
2386 SecurityBlob->UserName.Length = 0;
2387 SecurityBlob->UserName.MaximumLength = 0;
2389 SecurityBlob->UserName.Length =
2390 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2392 SecurityBlob->UserName.Length *= 2;
2393 SecurityBlob->UserName.MaximumLength =
2394 cpu_to_le16(SecurityBlob->UserName.Length);
2395 SecurityBlob->UserName.Buffer =
2396 cpu_to_le32(SecurityBlobLength);
2397 bcc_ptr += SecurityBlob->UserName.Length;
2398 SecurityBlobLength += SecurityBlob->UserName.Length;
2399 SecurityBlob->UserName.Length =
2400 cpu_to_le16(SecurityBlob->UserName.Length);
2403 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2404 SecurityBlob->WorkstationName.Length *= 2;
2405 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2406 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2407 bcc_ptr += SecurityBlob->WorkstationName.Length;
2408 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2409 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2411 if ((long) bcc_ptr % 2) {
2416 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2418 bcc_ptr += 2 * bytes_returned;
2420 cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
2422 bcc_ptr += 2 * bytes_returned;
2423 bcc_ptr += 2; /* null term version string */
2425 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2427 bcc_ptr += 2 * bytes_returned;
2430 bcc_ptr += 2; /* null terminate network opsys string */
2433 bcc_ptr += 2; /* null domain */
2434 } else { /* ASCII */
2435 if (domain == NULL) {
2436 SecurityBlob->DomainName.Buffer = 0;
2437 SecurityBlob->DomainName.Length = 0;
2438 SecurityBlob->DomainName.MaximumLength = 0;
2440 SecurityBlob->NegotiateFlags |=
2441 NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2442 strncpy(bcc_ptr, domain, 63);
2443 SecurityBlob->DomainName.Length = strnlen(domain, 64);
2444 SecurityBlob->DomainName.MaximumLength =
2445 cpu_to_le16(SecurityBlob->DomainName.Length);
2446 SecurityBlob->DomainName.Buffer =
2447 cpu_to_le32(SecurityBlobLength);
2448 bcc_ptr += SecurityBlob->DomainName.Length;
2449 SecurityBlobLength += SecurityBlob->DomainName.Length;
2450 SecurityBlob->DomainName.Length =
2451 cpu_to_le16(SecurityBlob->DomainName.Length);
2454 SecurityBlob->UserName.Buffer = 0;
2455 SecurityBlob->UserName.Length = 0;
2456 SecurityBlob->UserName.MaximumLength = 0;
2458 strncpy(bcc_ptr, user, 63);
2459 SecurityBlob->UserName.Length = strnlen(user, 64);
2460 SecurityBlob->UserName.MaximumLength =
2461 cpu_to_le16(SecurityBlob->UserName.Length);
2462 SecurityBlob->UserName.Buffer =
2463 cpu_to_le32(SecurityBlobLength);
2464 bcc_ptr += SecurityBlob->UserName.Length;
2465 SecurityBlobLength += SecurityBlob->UserName.Length;
2466 SecurityBlob->UserName.Length =
2467 cpu_to_le16(SecurityBlob->UserName.Length);
2469 /* BB fill in our workstation name if known BB */
2471 strcpy(bcc_ptr, "Linux version ");
2472 bcc_ptr += strlen("Linux version ");
2473 strcpy(bcc_ptr, UTS_RELEASE);
2474 bcc_ptr += strlen(UTS_RELEASE) + 1;
2475 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2476 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2477 bcc_ptr++; /* null domain */
2480 SecurityBlob->NegotiateFlags =
2481 cpu_to_le32(SecurityBlob->NegotiateFlags);
2482 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2483 BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2484 smb_buffer->smb_buf_length += BCC(smb_buffer);
2485 BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
2487 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2488 &bytes_returned, 1);
2490 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2491 } else if ((smb_buffer_response->WordCount == 3)
2492 || (smb_buffer_response->WordCount == 4)) {
2493 pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
2494 pSMBr->resp.SecurityBlobLength =
2495 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2496 if (pSMBr->resp.Action & GUEST_LOGIN)
2497 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2498 /* if(SecurityBlob2->MessageType != NtLm??){
2499 cFYI("Unexpected message type on auth response is %d "));
2503 ("Does UID on challenge %d match auth response UID %d ",
2504 ses->Suid, smb_buffer_response->Uid));
2505 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2506 bcc_ptr = pByteArea(smb_buffer_response);
2507 /* response can have either 3 or 4 word count - Samba sends 3 */
2508 if ((pSMBr->resp.hdr.WordCount == 3)
2509 || ((pSMBr->resp.hdr.WordCount == 4)
2510 && (pSMBr->resp.SecurityBlobLength <
2511 pSMBr->resp.ByteCount))) {
2512 if (pSMBr->resp.hdr.WordCount == 4) {
2514 pSMBr->resp.SecurityBlobLength;
2516 ("Security Blob Length %d ",
2517 pSMBr->resp.SecurityBlobLength));
2521 ("NTLMSSP response to Authenticate "));
2523 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2524 if ((long) (bcc_ptr) % 2) {
2526 (BCC(smb_buffer_response)
2528 bcc_ptr++; /* Unicode strings must be word aligned */
2530 remaining_words = BCC(smb_buffer_response) / 2;
2533 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2534 /* We look for obvious messed up bcc or strings in response so we do not go off
2535 the end since (at least) WIN2K and Windows XP have a major bug in not null
2536 terminating last Unicode string in response */
2538 cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
2539 cifs_strfromUCS_le(ses->serverOS,
2543 bcc_ptr += 2 * (len + 1);
2544 remaining_words -= len + 1;
2545 ses->serverOS[2 * len] = 0;
2546 ses->serverOS[1 + (2 * len)] = 0;
2547 if (remaining_words > 0) {
2548 len = UniStrnlen((wchar_t *)
2553 cifs_kcalloc(2 * (len + 1),
2555 cifs_strfromUCS_le(ses->
2561 bcc_ptr += 2 * (len + 1);
2562 ses->serverNOS[2 * len] = 0;
2563 ses->serverNOS[1+(2*len)] = 0;
2564 remaining_words -= len + 1;
2565 if (remaining_words > 0) {
2566 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2567 /* last string not always null terminated (e.g. for Windows XP & 2000) */
2592 } /* else no more room so create dummy domain string */
2594 ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL);
2595 } else { /* no room so create dummy domain and NOS string */
2596 ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
2597 ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
2599 } else { /* ASCII */
2600 len = strnlen(bcc_ptr, 1024);
2601 if (((long) bcc_ptr + len) -
2602 (long) pByteArea(smb_buffer_response)
2603 <= BCC(smb_buffer_response)) {
2604 ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
2605 strncpy(ses->serverOS,bcc_ptr, len);
2608 bcc_ptr[0] = 0; /* null terminate the string */
2611 len = strnlen(bcc_ptr, 1024);
2612 ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL);
2613 strncpy(ses->serverNOS, bcc_ptr, len);
2618 len = strnlen(bcc_ptr, 1024);
2619 ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL);
2620 strncpy(ses->serverDomain, bcc_ptr, len);
2626 ("Variable field of length %d extends beyond end of smb ",
2631 (" Security Blob Length extends beyond end of SMB"));
2634 cERROR(1, ("No session structure passed in."));
2638 (" Invalid Word count %d: ",
2639 smb_buffer_response->WordCount));
2644 cifs_buf_release(smb_buffer);
2650 CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2651 const char *tree, struct cifsTconInfo *tcon,
2652 const struct nls_table *nls_codepage)
2654 struct smb_hdr *smb_buffer;
2655 struct smb_hdr *smb_buffer_response;
2665 smb_buffer = cifs_buf_get();
2666 if (smb_buffer == 0) {
2669 smb_buffer_response = smb_buffer;
2671 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
2672 0 /*no tid */ , 4 /*wct */ );
2673 smb_buffer->Uid = ses->Suid;
2674 pSMB = (TCONX_REQ *) smb_buffer;
2675 pSMBr = (TCONX_RSP *) smb_buffer_response;
2677 pSMB->AndXCommand = 0xFF;
2678 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
2679 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
2680 bcc_ptr = &(pSMB->Password[0]);
2681 bcc_ptr++; /* skip password */
2683 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2684 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2686 if (ses->capabilities & CAP_STATUS32) {
2687 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2689 if (ses->capabilities & CAP_DFS) {
2690 smb_buffer->Flags2 |= SMBFLG2_DFS;
2692 if (ses->capabilities & CAP_UNICODE) {
2693 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2695 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
2696 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
2697 bcc_ptr += 2; /* skip trailing null */
2698 } else { /* ASCII */
2700 strcpy(bcc_ptr, tree);
2701 bcc_ptr += strlen(tree) + 1;
2703 strcpy(bcc_ptr, "?????");
2704 bcc_ptr += strlen("?????");
2706 BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2707 smb_buffer->smb_buf_length += BCC(smb_buffer);
2708 BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
2710 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
2712 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
2713 /* above now done in SendReceive */
2714 if ((rc == 0) && (tcon != NULL)) {
2715 tcon->tidStatus = CifsGood;
2716 tcon->tid = smb_buffer_response->Tid;
2717 bcc_ptr = pByteArea(smb_buffer_response);
2718 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
2719 /* skip service field (NB: this field is always ASCII) */
2720 bcc_ptr += length + 1;
2721 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
2722 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2723 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
2724 if (((long) bcc_ptr + (2 * length)) -
2725 (long) pByteArea(smb_buffer_response) <=
2726 BCC(smb_buffer_response)) {
2727 if(tcon->nativeFileSystem)
2728 kfree(tcon->nativeFileSystem);
2729 tcon->nativeFileSystem =
2730 cifs_kcalloc(length + 2, GFP_KERNEL);
2731 cifs_strfromUCS_le(tcon->nativeFileSystem,
2732 (wchar_t *) bcc_ptr,
2733 length, nls_codepage);
2734 bcc_ptr += 2 * length;
2735 bcc_ptr[0] = 0; /* null terminate the string */
2739 /* else do not bother copying these informational fields */
2741 length = strnlen(bcc_ptr, 1024);
2742 if (((long) bcc_ptr + length) -
2743 (long) pByteArea(smb_buffer_response) <=
2744 BCC(smb_buffer_response)) {
2745 if(tcon->nativeFileSystem)
2746 kfree(tcon->nativeFileSystem);
2747 tcon->nativeFileSystem =
2748 cifs_kcalloc(length + 1, GFP_KERNEL);
2749 strncpy(tcon->nativeFileSystem, bcc_ptr,
2752 /* else do not bother copying these informational fields */
2754 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
2755 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
2756 } else if ((rc == 0) && tcon == NULL) {
2757 /* all we need to save for IPC$ connection */
2758 ses->ipc_tid = smb_buffer_response->Tid;
2762 cifs_buf_release(smb_buffer);
2767 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
2771 struct cifsSesInfo *ses = NULL;
2775 if (cifs_sb->tcon) {
2776 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
2777 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
2782 tconInfoFree(cifs_sb->tcon);
2783 if ((ses) && (ses->server)) {
2784 cFYI(1, ("About to do SMBLogoff "));
2785 rc = CIFSSMBLogoff(xid, ses);
2791 set_current_state(TASK_INTERRUPTIBLE);
2792 schedule_timeout(HZ / 4); /* give captive thread time to exit */
2793 if((ses->server) && (ses->server->ssocket)) {
2794 cFYI(1,("Waking up socket by sending it signal "));
2795 send_sig(SIGKILL,ses->server->tsk,1);
2798 cFYI(1, ("No session or bad tcon"));
2801 cifs_sb->tcon = NULL;
2803 set_current_state(TASK_INTERRUPTIBLE);
2804 schedule_timeout(HZ / 2);
2810 return rc; /* BB check if we should always return zero here */
2813 int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
2814 struct nls_table * nls_info)
2817 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
2818 int ntlmv2_flag = FALSE;
2820 /* what if server changes its buffer size after dropping the session? */
2821 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
2822 rc = CIFSSMBNegotiate(xid, pSesInfo);
2823 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
2824 rc = CIFSSMBNegotiate(xid, pSesInfo);
2829 spin_lock(&GlobalMid_Lock);
2830 if(pSesInfo->server->tcpStatus != CifsExiting)
2831 pSesInfo->server->tcpStatus = CifsGood;
2834 spin_unlock(&GlobalMid_Lock);
2839 pSesInfo->capabilities = pSesInfo->server->capabilities;
2840 if(linuxExtEnabled == 0)
2841 pSesInfo->capabilities &= (~CAP_UNIX);
2842 pSesInfo->sequence_number = 0;
2843 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
2844 pSesInfo->server->secMode,
2845 pSesInfo->server->capabilities,
2846 pSesInfo->server->timeZone));
2847 if (extended_security
2848 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
2849 && (pSesInfo->server->secType == NTLMSSP)) {
2850 cFYI(1, ("New style sesssetup "));
2851 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
2852 NULL /* security blob */,
2853 0 /* blob length */,
2855 } else if (extended_security
2856 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
2857 && (pSesInfo->server->secType == RawNTLMSSP)) {
2858 cFYI(1, ("NTLMSSP sesssetup "));
2859 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
2866 cFYI(1,("Can use more secure NTLM version 2 password hash"));
2867 CalcNTLMv2_partial_mac_key(pSesInfo,
2869 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
2871 CalcNTLMv2_response(pSesInfo,v2_response);
2872 /* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */
2874 /* BB Put dummy sig in SessSetup PDU? */
2879 SMBNTencrypt(pSesInfo->password,
2880 pSesInfo->server->cryptKey,
2883 cifs_calculate_mac_key(pSesInfo->mac_signing_key,
2885 pSesInfo->password);
2887 /* for better security the weaker lanman hash not sent
2888 in AuthSessSetup so we no longer calculate it */
2890 rc = CIFSNTLMSSPAuthSessSetup(xid,
2896 } else { /* old style NTLM 0.12 session setup */
2897 SMBNTencrypt(pSesInfo->password,
2898 pSesInfo->server->cryptKey,
2901 cifs_calculate_mac_key(pSesInfo->mac_signing_key,
2902 ntlm_session_key, pSesInfo->password);
2903 rc = CIFSSessSetup(xid, pSesInfo,
2904 ntlm_session_key, nls_info);
2907 cERROR(1,("Send error in SessSetup = %d",rc));
2909 cFYI(1,("CIFS Session Established successfully"));
2910 pSesInfo->status = CifsGood;