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