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