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