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