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