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