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