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