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