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