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