]> git.karo-electronics.de Git - karo-tx-linux.git/blob - fs/cifs/connect.c
[PATCH] cifs: Add new mount parm mapchars
[karo-tx-linux.git] / fs / cifs / connect.c
1 /*
2  *   fs/cifs/connect.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2004
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   This library is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU Lesser General Public License as published
9  *   by the Free Software Foundation; either version 2.1 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This library is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
15  *   the GNU Lesser General Public License for more details.
16  *
17  *   You should have received a copy of the GNU Lesser General Public License
18  *   along with this library; if not, write to the Free Software
19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
20  */
21 #include <linux/fs.h>
22 #include <linux/net.h>
23 #include <linux/string.h>
24 #include <linux/list.h>
25 #include <linux/wait.h>
26 #include <linux/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 {
929         unsigned char *referrals = NULL;
930         unsigned int num_referrals;
931         int rc = 0;
932
933         rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, 
934                         &num_referrals, &referrals);
935
936         /* BB Add in code to: if valid refrl, if not ip address contact
937                 the helper that resolves tcp names, mount to it, try to 
938                 tcon to it unmount it if fail */
939
940         if(referrals)
941                 kfree(referrals);
942
943         return rc;
944 }
945
946 int
947 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
948                         const char *old_path, const struct nls_table *nls_codepage, 
949                         unsigned int *pnum_referrals, unsigned char ** preferrals)
950 {
951         char *temp_unc;
952         int rc = 0;
953
954         *pnum_referrals = 0;
955
956         if (pSesInfo->ipc_tid == 0) {
957                 temp_unc = kmalloc(2 /* for slashes */ +
958                         strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
959                                  + 1 + 4 /* slash IPC$ */  + 2,
960                                 GFP_KERNEL);
961                 if (temp_unc == NULL)
962                         return -ENOMEM;
963                 temp_unc[0] = '\\';
964                 temp_unc[1] = '\\';
965                 strcpy(temp_unc + 2, pSesInfo->serverName);
966                 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
967                 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
968                 cFYI(1,
969                      ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
970                 kfree(temp_unc);
971         }
972         if (rc == 0)
973                 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
974                                      pnum_referrals, nls_codepage);
975
976         return rc;
977 }
978
979 /* See RFC1001 section 14 on representation of Netbios names */
980 static void rfc1002mangle(char * target,char * source, unsigned int length)
981 {
982         unsigned int i,j;
983
984         for(i=0,j=0;i<(length);i++) {
985                 /* mask a nibble at a time and encode */
986                 target[j] = 'A' + (0x0F & (source[i] >> 4));
987                 target[j+1] = 'A' + (0x0F & source[i]);
988                 j+=2;
989         }
990
991 }
992
993
994 static int
995 ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, 
996                          char * netbios_name)
997 {
998         int rc = 0;
999         int connected = 0;
1000         __be16 orig_port = 0;
1001
1002         if(*csocket == NULL) {
1003                 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1004                 if (rc < 0) {
1005                         cERROR(1, ("Error %d creating socket",rc));
1006                         *csocket = NULL;
1007                         return rc;
1008                 } else {
1009                 /* BB other socket options to set KEEPALIVE, NODELAY? */
1010                         cFYI(1,("Socket created"));
1011                         (*csocket)->sk->sk_allocation = GFP_NOFS; 
1012                 }
1013         }
1014
1015         psin_server->sin_family = AF_INET;
1016         if(psin_server->sin_port) { /* user overrode default port */
1017                 rc = (*csocket)->ops->connect(*csocket,
1018                                 (struct sockaddr *) psin_server,
1019                                 sizeof (struct sockaddr_in),0);
1020                 if (rc >= 0)
1021                         connected = 1;
1022         } 
1023
1024         if(!connected) {
1025                 /* save original port so we can retry user specified port  
1026                         later if fall back ports fail this time  */
1027                 orig_port = psin_server->sin_port;
1028
1029                 /* do not retry on the same port we just failed on */
1030                 if(psin_server->sin_port != htons(CIFS_PORT)) {
1031                         psin_server->sin_port = htons(CIFS_PORT);
1032
1033                         rc = (*csocket)->ops->connect(*csocket,
1034                                         (struct sockaddr *) psin_server,
1035                                         sizeof (struct sockaddr_in),0);
1036                         if (rc >= 0)
1037                                 connected = 1;
1038                 }
1039         }
1040         if (!connected) {
1041                 psin_server->sin_port = htons(RFC1001_PORT);
1042                 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1043                                               psin_server, sizeof (struct sockaddr_in),0);
1044                 if (rc >= 0) 
1045                         connected = 1;
1046         }
1047
1048         /* give up here - unless we want to retry on different
1049                 protocol families some day */
1050         if (!connected) {
1051                 if(orig_port)
1052                         psin_server->sin_port = orig_port;
1053                 cFYI(1,("Error %d connecting to server via ipv4",rc));
1054                 sock_release(*csocket);
1055                 *csocket = NULL;
1056                 return rc;
1057         }
1058         /* Eventually check for other socket options to change from 
1059                 the default. sock_setsockopt not used because it expects 
1060                 user space buffer */
1061         (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1062
1063         /* send RFC1001 sessinit */
1064
1065         if(psin_server->sin_port == htons(RFC1001_PORT)) {
1066                 /* some servers require RFC1001 sessinit before sending
1067                 negprot - BB check reconnection in case where second 
1068                 sessinit is sent but no second negprot */
1069                 struct rfc1002_session_packet * ses_init_buf;
1070                 struct smb_hdr * smb_buf;
1071                 ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
1072                 if(ses_init_buf) {
1073                         ses_init_buf->trailer.session_req.called_len = 32;
1074                         rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1075                                 DEFAULT_CIFS_CALLED_NAME,16);
1076                         ses_init_buf->trailer.session_req.calling_len = 32;
1077                         /* calling name ends in null (byte 16) from old smb
1078                         convention. */
1079                         if(netbios_name && (netbios_name[0] !=0)) {
1080                                 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1081                                         netbios_name,16);
1082                         } else {
1083                                 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1084                                         "LINUX_CIFS_CLNT",16);
1085                         }
1086                         ses_init_buf->trailer.session_req.scope1 = 0;
1087                         ses_init_buf->trailer.session_req.scope2 = 0;
1088                         smb_buf = (struct smb_hdr *)ses_init_buf;
1089                         /* sizeof RFC1002_SESSION_REQUEST with no scope */
1090                         smb_buf->smb_buf_length = 0x81000044;
1091                         rc = smb_send(*csocket, smb_buf, 0x44,
1092                                 (struct sockaddr *)psin_server);
1093                         kfree(ses_init_buf);
1094                 }
1095                 /* else the negprot may still work without this 
1096                 even though malloc failed */
1097                 
1098         }
1099                 
1100         return rc;
1101 }
1102
1103 static int
1104 ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1105 {
1106         int rc = 0;
1107         int connected = 0;
1108         __be16 orig_port = 0;
1109
1110         if(*csocket == NULL) {
1111                 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1112                 if (rc < 0) {
1113                         cERROR(1, ("Error %d creating ipv6 socket",rc));
1114                         *csocket = NULL;
1115                         return rc;
1116                 } else {
1117                 /* BB other socket options to set KEEPALIVE, NODELAY? */
1118                          cFYI(1,("ipv6 Socket created"));
1119                         (*csocket)->sk->sk_allocation = GFP_NOFS;
1120                 }
1121         }
1122
1123         psin_server->sin6_family = AF_INET6;
1124
1125         if(psin_server->sin6_port) { /* user overrode default port */
1126                 rc = (*csocket)->ops->connect(*csocket,
1127                                 (struct sockaddr *) psin_server,
1128                                 sizeof (struct sockaddr_in6),0);
1129                 if (rc >= 0)
1130                         connected = 1;
1131         } 
1132
1133         if(!connected) {
1134                 /* save original port so we can retry user specified port  
1135                         later if fall back ports fail this time  */
1136
1137                 orig_port = psin_server->sin6_port;
1138                 /* do not retry on the same port we just failed on */
1139                 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1140                         psin_server->sin6_port = htons(CIFS_PORT);
1141
1142                         rc = (*csocket)->ops->connect(*csocket,
1143                                         (struct sockaddr *) psin_server,
1144                                         sizeof (struct sockaddr_in6),0);
1145                         if (rc >= 0)
1146                                 connected = 1;
1147                 }
1148         }
1149         if (!connected) {
1150                 psin_server->sin6_port = htons(RFC1001_PORT);
1151                 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1152                                          psin_server, sizeof (struct sockaddr_in6),0);
1153                 if (rc >= 0) 
1154                         connected = 1;
1155         }
1156
1157         /* give up here - unless we want to retry on different
1158                 protocol families some day */
1159         if (!connected) {
1160                 if(orig_port)
1161                         psin_server->sin6_port = orig_port;
1162                 cFYI(1,("Error %d connecting to server via ipv6",rc));
1163                 sock_release(*csocket);
1164                 *csocket = NULL;
1165                 return rc;
1166         }
1167         /* Eventually check for other socket options to change from 
1168                 the default. sock_setsockopt not used because it expects 
1169                 user space buffer */
1170         (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1171                 
1172         return rc;
1173 }
1174
1175 int
1176 cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1177            char *mount_data, const char *devname)
1178 {
1179         int rc = 0;
1180         int xid;
1181         int address_type = AF_INET;
1182         struct socket *csocket = NULL;
1183         struct sockaddr_in sin_server;
1184         struct sockaddr_in6 sin_server6;
1185         struct smb_vol volume_info;
1186         struct cifsSesInfo *pSesInfo = NULL;
1187         struct cifsSesInfo *existingCifsSes = NULL;
1188         struct cifsTconInfo *tcon = NULL;
1189         struct TCP_Server_Info *srvTcp = NULL;
1190
1191         xid = GetXid();
1192
1193 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1194         
1195         memset(&volume_info,0,sizeof(struct smb_vol));
1196         if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1197                 if(volume_info.UNC)
1198                         kfree(volume_info.UNC);
1199                 if(volume_info.password)
1200                         kfree(volume_info.password);
1201                 FreeXid(xid);
1202                 return -EINVAL;
1203         }
1204
1205         if (volume_info.username) {
1206                 /* BB fixme parse for domain name here */
1207                 cFYI(1, ("Username: %s ", volume_info.username));
1208
1209         } else {
1210                 cifserror("No username specified ");
1211         /* In userspace mount helper we can get user name from alternate
1212            locations such as env variables and files on disk */
1213                 if(volume_info.UNC)
1214                         kfree(volume_info.UNC);
1215                 if(volume_info.password)
1216                         kfree(volume_info.password);
1217                 FreeXid(xid);
1218                 return -EINVAL;
1219         }
1220
1221         if (volume_info.UNCip && volume_info.UNC) {
1222                 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1223
1224                 if(rc <= 0) {
1225                         /* not ipv4 address, try ipv6 */
1226                         rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); 
1227                         if(rc > 0)
1228                                 address_type = AF_INET6;
1229                 } else {
1230                         address_type = AF_INET;
1231                 }
1232        
1233                 if(rc <= 0) {
1234                         /* we failed translating address */
1235                         if(volume_info.UNC)
1236                                 kfree(volume_info.UNC);
1237                         if(volume_info.password)
1238                                 kfree(volume_info.password);
1239                         FreeXid(xid);
1240                         return -EINVAL;
1241                 }
1242
1243                 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1244                 /* success */
1245                 rc = 0;
1246         } else if (volume_info.UNCip){
1247                 /* BB using ip addr as server name connect to the DFS root below */
1248                 cERROR(1,("Connecting to DFS root not implemented yet"));
1249                 if(volume_info.UNC)
1250                         kfree(volume_info.UNC);
1251                 if(volume_info.password)
1252                         kfree(volume_info.password);
1253                 FreeXid(xid);
1254                 return -EINVAL;
1255         } else /* which servers DFS root would we conect to */ {
1256                 cERROR(1,
1257                        ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified  "));
1258                 if(volume_info.UNC)
1259                         kfree(volume_info.UNC);
1260                 if(volume_info.password)
1261                         kfree(volume_info.password);
1262                 FreeXid(xid);
1263                 return -EINVAL;
1264         }
1265
1266         /* this is needed for ASCII cp to Unicode converts */
1267         if(volume_info.iocharset == NULL) {
1268                 cifs_sb->local_nls = load_nls_default();
1269         /* load_nls_default can not return null */
1270         } else {
1271                 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1272                 if(cifs_sb->local_nls == NULL) {
1273                         cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1274                         if(volume_info.UNC)
1275                                 kfree(volume_info.UNC);
1276                         if(volume_info.password)
1277                                 kfree(volume_info.password);
1278                         FreeXid(xid);
1279                         return -ELIBACC;
1280                 }
1281         }
1282
1283         if(address_type == AF_INET)
1284                 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1285                         NULL /* no ipv6 addr */,
1286                         volume_info.username, &srvTcp);
1287         else if(address_type == AF_INET6)
1288                 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1289                         &sin_server6.sin6_addr,
1290                         volume_info.username, &srvTcp);
1291         else {
1292                 if(volume_info.UNC)
1293                         kfree(volume_info.UNC);
1294                 if(volume_info.password)
1295                         kfree(volume_info.password);
1296                 FreeXid(xid);
1297                 return -EINVAL;
1298         }
1299
1300
1301         if (srvTcp) {
1302                 cFYI(1, ("Existing tcp session with server found "));                
1303         } else {        /* create socket */
1304                 if(volume_info.port)
1305                         sin_server.sin_port = htons(volume_info.port);
1306                 else
1307                         sin_server.sin_port = 0;
1308                 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1309                 if (rc < 0) {
1310                         cERROR(1,
1311                                ("Error connecting to IPv4 socket. Aborting operation"));
1312                         if(csocket != NULL)
1313                                 sock_release(csocket);
1314                         if(volume_info.UNC)
1315                                 kfree(volume_info.UNC);
1316                         if(volume_info.password)
1317                                 kfree(volume_info.password);
1318                         FreeXid(xid);
1319                         return rc;
1320                 }
1321
1322                 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1323                 if (srvTcp == NULL) {
1324                         rc = -ENOMEM;
1325                         sock_release(csocket);
1326                         if(volume_info.UNC)
1327                                 kfree(volume_info.UNC);
1328                         if(volume_info.password)
1329                                 kfree(volume_info.password);
1330                         FreeXid(xid);
1331                         return rc;
1332                 } else {
1333                         memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1334                         memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1335                         atomic_set(&srvTcp->inFlight,0);
1336                         /* BB Add code for ipv6 case too */
1337                         srvTcp->ssocket = csocket;
1338                         srvTcp->protocolType = IPV4;
1339                         init_waitqueue_head(&srvTcp->response_q);
1340                         init_waitqueue_head(&srvTcp->request_q);
1341                         INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1342                         /* at this point we are the only ones with the pointer
1343                         to the struct since the kernel thread not created yet
1344                         so no need to spinlock this init of tcpStatus */
1345                         srvTcp->tcpStatus = CifsNew;
1346                         init_MUTEX(&srvTcp->tcpSem);
1347                         rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1348                                       CLONE_FS | CLONE_FILES | CLONE_VM);
1349                         if(rc < 0) {
1350                                 rc = -ENOMEM;
1351                                 sock_release(csocket);
1352                                 if(volume_info.UNC)
1353                                         kfree(volume_info.UNC);
1354                                 if(volume_info.password)
1355                                         kfree(volume_info.password);
1356                                 FreeXid(xid);
1357                                 return rc;
1358                         } else
1359                                 rc = 0;
1360                         memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
1361                         srvTcp->sequence_number = 0;
1362                 }
1363         }
1364
1365         if (existingCifsSes) {
1366                 pSesInfo = existingCifsSes;
1367                 cFYI(1, ("Existing smb sess found "));
1368                 if(volume_info.password)
1369                         kfree(volume_info.password);
1370                 /* volume_info.UNC freed at end of function */
1371         } else if (!rc) {
1372                 cFYI(1, ("Existing smb sess not found "));
1373                 pSesInfo = sesInfoAlloc();
1374                 if (pSesInfo == NULL)
1375                         rc = -ENOMEM;
1376                 else {
1377                         pSesInfo->server = srvTcp;
1378                         sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1379                                 NIPQUAD(sin_server.sin_addr.s_addr));
1380                 }
1381
1382                 if (!rc){
1383                         /* volume_info.password freed at unmount */   
1384                         if (volume_info.password)
1385                                 pSesInfo->password = volume_info.password;
1386                         if (volume_info.username)
1387                                 strncpy(pSesInfo->userName,
1388                                         volume_info.username,MAX_USERNAME_SIZE);
1389                         if (volume_info.domainname)
1390                                 strncpy(pSesInfo->domainName,
1391                                         volume_info.domainname,MAX_USERNAME_SIZE);
1392                         pSesInfo->linux_uid = volume_info.linux_uid;
1393                         down(&pSesInfo->sesSem);
1394                         rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1395                         up(&pSesInfo->sesSem);
1396                         if(!rc)
1397                                 atomic_inc(&srvTcp->socketUseCount);
1398                 } else
1399                         if(volume_info.password)
1400                                 kfree(volume_info.password);
1401         }
1402     
1403         /* search for existing tcon to this server share */
1404         if (!rc) {
1405                 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1406                         cifs_sb->rsize = volume_info.rsize;
1407                 else
1408                         cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1409                 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1410                         cifs_sb->wsize = volume_info.wsize;
1411                 else
1412                         cifs_sb->wsize = CIFSMaxBufSize; /* default */
1413                 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1414                         cifs_sb->rsize = PAGE_CACHE_SIZE;
1415                         cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1416                 }
1417                 cifs_sb->mnt_uid = volume_info.linux_uid;
1418                 cifs_sb->mnt_gid = volume_info.linux_gid;
1419                 cifs_sb->mnt_file_mode = volume_info.file_mode;
1420                 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1421                 cFYI(1,("file mode: 0x%x  dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1422
1423                 if(volume_info.noperm)
1424                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1425                 if(volume_info.setuids)
1426                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1427                 if(volume_info.server_ino)
1428                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
1429                 if(volume_info.remap)
1430                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
1431                 if(volume_info.no_xattr)
1432                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1433                 if(volume_info.direct_io) {
1434                         cERROR(1,("mounting share using direct i/o"));
1435                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1436                 }
1437
1438                 tcon =
1439                     find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1440                              volume_info.username);
1441                 if (tcon) {
1442                         cFYI(1, ("Found match on UNC path "));
1443                         /* we can have only one retry value for a connection
1444                            to a share so for resources mounted more than once
1445                            to the same server share the last value passed in 
1446                            for the retry flag is used */
1447                         tcon->retry = volume_info.retry;
1448                 } else {
1449                         tcon = tconInfoAlloc();
1450                         if (tcon == NULL)
1451                                 rc = -ENOMEM;
1452                         else {
1453                                 /* check for null share name ie connect to dfs root */
1454
1455                                 /* BB check if this works for exactly length three strings */
1456                                 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1457                                     && (strchr(volume_info.UNC + 3, '/') ==
1458                                         NULL)) {
1459                                         rc = connect_to_dfs_path(xid,
1460                                                                  pSesInfo,
1461                                                                  "",
1462                                                                  cifs_sb->
1463                                                                  local_nls);
1464                                         if(volume_info.UNC)
1465                                                 kfree(volume_info.UNC);
1466                                         FreeXid(xid);
1467                                         return -ENODEV;
1468                                 } else {
1469                                         rc = CIFSTCon(xid, pSesInfo, 
1470                                                 volume_info.UNC,
1471                                                 tcon, cifs_sb->local_nls);
1472                                         cFYI(1, ("CIFS Tcon rc = %d", rc));
1473                                 }
1474                                 if (!rc) {
1475                                         atomic_inc(&pSesInfo->inUse);
1476                                         tcon->retry = volume_info.retry;
1477                                 }
1478                         }
1479                 }
1480         }
1481         if(pSesInfo) {
1482                 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1483                         sb->s_maxbytes = (u64) 1 << 63;
1484                 } else
1485                         sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1486         }
1487
1488         sb->s_time_gran = 100;
1489
1490 /* on error free sesinfo and tcon struct if needed */
1491         if (rc) {
1492                 /* if session setup failed, use count is zero but
1493                 we still need to free cifsd thread */
1494                 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1495                         spin_lock(&GlobalMid_Lock);
1496                         srvTcp->tcpStatus = CifsExiting;
1497                         spin_unlock(&GlobalMid_Lock);
1498                         if(srvTcp->tsk)
1499                                 send_sig(SIGKILL,srvTcp->tsk,1);
1500                 }
1501                  /* If find_unc succeeded then rc == 0 so we can not end */
1502                 if (tcon)  /* up accidently freeing someone elses tcon struct */
1503                         tconInfoFree(tcon);
1504                 if (existingCifsSes == NULL) {
1505                         if (pSesInfo) {
1506                                 if ((pSesInfo->server) && 
1507                                     (pSesInfo->status == CifsGood)) {
1508                                         int temp_rc;
1509                                         temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1510                                         /* if the socketUseCount is now zero */
1511                                         if((temp_rc == -ESHUTDOWN) &&
1512                                            (pSesInfo->server->tsk))
1513                                                 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1514                                 } else
1515                                         cFYI(1, ("No session or bad tcon"));
1516                                 sesInfoFree(pSesInfo);
1517                                 /* pSesInfo = NULL; */
1518                         }
1519                 }
1520         } else {
1521                 atomic_inc(&tcon->useCount);
1522                 cifs_sb->tcon = tcon;
1523                 tcon->ses = pSesInfo;
1524
1525                 /* do not care if following two calls succeed - informational only */
1526                 CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
1527                 CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
1528                 if (tcon->ses->capabilities & CAP_UNIX) {
1529                         if(!CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls)) {
1530                                 if(!volume_info.no_psx_acl) {
1531                                         if(CIFS_UNIX_POSIX_ACL_CAP & 
1532                                            le64_to_cpu(tcon->fsUnixInfo.Capability))
1533                                                 cFYI(1,("server negotiated posix acl support"));
1534                                                 sb->s_flags |= MS_POSIXACL;
1535                                 }
1536                         }
1537                 }
1538         }
1539
1540         /* volume_info.password is freed above when existing session found
1541         (in which case it is not needed anymore) but when new sesion is created
1542         the password ptr is put in the new session structure (in which case the
1543         password will be freed at unmount time) */
1544         if(volume_info.UNC)
1545                 kfree(volume_info.UNC);
1546         FreeXid(xid);
1547         return rc;
1548 }
1549
1550 static int
1551 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1552               char session_key[CIFS_SESSION_KEY_SIZE],
1553               const struct nls_table *nls_codepage)
1554 {
1555         struct smb_hdr *smb_buffer;
1556         struct smb_hdr *smb_buffer_response;
1557         SESSION_SETUP_ANDX *pSMB;
1558         SESSION_SETUP_ANDX *pSMBr;
1559         char *bcc_ptr;
1560         char *user;
1561         char *domain;
1562         int rc = 0;
1563         int remaining_words = 0;
1564         int bytes_returned = 0;
1565         int len;
1566         __u32 capabilities;
1567         __u16 count;
1568
1569         cFYI(1, ("In sesssetup "));
1570         if(ses == NULL)
1571                 return -EINVAL;
1572         user = ses->userName;
1573         domain = ses->domainName;
1574         smb_buffer = cifs_buf_get();
1575         if (smb_buffer == NULL) {
1576                 return -ENOMEM;
1577         }
1578         smb_buffer_response = smb_buffer;
1579         pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1580
1581         /* send SMBsessionSetup here */
1582         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1583                         NULL /* no tCon exists yet */ , 13 /* wct */ );
1584
1585         pSMB->req_no_secext.AndXCommand = 0xFF;
1586         pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1587         pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1588
1589         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1590                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1591
1592         capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1593                 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1594         if (ses->capabilities & CAP_UNICODE) {
1595                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1596                 capabilities |= CAP_UNICODE;
1597         }
1598         if (ses->capabilities & CAP_STATUS32) {
1599                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1600                 capabilities |= CAP_STATUS32;
1601         }
1602         if (ses->capabilities & CAP_DFS) {
1603                 smb_buffer->Flags2 |= SMBFLG2_DFS;
1604                 capabilities |= CAP_DFS;
1605         }
1606         pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1607
1608         pSMB->req_no_secext.CaseInsensitivePasswordLength = 
1609                 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1610
1611         pSMB->req_no_secext.CaseSensitivePasswordLength =
1612             cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1613         bcc_ptr = pByteArea(smb_buffer);
1614         memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1615         bcc_ptr += CIFS_SESSION_KEY_SIZE;
1616         memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1617         bcc_ptr += CIFS_SESSION_KEY_SIZE;
1618
1619         if (ses->capabilities & CAP_UNICODE) {
1620                 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1621                         *bcc_ptr = 0;
1622                         bcc_ptr++;
1623                 }
1624                 if(user == NULL)
1625                         bytes_returned = 0; /* skill null user */
1626                 else
1627                         bytes_returned =
1628                                 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1629                                         nls_codepage);
1630                 /* convert number of 16 bit words to bytes */
1631                 bcc_ptr += 2 * bytes_returned;
1632                 bcc_ptr += 2;   /* trailing null */
1633                 if (domain == NULL)
1634                         bytes_returned =
1635                             cifs_strtoUCS((wchar_t *) bcc_ptr,
1636                                           "CIFS_LINUX_DOM", 32, nls_codepage);
1637                 else
1638                         bytes_returned =
1639                             cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1640                                           nls_codepage);
1641                 bcc_ptr += 2 * bytes_returned;
1642                 bcc_ptr += 2;
1643                 bytes_returned =
1644                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1645                                   32, nls_codepage);
1646                 bcc_ptr += 2 * bytes_returned;
1647                 bytes_returned =
1648                     cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1649                                   32, nls_codepage);
1650                 bcc_ptr += 2 * bytes_returned;
1651                 bcc_ptr += 2;
1652                 bytes_returned =
1653                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1654                                   64, nls_codepage);
1655                 bcc_ptr += 2 * bytes_returned;
1656                 bcc_ptr += 2;
1657         } else {
1658                 if(user != NULL) {                
1659                     strncpy(bcc_ptr, user, 200);
1660                     bcc_ptr += strnlen(user, 200);
1661                 }
1662                 *bcc_ptr = 0;
1663                 bcc_ptr++;
1664                 if (domain == NULL) {
1665                         strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1666                         bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1667                 } else {
1668                         strncpy(bcc_ptr, domain, 64);
1669                         bcc_ptr += strnlen(domain, 64);
1670                         *bcc_ptr = 0;
1671                         bcc_ptr++;
1672                 }
1673                 strcpy(bcc_ptr, "Linux version ");
1674                 bcc_ptr += strlen("Linux version ");
1675                 strcpy(bcc_ptr, system_utsname.release);
1676                 bcc_ptr += strlen(system_utsname.release) + 1;
1677                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1678                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1679         }
1680         count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1681         smb_buffer->smb_buf_length += count;
1682         pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
1683
1684         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1685                          &bytes_returned, 1);
1686         if (rc) {
1687 /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1688         } else if ((smb_buffer_response->WordCount == 3)
1689                    || (smb_buffer_response->WordCount == 4)) {
1690                 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1691                 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1692                 if (action & GUEST_LOGIN)
1693                         cFYI(1, (" Guest login"));      /* do we want to mark SesInfo struct ? */
1694                 ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
1695                 cFYI(1, ("UID = %d ", ses->Suid));
1696          /* response can have either 3 or 4 word count - Samba sends 3 */
1697                 bcc_ptr = pByteArea(smb_buffer_response);       
1698                 if ((pSMBr->resp.hdr.WordCount == 3)
1699                     || ((pSMBr->resp.hdr.WordCount == 4)
1700                         && (blob_len < pSMBr->resp.ByteCount))) {
1701                         if (pSMBr->resp.hdr.WordCount == 4)
1702                                 bcc_ptr += blob_len;
1703
1704                         if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1705                                 if ((long) (bcc_ptr) % 2) {
1706                                         remaining_words =
1707                                             (BCC(smb_buffer_response) - 1) /2;
1708                                         bcc_ptr++;      /* Unicode strings must be word aligned */
1709                                 } else {
1710                                         remaining_words =
1711                                                 BCC(smb_buffer_response) / 2;
1712                                 }
1713                                 len =
1714                                     UniStrnlen((wchar_t *) bcc_ptr,
1715                                                remaining_words - 1);
1716 /* We look for obvious messed up bcc or strings in response so we do not go off
1717    the end since (at least) WIN2K and Windows XP have a major bug in not null
1718    terminating last Unicode string in response  */
1719                                 ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
1720                                 cifs_strfromUCS_le(ses->serverOS,
1721                                            (wchar_t *)bcc_ptr, len,nls_codepage);
1722                                 bcc_ptr += 2 * (len + 1);
1723                                 remaining_words -= len + 1;
1724                                 ses->serverOS[2 * len] = 0;
1725                                 ses->serverOS[1 + (2 * len)] = 0;
1726                                 if (remaining_words > 0) {
1727                                         len = UniStrnlen((wchar_t *)bcc_ptr,
1728                                                          remaining_words-1);
1729                                         ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL);
1730                                         cifs_strfromUCS_le(ses->serverNOS,
1731                                                            (wchar_t *)bcc_ptr,len,nls_codepage);
1732                                         bcc_ptr += 2 * (len + 1);
1733                                         ses->serverNOS[2 * len] = 0;
1734                                         ses->serverNOS[1 + (2 * len)] = 0;
1735                                         if(strncmp(ses->serverNOS,
1736                                                 "NT LAN Manager 4",16) == 0) {
1737                                                 cFYI(1,("NT4 server"));
1738                                                 ses->flags |= CIFS_SES_NT4;
1739                                         }
1740                                         remaining_words -= len + 1;
1741                                         if (remaining_words > 0) {
1742                                                 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
1743           /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1744                                                 ses->serverDomain =
1745                                                     cifs_kcalloc(2*(len+1),GFP_KERNEL);
1746                                                 cifs_strfromUCS_le(ses->serverDomain,
1747                                                      (wchar_t *)bcc_ptr,len,nls_codepage);
1748                                                 bcc_ptr += 2 * (len + 1);
1749                                                 ses->serverDomain[2*len] = 0;
1750                                                 ses->serverDomain[1+(2*len)] = 0;
1751                                         } /* else no more room so create dummy domain string */
1752                                         else
1753                                                 ses->serverDomain =
1754                                                     cifs_kcalloc(2,
1755                                                             GFP_KERNEL);
1756                                 } else {        /* no room so create dummy domain and NOS string */
1757                                         ses->serverDomain =
1758                                             cifs_kcalloc(2, GFP_KERNEL);
1759                                         ses->serverNOS =
1760                                             cifs_kcalloc(2, GFP_KERNEL);
1761                                 }
1762                         } else {        /* ASCII */
1763                                 len = strnlen(bcc_ptr, 1024);
1764                                 if (((long) bcc_ptr + len) - (long)
1765                                     pByteArea(smb_buffer_response)
1766                                             <= BCC(smb_buffer_response)) {
1767                                         ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
1768                                         strncpy(ses->serverOS,bcc_ptr, len);
1769
1770                                         bcc_ptr += len;
1771                                         bcc_ptr[0] = 0; /* null terminate the string */
1772                                         bcc_ptr++;
1773
1774                                         len = strnlen(bcc_ptr, 1024);
1775                                         ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
1776                                         strncpy(ses->serverNOS, bcc_ptr, len);
1777                                         bcc_ptr += len;
1778                                         bcc_ptr[0] = 0;
1779                                         bcc_ptr++;
1780
1781                                         len = strnlen(bcc_ptr, 1024);
1782                                         ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL);
1783                                         strncpy(ses->serverDomain, bcc_ptr, len);
1784                                         bcc_ptr += len;
1785                                         bcc_ptr[0] = 0;
1786                                         bcc_ptr++;
1787                                 } else
1788                                         cFYI(1,
1789                                              ("Variable field of length %d extends beyond end of smb ",
1790                                               len));
1791                         }
1792                 } else {
1793                         cERROR(1,
1794                                (" Security Blob Length extends beyond end of SMB"));
1795                 }
1796         } else {
1797                 cERROR(1,
1798                        (" Invalid Word count %d: ",
1799                         smb_buffer_response->WordCount));
1800                 rc = -EIO;
1801         }
1802         
1803         if (smb_buffer)
1804                 cifs_buf_release(smb_buffer);
1805
1806         return rc;
1807 }
1808
1809 static int
1810 CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1811                 char *SecurityBlob,int SecurityBlobLength,
1812                 const struct nls_table *nls_codepage)
1813 {
1814         struct smb_hdr *smb_buffer;
1815         struct smb_hdr *smb_buffer_response;
1816         SESSION_SETUP_ANDX *pSMB;
1817         SESSION_SETUP_ANDX *pSMBr;
1818         char *bcc_ptr;
1819         char *user;
1820         char *domain;
1821         int rc = 0;
1822         int remaining_words = 0;
1823         int bytes_returned = 0;
1824         int len;
1825         __u32 capabilities;
1826         __u16 count;
1827
1828         cFYI(1, ("In spnego sesssetup "));
1829         if(ses == NULL)
1830                 return -EINVAL;
1831         user = ses->userName;
1832         domain = ses->domainName;
1833
1834         smb_buffer = cifs_buf_get();
1835         if (smb_buffer == NULL) {
1836                 return -ENOMEM;
1837         }
1838         smb_buffer_response = smb_buffer;
1839         pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1840
1841         /* send SMBsessionSetup here */
1842         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1843                         NULL /* no tCon exists yet */ , 12 /* wct */ );
1844         pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
1845         pSMB->req.AndXCommand = 0xFF;
1846         pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1847         pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1848
1849         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1850                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1851
1852         capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1853             CAP_EXTENDED_SECURITY;
1854         if (ses->capabilities & CAP_UNICODE) {
1855                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1856                 capabilities |= CAP_UNICODE;
1857         }
1858         if (ses->capabilities & CAP_STATUS32) {
1859                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1860                 capabilities |= CAP_STATUS32;
1861         }
1862         if (ses->capabilities & CAP_DFS) {
1863                 smb_buffer->Flags2 |= SMBFLG2_DFS;
1864                 capabilities |= CAP_DFS;
1865         }
1866         pSMB->req.Capabilities = cpu_to_le32(capabilities);
1867
1868         pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
1869         bcc_ptr = pByteArea(smb_buffer);
1870         memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
1871         bcc_ptr += SecurityBlobLength;
1872
1873         if (ses->capabilities & CAP_UNICODE) {
1874                 if ((long) bcc_ptr % 2) {       /* must be word aligned for Unicode strings */
1875                         *bcc_ptr = 0;
1876                         bcc_ptr++;
1877                 }
1878                 bytes_returned =
1879                     cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
1880                 bcc_ptr += 2 * bytes_returned;  /* convert num of 16 bit words to bytes */
1881                 bcc_ptr += 2;   /* trailing null */
1882                 if (domain == NULL)
1883                         bytes_returned =
1884                             cifs_strtoUCS((wchar_t *) bcc_ptr,
1885                                           "CIFS_LINUX_DOM", 32, nls_codepage);
1886                 else
1887                         bytes_returned =
1888                             cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1889                                           nls_codepage);
1890                 bcc_ptr += 2 * bytes_returned;
1891                 bcc_ptr += 2;
1892                 bytes_returned =
1893                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1894                                   32, nls_codepage);
1895                 bcc_ptr += 2 * bytes_returned;
1896                 bytes_returned =
1897                     cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
1898                                   nls_codepage);
1899                 bcc_ptr += 2 * bytes_returned;
1900                 bcc_ptr += 2;
1901                 bytes_returned =
1902                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1903                                   64, nls_codepage);
1904                 bcc_ptr += 2 * bytes_returned;
1905                 bcc_ptr += 2;
1906         } else {
1907                 strncpy(bcc_ptr, user, 200);
1908                 bcc_ptr += strnlen(user, 200);
1909                 *bcc_ptr = 0;
1910                 bcc_ptr++;
1911                 if (domain == NULL) {
1912                         strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1913                         bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1914                 } else {
1915                         strncpy(bcc_ptr, domain, 64);
1916                         bcc_ptr += strnlen(domain, 64);
1917                         *bcc_ptr = 0;
1918                         bcc_ptr++;
1919                 }
1920                 strcpy(bcc_ptr, "Linux version ");
1921                 bcc_ptr += strlen("Linux version ");
1922                 strcpy(bcc_ptr, system_utsname.release);
1923                 bcc_ptr += strlen(system_utsname.release) + 1;
1924                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1925                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1926         }
1927         count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1928         smb_buffer->smb_buf_length += count;
1929         pSMB->req.ByteCount = cpu_to_le16(count);
1930
1931         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1932                          &bytes_returned, 1);
1933         if (rc) {
1934 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
1935         } else if ((smb_buffer_response->WordCount == 3)
1936                    || (smb_buffer_response->WordCount == 4)) {
1937                 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1938                 __u16 blob_len =
1939                     le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1940                 if (action & GUEST_LOGIN)
1941                         cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
1942                 if (ses) {
1943                         ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
1944                         cFYI(1, ("UID = %d ", ses->Suid));
1945                         bcc_ptr = pByteArea(smb_buffer_response);       /* response can have either 3 or 4 word count - Samba sends 3 */
1946
1947                         /* BB Fix below to make endian neutral !! */
1948
1949                         if ((pSMBr->resp.hdr.WordCount == 3)
1950                             || ((pSMBr->resp.hdr.WordCount == 4)
1951                                 && (blob_len <
1952                                     pSMBr->resp.ByteCount))) {
1953                                 if (pSMBr->resp.hdr.WordCount == 4) {
1954                                         bcc_ptr +=
1955                                             blob_len;
1956                                         cFYI(1,
1957                                              ("Security Blob Length %d ",
1958                                               blob_len));
1959                                 }
1960
1961                                 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1962                                         if ((long) (bcc_ptr) % 2) {
1963                                                 remaining_words =
1964                                                     (BCC(smb_buffer_response)
1965                                                      - 1) / 2;
1966                                                 bcc_ptr++;      /* Unicode strings must be word aligned */
1967                                         } else {
1968                                                 remaining_words =
1969                                                     BCC
1970                                                     (smb_buffer_response) / 2;
1971                                         }
1972                                         len =
1973                                             UniStrnlen((wchar_t *) bcc_ptr,
1974                                                        remaining_words - 1);
1975 /* We look for obvious messed up bcc or strings in response so we do not go off
1976    the end since (at least) WIN2K and Windows XP have a major bug in not null
1977    terminating last Unicode string in response  */
1978                                         ses->serverOS =
1979                                             cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
1980                                         cifs_strfromUCS_le(ses->serverOS,
1981                                                            (wchar_t *)
1982                                                            bcc_ptr, len,
1983                                                            nls_codepage);
1984                                         bcc_ptr += 2 * (len + 1);
1985                                         remaining_words -= len + 1;
1986                                         ses->serverOS[2 * len] = 0;
1987                                         ses->serverOS[1 + (2 * len)] = 0;
1988                                         if (remaining_words > 0) {
1989                                                 len = UniStrnlen((wchar_t *)bcc_ptr,
1990                                                                  remaining_words
1991                                                                  - 1);
1992                                                 ses->serverNOS =
1993                                                     cifs_kcalloc(2 * (len + 1),
1994                                                             GFP_KERNEL);
1995                                                 cifs_strfromUCS_le(ses->serverNOS,
1996                                                                    (wchar_t *)bcc_ptr,
1997                                                                    len,
1998                                                                    nls_codepage);
1999                                                 bcc_ptr += 2 * (len + 1);
2000                                                 ses->serverNOS[2 * len] = 0;
2001                                                 ses->serverNOS[1 + (2 * len)] = 0;
2002                                                 remaining_words -= len + 1;
2003                                                 if (remaining_words > 0) {
2004                                                         len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
2005                             /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2006                                                         ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL);
2007                                                         cifs_strfromUCS_le(ses->serverDomain,
2008                                                              (wchar_t *)bcc_ptr, 
2009                                  len,
2010                                                              nls_codepage);
2011                                                         bcc_ptr += 2*(len+1);
2012                                                         ses->serverDomain[2*len] = 0;
2013                                                         ses->serverDomain[1+(2*len)] = 0;
2014                                                 } /* else no more room so create dummy domain string */
2015                                                 else
2016                                                         ses->serverDomain =
2017                                                             cifs_kcalloc(2,GFP_KERNEL);
2018                                         } else {        /* no room so create dummy domain and NOS string */
2019                                                 ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
2020                                                 ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
2021                                         }
2022                                 } else {        /* ASCII */
2023
2024                                         len = strnlen(bcc_ptr, 1024);
2025                                         if (((long) bcc_ptr + len) - (long)
2026                                             pByteArea(smb_buffer_response)
2027                                             <= BCC(smb_buffer_response)) {
2028                                                 ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL);
2029                                                 strncpy(ses->serverOS, bcc_ptr, len);
2030
2031                                                 bcc_ptr += len;
2032                                                 bcc_ptr[0] = 0; /* null terminate the string */
2033                                                 bcc_ptr++;
2034
2035                                                 len = strnlen(bcc_ptr, 1024);
2036                                                 ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
2037                                                 strncpy(ses->serverNOS, bcc_ptr, len);
2038                                                 bcc_ptr += len;
2039                                                 bcc_ptr[0] = 0;
2040                                                 bcc_ptr++;
2041
2042                                                 len = strnlen(bcc_ptr, 1024);
2043                                                 ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL);
2044                                                 strncpy(ses->serverDomain, bcc_ptr, len);
2045                                                 bcc_ptr += len;
2046                                                 bcc_ptr[0] = 0;
2047                                                 bcc_ptr++;
2048                                         } else
2049                                                 cFYI(1,
2050                                                      ("Variable field of length %d extends beyond end of smb ",
2051                                                       len));
2052                                 }
2053                         } else {
2054                                 cERROR(1,
2055                                        (" Security Blob Length extends beyond end of SMB"));
2056                         }
2057                 } else {
2058                         cERROR(1, ("No session structure passed in."));
2059                 }
2060         } else {
2061                 cERROR(1,
2062                        (" Invalid Word count %d: ",
2063                         smb_buffer_response->WordCount));
2064                 rc = -EIO;
2065         }
2066
2067         if (smb_buffer)
2068                 cifs_buf_release(smb_buffer);
2069
2070         return rc;
2071 }
2072
2073 static int
2074 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2075                               struct cifsSesInfo *ses, int * pNTLMv2_flag,
2076                               const struct nls_table *nls_codepage)
2077 {
2078         struct smb_hdr *smb_buffer;
2079         struct smb_hdr *smb_buffer_response;
2080         SESSION_SETUP_ANDX *pSMB;
2081         SESSION_SETUP_ANDX *pSMBr;
2082         char *bcc_ptr;
2083         char *domain;
2084         int rc = 0;
2085         int remaining_words = 0;
2086         int bytes_returned = 0;
2087         int len;
2088         int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2089         PNEGOTIATE_MESSAGE SecurityBlob;
2090         PCHALLENGE_MESSAGE SecurityBlob2;
2091         __u32 negotiate_flags, capabilities;
2092         __u16 count;
2093
2094         cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2095         if(ses == NULL)
2096                 return -EINVAL;
2097         domain = ses->domainName;
2098         *pNTLMv2_flag = FALSE;
2099         smb_buffer = cifs_buf_get();
2100         if (smb_buffer == NULL) {
2101                 return -ENOMEM;
2102         }
2103         smb_buffer_response = smb_buffer;
2104         pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2105         pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2106
2107         /* send SMBsessionSetup here */
2108         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2109                         NULL /* no tCon exists yet */ , 12 /* wct */ );
2110         pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2111         pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2112
2113         pSMB->req.AndXCommand = 0xFF;
2114         pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2115         pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2116
2117         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2118                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2119
2120         capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2121             CAP_EXTENDED_SECURITY;
2122         if (ses->capabilities & CAP_UNICODE) {
2123                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2124                 capabilities |= CAP_UNICODE;
2125         }
2126         if (ses->capabilities & CAP_STATUS32) {
2127                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2128                 capabilities |= CAP_STATUS32;
2129         }
2130         if (ses->capabilities & CAP_DFS) {
2131                 smb_buffer->Flags2 |= SMBFLG2_DFS;
2132                 capabilities |= CAP_DFS;
2133         }
2134         pSMB->req.Capabilities = cpu_to_le32(capabilities);
2135
2136         bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2137         SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2138         strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2139         SecurityBlob->MessageType = NtLmNegotiate;
2140         negotiate_flags =
2141             NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2142             NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2143             /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2144         if(sign_CIFS_PDUs)
2145                 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2146         if(ntlmv2_support)
2147                 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2148         /* setup pointers to domain name and workstation name */
2149         bcc_ptr += SecurityBlobLength;
2150
2151         SecurityBlob->WorkstationName.Buffer = 0;
2152         SecurityBlob->WorkstationName.Length = 0;
2153         SecurityBlob->WorkstationName.MaximumLength = 0;
2154
2155         if (domain == NULL) {
2156                 SecurityBlob->DomainName.Buffer = 0;
2157                 SecurityBlob->DomainName.Length = 0;
2158                 SecurityBlob->DomainName.MaximumLength = 0;
2159         } else {
2160                 __u16 len;
2161                 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2162                 strncpy(bcc_ptr, domain, 63);
2163                 len = strnlen(domain, 64);
2164                 SecurityBlob->DomainName.MaximumLength =
2165                     cpu_to_le16(len);
2166                 SecurityBlob->DomainName.Buffer =
2167                     cpu_to_le32((long) &SecurityBlob->
2168                                 DomainString -
2169                                 (long) &SecurityBlob->Signature);
2170                 bcc_ptr += len;
2171                 SecurityBlobLength += len;
2172                 SecurityBlob->DomainName.Length =
2173                     cpu_to_le16(len);
2174         }
2175         if (ses->capabilities & CAP_UNICODE) {
2176                 if ((long) bcc_ptr % 2) {
2177                         *bcc_ptr = 0;
2178                         bcc_ptr++;
2179                 }
2180
2181                 bytes_returned =
2182                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2183                                   32, nls_codepage);
2184                 bcc_ptr += 2 * bytes_returned;
2185                 bytes_returned =
2186                     cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2187                                   nls_codepage);
2188                 bcc_ptr += 2 * bytes_returned;
2189                 bcc_ptr += 2;   /* null terminate Linux version */
2190                 bytes_returned =
2191                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2192                                   64, nls_codepage);
2193                 bcc_ptr += 2 * bytes_returned;
2194                 *(bcc_ptr + 1) = 0;
2195                 *(bcc_ptr + 2) = 0;
2196                 bcc_ptr += 2;   /* null terminate network opsys string */
2197                 *(bcc_ptr + 1) = 0;
2198                 *(bcc_ptr + 2) = 0;
2199                 bcc_ptr += 2;   /* null domain */
2200         } else {                /* ASCII */
2201                 strcpy(bcc_ptr, "Linux version ");
2202                 bcc_ptr += strlen("Linux version ");
2203                 strcpy(bcc_ptr, system_utsname.release);
2204                 bcc_ptr += strlen(system_utsname.release) + 1;
2205                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2206                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2207                 bcc_ptr++;      /* empty domain field */
2208                 *bcc_ptr = 0;
2209         }
2210         SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2211         pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2212         count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2213         smb_buffer->smb_buf_length += count;
2214         pSMB->req.ByteCount = cpu_to_le16(count);
2215
2216         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2217                          &bytes_returned, 1);
2218
2219         if (smb_buffer_response->Status.CifsError ==
2220             cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2221                 rc = 0;
2222
2223         if (rc) {
2224 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
2225         } else if ((smb_buffer_response->WordCount == 3)
2226                    || (smb_buffer_response->WordCount == 4)) {
2227                 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2228                 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2229
2230                 if (action & GUEST_LOGIN)
2231                         cFYI(1, (" Guest login"));      
2232         /* Do we want to set anything in SesInfo struct when guest login? */
2233
2234                 bcc_ptr = pByteArea(smb_buffer_response);       
2235         /* response can have either 3 or 4 word count - Samba sends 3 */
2236
2237                 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2238                 if (SecurityBlob2->MessageType != NtLmChallenge) {
2239                         cFYI(1,
2240                              ("Unexpected NTLMSSP message type received %d",
2241                               SecurityBlob2->MessageType));
2242                 } else if (ses) {
2243                         ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ 
2244                         cFYI(1, ("UID = %d ", ses->Suid));
2245                         if ((pSMBr->resp.hdr.WordCount == 3)
2246                             || ((pSMBr->resp.hdr.WordCount == 4)
2247                                 && (blob_len <
2248                                     pSMBr->resp.ByteCount))) {
2249
2250                                 if (pSMBr->resp.hdr.WordCount == 4) {
2251                                         bcc_ptr += blob_len;
2252                                         cFYI(1,
2253                                              ("Security Blob Length %d ",
2254                                               blob_len));
2255                                 }
2256
2257                                 cFYI(1, ("NTLMSSP Challenge rcvd "));
2258
2259                                 memcpy(ses->server->cryptKey,
2260                                        SecurityBlob2->Challenge,
2261                                        CIFS_CRYPTO_KEY_SIZE);
2262                                 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2263                                         *pNTLMv2_flag = TRUE;
2264
2265                                 if((SecurityBlob2->NegotiateFlags & 
2266                                         cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) 
2267                                         || (sign_CIFS_PDUs > 1))
2268                                                 ses->server->secMode |= 
2269                                                         SECMODE_SIGN_REQUIRED;  
2270                                 if ((SecurityBlob2->NegotiateFlags & 
2271                                         cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2272                                                 ses->server->secMode |= 
2273                                                         SECMODE_SIGN_ENABLED;
2274
2275                                 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2276                                         if ((long) (bcc_ptr) % 2) {
2277                                                 remaining_words =
2278                                                     (BCC(smb_buffer_response)
2279                                                      - 1) / 2;
2280                                                 bcc_ptr++;      /* Unicode strings must be word aligned */
2281                                         } else {
2282                                                 remaining_words =
2283                                                     BCC
2284                                                     (smb_buffer_response) / 2;
2285                                         }
2286                                         len =
2287                                             UniStrnlen((wchar_t *) bcc_ptr,
2288                                                        remaining_words - 1);
2289 /* We look for obvious messed up bcc or strings in response so we do not go off
2290    the end since (at least) WIN2K and Windows XP have a major bug in not null
2291    terminating last Unicode string in response  */
2292                                         ses->serverOS =
2293                                             cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
2294                                         cifs_strfromUCS_le(ses->serverOS,
2295                                                            (wchar_t *)
2296                                                            bcc_ptr, len,
2297                                                            nls_codepage);
2298                                         bcc_ptr += 2 * (len + 1);
2299                                         remaining_words -= len + 1;
2300                                         ses->serverOS[2 * len] = 0;
2301                                         ses->serverOS[1 + (2 * len)] = 0;
2302                                         if (remaining_words > 0) {
2303                                                 len = UniStrnlen((wchar_t *)
2304                                                                  bcc_ptr,
2305                                                                  remaining_words
2306                                                                  - 1);
2307                                                 ses->serverNOS =
2308                                                     cifs_kcalloc(2 * (len + 1),
2309                                                             GFP_KERNEL);
2310                                                 cifs_strfromUCS_le(ses->
2311                                                                    serverNOS,
2312                                                                    (wchar_t *)
2313                                                                    bcc_ptr,
2314                                                                    len,
2315                                                                    nls_codepage);
2316                                                 bcc_ptr += 2 * (len + 1);
2317                                                 ses->serverNOS[2 * len] = 0;
2318                                                 ses->serverNOS[1 +
2319                                                                (2 * len)] = 0;
2320                                                 remaining_words -= len + 1;
2321                                                 if (remaining_words > 0) {
2322                                                         len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
2323            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2324                                                         ses->serverDomain =
2325                                                             cifs_kcalloc(2 *
2326                                                                     (len +
2327                                                                      1),
2328                                                                     GFP_KERNEL);
2329                                                         cifs_strfromUCS_le
2330                                                             (ses->
2331                                                              serverDomain,
2332                                                              (wchar_t *)
2333                                                              bcc_ptr, len,
2334                                                              nls_codepage);
2335                                                         bcc_ptr +=
2336                                                             2 * (len + 1);
2337                                                         ses->
2338                                                             serverDomain[2
2339                                                                          * len]
2340                                                             = 0;
2341                                                         ses->
2342                                                             serverDomain[1
2343                                                                          +
2344                                                                          (2
2345                                                                           *
2346                                                                           len)]
2347                                                             = 0;
2348                                                 } /* else no more room so create dummy domain string */
2349                                                 else
2350                                                         ses->serverDomain =
2351                                                             cifs_kcalloc(2,
2352                                                                     GFP_KERNEL);
2353                                         } else {        /* no room so create dummy domain and NOS string */
2354                                                 ses->serverDomain =
2355                                                     cifs_kcalloc(2, GFP_KERNEL);
2356                                                 ses->serverNOS =
2357                                                     cifs_kcalloc(2, GFP_KERNEL);
2358                                         }
2359                                 } else {        /* ASCII */
2360                                         len = strnlen(bcc_ptr, 1024);
2361                                         if (((long) bcc_ptr + len) - (long)
2362                                             pByteArea(smb_buffer_response)
2363                                             <= BCC(smb_buffer_response)) {
2364                                                 ses->serverOS =
2365                                                     cifs_kcalloc(len + 1,
2366                                                             GFP_KERNEL);
2367                                                 strncpy(ses->serverOS,
2368                                                         bcc_ptr, len);
2369
2370                                                 bcc_ptr += len;
2371                                                 bcc_ptr[0] = 0; /* null terminate string */
2372                                                 bcc_ptr++;
2373
2374                                                 len = strnlen(bcc_ptr, 1024);
2375                                                 ses->serverNOS =
2376                                                     cifs_kcalloc(len + 1,
2377                                                             GFP_KERNEL);
2378                                                 strncpy(ses->serverNOS, bcc_ptr, len);
2379                                                 bcc_ptr += len;
2380                                                 bcc_ptr[0] = 0;
2381                                                 bcc_ptr++;
2382
2383                                                 len = strnlen(bcc_ptr, 1024);
2384                                                 ses->serverDomain =
2385                                                     cifs_kcalloc(len + 1,
2386                                                             GFP_KERNEL);
2387                                                 strncpy(ses->serverDomain, bcc_ptr, len);       
2388                                                 bcc_ptr += len;
2389                                                 bcc_ptr[0] = 0;
2390                                                 bcc_ptr++;
2391                                         } else
2392                                                 cFYI(1,
2393                                                      ("Variable field of length %d extends beyond end of smb ",
2394                                                       len));
2395                                 }
2396                         } else {
2397                                 cERROR(1,
2398                                        (" Security Blob Length extends beyond end of SMB"));
2399                         }
2400                 } else {
2401                         cERROR(1, ("No session structure passed in."));
2402                 }
2403         } else {
2404                 cERROR(1,
2405                        (" Invalid Word count %d: ",
2406                         smb_buffer_response->WordCount));
2407                 rc = -EIO;
2408         }
2409
2410         if (smb_buffer)
2411                 cifs_buf_release(smb_buffer);
2412
2413         return rc;
2414 }
2415 static int
2416 CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2417                 char *ntlm_session_key, int ntlmv2_flag,
2418                 const struct nls_table *nls_codepage)
2419 {
2420         struct smb_hdr *smb_buffer;
2421         struct smb_hdr *smb_buffer_response;
2422         SESSION_SETUP_ANDX *pSMB;
2423         SESSION_SETUP_ANDX *pSMBr;
2424         char *bcc_ptr;
2425         char *user;
2426         char *domain;
2427         int rc = 0;
2428         int remaining_words = 0;
2429         int bytes_returned = 0;
2430         int len;
2431         int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2432         PAUTHENTICATE_MESSAGE SecurityBlob;
2433         __u32 negotiate_flags, capabilities;
2434         __u16 count;
2435
2436         cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2437         if(ses == NULL)
2438                 return -EINVAL;
2439         user = ses->userName;
2440         domain = ses->domainName;
2441         smb_buffer = cifs_buf_get();
2442         if (smb_buffer == NULL) {
2443                 return -ENOMEM;
2444         }
2445         smb_buffer_response = smb_buffer;
2446         pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2447         pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2448
2449         /* send SMBsessionSetup here */
2450         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2451                         NULL /* no tCon exists yet */ , 12 /* wct */ );
2452         pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2453         pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2454         pSMB->req.AndXCommand = 0xFF;
2455         pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2456         pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2457
2458         pSMB->req.hdr.Uid = ses->Suid;
2459
2460         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2461                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2462
2463         capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2464             CAP_EXTENDED_SECURITY;
2465         if (ses->capabilities & CAP_UNICODE) {
2466                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2467                 capabilities |= CAP_UNICODE;
2468         }
2469         if (ses->capabilities & CAP_STATUS32) {
2470                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2471                 capabilities |= CAP_STATUS32;
2472         }
2473         if (ses->capabilities & CAP_DFS) {
2474                 smb_buffer->Flags2 |= SMBFLG2_DFS;
2475                 capabilities |= CAP_DFS;
2476         }
2477         pSMB->req.Capabilities = cpu_to_le32(capabilities);
2478
2479         bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2480         SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2481         strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2482         SecurityBlob->MessageType = NtLmAuthenticate;
2483         bcc_ptr += SecurityBlobLength;
2484         negotiate_flags = 
2485             NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2486             NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2487             0x80000000 | NTLMSSP_NEGOTIATE_128;
2488         if(sign_CIFS_PDUs)
2489                 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2490         if(ntlmv2_flag)
2491                 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2492
2493 /* setup pointers to domain name and workstation name */
2494
2495         SecurityBlob->WorkstationName.Buffer = 0;
2496         SecurityBlob->WorkstationName.Length = 0;
2497         SecurityBlob->WorkstationName.MaximumLength = 0;
2498         SecurityBlob->SessionKey.Length = 0;
2499         SecurityBlob->SessionKey.MaximumLength = 0;
2500         SecurityBlob->SessionKey.Buffer = 0;
2501
2502         SecurityBlob->LmChallengeResponse.Length = 0;
2503         SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2504         SecurityBlob->LmChallengeResponse.Buffer = 0;
2505
2506         SecurityBlob->NtChallengeResponse.Length =
2507             cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2508         SecurityBlob->NtChallengeResponse.MaximumLength =
2509             cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2510         memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2511         SecurityBlob->NtChallengeResponse.Buffer =
2512             cpu_to_le32(SecurityBlobLength);
2513         SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2514         bcc_ptr += CIFS_SESSION_KEY_SIZE;
2515
2516         if (ses->capabilities & CAP_UNICODE) {
2517                 if (domain == NULL) {
2518                         SecurityBlob->DomainName.Buffer = 0;
2519                         SecurityBlob->DomainName.Length = 0;
2520                         SecurityBlob->DomainName.MaximumLength = 0;
2521                 } else {
2522                         __u16 len =
2523                             cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2524                                           nls_codepage);
2525                         len *= 2;
2526                         SecurityBlob->DomainName.MaximumLength =
2527                             cpu_to_le16(len);
2528                         SecurityBlob->DomainName.Buffer =
2529                             cpu_to_le32(SecurityBlobLength);
2530                         bcc_ptr += len;
2531                         SecurityBlobLength += len;
2532                         SecurityBlob->DomainName.Length =
2533                             cpu_to_le16(len);
2534                 }
2535                 if (user == NULL) {
2536                         SecurityBlob->UserName.Buffer = 0;
2537                         SecurityBlob->UserName.Length = 0;
2538                         SecurityBlob->UserName.MaximumLength = 0;
2539                 } else {
2540                         __u16 len =
2541                             cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2542                                           nls_codepage);
2543                         len *= 2;
2544                         SecurityBlob->UserName.MaximumLength =
2545                             cpu_to_le16(len);
2546                         SecurityBlob->UserName.Buffer =
2547                             cpu_to_le32(SecurityBlobLength);
2548                         bcc_ptr += len;
2549                         SecurityBlobLength += len;
2550                         SecurityBlob->UserName.Length =
2551                             cpu_to_le16(len);
2552                 }
2553
2554                 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2555                    SecurityBlob->WorkstationName.Length *= 2;
2556                    SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2557                    SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2558                    bcc_ptr += SecurityBlob->WorkstationName.Length;
2559                    SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2560                    SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length);  */
2561
2562                 if ((long) bcc_ptr % 2) {
2563                         *bcc_ptr = 0;
2564                         bcc_ptr++;
2565                 }
2566                 bytes_returned =
2567                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2568                                   32, nls_codepage);
2569                 bcc_ptr += 2 * bytes_returned;
2570                 bytes_returned =
2571                     cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2572                                   nls_codepage);
2573                 bcc_ptr += 2 * bytes_returned;
2574                 bcc_ptr += 2;   /* null term version string */
2575                 bytes_returned =
2576                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2577                                   64, nls_codepage);
2578                 bcc_ptr += 2 * bytes_returned;
2579                 *(bcc_ptr + 1) = 0;
2580                 *(bcc_ptr + 2) = 0;
2581                 bcc_ptr += 2;   /* null terminate network opsys string */
2582                 *(bcc_ptr + 1) = 0;
2583                 *(bcc_ptr + 2) = 0;
2584                 bcc_ptr += 2;   /* null domain */
2585         } else {                /* ASCII */
2586                 if (domain == NULL) {
2587                         SecurityBlob->DomainName.Buffer = 0;
2588                         SecurityBlob->DomainName.Length = 0;
2589                         SecurityBlob->DomainName.MaximumLength = 0;
2590                 } else {
2591                         __u16 len;
2592                         negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2593                         strncpy(bcc_ptr, domain, 63);
2594                         len = strnlen(domain, 64);
2595                         SecurityBlob->DomainName.MaximumLength =
2596                             cpu_to_le16(len);
2597                         SecurityBlob->DomainName.Buffer =
2598                             cpu_to_le32(SecurityBlobLength);
2599                         bcc_ptr += len;
2600                         SecurityBlobLength += len;
2601                         SecurityBlob->DomainName.Length = cpu_to_le16(len);
2602                 }
2603                 if (user == NULL) {
2604                         SecurityBlob->UserName.Buffer = 0;
2605                         SecurityBlob->UserName.Length = 0;
2606                         SecurityBlob->UserName.MaximumLength = 0;
2607                 } else {
2608                         __u16 len;
2609                         strncpy(bcc_ptr, user, 63);
2610                         len = strnlen(user, 64);
2611                         SecurityBlob->UserName.MaximumLength =
2612                             cpu_to_le16(len);
2613                         SecurityBlob->UserName.Buffer =
2614                             cpu_to_le32(SecurityBlobLength);
2615                         bcc_ptr += len;
2616                         SecurityBlobLength += len;
2617                         SecurityBlob->UserName.Length = cpu_to_le16(len);
2618                 }
2619                 /* BB fill in our workstation name if known BB */
2620
2621                 strcpy(bcc_ptr, "Linux version ");
2622                 bcc_ptr += strlen("Linux version ");
2623                 strcpy(bcc_ptr, system_utsname.release);
2624                 bcc_ptr += strlen(system_utsname.release) + 1;
2625                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2626                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2627                 bcc_ptr++;      /* null domain */
2628                 *bcc_ptr = 0;
2629         }
2630         SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2631         pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2632         count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2633         smb_buffer->smb_buf_length += count;
2634         pSMB->req.ByteCount = cpu_to_le16(count);
2635
2636         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2637                          &bytes_returned, 1);
2638         if (rc) {
2639 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
2640         } else if ((smb_buffer_response->WordCount == 3)
2641                    || (smb_buffer_response->WordCount == 4)) {
2642                 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2643                 __u16 blob_len =
2644                     le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2645                 if (action & GUEST_LOGIN)
2646                         cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
2647 /*        if(SecurityBlob2->MessageType != NtLm??){                               
2648                  cFYI("Unexpected message type on auth response is %d ")); 
2649         } */
2650                 if (ses) {
2651                         cFYI(1,
2652                              ("Does UID on challenge %d match auth response UID %d ",
2653                               ses->Suid, smb_buffer_response->Uid));
2654                         ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2655                         bcc_ptr = pByteArea(smb_buffer_response);       
2656             /* response can have either 3 or 4 word count - Samba sends 3 */
2657                         if ((pSMBr->resp.hdr.WordCount == 3)
2658                             || ((pSMBr->resp.hdr.WordCount == 4)
2659                                 && (blob_len <
2660                                     pSMBr->resp.ByteCount))) {
2661                                 if (pSMBr->resp.hdr.WordCount == 4) {
2662                                         bcc_ptr +=
2663                                             blob_len;
2664                                         cFYI(1,
2665                                              ("Security Blob Length %d ",
2666                                               blob_len));
2667                                 }
2668
2669                                 cFYI(1,
2670                                      ("NTLMSSP response to Authenticate "));
2671
2672                                 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2673                                         if ((long) (bcc_ptr) % 2) {
2674                                                 remaining_words =
2675                                                     (BCC(smb_buffer_response)
2676                                                      - 1) / 2;
2677                                                 bcc_ptr++;      /* Unicode strings must be word aligned */
2678                                         } else {
2679                                                 remaining_words = BCC(smb_buffer_response) / 2;
2680                                         }
2681                                         len =
2682                                             UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2683 /* We look for obvious messed up bcc or strings in response so we do not go off
2684   the end since (at least) WIN2K and Windows XP have a major bug in not null
2685   terminating last Unicode string in response  */
2686                                         ses->serverOS =
2687                                             cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
2688                                         cifs_strfromUCS_le(ses->serverOS,
2689                                                            (wchar_t *)
2690                                                            bcc_ptr, len,
2691                                                            nls_codepage);
2692                                         bcc_ptr += 2 * (len + 1);
2693                                         remaining_words -= len + 1;
2694                                         ses->serverOS[2 * len] = 0;
2695                                         ses->serverOS[1 + (2 * len)] = 0;
2696                                         if (remaining_words > 0) {
2697                                                 len = UniStrnlen((wchar_t *)
2698                                                                  bcc_ptr,
2699                                                                  remaining_words
2700                                                                  - 1);
2701                                                 ses->serverNOS =
2702                                                     cifs_kcalloc(2 * (len + 1),
2703                                                             GFP_KERNEL);
2704                                                 cifs_strfromUCS_le(ses->
2705                                                                    serverNOS,
2706                                                                    (wchar_t *)
2707                                                                    bcc_ptr,
2708                                                                    len,
2709                                                                    nls_codepage);
2710                                                 bcc_ptr += 2 * (len + 1);
2711                                                 ses->serverNOS[2 * len] = 0;
2712                                                 ses->serverNOS[1+(2*len)] = 0;
2713                                                 remaining_words -= len + 1;
2714                                                 if (remaining_words > 0) {
2715                                                         len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
2716      /* last string not always null terminated (e.g. for Windows XP & 2000) */
2717                                                         ses->serverDomain =
2718                                                             cifs_kcalloc(2 *
2719                                                                     (len +
2720                                                                      1),
2721                                                                     GFP_KERNEL);
2722                                                         cifs_strfromUCS_le
2723                                                             (ses->
2724                                                              serverDomain,
2725                                                              (wchar_t *)
2726                                                              bcc_ptr, len,
2727                                                              nls_codepage);
2728                                                         bcc_ptr +=
2729                                                             2 * (len + 1);
2730                                                         ses->
2731                                                             serverDomain[2
2732                                                                          * len]
2733                                                             = 0;
2734                                                         ses->
2735                                                             serverDomain[1
2736                                                                          +
2737                                                                          (2
2738                                                                           *
2739                                                                           len)]
2740                                                             = 0;
2741                                                 } /* else no more room so create dummy domain string */
2742                                                 else
2743                                                         ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL);
2744                                         } else {  /* no room so create dummy domain and NOS string */
2745                                                 ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
2746                                                 ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
2747                                         }
2748                                 } else {        /* ASCII */
2749                                         len = strnlen(bcc_ptr, 1024);
2750                                         if (((long) bcc_ptr + len) - 
2751                         (long) pByteArea(smb_buffer_response) 
2752                             <= BCC(smb_buffer_response)) {
2753                                                 ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
2754                                                 strncpy(ses->serverOS,bcc_ptr, len);
2755
2756                                                 bcc_ptr += len;
2757                                                 bcc_ptr[0] = 0; /* null terminate the string */
2758                                                 bcc_ptr++;
2759
2760                                                 len = strnlen(bcc_ptr, 1024);
2761                                                 ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL);
2762                                                 strncpy(ses->serverNOS, bcc_ptr, len);  
2763                                                 bcc_ptr += len;
2764                                                 bcc_ptr[0] = 0;
2765                                                 bcc_ptr++;
2766
2767                                                 len = strnlen(bcc_ptr, 1024);
2768                                                 ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL);
2769                                                 strncpy(ses->serverDomain, bcc_ptr, len);
2770                                                 bcc_ptr += len;
2771                                                 bcc_ptr[0] = 0;
2772                                                 bcc_ptr++;
2773                                         } else
2774                                                 cFYI(1,
2775                                                      ("Variable field of length %d extends beyond end of smb ",
2776                                                       len));
2777                                 }
2778                         } else {
2779                                 cERROR(1,
2780                                        (" Security Blob Length extends beyond end of SMB"));
2781                         }
2782                 } else {
2783                         cERROR(1, ("No session structure passed in."));
2784                 }
2785         } else {
2786                 cERROR(1,
2787                        (" Invalid Word count %d: ",
2788                         smb_buffer_response->WordCount));
2789                 rc = -EIO;
2790         }
2791
2792         if (smb_buffer)
2793                 cifs_buf_release(smb_buffer);
2794
2795         return rc;
2796 }
2797
2798 int
2799 CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2800          const char *tree, struct cifsTconInfo *tcon,
2801          const struct nls_table *nls_codepage)
2802 {
2803         struct smb_hdr *smb_buffer;
2804         struct smb_hdr *smb_buffer_response;
2805         TCONX_REQ *pSMB;
2806         TCONX_RSP *pSMBr;
2807         unsigned char *bcc_ptr;
2808         int rc = 0;
2809         int length;
2810         __u16 count;
2811
2812         if (ses == NULL)
2813                 return -EIO;
2814
2815         smb_buffer = cifs_buf_get();
2816         if (smb_buffer == NULL) {
2817                 return -ENOMEM;
2818         }
2819         smb_buffer_response = smb_buffer;
2820
2821         header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
2822                         NULL /*no tid */ , 4 /*wct */ );
2823         smb_buffer->Uid = ses->Suid;
2824         pSMB = (TCONX_REQ *) smb_buffer;
2825         pSMBr = (TCONX_RSP *) smb_buffer_response;
2826
2827         pSMB->AndXCommand = 0xFF;
2828         pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
2829         pSMB->PasswordLength = cpu_to_le16(1);  /* minimum */
2830         bcc_ptr = &pSMB->Password[0];
2831         bcc_ptr++;              /* skip password */
2832
2833         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2834                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2835
2836         if (ses->capabilities & CAP_STATUS32) {
2837                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2838         }
2839         if (ses->capabilities & CAP_DFS) {
2840                 smb_buffer->Flags2 |= SMBFLG2_DFS;
2841         }
2842         if (ses->capabilities & CAP_UNICODE) {
2843                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2844                 length =
2845                     cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
2846                 bcc_ptr += 2 * length;  /* convert num of 16 bit words to bytes */
2847                 bcc_ptr += 2;   /* skip trailing null */
2848         } else {                /* ASCII */
2849
2850                 strcpy(bcc_ptr, tree);
2851                 bcc_ptr += strlen(tree) + 1;
2852         }
2853         strcpy(bcc_ptr, "?????");
2854         bcc_ptr += strlen("?????");
2855         bcc_ptr += 1;
2856         count = bcc_ptr - &pSMB->Password[0];
2857         pSMB->hdr.smb_buf_length += count;
2858         pSMB->ByteCount = cpu_to_le16(count);
2859
2860         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
2861
2862         /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
2863         /* above now done in SendReceive */
2864         if ((rc == 0) && (tcon != NULL)) {
2865                 tcon->tidStatus = CifsGood;
2866                 tcon->tid = smb_buffer_response->Tid;
2867                 bcc_ptr = pByteArea(smb_buffer_response);
2868                 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
2869         /* skip service field (NB: this field is always ASCII) */
2870                 bcc_ptr += length + 1;  
2871                 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
2872                 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2873                         length = UniStrnlen((wchar_t *) bcc_ptr, 512);
2874                         if ((bcc_ptr + (2 * length)) -
2875                              pByteArea(smb_buffer_response) <=
2876                             BCC(smb_buffer_response)) {
2877                                 if(tcon->nativeFileSystem)
2878                                         kfree(tcon->nativeFileSystem);
2879                                 tcon->nativeFileSystem =
2880                                     cifs_kcalloc(length + 2, GFP_KERNEL);
2881                                 cifs_strfromUCS_le(tcon->nativeFileSystem,
2882                                                    (wchar_t *) bcc_ptr,
2883                                                    length, nls_codepage);
2884                                 bcc_ptr += 2 * length;
2885                                 bcc_ptr[0] = 0; /* null terminate the string */
2886                                 bcc_ptr[1] = 0;
2887                                 bcc_ptr += 2;
2888                         }
2889                         /* else do not bother copying these informational fields */
2890                 } else {
2891                         length = strnlen(bcc_ptr, 1024);
2892                         if ((bcc_ptr + length) -
2893                             pByteArea(smb_buffer_response) <=
2894                             BCC(smb_buffer_response)) {
2895                                 if(tcon->nativeFileSystem)
2896                                         kfree(tcon->nativeFileSystem);
2897                                 tcon->nativeFileSystem =
2898                                     cifs_kcalloc(length + 1, GFP_KERNEL);
2899                                 strncpy(tcon->nativeFileSystem, bcc_ptr,
2900                                         length);
2901                         }
2902                         /* else do not bother copying these informational fields */
2903                 }
2904                 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
2905                 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
2906         } else if ((rc == 0) && tcon == NULL) {
2907         /* all we need to save for IPC$ connection */
2908                 ses->ipc_tid = smb_buffer_response->Tid;
2909         }
2910
2911         if (smb_buffer)
2912                 cifs_buf_release(smb_buffer);
2913         return rc;
2914 }
2915
2916 int
2917 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
2918 {
2919         int rc = 0;
2920         int xid;
2921         struct cifsSesInfo *ses = NULL;
2922         struct task_struct *cifsd_task;
2923
2924         xid = GetXid();
2925
2926         if (cifs_sb->tcon) {
2927                 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
2928                 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
2929                 if (rc == -EBUSY) {
2930                         FreeXid(xid);
2931                         return 0;
2932                 }
2933                 tconInfoFree(cifs_sb->tcon);
2934                 if ((ses) && (ses->server)) {
2935                         /* save off task so we do not refer to ses later */
2936                         cifsd_task = ses->server->tsk;
2937                         cFYI(1, ("About to do SMBLogoff "));
2938                         rc = CIFSSMBLogoff(xid, ses);
2939                         if (rc == -EBUSY) {
2940                                 FreeXid(xid);
2941                                 return 0;
2942                         } else if (rc == -ESHUTDOWN) {
2943                                 cFYI(1,("Waking up socket by sending it signal"));
2944                                 if(cifsd_task)
2945                                         send_sig(SIGKILL,cifsd_task,1);
2946                                 rc = 0;
2947                         } /* else - we have an smb session
2948                                 left on this socket do not kill cifsd */
2949                 } else
2950                         cFYI(1, ("No session or bad tcon"));
2951         }
2952         
2953         cifs_sb->tcon = NULL;
2954         if (ses) {
2955                 set_current_state(TASK_INTERRUPTIBLE);
2956                 schedule_timeout(HZ / 2);
2957         }
2958         if (ses)
2959                 sesInfoFree(ses);
2960
2961         FreeXid(xid);
2962         return rc;              /* BB check if we should always return zero here */
2963
2964
2965 int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
2966                                            struct nls_table * nls_info)
2967 {
2968         int rc = 0;
2969         char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
2970         int ntlmv2_flag = FALSE;
2971         int first_time = 0;
2972
2973         /* what if server changes its buffer size after dropping the session? */
2974         if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
2975                 rc = CIFSSMBNegotiate(xid, pSesInfo);
2976                 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
2977                         rc = CIFSSMBNegotiate(xid, pSesInfo);
2978                         if(rc == -EAGAIN) 
2979                                 rc = -EHOSTDOWN;
2980                 }
2981                 if(rc == 0) {
2982                         spin_lock(&GlobalMid_Lock);
2983                         if(pSesInfo->server->tcpStatus != CifsExiting)
2984                                 pSesInfo->server->tcpStatus = CifsGood;
2985                         else
2986                                 rc = -EHOSTDOWN;
2987                         spin_unlock(&GlobalMid_Lock);
2988
2989                 }
2990                 first_time = 1;
2991         }
2992         if (!rc) {
2993                 pSesInfo->capabilities = pSesInfo->server->capabilities;
2994                 if(linuxExtEnabled == 0)
2995                         pSesInfo->capabilities &= (~CAP_UNIX);
2996         /*      pSesInfo->sequence_number = 0;*/
2997                 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
2998                         pSesInfo->server->secMode,
2999                         pSesInfo->server->capabilities,
3000                         pSesInfo->server->timeZone));
3001                 if (extended_security
3002                                 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3003                                 && (pSesInfo->server->secType == NTLMSSP)) {
3004                         cFYI(1, ("New style sesssetup "));
3005                         rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3006                                 NULL /* security blob */, 
3007                                 0 /* blob length */,
3008                                 nls_info);
3009                 } else if (extended_security
3010                            && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3011                            && (pSesInfo->server->secType == RawNTLMSSP)) {
3012                         cFYI(1, ("NTLMSSP sesssetup "));
3013                         rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3014                                                 pSesInfo,
3015                                                 &ntlmv2_flag,
3016                                                 nls_info);
3017                         if (!rc) {
3018                                 if(ntlmv2_flag) {
3019                                         char * v2_response;
3020                                         cFYI(1,("Can use more secure NTLM version 2 password hash"));
3021                                         if(CalcNTLMv2_partial_mac_key(pSesInfo, 
3022                                                 nls_info)) {
3023                                                 rc = -ENOMEM;
3024                                                 goto ss_err_exit;
3025                                         } else
3026                                                 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3027                                         if(v2_response) {
3028                                                 CalcNTLMv2_response(pSesInfo,v2_response);
3029                                 /*              if(first_time)
3030                                                         cifs_calculate_ntlmv2_mac_key(
3031                                                           pSesInfo->server->mac_signing_key, 
3032                                                           response, ntlm_session_key, */
3033                                                 kfree(v2_response);
3034                                         /* BB Put dummy sig in SessSetup PDU? */
3035                                         } else {
3036                                                 rc = -ENOMEM;
3037                                                 goto ss_err_exit;
3038                                         }
3039
3040                                 } else {
3041                                         SMBNTencrypt(pSesInfo->password,
3042                                                 pSesInfo->server->cryptKey,
3043                                                 ntlm_session_key);
3044
3045                                         if(first_time)
3046                                                 cifs_calculate_mac_key(
3047                                                         pSesInfo->server->mac_signing_key,
3048                                                         ntlm_session_key,
3049                                                         pSesInfo->password);
3050                                 }
3051                         /* for better security the weaker lanman hash not sent
3052                            in AuthSessSetup so we no longer calculate it */
3053
3054                                 rc = CIFSNTLMSSPAuthSessSetup(xid,
3055                                         pSesInfo,
3056                                         ntlm_session_key,
3057                                         ntlmv2_flag,
3058                                         nls_info);
3059                         }
3060                 } else { /* old style NTLM 0.12 session setup */
3061                         SMBNTencrypt(pSesInfo->password,
3062                                 pSesInfo->server->cryptKey,
3063                                 ntlm_session_key);
3064
3065                         if(first_time)          
3066                                 cifs_calculate_mac_key(
3067                                         pSesInfo->server->mac_signing_key,
3068                                         ntlm_session_key, pSesInfo->password);
3069
3070                         rc = CIFSSessSetup(xid, pSesInfo,
3071                                 ntlm_session_key, nls_info);
3072                 }
3073                 if (rc) {
3074                         cERROR(1,("Send error in SessSetup = %d",rc));
3075                 } else {
3076                         cFYI(1,("CIFS Session Established successfully"));
3077                         pSesInfo->status = CifsGood;
3078                 }
3079         }
3080 ss_err_exit:
3081         return rc;
3082 }
3083