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