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