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