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