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