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 if(server->tcpStatus == CifsExiting)
100 server->tcpStatus = CifsNeedReconnect;
103 cFYI(1, ("Reconnecting tcp session "));
105 /* before reconnecting the tcp session, mark the smb session (uid)
106 and the tid bad so they are not used until reconnected */
107 read_lock(&GlobalSMBSeslock);
108 list_for_each(tmp, &GlobalSMBSessionList) {
109 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
111 if (ses->server == server) {
112 ses->status = CifsNeedReconnect;
116 /* else tcp and smb sessions need reconnection */
118 list_for_each(tmp, &GlobalTreeConnectionList) {
119 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
120 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
121 tcon->tidStatus = CifsNeedReconnect;
124 read_unlock(&GlobalSMBSeslock);
126 if(server->ssocket) {
127 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
128 server->ssocket->flags));
129 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
130 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
131 server->ssocket->flags));
132 sock_release(server->ssocket);
133 server->ssocket = NULL;
136 spin_lock(&GlobalMid_Lock);
137 list_for_each(tmp, &server->pending_mid_q) {
138 mid_entry = list_entry(tmp, struct
142 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
143 /* Mark other intransit requests as needing retry so
144 we do not immediately mark the session bad again
145 (ie after we reconnect below) as they timeout too */
146 mid_entry->midState = MID_RETRY_NEEDED;
150 spin_unlock(&GlobalMid_Lock);
153 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
155 if(server->protocolType == IPV6) {
156 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
158 rc = ipv4_connect(&server->addr.sockAddr,
160 server->workstation_RFC1001_name);
163 set_current_state(TASK_INTERRUPTIBLE);
164 schedule_timeout(3 * HZ);
166 atomic_inc(&tcpSesReconnectCount);
167 server->tcpStatus = CifsGood;
168 atomic_set(&server->inFlight,0);
169 wake_up(&server->response_q);
176 cifs_demultiplex_thread(struct TCP_Server_Info *server)
179 unsigned int pdu_length, total_read;
180 struct smb_hdr *smb_buffer = NULL;
181 struct msghdr smb_msg;
182 mm_segment_t temp_fs;
184 struct socket *csocket = server->ssocket;
185 struct list_head *tmp;
186 struct cifsSesInfo *ses;
187 struct task_struct *task_to_wake = NULL;
188 struct mid_q_entry *mid_entry;
192 allow_signal(SIGKILL);
193 current->flags |= PF_MEMALLOC;
194 server->tsk = current; /* save process info to wake at shutdown */
195 cFYI(1, ("Demultiplex PID: %d", current->pid));
197 temp_fs = get_fs(); /* we must turn off socket api parm checking */
200 while (server->tcpStatus != CifsExiting) {
201 if (smb_buffer == NULL)
202 smb_buffer = cifs_buf_get();
204 memset(smb_buffer, 0, sizeof (struct smb_hdr));
206 if (smb_buffer == NULL) {
207 cERROR(1,("Can not get memory for SMB response"));
208 set_current_state(TASK_INTERRUPTIBLE);
209 schedule_timeout(HZ * 3); /* give system time to free memory */
212 iov.iov_base = smb_buffer;
213 iov.iov_len = sizeof (struct smb_hdr) - 1;
214 /* 1 byte less above since wct is not always returned in error cases */
215 smb_msg.msg_iov = &iov;
216 smb_msg.msg_iovlen = 1;
217 smb_msg.msg_control = NULL;
218 smb_msg.msg_controllen = 0;
221 sock_recvmsg(csocket, &smb_msg,
222 sizeof (struct smb_hdr) -
223 1 /* RFC1001 header and SMB header */ ,
224 MSG_PEEK /* flags see socket.h */ );
226 if(server->tcpStatus == CifsExiting) {
228 } else if (server->tcpStatus == CifsNeedReconnect) {
229 cFYI(1,("Reconnecting after server stopped responding"));
230 cifs_reconnect(server);
231 cFYI(1,("call to reconnect done"));
232 csocket = server->ssocket;
234 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
235 set_current_state(TASK_INTERRUPTIBLE);
236 schedule_timeout(1); /* minimum sleep to prevent looping
237 allowing socket to clear and app threads to set
238 tcpStatus CifsNeedReconnect if server hung */
240 } else if (length <= 0) {
241 if(server->tcpStatus == CifsNew) {
242 cFYI(1,("tcp session abended prematurely (after SMBnegprot)"));
243 /* some servers kill tcp session rather than returning
244 smb negprot error in which case reconnecting here is
245 not going to help - return error to mount */
246 server->tcpStatus = CifsExiting;
247 wake_up(&server->response_q);
251 cFYI(1,("Reconnecting after unexpected rcvmsg error "));
252 cifs_reconnect(server);
253 csocket = server->ssocket;
254 wake_up(&server->response_q);
258 pdu_length = 4 + ntohl(smb_buffer->smb_buf_length);
259 /* Ony read pdu_length after below checks for too short (due
260 to e.g. int overflow) and too long ie beyond end of buf */
261 cFYI(1, ("Peek length rcvd: 0x%x beginning 0x%x)", length, pdu_length));
263 temp = (char *) smb_buffer;
265 if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
266 iov.iov_base = smb_buffer;
268 length = sock_recvmsg(csocket, &smb_msg, 4, 0);
269 cFYI(0,("Received 4 byte keep alive packet"));
270 } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
271 iov.iov_base = smb_buffer;
273 length = sock_recvmsg(csocket, &smb_msg, 4, 0);
274 cFYI(1,("Good RFC 1002 session rsp"));
275 } else if ((temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE)
277 /* we get this from Windows 98 instead of error on SMB negprot response */
278 cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
279 if(server->tcpStatus == CifsNew) {
280 /* if nack on negprot (rather than
281 ret of smb negprot error) reconnecting
282 not going to help, ret error to mount */
283 server->tcpStatus = CifsExiting;
284 /* wake up thread doing negprot */
285 wake_up(&server->response_q);
288 /* give server a second to
289 clean up before reconnect attempt */
290 set_current_state(TASK_INTERRUPTIBLE);
291 schedule_timeout(HZ);
292 /* always try 445 first on reconnect
293 since we get NACK on some if we ever
294 connected to port 139 (the NACK is
295 since we do not begin with RFC1001
296 session initialize frame) */
297 server->addr.sockAddr.sin_port = CIFS_PORT;
298 cifs_reconnect(server);
299 csocket = server->ssocket;
300 wake_up(&server->response_q);
303 } else if (temp[0] != (char) 0) {
304 cERROR(1,("Unknown RFC 1002 frame"));
305 cifs_dump_mem(" Received Data: ", temp, length);
306 cifs_reconnect(server);
307 csocket = server->ssocket;
310 if ((length != sizeof (struct smb_hdr) - 1)
312 CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)
314 sizeof (struct smb_hdr) - 1)
317 (smb_buffer, smb_buffer->Mid))) {
319 ("Invalid size or format for SMB found with length %d and pdu_lenght %d",
320 length, pdu_length));
321 cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
322 /* could we fix this network corruption by finding next
323 smb header (instead of killing the session) and
324 restart reading from next valid SMB found? */
325 cifs_reconnect(server);
326 csocket = server->ssocket;
328 } else { /* length ok */
331 iov.iov_base = smb_buffer;
332 iov.iov_len = pdu_length;
334 total_read < pdu_length;
335 total_read += length) {
336 length = sock_recvmsg(csocket, &smb_msg,
337 pdu_length - total_read, 0);
340 ("Zero length receive when expecting %d ",
341 pdu_length - total_read));
342 cifs_reconnect(server);
343 csocket = server->ssocket;
349 dump_smb(smb_buffer, length);
351 (smb_buffer, smb_buffer->Mid, total_read)) {
352 cERROR(1, ("Bad SMB Received "));
357 spin_lock(&GlobalMid_Lock);
358 list_for_each(tmp, &server->pending_mid_q) {
359 mid_entry = list_entry(tmp, struct
363 if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
365 (" Mid 0x%x matched - waking up ",mid_entry->mid));
366 task_to_wake = mid_entry->tsk;
367 mid_entry->resp_buf =
369 mid_entry->midState =
370 MID_RESPONSE_RECEIVED;
373 spin_unlock(&GlobalMid_Lock);
375 smb_buffer = NULL; /* will be freed by users thread after he is done */
376 wake_up_process(task_to_wake);
377 } else if (is_valid_oplock_break(smb_buffer) == FALSE) {
378 cERROR(1, ("No task to wake, unknown frame rcvd!"));
379 cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
384 ("Frame less than four bytes received %d bytes long.",
387 length = sock_recvmsg(csocket, &smb_msg, length, 0); /* throw away junk frame */
389 (" with junk 0x%x in it ",
390 *(__u32 *) smb_buffer));
394 server->tcpStatus = CifsExiting;
395 atomic_set(&server->inFlight, 0);
396 /* Although there should not be any requests blocked on
397 this queue it can not hurt to be paranoid and try to wake up requests
398 that may haven been blocked when more than 50 at time were on the wire
399 to the same server - they now will see the session is in exit state
400 and get out of SendReceive. */
401 wake_up_all(&server->request_q);
403 if(server->ssocket) {
404 sock_release(csocket);
405 server->ssocket = NULL;
408 if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */
409 cifs_buf_release(smb_buffer);
411 read_lock(&GlobalSMBSeslock);
412 if (list_empty(&server->pending_mid_q)) {
413 /* loop through server session structures attached to this and mark them dead */
414 list_for_each(tmp, &GlobalSMBSessionList) {
416 list_entry(tmp, struct cifsSesInfo,
418 if (ses->server == server) {
419 ses->status = CifsExiting;
423 read_unlock(&GlobalSMBSeslock);
425 spin_lock(&GlobalMid_Lock);
426 list_for_each(tmp, &server->pending_mid_q) {
427 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
428 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
430 (" Clearing Mid 0x%x - waking up ",mid_entry->mid));
431 task_to_wake = mid_entry->tsk;
433 wake_up_process(task_to_wake);
437 spin_unlock(&GlobalMid_Lock);
438 read_unlock(&GlobalSMBSeslock);
439 set_current_state(TASK_INTERRUPTIBLE);
440 /* 1/8th of sec should be more than enough time for them to exit */
441 schedule_timeout(HZ/8);
444 if (list_empty(&server->pending_mid_q)) {
445 /* mpx threads have not exited yet give them
446 at least the smb send timeout time for long ops */
447 cFYI(1, ("Wait for exit from demultiplex thread"));
448 set_current_state(TASK_INTERRUPTIBLE);
449 schedule_timeout(46 * HZ);
450 /* if threads still have not exited they are probably never
451 coming home not much else we can do but free the memory */
455 cFYI(1, ("About to exit from demultiplex thread"));
460 cifs_kcalloc(size_t size, int type)
463 addr = kmalloc(size, type);
465 memset(addr, 0, size);
470 cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol)
474 unsigned int temp_len, i, j;
480 memset(vol->source_rfc1001_name,0x20,15);
481 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
482 /* does not have to be a perfect mapping since the field is
483 informational, only used for servers that do not support
484 port 445 and it can be overridden at mount time */
485 vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]);
487 vol->source_rfc1001_name[15] = 0;
489 vol->linux_uid = current->uid; /* current->euid instead? */
490 vol->linux_gid = current->gid;
491 vol->dir_mode = S_IRWXUGO;
492 /* 2767 perms indicate mandatory locking support */
493 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
495 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
501 if(strncmp(options,"sep=",4) == 0) {
502 if(options[4] != 0) {
503 separator[0] = options[4];
506 cFYI(1,("Null separator not allowed"));
510 while ((data = strsep(&options, separator)) != NULL) {
513 if ((value = strchr(data, '=')) != NULL)
515 if (strnicmp(data, "user", 4) == 0) {
516 if (!value || !*value) {
518 "CIFS: invalid or missing username\n");
519 return 1; /* needs_arg; */
521 if (strnlen(value, 200) < 200) {
522 vol->username = value;
524 printk(KERN_WARNING "CIFS: username too long\n");
527 } else if (strnicmp(data, "pass", 4) == 0) {
528 if (!value || !*value) {
529 vol->password = NULL;
532 temp_len = strlen(value);
533 /* removed password length check, NTLM passwords
534 can be arbitrarily long */
536 /* if comma in password, the string will be
537 prematurely null terminated. Commas in password are
538 specified across the cifs mount interface by a double
539 comma ie ,, and a comma used as in other cases ie ','
540 as a parameter delimiter/separator is single and due
541 to the strsep above is temporarily zeroed. */
543 /* NB: password legally can have multiple commas and
544 the only illegal character in a password is null */
546 if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) {
548 value[temp_len] = separator[0];
549 temp_len+=2; /* move after the second comma */
550 while(value[temp_len] != 0) {
551 if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) {
552 /* single comma indicating start of next parm */
557 if(value[temp_len] == 0) {
561 /* move options to point to start of next parm */
562 options = value + temp_len + 1;
564 /* go from value to (value + temp_len) condensing double commas to singles */
565 vol->password = cifs_kcalloc(temp_len, GFP_KERNEL);
566 for(i=0,j=0;i<temp_len;i++,j++) {
567 vol->password[j] = value[i];
568 if(value[i] == separator[0] && value[i+1] == separator[0]) {
569 /* skip second comma */
573 /* value[temp_len] is zeroed above so
574 vol->password[temp_len] guaranteed to be null */
576 vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL);
577 strcpy(vol->password, value);
579 } else if (strnicmp(data, "ip", 2) == 0) {
580 if (!value || !*value) {
582 } else if (strnlen(value, 35) < 35) {
585 printk(KERN_WARNING "CIFS: ip address too long\n");
588 } else if ((strnicmp(data, "unc", 3) == 0)
589 || (strnicmp(data, "target", 6) == 0)
590 || (strnicmp(data, "path", 4) == 0)) {
591 if (!value || !*value) {
593 "CIFS: invalid path to network resource\n");
594 return 1; /* needs_arg; */
596 if ((temp_len = strnlen(value, 300)) < 300) {
597 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
598 strcpy(vol->UNC,value);
599 if (strncmp(vol->UNC, "//", 2) == 0) {
602 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
604 "CIFS: UNC Path does not begin with // or \\\\ \n");
608 printk(KERN_WARNING "CIFS: UNC name too long\n");
611 } else if ((strnicmp(data, "domain", 3) == 0)
612 || (strnicmp(data, "workgroup", 5) == 0)) {
613 if (!value || !*value) {
614 printk(KERN_WARNING "CIFS: invalid domain name\n");
615 return 1; /* needs_arg; */
617 /* BB are there cases in which a comma can be valid in
618 a domain name and need special handling? */
619 if (strnlen(value, 65) < 65) {
620 vol->domainname = value;
621 cFYI(1, ("Domain name set"));
623 printk(KERN_WARNING "CIFS: domain name too long\n");
626 } else if (strnicmp(data, "iocharset", 9) == 0) {
627 if (!value || !*value) {
628 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
629 return 1; /* needs_arg; */
631 if (strnlen(value, 65) < 65) {
632 if(strnicmp(value,"default",7))
633 vol->iocharset = value;
634 /* if iocharset not set load_nls_default used by caller */
635 cFYI(1, ("iocharset set to %s",value));
637 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
640 } else if (strnicmp(data, "uid", 3) == 0) {
641 if (value && *value) {
643 simple_strtoul(value, &value, 0);
645 } else if (strnicmp(data, "gid", 3) == 0) {
646 if (value && *value) {
648 simple_strtoul(value, &value, 0);
650 } else if (strnicmp(data, "file_mode", 4) == 0) {
651 if (value && *value) {
653 simple_strtoul(value, &value, 0);
655 } else if (strnicmp(data, "dir_mode", 3) == 0) {
656 if (value && *value) {
658 simple_strtoul(value, &value, 0);
660 } else if (strnicmp(data, "port", 4) == 0) {
661 if (value && *value) {
663 simple_strtoul(value, &value, 0);
665 } else if (strnicmp(data, "rsize", 5) == 0) {
666 if (value && *value) {
668 simple_strtoul(value, &value, 0);
670 } else if (strnicmp(data, "wsize", 5) == 0) {
671 if (value && *value) {
673 simple_strtoul(value, &value, 0);
675 } else if (strnicmp(data, "sockopt", 5) == 0) {
676 if (value && *value) {
678 simple_strtoul(value, &value, 0);
680 } else if (strnicmp(data, "netbiosname", 4) == 0) {
681 if (!value || !*value || (*value == ' ')) {
682 cFYI(1,("invalid (empty) netbiosname specified"));
684 memset(vol->source_rfc1001_name,0x20,15);
686 /* BB are there cases in which a comma can be
687 valid in this workstation netbios name (and need
688 special handling)? */
690 /* We do not uppercase netbiosname for user */
694 vol->source_rfc1001_name[i] = value[i];
696 /* The string has 16th byte zero still from
697 set at top of the function */
698 if((i==15) && (value[i] != 0))
699 printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
701 } else if (strnicmp(data, "version", 3) == 0) {
703 } else if (strnicmp(data, "rw", 2) == 0) {
705 } else if ((strnicmp(data, "suid", 4) == 0) ||
706 (strnicmp(data, "nosuid", 6) == 0) ||
707 (strnicmp(data, "exec", 4) == 0) ||
708 (strnicmp(data, "noexec", 6) == 0) ||
709 (strnicmp(data, "nodev", 5) == 0) ||
710 (strnicmp(data, "noauto", 6) == 0) ||
711 (strnicmp(data, "dev", 3) == 0)) {
712 /* The mount tool or mount.cifs helper (if present)
713 uses these opts to set flags, and the flags are read
714 by the kernel vfs layer before we get here (ie
715 before read super) so there is no point trying to
716 parse these options again and set anything and it
717 is ok to just ignore them */
719 } else if (strnicmp(data, "ro", 2) == 0) {
721 } else if (strnicmp(data, "hard", 4) == 0) {
723 } else if (strnicmp(data, "soft", 4) == 0) {
725 } else if (strnicmp(data, "nohard", 6) == 0) {
727 } else if (strnicmp(data, "nosoft", 6) == 0) {
729 } else if (strnicmp(data, "nointr", 6) == 0) {
731 } else if (strnicmp(data, "intr", 4) == 0) {
733 } else if (strnicmp(data, "noac", 4) == 0) {
734 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
736 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
738 if (vol->UNC == NULL) {
739 if(devname == NULL) {
740 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
743 if ((temp_len = strnlen(devname, 300)) < 300) {
744 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
745 strcpy(vol->UNC,devname);
746 if (strncmp(vol->UNC, "//", 2) == 0) {
749 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
750 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
754 printk(KERN_WARNING "CIFS: UNC name too long\n");
759 vol->UNCip = &vol->UNC[2];
764 static struct cifsSesInfo *
765 cifs_find_tcp_session(__u32 new_target_ip_addr,
766 char *userName, struct TCP_Server_Info **psrvTcp)
768 struct list_head *tmp;
769 struct cifsSesInfo *ses;
772 read_lock(&GlobalSMBSeslock);
773 list_for_each(tmp, &GlobalSMBSessionList) {
774 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
776 if (ses->server->addr.sockAddr.sin_addr.s_addr ==
777 new_target_ip_addr) {
778 /* BB lock server and tcp session and increment use count here?? */
779 *psrvTcp = ses->server; /* found a match on the TCP session */
780 /* BB check if reconnection needed */
782 (ses->userName, userName,
783 MAX_USERNAME_SIZE) == 0){
784 read_unlock(&GlobalSMBSeslock);
785 return ses; /* found exact match on both tcp and SMB sessions */
789 /* else tcp and smb sessions need reconnection */
791 read_unlock(&GlobalSMBSeslock);
795 static struct cifsTconInfo *
796 find_unc(__u32 new_target_ip_addr, char *uncName, char *userName)
798 struct list_head *tmp;
799 struct cifsTconInfo *tcon;
801 read_lock(&GlobalSMBSeslock);
802 list_for_each(tmp, &GlobalTreeConnectionList) {
803 cFYI(1, ("Next tcon - "));
804 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
806 if (tcon->ses->server) {
808 (" old ip addr: %x == new ip %x ?",
809 tcon->ses->server->addr.sockAddr.sin_addr.
810 s_addr, new_target_ip_addr));
811 if (tcon->ses->server->addr.sockAddr.sin_addr.
812 s_addr == new_target_ip_addr) {
813 /* BB lock tcon and server and tcp session and increment use count here? */
814 /* found a match on the TCP session */
815 /* BB check if reconnection needed */
816 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
817 tcon->treeName, uncName));
819 (tcon->treeName, uncName,
820 MAX_TREE_SIZE) == 0) {
822 ("Matched UNC, old user: %s == new: %s ?",
823 tcon->treeName, uncName));
825 (tcon->ses->userName,
827 MAX_USERNAME_SIZE) == 0) {
828 read_unlock(&GlobalSMBSeslock);
829 return tcon;/* also matched user (smb session)*/
836 read_unlock(&GlobalSMBSeslock);
841 connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
842 const char *old_path, const struct nls_table *nls_codepage)
844 unsigned char *referrals = NULL;
845 unsigned int num_referrals;
848 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
849 &num_referrals, &referrals);
851 /* BB Add in code to: if valid refrl, if not ip address contact
852 the helper that resolves tcp names, mount to it, try to
853 tcon to it unmount it if fail */
862 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
863 const char *old_path, const struct nls_table *nls_codepage,
864 unsigned int *pnum_referrals, unsigned char ** preferrals)
871 if (pSesInfo->ipc_tid == 0) {
872 temp_unc = kmalloc(2 /* for slashes */ +
873 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
874 + 1 + 4 /* slash IPC$ */ + 2,
876 if (temp_unc == NULL)
880 strcpy(temp_unc + 2, pSesInfo->serverName);
881 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
882 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
884 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
888 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
889 pnum_referrals, nls_codepage);
894 /* See RFC1001 section 14 on representation of Netbios names */
895 static void rfc1002mangle(char * target,char * source, unsigned int length)
899 for(i=0,j=0;i<(length);i++) {
900 /* mask a nibble at a time and encode */
901 target[j] = 'A' + (0x0F & (source[i] >> 4));
902 target[j+1] = 'A' + (0x0F & source[i]);
910 ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
915 unsigned short int orig_port = 0;
917 if(*csocket == NULL) {
918 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
920 cERROR(1, ("Error %d creating socket",rc));
924 /* BB other socket options to set KEEPALIVE, NODELAY? */
925 cFYI(1,("Socket created"));
926 (*csocket)->sk->sk_allocation = GFP_NOFS;
930 psin_server->sin_family = AF_INET;
931 if(psin_server->sin_port) { /* user overrode default port */
932 rc = (*csocket)->ops->connect(*csocket,
933 (struct sockaddr *) psin_server,
934 sizeof (struct sockaddr_in),0);
940 /* save original port so we can retry user specified port
941 later if fall back ports fail this time */
942 orig_port = psin_server->sin_port;
944 /* do not retry on the same port we just failed on */
945 if(psin_server->sin_port != htons(CIFS_PORT)) {
946 psin_server->sin_port = htons(CIFS_PORT);
948 rc = (*csocket)->ops->connect(*csocket,
949 (struct sockaddr *) psin_server,
950 sizeof (struct sockaddr_in),0);
956 psin_server->sin_port = htons(RFC1001_PORT);
957 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
958 psin_server, sizeof (struct sockaddr_in),0);
963 /* give up here - unless we want to retry on different
964 protocol families some day */
967 psin_server->sin_port = orig_port;
968 cFYI(1,("Error %d connecting to server via ipv4",rc));
969 sock_release(*csocket);
973 /* Eventually check for other socket options to change from
974 the default. sock_setsockopt not used because it expects
976 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
978 /* send RFC1001 sessinit */
980 if(psin_server->sin_port == htons(139)) {
981 /* some servers require RFC1001 sessinit before sending
982 negprot - BB check reconnection in case where second
983 sessinit is sent but no second negprot */
984 struct rfc1002_session_packet * ses_init_buf;
985 struct smb_hdr * smb_buf;
986 ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
988 ses_init_buf->trailer.session_req.called_len = 32;
989 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
990 DEFAULT_CIFS_CALLED_NAME,16);
991 ses_init_buf->trailer.session_req.calling_len = 32;
992 /* calling name ends in null (byte 16) from old smb
994 if(netbios_name && (netbios_name[0] !=0)) {
995 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
998 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
999 "LINUX_CIFS_CLNT",16);
1001 ses_init_buf->trailer.session_req.scope1 = 0;
1002 ses_init_buf->trailer.session_req.scope2 = 0;
1003 smb_buf = (struct smb_hdr *)ses_init_buf;
1004 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1005 smb_buf->smb_buf_length = 0x81000044;
1006 rc = smb_send(*csocket, smb_buf, 0x44,
1007 (struct sockaddr *)psin_server);
1008 kfree(ses_init_buf);
1010 /* else the negprot may still work without this
1011 even though malloc failed */
1019 ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1024 if(*csocket == NULL) {
1025 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1027 cERROR(1, ("Error %d creating ipv6 socket",rc));
1031 /* BB other socket options to set KEEPALIVE, NODELAY? */
1032 cFYI(1,("ipv6 Socket created"));
1033 (*csocket)->sk->sk_allocation = GFP_NOFS;
1037 psin_server->sin6_family = AF_INET6;
1039 if(psin_server->sin6_port) { /* user overrode default port */
1040 rc = (*csocket)->ops->connect(*csocket,
1041 (struct sockaddr *) psin_server,
1042 sizeof (struct sockaddr_in6),0);
1048 /* do not retry on the same port we just failed on */
1049 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1050 psin_server->sin6_port = htons(CIFS_PORT);
1052 rc = (*csocket)->ops->connect(*csocket,
1053 (struct sockaddr *) psin_server,
1054 sizeof (struct sockaddr_in6),0);
1060 psin_server->sin6_port = htons(RFC1001_PORT);
1061 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1062 psin_server, sizeof (struct sockaddr_in6),0);
1067 /* give up here - unless we want to retry on different
1068 protocol families some day */
1070 cFYI(1,("Error %d connecting to server via ipv6",rc));
1071 sock_release(*csocket);
1075 /* Eventually check for other socket options to change from
1076 the default. sock_setsockopt not used because it expects
1077 user space buffer */
1078 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1084 cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1085 char *mount_data, const char *devname)
1089 struct socket *csocket = NULL;
1090 struct sockaddr_in sin_server;
1091 struct sockaddr_in6 sin_server6;
1092 struct smb_vol volume_info;
1093 struct cifsSesInfo *pSesInfo = NULL;
1094 struct cifsSesInfo *existingCifsSes = NULL;
1095 struct cifsTconInfo *tcon = NULL;
1096 struct TCP_Server_Info *srvTcp = NULL;
1100 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1102 memset(&volume_info,0,sizeof(struct smb_vol));
1103 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1105 kfree(volume_info.UNC);
1106 if(volume_info.password)
1107 kfree(volume_info.password);
1112 if (volume_info.username) {
1113 cFYI(1, ("Username: %s ", volume_info.username));
1116 cifserror("No username specified ");
1117 /* In userspace mount helper we can get user name from alternate
1118 locations such as env variables and files on disk */
1120 kfree(volume_info.UNC);
1121 if(volume_info.password)
1122 kfree(volume_info.password);
1127 if (volume_info.UNCip && volume_info.UNC) {
1128 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1131 /* not ipv4 address, try ipv6 */
1132 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1136 /* we failed translating address */
1138 kfree(volume_info.UNC);
1139 if(volume_info.password)
1140 kfree(volume_info.password);
1145 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1148 } else if (volume_info.UNCip){
1149 /* BB using ip addr as server name connect to the DFS root below */
1150 cERROR(1,("Connecting to DFS root not implemented yet"));
1152 kfree(volume_info.UNC);
1153 if(volume_info.password)
1154 kfree(volume_info.password);
1157 } else /* which servers DFS root would we conect to */ {
1159 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1161 kfree(volume_info.UNC);
1162 if(volume_info.password)
1163 kfree(volume_info.password);
1168 /* this is needed for ASCII cp to Unicode converts */
1169 if(volume_info.iocharset == NULL) {
1170 cifs_sb->local_nls = load_nls_default();
1171 /* load_nls_default can not return null */
1173 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1174 if(cifs_sb->local_nls == NULL) {
1175 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1177 kfree(volume_info.UNC);
1178 if(volume_info.password)
1179 kfree(volume_info.password);
1186 cifs_find_tcp_session(sin_server.sin_addr.s_addr,
1187 volume_info.username, &srvTcp);
1189 cFYI(1, ("Existing tcp session with server found "));
1190 } else { /* create socket */
1191 if(volume_info.port)
1192 sin_server.sin_port = htons(volume_info.port);
1194 sin_server.sin_port = 0;
1195 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1198 ("Error connecting to IPv4 socket. Aborting operation"));
1200 sock_release(csocket);
1202 kfree(volume_info.UNC);
1203 if(volume_info.password)
1204 kfree(volume_info.password);
1209 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1210 if (srvTcp == NULL) {
1212 sock_release(csocket);
1214 kfree(volume_info.UNC);
1215 if(volume_info.password)
1216 kfree(volume_info.password);
1220 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1221 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1222 atomic_set(&srvTcp->inFlight,0);
1223 /* BB Add code for ipv6 case too */
1224 srvTcp->ssocket = csocket;
1225 srvTcp->protocolType = IPV4;
1226 init_waitqueue_head(&srvTcp->response_q);
1227 init_waitqueue_head(&srvTcp->request_q);
1228 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1229 srvTcp->tcpStatus = CifsNew;
1230 init_MUTEX(&srvTcp->tcpSem);
1231 kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1232 CLONE_FS | CLONE_FILES | CLONE_VM);
1233 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
1237 if (existingCifsSes) {
1238 pSesInfo = existingCifsSes;
1239 cFYI(1, ("Existing smb sess found "));
1240 if(volume_info.password)
1241 kfree(volume_info.password);
1242 /* volume_info.UNC freed at end of function */
1244 cFYI(1, ("Existing smb sess not found "));
1245 pSesInfo = sesInfoAlloc();
1246 if (pSesInfo == NULL)
1249 pSesInfo->server = srvTcp;
1250 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1251 NIPQUAD(sin_server.sin_addr.s_addr));
1255 /* volume_info.password freed at unmount */
1256 if (volume_info.password)
1257 pSesInfo->password = volume_info.password;
1258 if (volume_info.username)
1259 strncpy(pSesInfo->userName,
1260 volume_info.username,MAX_USERNAME_SIZE);
1261 if (volume_info.domainname)
1262 strncpy(pSesInfo->domainName,
1263 volume_info.domainname,MAX_USERNAME_SIZE);
1264 pSesInfo->linux_uid = volume_info.linux_uid;
1265 down(&pSesInfo->sesSem);
1266 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1267 up(&pSesInfo->sesSem);
1269 atomic_inc(&srvTcp->socketUseCount);
1271 if(volume_info.password)
1272 kfree(volume_info.password);
1275 /* search for existing tcon to this server share */
1277 if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
1278 cifs_sb->rsize = volume_info.rsize;
1280 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1281 if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
1282 cifs_sb->wsize = volume_info.wsize;
1284 cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1285 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1286 cifs_sb->rsize = PAGE_CACHE_SIZE;
1287 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1289 cifs_sb->mnt_uid = volume_info.linux_uid;
1290 cifs_sb->mnt_gid = volume_info.linux_gid;
1291 cifs_sb->mnt_file_mode = volume_info.file_mode;
1292 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1293 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1295 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1296 volume_info.username);
1298 cFYI(1, ("Found match on UNC path "));
1299 /* we can have only one retry value for a connection
1300 to a share so for resources mounted more than once
1301 to the same server share the last value passed in
1302 for the retry flag is used */
1303 tcon->retry = volume_info.retry;
1305 tcon = tconInfoAlloc();
1309 /* check for null share name ie connect to dfs root */
1311 /* BB check if this works for exactly length three strings */
1312 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1313 && (strchr(volume_info.UNC + 3, '/') ==
1315 rc = connect_to_dfs_path(xid,
1321 kfree(volume_info.UNC);
1325 rc = CIFSTCon(xid, pSesInfo,
1327 tcon, cifs_sb->local_nls);
1328 cFYI(1, ("CIFS Tcon rc = %d", rc));
1331 atomic_inc(&pSesInfo->inUse);
1332 tcon->retry = volume_info.retry;
1337 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1338 cFYI(0, ("Large files supported "));
1339 sb->s_maxbytes = (u64) 1 << 63;
1341 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1343 /* on error free sesinfo and tcon struct if needed */
1345 if(atomic_read(&srvTcp->socketUseCount) == 0)
1346 srvTcp->tcpStatus = CifsExiting;
1347 /* If find_unc succeeded then rc == 0 so we can not end */
1348 if (tcon) /* up here accidently freeing someone elses tcon struct */
1350 if (existingCifsSes == 0) {
1352 if (pSesInfo->server) {
1354 CIFSSMBLogoff(xid, pSesInfo);
1355 if(pSesInfo->server->tsk)
1356 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1357 set_current_state(TASK_INTERRUPTIBLE);
1358 schedule_timeout(HZ / 4); /* give captive thread time to exit */
1360 cFYI(1, ("No session or bad tcon"));
1361 sesInfoFree(pSesInfo);
1362 /* pSesInfo = NULL; */
1366 atomic_inc(&tcon->useCount);
1367 cifs_sb->tcon = tcon;
1368 tcon->ses = pSesInfo;
1370 /* do not care if following two calls succeed - informational only */
1371 CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
1372 CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
1373 if (tcon->ses->capabilities & CAP_UNIX)
1374 CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls);
1377 /* volume_info.password is freed above when existing session found
1378 (in which case it is not needed anymore) but when new sesion is created
1379 the password ptr is put in the new session structure (in which case the
1380 password will be freed at unmount time) */
1382 kfree(volume_info.UNC);
1388 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1389 char session_key[CIFS_SESSION_KEY_SIZE],
1390 const struct nls_table *nls_codepage)
1392 struct smb_hdr *smb_buffer;
1393 struct smb_hdr *smb_buffer_response;
1394 SESSION_SETUP_ANDX *pSMB;
1395 SESSION_SETUP_ANDX *pSMBr;
1397 char *user = ses->userName;
1398 char *domain = ses->domainName;
1400 int remaining_words = 0;
1401 int bytes_returned = 0;
1404 cFYI(1, ("In sesssetup "));
1406 smb_buffer = cifs_buf_get();
1407 if (smb_buffer == 0) {
1410 smb_buffer_response = smb_buffer;
1411 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1413 /* send SMBsessionSetup here */
1414 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1415 0 /* no tCon exists yet */ , 13 /* wct */ );
1417 pSMB->req_no_secext.AndXCommand = 0xFF;
1418 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1419 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1421 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1422 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1424 pSMB->req_no_secext.Capabilities =
1425 CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS;
1426 if (ses->capabilities & CAP_UNICODE) {
1427 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1428 pSMB->req_no_secext.Capabilities |= CAP_UNICODE;
1430 if (ses->capabilities & CAP_STATUS32) {
1431 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1432 pSMB->req_no_secext.Capabilities |= CAP_STATUS32;
1434 if (ses->capabilities & CAP_DFS) {
1435 smb_buffer->Flags2 |= SMBFLG2_DFS;
1436 pSMB->req_no_secext.Capabilities |= CAP_DFS;
1438 pSMB->req_no_secext.Capabilities =
1439 cpu_to_le32(pSMB->req_no_secext.Capabilities);
1440 /* pSMB->req_no_secext.CaseInsensitivePasswordLength =
1441 CIFS_SESSION_KEY_SIZE; */
1442 pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
1443 pSMB->req_no_secext.CaseSensitivePasswordLength =
1444 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1445 bcc_ptr = pByteArea(smb_buffer);
1446 /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE);
1447 bcc_ptr += CIFS_SESSION_KEY_SIZE; */
1448 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1449 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1451 if (ses->capabilities & CAP_UNICODE) {
1452 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1457 bytes_returned = 0; /* skill null user */
1460 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1462 bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */
1463 bcc_ptr += 2; /* trailing null */
1466 cifs_strtoUCS((wchar_t *) bcc_ptr,
1467 "CIFS_LINUX_DOM", 32, nls_codepage);
1470 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1472 bcc_ptr += 2 * bytes_returned;
1475 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1477 bcc_ptr += 2 * bytes_returned;
1479 cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
1481 bcc_ptr += 2 * bytes_returned;
1484 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1486 bcc_ptr += 2 * bytes_returned;
1490 strncpy(bcc_ptr, user, 200);
1491 bcc_ptr += strnlen(user, 200);
1495 if (domain == NULL) {
1496 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1497 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1499 strncpy(bcc_ptr, domain, 64);
1500 bcc_ptr += strnlen(domain, 64);
1504 strcpy(bcc_ptr, "Linux version ");
1505 bcc_ptr += strlen("Linux version ");
1506 strcpy(bcc_ptr, UTS_RELEASE);
1507 bcc_ptr += strlen(UTS_RELEASE) + 1;
1508 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1509 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1511 BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1512 smb_buffer->smb_buf_length += BCC(smb_buffer);
1513 BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
1515 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1516 &bytes_returned, 1);
1518 /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1519 } else if ((smb_buffer_response->WordCount == 3)
1520 || (smb_buffer_response->WordCount == 4)) {
1521 pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
1522 if (pSMBr->resp.Action & GUEST_LOGIN)
1523 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
1525 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1526 cFYI(1, ("UID = %d ", ses->Suid));
1527 /* response can have either 3 or 4 word count - Samba sends 3 */
1528 bcc_ptr = pByteArea(smb_buffer_response);
1529 if ((pSMBr->resp.hdr.WordCount == 3)
1530 || ((pSMBr->resp.hdr.WordCount == 4)
1531 && (pSMBr->resp.SecurityBlobLength <
1532 pSMBr->resp.ByteCount))) {
1533 if (pSMBr->resp.hdr.WordCount == 4)
1535 pSMBr->resp.SecurityBlobLength;
1537 if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
1538 if ((long) (bcc_ptr) % 2) {
1540 (BCC(smb_buffer_response)
1542 bcc_ptr++; /* Unicode strings must be word aligned */
1546 (smb_buffer_response) / 2;
1549 UniStrnlen((wchar_t *) bcc_ptr,
1550 remaining_words - 1);
1551 /* We look for obvious messed up bcc or strings in response so we do not go off
1552 the end since (at least) WIN2K and Windows XP have a major bug in not null
1553 terminating last Unicode string in response */
1554 ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
1555 cifs_strfromUCS_le(ses->serverOS,
1556 (wchar_t *)bcc_ptr, len,nls_codepage);
1557 bcc_ptr += 2 * (len + 1);
1558 remaining_words -= len + 1;
1559 ses->serverOS[2 * len] = 0;
1560 ses->serverOS[1 + (2 * len)] = 0;
1561 if (remaining_words > 0) {
1562 len = UniStrnlen((wchar_t *)bcc_ptr,
1565 ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL);
1566 cifs_strfromUCS_le(ses->serverNOS,
1567 (wchar_t *)bcc_ptr,len,nls_codepage);
1568 bcc_ptr += 2 * (len + 1);
1569 ses->serverNOS[2 * len] = 0;
1570 ses->serverNOS[1 + (2 * len)] = 0;
1571 remaining_words -= len + 1;
1572 if (remaining_words > 0) {
1573 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
1574 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1576 cifs_kcalloc(2*(len+1),GFP_KERNEL);
1577 cifs_strfromUCS_le(ses->serverDomain,
1578 (wchar_t *)bcc_ptr,len,nls_codepage);
1579 bcc_ptr += 2 * (len + 1);
1580 ses->serverDomain[2*len] = 0;
1581 ses->serverDomain[1+(2*len)] = 0;
1582 } /* else no more room so create dummy domain string */
1587 } else { /* no room so create dummy domain and NOS string */
1589 cifs_kcalloc(2, GFP_KERNEL);
1591 cifs_kcalloc(2, GFP_KERNEL);
1593 } else { /* ASCII */
1594 len = strnlen(bcc_ptr, 1024);
1595 if (((long) bcc_ptr + len) - (long)
1596 pByteArea(smb_buffer_response)
1597 <= BCC(smb_buffer_response)) {
1598 ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
1599 strncpy(ses->serverOS,bcc_ptr, len);
1602 bcc_ptr[0] = 0; /* null terminate the string */
1605 len = strnlen(bcc_ptr, 1024);
1606 ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
1607 strncpy(ses->serverNOS, bcc_ptr, len);
1612 len = strnlen(bcc_ptr, 1024);
1613 ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL);
1614 strncpy(ses->serverDomain, bcc_ptr, len);
1620 ("Variable field of length %d extends beyond end of smb ",
1625 (" Security Blob Length extends beyond end of SMB"));
1628 cERROR(1, ("No session structure passed in."));
1632 (" Invalid Word count %d: ",
1633 smb_buffer_response->WordCount));
1638 cifs_buf_release(smb_buffer);
1644 CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1645 char *SecurityBlob,int SecurityBlobLength,
1646 const struct nls_table *nls_codepage)
1648 struct smb_hdr *smb_buffer;
1649 struct smb_hdr *smb_buffer_response;
1650 SESSION_SETUP_ANDX *pSMB;
1651 SESSION_SETUP_ANDX *pSMBr;
1653 char *user = ses->userName;
1654 char *domain = ses->domainName;
1656 int remaining_words = 0;
1657 int bytes_returned = 0;
1660 cFYI(1, ("In spnego sesssetup "));
1662 smb_buffer = cifs_buf_get();
1663 if (smb_buffer == 0) {
1666 smb_buffer_response = smb_buffer;
1667 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1669 /* send SMBsessionSetup here */
1670 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1671 0 /* no tCon exists yet */ , 12 /* wct */ );
1672 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
1673 pSMB->req.AndXCommand = 0xFF;
1674 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1675 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1677 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1678 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1680 pSMB->req.Capabilities =
1681 CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1682 CAP_EXTENDED_SECURITY;
1683 if (ses->capabilities & CAP_UNICODE) {
1684 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1685 pSMB->req.Capabilities |= CAP_UNICODE;
1687 if (ses->capabilities & CAP_STATUS32) {
1688 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1689 pSMB->req.Capabilities |= CAP_STATUS32;
1691 if (ses->capabilities & CAP_DFS) {
1692 smb_buffer->Flags2 |= SMBFLG2_DFS;
1693 pSMB->req.Capabilities |= CAP_DFS;
1695 pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
1697 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
1698 bcc_ptr = pByteArea(smb_buffer);
1699 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
1700 bcc_ptr += SecurityBlobLength;
1702 if (ses->capabilities & CAP_UNICODE) {
1703 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
1708 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
1709 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
1710 bcc_ptr += 2; /* trailing null */
1713 cifs_strtoUCS((wchar_t *) bcc_ptr,
1714 "CIFS_LINUX_DOM", 32, nls_codepage);
1717 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1719 bcc_ptr += 2 * bytes_returned;
1722 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1724 bcc_ptr += 2 * bytes_returned;
1726 cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
1728 bcc_ptr += 2 * bytes_returned;
1731 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1733 bcc_ptr += 2 * bytes_returned;
1736 strncpy(bcc_ptr, user, 200);
1737 bcc_ptr += strnlen(user, 200);
1740 if (domain == NULL) {
1741 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1742 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1744 strncpy(bcc_ptr, domain, 64);
1745 bcc_ptr += strnlen(domain, 64);
1749 strcpy(bcc_ptr, "Linux version ");
1750 bcc_ptr += strlen("Linux version ");
1751 strcpy(bcc_ptr, UTS_RELEASE);
1752 bcc_ptr += strlen(UTS_RELEASE) + 1;
1753 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1754 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1756 BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1757 smb_buffer->smb_buf_length += BCC(smb_buffer);
1758 BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
1760 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1761 &bytes_returned, 1);
1763 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
1764 } else if ((smb_buffer_response->WordCount == 3)
1765 || (smb_buffer_response->WordCount == 4)) {
1766 pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
1767 pSMBr->resp.SecurityBlobLength =
1768 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1769 if (pSMBr->resp.Action & GUEST_LOGIN)
1770 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
1772 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1773 cFYI(1, ("UID = %d ", ses->Suid));
1774 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
1776 /* BB Fix below to make endian neutral !! */
1778 if ((pSMBr->resp.hdr.WordCount == 3)
1779 || ((pSMBr->resp.hdr.WordCount == 4)
1780 && (pSMBr->resp.SecurityBlobLength <
1781 pSMBr->resp.ByteCount))) {
1782 if (pSMBr->resp.hdr.WordCount == 4) {
1784 pSMBr->resp.SecurityBlobLength;
1786 ("Security Blob Length %d ",
1787 pSMBr->resp.SecurityBlobLength));
1790 if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
1791 if ((long) (bcc_ptr) % 2) {
1793 (BCC(smb_buffer_response)
1795 bcc_ptr++; /* Unicode strings must be word aligned */
1799 (smb_buffer_response) / 2;
1802 UniStrnlen((wchar_t *) bcc_ptr,
1803 remaining_words - 1);
1804 /* We look for obvious messed up bcc or strings in response so we do not go off
1805 the end since (at least) WIN2K and Windows XP have a major bug in not null
1806 terminating last Unicode string in response */
1808 cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
1809 cifs_strfromUCS_le(ses->serverOS,
1813 bcc_ptr += 2 * (len + 1);
1814 remaining_words -= len + 1;
1815 ses->serverOS[2 * len] = 0;
1816 ses->serverOS[1 + (2 * len)] = 0;
1817 if (remaining_words > 0) {
1818 len = UniStrnlen((wchar_t *)bcc_ptr,
1822 cifs_kcalloc(2 * (len + 1),
1824 cifs_strfromUCS_le(ses->serverNOS,
1828 bcc_ptr += 2 * (len + 1);
1829 ses->serverNOS[2 * len] = 0;
1830 ses->serverNOS[1 + (2 * len)] = 0;
1831 remaining_words -= len + 1;
1832 if (remaining_words > 0) {
1833 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
1834 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1835 ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL);
1836 cifs_strfromUCS_le(ses->serverDomain,
1840 bcc_ptr += 2*(len+1);
1841 ses->serverDomain[2*len] = 0;
1842 ses->serverDomain[1+(2*len)] = 0;
1843 } /* else no more room so create dummy domain string */
1846 cifs_kcalloc(2,GFP_KERNEL);
1847 } else { /* no room so create dummy domain and NOS string */
1848 ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
1849 ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
1851 } else { /* ASCII */
1853 len = strnlen(bcc_ptr, 1024);
1854 if (((long) bcc_ptr + len) - (long)
1855 pByteArea(smb_buffer_response)
1856 <= BCC(smb_buffer_response)) {
1857 ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL);
1858 strncpy(ses->serverOS, bcc_ptr, len);
1861 bcc_ptr[0] = 0; /* null terminate the string */
1864 len = strnlen(bcc_ptr, 1024);
1865 ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
1866 strncpy(ses->serverNOS, bcc_ptr, len);
1871 len = strnlen(bcc_ptr, 1024);
1872 ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL);
1873 strncpy(ses->serverDomain, bcc_ptr, len);
1879 ("Variable field of length %d extends beyond end of smb ",
1884 (" Security Blob Length extends beyond end of SMB"));
1887 cERROR(1, ("No session structure passed in."));
1891 (" Invalid Word count %d: ",
1892 smb_buffer_response->WordCount));
1897 cifs_buf_release(smb_buffer);
1903 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
1904 struct cifsSesInfo *ses, int * pNTLMv2_flag,
1905 const struct nls_table *nls_codepage)
1907 struct smb_hdr *smb_buffer;
1908 struct smb_hdr *smb_buffer_response;
1909 SESSION_SETUP_ANDX *pSMB;
1910 SESSION_SETUP_ANDX *pSMBr;
1912 char *domain = ses->domainName;
1914 int remaining_words = 0;
1915 int bytes_returned = 0;
1917 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
1918 PNEGOTIATE_MESSAGE SecurityBlob;
1919 PCHALLENGE_MESSAGE SecurityBlob2;
1921 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
1922 *pNTLMv2_flag = FALSE;
1923 smb_buffer = cifs_buf_get();
1924 if (smb_buffer == 0) {
1927 smb_buffer_response = smb_buffer;
1928 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1929 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
1931 /* send SMBsessionSetup here */
1932 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1933 0 /* no tCon exists yet */ , 12 /* wct */ );
1934 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
1935 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
1937 pSMB->req.AndXCommand = 0xFF;
1938 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1939 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1941 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1942 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1944 pSMB->req.Capabilities =
1945 CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1946 CAP_EXTENDED_SECURITY;
1947 if (ses->capabilities & CAP_UNICODE) {
1948 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1949 pSMB->req.Capabilities |= CAP_UNICODE;
1951 if (ses->capabilities & CAP_STATUS32) {
1952 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1953 pSMB->req.Capabilities |= CAP_STATUS32;
1955 if (ses->capabilities & CAP_DFS) {
1956 smb_buffer->Flags2 |= SMBFLG2_DFS;
1957 pSMB->req.Capabilities |= CAP_DFS;
1959 pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
1961 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
1962 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
1963 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
1964 SecurityBlob->MessageType = NtLmNegotiate;
1965 SecurityBlob->NegotiateFlags =
1966 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
1967 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
1968 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
1970 SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
1972 SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
1973 /* setup pointers to domain name and workstation name */
1974 bcc_ptr += SecurityBlobLength;
1976 SecurityBlob->WorkstationName.Buffer = 0;
1977 SecurityBlob->WorkstationName.Length = 0;
1978 SecurityBlob->WorkstationName.MaximumLength = 0;
1980 if (domain == NULL) {
1981 SecurityBlob->DomainName.Buffer = 0;
1982 SecurityBlob->DomainName.Length = 0;
1983 SecurityBlob->DomainName.MaximumLength = 0;
1985 SecurityBlob->NegotiateFlags |=
1986 NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
1987 strncpy(bcc_ptr, domain, 63);
1988 SecurityBlob->DomainName.Length = strnlen(domain, 64);
1989 SecurityBlob->DomainName.MaximumLength =
1990 cpu_to_le16(SecurityBlob->DomainName.Length);
1991 SecurityBlob->DomainName.Buffer =
1992 cpu_to_le32((long) &SecurityBlob->
1994 (long) &SecurityBlob->Signature);
1995 bcc_ptr += SecurityBlob->DomainName.Length;
1996 SecurityBlobLength += SecurityBlob->DomainName.Length;
1997 SecurityBlob->DomainName.Length =
1998 cpu_to_le16(SecurityBlob->DomainName.Length);
2000 if (ses->capabilities & CAP_UNICODE) {
2001 if ((long) bcc_ptr % 2) {
2007 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2009 bcc_ptr += 2 * bytes_returned;
2011 cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
2013 bcc_ptr += 2 * bytes_returned;
2014 bcc_ptr += 2; /* null terminate Linux version */
2016 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2018 bcc_ptr += 2 * bytes_returned;
2021 bcc_ptr += 2; /* null terminate network opsys string */
2024 bcc_ptr += 2; /* null domain */
2025 } else { /* ASCII */
2026 strcpy(bcc_ptr, "Linux version ");
2027 bcc_ptr += strlen("Linux version ");
2028 strcpy(bcc_ptr, UTS_RELEASE);
2029 bcc_ptr += strlen(UTS_RELEASE) + 1;
2030 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2031 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2032 bcc_ptr++; /* empty domain field */
2035 SecurityBlob->NegotiateFlags =
2036 cpu_to_le32(SecurityBlob->NegotiateFlags);
2037 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2038 BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2039 smb_buffer->smb_buf_length += BCC(smb_buffer);
2040 BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
2042 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2043 &bytes_returned, 1);
2045 if (smb_buffer_response->Status.CifsError ==
2046 (NT_STATUS_MORE_PROCESSING_REQUIRED))
2050 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2051 } else if ((smb_buffer_response->WordCount == 3)
2052 || (smb_buffer_response->WordCount == 4)) {
2053 pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
2054 pSMBr->resp.SecurityBlobLength =
2055 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2056 if (pSMBr->resp.Action & GUEST_LOGIN)
2057 cFYI(1, (" Guest login"));
2058 /* Do we want to set anything in SesInfo struct when guest login? */
2060 bcc_ptr = pByteArea(smb_buffer_response);
2061 /* response can have either 3 or 4 word count - Samba sends 3 */
2063 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2064 if (SecurityBlob2->MessageType != NtLmChallenge) {
2066 ("Unexpected NTLMSSP message type received %d",
2067 SecurityBlob2->MessageType));
2069 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2070 cFYI(1, ("UID = %d ", ses->Suid));
2071 if ((pSMBr->resp.hdr.WordCount == 3)
2072 || ((pSMBr->resp.hdr.WordCount == 4)
2073 && (pSMBr->resp.SecurityBlobLength <
2074 pSMBr->resp.ByteCount))) {
2075 if (pSMBr->resp.hdr.WordCount == 4) {
2077 pSMBr->resp.SecurityBlobLength;
2079 ("Security Blob Length %d ",
2080 pSMBr->resp.SecurityBlobLength));
2083 cFYI(1, ("NTLMSSP Challenge rcvd "));
2085 memcpy(ses->server->cryptKey,
2086 SecurityBlob2->Challenge,
2087 CIFS_CRYPTO_KEY_SIZE);
2088 if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2)
2089 *pNTLMv2_flag = TRUE;
2091 if((SecurityBlob2->NegotiateFlags &
2092 NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
2093 || (sign_CIFS_PDUs > 1))
2094 ses->server->secMode |=
2095 SECMODE_SIGN_REQUIRED;
2096 if ((SecurityBlob2->NegotiateFlags &
2097 NTLMSSP_NEGOTIATE_SIGN) && (sign_CIFS_PDUs))
2098 ses->server->secMode |=
2099 SECMODE_SIGN_ENABLED;
2101 if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
2102 if ((long) (bcc_ptr) % 2) {
2104 (BCC(smb_buffer_response)
2106 bcc_ptr++; /* Unicode strings must be word aligned */
2110 (smb_buffer_response) / 2;
2113 UniStrnlen((wchar_t *) bcc_ptr,
2114 remaining_words - 1);
2115 /* We look for obvious messed up bcc or strings in response so we do not go off
2116 the end since (at least) WIN2K and Windows XP have a major bug in not null
2117 terminating last Unicode string in response */
2119 cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
2120 cifs_strfromUCS_le(ses->serverOS,
2124 bcc_ptr += 2 * (len + 1);
2125 remaining_words -= len + 1;
2126 ses->serverOS[2 * len] = 0;
2127 ses->serverOS[1 + (2 * len)] = 0;
2128 if (remaining_words > 0) {
2129 len = UniStrnlen((wchar_t *)
2134 cifs_kcalloc(2 * (len + 1),
2136 cifs_strfromUCS_le(ses->
2142 bcc_ptr += 2 * (len + 1);
2143 ses->serverNOS[2 * len] = 0;
2146 remaining_words -= len + 1;
2147 if (remaining_words > 0) {
2148 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2149 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2174 } /* else no more room so create dummy domain string */
2179 } else { /* no room so create dummy domain and NOS string */
2181 cifs_kcalloc(2, GFP_KERNEL);
2183 cifs_kcalloc(2, GFP_KERNEL);
2185 } else { /* ASCII */
2186 len = strnlen(bcc_ptr, 1024);
2187 if (((long) bcc_ptr + len) - (long)
2188 pByteArea(smb_buffer_response)
2189 <= BCC(smb_buffer_response)) {
2191 cifs_kcalloc(len + 1,
2193 strncpy(ses->serverOS,
2197 bcc_ptr[0] = 0; /* null terminate string */
2200 len = strnlen(bcc_ptr, 1024);
2202 cifs_kcalloc(len + 1,
2204 strncpy(ses->serverNOS, bcc_ptr, len);
2209 len = strnlen(bcc_ptr, 1024);
2211 cifs_kcalloc(len + 1,
2213 strncpy(ses->serverDomain, bcc_ptr, len);
2219 ("Variable field of length %d extends beyond end of smb ",
2224 (" Security Blob Length extends beyond end of SMB"));
2227 cERROR(1, ("No session structure passed in."));
2231 (" Invalid Word count %d: ",
2232 smb_buffer_response->WordCount));
2237 cifs_buf_release(smb_buffer);
2243 CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2244 char *ntlm_session_key, int ntlmv2_flag,
2245 const struct nls_table *nls_codepage)
2247 struct smb_hdr *smb_buffer;
2248 struct smb_hdr *smb_buffer_response;
2249 SESSION_SETUP_ANDX *pSMB;
2250 SESSION_SETUP_ANDX *pSMBr;
2252 char *user = ses->userName;
2253 char *domain = ses->domainName;
2255 int remaining_words = 0;
2256 int bytes_returned = 0;
2258 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2259 PAUTHENTICATE_MESSAGE SecurityBlob;
2261 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2263 smb_buffer = cifs_buf_get();
2264 if (smb_buffer == 0) {
2267 smb_buffer_response = smb_buffer;
2268 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2269 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2271 /* send SMBsessionSetup here */
2272 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2273 0 /* no tCon exists yet */ , 12 /* wct */ );
2274 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2275 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2276 pSMB->req.AndXCommand = 0xFF;
2277 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2278 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2280 pSMB->req.hdr.Uid = ses->Suid;
2282 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2283 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2285 pSMB->req.Capabilities =
2286 CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2287 CAP_EXTENDED_SECURITY;
2288 if (ses->capabilities & CAP_UNICODE) {
2289 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2290 pSMB->req.Capabilities |= CAP_UNICODE;
2292 if (ses->capabilities & CAP_STATUS32) {
2293 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2294 pSMB->req.Capabilities |= CAP_STATUS32;
2296 if (ses->capabilities & CAP_DFS) {
2297 smb_buffer->Flags2 |= SMBFLG2_DFS;
2298 pSMB->req.Capabilities |= CAP_DFS;
2300 pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
2302 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2303 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2304 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2305 SecurityBlob->MessageType = NtLmAuthenticate;
2306 bcc_ptr += SecurityBlobLength;
2307 SecurityBlob->NegotiateFlags =
2308 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2309 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2310 0x80000000 | NTLMSSP_NEGOTIATE_128;
2312 SecurityBlob->NegotiateFlags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2314 SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
2316 /* setup pointers to domain name and workstation name */
2318 SecurityBlob->WorkstationName.Buffer = 0;
2319 SecurityBlob->WorkstationName.Length = 0;
2320 SecurityBlob->WorkstationName.MaximumLength = 0;
2321 SecurityBlob->SessionKey.Length = 0;
2322 SecurityBlob->SessionKey.MaximumLength = 0;
2323 SecurityBlob->SessionKey.Buffer = 0;
2325 SecurityBlob->LmChallengeResponse.Length = 0;
2326 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2327 SecurityBlob->LmChallengeResponse.Buffer = 0;
2329 SecurityBlob->NtChallengeResponse.Length =
2330 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2331 SecurityBlob->NtChallengeResponse.MaximumLength =
2332 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2333 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2334 SecurityBlob->NtChallengeResponse.Buffer =
2335 cpu_to_le32(SecurityBlobLength);
2336 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2337 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2339 if (ses->capabilities & CAP_UNICODE) {
2340 if (domain == NULL) {
2341 SecurityBlob->DomainName.Buffer = 0;
2342 SecurityBlob->DomainName.Length = 0;
2343 SecurityBlob->DomainName.MaximumLength = 0;
2345 SecurityBlob->DomainName.Length =
2346 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2348 SecurityBlob->DomainName.Length *= 2;
2349 SecurityBlob->DomainName.MaximumLength =
2350 cpu_to_le16(SecurityBlob->DomainName.Length);
2351 SecurityBlob->DomainName.Buffer =
2352 cpu_to_le32(SecurityBlobLength);
2353 bcc_ptr += SecurityBlob->DomainName.Length;
2354 SecurityBlobLength += SecurityBlob->DomainName.Length;
2355 SecurityBlob->DomainName.Length =
2356 cpu_to_le16(SecurityBlob->DomainName.Length);
2359 SecurityBlob->UserName.Buffer = 0;
2360 SecurityBlob->UserName.Length = 0;
2361 SecurityBlob->UserName.MaximumLength = 0;
2363 SecurityBlob->UserName.Length =
2364 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2366 SecurityBlob->UserName.Length *= 2;
2367 SecurityBlob->UserName.MaximumLength =
2368 cpu_to_le16(SecurityBlob->UserName.Length);
2369 SecurityBlob->UserName.Buffer =
2370 cpu_to_le32(SecurityBlobLength);
2371 bcc_ptr += SecurityBlob->UserName.Length;
2372 SecurityBlobLength += SecurityBlob->UserName.Length;
2373 SecurityBlob->UserName.Length =
2374 cpu_to_le16(SecurityBlob->UserName.Length);
2377 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2378 SecurityBlob->WorkstationName.Length *= 2;
2379 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2380 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2381 bcc_ptr += SecurityBlob->WorkstationName.Length;
2382 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2383 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2385 if ((long) bcc_ptr % 2) {
2390 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2392 bcc_ptr += 2 * bytes_returned;
2394 cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
2396 bcc_ptr += 2 * bytes_returned;
2397 bcc_ptr += 2; /* null term version string */
2399 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2401 bcc_ptr += 2 * bytes_returned;
2404 bcc_ptr += 2; /* null terminate network opsys string */
2407 bcc_ptr += 2; /* null domain */
2408 } else { /* ASCII */
2409 if (domain == NULL) {
2410 SecurityBlob->DomainName.Buffer = 0;
2411 SecurityBlob->DomainName.Length = 0;
2412 SecurityBlob->DomainName.MaximumLength = 0;
2414 SecurityBlob->NegotiateFlags |=
2415 NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2416 strncpy(bcc_ptr, domain, 63);
2417 SecurityBlob->DomainName.Length = strnlen(domain, 64);
2418 SecurityBlob->DomainName.MaximumLength =
2419 cpu_to_le16(SecurityBlob->DomainName.Length);
2420 SecurityBlob->DomainName.Buffer =
2421 cpu_to_le32(SecurityBlobLength);
2422 bcc_ptr += SecurityBlob->DomainName.Length;
2423 SecurityBlobLength += SecurityBlob->DomainName.Length;
2424 SecurityBlob->DomainName.Length =
2425 cpu_to_le16(SecurityBlob->DomainName.Length);
2428 SecurityBlob->UserName.Buffer = 0;
2429 SecurityBlob->UserName.Length = 0;
2430 SecurityBlob->UserName.MaximumLength = 0;
2432 strncpy(bcc_ptr, user, 63);
2433 SecurityBlob->UserName.Length = strnlen(user, 64);
2434 SecurityBlob->UserName.MaximumLength =
2435 cpu_to_le16(SecurityBlob->UserName.Length);
2436 SecurityBlob->UserName.Buffer =
2437 cpu_to_le32(SecurityBlobLength);
2438 bcc_ptr += SecurityBlob->UserName.Length;
2439 SecurityBlobLength += SecurityBlob->UserName.Length;
2440 SecurityBlob->UserName.Length =
2441 cpu_to_le16(SecurityBlob->UserName.Length);
2443 /* BB fill in our workstation name if known BB */
2445 strcpy(bcc_ptr, "Linux version ");
2446 bcc_ptr += strlen("Linux version ");
2447 strcpy(bcc_ptr, UTS_RELEASE);
2448 bcc_ptr += strlen(UTS_RELEASE) + 1;
2449 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2450 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2451 bcc_ptr++; /* null domain */
2454 SecurityBlob->NegotiateFlags =
2455 cpu_to_le32(SecurityBlob->NegotiateFlags);
2456 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2457 BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2458 smb_buffer->smb_buf_length += BCC(smb_buffer);
2459 BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
2461 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2462 &bytes_returned, 1);
2464 /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2465 } else if ((smb_buffer_response->WordCount == 3)
2466 || (smb_buffer_response->WordCount == 4)) {
2467 pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
2468 pSMBr->resp.SecurityBlobLength =
2469 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2470 if (pSMBr->resp.Action & GUEST_LOGIN)
2471 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2472 /* if(SecurityBlob2->MessageType != NtLm??){
2473 cFYI("Unexpected message type on auth response is %d "));
2477 ("Does UID on challenge %d match auth response UID %d ",
2478 ses->Suid, smb_buffer_response->Uid));
2479 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2480 bcc_ptr = pByteArea(smb_buffer_response);
2481 /* response can have either 3 or 4 word count - Samba sends 3 */
2482 if ((pSMBr->resp.hdr.WordCount == 3)
2483 || ((pSMBr->resp.hdr.WordCount == 4)
2484 && (pSMBr->resp.SecurityBlobLength <
2485 pSMBr->resp.ByteCount))) {
2486 if (pSMBr->resp.hdr.WordCount == 4) {
2488 pSMBr->resp.SecurityBlobLength;
2490 ("Security Blob Length %d ",
2491 pSMBr->resp.SecurityBlobLength));
2495 ("NTLMSSP response to Authenticate "));
2497 if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
2498 if ((long) (bcc_ptr) % 2) {
2500 (BCC(smb_buffer_response)
2502 bcc_ptr++; /* Unicode strings must be word aligned */
2504 remaining_words = BCC(smb_buffer_response) / 2;
2507 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2508 /* We look for obvious messed up bcc or strings in response so we do not go off
2509 the end since (at least) WIN2K and Windows XP have a major bug in not null
2510 terminating last Unicode string in response */
2512 cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
2513 cifs_strfromUCS_le(ses->serverOS,
2517 bcc_ptr += 2 * (len + 1);
2518 remaining_words -= len + 1;
2519 ses->serverOS[2 * len] = 0;
2520 ses->serverOS[1 + (2 * len)] = 0;
2521 if (remaining_words > 0) {
2522 len = UniStrnlen((wchar_t *)
2527 cifs_kcalloc(2 * (len + 1),
2529 cifs_strfromUCS_le(ses->
2535 bcc_ptr += 2 * (len + 1);
2536 ses->serverNOS[2 * len] = 0;
2537 ses->serverNOS[1+(2*len)] = 0;
2538 remaining_words -= len + 1;
2539 if (remaining_words > 0) {
2540 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2541 /* last string not always null terminated (e.g. for Windows XP & 2000) */
2566 } /* else no more room so create dummy domain string */
2568 ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL);
2569 } else { /* no room so create dummy domain and NOS string */
2570 ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
2571 ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
2573 } else { /* ASCII */
2574 len = strnlen(bcc_ptr, 1024);
2575 if (((long) bcc_ptr + len) -
2576 (long) pByteArea(smb_buffer_response)
2577 <= BCC(smb_buffer_response)) {
2578 ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
2579 strncpy(ses->serverOS,bcc_ptr, len);
2582 bcc_ptr[0] = 0; /* null terminate the string */
2585 len = strnlen(bcc_ptr, 1024);
2586 ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL);
2587 strncpy(ses->serverNOS, bcc_ptr, len);
2592 len = strnlen(bcc_ptr, 1024);
2593 ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL);
2594 strncpy(ses->serverDomain, bcc_ptr, len);
2600 ("Variable field of length %d extends beyond end of smb ",
2605 (" Security Blob Length extends beyond end of SMB"));
2608 cERROR(1, ("No session structure passed in."));
2612 (" Invalid Word count %d: ",
2613 smb_buffer_response->WordCount));
2618 cifs_buf_release(smb_buffer);
2624 CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2625 const char *tree, struct cifsTconInfo *tcon,
2626 const struct nls_table *nls_codepage)
2628 struct smb_hdr *smb_buffer;
2629 struct smb_hdr *smb_buffer_response;
2639 smb_buffer = cifs_buf_get();
2640 if (smb_buffer == 0) {
2643 smb_buffer_response = smb_buffer;
2645 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
2646 0 /*no tid */ , 4 /*wct */ );
2647 smb_buffer->Uid = ses->Suid;
2648 pSMB = (TCONX_REQ *) smb_buffer;
2649 pSMBr = (TCONX_RSP *) smb_buffer_response;
2651 pSMB->AndXCommand = 0xFF;
2652 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
2653 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
2654 bcc_ptr = &(pSMB->Password[0]);
2655 bcc_ptr++; /* skip password */
2657 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2658 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2660 if (ses->capabilities & CAP_STATUS32) {
2661 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2663 if (ses->capabilities & CAP_DFS) {
2664 smb_buffer->Flags2 |= SMBFLG2_DFS;
2666 if (ses->capabilities & CAP_UNICODE) {
2667 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2669 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
2670 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
2671 bcc_ptr += 2; /* skip trailing null */
2672 } else { /* ASCII */
2674 strcpy(bcc_ptr, tree);
2675 bcc_ptr += strlen(tree) + 1;
2677 strcpy(bcc_ptr, "?????");
2678 bcc_ptr += strlen("?????");
2680 BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2681 smb_buffer->smb_buf_length += BCC(smb_buffer);
2682 BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
2684 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
2686 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
2687 /* above now done in SendReceive */
2688 if ((rc == 0) && (tcon != NULL)) {
2689 tcon->tidStatus = CifsGood;
2690 tcon->tid = smb_buffer_response->Tid;
2691 bcc_ptr = pByteArea(smb_buffer_response);
2692 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
2693 /* skip service field (NB: this field is always ASCII) */
2694 bcc_ptr += length + 1;
2695 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
2696 if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
2697 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
2698 if (((long) bcc_ptr + (2 * length)) -
2699 (long) pByteArea(smb_buffer_response) <=
2700 BCC(smb_buffer_response)) {
2701 if(tcon->nativeFileSystem)
2702 kfree(tcon->nativeFileSystem);
2703 tcon->nativeFileSystem =
2704 cifs_kcalloc(length + 2, GFP_KERNEL);
2705 cifs_strfromUCS_le(tcon->nativeFileSystem,
2706 (wchar_t *) bcc_ptr,
2707 length, nls_codepage);
2708 bcc_ptr += 2 * length;
2709 bcc_ptr[0] = 0; /* null terminate the string */
2713 /* else do not bother copying these informational fields */
2715 length = strnlen(bcc_ptr, 1024);
2716 if (((long) bcc_ptr + length) -
2717 (long) pByteArea(smb_buffer_response) <=
2718 BCC(smb_buffer_response)) {
2719 if(tcon->nativeFileSystem)
2720 kfree(tcon->nativeFileSystem);
2721 tcon->nativeFileSystem =
2722 cifs_kcalloc(length + 1, GFP_KERNEL);
2723 strncpy(tcon->nativeFileSystem, bcc_ptr,
2726 /* else do not bother copying these informational fields */
2728 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
2729 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
2730 } else if ((rc == 0) && tcon == NULL) {
2731 /* all we need to save for IPC$ connection */
2732 ses->ipc_tid = smb_buffer_response->Tid;
2736 cifs_buf_release(smb_buffer);
2741 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
2745 struct cifsSesInfo *ses = NULL;
2749 if (cifs_sb->tcon) {
2750 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
2751 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
2756 tconInfoFree(cifs_sb->tcon);
2757 if ((ses) && (ses->server)) {
2758 cFYI(1, ("About to do SMBLogoff "));
2759 rc = CIFSSMBLogoff(xid, ses);
2765 set_current_state(TASK_INTERRUPTIBLE);
2766 schedule_timeout(HZ / 4); /* give captive thread time to exit */
2767 if((ses->server) && (ses->server->ssocket)) {
2768 cFYI(1,("Waking up socket by sending it signal "));
2769 send_sig(SIGKILL,ses->server->tsk,1);
2772 cFYI(1, ("No session or bad tcon"));
2775 cifs_sb->tcon = NULL;
2777 set_current_state(TASK_INTERRUPTIBLE);
2778 schedule_timeout(HZ / 2);
2784 return rc; /* BB check if we should always return zero here */
2787 int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
2788 struct nls_table * nls_info)
2791 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
2792 int ntlmv2_flag = FALSE;
2794 /* what if server changes its buffer size after dropping the session? */
2795 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
2796 rc = CIFSSMBNegotiate(xid, pSesInfo);
2797 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
2798 rc = CIFSSMBNegotiate(xid, pSesInfo);
2803 pSesInfo->server->tcpStatus = CifsGood;
2806 pSesInfo->capabilities = pSesInfo->server->capabilities;
2807 if(linuxExtEnabled == 0)
2808 pSesInfo->capabilities &= (~CAP_UNIX);
2809 pSesInfo->sequence_number = 0;
2810 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
2811 pSesInfo->server->secMode,
2812 pSesInfo->server->capabilities,
2813 pSesInfo->server->timeZone));
2814 if (extended_security
2815 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
2816 && (pSesInfo->server->secType == NTLMSSP)) {
2817 cFYI(1, ("New style sesssetup "));
2818 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
2819 NULL /* security blob */,
2820 0 /* blob length */,
2822 } else if (extended_security
2823 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
2824 && (pSesInfo->server->secType == RawNTLMSSP)) {
2825 cFYI(1, ("NTLMSSP sesssetup "));
2826 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
2833 cFYI(1,("Can use more secure NTLM version 2 password hash"));
2834 CalcNTLMv2_partial_mac_key(pSesInfo,
2836 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
2838 CalcNTLMv2_response(pSesInfo,v2_response);
2839 /* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */
2841 /* BB Put dummy sig in SessSetup PDU? */
2846 SMBNTencrypt(pSesInfo->password,
2847 pSesInfo->server->cryptKey,
2850 cifs_calculate_mac_key(pSesInfo->mac_signing_key,
2852 pSesInfo->password);
2854 /* for better security the weaker lanman hash not sent
2855 in AuthSessSetup so we no longer calculate it */
2857 rc = CIFSNTLMSSPAuthSessSetup(xid,
2863 } else { /* old style NTLM 0.12 session setup */
2864 SMBNTencrypt(pSesInfo->password,
2865 pSesInfo->server->cryptKey,
2868 cifs_calculate_mac_key(pSesInfo->mac_signing_key,
2869 ntlm_session_key, pSesInfo->password);
2870 rc = CIFSSessSetup(xid, pSesInfo,
2871 ntlm_session_key, nls_info);
2874 cERROR(1,("Send error in SessSetup = %d",rc));
2876 cFYI(1,("CIFS Session Established successfully"));
2877 pSesInfo->status = CifsGood;