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