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