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