ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / fs / cifs / connect.c
1 /*
2  *   fs/cifs/connect.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2004
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
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.
11  *
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.
16  *
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 
20  */
21 #include <linux/fs.h>
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>
33 #include "cifspdu.h"
34 #include "cifsglob.h"
35 #include "cifsproto.h"
36 #include "cifs_unicode.h"
37 #include "cifs_debug.h"
38 #include "cifs_fs_sb.h"
39 #include "ntlmssp.h"
40 #include "nterr.h"
41 #include "rfc1002pdu.h"
42
43 #define CIFS_PORT 445
44 #define RFC1001_PORT 139
45
46 extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
47                        unsigned char *p24);
48 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
49                          unsigned char *p24);
50 extern int cifs_inet_pton(int, const char *, void *dst);
51
52 struct smb_vol {
53         char *username;
54         char *password;
55         char *domainname;
56         char *UNC;
57         char *UNCip;
58         char *iocharset;  /* local code page for mapping to and from Unicode */
59         char source_rfc1001_name[16]; /* netbios name of client */
60         uid_t linux_uid;
61         gid_t linux_gid;
62         mode_t file_mode;
63         mode_t dir_mode;
64         int rw:1;
65         int retry:1;
66         unsigned int rsize;
67         unsigned int wsize;
68         unsigned int sockopt;
69         unsigned short int port;
70 };
71
72 static int ipv4_connect(struct sockaddr_in *psin_server, 
73                         struct socket **csocket,
74                         char * netb_name);
75 static int ipv6_connect(struct sockaddr_in6 *psin_server, 
76                         struct socket **csocket);
77
78
79         /* 
80          * cifs tcp session reconnection
81          * 
82          * mark tcp session as reconnecting so temporarily locked
83          * mark all smb sessions as reconnecting for tcp session
84          * reconnect tcp session
85          * wake up waiters on reconnection? - (not needed currently)
86          */
87
88 int
89 cifs_reconnect(struct TCP_Server_Info *server)
90 {
91         int rc = 0;
92         struct list_head *tmp;
93         struct cifsSesInfo *ses;
94         struct cifsTconInfo *tcon;
95         struct mid_q_entry * mid_entry;
96         
97         if(server->tcpStatus == CifsExiting)
98                 return rc;
99         server->tcpStatus = CifsNeedReconnect;
100         server->maxBuf = 0;
101
102         cFYI(1, ("Reconnecting tcp session "));
103
104         /* before reconnecting the tcp session, mark the smb session (uid)
105                 and the tid bad so they are not used until reconnected */
106         read_lock(&GlobalSMBSeslock);
107         list_for_each(tmp, &GlobalSMBSessionList) {
108                 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
109                 if (ses->server) {
110                         if (ses->server == server) {
111                                 ses->status = CifsNeedReconnect;
112                                 ses->ipc_tid = 0;
113                         }
114                 }
115                 /* else tcp and smb sessions need reconnection */
116         }
117         list_for_each(tmp, &GlobalTreeConnectionList) {
118                 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
119                 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
120                         tcon->tidStatus = CifsNeedReconnect;
121                 }
122         }
123         read_unlock(&GlobalSMBSeslock);
124
125         if(server->ssocket) {
126                 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
127                         server->ssocket->flags));
128                 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
129                 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
130                         server->ssocket->flags));
131                 sock_release(server->ssocket);
132                 server->ssocket = NULL;
133         }
134
135         spin_lock(&GlobalMid_Lock);
136         list_for_each(tmp, &server->pending_mid_q) {
137                 mid_entry = list_entry(tmp, struct
138                                         mid_q_entry,
139                                         qhead);
140                 if(mid_entry) {
141                         if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
142                                 /* Mark other intransit requests as needing retry so 
143                                   we do not immediately mark the session bad again 
144                                   (ie after we reconnect below) as they timeout too */
145                                 mid_entry->midState = MID_RETRY_NEEDED;
146                         }
147                 }
148         }
149         spin_unlock(&GlobalMid_Lock);
150
151
152         while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
153         {
154                 if(server->protocolType == IPV6) {
155                         rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
156                 } else {
157                         rc = ipv4_connect(&server->addr.sockAddr, 
158                                         &server->ssocket,
159                                         server->workstation_RFC1001_name);
160                 }
161                 if(rc) {
162                         set_current_state(TASK_INTERRUPTIBLE);
163                         schedule_timeout(3 * HZ);
164                 } else {
165                         atomic_inc(&tcpSesReconnectCount);
166                         server->tcpStatus = CifsGood;
167                         wake_up(&server->response_q);
168                 }
169         }
170         return rc;
171 }
172
173 static int
174 cifs_demultiplex_thread(struct TCP_Server_Info *server)
175 {
176         int length;
177         unsigned int pdu_length, total_read;
178         struct smb_hdr *smb_buffer = NULL;
179         struct msghdr smb_msg;
180         mm_segment_t temp_fs;
181         struct iovec iov;
182         struct socket *csocket = server->ssocket;
183         struct list_head *tmp;
184         struct cifsSesInfo *ses;
185         struct task_struct *task_to_wake = NULL;
186         struct mid_q_entry *mid_entry;
187         char *temp;
188
189         daemonize("cifsd");
190         allow_signal(SIGKILL);
191         current->flags |= PF_MEMALLOC;
192         server->tsk = current;  /* save process info to wake at shutdown */
193         cFYI(1, ("Demultiplex PID: %d", current->pid));
194
195         temp_fs = get_fs();     /* we must turn off socket api parm checking */
196         set_fs(get_ds());
197
198         while (server->tcpStatus != CifsExiting) {
199                 if (smb_buffer == NULL)
200                         smb_buffer = cifs_buf_get();
201                 else
202                         memset(smb_buffer, 0, sizeof (struct smb_hdr));
203
204                 if (smb_buffer == NULL) {
205                         cERROR(1,("Can not get memory for SMB response"));
206                         set_current_state(TASK_INTERRUPTIBLE);
207                         schedule_timeout(HZ * 3); /* give system time to free memory */
208                         continue;
209                 }
210                 iov.iov_base = smb_buffer;
211                 iov.iov_len = sizeof (struct smb_hdr) - 1;      
212         /* 1 byte less above since wct is not always returned in error cases */
213                 smb_msg.msg_iov = &iov;
214                 smb_msg.msg_iovlen = 1;
215                 smb_msg.msg_control = NULL;
216                 smb_msg.msg_controllen = 0;
217
218                 length =
219                     sock_recvmsg(csocket, &smb_msg,
220                                  sizeof (struct smb_hdr) -
221                                  1 /* RFC1001 header and SMB header */ ,
222                                  MSG_PEEK /* flags see socket.h */ );
223
224                 if(server->tcpStatus == CifsExiting) {
225                         break;
226                 } else if (server->tcpStatus == CifsNeedReconnect) {
227                         cFYI(1,("Reconnecting after server stopped responding"));
228                         cifs_reconnect(server);
229                         cFYI(1,("call to reconnect done"));
230                         csocket = server->ssocket;
231                         continue;
232                 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
233                         set_current_state(TASK_INTERRUPTIBLE);
234                         schedule_timeout(1); /* minimum sleep to prevent looping
235                                 allowing socket to clear and app threads to set
236                                 tcpStatus CifsNeedReconnect if server hung */
237                         continue;
238                 } else if (length <= 0) {
239                         if(server->tcpStatus == CifsNew) {
240                                 cFYI(1,("tcp session abended prematurely (after SMBnegprot)"));
241                                 /* some servers kill tcp session rather than returning
242                                         smb negprot error in which case reconnecting here is
243                                         not going to help - return error to mount */
244                                 server->tcpStatus = CifsExiting;
245                                 wake_up(&server->response_q);
246                                 break;
247                         }
248
249                         cFYI(1,("Reconnecting after unexpected rcvmsg error "));
250                         cifs_reconnect(server);
251                         csocket = server->ssocket;
252                         wake_up(&server->response_q);
253                         continue;
254                 }
255
256                 pdu_length = 4 + ntohl(smb_buffer->smb_buf_length);
257                 /* Ony read pdu_length after below checks for too short (due
258                    to e.g. int overflow) and too long ie beyond end of buf */
259                 cFYI(1, ("Peek length rcvd: 0x%x beginning 0x%x)", length, pdu_length));
260
261                 temp = (char *) smb_buffer;
262                 if (length > 3) {
263                         if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
264                                 iov.iov_base = smb_buffer;
265                                 iov.iov_len = 4;
266                                 length = sock_recvmsg(csocket, &smb_msg, 4, 0);
267                                 cFYI(0,("Received 4 byte keep alive packet"));
268                         } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
269                                 iov.iov_base = smb_buffer;
270                                         iov.iov_len = 4;
271                                         length = sock_recvmsg(csocket, &smb_msg, 4, 0);
272                                         cFYI(1,("Good RFC 1002 session rsp"));
273                         } else if ((temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE)
274                                    && (length == 5)) {
275                                 /* we get this from Windows 98 instead of error on SMB negprot response */
276                                 cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
277                                 if(server->tcpStatus == CifsNew) {
278                                         /* if nack on negprot (rather than 
279                                         ret of smb negprot error) reconnecting
280                                         not going to help, ret error to mount */
281                                         server->tcpStatus = CifsExiting;
282                                         /* wake up thread doing negprot */
283                                         wake_up(&server->response_q);
284                                         break;
285                                 } else {
286                                         /* give server a second to
287                                         clean up before reconnect attempt */
288                                         set_current_state(TASK_INTERRUPTIBLE);
289                                         schedule_timeout(HZ);
290                                         /* always try 445 first on reconnect
291                                         since we get NACK on some if we ever
292                                         connected to port 139 (the NACK is 
293                                         since we do not begin with RFC1001
294                                         session initialize frame) */
295                                         server->addr.sockAddr.sin_port = CIFS_PORT;
296                                         cifs_reconnect(server);
297                                         csocket = server->ssocket;
298                                         wake_up(&server->response_q);
299                                         continue;
300                                 }
301                         } else if (temp[0] != (char) 0) {
302                                 cERROR(1,("Unknown RFC 1002 frame"));
303                                 cifs_dump_mem(" Received Data: ", temp, length);
304                                 cifs_reconnect(server);
305                                 csocket = server->ssocket;
306                                 continue;
307                         } else {
308                                 if ((length != sizeof (struct smb_hdr) - 1)
309                                     || (pdu_length >
310                                         CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)
311                                     || (pdu_length <
312                                         sizeof (struct smb_hdr) - 1)
313                                     ||
314                                     (checkSMBhdr
315                                      (smb_buffer, smb_buffer->Mid))) {
316                                         cERROR(1,
317                                             ("Invalid size or format for SMB found with length %d and pdu_lenght %d",
318                                                 length, pdu_length));
319                                         cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
320                                         /* could we fix this network corruption by finding next 
321                                                 smb header (instead of killing the session) and
322                                                 restart reading from next valid SMB found? */
323                                         cifs_reconnect(server);
324                                         csocket = server->ssocket;
325                                         continue;
326                                 } else {        /* length ok */
327
328                                         length = 0;
329                                         iov.iov_base = smb_buffer;
330                                         iov.iov_len = pdu_length;
331                                         for (total_read = 0; 
332                                              total_read < pdu_length;
333                                              total_read += length) {    
334                                                 length = sock_recvmsg(csocket, &smb_msg, 
335                                                         pdu_length - total_read, 0);
336                                                 if (length == 0) {
337                                                         cERROR(1,
338                                                                ("Zero length receive when expecting %d ",
339                                                                 pdu_length - total_read));
340                                                         cifs_reconnect(server);
341                                                         csocket = server->ssocket;
342                                                         continue;
343                                                 }
344                                         }
345                                 }
346
347                                 dump_smb(smb_buffer, length);
348                                 if (checkSMB
349                                     (smb_buffer, smb_buffer->Mid, total_read)) {
350                                         cERROR(1, ("Bad SMB Received "));
351                                         continue;
352                                 }
353
354                                 task_to_wake = NULL;
355                                 spin_lock(&GlobalMid_Lock);
356                                 list_for_each(tmp, &server->pending_mid_q) {
357                                         mid_entry = list_entry(tmp, struct
358                                                                mid_q_entry,
359                                                                qhead);
360
361                                         if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
362                                                 cFYI(1,
363                                                      (" Mid 0x%x matched - waking up ",mid_entry->mid));
364                                                 task_to_wake = mid_entry->tsk;
365                                                 mid_entry->resp_buf =
366                                                     smb_buffer;
367                                                 mid_entry->midState =
368                                                     MID_RESPONSE_RECEIVED;
369                                         }
370                                 }
371                                 spin_unlock(&GlobalMid_Lock);
372                                 if (task_to_wake) {
373                                         smb_buffer = NULL;      /* will be freed by users thread after he is done */
374                                         wake_up_process(task_to_wake);
375                                 } else if (is_valid_oplock_break(smb_buffer) == FALSE) {                          
376                                         cERROR(1, ("No task to wake, unknown frame rcvd!"));
377                                         cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
378                                 }
379                         }
380                 } else {
381                         cFYI(0,
382                              ("Frame less than four bytes received  %d bytes long.",
383                               length));
384                         if (length > 0) {
385                                 length = sock_recvmsg(csocket, &smb_msg, length, 0);    /* throw away junk frame */
386                                 cFYI(1,
387                                      (" with junk  0x%x in it ",
388                                       *(__u32 *) smb_buffer));
389                         }
390                 }
391         }
392    
393         server->tcpStatus = CifsExiting;
394         server->tsk = NULL;
395         if(server->ssocket) {
396                 sock_release(csocket);
397                 server->ssocket = NULL;
398         }
399         set_fs(temp_fs);
400         if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */
401                 cifs_buf_release(smb_buffer);
402
403         read_lock(&GlobalSMBSeslock);
404         if (list_empty(&server->pending_mid_q)) {
405                 /* loop through server session structures attached to this and mark them dead */
406                 list_for_each(tmp, &GlobalSMBSessionList) {
407                         ses =
408                             list_entry(tmp, struct cifsSesInfo,
409                                        cifsSessionList);
410                         if (ses->server == server) {
411                                 ses->status = CifsExiting;
412                                 ses->server = NULL;
413                         }
414                 }
415                 read_unlock(&GlobalSMBSeslock);
416         } else {
417                 spin_lock(&GlobalMid_Lock);
418                 list_for_each(tmp, &server->pending_mid_q) {
419                 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
420                         if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
421                                 cFYI(1,
422                                          (" Clearing Mid 0x%x - waking up ",mid_entry->mid));
423                                 task_to_wake = mid_entry->tsk;
424                                 if(task_to_wake) {
425                                         wake_up_process(task_to_wake);
426                                 }
427                         }
428                 }
429                 spin_unlock(&GlobalMid_Lock);
430                 read_unlock(&GlobalSMBSeslock);
431                 set_current_state(TASK_INTERRUPTIBLE);
432                 /* 1/8th of sec should be more than enough time for them to exit */
433                 schedule_timeout(HZ/8); 
434         }
435
436         if (list_empty(&server->pending_mid_q)) {
437                 /* mpx threads have not exited yet give them 
438                 at least the smb send timeout time for long ops */
439                 cFYI(1, ("Wait for exit from demultiplex thread"));
440                 set_current_state(TASK_INTERRUPTIBLE);
441                 schedule_timeout(46 * HZ);      
442                 /* if threads still have not exited they are probably never
443                 coming home not much else we can do but free the memory */
444         }
445         kfree(server);
446
447         cFYI(1, ("About to exit from demultiplex thread"));
448         return 0;
449 }
450
451 static void * 
452 cifs_kcalloc(size_t size, int type)
453 {
454         void *addr;
455         addr = kmalloc(size, type);
456         if (addr)
457                 memset(addr, 0, size);
458         return addr;
459 }
460
461 static int
462 cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol)
463 {
464         char *value;
465         char *data;
466         unsigned int  temp_len, i, j;
467         char separator[2];
468
469         separator[0] = ',';
470         separator[1] = 0; 
471
472         memset(vol->source_rfc1001_name,0x20,15);
473         for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
474                 /* does not have to be a perfect mapping since the field is
475                 informational, only used for servers that do not support
476                 port 445 and it can be overridden at mount time */
477                 vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]);
478         }
479         vol->source_rfc1001_name[15] = 0;
480
481         vol->linux_uid = current->uid;  /* current->euid instead? */
482         vol->linux_gid = current->gid;
483         vol->dir_mode = S_IRWXUGO;
484         /* 2767 perms indicate mandatory locking support */
485         vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
486
487         /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
488         vol->rw = TRUE;
489
490         if (!options)
491                 return 1;
492
493         if(strncmp(options,"sep=",4) == 0) {
494                 if(options[4] != 0) {
495                         separator[0] = options[4];
496                         options += 5;
497                 } else {
498                         cFYI(1,("Null separator not allowed"));
499                 }
500         }
501                 
502         while ((data = strsep(&options, separator)) != NULL) {
503                 if (!*data)
504                         continue;
505                 if ((value = strchr(data, '=')) != NULL)
506                         *value++ = '\0';
507                 if (strnicmp(data, "user", 4) == 0) {
508                         if (!value || !*value) {
509                                 printk(KERN_WARNING
510                                        "CIFS: invalid or missing username\n");
511                                 return 1;       /* needs_arg; */
512                         }
513                         if (strnlen(value, 200) < 200) {
514                                 vol->username = value;
515                         } else {
516                                 printk(KERN_WARNING "CIFS: username too long\n");
517                                 return 1;
518                         }
519                 } else if (strnicmp(data, "pass", 4) == 0) {
520                         if (!value || !*value) {
521                                 vol->password = NULL;
522                                 continue;
523                         }
524                         temp_len = strlen(value);
525                         /* removed password length check, NTLM passwords
526                                 can be arbitrarily long */
527
528                         /* if comma in password, the string will be 
529                         prematurely null terminated.  Commas in password are
530                         specified across the cifs mount interface by a double
531                         comma ie ,, and a comma used as in other cases ie ','
532                         as a parameter delimiter/separator is single and due
533                         to the strsep above is temporarily zeroed. */
534
535                         /* NB: password legally can have multiple commas and
536                         the only illegal character in a password is null */
537                                 
538                         if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) {
539                                 /* reinsert comma */
540                                 value[temp_len] = separator[0];
541                                 temp_len+=2;  /* move after the second comma */
542                                 while(value[temp_len] != 0)  {
543                                         if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) {
544                                                 /* single comma indicating start of next parm */
545                                                 break;
546                                         }
547                                         temp_len++;
548                                 }
549                                 if(value[temp_len] == 0) {
550                                         options = NULL;
551                                 } else {
552                                         value[temp_len] = 0;
553                                         /* move options to point to start of next parm */
554                                         options = value + temp_len + 1;
555                                 }
556                                 /* go from value to (value + temp_len) condensing double commas to singles */
557                                 vol->password = cifs_kcalloc(temp_len, GFP_KERNEL);
558                                 for(i=0,j=0;i<temp_len;i++,j++) {
559                                         vol->password[j] = value[i];
560                                         if(value[i] == separator[0] && value[i+1] == separator[0]) {
561                                                 /* skip second comma */
562                                                 i++;
563                                         }
564                                 }
565                                 /* value[temp_len] is zeroed above so
566                                          vol->password[temp_len] guaranteed to be null */
567                         } else {
568                                 vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL);
569                                 strcpy(vol->password, value);
570                         }
571                 } else if (strnicmp(data, "ip", 2) == 0) {
572                         if (!value || !*value) {
573                                 vol->UNCip = NULL;
574                         } else if (strnlen(value, 35) < 35) {
575                                 vol->UNCip = value;
576                         } else {
577                                 printk(KERN_WARNING "CIFS: ip address too long\n");
578                                 return 1;
579                         }
580                 } else if ((strnicmp(data, "unc", 3) == 0)
581                            || (strnicmp(data, "target", 6) == 0)
582                            || (strnicmp(data, "path", 4) == 0)) {
583                         if (!value || !*value) {
584                                 printk(KERN_WARNING
585                                        "CIFS: invalid path to network resource\n");
586                                 return 1;       /* needs_arg; */
587                         }
588                         if ((temp_len = strnlen(value, 300)) < 300) {
589                                 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
590                                 strcpy(vol->UNC,value);
591                                 if (strncmp(vol->UNC, "//", 2) == 0) {
592                                         vol->UNC[0] = '\\';
593                                         vol->UNC[1] = '\\';
594                                 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {                    
595                                         printk(KERN_WARNING
596                                                "CIFS: UNC Path does not begin with // or \\\\ \n");
597                                         return 1;
598                                 }
599                         } else {
600                                 printk(KERN_WARNING "CIFS: UNC name too long\n");
601                                 return 1;
602                         }
603                 } else if ((strnicmp(data, "domain", 3) == 0)
604                            || (strnicmp(data, "workgroup", 5) == 0)) {
605                         if (!value || !*value) {
606                                 printk(KERN_WARNING "CIFS: invalid domain name\n");
607                                 return 1;       /* needs_arg; */
608                         }
609                         /* BB are there cases in which a comma can be valid in
610                         a domain name and need special handling? */
611                         if (strnlen(value, 65) < 65) {
612                                 vol->domainname = value;
613                                 cFYI(1, ("Domain name set"));
614                         } else {
615                                 printk(KERN_WARNING "CIFS: domain name too long\n");
616                                 return 1;
617                         }
618                 } else if (strnicmp(data, "iocharset", 9) == 0) {
619                         if (!value || !*value) {
620                                 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
621                                 return 1;       /* needs_arg; */
622                         }
623                         if (strnlen(value, 65) < 65) {
624                                 if(strnicmp(value,"default",7))
625                                         vol->iocharset = value;
626                                 /* if iocharset not set load_nls_default used by caller */
627                                 cFYI(1, ("iocharset set to %s",value));
628                         } else {
629                                 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
630                                 return 1;
631                         }
632                 } else if (strnicmp(data, "uid", 3) == 0) {
633                         if (value && *value) {
634                                 vol->linux_uid =
635                                         simple_strtoul(value, &value, 0);
636                         }
637                 } else if (strnicmp(data, "gid", 3) == 0) {
638                         if (value && *value) {
639                                 vol->linux_gid =
640                                         simple_strtoul(value, &value, 0);
641                         }
642                 } else if (strnicmp(data, "file_mode", 4) == 0) {
643                         if (value && *value) {
644                                 vol->file_mode =
645                                         simple_strtoul(value, &value, 0);
646                         }
647                 } else if (strnicmp(data, "dir_mode", 3) == 0) {
648                         if (value && *value) {
649                                 vol->dir_mode =
650                                         simple_strtoul(value, &value, 0);
651                         }
652                 } else if (strnicmp(data, "port", 4) == 0) {
653                         if (value && *value) {
654                                 vol->port =
655                                         simple_strtoul(value, &value, 0);
656                         }
657                 } else if (strnicmp(data, "rsize", 5) == 0) {
658                         if (value && *value) {
659                                 vol->rsize =
660                                         simple_strtoul(value, &value, 0);
661                         }
662                 } else if (strnicmp(data, "wsize", 5) == 0) {
663                         if (value && *value) {
664                                 vol->wsize =
665                                         simple_strtoul(value, &value, 0);
666                         }
667                 } else if (strnicmp(data, "sockopt", 5) == 0) {
668                         if (value && *value) {
669                                 vol->sockopt =
670                                         simple_strtoul(value, &value, 0);
671                         }
672                 } else if (strnicmp(data, "netbiosname", 4) == 0) {
673                         if (!value || !*value || (*value == ' ')) {
674                                 cFYI(1,("invalid (empty) netbiosname specified"));
675                         } else {
676                                 memset(vol->source_rfc1001_name,0x20,15);
677                                 for(i=0;i<15;i++) {
678                                 /* BB are there cases in which a comma can be 
679                                 valid in this workstation netbios name (and need
680                                 special handling)? */
681
682                                 /* We do not uppercase netbiosname for user */
683                                         if (value[i]==0)
684                                                 break;
685                                         else 
686                                                 vol->source_rfc1001_name[i] = value[i];
687                                 }
688                                 /* The string has 16th byte zero still from
689                                 set at top of the function  */
690                                 if((i==15) && (value[i] != 0))
691                                         printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
692                         }
693                 } else if (strnicmp(data, "version", 3) == 0) {
694                         /* ignore */
695                 } else if (strnicmp(data, "rw", 2) == 0) {
696                         vol->rw = TRUE;
697                 } else if ((strnicmp(data, "suid", 4) == 0) ||
698                                    (strnicmp(data, "nosuid", 6) == 0) ||
699                                    (strnicmp(data, "exec", 4) == 0) ||
700                                    (strnicmp(data, "noexec", 6) == 0) ||
701                                    (strnicmp(data, "nodev", 5) == 0) ||
702                                    (strnicmp(data, "dev", 3) == 0)) {
703                         /*  The mount tool or mount.cifs helper (if present)
704                                 uses these opts to set flags, and the flags are read
705                                 by the kernel vfs layer before we get here (ie
706                                 before read super) so there is no point trying to
707                                 parse these options again and set anything and it
708                                 is ok to just ignore them */
709                         continue;
710                 } else if (strnicmp(data, "ro", 2) == 0) {
711                         vol->rw = FALSE;
712                 } else if (strnicmp(data, "hard", 4) == 0) {
713                         vol->retry = 1;
714                 } else if (strnicmp(data, "soft", 4) == 0) {
715                         vol->retry = 0;
716                 } else if (strnicmp(data, "nohard", 6) == 0) {
717                         vol->retry = 0;
718                 } else if (strnicmp(data, "nosoft", 6) == 0) {
719                         vol->retry = 1;
720                 } else
721                         printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
722         }
723         if (vol->UNC == NULL) {
724                 if(devname == NULL) {
725                         printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
726                         return 1;
727                 }
728                 if ((temp_len = strnlen(devname, 300)) < 300) {
729                         vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
730                         strcpy(vol->UNC,devname);
731                         if (strncmp(vol->UNC, "//", 2) == 0) {
732                                 vol->UNC[0] = '\\';
733                                 vol->UNC[1] = '\\';
734                         } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
735                                 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
736                                 return 1;
737                         }
738                 } else {
739                         printk(KERN_WARNING "CIFS: UNC name too long\n");
740                         return 1;
741                 }
742         }
743         if(vol->UNCip == 0)
744                 vol->UNCip = &vol->UNC[2];
745
746         return 0;
747 }
748
749 static struct cifsSesInfo *
750 cifs_find_tcp_session(__u32 new_target_ip_addr,
751                  char *userName, struct TCP_Server_Info **psrvTcp)
752 {
753         struct list_head *tmp;
754         struct cifsSesInfo *ses;
755
756         *psrvTcp = NULL;
757         read_lock(&GlobalSMBSeslock);
758         list_for_each(tmp, &GlobalSMBSessionList) {
759                 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
760                 if (ses->server) {
761                         if (ses->server->addr.sockAddr.sin_addr.s_addr ==
762                             new_target_ip_addr) {
763                                 /* BB lock server and tcp session and increment use count here?? */
764                                 *psrvTcp = ses->server; /* found a match on the TCP session */
765                                 /* BB check if reconnection needed */
766                                 if (strncmp
767                                     (ses->userName, userName,
768                                      MAX_USERNAME_SIZE) == 0){
769                                         read_unlock(&GlobalSMBSeslock);
770                                         return ses;     /* found exact match on both tcp and SMB sessions */
771                                 }
772                         }
773                 }
774                 /* else tcp and smb sessions need reconnection */
775         }
776         read_unlock(&GlobalSMBSeslock);
777         return NULL;
778 }
779
780 static struct cifsTconInfo *
781 find_unc(__u32 new_target_ip_addr, char *uncName, char *userName)
782 {
783         struct list_head *tmp;
784         struct cifsTconInfo *tcon;
785
786         read_lock(&GlobalSMBSeslock);
787         list_for_each(tmp, &GlobalTreeConnectionList) {
788                 cFYI(1, ("Next tcon - "));
789                 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
790                 if (tcon->ses) {
791                         if (tcon->ses->server) {
792                                 cFYI(1,
793                                      (" old ip addr: %x == new ip %x ?",
794                                       tcon->ses->server->addr.sockAddr.sin_addr.
795                                       s_addr, new_target_ip_addr));
796                                 if (tcon->ses->server->addr.sockAddr.sin_addr.
797                                     s_addr == new_target_ip_addr) {
798         /* BB lock tcon and server and tcp session and increment use count here? */
799                                         /* found a match on the TCP session */
800                                         /* BB check if reconnection needed */
801                                         cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
802                                               tcon->treeName, uncName));
803                                         if (strncmp
804                                             (tcon->treeName, uncName,
805                                              MAX_TREE_SIZE) == 0) {
806                                                 cFYI(1,
807                                                      ("Matched UNC, old user: %s == new: %s ?",
808                                                       tcon->treeName, uncName));
809                                                 if (strncmp
810                                                     (tcon->ses->userName,
811                                                      userName,
812                                                      MAX_USERNAME_SIZE) == 0) {
813                                                         read_unlock(&GlobalSMBSeslock);
814                                                         return tcon;/* also matched user (smb session)*/
815                                                 }
816                                         }
817                                 }
818                         }
819                 }
820         }
821         read_unlock(&GlobalSMBSeslock);
822         return NULL;
823 }
824
825 int
826 connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
827                     const char *old_path, const struct nls_table *nls_codepage)
828 {
829         unsigned char *referrals = NULL;
830         unsigned int num_referrals;
831         int rc = 0;
832
833         rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, 
834                         &num_referrals, &referrals);
835
836         /* BB Add in code to: if valid refrl, if not ip address contact
837                 the helper that resolves tcp names, mount to it, try to 
838                 tcon to it unmount it if fail */
839
840         if(referrals)
841                 kfree(referrals);
842
843         return rc;
844 }
845
846 int
847 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
848                         const char *old_path, const struct nls_table *nls_codepage, 
849                         unsigned int *pnum_referrals, unsigned char ** preferrals)
850 {
851         char *temp_unc;
852         int rc = 0;
853
854         *pnum_referrals = 0;
855
856         if (pSesInfo->ipc_tid == 0) {
857                 temp_unc = kmalloc(2 /* for slashes */ +
858                         strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
859                                  + 1 + 4 /* slash IPC$ */  + 2,
860                                 GFP_KERNEL);
861                 if (temp_unc == NULL)
862                         return -ENOMEM;
863                 temp_unc[0] = '\\';
864                 temp_unc[1] = '\\';
865                 strcpy(temp_unc + 2, pSesInfo->serverName);
866                 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
867                 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
868                 cFYI(1,
869                      ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
870                 kfree(temp_unc);
871         }
872         if (rc == 0)
873                 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
874                                      pnum_referrals, nls_codepage);
875
876         return rc;
877 }
878
879 /* See RFC1001 section 14 on representation of Netbios names */
880 static void rfc1002mangle(char * target,char * source, unsigned int length)
881 {
882         unsigned int i,j;
883
884         for(i=0,j=0;i<(length);i++) {
885                 /* mask a nibble at a time and encode */
886                 target[j] = 'A' + (0x0F & (source[i] >> 4));
887                 target[j+1] = 'A' + (0x0F & source[i]);
888                 j+=2;
889         }
890
891 }
892
893
894 static int
895 ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, 
896                          char * netbios_name)
897 {
898         int rc = 0;
899         int connected = 0;
900         unsigned short int orig_port = 0;
901
902         if(*csocket == NULL) {
903                 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
904                 if (rc < 0) {
905                         cERROR(1, ("Error %d creating socket",rc));
906                         *csocket = NULL;
907                         return rc;
908                 } else {
909                 /* BB other socket options to set KEEPALIVE, NODELAY? */
910                         cFYI(1,("Socket created"));
911         /*              (*csocket)->sk->allocation = GFP_NOFS; */ /* BB is there equivalent in 2.6 */
912                 }
913         }
914
915         psin_server->sin_family = AF_INET;
916         if(psin_server->sin_port) { /* user overrode default port */
917                 rc = (*csocket)->ops->connect(*csocket,
918                                 (struct sockaddr *) psin_server,
919                                 sizeof (struct sockaddr_in),0);
920                 if (rc >= 0)
921                         connected = 1;
922         } 
923
924         if(!connected) {
925                 /* save original port so we can retry user specified port  
926                         later if fall back ports fail this time  */
927                 orig_port = psin_server->sin_port;
928
929                 /* do not retry on the same port we just failed on */
930                 if(psin_server->sin_port != htons(CIFS_PORT)) {
931                         psin_server->sin_port = htons(CIFS_PORT);
932
933                         rc = (*csocket)->ops->connect(*csocket,
934                                         (struct sockaddr *) psin_server,
935                                         sizeof (struct sockaddr_in),0);
936                         if (rc >= 0)
937                                 connected = 1;
938                 }
939         }
940         if (!connected) {
941                 psin_server->sin_port = htons(RFC1001_PORT);
942                 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
943                                               psin_server, sizeof (struct sockaddr_in),0);
944                 if (rc >= 0) 
945                         connected = 1;
946         }
947
948         /* give up here - unless we want to retry on different
949                 protocol families some day */
950         if (!connected) {
951                 if(orig_port)
952                         psin_server->sin_port = orig_port;
953                 cFYI(1,("Error %d connecting to server via ipv4",rc));
954                 sock_release(*csocket);
955                 *csocket = NULL;
956                 return rc;
957         }
958         /* Eventually check for other socket options to change from 
959                 the default. sock_setsockopt not used because it expects 
960                 user space buffer */
961         (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
962
963         /* send RFC1001 sessinit */
964
965         if(psin_server->sin_port == htons(139)) {
966                 /* some servers require RFC1001 sessinit before sending
967                 negprot - BB check reconnection in case where second 
968                 sessinit is sent but no second negprot */
969                 struct rfc1002_session_packet * ses_init_buf;
970                 struct smb_hdr * smb_buf;
971                 ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
972                 if(ses_init_buf) {
973                         ses_init_buf->trailer.session_req.called_len = 32;
974                         rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
975                                 DEFAULT_CIFS_CALLED_NAME,16);
976                         ses_init_buf->trailer.session_req.calling_len = 32;
977                         /* calling name ends in null (byte 16) from old smb
978                         convention. */
979                         if(netbios_name && (netbios_name[0] !=0)) {
980                                 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
981                                         netbios_name,16);
982                         } else {
983                                 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
984                                         "LINUX_CIFS_CLNT",16);
985                         }
986                         ses_init_buf->trailer.session_req.scope1 = 0;
987                         ses_init_buf->trailer.session_req.scope2 = 0;
988                         smb_buf = (struct smb_hdr *)ses_init_buf;
989                         /* sizeof RFC1002_SESSION_REQUEST with no scope */
990                         smb_buf->smb_buf_length = 0x81000044;
991                         rc = smb_send(*csocket, smb_buf, 0x44,
992                                 (struct sockaddr *)psin_server);
993                         kfree(ses_init_buf);
994                 }
995                 /* else the negprot may still work without this 
996                 even though malloc failed */
997                 
998         }
999                 
1000         return rc;
1001 }
1002
1003 static int
1004 ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1005 {
1006         int rc = 0;
1007         int connected = 0;
1008
1009         if(*csocket == NULL) {
1010                 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1011                 if (rc < 0) {
1012                         cERROR(1, ("Error %d creating ipv6 socket",rc));
1013                         *csocket = NULL;
1014                         return rc;
1015                 } else {
1016                 /* BB other socket options to set KEEPALIVE, NODELAY? */
1017                          cFYI(1,("ipv6 Socket created"));
1018                 }
1019         }
1020
1021         psin_server->sin6_family = AF_INET6;
1022
1023         if(psin_server->sin6_port) { /* user overrode default port */
1024                 rc = (*csocket)->ops->connect(*csocket,
1025                                 (struct sockaddr *) psin_server,
1026                                 sizeof (struct sockaddr_in6),0);
1027                 if (rc >= 0)
1028                         connected = 1;
1029         } 
1030
1031         if(!connected) {
1032                 /* do not retry on the same port we just failed on */
1033                 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1034                         psin_server->sin6_port = htons(CIFS_PORT);
1035
1036                         rc = (*csocket)->ops->connect(*csocket,
1037                                         (struct sockaddr *) psin_server,
1038                                         sizeof (struct sockaddr_in6),0);
1039                         if (rc >= 0)
1040                                 connected = 1;
1041                 }
1042         }
1043         if (!connected) {
1044                 psin_server->sin6_port = htons(RFC1001_PORT);
1045                 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1046                                          psin_server, sizeof (struct sockaddr_in6),0);
1047                 if (rc >= 0) 
1048                         connected = 1;
1049         }
1050
1051         /* give up here - unless we want to retry on different
1052                 protocol families some day */
1053         if (!connected) {
1054                 cFYI(1,("Error %d connecting to server via ipv6",rc));
1055                 sock_release(*csocket);
1056                 *csocket = NULL;
1057                 return rc;
1058         }
1059         /* Eventually check for other socket options to change from 
1060                 the default. sock_setsockopt not used because it expects 
1061                 user space buffer */
1062         (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1063                 
1064         return rc;
1065 }
1066
1067 int
1068 cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1069            char *mount_data, const char *devname)
1070 {
1071         int rc = 0;
1072         int xid;
1073         struct socket *csocket = NULL;
1074         struct sockaddr_in sin_server;
1075         struct sockaddr_in6 sin_server6;
1076         struct smb_vol volume_info;
1077         struct cifsSesInfo *pSesInfo = NULL;
1078         struct cifsSesInfo *existingCifsSes = NULL;
1079         struct cifsTconInfo *tcon = NULL;
1080         struct TCP_Server_Info *srvTcp = NULL;
1081
1082         xid = GetXid();
1083
1084 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1085         
1086         memset(&volume_info,0,sizeof(struct smb_vol));
1087         if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1088                 if(volume_info.UNC)
1089                         kfree(volume_info.UNC);
1090                 if(volume_info.password)
1091                         kfree(volume_info.password);
1092                 FreeXid(xid);
1093                 return -EINVAL;
1094         }
1095
1096         if (volume_info.username) {
1097                 cFYI(1, ("Username: %s ", volume_info.username));
1098
1099         } else {
1100                 cifserror("No username specified ");
1101         /* In userspace mount helper we can get user name from alternate
1102            locations such as env variables and files on disk */
1103                 if(volume_info.UNC)
1104                         kfree(volume_info.UNC);
1105                 if(volume_info.password)
1106                         kfree(volume_info.password);
1107                 FreeXid(xid);
1108                 return -EINVAL;
1109         }
1110
1111         if (volume_info.UNCip && volume_info.UNC) {
1112                 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1113
1114                 if(rc == 0) {
1115                         /* not ipv4 address, try ipv6 */
1116                         rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); 
1117                 } 
1118        
1119                 if(rc != 1) {
1120                         /* we failed translating address */
1121                         if(volume_info.UNC)
1122                                 kfree(volume_info.UNC);
1123                         if(volume_info.password)
1124                                 kfree(volume_info.password);
1125                         FreeXid(xid);
1126                         return -EINVAL;
1127                 }
1128
1129                 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1130                 /* success */
1131                 rc = 0;
1132         } else if (volume_info.UNCip){
1133                 /* BB using ip addr as server name connect to the DFS root below */
1134                 cERROR(1,("Connecting to DFS root not implemented yet"));
1135                 if(volume_info.UNC)
1136                         kfree(volume_info.UNC);
1137                 if(volume_info.password)
1138                         kfree(volume_info.password);
1139                 FreeXid(xid);
1140                 return -EINVAL;
1141         } else /* which servers DFS root would we conect to */ {
1142                 cERROR(1,
1143                        ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified  "));
1144                 if(volume_info.UNC)
1145                         kfree(volume_info.UNC);
1146                 if(volume_info.password)
1147                         kfree(volume_info.password);
1148                 FreeXid(xid);
1149                 return -EINVAL;
1150         }
1151
1152         /* this is needed for ASCII cp to Unicode converts */
1153         if(volume_info.iocharset == NULL) {
1154                 cifs_sb->local_nls = load_nls_default();
1155         /* load_nls_default can not return null */
1156         } else {
1157                 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1158                 if(cifs_sb->local_nls == NULL) {
1159                         cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1160                         if(volume_info.UNC)
1161                                 kfree(volume_info.UNC);
1162                         if(volume_info.password)
1163                                 kfree(volume_info.password);
1164                         FreeXid(xid);
1165                         return -ELIBACC;
1166                 }
1167         }
1168
1169         existingCifsSes =
1170             cifs_find_tcp_session(sin_server.sin_addr.s_addr,
1171                              volume_info.username, &srvTcp);
1172         if (srvTcp) {
1173                 cFYI(1, ("Existing tcp session with server found "));                
1174         } else {        /* create socket */
1175                 if(volume_info.port)
1176                         sin_server.sin_port = htons(volume_info.port);
1177                 else
1178                         sin_server.sin_port = 0;
1179                 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1180                 if (rc < 0) {
1181                         cERROR(1,
1182                                ("Error connecting to IPv4 socket. Aborting operation"));
1183                         if(csocket != NULL)
1184                                 sock_release(csocket);
1185                         if(volume_info.UNC)
1186                                 kfree(volume_info.UNC);
1187                         if(volume_info.password)
1188                                 kfree(volume_info.password);
1189                         FreeXid(xid);
1190                         return rc;
1191                 }
1192
1193                 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1194                 if (srvTcp == NULL) {
1195                         rc = -ENOMEM;
1196                         sock_release(csocket);
1197                         if(volume_info.UNC)
1198                                 kfree(volume_info.UNC);
1199                         if(volume_info.password)
1200                                 kfree(volume_info.password);
1201                         FreeXid(xid);
1202                         return rc;
1203                 } else {
1204                         memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1205                         memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));       
1206             /* BB Add code for ipv6 case too */
1207                         srvTcp->ssocket = csocket;
1208                         srvTcp->protocolType = IPV4;
1209                         init_waitqueue_head(&srvTcp->response_q);
1210                         INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1211                         srvTcp->tcpStatus = CifsNew;
1212                         init_MUTEX(&srvTcp->tcpSem);
1213                         kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1214                                       CLONE_FS | CLONE_FILES | CLONE_VM);
1215                         memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
1216                 }
1217         }
1218
1219         if (existingCifsSes) {
1220                 pSesInfo = existingCifsSes;
1221                 cFYI(1, ("Existing smb sess found "));
1222                 if(volume_info.password)
1223                         kfree(volume_info.password);
1224                 /* volume_info.UNC freed at end of function */
1225         } else if (!rc) {
1226                 cFYI(1, ("Existing smb sess not found "));
1227                 pSesInfo = sesInfoAlloc();
1228                 if (pSesInfo == NULL)
1229                         rc = -ENOMEM;
1230                 else {
1231                         pSesInfo->server = srvTcp;
1232                         sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1233                                 NIPQUAD(sin_server.sin_addr.s_addr));
1234                 }
1235
1236                 if (!rc){
1237                         /* volume_info.password freed at unmount */   
1238                         if (volume_info.password)
1239                                 pSesInfo->password = volume_info.password;
1240                         if (volume_info.username)
1241                                 strncpy(pSesInfo->userName,
1242                                         volume_info.username,MAX_USERNAME_SIZE);
1243                         if (volume_info.domainname)
1244                                 strncpy(pSesInfo->domainName,
1245                                         volume_info.domainname,MAX_USERNAME_SIZE);
1246                         pSesInfo->linux_uid = volume_info.linux_uid;
1247                         down(&pSesInfo->sesSem);
1248                         rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1249                         up(&pSesInfo->sesSem);
1250                         if(!rc)
1251                                 atomic_inc(&srvTcp->socketUseCount);
1252                 } else
1253                         if(volume_info.password)
1254                                 kfree(volume_info.password);
1255         }
1256     
1257         /* search for existing tcon to this server share */
1258         if (!rc) {
1259                 if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
1260                         cifs_sb->rsize = volume_info.rsize;
1261                 else
1262                         cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1263                 if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
1264                         cifs_sb->wsize = volume_info.wsize;
1265                 else
1266                         cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1267                 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1268                         cifs_sb->rsize = PAGE_CACHE_SIZE;
1269                         cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1270                 }
1271                 cifs_sb->mnt_uid = volume_info.linux_uid;
1272                 cifs_sb->mnt_gid = volume_info.linux_gid;
1273                 cifs_sb->mnt_file_mode = volume_info.file_mode;
1274                 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1275                 cFYI(1,("file mode: 0x%x  dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1276                 tcon =
1277                     find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1278                              volume_info.username);
1279                 if (tcon) {
1280                         cFYI(1, ("Found match on UNC path "));
1281                         /* we can have only one retry value for a connection
1282                            to a share so for resources mounted more than once
1283                            to the same server share the last value passed in 
1284                            for the retry flag is used */
1285                         tcon->retry = volume_info.retry;
1286                 } else {
1287                         tcon = tconInfoAlloc();
1288                         if (tcon == NULL)
1289                                 rc = -ENOMEM;
1290                         else {
1291                                 /* check for null share name ie connect to dfs root */
1292
1293                                 /* BB check if this works for exactly length three strings */
1294                                 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1295                                     && (strchr(volume_info.UNC + 3, '/') ==
1296                                         NULL)) {
1297                                         rc = connect_to_dfs_path(xid,
1298                                                                  pSesInfo,
1299                                                                  "",
1300                                                                  cifs_sb->
1301                                                                  local_nls);
1302                                         if(volume_info.UNC)
1303                                                 kfree(volume_info.UNC);
1304                                         FreeXid(xid);
1305                                         return -ENODEV;
1306                                 } else {
1307                                         rc = CIFSTCon(xid, pSesInfo, 
1308                                                 volume_info.UNC,
1309                                                 tcon, cifs_sb->local_nls);
1310                                         cFYI(1, ("CIFS Tcon rc = %d", rc));
1311                                 }
1312                                 if (!rc) {
1313                                         atomic_inc(&pSesInfo->inUse);
1314                                         tcon->retry = volume_info.retry;
1315                                 }
1316                         }
1317                 }
1318         }
1319         if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1320                 cFYI(0, ("Large files supported "));
1321                 sb->s_maxbytes = (u64) 1 << 63;
1322         } else
1323                 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1324
1325 /* on error free sesinfo and tcon struct if needed */
1326         if (rc) {
1327                 if(atomic_read(&srvTcp->socketUseCount) == 0)
1328                         srvTcp->tcpStatus = CifsExiting;
1329                            /* If find_unc succeeded then rc == 0 so we can not end */
1330                 if (tcon)  /* up here accidently freeing someone elses tcon struct */
1331                         tconInfoFree(tcon);
1332                 if (existingCifsSes == 0) {
1333                         if (pSesInfo) {
1334                                 if (pSesInfo->server) {
1335                                         if (pSesInfo->Suid)
1336                                                 CIFSSMBLogoff(xid, pSesInfo);
1337                                         if(pSesInfo->server->tsk)
1338                                                 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1339                                         set_current_state(TASK_INTERRUPTIBLE);
1340                                         schedule_timeout(HZ / 4);       /* give captive thread time to exit */
1341                                 } else
1342                                         cFYI(1, ("No session or bad tcon"));
1343                                 sesInfoFree(pSesInfo);
1344                                 /* pSesInfo = NULL; */
1345                         }
1346                 }
1347         } else {
1348                 atomic_inc(&tcon->useCount);
1349                 cifs_sb->tcon = tcon;
1350                 tcon->ses = pSesInfo;
1351
1352                 /* do not care if following two calls succeed - informational only */
1353                 CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
1354                 CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
1355                 if (tcon->ses->capabilities & CAP_UNIX)
1356                         CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls);
1357         }
1358
1359         /* volume_info.password is freed above when existing session found
1360         (in which case it is not needed anymore) but when new sesion is created
1361         the password ptr is put in the new session structure (in which case the
1362         password will be freed at unmount time) */
1363         if(volume_info.UNC)
1364                 kfree(volume_info.UNC);
1365         FreeXid(xid);
1366         return rc;
1367 }
1368
1369 static int
1370 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1371               char session_key[CIFS_SESSION_KEY_SIZE],
1372               const struct nls_table *nls_codepage)
1373 {
1374         struct smb_hdr *smb_buffer;
1375         struct smb_hdr *smb_buffer_response;
1376         SESSION_SETUP_ANDX *pSMB;
1377         SESSION_SETUP_ANDX *pSMBr;
1378         char *bcc_ptr;
1379         char *user = ses->userName;
1380         char *domain = ses->domainName;
1381         int rc = 0;
1382         int remaining_words = 0;
1383         int bytes_returned = 0;
1384         int len;
1385
1386         cFYI(1, ("In sesssetup "));
1387
1388         smb_buffer = cifs_buf_get();
1389         if (smb_buffer == 0) {
1390                 return -ENOMEM;
1391         }
1392         smb_buffer_response = smb_buffer;
1393         pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1394
1395         /* send SMBsessionSetup here */
1396         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1397                         0 /* no tCon exists yet */ , 13 /* wct */ );
1398
1399         pSMB->req_no_secext.AndXCommand = 0xFF;
1400         pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1401         pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1402
1403         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1404                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1405
1406         pSMB->req_no_secext.Capabilities =
1407             CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS;
1408         if (ses->capabilities & CAP_UNICODE) {
1409                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1410                 pSMB->req_no_secext.Capabilities |= CAP_UNICODE;
1411         }
1412         if (ses->capabilities & CAP_STATUS32) {
1413                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1414                 pSMB->req_no_secext.Capabilities |= CAP_STATUS32;
1415         }
1416         if (ses->capabilities & CAP_DFS) {
1417                 smb_buffer->Flags2 |= SMBFLG2_DFS;
1418                 pSMB->req_no_secext.Capabilities |= CAP_DFS;
1419         }
1420         pSMB->req_no_secext.Capabilities =
1421             cpu_to_le32(pSMB->req_no_secext.Capabilities);
1422         /* pSMB->req_no_secext.CaseInsensitivePasswordLength =
1423            CIFS_SESSION_KEY_SIZE; */
1424         pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
1425         pSMB->req_no_secext.CaseSensitivePasswordLength =
1426             cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1427         bcc_ptr = pByteArea(smb_buffer);
1428         /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE);
1429            bcc_ptr += CIFS_SESSION_KEY_SIZE; */
1430         memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1431         bcc_ptr += CIFS_SESSION_KEY_SIZE;
1432
1433         if (ses->capabilities & CAP_UNICODE) {
1434                 if ((long) bcc_ptr % 2) {       /* must be word aligned for Unicode */
1435                         *bcc_ptr = 0;
1436                         bcc_ptr++;
1437                 }
1438                 if(user == NULL)
1439                         bytes_returned = 0; /* skill null user */
1440                 else
1441                         bytes_returned =
1442                                 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1443                                         nls_codepage);
1444                 bcc_ptr += 2 * bytes_returned;  /* convert num 16 bit words to bytes */
1445                 bcc_ptr += 2;   /* trailing null */
1446                 if (domain == NULL)
1447                         bytes_returned =
1448                             cifs_strtoUCS((wchar_t *) bcc_ptr,
1449                                           "CIFS_LINUX_DOM", 32, nls_codepage);
1450                 else
1451                         bytes_returned =
1452                             cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1453                                           nls_codepage);
1454                 bcc_ptr += 2 * bytes_returned;
1455                 bcc_ptr += 2;
1456                 bytes_returned =
1457                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1458                                   32, nls_codepage);
1459                 bcc_ptr += 2 * bytes_returned;
1460                 bytes_returned =
1461                     cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
1462                                   nls_codepage);
1463                 bcc_ptr += 2 * bytes_returned;
1464                 bcc_ptr += 2;
1465                 bytes_returned =
1466                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1467                                   64, nls_codepage);
1468                 bcc_ptr += 2 * bytes_returned;
1469                 bcc_ptr += 2;
1470         } else {
1471                 if(user != NULL) {                
1472                     strncpy(bcc_ptr, user, 200);
1473                     bcc_ptr += strnlen(user, 200);
1474                 }
1475                 *bcc_ptr = 0;
1476                 bcc_ptr++;
1477                 if (domain == NULL) {
1478                         strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1479                         bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1480                 } else {
1481                         strncpy(bcc_ptr, domain, 64);
1482                         bcc_ptr += strnlen(domain, 64);
1483                         *bcc_ptr = 0;
1484                         bcc_ptr++;
1485                 }
1486                 strcpy(bcc_ptr, "Linux version ");
1487                 bcc_ptr += strlen("Linux version ");
1488                 strcpy(bcc_ptr, UTS_RELEASE);
1489                 bcc_ptr += strlen(UTS_RELEASE) + 1;
1490                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1491                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1492         }
1493         BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1494         smb_buffer->smb_buf_length += BCC(smb_buffer);
1495         BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
1496
1497         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1498                          &bytes_returned, 1);
1499         if (rc) {
1500 /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1501         } else if ((smb_buffer_response->WordCount == 3)
1502                    || (smb_buffer_response->WordCount == 4)) {
1503                 pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
1504                 if (pSMBr->resp.Action & GUEST_LOGIN)
1505                         cFYI(1, (" Guest login"));      /* do we want to mark SesInfo struct ? */
1506                 if (ses) {
1507                         ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
1508                         cFYI(1, ("UID = %d ", ses->Suid));
1509          /* response can have either 3 or 4 word count - Samba sends 3 */
1510                         bcc_ptr = pByteArea(smb_buffer_response);       
1511                         if ((pSMBr->resp.hdr.WordCount == 3)
1512                             || ((pSMBr->resp.hdr.WordCount == 4)
1513                                 && (pSMBr->resp.SecurityBlobLength <
1514                                     pSMBr->resp.ByteCount))) {
1515                                 if (pSMBr->resp.hdr.WordCount == 4)
1516                                         bcc_ptr +=
1517                                             pSMBr->resp.SecurityBlobLength;
1518
1519                                 if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
1520                                         if ((long) (bcc_ptr) % 2) {
1521                                                 remaining_words =
1522                                                     (BCC(smb_buffer_response)
1523                                                      - 1) / 2;
1524                                                 bcc_ptr++;      /* Unicode strings must be word aligned */
1525                                         } else {
1526                                                 remaining_words =
1527                                                     BCC
1528                                                     (smb_buffer_response) / 2;
1529                                         }
1530                                         len =
1531                                             UniStrnlen((wchar_t *) bcc_ptr,
1532                                                        remaining_words - 1);
1533 /* We look for obvious messed up bcc or strings in response so we do not go off
1534    the end since (at least) WIN2K and Windows XP have a major bug in not null
1535    terminating last Unicode string in response  */
1536                                         ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
1537                                         cifs_strfromUCS_le(ses->serverOS,
1538                                                            (wchar_t *)bcc_ptr, len,nls_codepage);
1539                                         bcc_ptr += 2 * (len + 1);
1540                                         remaining_words -= len + 1;
1541                                         ses->serverOS[2 * len] = 0;
1542                                         ses->serverOS[1 + (2 * len)] = 0;
1543                                         if (remaining_words > 0) {
1544                                                 len = UniStrnlen((wchar_t *)bcc_ptr,
1545                                                                  remaining_words
1546                                                                  - 1);
1547                                                 ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL);
1548                                                 cifs_strfromUCS_le(ses->serverNOS,
1549                                                                    (wchar_t *)bcc_ptr,len,nls_codepage);
1550                                                 bcc_ptr += 2 * (len + 1);
1551                                                 ses->serverNOS[2 * len] = 0;
1552                                                 ses->serverNOS[1 + (2 * len)] = 0;
1553                                                 remaining_words -= len + 1;
1554                                                 if (remaining_words > 0) {
1555                                                         len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
1556           /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1557                                                         ses->serverDomain =
1558                                                             cifs_kcalloc(2*(len+1),GFP_KERNEL);
1559                                                         cifs_strfromUCS_le(ses->serverDomain,
1560                                                              (wchar_t *)bcc_ptr,len,nls_codepage);
1561                                                         bcc_ptr += 2 * (len + 1);
1562                                                         ses->serverDomain[2*len] = 0;
1563                                                         ses->serverDomain[1+(2*len)] = 0;
1564                                                 } /* else no more room so create dummy domain string */
1565                                                 else
1566                                                         ses->serverDomain =
1567                                                             cifs_kcalloc(2,
1568                                                                     GFP_KERNEL);
1569                                         } else {        /* no room so create dummy domain and NOS string */
1570                                                 ses->serverDomain =
1571                                                     cifs_kcalloc(2, GFP_KERNEL);
1572                                                 ses->serverNOS =
1573                                                     cifs_kcalloc(2, GFP_KERNEL);
1574                                         }
1575                                 } else {        /* ASCII */
1576                                         len = strnlen(bcc_ptr, 1024);
1577                                         if (((long) bcc_ptr + len) - (long)
1578                                             pByteArea(smb_buffer_response)
1579                                             <= BCC(smb_buffer_response)) {
1580                                                 ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
1581                                                 strncpy(ses->serverOS,bcc_ptr, len);
1582
1583                                                 bcc_ptr += len;
1584                                                 bcc_ptr[0] = 0; /* null terminate the string */
1585                                                 bcc_ptr++;
1586
1587                                                 len = strnlen(bcc_ptr, 1024);
1588                                                 ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
1589                                                 strncpy(ses->serverNOS, bcc_ptr, len);
1590                                                 bcc_ptr += len;
1591                                                 bcc_ptr[0] = 0;
1592                                                 bcc_ptr++;
1593
1594                                                 len = strnlen(bcc_ptr, 1024);
1595                                                 ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL);
1596                                                 strncpy(ses->serverDomain, bcc_ptr, len);
1597                                                 bcc_ptr += len;
1598                                                 bcc_ptr[0] = 0;
1599                                                 bcc_ptr++;
1600                                         } else
1601                                                 cFYI(1,
1602                                                      ("Variable field of length %d extends beyond end of smb ",
1603                                                       len));
1604                                 }
1605                         } else {
1606                                 cERROR(1,
1607                                        (" Security Blob Length extends beyond end of SMB"));
1608                         }
1609                 } else {
1610                         cERROR(1, ("No session structure passed in."));
1611                 }
1612         } else {
1613                 cERROR(1,
1614                        (" Invalid Word count %d: ",
1615                         smb_buffer_response->WordCount));
1616                 rc = -EIO;
1617         }
1618         
1619         if (smb_buffer)
1620                 cifs_buf_release(smb_buffer);
1621
1622         return rc;
1623 }
1624
1625 static int
1626 CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1627                 char *SecurityBlob,int SecurityBlobLength,
1628                 const struct nls_table *nls_codepage)
1629 {
1630         struct smb_hdr *smb_buffer;
1631         struct smb_hdr *smb_buffer_response;
1632         SESSION_SETUP_ANDX *pSMB;
1633         SESSION_SETUP_ANDX *pSMBr;
1634         char *bcc_ptr;
1635         char *user = ses->userName;
1636         char *domain = ses->domainName;
1637         int rc = 0;
1638         int remaining_words = 0;
1639         int bytes_returned = 0;
1640         int len;
1641
1642         cFYI(1, ("In spnego sesssetup "));
1643
1644         smb_buffer = cifs_buf_get();
1645         if (smb_buffer == 0) {
1646                 return -ENOMEM;
1647         }
1648         smb_buffer_response = smb_buffer;
1649         pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1650
1651         /* send SMBsessionSetup here */
1652         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1653                         0 /* no tCon exists yet */ , 12 /* wct */ );
1654         pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
1655         pSMB->req.AndXCommand = 0xFF;
1656         pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1657         pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1658
1659         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1660                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1661
1662         pSMB->req.Capabilities =
1663             CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1664             CAP_EXTENDED_SECURITY;
1665         if (ses->capabilities & CAP_UNICODE) {
1666                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1667                 pSMB->req.Capabilities |= CAP_UNICODE;
1668         }
1669         if (ses->capabilities & CAP_STATUS32) {
1670                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1671                 pSMB->req.Capabilities |= CAP_STATUS32;
1672         }
1673         if (ses->capabilities & CAP_DFS) {
1674                 smb_buffer->Flags2 |= SMBFLG2_DFS;
1675                 pSMB->req.Capabilities |= CAP_DFS;
1676         }
1677         pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
1678
1679         pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
1680         bcc_ptr = pByteArea(smb_buffer);
1681         memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
1682         bcc_ptr += SecurityBlobLength;
1683
1684         if (ses->capabilities & CAP_UNICODE) {
1685                 if ((long) bcc_ptr % 2) {       /* must be word aligned for Unicode strings */
1686                         *bcc_ptr = 0;
1687                         bcc_ptr++;
1688                 }
1689                 bytes_returned =
1690                     cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
1691                 bcc_ptr += 2 * bytes_returned;  /* convert num of 16 bit words to bytes */
1692                 bcc_ptr += 2;   /* trailing null */
1693                 if (domain == NULL)
1694                         bytes_returned =
1695                             cifs_strtoUCS((wchar_t *) bcc_ptr,
1696                                           "CIFS_LINUX_DOM", 32, nls_codepage);
1697                 else
1698                         bytes_returned =
1699                             cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1700                                           nls_codepage);
1701                 bcc_ptr += 2 * bytes_returned;
1702                 bcc_ptr += 2;
1703                 bytes_returned =
1704                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1705                                   32, nls_codepage);
1706                 bcc_ptr += 2 * bytes_returned;
1707                 bytes_returned =
1708                     cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
1709                                   nls_codepage);
1710                 bcc_ptr += 2 * bytes_returned;
1711                 bcc_ptr += 2;
1712                 bytes_returned =
1713                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1714                                   64, nls_codepage);
1715                 bcc_ptr += 2 * bytes_returned;
1716                 bcc_ptr += 2;
1717         } else {
1718                 strncpy(bcc_ptr, user, 200);
1719                 bcc_ptr += strnlen(user, 200);
1720                 *bcc_ptr = 0;
1721                 bcc_ptr++;
1722                 if (domain == NULL) {
1723                         strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1724                         bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1725                 } else {
1726                         strncpy(bcc_ptr, domain, 64);
1727                         bcc_ptr += strnlen(domain, 64);
1728                         *bcc_ptr = 0;
1729                         bcc_ptr++;
1730                 }
1731                 strcpy(bcc_ptr, "Linux version ");
1732                 bcc_ptr += strlen("Linux version ");
1733                 strcpy(bcc_ptr, UTS_RELEASE);
1734                 bcc_ptr += strlen(UTS_RELEASE) + 1;
1735                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1736                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1737         }
1738         BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1739         smb_buffer->smb_buf_length += BCC(smb_buffer);
1740         BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
1741
1742         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1743                          &bytes_returned, 1);
1744         if (rc) {
1745 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
1746         } else if ((smb_buffer_response->WordCount == 3)
1747                    || (smb_buffer_response->WordCount == 4)) {
1748                 pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
1749                 pSMBr->resp.SecurityBlobLength =
1750                     le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1751                 if (pSMBr->resp.Action & GUEST_LOGIN)
1752                         cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
1753                 if (ses) {
1754                         ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
1755                         cFYI(1, ("UID = %d ", ses->Suid));
1756                         bcc_ptr = pByteArea(smb_buffer_response);       /* response can have either 3 or 4 word count - Samba sends 3 */
1757
1758                         /* BB Fix below to make endian neutral !! */
1759
1760                         if ((pSMBr->resp.hdr.WordCount == 3)
1761                             || ((pSMBr->resp.hdr.WordCount == 4)
1762                                 && (pSMBr->resp.SecurityBlobLength <
1763                                     pSMBr->resp.ByteCount))) {
1764                                 if (pSMBr->resp.hdr.WordCount == 4) {
1765                                         bcc_ptr +=
1766                                             pSMBr->resp.SecurityBlobLength;
1767                                         cFYI(1,
1768                                              ("Security Blob Length %d ",
1769                                               pSMBr->resp.SecurityBlobLength));
1770                                 }
1771
1772                                 if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
1773                                         if ((long) (bcc_ptr) % 2) {
1774                                                 remaining_words =
1775                                                     (BCC(smb_buffer_response)
1776                                                      - 1) / 2;
1777                                                 bcc_ptr++;      /* Unicode strings must be word aligned */
1778                                         } else {
1779                                                 remaining_words =
1780                                                     BCC
1781                                                     (smb_buffer_response) / 2;
1782                                         }
1783                                         len =
1784                                             UniStrnlen((wchar_t *) bcc_ptr,
1785                                                        remaining_words - 1);
1786 /* We look for obvious messed up bcc or strings in response so we do not go off
1787    the end since (at least) WIN2K and Windows XP have a major bug in not null
1788    terminating last Unicode string in response  */
1789                                         ses->serverOS =
1790                                             cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
1791                                         cifs_strfromUCS_le(ses->serverOS,
1792                                                            (wchar_t *)
1793                                                            bcc_ptr, len,
1794                                                            nls_codepage);
1795                                         bcc_ptr += 2 * (len + 1);
1796                                         remaining_words -= len + 1;
1797                                         ses->serverOS[2 * len] = 0;
1798                                         ses->serverOS[1 + (2 * len)] = 0;
1799                                         if (remaining_words > 0) {
1800                                                 len = UniStrnlen((wchar_t *)bcc_ptr,
1801                                                                  remaining_words
1802                                                                  - 1);
1803                                                 ses->serverNOS =
1804                                                     cifs_kcalloc(2 * (len + 1),
1805                                                             GFP_KERNEL);
1806                                                 cifs_strfromUCS_le(ses->serverNOS,
1807                                                                    (wchar_t *)bcc_ptr,
1808                                                                    len,
1809                                                                    nls_codepage);
1810                                                 bcc_ptr += 2 * (len + 1);
1811                                                 ses->serverNOS[2 * len] = 0;
1812                                                 ses->serverNOS[1 + (2 * len)] = 0;
1813                                                 remaining_words -= len + 1;
1814                                                 if (remaining_words > 0) {
1815                                                         len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
1816                             /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1817                                                         ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL);
1818                                                         cifs_strfromUCS_le(ses->serverDomain,
1819                                                              (wchar_t *)bcc_ptr, 
1820                                  len,
1821                                                              nls_codepage);
1822                                                         bcc_ptr += 2*(len+1);
1823                                                         ses->serverDomain[2*len] = 0;
1824                                                         ses->serverDomain[1+(2*len)] = 0;
1825                                                 } /* else no more room so create dummy domain string */
1826                                                 else
1827                                                         ses->serverDomain =
1828                                                             cifs_kcalloc(2,GFP_KERNEL);
1829                                         } else {        /* no room so create dummy domain and NOS string */
1830                                                 ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
1831                                                 ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
1832                                         }
1833                                 } else {        /* ASCII */
1834
1835                                         len = strnlen(bcc_ptr, 1024);
1836                                         if (((long) bcc_ptr + len) - (long)
1837                                             pByteArea(smb_buffer_response)
1838                                             <= BCC(smb_buffer_response)) {
1839                                                 ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL);
1840                                                 strncpy(ses->serverOS, bcc_ptr, len);
1841
1842                                                 bcc_ptr += len;
1843                                                 bcc_ptr[0] = 0; /* null terminate the string */
1844                                                 bcc_ptr++;
1845
1846                                                 len = strnlen(bcc_ptr, 1024);
1847                                                 ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
1848                                                 strncpy(ses->serverNOS, bcc_ptr, len);
1849                                                 bcc_ptr += len;
1850                                                 bcc_ptr[0] = 0;
1851                                                 bcc_ptr++;
1852
1853                                                 len = strnlen(bcc_ptr, 1024);
1854                                                 ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL);
1855                                                 strncpy(ses->serverDomain, bcc_ptr, len);
1856                                                 bcc_ptr += len;
1857                                                 bcc_ptr[0] = 0;
1858                                                 bcc_ptr++;
1859                                         } else
1860                                                 cFYI(1,
1861                                                      ("Variable field of length %d extends beyond end of smb ",
1862                                                       len));
1863                                 }
1864                         } else {
1865                                 cERROR(1,
1866                                        (" Security Blob Length extends beyond end of SMB"));
1867                         }
1868                 } else {
1869                         cERROR(1, ("No session structure passed in."));
1870                 }
1871         } else {
1872                 cERROR(1,
1873                        (" Invalid Word count %d: ",
1874                         smb_buffer_response->WordCount));
1875                 rc = -EIO;
1876         }
1877
1878         if (smb_buffer)
1879                 cifs_buf_release(smb_buffer);
1880
1881         return rc;
1882 }
1883
1884 static int
1885 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
1886                               struct cifsSesInfo *ses, int * pNTLMv2_flag,
1887                               const struct nls_table *nls_codepage)
1888 {
1889         struct smb_hdr *smb_buffer;
1890         struct smb_hdr *smb_buffer_response;
1891         SESSION_SETUP_ANDX *pSMB;
1892         SESSION_SETUP_ANDX *pSMBr;
1893         char *bcc_ptr;
1894         char *domain = ses->domainName;
1895         int rc = 0;
1896         int remaining_words = 0;
1897         int bytes_returned = 0;
1898         int len;
1899         int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
1900         PNEGOTIATE_MESSAGE SecurityBlob;
1901         PCHALLENGE_MESSAGE SecurityBlob2;
1902
1903         cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
1904         *pNTLMv2_flag = FALSE;
1905         smb_buffer = cifs_buf_get();
1906         if (smb_buffer == 0) {
1907                 return -ENOMEM;
1908         }
1909         smb_buffer_response = smb_buffer;
1910         pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1911         pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
1912
1913         /* send SMBsessionSetup here */
1914         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1915                         0 /* no tCon exists yet */ , 12 /* wct */ );
1916         pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
1917         pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
1918
1919         pSMB->req.AndXCommand = 0xFF;
1920         pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1921         pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1922
1923         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1924                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1925
1926         pSMB->req.Capabilities =
1927             CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1928             CAP_EXTENDED_SECURITY;
1929         if (ses->capabilities & CAP_UNICODE) {
1930                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1931                 pSMB->req.Capabilities |= CAP_UNICODE;
1932         }
1933         if (ses->capabilities & CAP_STATUS32) {
1934                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1935                 pSMB->req.Capabilities |= CAP_STATUS32;
1936         }
1937         if (ses->capabilities & CAP_DFS) {
1938                 smb_buffer->Flags2 |= SMBFLG2_DFS;
1939                 pSMB->req.Capabilities |= CAP_DFS;
1940         }
1941         pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
1942
1943         bcc_ptr = (char *) &pSMB->req.SecurityBlob;
1944         SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
1945         strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
1946         SecurityBlob->MessageType = NtLmNegotiate;
1947         SecurityBlob->NegotiateFlags =
1948             NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
1949             NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
1950             /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
1951         if(sign_CIFS_PDUs)
1952                 SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
1953         if(ntlmv2_support)
1954                 SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
1955         /* setup pointers to domain name and workstation name */
1956         bcc_ptr += SecurityBlobLength;
1957
1958         SecurityBlob->WorkstationName.Buffer = 0;
1959         SecurityBlob->WorkstationName.Length = 0;
1960         SecurityBlob->WorkstationName.MaximumLength = 0;
1961
1962         if (domain == NULL) {
1963                 SecurityBlob->DomainName.Buffer = 0;
1964                 SecurityBlob->DomainName.Length = 0;
1965                 SecurityBlob->DomainName.MaximumLength = 0;
1966         } else {
1967                 SecurityBlob->NegotiateFlags |=
1968                     NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
1969                 strncpy(bcc_ptr, domain, 63);
1970                 SecurityBlob->DomainName.Length = strnlen(domain, 64);
1971                 SecurityBlob->DomainName.MaximumLength =
1972                     cpu_to_le16(SecurityBlob->DomainName.Length);
1973                 SecurityBlob->DomainName.Buffer =
1974                     cpu_to_le32((long) &SecurityBlob->
1975                                 DomainString -
1976                                 (long) &SecurityBlob->Signature);
1977                 bcc_ptr += SecurityBlob->DomainName.Length;
1978                 SecurityBlobLength += SecurityBlob->DomainName.Length;
1979                 SecurityBlob->DomainName.Length =
1980                     cpu_to_le16(SecurityBlob->DomainName.Length);
1981         }
1982         if (ses->capabilities & CAP_UNICODE) {
1983                 if ((long) bcc_ptr % 2) {
1984                         *bcc_ptr = 0;
1985                         bcc_ptr++;
1986                 }
1987
1988                 bytes_returned =
1989                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1990                                   32, nls_codepage);
1991                 bcc_ptr += 2 * bytes_returned;
1992                 bytes_returned =
1993                     cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
1994                                   nls_codepage);
1995                 bcc_ptr += 2 * bytes_returned;
1996                 bcc_ptr += 2;   /* null terminate Linux version */
1997                 bytes_returned =
1998                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1999                                   64, nls_codepage);
2000                 bcc_ptr += 2 * bytes_returned;
2001                 *(bcc_ptr + 1) = 0;
2002                 *(bcc_ptr + 2) = 0;
2003                 bcc_ptr += 2;   /* null terminate network opsys string */
2004                 *(bcc_ptr + 1) = 0;
2005                 *(bcc_ptr + 2) = 0;
2006                 bcc_ptr += 2;   /* null domain */
2007         } else {                /* ASCII */
2008                 strcpy(bcc_ptr, "Linux version ");
2009                 bcc_ptr += strlen("Linux version ");
2010                 strcpy(bcc_ptr, UTS_RELEASE);
2011                 bcc_ptr += strlen(UTS_RELEASE) + 1;
2012                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2013                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2014                 bcc_ptr++;      /* empty domain field */
2015                 *bcc_ptr = 0;
2016         }
2017         SecurityBlob->NegotiateFlags =
2018             cpu_to_le32(SecurityBlob->NegotiateFlags);
2019         pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2020         BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2021         smb_buffer->smb_buf_length += BCC(smb_buffer);
2022         BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
2023
2024         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2025                          &bytes_returned, 1);
2026
2027         if (smb_buffer_response->Status.CifsError ==
2028             (NT_STATUS_MORE_PROCESSING_REQUIRED))
2029                 rc = 0;
2030
2031         if (rc) {
2032 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
2033         } else if ((smb_buffer_response->WordCount == 3)
2034                    || (smb_buffer_response->WordCount == 4)) {
2035                 pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
2036                 pSMBr->resp.SecurityBlobLength =
2037                     le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2038                 if (pSMBr->resp.Action & GUEST_LOGIN)
2039                         cFYI(1, (" Guest login"));      
2040         /* Do we want to set anything in SesInfo struct when guest login? */
2041
2042                 bcc_ptr = pByteArea(smb_buffer_response);       
2043         /* response can have either 3 or 4 word count - Samba sends 3 */
2044
2045                 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2046                 if (SecurityBlob2->MessageType != NtLmChallenge) {
2047                         cFYI(1,
2048                              ("Unexpected NTLMSSP message type received %d",
2049                               SecurityBlob2->MessageType));
2050                 } else if (ses) {
2051                         ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ 
2052                         cFYI(1, ("UID = %d ", ses->Suid));
2053                         if ((pSMBr->resp.hdr.WordCount == 3)
2054                             || ((pSMBr->resp.hdr.WordCount == 4)
2055                                 && (pSMBr->resp.SecurityBlobLength <
2056                                     pSMBr->resp.ByteCount))) {
2057                                 if (pSMBr->resp.hdr.WordCount == 4) {
2058                                         bcc_ptr +=
2059                                             pSMBr->resp.SecurityBlobLength;
2060                                         cFYI(1,
2061                                              ("Security Blob Length %d ",
2062                                               pSMBr->resp.SecurityBlobLength));
2063                                 }
2064
2065                                 cFYI(1, ("NTLMSSP Challenge rcvd "));
2066
2067                                 memcpy(ses->server->cryptKey,
2068                                        SecurityBlob2->Challenge,
2069                                        CIFS_CRYPTO_KEY_SIZE);
2070                                 if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2)
2071                                         *pNTLMv2_flag = TRUE;
2072
2073                                 if((SecurityBlob2->NegotiateFlags & 
2074                                         NTLMSSP_NEGOTIATE_ALWAYS_SIGN) 
2075                                         || (sign_CIFS_PDUs > 1))
2076                                                 ses->server->secMode |= 
2077                                                         SECMODE_SIGN_REQUIRED;  
2078                                 if ((SecurityBlob2->NegotiateFlags & 
2079                                         NTLMSSP_NEGOTIATE_SIGN) && (sign_CIFS_PDUs))
2080                                                 ses->server->secMode |= 
2081                                                         SECMODE_SIGN_ENABLED;
2082
2083                                 if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
2084                                         if ((long) (bcc_ptr) % 2) {
2085                                                 remaining_words =
2086                                                     (BCC(smb_buffer_response)
2087                                                      - 1) / 2;
2088                                                 bcc_ptr++;      /* Unicode strings must be word aligned */
2089                                         } else {
2090                                                 remaining_words =
2091                                                     BCC
2092                                                     (smb_buffer_response) / 2;
2093                                         }
2094                                         len =
2095                                             UniStrnlen((wchar_t *) bcc_ptr,
2096                                                        remaining_words - 1);
2097 /* We look for obvious messed up bcc or strings in response so we do not go off
2098    the end since (at least) WIN2K and Windows XP have a major bug in not null
2099    terminating last Unicode string in response  */
2100                                         ses->serverOS =
2101                                             cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
2102                                         cifs_strfromUCS_le(ses->serverOS,
2103                                                            (wchar_t *)
2104                                                            bcc_ptr, len,
2105                                                            nls_codepage);
2106                                         bcc_ptr += 2 * (len + 1);
2107                                         remaining_words -= len + 1;
2108                                         ses->serverOS[2 * len] = 0;
2109                                         ses->serverOS[1 + (2 * len)] = 0;
2110                                         if (remaining_words > 0) {
2111                                                 len = UniStrnlen((wchar_t *)
2112                                                                  bcc_ptr,
2113                                                                  remaining_words
2114                                                                  - 1);
2115                                                 ses->serverNOS =
2116                                                     cifs_kcalloc(2 * (len + 1),
2117                                                             GFP_KERNEL);
2118                                                 cifs_strfromUCS_le(ses->
2119                                                                    serverNOS,
2120                                                                    (wchar_t *)
2121                                                                    bcc_ptr,
2122                                                                    len,
2123                                                                    nls_codepage);
2124                                                 bcc_ptr += 2 * (len + 1);
2125                                                 ses->serverNOS[2 * len] = 0;
2126                                                 ses->serverNOS[1 +
2127                                                                (2 * len)] = 0;
2128                                                 remaining_words -= len + 1;
2129                                                 if (remaining_words > 0) {
2130                                                         len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
2131            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2132                                                         ses->serverDomain =
2133                                                             cifs_kcalloc(2 *
2134                                                                     (len +
2135                                                                      1),
2136                                                                     GFP_KERNEL);
2137                                                         cifs_strfromUCS_le
2138                                                             (ses->
2139                                                              serverDomain,
2140                                                              (wchar_t *)
2141                                                              bcc_ptr, len,
2142                                                              nls_codepage);
2143                                                         bcc_ptr +=
2144                                                             2 * (len + 1);
2145                                                         ses->
2146                                                             serverDomain[2
2147                                                                          * len]
2148                                                             = 0;
2149                                                         ses->
2150                                                             serverDomain[1
2151                                                                          +
2152                                                                          (2
2153                                                                           *
2154                                                                           len)]
2155                                                             = 0;
2156                                                 } /* else no more room so create dummy domain string */
2157                                                 else
2158                                                         ses->serverDomain =
2159                                                             cifs_kcalloc(2,
2160                                                                     GFP_KERNEL);
2161                                         } else {        /* no room so create dummy domain and NOS string */
2162                                                 ses->serverDomain =
2163                                                     cifs_kcalloc(2, GFP_KERNEL);
2164                                                 ses->serverNOS =
2165                                                     cifs_kcalloc(2, GFP_KERNEL);
2166                                         }
2167                                 } else {        /* ASCII */
2168                                         len = strnlen(bcc_ptr, 1024);
2169                                         if (((long) bcc_ptr + len) - (long)
2170                                             pByteArea(smb_buffer_response)
2171                                             <= BCC(smb_buffer_response)) {
2172                                                 ses->serverOS =
2173                                                     cifs_kcalloc(len + 1,
2174                                                             GFP_KERNEL);
2175                                                 strncpy(ses->serverOS,
2176                                                         bcc_ptr, len);
2177
2178                                                 bcc_ptr += len;
2179                                                 bcc_ptr[0] = 0; /* null terminate string */
2180                                                 bcc_ptr++;
2181
2182                                                 len = strnlen(bcc_ptr, 1024);
2183                                                 ses->serverNOS =
2184                                                     cifs_kcalloc(len + 1,
2185                                                             GFP_KERNEL);
2186                                                 strncpy(ses->serverNOS, bcc_ptr, len);
2187                                                 bcc_ptr += len;
2188                                                 bcc_ptr[0] = 0;
2189                                                 bcc_ptr++;
2190
2191                                                 len = strnlen(bcc_ptr, 1024);
2192                                                 ses->serverDomain =
2193                                                     cifs_kcalloc(len + 1,
2194                                                             GFP_KERNEL);
2195                                                 strncpy(ses->serverDomain, bcc_ptr, len);       
2196                                                 bcc_ptr += len;
2197                                                 bcc_ptr[0] = 0;
2198                                                 bcc_ptr++;
2199                                         } else
2200                                                 cFYI(1,
2201                                                      ("Variable field of length %d extends beyond end of smb ",
2202                                                       len));
2203                                 }
2204                         } else {
2205                                 cERROR(1,
2206                                        (" Security Blob Length extends beyond end of SMB"));
2207                         }
2208                 } else {
2209                         cERROR(1, ("No session structure passed in."));
2210                 }
2211         } else {
2212                 cERROR(1,
2213                        (" Invalid Word count %d: ",
2214                         smb_buffer_response->WordCount));
2215                 rc = -EIO;
2216         }
2217
2218         if (smb_buffer)
2219                 cifs_buf_release(smb_buffer);
2220
2221         return rc;
2222 }
2223
2224 static int
2225 CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2226                 char *ntlm_session_key, int ntlmv2_flag,
2227                 const struct nls_table *nls_codepage)
2228 {
2229         struct smb_hdr *smb_buffer;
2230         struct smb_hdr *smb_buffer_response;
2231         SESSION_SETUP_ANDX *pSMB;
2232         SESSION_SETUP_ANDX *pSMBr;
2233         char *bcc_ptr;
2234         char *user = ses->userName;
2235         char *domain = ses->domainName;
2236         int rc = 0;
2237         int remaining_words = 0;
2238         int bytes_returned = 0;
2239         int len;
2240         int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2241         PAUTHENTICATE_MESSAGE SecurityBlob;
2242
2243         cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2244
2245         smb_buffer = cifs_buf_get();
2246         if (smb_buffer == 0) {
2247                 return -ENOMEM;
2248         }
2249         smb_buffer_response = smb_buffer;
2250         pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2251         pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2252
2253         /* send SMBsessionSetup here */
2254         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2255                         0 /* no tCon exists yet */ , 12 /* wct */ );
2256         pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2257         pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2258         pSMB->req.AndXCommand = 0xFF;
2259         pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2260         pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2261
2262         pSMB->req.hdr.Uid = ses->Suid;
2263
2264         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2265                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2266
2267         pSMB->req.Capabilities =
2268             CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2269             CAP_EXTENDED_SECURITY;
2270         if (ses->capabilities & CAP_UNICODE) {
2271                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2272                 pSMB->req.Capabilities |= CAP_UNICODE;
2273         }
2274         if (ses->capabilities & CAP_STATUS32) {
2275                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2276                 pSMB->req.Capabilities |= CAP_STATUS32;
2277         }
2278         if (ses->capabilities & CAP_DFS) {
2279                 smb_buffer->Flags2 |= SMBFLG2_DFS;
2280                 pSMB->req.Capabilities |= CAP_DFS;
2281         }
2282         pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
2283
2284         bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2285         SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2286         strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2287         SecurityBlob->MessageType = NtLmAuthenticate;
2288         bcc_ptr += SecurityBlobLength;
2289         SecurityBlob->NegotiateFlags =
2290             NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2291             NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2292             0x80000000 | NTLMSSP_NEGOTIATE_128;
2293         if(sign_CIFS_PDUs)
2294                 SecurityBlob->NegotiateFlags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2295         if(ntlmv2_flag)
2296                 SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
2297
2298 /* setup pointers to domain name and workstation name */
2299
2300         SecurityBlob->WorkstationName.Buffer = 0;
2301         SecurityBlob->WorkstationName.Length = 0;
2302         SecurityBlob->WorkstationName.MaximumLength = 0;
2303         SecurityBlob->SessionKey.Length = 0;
2304         SecurityBlob->SessionKey.MaximumLength = 0;
2305         SecurityBlob->SessionKey.Buffer = 0;
2306
2307         SecurityBlob->LmChallengeResponse.Length = 0;
2308         SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2309         SecurityBlob->LmChallengeResponse.Buffer = 0;
2310
2311         SecurityBlob->NtChallengeResponse.Length =
2312             cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2313         SecurityBlob->NtChallengeResponse.MaximumLength =
2314             cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2315         memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2316         SecurityBlob->NtChallengeResponse.Buffer =
2317             cpu_to_le32(SecurityBlobLength);
2318         SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2319         bcc_ptr += CIFS_SESSION_KEY_SIZE;
2320
2321         if (ses->capabilities & CAP_UNICODE) {
2322                 if (domain == NULL) {
2323                         SecurityBlob->DomainName.Buffer = 0;
2324                         SecurityBlob->DomainName.Length = 0;
2325                         SecurityBlob->DomainName.MaximumLength = 0;
2326                 } else {
2327                         SecurityBlob->DomainName.Length =
2328                             cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2329                                           nls_codepage);
2330                         SecurityBlob->DomainName.Length *= 2;
2331                         SecurityBlob->DomainName.MaximumLength =
2332                             cpu_to_le16(SecurityBlob->DomainName.Length);
2333                         SecurityBlob->DomainName.Buffer =
2334                             cpu_to_le32(SecurityBlobLength);
2335                         bcc_ptr += SecurityBlob->DomainName.Length;
2336                         SecurityBlobLength += SecurityBlob->DomainName.Length;
2337                         SecurityBlob->DomainName.Length =
2338                             cpu_to_le16(SecurityBlob->DomainName.Length);
2339                 }
2340                 if (user == NULL) {
2341                         SecurityBlob->UserName.Buffer = 0;
2342                         SecurityBlob->UserName.Length = 0;
2343                         SecurityBlob->UserName.MaximumLength = 0;
2344                 } else {
2345                         SecurityBlob->UserName.Length =
2346                             cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2347                                           nls_codepage);
2348                         SecurityBlob->UserName.Length *= 2;
2349                         SecurityBlob->UserName.MaximumLength =
2350                             cpu_to_le16(SecurityBlob->UserName.Length);
2351                         SecurityBlob->UserName.Buffer =
2352                             cpu_to_le32(SecurityBlobLength);
2353                         bcc_ptr += SecurityBlob->UserName.Length;
2354                         SecurityBlobLength += SecurityBlob->UserName.Length;
2355                         SecurityBlob->UserName.Length =
2356                             cpu_to_le16(SecurityBlob->UserName.Length);
2357                 }
2358
2359                 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2360                    SecurityBlob->WorkstationName.Length *= 2;
2361                    SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2362                    SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2363                    bcc_ptr += SecurityBlob->WorkstationName.Length;
2364                    SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2365                    SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length);  */
2366
2367                 if ((long) bcc_ptr % 2) {
2368                         *bcc_ptr = 0;
2369                         bcc_ptr++;
2370                 }
2371                 bytes_returned =
2372                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2373                                   32, nls_codepage);
2374                 bcc_ptr += 2 * bytes_returned;
2375                 bytes_returned =
2376                     cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
2377                                   nls_codepage);
2378                 bcc_ptr += 2 * bytes_returned;
2379                 bcc_ptr += 2;   /* null term version string */
2380                 bytes_returned =
2381                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2382                                   64, nls_codepage);
2383                 bcc_ptr += 2 * bytes_returned;
2384                 *(bcc_ptr + 1) = 0;
2385                 *(bcc_ptr + 2) = 0;
2386                 bcc_ptr += 2;   /* null terminate network opsys string */
2387                 *(bcc_ptr + 1) = 0;
2388                 *(bcc_ptr + 2) = 0;
2389                 bcc_ptr += 2;   /* null domain */
2390         } else {                /* ASCII */
2391                 if (domain == NULL) {
2392                         SecurityBlob->DomainName.Buffer = 0;
2393                         SecurityBlob->DomainName.Length = 0;
2394                         SecurityBlob->DomainName.MaximumLength = 0;
2395                 } else {
2396                         SecurityBlob->NegotiateFlags |=
2397                             NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2398                         strncpy(bcc_ptr, domain, 63);
2399                         SecurityBlob->DomainName.Length = strnlen(domain, 64);
2400                         SecurityBlob->DomainName.MaximumLength =
2401                             cpu_to_le16(SecurityBlob->DomainName.Length);
2402                         SecurityBlob->DomainName.Buffer =
2403                             cpu_to_le32(SecurityBlobLength);
2404                         bcc_ptr += SecurityBlob->DomainName.Length;
2405                         SecurityBlobLength += SecurityBlob->DomainName.Length;
2406                         SecurityBlob->DomainName.Length =
2407                             cpu_to_le16(SecurityBlob->DomainName.Length);
2408                 }
2409                 if (user == NULL) {
2410                         SecurityBlob->UserName.Buffer = 0;
2411                         SecurityBlob->UserName.Length = 0;
2412                         SecurityBlob->UserName.MaximumLength = 0;
2413                 } else {
2414                         strncpy(bcc_ptr, user, 63);
2415                         SecurityBlob->UserName.Length = strnlen(user, 64);
2416                         SecurityBlob->UserName.MaximumLength =
2417                             cpu_to_le16(SecurityBlob->UserName.Length);
2418                         SecurityBlob->UserName.Buffer =
2419                             cpu_to_le32(SecurityBlobLength);
2420                         bcc_ptr += SecurityBlob->UserName.Length;
2421                         SecurityBlobLength += SecurityBlob->UserName.Length;
2422                         SecurityBlob->UserName.Length =
2423                             cpu_to_le16(SecurityBlob->UserName.Length);
2424                 }
2425                 /* BB fill in our workstation name if known BB */
2426
2427                 strcpy(bcc_ptr, "Linux version ");
2428                 bcc_ptr += strlen("Linux version ");
2429                 strcpy(bcc_ptr, UTS_RELEASE);
2430                 bcc_ptr += strlen(UTS_RELEASE) + 1;
2431                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2432                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2433                 bcc_ptr++;      /* null domain */
2434                 *bcc_ptr = 0;
2435         }
2436         SecurityBlob->NegotiateFlags =
2437             cpu_to_le32(SecurityBlob->NegotiateFlags);
2438         pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2439         BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2440         smb_buffer->smb_buf_length += BCC(smb_buffer);
2441         BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
2442
2443         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2444                          &bytes_returned, 1);
2445         if (rc) {
2446 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
2447         } else if ((smb_buffer_response->WordCount == 3)
2448                    || (smb_buffer_response->WordCount == 4)) {
2449                 pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
2450                 pSMBr->resp.SecurityBlobLength =
2451                     le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2452                 if (pSMBr->resp.Action & GUEST_LOGIN)
2453                         cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
2454 /*        if(SecurityBlob2->MessageType != NtLm??){                               
2455                  cFYI("Unexpected message type on auth response is %d ")); 
2456         } */
2457                 if (ses) {
2458                         cFYI(1,
2459                              ("Does UID on challenge %d match auth response UID %d ",
2460                               ses->Suid, smb_buffer_response->Uid));
2461                         ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2462                         bcc_ptr = pByteArea(smb_buffer_response);       
2463             /* response can have either 3 or 4 word count - Samba sends 3 */
2464                         if ((pSMBr->resp.hdr.WordCount == 3)
2465                             || ((pSMBr->resp.hdr.WordCount == 4)
2466                                 && (pSMBr->resp.SecurityBlobLength <
2467                                     pSMBr->resp.ByteCount))) {
2468                                 if (pSMBr->resp.hdr.WordCount == 4) {
2469                                         bcc_ptr +=
2470                                             pSMBr->resp.SecurityBlobLength;
2471                                         cFYI(1,
2472                                              ("Security Blob Length %d ",
2473                                               pSMBr->resp.SecurityBlobLength));
2474                                 }
2475
2476                                 cFYI(1,
2477                                      ("NTLMSSP response to Authenticate "));
2478
2479                                 if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
2480                                         if ((long) (bcc_ptr) % 2) {
2481                                                 remaining_words =
2482                                                     (BCC(smb_buffer_response)
2483                                                      - 1) / 2;
2484                                                 bcc_ptr++;      /* Unicode strings must be word aligned */
2485                                         } else {
2486                                                 remaining_words = BCC(smb_buffer_response) / 2;
2487                                         }
2488                                         len =
2489                                             UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2490 /* We look for obvious messed up bcc or strings in response so we do not go off
2491   the end since (at least) WIN2K and Windows XP have a major bug in not null
2492   terminating last Unicode string in response  */
2493                                         ses->serverOS =
2494                                             cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
2495                                         cifs_strfromUCS_le(ses->serverOS,
2496                                                            (wchar_t *)
2497                                                            bcc_ptr, len,
2498                                                            nls_codepage);
2499                                         bcc_ptr += 2 * (len + 1);
2500                                         remaining_words -= len + 1;
2501                                         ses->serverOS[2 * len] = 0;
2502                                         ses->serverOS[1 + (2 * len)] = 0;
2503                                         if (remaining_words > 0) {
2504                                                 len = UniStrnlen((wchar_t *)
2505                                                                  bcc_ptr,
2506                                                                  remaining_words
2507                                                                  - 1);
2508                                                 ses->serverNOS =
2509                                                     cifs_kcalloc(2 * (len + 1),
2510                                                             GFP_KERNEL);
2511                                                 cifs_strfromUCS_le(ses->
2512                                                                    serverNOS,
2513                                                                    (wchar_t *)
2514                                                                    bcc_ptr,
2515                                                                    len,
2516                                                                    nls_codepage);
2517                                                 bcc_ptr += 2 * (len + 1);
2518                                                 ses->serverNOS[2 * len] = 0;
2519                                                 ses->serverNOS[1+(2*len)] = 0;
2520                                                 remaining_words -= len + 1;
2521                                                 if (remaining_words > 0) {
2522                                                         len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
2523      /* last string not always null terminated (e.g. for Windows XP & 2000) */
2524                                                         ses->serverDomain =
2525                                                             cifs_kcalloc(2 *
2526                                                                     (len +
2527                                                                      1),
2528                                                                     GFP_KERNEL);
2529                                                         cifs_strfromUCS_le
2530                                                             (ses->
2531                                                              serverDomain,
2532                                                              (wchar_t *)
2533                                                              bcc_ptr, len,
2534                                                              nls_codepage);
2535                                                         bcc_ptr +=
2536                                                             2 * (len + 1);
2537                                                         ses->
2538                                                             serverDomain[2
2539                                                                          * len]
2540                                                             = 0;
2541                                                         ses->
2542                                                             serverDomain[1
2543                                                                          +
2544                                                                          (2
2545                                                                           *
2546                                                                           len)]
2547                                                             = 0;
2548                                                 } /* else no more room so create dummy domain string */
2549                                                 else
2550                                                         ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL);
2551                                         } else {  /* no room so create dummy domain and NOS string */
2552                                                 ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
2553                                                 ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
2554                                         }
2555                                 } else {        /* ASCII */
2556                                         len = strnlen(bcc_ptr, 1024);
2557                                         if (((long) bcc_ptr + len) - 
2558                         (long) pByteArea(smb_buffer_response) 
2559                             <= BCC(smb_buffer_response)) {
2560                                                 ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
2561                                                 strncpy(ses->serverOS,bcc_ptr, len);
2562
2563                                                 bcc_ptr += len;
2564                                                 bcc_ptr[0] = 0; /* null terminate the string */
2565                                                 bcc_ptr++;
2566
2567                                                 len = strnlen(bcc_ptr, 1024);
2568                                                 ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL);
2569                                                 strncpy(ses->serverNOS, bcc_ptr, len);  
2570                                                 bcc_ptr += len;
2571                                                 bcc_ptr[0] = 0;
2572                                                 bcc_ptr++;
2573
2574                                                 len = strnlen(bcc_ptr, 1024);
2575                                                 ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL);
2576                                                 strncpy(ses->serverDomain, bcc_ptr, len);
2577                                                 bcc_ptr += len;
2578                                                 bcc_ptr[0] = 0;
2579                                                 bcc_ptr++;
2580                                         } else
2581                                                 cFYI(1,
2582                                                      ("Variable field of length %d extends beyond end of smb ",
2583                                                       len));
2584                                 }
2585                         } else {
2586                                 cERROR(1,
2587                                        (" Security Blob Length extends beyond end of SMB"));
2588                         }
2589                 } else {
2590                         cERROR(1, ("No session structure passed in."));
2591                 }
2592         } else {
2593                 cERROR(1,
2594                        (" Invalid Word count %d: ",
2595                         smb_buffer_response->WordCount));
2596                 rc = -EIO;
2597         }
2598
2599         if (smb_buffer)
2600                 cifs_buf_release(smb_buffer);
2601
2602         return rc;
2603 }
2604
2605 int
2606 CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2607          const char *tree, struct cifsTconInfo *tcon,
2608          const struct nls_table *nls_codepage)
2609 {
2610         struct smb_hdr *smb_buffer;
2611         struct smb_hdr *smb_buffer_response;
2612         TCONX_REQ *pSMB;
2613         TCONX_RSP *pSMBr;
2614         char *bcc_ptr;
2615         int rc = 0;
2616         int length;
2617
2618         if (ses == NULL)
2619                 return -EIO;
2620
2621         smb_buffer = cifs_buf_get();
2622         if (smb_buffer == 0) {
2623                 return -ENOMEM;
2624         }
2625         smb_buffer_response = smb_buffer;
2626
2627         header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
2628                         0 /*no tid */ , 4 /*wct */ );
2629         smb_buffer->Uid = ses->Suid;
2630         pSMB = (TCONX_REQ *) smb_buffer;
2631         pSMBr = (TCONX_RSP *) smb_buffer_response;
2632
2633         pSMB->AndXCommand = 0xFF;
2634         pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
2635         pSMB->PasswordLength = cpu_to_le16(1);  /* minimum */
2636         bcc_ptr = &(pSMB->Password[0]);
2637         bcc_ptr++;              /* skip password */
2638
2639         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2640                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2641
2642         if (ses->capabilities & CAP_STATUS32) {
2643                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2644         }
2645         if (ses->capabilities & CAP_DFS) {
2646                 smb_buffer->Flags2 |= SMBFLG2_DFS;
2647         }
2648         if (ses->capabilities & CAP_UNICODE) {
2649                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2650                 length =
2651                     cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
2652                 bcc_ptr += 2 * length;  /* convert num of 16 bit words to bytes */
2653                 bcc_ptr += 2;   /* skip trailing null */
2654         } else {                /* ASCII */
2655
2656                 strcpy(bcc_ptr, tree);
2657                 bcc_ptr += strlen(tree) + 1;
2658         }
2659         strcpy(bcc_ptr, "?????");
2660         bcc_ptr += strlen("?????");
2661         bcc_ptr += 1;
2662         BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2663         smb_buffer->smb_buf_length += BCC(smb_buffer);
2664         BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
2665
2666         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
2667
2668         /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
2669         /* above now done in SendReceive */
2670         if ((rc == 0) && (tcon != NULL)) {
2671         tcon->tidStatus = CifsGood;
2672                 tcon->tid = smb_buffer_response->Tid;
2673                 bcc_ptr = pByteArea(smb_buffer_response);
2674                 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
2675         /* skip service field (NB: this field is always ASCII) */
2676                 bcc_ptr += length + 1;  
2677                 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
2678                 if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
2679                         length = UniStrnlen((wchar_t *) bcc_ptr, 512);
2680                         if (((long) bcc_ptr + (2 * length)) -
2681                             (long) pByteArea(smb_buffer_response) <=
2682                             BCC(smb_buffer_response)) {
2683                                 if(tcon->nativeFileSystem)
2684                                         kfree(tcon->nativeFileSystem);
2685                                 tcon->nativeFileSystem =
2686                                     cifs_kcalloc(length + 2, GFP_KERNEL);
2687                                 cifs_strfromUCS_le(tcon->nativeFileSystem,
2688                                                    (wchar_t *) bcc_ptr,
2689                                                    length, nls_codepage);
2690                                 bcc_ptr += 2 * length;
2691                                 bcc_ptr[0] = 0; /* null terminate the string */
2692                                 bcc_ptr[1] = 0;
2693                                 bcc_ptr += 2;
2694                         }
2695                         /* else do not bother copying these informational fields */
2696                 } else {
2697                         length = strnlen(bcc_ptr, 1024);
2698                         if (((long) bcc_ptr + 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 + 1, GFP_KERNEL);
2705                                 strncpy(tcon->nativeFileSystem, bcc_ptr,
2706                                         length);
2707                         }
2708                         /* else do not bother copying these informational fields */
2709                 }
2710                 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
2711                 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
2712         } else if ((rc == 0) && tcon == NULL) {
2713         /* all we need to save for IPC$ connection */
2714                 ses->ipc_tid = smb_buffer_response->Tid;
2715         }
2716
2717         if (smb_buffer)
2718                 cifs_buf_release(smb_buffer);
2719         return rc;
2720 }
2721
2722 int
2723 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
2724 {
2725         int rc = 0;
2726         int xid;
2727         struct cifsSesInfo *ses = NULL;
2728
2729         xid = GetXid();
2730
2731         if (cifs_sb->tcon) {
2732                 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
2733                 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
2734                 if (rc == -EBUSY) {
2735                         FreeXid(xid);
2736                         return 0;
2737                 }
2738                 tconInfoFree(cifs_sb->tcon);
2739                 if ((ses) && (ses->server)) {
2740                         cFYI(1, ("About to do SMBLogoff "));
2741                         rc = CIFSSMBLogoff(xid, ses);
2742                         if (rc == -EBUSY) {
2743                                 FreeXid(xid);
2744                                 return 0;
2745                         }
2746                         set_current_state(TASK_INTERRUPTIBLE);
2747                         schedule_timeout(HZ / 4);       /* give captive thread time to exit */
2748                         if((ses->server) && (ses->server->ssocket)) {            
2749                                 cFYI(1,("Waking up socket by sending it signal "));
2750                                 send_sig(SIGKILL,ses->server->tsk,1);
2751                         }
2752                 } else
2753                         cFYI(1, ("No session or bad tcon"));
2754         }
2755         
2756         cifs_sb->tcon = NULL;
2757         if (ses) {
2758                 set_current_state(TASK_INTERRUPTIBLE);
2759                 schedule_timeout(HZ / 2);
2760         }
2761         if (ses)
2762                 sesInfoFree(ses);
2763
2764         FreeXid(xid);
2765         return rc;              /* BB check if we should always return zero here */
2766
2767
2768 int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
2769                                            struct nls_table * nls_info)
2770 {
2771         int rc = 0;
2772         char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
2773         int ntlmv2_flag = FALSE;
2774
2775     /* what if server changes its buffer size after dropping the session? */
2776         if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
2777                 rc = CIFSSMBNegotiate(xid, pSesInfo);
2778                 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
2779                         rc = CIFSSMBNegotiate(xid, pSesInfo);
2780                         if(rc == -EAGAIN) 
2781                                 rc = -EHOSTDOWN;
2782                 }
2783                 if(rc == 0)
2784                         pSesInfo->server->tcpStatus = CifsGood;
2785         }
2786         if (!rc) {
2787                 pSesInfo->capabilities = pSesInfo->server->capabilities;
2788                 if(linuxExtEnabled == 0)
2789                         pSesInfo->capabilities &= (~CAP_UNIX);
2790                 pSesInfo->sequence_number = 0;
2791                 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
2792                         pSesInfo->server->secMode,
2793                         pSesInfo->server->capabilities,
2794                         pSesInfo->server->timeZone));
2795                 if (extended_security
2796                                 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
2797                                 && (pSesInfo->server->secType == NTLMSSP)) {
2798                         cFYI(1, ("New style sesssetup "));
2799                         rc = CIFSSpnegoSessSetup(xid, pSesInfo,
2800                                 NULL /* security blob */, 
2801                                 0 /* blob length */,
2802                                 nls_info);
2803                 } else if (extended_security
2804                            && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
2805                            && (pSesInfo->server->secType == RawNTLMSSP)) {
2806                         cFYI(1, ("NTLMSSP sesssetup "));
2807                         rc = CIFSNTLMSSPNegotiateSessSetup(xid,
2808                                                 pSesInfo,
2809                                                 &ntlmv2_flag,
2810                                                 nls_info);
2811                         if (!rc) {
2812                                 if(ntlmv2_flag) {
2813                                         char * v2_response;
2814                                         cFYI(1,("Can use more secure NTLM version 2 password hash"));
2815                                         CalcNTLMv2_partial_mac_key(pSesInfo, 
2816                                                 nls_info);
2817                                         v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
2818                                         if(v2_response) {
2819                                                 CalcNTLMv2_response(pSesInfo,v2_response);
2820 /*                                              cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */
2821                                                 kfree(v2_response);
2822                                         /* BB Put dummy sig in SessSetup PDU? */
2823                                         } else
2824                                                 rc = -ENOMEM;
2825
2826                                 } else {
2827                                         SMBNTencrypt(pSesInfo->password,
2828                                                 pSesInfo->server->cryptKey,
2829                                                 ntlm_session_key);
2830
2831                                         cifs_calculate_mac_key(pSesInfo->mac_signing_key,
2832                                                 ntlm_session_key,
2833                                                 pSesInfo->password);
2834                                 }
2835                         /* for better security the weaker lanman hash not sent
2836                            in AuthSessSetup so we no longer calculate it */
2837
2838                                 rc = CIFSNTLMSSPAuthSessSetup(xid,
2839                                         pSesInfo,
2840                                         ntlm_session_key,
2841                                         ntlmv2_flag,
2842                                         nls_info);
2843                         }
2844                 } else { /* old style NTLM 0.12 session setup */
2845                         SMBNTencrypt(pSesInfo->password,
2846                                 pSesInfo->server->cryptKey,
2847                                 ntlm_session_key);
2848
2849                         cifs_calculate_mac_key(pSesInfo->mac_signing_key, 
2850                                 ntlm_session_key, pSesInfo->password);
2851                         rc = CIFSSessSetup(xid, pSesInfo,
2852                                 ntlm_session_key, nls_info);
2853                 }
2854                 if (rc) {
2855                         cERROR(1,("Send error in SessSetup = %d",rc));
2856                 } else {
2857                         cFYI(1,("CIFS Session Established successfully"));
2858                         pSesInfo->status = CifsGood;
2859                 }
2860         }
2861         return rc;
2862 }
2863