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