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