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