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