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