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