]> Pileus Git - ~andy/linux/blob - fs/cifs/connect.c
[CIFS] Add mount option for disabling sending byte range lock requests
[~andy/linux] / 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                 } else if (strnicmp(data, "setuids", 7) == 0) {
1052                         vol->setuids = 1;
1053                 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1054                         vol->setuids = 0;
1055                 } else if (strnicmp(data, "nohard", 6) == 0) {
1056                         vol->retry = 0;
1057                 } else if (strnicmp(data, "nosoft", 6) == 0) {
1058                         vol->retry = 1;
1059                 } else if (strnicmp(data, "nointr", 6) == 0) {
1060                         vol->intr = 0;
1061                 } else if (strnicmp(data, "intr", 4) == 0) {
1062                         vol->intr = 1;
1063                 } else if (strnicmp(data, "serverino",7) == 0) {
1064                         vol->server_ino = 1;
1065                 } else if (strnicmp(data, "noserverino",9) == 0) {
1066                         vol->server_ino = 0;
1067                 } else if (strnicmp(data, "acl",3) == 0) {
1068                         vol->no_psx_acl = 0;
1069                 } else if (strnicmp(data, "noacl",5) == 0) {
1070                         vol->no_psx_acl = 1;
1071                 } else if (strnicmp(data, "direct",6) == 0) {
1072                         vol->direct_io = 1;
1073                 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1074                         vol->direct_io = 1;
1075                 } else if (strnicmp(data, "in6_addr",8) == 0) {
1076                         if (!value || !*value) {
1077                                 vol->in6_addr = NULL;
1078                         } else if (strnlen(value, 49) == 48) {
1079                                 vol->in6_addr = value;
1080                         } else {
1081                                 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1082                                 return 1;
1083                         }
1084                 } else if (strnicmp(data, "noac", 4) == 0) {
1085                         printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1086                 } else
1087                         printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1088         }
1089         if (vol->UNC == NULL) {
1090                 if(devname == NULL) {
1091                         printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1092                         return 1;
1093                 }
1094                 if ((temp_len = strnlen(devname, 300)) < 300) {
1095                         vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1096                         if(vol->UNC == NULL)
1097                                 return 1;
1098                         strcpy(vol->UNC,devname);
1099                         if (strncmp(vol->UNC, "//", 2) == 0) {
1100                                 vol->UNC[0] = '\\';
1101                                 vol->UNC[1] = '\\';
1102                         } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1103                                 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1104                                 return 1;
1105                         }
1106                 } else {
1107                         printk(KERN_WARNING "CIFS: UNC name too long\n");
1108                         return 1;
1109                 }
1110         }
1111         if(vol->UNCip == NULL)
1112                 vol->UNCip = &vol->UNC[2];
1113
1114         return 0;
1115 }
1116
1117 static struct cifsSesInfo *
1118 cifs_find_tcp_session(struct in_addr * target_ip_addr, 
1119                 struct in6_addr *target_ip6_addr,
1120                  char *userName, struct TCP_Server_Info **psrvTcp)
1121 {
1122         struct list_head *tmp;
1123         struct cifsSesInfo *ses;
1124         *psrvTcp = NULL;
1125         read_lock(&GlobalSMBSeslock);
1126
1127         list_for_each(tmp, &GlobalSMBSessionList) {
1128                 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1129                 if (ses->server) {
1130                         if((target_ip_addr && 
1131                                 (ses->server->addr.sockAddr.sin_addr.s_addr
1132                                   == target_ip_addr->s_addr)) || (target_ip6_addr
1133                                 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1134                                         target_ip6_addr,sizeof(*target_ip6_addr)))){
1135                                 /* BB lock server and tcp session and increment use count here?? */
1136                                 *psrvTcp = ses->server; /* found a match on the TCP session */
1137                                 /* BB check if reconnection needed */
1138                                 if (strncmp
1139                                     (ses->userName, userName,
1140                                      MAX_USERNAME_SIZE) == 0){
1141                                         read_unlock(&GlobalSMBSeslock);
1142                                         return ses;     /* found exact match on both tcp and SMB sessions */
1143                                 }
1144                         }
1145                 }
1146                 /* else tcp and smb sessions need reconnection */
1147         }
1148         read_unlock(&GlobalSMBSeslock);
1149         return NULL;
1150 }
1151
1152 static struct cifsTconInfo *
1153 find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1154 {
1155         struct list_head *tmp;
1156         struct cifsTconInfo *tcon;
1157
1158         read_lock(&GlobalSMBSeslock);
1159         list_for_each(tmp, &GlobalTreeConnectionList) {
1160                 cFYI(1, ("Next tcon - "));
1161                 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1162                 if (tcon->ses) {
1163                         if (tcon->ses->server) {
1164                                 cFYI(1,
1165                                      (" old ip addr: %x == new ip %x ?",
1166                                       tcon->ses->server->addr.sockAddr.sin_addr.
1167                                       s_addr, new_target_ip_addr));
1168                                 if (tcon->ses->server->addr.sockAddr.sin_addr.
1169                                     s_addr == new_target_ip_addr) {
1170         /* BB lock tcon and server and tcp session and increment use count here? */
1171                                         /* found a match on the TCP session */
1172                                         /* BB check if reconnection needed */
1173                                         cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1174                                               tcon->treeName, uncName));
1175                                         if (strncmp
1176                                             (tcon->treeName, uncName,
1177                                              MAX_TREE_SIZE) == 0) {
1178                                                 cFYI(1,
1179                                                      ("Matched UNC, old user: %s == new: %s ?",
1180                                                       tcon->treeName, uncName));
1181                                                 if (strncmp
1182                                                     (tcon->ses->userName,
1183                                                      userName,
1184                                                      MAX_USERNAME_SIZE) == 0) {
1185                                                         read_unlock(&GlobalSMBSeslock);
1186                                                         return tcon;/* also matched user (smb session)*/
1187                                                 }
1188                                         }
1189                                 }
1190                         }
1191                 }
1192         }
1193         read_unlock(&GlobalSMBSeslock);
1194         return NULL;
1195 }
1196
1197 int
1198 connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1199                     const char *old_path, const struct nls_table *nls_codepage,
1200                     int remap)
1201 {
1202         unsigned char *referrals = NULL;
1203         unsigned int num_referrals;
1204         int rc = 0;
1205
1206         rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, 
1207                         &num_referrals, &referrals, remap);
1208
1209         /* BB Add in code to: if valid refrl, if not ip address contact
1210                 the helper that resolves tcp names, mount to it, try to 
1211                 tcon to it unmount it if fail */
1212
1213         if(referrals)
1214                 kfree(referrals);
1215
1216         return rc;
1217 }
1218
1219 int
1220 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1221                         const char *old_path, const struct nls_table *nls_codepage, 
1222                         unsigned int *pnum_referrals, 
1223                         unsigned char ** preferrals, int remap)
1224 {
1225         char *temp_unc;
1226         int rc = 0;
1227
1228         *pnum_referrals = 0;
1229
1230         if (pSesInfo->ipc_tid == 0) {
1231                 temp_unc = kmalloc(2 /* for slashes */ +
1232                         strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1233                                  + 1 + 4 /* slash IPC$ */  + 2,
1234                                 GFP_KERNEL);
1235                 if (temp_unc == NULL)
1236                         return -ENOMEM;
1237                 temp_unc[0] = '\\';
1238                 temp_unc[1] = '\\';
1239                 strcpy(temp_unc + 2, pSesInfo->serverName);
1240                 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1241                 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1242                 cFYI(1,
1243                      ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1244                 kfree(temp_unc);
1245         }
1246         if (rc == 0)
1247                 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
1248                                      pnum_referrals, nls_codepage, remap);
1249
1250         return rc;
1251 }
1252
1253 /* See RFC1001 section 14 on representation of Netbios names */
1254 static void rfc1002mangle(char * target,char * source, unsigned int length)
1255 {
1256         unsigned int i,j;
1257
1258         for(i=0,j=0;i<(length);i++) {
1259                 /* mask a nibble at a time and encode */
1260                 target[j] = 'A' + (0x0F & (source[i] >> 4));
1261                 target[j+1] = 'A' + (0x0F & source[i]);
1262                 j+=2;
1263         }
1264
1265 }
1266
1267
1268 static int
1269 ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, 
1270                          char * netbios_name)
1271 {
1272         int rc = 0;
1273         int connected = 0;
1274         __be16 orig_port = 0;
1275
1276         if(*csocket == NULL) {
1277                 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1278                 if (rc < 0) {
1279                         cERROR(1, ("Error %d creating socket",rc));
1280                         *csocket = NULL;
1281                         return rc;
1282                 } else {
1283                 /* BB other socket options to set KEEPALIVE, NODELAY? */
1284                         cFYI(1,("Socket created"));
1285                         (*csocket)->sk->sk_allocation = GFP_NOFS; 
1286                 }
1287         }
1288
1289         psin_server->sin_family = AF_INET;
1290         if(psin_server->sin_port) { /* user overrode default port */
1291                 rc = (*csocket)->ops->connect(*csocket,
1292                                 (struct sockaddr *) psin_server,
1293                                 sizeof (struct sockaddr_in),0);
1294                 if (rc >= 0)
1295                         connected = 1;
1296         } 
1297
1298         if(!connected) {
1299                 /* save original port so we can retry user specified port  
1300                         later if fall back ports fail this time  */
1301                 orig_port = psin_server->sin_port;
1302
1303                 /* do not retry on the same port we just failed on */
1304                 if(psin_server->sin_port != htons(CIFS_PORT)) {
1305                         psin_server->sin_port = htons(CIFS_PORT);
1306
1307                         rc = (*csocket)->ops->connect(*csocket,
1308                                         (struct sockaddr *) psin_server,
1309                                         sizeof (struct sockaddr_in),0);
1310                         if (rc >= 0)
1311                                 connected = 1;
1312                 }
1313         }
1314         if (!connected) {
1315                 psin_server->sin_port = htons(RFC1001_PORT);
1316                 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1317                                               psin_server, sizeof (struct sockaddr_in),0);
1318                 if (rc >= 0) 
1319                         connected = 1;
1320         }
1321
1322         /* give up here - unless we want to retry on different
1323                 protocol families some day */
1324         if (!connected) {
1325                 if(orig_port)
1326                         psin_server->sin_port = orig_port;
1327                 cFYI(1,("Error %d connecting to server via ipv4",rc));
1328                 sock_release(*csocket);
1329                 *csocket = NULL;
1330                 return rc;
1331         }
1332         /* Eventually check for other socket options to change from 
1333                 the default. sock_setsockopt not used because it expects 
1334                 user space buffer */
1335         (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1336
1337         /* send RFC1001 sessinit */
1338
1339         if(psin_server->sin_port == htons(RFC1001_PORT)) {
1340                 /* some servers require RFC1001 sessinit before sending
1341                 negprot - BB check reconnection in case where second 
1342                 sessinit is sent but no second negprot */
1343                 struct rfc1002_session_packet * ses_init_buf;
1344                 struct smb_hdr * smb_buf;
1345                 ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
1346                 if(ses_init_buf) {
1347                         ses_init_buf->trailer.session_req.called_len = 32;
1348                         rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1349                                 DEFAULT_CIFS_CALLED_NAME,16);
1350                         ses_init_buf->trailer.session_req.calling_len = 32;
1351                         /* calling name ends in null (byte 16) from old smb
1352                         convention. */
1353                         if(netbios_name && (netbios_name[0] !=0)) {
1354                                 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1355                                         netbios_name,16);
1356                         } else {
1357                                 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1358                                         "LINUX_CIFS_CLNT",16);
1359                         }
1360                         ses_init_buf->trailer.session_req.scope1 = 0;
1361                         ses_init_buf->trailer.session_req.scope2 = 0;
1362                         smb_buf = (struct smb_hdr *)ses_init_buf;
1363                         /* sizeof RFC1002_SESSION_REQUEST with no scope */
1364                         smb_buf->smb_buf_length = 0x81000044;
1365                         rc = smb_send(*csocket, smb_buf, 0x44,
1366                                 (struct sockaddr *)psin_server);
1367                         kfree(ses_init_buf);
1368                 }
1369                 /* else the negprot may still work without this 
1370                 even though malloc failed */
1371                 
1372         }
1373                 
1374         return rc;
1375 }
1376
1377 static int
1378 ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1379 {
1380         int rc = 0;
1381         int connected = 0;
1382         __be16 orig_port = 0;
1383
1384         if(*csocket == NULL) {
1385                 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1386                 if (rc < 0) {
1387                         cERROR(1, ("Error %d creating ipv6 socket",rc));
1388                         *csocket = NULL;
1389                         return rc;
1390                 } else {
1391                 /* BB other socket options to set KEEPALIVE, NODELAY? */
1392                          cFYI(1,("ipv6 Socket created"));
1393                         (*csocket)->sk->sk_allocation = GFP_NOFS;
1394                 }
1395         }
1396
1397         psin_server->sin6_family = AF_INET6;
1398
1399         if(psin_server->sin6_port) { /* user overrode default port */
1400                 rc = (*csocket)->ops->connect(*csocket,
1401                                 (struct sockaddr *) psin_server,
1402                                 sizeof (struct sockaddr_in6),0);
1403                 if (rc >= 0)
1404                         connected = 1;
1405         } 
1406
1407         if(!connected) {
1408                 /* save original port so we can retry user specified port  
1409                         later if fall back ports fail this time  */
1410
1411                 orig_port = psin_server->sin6_port;
1412                 /* do not retry on the same port we just failed on */
1413                 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1414                         psin_server->sin6_port = htons(CIFS_PORT);
1415
1416                         rc = (*csocket)->ops->connect(*csocket,
1417                                         (struct sockaddr *) psin_server,
1418                                         sizeof (struct sockaddr_in6),0);
1419                         if (rc >= 0)
1420                                 connected = 1;
1421                 }
1422         }
1423         if (!connected) {
1424                 psin_server->sin6_port = htons(RFC1001_PORT);
1425                 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1426                                          psin_server, sizeof (struct sockaddr_in6),0);
1427                 if (rc >= 0) 
1428                         connected = 1;
1429         }
1430
1431         /* give up here - unless we want to retry on different
1432                 protocol families some day */
1433         if (!connected) {
1434                 if(orig_port)
1435                         psin_server->sin6_port = orig_port;
1436                 cFYI(1,("Error %d connecting to server via ipv6",rc));
1437                 sock_release(*csocket);
1438                 *csocket = NULL;
1439                 return rc;
1440         }
1441         /* Eventually check for other socket options to change from 
1442                 the default. sock_setsockopt not used because it expects 
1443                 user space buffer */
1444         (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1445                 
1446         return rc;
1447 }
1448
1449 int
1450 cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1451            char *mount_data, const char *devname)
1452 {
1453         int rc = 0;
1454         int xid;
1455         int address_type = AF_INET;
1456         struct socket *csocket = NULL;
1457         struct sockaddr_in sin_server;
1458         struct sockaddr_in6 sin_server6;
1459         struct smb_vol volume_info;
1460         struct cifsSesInfo *pSesInfo = NULL;
1461         struct cifsSesInfo *existingCifsSes = NULL;
1462         struct cifsTconInfo *tcon = NULL;
1463         struct TCP_Server_Info *srvTcp = NULL;
1464
1465         xid = GetXid();
1466
1467 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1468         
1469         memset(&volume_info,0,sizeof(struct smb_vol));
1470         if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1471                 if(volume_info.UNC)
1472                         kfree(volume_info.UNC);
1473                 if(volume_info.password)
1474                         kfree(volume_info.password);
1475                 FreeXid(xid);
1476                 return -EINVAL;
1477         }
1478
1479         if (volume_info.username) {
1480                 /* BB fixme parse for domain name here */
1481                 cFYI(1, ("Username: %s ", volume_info.username));
1482
1483         } else {
1484                 cifserror("No username specified ");
1485         /* In userspace mount helper we can get user name from alternate
1486            locations such as env variables and files on disk */
1487                 if(volume_info.UNC)
1488                         kfree(volume_info.UNC);
1489                 if(volume_info.password)
1490                         kfree(volume_info.password);
1491                 FreeXid(xid);
1492                 return -EINVAL;
1493         }
1494
1495         if (volume_info.UNCip && volume_info.UNC) {
1496                 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1497
1498                 if(rc <= 0) {
1499                         /* not ipv4 address, try ipv6 */
1500                         rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); 
1501                         if(rc > 0)
1502                                 address_type = AF_INET6;
1503                 } else {
1504                         address_type = AF_INET;
1505                 }
1506        
1507                 if(rc <= 0) {
1508                         /* we failed translating address */
1509                         if(volume_info.UNC)
1510                                 kfree(volume_info.UNC);
1511                         if(volume_info.password)
1512                                 kfree(volume_info.password);
1513                         FreeXid(xid);
1514                         return -EINVAL;
1515                 }
1516
1517                 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1518                 /* success */
1519                 rc = 0;
1520         } else if (volume_info.UNCip){
1521                 /* BB using ip addr as server name connect to the DFS root below */
1522                 cERROR(1,("Connecting to DFS root not implemented yet"));
1523                 if(volume_info.UNC)
1524                         kfree(volume_info.UNC);
1525                 if(volume_info.password)
1526                         kfree(volume_info.password);
1527                 FreeXid(xid);
1528                 return -EINVAL;
1529         } else /* which servers DFS root would we conect to */ {
1530                 cERROR(1,
1531                        ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified  "));
1532                 if(volume_info.UNC)
1533                         kfree(volume_info.UNC);
1534                 if(volume_info.password)
1535                         kfree(volume_info.password);
1536                 FreeXid(xid);
1537                 return -EINVAL;
1538         }
1539
1540         /* this is needed for ASCII cp to Unicode converts */
1541         if(volume_info.iocharset == NULL) {
1542                 cifs_sb->local_nls = load_nls_default();
1543         /* load_nls_default can not return null */
1544         } else {
1545                 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1546                 if(cifs_sb->local_nls == NULL) {
1547                         cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1548                         if(volume_info.UNC)
1549                                 kfree(volume_info.UNC);
1550                         if(volume_info.password)
1551                                 kfree(volume_info.password);
1552                         FreeXid(xid);
1553                         return -ELIBACC;
1554                 }
1555         }
1556
1557         if(address_type == AF_INET)
1558                 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1559                         NULL /* no ipv6 addr */,
1560                         volume_info.username, &srvTcp);
1561         else if(address_type == AF_INET6)
1562                 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1563                         &sin_server6.sin6_addr,
1564                         volume_info.username, &srvTcp);
1565         else {
1566                 if(volume_info.UNC)
1567                         kfree(volume_info.UNC);
1568                 if(volume_info.password)
1569                         kfree(volume_info.password);
1570                 FreeXid(xid);
1571                 return -EINVAL;
1572         }
1573
1574
1575         if (srvTcp) {
1576                 cFYI(1, ("Existing tcp session with server found "));                
1577         } else {        /* create socket */
1578                 if(volume_info.port)
1579                         sin_server.sin_port = htons(volume_info.port);
1580                 else
1581                         sin_server.sin_port = 0;
1582                 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1583                 if (rc < 0) {
1584                         cERROR(1,
1585                                ("Error connecting to IPv4 socket. Aborting operation"));
1586                         if(csocket != NULL)
1587                                 sock_release(csocket);
1588                         if(volume_info.UNC)
1589                                 kfree(volume_info.UNC);
1590                         if(volume_info.password)
1591                                 kfree(volume_info.password);
1592                         FreeXid(xid);
1593                         return rc;
1594                 }
1595
1596                 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1597                 if (srvTcp == NULL) {
1598                         rc = -ENOMEM;
1599                         sock_release(csocket);
1600                         if(volume_info.UNC)
1601                                 kfree(volume_info.UNC);
1602                         if(volume_info.password)
1603                                 kfree(volume_info.password);
1604                         FreeXid(xid);
1605                         return rc;
1606                 } else {
1607                         memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1608                         memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1609                         atomic_set(&srvTcp->inFlight,0);
1610                         /* BB Add code for ipv6 case too */
1611                         srvTcp->ssocket = csocket;
1612                         srvTcp->protocolType = IPV4;
1613                         init_waitqueue_head(&srvTcp->response_q);
1614                         init_waitqueue_head(&srvTcp->request_q);
1615                         INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1616                         /* at this point we are the only ones with the pointer
1617                         to the struct since the kernel thread not created yet
1618                         so no need to spinlock this init of tcpStatus */
1619                         srvTcp->tcpStatus = CifsNew;
1620                         init_MUTEX(&srvTcp->tcpSem);
1621                         rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1622                                       CLONE_FS | CLONE_FILES | CLONE_VM);
1623                         if(rc < 0) {
1624                                 rc = -ENOMEM;
1625                                 sock_release(csocket);
1626                                 if(volume_info.UNC)
1627                                         kfree(volume_info.UNC);
1628                                 if(volume_info.password)
1629                                         kfree(volume_info.password);
1630                                 FreeXid(xid);
1631                                 return rc;
1632                         }
1633                         wait_for_completion(&cifsd_complete);
1634                         rc = 0;
1635                         memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
1636                         srvTcp->sequence_number = 0;
1637                 }
1638         }
1639
1640         if (existingCifsSes) {
1641                 pSesInfo = existingCifsSes;
1642                 cFYI(1, ("Existing smb sess found "));
1643                 if(volume_info.password)
1644                         kfree(volume_info.password);
1645                 /* volume_info.UNC freed at end of function */
1646         } else if (!rc) {
1647                 cFYI(1, ("Existing smb sess not found "));
1648                 pSesInfo = sesInfoAlloc();
1649                 if (pSesInfo == NULL)
1650                         rc = -ENOMEM;
1651                 else {
1652                         pSesInfo->server = srvTcp;
1653                         sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1654                                 NIPQUAD(sin_server.sin_addr.s_addr));
1655                 }
1656
1657                 if (!rc){
1658                         /* volume_info.password freed at unmount */   
1659                         if (volume_info.password)
1660                                 pSesInfo->password = volume_info.password;
1661                         if (volume_info.username)
1662                                 strncpy(pSesInfo->userName,
1663                                         volume_info.username,MAX_USERNAME_SIZE);
1664                         if (volume_info.domainname)
1665                                 strncpy(pSesInfo->domainName,
1666                                         volume_info.domainname,MAX_USERNAME_SIZE);
1667                         pSesInfo->linux_uid = volume_info.linux_uid;
1668                         down(&pSesInfo->sesSem);
1669                         rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1670                         up(&pSesInfo->sesSem);
1671                         if(!rc)
1672                                 atomic_inc(&srvTcp->socketUseCount);
1673                 } else
1674                         if(volume_info.password)
1675                                 kfree(volume_info.password);
1676         }
1677     
1678         /* search for existing tcon to this server share */
1679         if (!rc) {
1680                 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1681                         cifs_sb->rsize = volume_info.rsize;
1682                 else
1683                         cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1684                 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1685                         cifs_sb->wsize = volume_info.wsize;
1686                 else
1687                         cifs_sb->wsize = CIFSMaxBufSize; /* default */
1688                 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1689                         cifs_sb->rsize = PAGE_CACHE_SIZE;
1690                         cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1691                 }
1692                 cifs_sb->mnt_uid = volume_info.linux_uid;
1693                 cifs_sb->mnt_gid = volume_info.linux_gid;
1694                 cifs_sb->mnt_file_mode = volume_info.file_mode;
1695                 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1696                 cFYI(1,("file mode: 0x%x  dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1697
1698                 if(volume_info.noperm)
1699                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1700                 if(volume_info.setuids)
1701                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1702                 if(volume_info.server_ino)
1703                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
1704                 if(volume_info.remap)
1705                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
1706                 if(volume_info.no_xattr)
1707                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1708                 if(volume_info.sfu_emul)
1709                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
1710                 if(volume_info.nocase)
1711                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CASE_INSENS;
1712                 if(volume_info.nobrl)
1713                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
1714
1715                 if(volume_info.direct_io) {
1716                         cFYI(1,("mounting share using direct i/o"));
1717                         cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1718                 }
1719
1720                 tcon =
1721                     find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1722                              volume_info.username);
1723                 if (tcon) {
1724                         cFYI(1, ("Found match on UNC path "));
1725                         /* we can have only one retry value for a connection
1726                            to a share so for resources mounted more than once
1727                            to the same server share the last value passed in 
1728                            for the retry flag is used */
1729                         tcon->retry = volume_info.retry;
1730                 } else {
1731                         tcon = tconInfoAlloc();
1732                         if (tcon == NULL)
1733                                 rc = -ENOMEM;
1734                         else {
1735                                 /* check for null share name ie connect to dfs root */
1736
1737                                 /* BB check if this works for exactly length three strings */
1738                                 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1739                                     && (strchr(volume_info.UNC + 3, '/') ==
1740                                         NULL)) {
1741                                         rc = connect_to_dfs_path(xid, pSesInfo,
1742                                                         "", cifs_sb->local_nls,
1743                                                         cifs_sb->mnt_cifs_flags & 
1744                                                           CIFS_MOUNT_MAP_SPECIAL_CHR);
1745                                         if(volume_info.UNC)
1746                                                 kfree(volume_info.UNC);
1747                                         FreeXid(xid);
1748                                         return -ENODEV;
1749                                 } else {
1750                                         rc = CIFSTCon(xid, pSesInfo, 
1751                                                 volume_info.UNC,
1752                                                 tcon, cifs_sb->local_nls);
1753                                         cFYI(1, ("CIFS Tcon rc = %d", rc));
1754                                 }
1755                                 if (!rc) {
1756                                         atomic_inc(&pSesInfo->inUse);
1757                                         tcon->retry = volume_info.retry;
1758                                 }
1759                         }
1760                 }
1761         }
1762         if(pSesInfo) {
1763                 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1764                         sb->s_maxbytes = (u64) 1 << 63;
1765                 } else
1766                         sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1767         }
1768
1769         sb->s_time_gran = 100;
1770
1771 /* on error free sesinfo and tcon struct if needed */
1772         if (rc) {
1773                 /* if session setup failed, use count is zero but
1774                 we still need to free cifsd thread */
1775                 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1776                         spin_lock(&GlobalMid_Lock);
1777                         srvTcp->tcpStatus = CifsExiting;
1778                         spin_unlock(&GlobalMid_Lock);
1779                         if(srvTcp->tsk) {
1780                                 send_sig(SIGKILL,srvTcp->tsk,1);
1781                                 wait_for_completion(&cifsd_complete);
1782                         }
1783                 }
1784                  /* If find_unc succeeded then rc == 0 so we can not end */
1785                 if (tcon)  /* up accidently freeing someone elses tcon struct */
1786                         tconInfoFree(tcon);
1787                 if (existingCifsSes == NULL) {
1788                         if (pSesInfo) {
1789                                 if ((pSesInfo->server) && 
1790                                     (pSesInfo->status == CifsGood)) {
1791                                         int temp_rc;
1792                                         temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1793                                         /* if the socketUseCount is now zero */
1794                                         if((temp_rc == -ESHUTDOWN) &&
1795                                            (pSesInfo->server->tsk)) {
1796                                                 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1797                                                 wait_for_completion(&cifsd_complete);
1798                                         }
1799                                 } else
1800                                         cFYI(1, ("No session or bad tcon"));
1801                                 sesInfoFree(pSesInfo);
1802                                 /* pSesInfo = NULL; */
1803                         }
1804                 }
1805         } else {
1806                 atomic_inc(&tcon->useCount);
1807                 cifs_sb->tcon = tcon;
1808                 tcon->ses = pSesInfo;
1809
1810                 /* do not care if following two calls succeed - informational only */
1811                 CIFSSMBQFSDeviceInfo(xid, tcon);
1812                 CIFSSMBQFSAttributeInfo(xid, tcon);
1813                 if (tcon->ses->capabilities & CAP_UNIX) {
1814                         if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
1815                                 if(!volume_info.no_psx_acl) {
1816                                         if(CIFS_UNIX_POSIX_ACL_CAP & 
1817                                            le64_to_cpu(tcon->fsUnixInfo.Capability))
1818                                                 cFYI(1,("server negotiated posix acl support"));
1819                                                 sb->s_flags |= MS_POSIXACL;
1820                                 }
1821
1822                                 /* Try and negotiate POSIX pathnames if we can. */
1823                                 if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
1824                                     le64_to_cpu(tcon->fsUnixInfo.Capability))) {
1825                                         if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP))  {
1826                                                 cFYI(1,("negotiated posix pathnames support"));
1827                                                 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
1828                                         } else {
1829                                                 cFYI(1,("posix pathnames support requested but not supported"));
1830                                         }
1831                                 }
1832                         }
1833                 }
1834         }
1835
1836         /* volume_info.password is freed above when existing session found
1837         (in which case it is not needed anymore) but when new sesion is created
1838         the password ptr is put in the new session structure (in which case the
1839         password will be freed at unmount time) */
1840         if(volume_info.UNC)
1841                 kfree(volume_info.UNC);
1842         FreeXid(xid);
1843         return rc;
1844 }
1845
1846 static int
1847 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1848               char session_key[CIFS_SESSION_KEY_SIZE],
1849               const struct nls_table *nls_codepage)
1850 {
1851         struct smb_hdr *smb_buffer;
1852         struct smb_hdr *smb_buffer_response;
1853         SESSION_SETUP_ANDX *pSMB;
1854         SESSION_SETUP_ANDX *pSMBr;
1855         char *bcc_ptr;
1856         char *user;
1857         char *domain;
1858         int rc = 0;
1859         int remaining_words = 0;
1860         int bytes_returned = 0;
1861         int len;
1862         __u32 capabilities;
1863         __u16 count;
1864
1865         cFYI(1, ("In sesssetup "));
1866         if(ses == NULL)
1867                 return -EINVAL;
1868         user = ses->userName;
1869         domain = ses->domainName;
1870         smb_buffer = cifs_buf_get();
1871         if (smb_buffer == NULL) {
1872                 return -ENOMEM;
1873         }
1874         smb_buffer_response = smb_buffer;
1875         pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1876
1877         /* send SMBsessionSetup here */
1878         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1879                         NULL /* no tCon exists yet */ , 13 /* wct */ );
1880
1881         smb_buffer->Mid = GetNextMid(ses->server);
1882         pSMB->req_no_secext.AndXCommand = 0xFF;
1883         pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1884         pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1885
1886         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1887                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1888
1889         capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1890                 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1891         if (ses->capabilities & CAP_UNICODE) {
1892                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1893                 capabilities |= CAP_UNICODE;
1894         }
1895         if (ses->capabilities & CAP_STATUS32) {
1896                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1897                 capabilities |= CAP_STATUS32;
1898         }
1899         if (ses->capabilities & CAP_DFS) {
1900                 smb_buffer->Flags2 |= SMBFLG2_DFS;
1901                 capabilities |= CAP_DFS;
1902         }
1903         pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1904
1905         pSMB->req_no_secext.CaseInsensitivePasswordLength = 
1906                 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1907
1908         pSMB->req_no_secext.CaseSensitivePasswordLength =
1909             cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1910         bcc_ptr = pByteArea(smb_buffer);
1911         memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1912         bcc_ptr += CIFS_SESSION_KEY_SIZE;
1913         memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1914         bcc_ptr += CIFS_SESSION_KEY_SIZE;
1915
1916         if (ses->capabilities & CAP_UNICODE) {
1917                 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1918                         *bcc_ptr = 0;
1919                         bcc_ptr++;
1920                 }
1921                 if(user == NULL)
1922                         bytes_returned = 0; /* skill null user */
1923                 else
1924                         bytes_returned =
1925                                 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1926                                         nls_codepage);
1927                 /* convert number of 16 bit words to bytes */
1928                 bcc_ptr += 2 * bytes_returned;
1929                 bcc_ptr += 2;   /* trailing null */
1930                 if (domain == NULL)
1931                         bytes_returned =
1932                             cifs_strtoUCS((wchar_t *) bcc_ptr,
1933                                           "CIFS_LINUX_DOM", 32, nls_codepage);
1934                 else
1935                         bytes_returned =
1936                             cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1937                                           nls_codepage);
1938                 bcc_ptr += 2 * bytes_returned;
1939                 bcc_ptr += 2;
1940                 bytes_returned =
1941                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1942                                   32, nls_codepage);
1943                 bcc_ptr += 2 * bytes_returned;
1944                 bytes_returned =
1945                     cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1946                                   32, nls_codepage);
1947                 bcc_ptr += 2 * bytes_returned;
1948                 bcc_ptr += 2;
1949                 bytes_returned =
1950                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1951                                   64, nls_codepage);
1952                 bcc_ptr += 2 * bytes_returned;
1953                 bcc_ptr += 2;
1954         } else {
1955                 if(user != NULL) {                
1956                     strncpy(bcc_ptr, user, 200);
1957                     bcc_ptr += strnlen(user, 200);
1958                 }
1959                 *bcc_ptr = 0;
1960                 bcc_ptr++;
1961                 if (domain == NULL) {
1962                         strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1963                         bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1964                 } else {
1965                         strncpy(bcc_ptr, domain, 64);
1966                         bcc_ptr += strnlen(domain, 64);
1967                         *bcc_ptr = 0;
1968                         bcc_ptr++;
1969                 }
1970                 strcpy(bcc_ptr, "Linux version ");
1971                 bcc_ptr += strlen("Linux version ");
1972                 strcpy(bcc_ptr, system_utsname.release);
1973                 bcc_ptr += strlen(system_utsname.release) + 1;
1974                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1975                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1976         }
1977         count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1978         smb_buffer->smb_buf_length += count;
1979         pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
1980
1981         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1982                          &bytes_returned, 1);
1983         if (rc) {
1984 /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1985         } else if ((smb_buffer_response->WordCount == 3)
1986                    || (smb_buffer_response->WordCount == 4)) {
1987                 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1988                 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1989                 if (action & GUEST_LOGIN)
1990                         cFYI(1, (" Guest login"));      /* do we want to mark SesInfo struct ? */
1991                 ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
1992                 cFYI(1, ("UID = %d ", ses->Suid));
1993          /* response can have either 3 or 4 word count - Samba sends 3 */
1994                 bcc_ptr = pByteArea(smb_buffer_response);       
1995                 if ((pSMBr->resp.hdr.WordCount == 3)
1996                     || ((pSMBr->resp.hdr.WordCount == 4)
1997                         && (blob_len < pSMBr->resp.ByteCount))) {
1998                         if (pSMBr->resp.hdr.WordCount == 4)
1999                                 bcc_ptr += blob_len;
2000
2001                         if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2002                                 if ((long) (bcc_ptr) % 2) {
2003                                         remaining_words =
2004                                             (BCC(smb_buffer_response) - 1) /2;
2005                                         bcc_ptr++;      /* Unicode strings must be word aligned */
2006                                 } else {
2007                                         remaining_words =
2008                                                 BCC(smb_buffer_response) / 2;
2009                                 }
2010                                 len =
2011                                     UniStrnlen((wchar_t *) bcc_ptr,
2012                                                remaining_words - 1);
2013 /* We look for obvious messed up bcc or strings in response so we do not go off
2014    the end since (at least) WIN2K and Windows XP have a major bug in not null
2015    terminating last Unicode string in response  */
2016                                 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2017                                 if(ses->serverOS == NULL)
2018                                         goto sesssetup_nomem;
2019                                 cifs_strfromUCS_le(ses->serverOS,
2020                                            (wchar_t *)bcc_ptr, len,nls_codepage);
2021                                 bcc_ptr += 2 * (len + 1);
2022                                 remaining_words -= len + 1;
2023                                 ses->serverOS[2 * len] = 0;
2024                                 ses->serverOS[1 + (2 * len)] = 0;
2025                                 if (remaining_words > 0) {
2026                                         len = UniStrnlen((wchar_t *)bcc_ptr,
2027                                                          remaining_words-1);
2028                                         ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
2029                                         if(ses->serverNOS == NULL)
2030                                                 goto sesssetup_nomem;
2031                                         cifs_strfromUCS_le(ses->serverNOS,
2032                                                            (wchar_t *)bcc_ptr,len,nls_codepage);
2033                                         bcc_ptr += 2 * (len + 1);
2034                                         ses->serverNOS[2 * len] = 0;
2035                                         ses->serverNOS[1 + (2 * len)] = 0;
2036                                         if(strncmp(ses->serverNOS,
2037                                                 "NT LAN Manager 4",16) == 0) {
2038                                                 cFYI(1,("NT4 server"));
2039                                                 ses->flags |= CIFS_SES_NT4;
2040                                         }
2041                                         remaining_words -= len + 1;
2042                                         if (remaining_words > 0) {
2043                                                 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2044           /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2045                                                 ses->serverDomain =
2046                                                     kcalloc(1, 2*(len+1),GFP_KERNEL);
2047                                                 if(ses->serverDomain == NULL)
2048                                                         goto sesssetup_nomem;
2049                                                 cifs_strfromUCS_le(ses->serverDomain,
2050                                                      (wchar_t *)bcc_ptr,len,nls_codepage);
2051                                                 bcc_ptr += 2 * (len + 1);
2052                                                 ses->serverDomain[2*len] = 0;
2053                                                 ses->serverDomain[1+(2*len)] = 0;
2054                                         } /* else no more room so create dummy domain string */
2055                                         else
2056                                                 ses->serverDomain = 
2057                                                         kcalloc(1, 2, GFP_KERNEL);
2058                                 } else {        /* no room so create dummy domain and NOS string */
2059                                         /* if these kcallocs fail not much we
2060                                            can do, but better to not fail the
2061                                            sesssetup itself */
2062                                         ses->serverDomain =
2063                                             kcalloc(1, 2, GFP_KERNEL);
2064                                         ses->serverNOS =
2065                                             kcalloc(1, 2, GFP_KERNEL);
2066                                 }
2067                         } else {        /* ASCII */
2068                                 len = strnlen(bcc_ptr, 1024);
2069                                 if (((long) bcc_ptr + len) - (long)
2070                                     pByteArea(smb_buffer_response)
2071                                             <= BCC(smb_buffer_response)) {
2072                                         ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
2073                                         if(ses->serverOS == NULL)
2074                                                 goto sesssetup_nomem;
2075                                         strncpy(ses->serverOS,bcc_ptr, len);
2076
2077                                         bcc_ptr += len;
2078                                         bcc_ptr[0] = 0; /* null terminate the string */
2079                                         bcc_ptr++;
2080
2081                                         len = strnlen(bcc_ptr, 1024);
2082                                         ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2083                                         if(ses->serverNOS == NULL)
2084                                                 goto sesssetup_nomem;
2085                                         strncpy(ses->serverNOS, bcc_ptr, len);
2086                                         bcc_ptr += len;
2087                                         bcc_ptr[0] = 0;
2088                                         bcc_ptr++;
2089
2090                                         len = strnlen(bcc_ptr, 1024);
2091                                         ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
2092                                         if(ses->serverDomain == NULL)
2093                                                 goto sesssetup_nomem;
2094                                         strncpy(ses->serverDomain, bcc_ptr, len);
2095                                         bcc_ptr += len;
2096                                         bcc_ptr[0] = 0;
2097                                         bcc_ptr++;
2098                                 } else
2099                                         cFYI(1,
2100                                              ("Variable field of length %d extends beyond end of smb ",
2101                                               len));
2102                         }
2103                 } else {
2104                         cERROR(1,
2105                                (" Security Blob Length extends beyond end of SMB"));
2106                 }
2107         } else {
2108                 cERROR(1,
2109                        (" Invalid Word count %d: ",
2110                         smb_buffer_response->WordCount));
2111                 rc = -EIO;
2112         }
2113 sesssetup_nomem:        /* do not return an error on nomem for the info strings,
2114                            since that could make reconnection harder, and
2115                            reconnection might be needed to free memory */
2116         if (smb_buffer)
2117                 cifs_buf_release(smb_buffer);
2118
2119         return rc;
2120 }
2121
2122 static int
2123 CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2124                 char *SecurityBlob,int SecurityBlobLength,
2125                 const struct nls_table *nls_codepage)
2126 {
2127         struct smb_hdr *smb_buffer;
2128         struct smb_hdr *smb_buffer_response;
2129         SESSION_SETUP_ANDX *pSMB;
2130         SESSION_SETUP_ANDX *pSMBr;
2131         char *bcc_ptr;
2132         char *user;
2133         char *domain;
2134         int rc = 0;
2135         int remaining_words = 0;
2136         int bytes_returned = 0;
2137         int len;
2138         __u32 capabilities;
2139         __u16 count;
2140
2141         cFYI(1, ("In spnego sesssetup "));
2142         if(ses == NULL)
2143                 return -EINVAL;
2144         user = ses->userName;
2145         domain = ses->domainName;
2146
2147         smb_buffer = cifs_buf_get();
2148         if (smb_buffer == NULL) {
2149                 return -ENOMEM;
2150         }
2151         smb_buffer_response = smb_buffer;
2152         pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2153
2154         /* send SMBsessionSetup here */
2155         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2156                         NULL /* no tCon exists yet */ , 12 /* wct */ );
2157
2158         smb_buffer->Mid = GetNextMid(ses->server);
2159         pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2160         pSMB->req.AndXCommand = 0xFF;
2161         pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2162         pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2163
2164         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2165                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2166
2167         capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2168             CAP_EXTENDED_SECURITY;
2169         if (ses->capabilities & CAP_UNICODE) {
2170                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2171                 capabilities |= CAP_UNICODE;
2172         }
2173         if (ses->capabilities & CAP_STATUS32) {
2174                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2175                 capabilities |= CAP_STATUS32;
2176         }
2177         if (ses->capabilities & CAP_DFS) {
2178                 smb_buffer->Flags2 |= SMBFLG2_DFS;
2179                 capabilities |= CAP_DFS;
2180         }
2181         pSMB->req.Capabilities = cpu_to_le32(capabilities);
2182
2183         pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2184         bcc_ptr = pByteArea(smb_buffer);
2185         memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2186         bcc_ptr += SecurityBlobLength;
2187
2188         if (ses->capabilities & CAP_UNICODE) {
2189                 if ((long) bcc_ptr % 2) {       /* must be word aligned for Unicode strings */
2190                         *bcc_ptr = 0;
2191                         bcc_ptr++;
2192                 }
2193                 bytes_returned =
2194                     cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2195                 bcc_ptr += 2 * bytes_returned;  /* convert num of 16 bit words to bytes */
2196                 bcc_ptr += 2;   /* trailing null */
2197                 if (domain == NULL)
2198                         bytes_returned =
2199                             cifs_strtoUCS((wchar_t *) bcc_ptr,
2200                                           "CIFS_LINUX_DOM", 32, nls_codepage);
2201                 else
2202                         bytes_returned =
2203                             cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2204                                           nls_codepage);
2205                 bcc_ptr += 2 * bytes_returned;
2206                 bcc_ptr += 2;
2207                 bytes_returned =
2208                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2209                                   32, nls_codepage);
2210                 bcc_ptr += 2 * bytes_returned;
2211                 bytes_returned =
2212                     cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2213                                   nls_codepage);
2214                 bcc_ptr += 2 * bytes_returned;
2215                 bcc_ptr += 2;
2216                 bytes_returned =
2217                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2218                                   64, nls_codepage);
2219                 bcc_ptr += 2 * bytes_returned;
2220                 bcc_ptr += 2;
2221         } else {
2222                 strncpy(bcc_ptr, user, 200);
2223                 bcc_ptr += strnlen(user, 200);
2224                 *bcc_ptr = 0;
2225                 bcc_ptr++;
2226                 if (domain == NULL) {
2227                         strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2228                         bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2229                 } else {
2230                         strncpy(bcc_ptr, domain, 64);
2231                         bcc_ptr += strnlen(domain, 64);
2232                         *bcc_ptr = 0;
2233                         bcc_ptr++;
2234                 }
2235                 strcpy(bcc_ptr, "Linux version ");
2236                 bcc_ptr += strlen("Linux version ");
2237                 strcpy(bcc_ptr, system_utsname.release);
2238                 bcc_ptr += strlen(system_utsname.release) + 1;
2239                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2240                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2241         }
2242         count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2243         smb_buffer->smb_buf_length += count;
2244         pSMB->req.ByteCount = cpu_to_le16(count);
2245
2246         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2247                          &bytes_returned, 1);
2248         if (rc) {
2249 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
2250         } else if ((smb_buffer_response->WordCount == 3)
2251                    || (smb_buffer_response->WordCount == 4)) {
2252                 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2253                 __u16 blob_len =
2254                     le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2255                 if (action & GUEST_LOGIN)
2256                         cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
2257                 if (ses) {
2258                         ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
2259                         cFYI(1, ("UID = %d ", ses->Suid));
2260                         bcc_ptr = pByteArea(smb_buffer_response);       /* response can have either 3 or 4 word count - Samba sends 3 */
2261
2262                         /* BB Fix below to make endian neutral !! */
2263
2264                         if ((pSMBr->resp.hdr.WordCount == 3)
2265                             || ((pSMBr->resp.hdr.WordCount == 4)
2266                                 && (blob_len <
2267                                     pSMBr->resp.ByteCount))) {
2268                                 if (pSMBr->resp.hdr.WordCount == 4) {
2269                                         bcc_ptr +=
2270                                             blob_len;
2271                                         cFYI(1,
2272                                              ("Security Blob Length %d ",
2273                                               blob_len));
2274                                 }
2275
2276                                 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2277                                         if ((long) (bcc_ptr) % 2) {
2278                                                 remaining_words =
2279                                                     (BCC(smb_buffer_response)
2280                                                      - 1) / 2;
2281                                                 bcc_ptr++;      /* Unicode strings must be word aligned */
2282                                         } else {
2283                                                 remaining_words =
2284                                                     BCC
2285                                                     (smb_buffer_response) / 2;
2286                                         }
2287                                         len =
2288                                             UniStrnlen((wchar_t *) bcc_ptr,
2289                                                        remaining_words - 1);
2290 /* We look for obvious messed up bcc or strings in response so we do not go off
2291    the end since (at least) WIN2K and Windows XP have a major bug in not null
2292    terminating last Unicode string in response  */
2293                                         ses->serverOS =
2294                                             kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2295                                         cifs_strfromUCS_le(ses->serverOS,
2296                                                            (wchar_t *)
2297                                                            bcc_ptr, len,
2298                                                            nls_codepage);
2299                                         bcc_ptr += 2 * (len + 1);
2300                                         remaining_words -= len + 1;
2301                                         ses->serverOS[2 * len] = 0;
2302                                         ses->serverOS[1 + (2 * len)] = 0;
2303                                         if (remaining_words > 0) {
2304                                                 len = UniStrnlen((wchar_t *)bcc_ptr,
2305                                                                  remaining_words
2306                                                                  - 1);
2307                                                 ses->serverNOS =
2308                                                     kcalloc(1, 2 * (len + 1),
2309                                                             GFP_KERNEL);
2310                                                 cifs_strfromUCS_le(ses->serverNOS,
2311                                                                    (wchar_t *)bcc_ptr,
2312                                                                    len,
2313                                                                    nls_codepage);
2314                                                 bcc_ptr += 2 * (len + 1);
2315                                                 ses->serverNOS[2 * len] = 0;
2316                                                 ses->serverNOS[1 + (2 * len)] = 0;
2317                                                 remaining_words -= len + 1;
2318                                                 if (remaining_words > 0) {
2319                                                         len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
2320                             /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2321                                                         ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
2322                                                         cifs_strfromUCS_le(ses->serverDomain,
2323                                                              (wchar_t *)bcc_ptr, 
2324                                  len,
2325                                                              nls_codepage);
2326                                                         bcc_ptr += 2*(len+1);
2327                                                         ses->serverDomain[2*len] = 0;
2328                                                         ses->serverDomain[1+(2*len)] = 0;
2329                                                 } /* else no more room so create dummy domain string */
2330                                                 else
2331                                                         ses->serverDomain =
2332                                                             kcalloc(1, 2,GFP_KERNEL);
2333                                         } else {        /* no room so create dummy domain and NOS string */
2334                                                 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2335                                                 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
2336                                         }
2337                                 } else {        /* ASCII */
2338
2339                                         len = strnlen(bcc_ptr, 1024);
2340                                         if (((long) bcc_ptr + len) - (long)
2341                                             pByteArea(smb_buffer_response)
2342                                             <= BCC(smb_buffer_response)) {
2343                                                 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
2344                                                 strncpy(ses->serverOS, bcc_ptr, len);
2345
2346                                                 bcc_ptr += len;
2347                                                 bcc_ptr[0] = 0; /* null terminate the string */
2348                                                 bcc_ptr++;
2349
2350                                                 len = strnlen(bcc_ptr, 1024);
2351                                                 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2352                                                 strncpy(ses->serverNOS, bcc_ptr, len);
2353                                                 bcc_ptr += len;
2354                                                 bcc_ptr[0] = 0;
2355                                                 bcc_ptr++;
2356
2357                                                 len = strnlen(bcc_ptr, 1024);
2358                                                 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
2359                                                 strncpy(ses->serverDomain, bcc_ptr, len);
2360                                                 bcc_ptr += len;
2361                                                 bcc_ptr[0] = 0;
2362                                                 bcc_ptr++;
2363                                         } else
2364                                                 cFYI(1,
2365                                                      ("Variable field of length %d extends beyond end of smb ",
2366                                                       len));
2367                                 }
2368                         } else {
2369                                 cERROR(1,
2370                                        (" Security Blob Length extends beyond end of SMB"));
2371                         }
2372                 } else {
2373                         cERROR(1, ("No session structure passed in."));
2374                 }
2375         } else {
2376                 cERROR(1,
2377                        (" Invalid Word count %d: ",
2378                         smb_buffer_response->WordCount));
2379                 rc = -EIO;
2380         }
2381
2382         if (smb_buffer)
2383                 cifs_buf_release(smb_buffer);
2384
2385         return rc;
2386 }
2387
2388 static int
2389 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2390                               struct cifsSesInfo *ses, int * pNTLMv2_flag,
2391                               const struct nls_table *nls_codepage)
2392 {
2393         struct smb_hdr *smb_buffer;
2394         struct smb_hdr *smb_buffer_response;
2395         SESSION_SETUP_ANDX *pSMB;
2396         SESSION_SETUP_ANDX *pSMBr;
2397         char *bcc_ptr;
2398         char *domain;
2399         int rc = 0;
2400         int remaining_words = 0;
2401         int bytes_returned = 0;
2402         int len;
2403         int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2404         PNEGOTIATE_MESSAGE SecurityBlob;
2405         PCHALLENGE_MESSAGE SecurityBlob2;
2406         __u32 negotiate_flags, capabilities;
2407         __u16 count;
2408
2409         cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2410         if(ses == NULL)
2411                 return -EINVAL;
2412         domain = ses->domainName;
2413         *pNTLMv2_flag = FALSE;
2414         smb_buffer = cifs_buf_get();
2415         if (smb_buffer == NULL) {
2416                 return -ENOMEM;
2417         }
2418         smb_buffer_response = smb_buffer;
2419         pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2420         pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2421
2422         /* send SMBsessionSetup here */
2423         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2424                         NULL /* no tCon exists yet */ , 12 /* wct */ );
2425
2426         smb_buffer->Mid = GetNextMid(ses->server);
2427         pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2428         pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2429
2430         pSMB->req.AndXCommand = 0xFF;
2431         pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2432         pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2433
2434         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2435                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2436
2437         capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2438             CAP_EXTENDED_SECURITY;
2439         if (ses->capabilities & CAP_UNICODE) {
2440                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2441                 capabilities |= CAP_UNICODE;
2442         }
2443         if (ses->capabilities & CAP_STATUS32) {
2444                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2445                 capabilities |= CAP_STATUS32;
2446         }
2447         if (ses->capabilities & CAP_DFS) {
2448                 smb_buffer->Flags2 |= SMBFLG2_DFS;
2449                 capabilities |= CAP_DFS;
2450         }
2451         pSMB->req.Capabilities = cpu_to_le32(capabilities);
2452
2453         bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2454         SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2455         strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2456         SecurityBlob->MessageType = NtLmNegotiate;
2457         negotiate_flags =
2458             NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2459             NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2460             /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2461         if(sign_CIFS_PDUs)
2462                 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2463         if(ntlmv2_support)
2464                 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2465         /* setup pointers to domain name and workstation name */
2466         bcc_ptr += SecurityBlobLength;
2467
2468         SecurityBlob->WorkstationName.Buffer = 0;
2469         SecurityBlob->WorkstationName.Length = 0;
2470         SecurityBlob->WorkstationName.MaximumLength = 0;
2471
2472         if (domain == NULL) {
2473                 SecurityBlob->DomainName.Buffer = 0;
2474                 SecurityBlob->DomainName.Length = 0;
2475                 SecurityBlob->DomainName.MaximumLength = 0;
2476         } else {
2477                 __u16 len;
2478                 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2479                 strncpy(bcc_ptr, domain, 63);
2480                 len = strnlen(domain, 64);
2481                 SecurityBlob->DomainName.MaximumLength =
2482                     cpu_to_le16(len);
2483                 SecurityBlob->DomainName.Buffer =
2484                     cpu_to_le32((long) &SecurityBlob->
2485                                 DomainString -
2486                                 (long) &SecurityBlob->Signature);
2487                 bcc_ptr += len;
2488                 SecurityBlobLength += len;
2489                 SecurityBlob->DomainName.Length =
2490                     cpu_to_le16(len);
2491         }
2492         if (ses->capabilities & CAP_UNICODE) {
2493                 if ((long) bcc_ptr % 2) {
2494                         *bcc_ptr = 0;
2495                         bcc_ptr++;
2496                 }
2497
2498                 bytes_returned =
2499                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2500                                   32, nls_codepage);
2501                 bcc_ptr += 2 * bytes_returned;
2502                 bytes_returned =
2503                     cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2504                                   nls_codepage);
2505                 bcc_ptr += 2 * bytes_returned;
2506                 bcc_ptr += 2;   /* null terminate Linux version */
2507                 bytes_returned =
2508                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2509                                   64, nls_codepage);
2510                 bcc_ptr += 2 * bytes_returned;
2511                 *(bcc_ptr + 1) = 0;
2512                 *(bcc_ptr + 2) = 0;
2513                 bcc_ptr += 2;   /* null terminate network opsys string */
2514                 *(bcc_ptr + 1) = 0;
2515                 *(bcc_ptr + 2) = 0;
2516                 bcc_ptr += 2;   /* null domain */
2517         } else {                /* ASCII */
2518                 strcpy(bcc_ptr, "Linux version ");
2519                 bcc_ptr += strlen("Linux version ");
2520                 strcpy(bcc_ptr, system_utsname.release);
2521                 bcc_ptr += strlen(system_utsname.release) + 1;
2522                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2523                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2524                 bcc_ptr++;      /* empty domain field */
2525                 *bcc_ptr = 0;
2526         }
2527         SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2528         pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2529         count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2530         smb_buffer->smb_buf_length += count;
2531         pSMB->req.ByteCount = cpu_to_le16(count);
2532
2533         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2534                          &bytes_returned, 1);
2535
2536         if (smb_buffer_response->Status.CifsError ==
2537             cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2538                 rc = 0;
2539
2540         if (rc) {
2541 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
2542         } else if ((smb_buffer_response->WordCount == 3)
2543                    || (smb_buffer_response->WordCount == 4)) {
2544                 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2545                 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2546
2547                 if (action & GUEST_LOGIN)
2548                         cFYI(1, (" Guest login"));      
2549         /* Do we want to set anything in SesInfo struct when guest login? */
2550
2551                 bcc_ptr = pByteArea(smb_buffer_response);       
2552         /* response can have either 3 or 4 word count - Samba sends 3 */
2553
2554                 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2555                 if (SecurityBlob2->MessageType != NtLmChallenge) {
2556                         cFYI(1,
2557                              ("Unexpected NTLMSSP message type received %d",
2558                               SecurityBlob2->MessageType));
2559                 } else if (ses) {
2560                         ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ 
2561                         cFYI(1, ("UID = %d ", ses->Suid));
2562                         if ((pSMBr->resp.hdr.WordCount == 3)
2563                             || ((pSMBr->resp.hdr.WordCount == 4)
2564                                 && (blob_len <
2565                                     pSMBr->resp.ByteCount))) {
2566
2567                                 if (pSMBr->resp.hdr.WordCount == 4) {
2568                                         bcc_ptr += blob_len;
2569                                         cFYI(1,
2570                                              ("Security Blob Length %d ",
2571                                               blob_len));
2572                                 }
2573
2574                                 cFYI(1, ("NTLMSSP Challenge rcvd "));
2575
2576                                 memcpy(ses->server->cryptKey,
2577                                        SecurityBlob2->Challenge,
2578                                        CIFS_CRYPTO_KEY_SIZE);
2579                                 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2580                                         *pNTLMv2_flag = TRUE;
2581
2582                                 if((SecurityBlob2->NegotiateFlags & 
2583                                         cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) 
2584                                         || (sign_CIFS_PDUs > 1))
2585                                                 ses->server->secMode |= 
2586                                                         SECMODE_SIGN_REQUIRED;  
2587                                 if ((SecurityBlob2->NegotiateFlags & 
2588                                         cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2589                                                 ses->server->secMode |= 
2590                                                         SECMODE_SIGN_ENABLED;
2591
2592                                 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2593                                         if ((long) (bcc_ptr) % 2) {
2594                                                 remaining_words =
2595                                                     (BCC(smb_buffer_response)
2596                                                      - 1) / 2;
2597                                                 bcc_ptr++;      /* Unicode strings must be word aligned */
2598                                         } else {
2599                                                 remaining_words =
2600                                                     BCC
2601                                                     (smb_buffer_response) / 2;
2602                                         }
2603                                         len =
2604                                             UniStrnlen((wchar_t *) bcc_ptr,
2605                                                        remaining_words - 1);
2606 /* We look for obvious messed up bcc or strings in response so we do not go off
2607    the end since (at least) WIN2K and Windows XP have a major bug in not null
2608    terminating last Unicode string in response  */
2609                                         ses->serverOS =
2610                                             kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2611                                         cifs_strfromUCS_le(ses->serverOS,
2612                                                            (wchar_t *)
2613                                                            bcc_ptr, len,
2614                                                            nls_codepage);
2615                                         bcc_ptr += 2 * (len + 1);
2616                                         remaining_words -= len + 1;
2617                                         ses->serverOS[2 * len] = 0;
2618                                         ses->serverOS[1 + (2 * len)] = 0;
2619                                         if (remaining_words > 0) {
2620                                                 len = UniStrnlen((wchar_t *)
2621                                                                  bcc_ptr,
2622                                                                  remaining_words
2623                                                                  - 1);
2624                                                 ses->serverNOS =
2625                                                     kcalloc(1, 2 * (len + 1),
2626                                                             GFP_KERNEL);
2627                                                 cifs_strfromUCS_le(ses->
2628                                                                    serverNOS,
2629                                                                    (wchar_t *)
2630                                                                    bcc_ptr,
2631                                                                    len,
2632                                                                    nls_codepage);
2633                                                 bcc_ptr += 2 * (len + 1);
2634                                                 ses->serverNOS[2 * len] = 0;
2635                                                 ses->serverNOS[1 +
2636                                                                (2 * len)] = 0;
2637                                                 remaining_words -= len + 1;
2638                                                 if (remaining_words > 0) {
2639                                                         len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
2640            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2641                                                         ses->serverDomain =
2642                                                             kcalloc(1, 2 *
2643                                                                     (len +
2644                                                                      1),
2645                                                                     GFP_KERNEL);
2646                                                         cifs_strfromUCS_le
2647                                                             (ses->
2648                                                              serverDomain,
2649                                                              (wchar_t *)
2650                                                              bcc_ptr, len,
2651                                                              nls_codepage);
2652                                                         bcc_ptr +=
2653                                                             2 * (len + 1);
2654                                                         ses->
2655                                                             serverDomain[2
2656                                                                          * len]
2657                                                             = 0;
2658                                                         ses->
2659                                                             serverDomain[1
2660                                                                          +
2661                                                                          (2
2662                                                                           *
2663                                                                           len)]
2664                                                             = 0;
2665                                                 } /* else no more room so create dummy domain string */
2666                                                 else
2667                                                         ses->serverDomain =
2668                                                             kcalloc(1, 2,
2669                                                                     GFP_KERNEL);
2670                                         } else {        /* no room so create dummy domain and NOS string */
2671                                                 ses->serverDomain =
2672                                                     kcalloc(1, 2, GFP_KERNEL);
2673                                                 ses->serverNOS =
2674                                                     kcalloc(1, 2, GFP_KERNEL);
2675                                         }
2676                                 } else {        /* ASCII */
2677                                         len = strnlen(bcc_ptr, 1024);
2678                                         if (((long) bcc_ptr + len) - (long)
2679                                             pByteArea(smb_buffer_response)
2680                                             <= BCC(smb_buffer_response)) {
2681                                                 ses->serverOS =
2682                                                     kcalloc(1, len + 1,
2683                                                             GFP_KERNEL);
2684                                                 strncpy(ses->serverOS,
2685                                                         bcc_ptr, len);
2686
2687                                                 bcc_ptr += len;
2688                                                 bcc_ptr[0] = 0; /* null terminate string */
2689                                                 bcc_ptr++;
2690
2691                                                 len = strnlen(bcc_ptr, 1024);
2692                                                 ses->serverNOS =
2693                                                     kcalloc(1, len + 1,
2694                                                             GFP_KERNEL);
2695                                                 strncpy(ses->serverNOS, bcc_ptr, len);
2696                                                 bcc_ptr += len;
2697                                                 bcc_ptr[0] = 0;
2698                                                 bcc_ptr++;
2699
2700                                                 len = strnlen(bcc_ptr, 1024);
2701                                                 ses->serverDomain =
2702                                                     kcalloc(1, len + 1,
2703                                                             GFP_KERNEL);
2704                                                 strncpy(ses->serverDomain, bcc_ptr, len);       
2705                                                 bcc_ptr += len;
2706                                                 bcc_ptr[0] = 0;
2707                                                 bcc_ptr++;
2708                                         } else
2709                                                 cFYI(1,
2710                                                      ("Variable field of length %d extends beyond end of smb ",
2711                                                       len));
2712                                 }
2713                         } else {
2714                                 cERROR(1,
2715                                        (" Security Blob Length extends beyond end of SMB"));
2716                         }
2717                 } else {
2718                         cERROR(1, ("No session structure passed in."));
2719                 }
2720         } else {
2721                 cERROR(1,
2722                        (" Invalid Word count %d: ",
2723                         smb_buffer_response->WordCount));
2724                 rc = -EIO;
2725         }
2726
2727         if (smb_buffer)
2728                 cifs_buf_release(smb_buffer);
2729
2730         return rc;
2731 }
2732 static int
2733 CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2734                 char *ntlm_session_key, int ntlmv2_flag,
2735                 const struct nls_table *nls_codepage)
2736 {
2737         struct smb_hdr *smb_buffer;
2738         struct smb_hdr *smb_buffer_response;
2739         SESSION_SETUP_ANDX *pSMB;
2740         SESSION_SETUP_ANDX *pSMBr;
2741         char *bcc_ptr;
2742         char *user;
2743         char *domain;
2744         int rc = 0;
2745         int remaining_words = 0;
2746         int bytes_returned = 0;
2747         int len;
2748         int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2749         PAUTHENTICATE_MESSAGE SecurityBlob;
2750         __u32 negotiate_flags, capabilities;
2751         __u16 count;
2752
2753         cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2754         if(ses == NULL)
2755                 return -EINVAL;
2756         user = ses->userName;
2757         domain = ses->domainName;
2758         smb_buffer = cifs_buf_get();
2759         if (smb_buffer == NULL) {
2760                 return -ENOMEM;
2761         }
2762         smb_buffer_response = smb_buffer;
2763         pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2764         pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2765
2766         /* send SMBsessionSetup here */
2767         header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2768                         NULL /* no tCon exists yet */ , 12 /* wct */ );
2769
2770         smb_buffer->Mid = GetNextMid(ses->server);
2771         pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2772         pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2773         pSMB->req.AndXCommand = 0xFF;
2774         pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2775         pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2776
2777         pSMB->req.hdr.Uid = ses->Suid;
2778
2779         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2780                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2781
2782         capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2783             CAP_EXTENDED_SECURITY;
2784         if (ses->capabilities & CAP_UNICODE) {
2785                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2786                 capabilities |= CAP_UNICODE;
2787         }
2788         if (ses->capabilities & CAP_STATUS32) {
2789                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2790                 capabilities |= CAP_STATUS32;
2791         }
2792         if (ses->capabilities & CAP_DFS) {
2793                 smb_buffer->Flags2 |= SMBFLG2_DFS;
2794                 capabilities |= CAP_DFS;
2795         }
2796         pSMB->req.Capabilities = cpu_to_le32(capabilities);
2797
2798         bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2799         SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2800         strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2801         SecurityBlob->MessageType = NtLmAuthenticate;
2802         bcc_ptr += SecurityBlobLength;
2803         negotiate_flags = 
2804             NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2805             NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2806             0x80000000 | NTLMSSP_NEGOTIATE_128;
2807         if(sign_CIFS_PDUs)
2808                 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2809         if(ntlmv2_flag)
2810                 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2811
2812 /* setup pointers to domain name and workstation name */
2813
2814         SecurityBlob->WorkstationName.Buffer = 0;
2815         SecurityBlob->WorkstationName.Length = 0;
2816         SecurityBlob->WorkstationName.MaximumLength = 0;
2817         SecurityBlob->SessionKey.Length = 0;
2818         SecurityBlob->SessionKey.MaximumLength = 0;
2819         SecurityBlob->SessionKey.Buffer = 0;
2820
2821         SecurityBlob->LmChallengeResponse.Length = 0;
2822         SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2823         SecurityBlob->LmChallengeResponse.Buffer = 0;
2824
2825         SecurityBlob->NtChallengeResponse.Length =
2826             cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2827         SecurityBlob->NtChallengeResponse.MaximumLength =
2828             cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2829         memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2830         SecurityBlob->NtChallengeResponse.Buffer =
2831             cpu_to_le32(SecurityBlobLength);
2832         SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2833         bcc_ptr += CIFS_SESSION_KEY_SIZE;
2834
2835         if (ses->capabilities & CAP_UNICODE) {
2836                 if (domain == NULL) {
2837                         SecurityBlob->DomainName.Buffer = 0;
2838                         SecurityBlob->DomainName.Length = 0;
2839                         SecurityBlob->DomainName.MaximumLength = 0;
2840                 } else {
2841                         __u16 len =
2842                             cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2843                                           nls_codepage);
2844                         len *= 2;
2845                         SecurityBlob->DomainName.MaximumLength =
2846                             cpu_to_le16(len);
2847                         SecurityBlob->DomainName.Buffer =
2848                             cpu_to_le32(SecurityBlobLength);
2849                         bcc_ptr += len;
2850                         SecurityBlobLength += len;
2851                         SecurityBlob->DomainName.Length =
2852                             cpu_to_le16(len);
2853                 }
2854                 if (user == NULL) {
2855                         SecurityBlob->UserName.Buffer = 0;
2856                         SecurityBlob->UserName.Length = 0;
2857                         SecurityBlob->UserName.MaximumLength = 0;
2858                 } else {
2859                         __u16 len =
2860                             cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2861                                           nls_codepage);
2862                         len *= 2;
2863                         SecurityBlob->UserName.MaximumLength =
2864                             cpu_to_le16(len);
2865                         SecurityBlob->UserName.Buffer =
2866                             cpu_to_le32(SecurityBlobLength);
2867                         bcc_ptr += len;
2868                         SecurityBlobLength += len;
2869                         SecurityBlob->UserName.Length =
2870                             cpu_to_le16(len);
2871                 }
2872
2873                 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2874                    SecurityBlob->WorkstationName.Length *= 2;
2875                    SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2876                    SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2877                    bcc_ptr += SecurityBlob->WorkstationName.Length;
2878                    SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2879                    SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length);  */
2880
2881                 if ((long) bcc_ptr % 2) {
2882                         *bcc_ptr = 0;
2883                         bcc_ptr++;
2884                 }
2885                 bytes_returned =
2886                     cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2887                                   32, nls_codepage);
2888                 bcc_ptr += 2 * bytes_returned;
2889                 bytes_returned =
2890                     cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2891                                   nls_codepage);
2892                 bcc_ptr += 2 * bytes_returned;
2893                 bcc_ptr += 2;   /* null term version string */
2894                 bytes_returned =
2895                     cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2896                                   64, nls_codepage);
2897                 bcc_ptr += 2 * bytes_returned;
2898                 *(bcc_ptr + 1) = 0;
2899                 *(bcc_ptr + 2) = 0;
2900                 bcc_ptr += 2;   /* null terminate network opsys string */
2901                 *(bcc_ptr + 1) = 0;
2902                 *(bcc_ptr + 2) = 0;
2903                 bcc_ptr += 2;   /* null domain */
2904         } else {                /* ASCII */
2905                 if (domain == NULL) {
2906                         SecurityBlob->DomainName.Buffer = 0;
2907                         SecurityBlob->DomainName.Length = 0;
2908                         SecurityBlob->DomainName.MaximumLength = 0;
2909                 } else {
2910                         __u16 len;
2911                         negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2912                         strncpy(bcc_ptr, domain, 63);
2913                         len = strnlen(domain, 64);
2914                         SecurityBlob->DomainName.MaximumLength =
2915                             cpu_to_le16(len);
2916                         SecurityBlob->DomainName.Buffer =
2917                             cpu_to_le32(SecurityBlobLength);
2918                         bcc_ptr += len;
2919                         SecurityBlobLength += len;
2920                         SecurityBlob->DomainName.Length = cpu_to_le16(len);
2921                 }
2922                 if (user == NULL) {
2923                         SecurityBlob->UserName.Buffer = 0;
2924                         SecurityBlob->UserName.Length = 0;
2925                         SecurityBlob->UserName.MaximumLength = 0;
2926                 } else {
2927                         __u16 len;
2928                         strncpy(bcc_ptr, user, 63);
2929                         len = strnlen(user, 64);
2930                         SecurityBlob->UserName.MaximumLength =
2931                             cpu_to_le16(len);
2932                         SecurityBlob->UserName.Buffer =
2933                             cpu_to_le32(SecurityBlobLength);
2934                         bcc_ptr += len;
2935                         SecurityBlobLength += len;
2936                         SecurityBlob->UserName.Length = cpu_to_le16(len);
2937                 }
2938                 /* BB fill in our workstation name if known BB */
2939
2940                 strcpy(bcc_ptr, "Linux version ");
2941                 bcc_ptr += strlen("Linux version ");
2942                 strcpy(bcc_ptr, system_utsname.release);
2943                 bcc_ptr += strlen(system_utsname.release) + 1;
2944                 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2945                 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2946                 bcc_ptr++;      /* null domain */
2947                 *bcc_ptr = 0;
2948         }
2949         SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2950         pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2951         count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2952         smb_buffer->smb_buf_length += count;
2953         pSMB->req.ByteCount = cpu_to_le16(count);
2954
2955         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2956                          &bytes_returned, 1);
2957         if (rc) {
2958 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
2959         } else if ((smb_buffer_response->WordCount == 3)
2960                    || (smb_buffer_response->WordCount == 4)) {
2961                 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2962                 __u16 blob_len =
2963                     le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2964                 if (action & GUEST_LOGIN)
2965                         cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
2966 /*        if(SecurityBlob2->MessageType != NtLm??){                               
2967                  cFYI("Unexpected message type on auth response is %d ")); 
2968         } */
2969                 if (ses) {
2970                         cFYI(1,
2971                              ("Does UID on challenge %d match auth response UID %d ",
2972                               ses->Suid, smb_buffer_response->Uid));
2973                         ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2974                         bcc_ptr = pByteArea(smb_buffer_response);       
2975             /* response can have either 3 or 4 word count - Samba sends 3 */
2976                         if ((pSMBr->resp.hdr.WordCount == 3)
2977                             || ((pSMBr->resp.hdr.WordCount == 4)
2978                                 && (blob_len <
2979                                     pSMBr->resp.ByteCount))) {
2980                                 if (pSMBr->resp.hdr.WordCount == 4) {
2981                                         bcc_ptr +=
2982                                             blob_len;
2983                                         cFYI(1,
2984                                              ("Security Blob Length %d ",
2985                                               blob_len));
2986                                 }
2987
2988                                 cFYI(1,
2989                                      ("NTLMSSP response to Authenticate "));
2990
2991                                 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2992                                         if ((long) (bcc_ptr) % 2) {
2993                                                 remaining_words =
2994                                                     (BCC(smb_buffer_response)
2995                                                      - 1) / 2;
2996                                                 bcc_ptr++;      /* Unicode strings must be word aligned */
2997                                         } else {
2998                                                 remaining_words = BCC(smb_buffer_response) / 2;
2999                                         }
3000                                         len =
3001                                             UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3002 /* We look for obvious messed up bcc or strings in response so we do not go off
3003   the end since (at least) WIN2K and Windows XP have a major bug in not null
3004   terminating last Unicode string in response  */
3005                                         ses->serverOS =
3006                                             kcalloc(1, 2 * (len + 1), GFP_KERNEL);
3007                                         cifs_strfromUCS_le(ses->serverOS,
3008                                                            (wchar_t *)
3009                                                            bcc_ptr, len,
3010                                                            nls_codepage);
3011                                         bcc_ptr += 2 * (len + 1);
3012                                         remaining_words -= len + 1;
3013                                         ses->serverOS[2 * len] = 0;
3014                                         ses->serverOS[1 + (2 * len)] = 0;
3015                                         if (remaining_words > 0) {
3016                                                 len = UniStrnlen((wchar_t *)
3017                                                                  bcc_ptr,
3018                                                                  remaining_words
3019                                                                  - 1);
3020                                                 ses->serverNOS =
3021                                                     kcalloc(1, 2 * (len + 1),
3022                                                             GFP_KERNEL);
3023                                                 cifs_strfromUCS_le(ses->
3024                                                                    serverNOS,
3025                                                                    (wchar_t *)
3026                                                                    bcc_ptr,
3027                                                                    len,
3028                                                                    nls_codepage);
3029                                                 bcc_ptr += 2 * (len + 1);
3030                                                 ses->serverNOS[2 * len] = 0;
3031                                                 ses->serverNOS[1+(2*len)] = 0;
3032                                                 remaining_words -= len + 1;
3033                                                 if (remaining_words > 0) {
3034                                                         len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
3035      /* last string not always null terminated (e.g. for Windows XP & 2000) */
3036                                                         ses->serverDomain =
3037                                                             kcalloc(1, 2 *
3038                                                                     (len +
3039                                                                      1),
3040                                                                     GFP_KERNEL);
3041                                                         cifs_strfromUCS_le
3042                                                             (ses->
3043                                                              serverDomain,
3044                                                              (wchar_t *)
3045                                                              bcc_ptr, len,
3046                                                              nls_codepage);
3047                                                         bcc_ptr +=
3048                                                             2 * (len + 1);
3049                                                         ses->
3050                                                             serverDomain[2
3051                                                                          * len]
3052                                                             = 0;
3053                                                         ses->
3054                                                             serverDomain[1
3055                                                                          +
3056                                                                          (2
3057                                                                           *
3058                                                                           len)]
3059                                                             = 0;
3060                                                 } /* else no more room so create dummy domain string */
3061                                                 else
3062                                                         ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
3063                                         } else {  /* no room so create dummy domain and NOS string */
3064                                                 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
3065                                                 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
3066                                         }
3067                                 } else {        /* ASCII */
3068                                         len = strnlen(bcc_ptr, 1024);
3069                                         if (((long) bcc_ptr + len) - 
3070                         (long) pByteArea(smb_buffer_response) 
3071                             <= BCC(smb_buffer_response)) {
3072                                                 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
3073                                                 strncpy(ses->serverOS,bcc_ptr, len);
3074
3075                                                 bcc_ptr += len;
3076                                                 bcc_ptr[0] = 0; /* null terminate the string */
3077                                                 bcc_ptr++;
3078
3079                                                 len = strnlen(bcc_ptr, 1024);
3080                                                 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
3081                                                 strncpy(ses->serverNOS, bcc_ptr, len);  
3082                                                 bcc_ptr += len;
3083                                                 bcc_ptr[0] = 0;
3084                                                 bcc_ptr++;
3085
3086                                                 len = strnlen(bcc_ptr, 1024);
3087                                                 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
3088                                                 strncpy(ses->serverDomain, bcc_ptr, len);
3089                                                 bcc_ptr += len;
3090                                                 bcc_ptr[0] = 0;
3091                                                 bcc_ptr++;
3092                                         } else
3093                                                 cFYI(1,
3094                                                      ("Variable field of length %d extends beyond end of smb ",
3095                                                       len));
3096                                 }
3097                         } else {
3098                                 cERROR(1,
3099                                        (" Security Blob Length extends beyond end of SMB"));
3100                         }
3101                 } else {
3102                         cERROR(1, ("No session structure passed in."));
3103                 }
3104         } else {
3105                 cERROR(1,
3106                        (" Invalid Word count %d: ",
3107                         smb_buffer_response->WordCount));
3108                 rc = -EIO;
3109         }
3110
3111         if (smb_buffer)
3112                 cifs_buf_release(smb_buffer);
3113
3114         return rc;
3115 }
3116
3117 int
3118 CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3119          const char *tree, struct cifsTconInfo *tcon,
3120          const struct nls_table *nls_codepage)
3121 {
3122         struct smb_hdr *smb_buffer;
3123         struct smb_hdr *smb_buffer_response;
3124         TCONX_REQ *pSMB;
3125         TCONX_RSP *pSMBr;
3126         unsigned char *bcc_ptr;
3127         int rc = 0;
3128         int length;
3129         __u16 count;
3130
3131         if (ses == NULL)
3132                 return -EIO;
3133
3134         smb_buffer = cifs_buf_get();
3135         if (smb_buffer == NULL) {
3136                 return -ENOMEM;
3137         }
3138         smb_buffer_response = smb_buffer;
3139
3140         header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3141                         NULL /*no tid */ , 4 /*wct */ );
3142
3143         smb_buffer->Mid = GetNextMid(ses->server);
3144         smb_buffer->Uid = ses->Suid;
3145         pSMB = (TCONX_REQ *) smb_buffer;
3146         pSMBr = (TCONX_RSP *) smb_buffer_response;
3147
3148         pSMB->AndXCommand = 0xFF;
3149         pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3150         pSMB->PasswordLength = cpu_to_le16(1);  /* minimum */
3151         bcc_ptr = &pSMB->Password[0];
3152         bcc_ptr++;              /* skip password */
3153
3154         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3155                 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3156
3157         if (ses->capabilities & CAP_STATUS32) {
3158                 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3159         }
3160         if (ses->capabilities & CAP_DFS) {
3161                 smb_buffer->Flags2 |= SMBFLG2_DFS;
3162         }
3163         if (ses->capabilities & CAP_UNICODE) {
3164                 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3165                 length =
3166                     cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3167                 bcc_ptr += 2 * length;  /* convert num of 16 bit words to bytes */
3168                 bcc_ptr += 2;   /* skip trailing null */
3169         } else {                /* ASCII */
3170
3171                 strcpy(bcc_ptr, tree);
3172                 bcc_ptr += strlen(tree) + 1;
3173         }
3174         strcpy(bcc_ptr, "?????");
3175         bcc_ptr += strlen("?????");
3176         bcc_ptr += 1;
3177         count = bcc_ptr - &pSMB->Password[0];
3178         pSMB->hdr.smb_buf_length += count;
3179         pSMB->ByteCount = cpu_to_le16(count);
3180
3181         rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3182
3183         /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3184         /* above now done in SendReceive */
3185         if ((rc == 0) && (tcon != NULL)) {
3186                 tcon->tidStatus = CifsGood;
3187                 tcon->tid = smb_buffer_response->Tid;
3188                 bcc_ptr = pByteArea(smb_buffer_response);
3189                 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3190         /* skip service field (NB: this field is always ASCII) */
3191                 bcc_ptr += length + 1;  
3192                 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3193                 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3194                         length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3195                         if ((bcc_ptr + (2 * length)) -
3196                              pByteArea(smb_buffer_response) <=
3197                             BCC(smb_buffer_response)) {
3198                                 if(tcon->nativeFileSystem)
3199                                         kfree(tcon->nativeFileSystem);
3200                                 tcon->nativeFileSystem =
3201                                     kcalloc(1, length + 2, GFP_KERNEL);
3202                                 cifs_strfromUCS_le(tcon->nativeFileSystem,
3203                                                    (wchar_t *) bcc_ptr,
3204                                                    length, nls_codepage);
3205                                 bcc_ptr += 2 * length;
3206                                 bcc_ptr[0] = 0; /* null terminate the string */
3207                                 bcc_ptr[1] = 0;
3208                                 bcc_ptr += 2;
3209                         }
3210                         /* else do not bother copying these informational fields */
3211                 } else {
3212                         length = strnlen(bcc_ptr, 1024);
3213                         if ((bcc_ptr + length) -
3214                             pByteArea(smb_buffer_response) <=
3215                             BCC(smb_buffer_response)) {
3216                                 if(tcon->nativeFileSystem)
3217                                         kfree(tcon->nativeFileSystem);
3218                                 tcon->nativeFileSystem =
3219                                     kcalloc(1, length + 1, GFP_KERNEL);
3220                                 strncpy(tcon->nativeFileSystem, bcc_ptr,
3221                                         length);
3222                         }
3223                         /* else do not bother copying these informational fields */
3224                 }
3225                 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3226                 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3227         } else if ((rc == 0) && tcon == NULL) {
3228         /* all we need to save for IPC$ connection */
3229                 ses->ipc_tid = smb_buffer_response->Tid;
3230         }
3231
3232         if (smb_buffer)
3233                 cifs_buf_release(smb_buffer);
3234         return rc;
3235 }
3236
3237 int
3238 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3239 {
3240         int rc = 0;
3241         int xid;
3242         struct cifsSesInfo *ses = NULL;
3243         struct task_struct *cifsd_task;
3244
3245         xid = GetXid();
3246
3247         if (cifs_sb->tcon) {
3248                 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3249                 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3250                 if (rc == -EBUSY) {
3251                         FreeXid(xid);
3252                         return 0;
3253                 }
3254                 tconInfoFree(cifs_sb->tcon);
3255                 if ((ses) && (ses->server)) {
3256                         /* save off task so we do not refer to ses later */
3257                         cifsd_task = ses->server->tsk;
3258                         cFYI(1, ("About to do SMBLogoff "));
3259                         rc = CIFSSMBLogoff(xid, ses);
3260                         if (rc == -EBUSY) {
3261                                 FreeXid(xid);
3262                                 return 0;
3263                         } else if (rc == -ESHUTDOWN) {
3264                                 cFYI(1,("Waking up socket by sending it signal"));
3265                                 if(cifsd_task) {
3266                                         send_sig(SIGKILL,cifsd_task,1);
3267                                         wait_for_completion(&cifsd_complete);
3268                                 }
3269                                 rc = 0;
3270                         } /* else - we have an smb session
3271                                 left on this socket do not kill cifsd */
3272                 } else
3273                         cFYI(1, ("No session or bad tcon"));
3274         }
3275         
3276         cifs_sb->tcon = NULL;
3277         if (ses) {
3278                 set_current_state(TASK_INTERRUPTIBLE);
3279                 schedule_timeout(HZ / 2);
3280         }
3281         if (ses)
3282                 sesInfoFree(ses);
3283
3284         FreeXid(xid);
3285         return rc;              /* BB check if we should always return zero here */
3286
3287
3288 int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3289                                            struct nls_table * nls_info)
3290 {
3291         int rc = 0;
3292         char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3293         int ntlmv2_flag = FALSE;
3294         int first_time = 0;
3295
3296         /* what if server changes its buffer size after dropping the session? */
3297         if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3298                 rc = CIFSSMBNegotiate(xid, pSesInfo);
3299                 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3300                         rc = CIFSSMBNegotiate(xid, pSesInfo);
3301                         if(rc == -EAGAIN) 
3302                                 rc = -EHOSTDOWN;
3303                 }
3304                 if(rc == 0) {
3305                         spin_lock(&GlobalMid_Lock);
3306                         if(pSesInfo->server->tcpStatus != CifsExiting)
3307                                 pSesInfo->server->tcpStatus = CifsGood;
3308                         else
3309                                 rc = -EHOSTDOWN;
3310                         spin_unlock(&GlobalMid_Lock);
3311
3312                 }
3313                 first_time = 1;
3314         }
3315         if (!rc) {
3316                 pSesInfo->capabilities = pSesInfo->server->capabilities;
3317                 if(linuxExtEnabled == 0)
3318                         pSesInfo->capabilities &= (~CAP_UNIX);
3319         /*      pSesInfo->sequence_number = 0;*/
3320                 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3321                         pSesInfo->server->secMode,
3322                         pSesInfo->server->capabilities,
3323                         pSesInfo->server->timeZone));
3324                 if (extended_security
3325                                 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3326                                 && (pSesInfo->server->secType == NTLMSSP)) {
3327                         cFYI(1, ("New style sesssetup "));
3328                         rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3329                                 NULL /* security blob */, 
3330                                 0 /* blob length */,
3331                                 nls_info);
3332                 } else if (extended_security
3333                            && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3334                            && (pSesInfo->server->secType == RawNTLMSSP)) {
3335                         cFYI(1, ("NTLMSSP sesssetup "));
3336                         rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3337                                                 pSesInfo,
3338                                                 &ntlmv2_flag,
3339                                                 nls_info);
3340                         if (!rc) {
3341                                 if(ntlmv2_flag) {
3342                                         char * v2_response;
3343                                         cFYI(1,("Can use more secure NTLM version 2 password hash"));
3344                                         if(CalcNTLMv2_partial_mac_key(pSesInfo, 
3345                                                 nls_info)) {
3346                                                 rc = -ENOMEM;
3347                                                 goto ss_err_exit;
3348                                         } else
3349                                                 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3350                                         if(v2_response) {
3351                                                 CalcNTLMv2_response(pSesInfo,v2_response);
3352                                 /*              if(first_time)
3353                                                         cifs_calculate_ntlmv2_mac_key(
3354                                                           pSesInfo->server->mac_signing_key, 
3355                                                           response, ntlm_session_key, */
3356                                                 kfree(v2_response);
3357                                         /* BB Put dummy sig in SessSetup PDU? */
3358                                         } else {
3359                                                 rc = -ENOMEM;
3360                                                 goto ss_err_exit;
3361                                         }
3362
3363                                 } else {
3364                                         SMBNTencrypt(pSesInfo->password,
3365                                                 pSesInfo->server->cryptKey,
3366                                                 ntlm_session_key);
3367
3368                                         if(first_time)
3369                                                 cifs_calculate_mac_key(
3370                                                         pSesInfo->server->mac_signing_key,
3371                                                         ntlm_session_key,
3372                                                         pSesInfo->password);
3373                                 }
3374                         /* for better security the weaker lanman hash not sent
3375                            in AuthSessSetup so we no longer calculate it */
3376
3377                                 rc = CIFSNTLMSSPAuthSessSetup(xid,
3378                                         pSesInfo,
3379                                         ntlm_session_key,
3380                                         ntlmv2_flag,
3381                                         nls_info);
3382                         }
3383                 } else { /* old style NTLM 0.12 session setup */
3384                         SMBNTencrypt(pSesInfo->password,
3385                                 pSesInfo->server->cryptKey,
3386                                 ntlm_session_key);
3387
3388                         if(first_time)          
3389                                 cifs_calculate_mac_key(
3390                                         pSesInfo->server->mac_signing_key,
3391                                         ntlm_session_key, pSesInfo->password);
3392
3393                         rc = CIFSSessSetup(xid, pSesInfo,
3394                                 ntlm_session_key, nls_info);
3395                 }
3396                 if (rc) {
3397                         cERROR(1,("Send error in SessSetup = %d",rc));
3398                 } else {
3399                         cFYI(1,("CIFS Session Established successfully"));
3400                         pSesInfo->status = CifsGood;
3401                 }
3402         }
3403 ss_err_exit:
3404         return rc;
3405 }
3406