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