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