]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/cifs/connect.c
[PATCH] cifs: finish up of special character mapping capable unicode conversion routi...
[net-next-2.6.git] / fs / cifs / connect.c
CommitLineData
1da177e4
LT
1/*
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;
6a0b4824 75 unsigned remap:1; /* set to remap seven reserved chars in filenames */
1da177e4
LT
76 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;
ad009ac9
SF
186 server->sequence_number = 0;
187 spin_unlock(&GlobalMid_Lock);
1da177e4
LT
188 /* 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;
6a0b4824
SF
775 } else if (strnicmp(data, "mapchars", 8) == 0) {
776 vol->remap = 1;
777 } else if (strnicmp(data, "nomapchars", 10) == 0) {
778 vol->remap = 0;
1da177e4
LT
779 } 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,
927 const char *old_path, const struct nls_table *nls_codepage)
928{
929 unsigned char *referrals = NULL;
930 unsigned int num_referrals;
931 int rc = 0;
932
933 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
934 &num_referrals, &referrals);
935
936 /* BB Add in code to: if valid refrl, if not ip address contact
937 the helper that resolves tcp names, mount to it, try to
938 tcon to it unmount it if fail */
939
940 if(referrals)
941 kfree(referrals);
942
943 return rc;
944}
945
946int
947get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
948 const char *old_path, const struct nls_table *nls_codepage,
949 unsigned int *pnum_referrals, unsigned char ** preferrals)
950{
951 char *temp_unc;
952 int rc = 0;
953
954 *pnum_referrals = 0;
955
956 if (pSesInfo->ipc_tid == 0) {
957 temp_unc = kmalloc(2 /* for slashes */ +
958 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
959 + 1 + 4 /* slash IPC$ */ + 2,
960 GFP_KERNEL);
961 if (temp_unc == NULL)
962 return -ENOMEM;
963 temp_unc[0] = '\\';
964 temp_unc[1] = '\\';
965 strcpy(temp_unc + 2, pSesInfo->serverName);
966 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
967 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
968 cFYI(1,
969 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
970 kfree(temp_unc);
971 }
972 if (rc == 0)
973 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
974 pnum_referrals, nls_codepage);
975
976 return rc;
977}
978
979/* See RFC1001 section 14 on representation of Netbios names */
980static void rfc1002mangle(char * target,char * source, unsigned int length)
981{
982 unsigned int i,j;
983
984 for(i=0,j=0;i<(length);i++) {
985 /* mask a nibble at a time and encode */
986 target[j] = 'A' + (0x0F & (source[i] >> 4));
987 target[j+1] = 'A' + (0x0F & source[i]);
988 j+=2;
989 }
990
991}
992
993
994static int
995ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
996 char * netbios_name)
997{
998 int rc = 0;
999 int connected = 0;
1000 __be16 orig_port = 0;
1001
1002 if(*csocket == NULL) {
1003 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1004 if (rc < 0) {
1005 cERROR(1, ("Error %d creating socket",rc));
1006 *csocket = NULL;
1007 return rc;
1008 } else {
1009 /* BB other socket options to set KEEPALIVE, NODELAY? */
1010 cFYI(1,("Socket created"));
1011 (*csocket)->sk->sk_allocation = GFP_NOFS;
1012 }
1013 }
1014
1015 psin_server->sin_family = AF_INET;
1016 if(psin_server->sin_port) { /* user overrode default port */
1017 rc = (*csocket)->ops->connect(*csocket,
1018 (struct sockaddr *) psin_server,
1019 sizeof (struct sockaddr_in),0);
1020 if (rc >= 0)
1021 connected = 1;
1022 }
1023
1024 if(!connected) {
1025 /* save original port so we can retry user specified port
1026 later if fall back ports fail this time */
1027 orig_port = psin_server->sin_port;
1028
1029 /* do not retry on the same port we just failed on */
1030 if(psin_server->sin_port != htons(CIFS_PORT)) {
1031 psin_server->sin_port = htons(CIFS_PORT);
1032
1033 rc = (*csocket)->ops->connect(*csocket,
1034 (struct sockaddr *) psin_server,
1035 sizeof (struct sockaddr_in),0);
1036 if (rc >= 0)
1037 connected = 1;
1038 }
1039 }
1040 if (!connected) {
1041 psin_server->sin_port = htons(RFC1001_PORT);
1042 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1043 psin_server, sizeof (struct sockaddr_in),0);
1044 if (rc >= 0)
1045 connected = 1;
1046 }
1047
1048 /* give up here - unless we want to retry on different
1049 protocol families some day */
1050 if (!connected) {
1051 if(orig_port)
1052 psin_server->sin_port = orig_port;
1053 cFYI(1,("Error %d connecting to server via ipv4",rc));
1054 sock_release(*csocket);
1055 *csocket = NULL;
1056 return rc;
1057 }
1058 /* Eventually check for other socket options to change from
1059 the default. sock_setsockopt not used because it expects
1060 user space buffer */
1061 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1062
1063 /* send RFC1001 sessinit */
1064
1065 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1066 /* some servers require RFC1001 sessinit before sending
1067 negprot - BB check reconnection in case where second
1068 sessinit is sent but no second negprot */
1069 struct rfc1002_session_packet * ses_init_buf;
1070 struct smb_hdr * smb_buf;
1071 ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
1072 if(ses_init_buf) {
1073 ses_init_buf->trailer.session_req.called_len = 32;
1074 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1075 DEFAULT_CIFS_CALLED_NAME,16);
1076 ses_init_buf->trailer.session_req.calling_len = 32;
1077 /* calling name ends in null (byte 16) from old smb
1078 convention. */
1079 if(netbios_name && (netbios_name[0] !=0)) {
1080 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1081 netbios_name,16);
1082 } else {
1083 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1084 "LINUX_CIFS_CLNT",16);
1085 }
1086 ses_init_buf->trailer.session_req.scope1 = 0;
1087 ses_init_buf->trailer.session_req.scope2 = 0;
1088 smb_buf = (struct smb_hdr *)ses_init_buf;
1089 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1090 smb_buf->smb_buf_length = 0x81000044;
1091 rc = smb_send(*csocket, smb_buf, 0x44,
1092 (struct sockaddr *)psin_server);
1093 kfree(ses_init_buf);
1094 }
1095 /* else the negprot may still work without this
1096 even though malloc failed */
1097
1098 }
1099
1100 return rc;
1101}
1102
1103static int
1104ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1105{
1106 int rc = 0;
1107 int connected = 0;
1108 __be16 orig_port = 0;
1109
1110 if(*csocket == NULL) {
1111 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1112 if (rc < 0) {
1113 cERROR(1, ("Error %d creating ipv6 socket",rc));
1114 *csocket = NULL;
1115 return rc;
1116 } else {
1117 /* BB other socket options to set KEEPALIVE, NODELAY? */
1118 cFYI(1,("ipv6 Socket created"));
1119 (*csocket)->sk->sk_allocation = GFP_NOFS;
1120 }
1121 }
1122
1123 psin_server->sin6_family = AF_INET6;
1124
1125 if(psin_server->sin6_port) { /* user overrode default port */
1126 rc = (*csocket)->ops->connect(*csocket,
1127 (struct sockaddr *) psin_server,
1128 sizeof (struct sockaddr_in6),0);
1129 if (rc >= 0)
1130 connected = 1;
1131 }
1132
1133 if(!connected) {
1134 /* save original port so we can retry user specified port
1135 later if fall back ports fail this time */
1136
1137 orig_port = psin_server->sin6_port;
1138 /* do not retry on the same port we just failed on */
1139 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1140 psin_server->sin6_port = htons(CIFS_PORT);
1141
1142 rc = (*csocket)->ops->connect(*csocket,
1143 (struct sockaddr *) psin_server,
1144 sizeof (struct sockaddr_in6),0);
1145 if (rc >= 0)
1146 connected = 1;
1147 }
1148 }
1149 if (!connected) {
1150 psin_server->sin6_port = htons(RFC1001_PORT);
1151 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1152 psin_server, sizeof (struct sockaddr_in6),0);
1153 if (rc >= 0)
1154 connected = 1;
1155 }
1156
1157 /* give up here - unless we want to retry on different
1158 protocol families some day */
1159 if (!connected) {
1160 if(orig_port)
1161 psin_server->sin6_port = orig_port;
1162 cFYI(1,("Error %d connecting to server via ipv6",rc));
1163 sock_release(*csocket);
1164 *csocket = NULL;
1165 return rc;
1166 }
1167 /* Eventually check for other socket options to change from
1168 the default. sock_setsockopt not used because it expects
1169 user space buffer */
1170 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1171
1172 return rc;
1173}
1174
1175int
1176cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1177 char *mount_data, const char *devname)
1178{
1179 int rc = 0;
1180 int xid;
1181 int address_type = AF_INET;
1182 struct socket *csocket = NULL;
1183 struct sockaddr_in sin_server;
1184 struct sockaddr_in6 sin_server6;
1185 struct smb_vol volume_info;
1186 struct cifsSesInfo *pSesInfo = NULL;
1187 struct cifsSesInfo *existingCifsSes = NULL;
1188 struct cifsTconInfo *tcon = NULL;
1189 struct TCP_Server_Info *srvTcp = NULL;
1190
1191 xid = GetXid();
1192
1193/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1194
1195 memset(&volume_info,0,sizeof(struct smb_vol));
1196 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1197 if(volume_info.UNC)
1198 kfree(volume_info.UNC);
1199 if(volume_info.password)
1200 kfree(volume_info.password);
1201 FreeXid(xid);
1202 return -EINVAL;
1203 }
1204
1205 if (volume_info.username) {
1206 /* BB fixme parse for domain name here */
1207 cFYI(1, ("Username: %s ", volume_info.username));
1208
1209 } else {
1210 cifserror("No username specified ");
1211 /* In userspace mount helper we can get user name from alternate
1212 locations such as env variables and files on disk */
1213 if(volume_info.UNC)
1214 kfree(volume_info.UNC);
1215 if(volume_info.password)
1216 kfree(volume_info.password);
1217 FreeXid(xid);
1218 return -EINVAL;
1219 }
1220
1221 if (volume_info.UNCip && volume_info.UNC) {
1222 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1223
1224 if(rc <= 0) {
1225 /* not ipv4 address, try ipv6 */
1226 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1227 if(rc > 0)
1228 address_type = AF_INET6;
1229 } else {
1230 address_type = AF_INET;
1231 }
1232
1233 if(rc <= 0) {
1234 /* we failed translating address */
1235 if(volume_info.UNC)
1236 kfree(volume_info.UNC);
1237 if(volume_info.password)
1238 kfree(volume_info.password);
1239 FreeXid(xid);
1240 return -EINVAL;
1241 }
1242
1243 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1244 /* success */
1245 rc = 0;
1246 } else if (volume_info.UNCip){
1247 /* BB using ip addr as server name connect to the DFS root below */
1248 cERROR(1,("Connecting to DFS root not implemented yet"));
1249 if(volume_info.UNC)
1250 kfree(volume_info.UNC);
1251 if(volume_info.password)
1252 kfree(volume_info.password);
1253 FreeXid(xid);
1254 return -EINVAL;
1255 } else /* which servers DFS root would we conect to */ {
1256 cERROR(1,
1257 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1258 if(volume_info.UNC)
1259 kfree(volume_info.UNC);
1260 if(volume_info.password)
1261 kfree(volume_info.password);
1262 FreeXid(xid);
1263 return -EINVAL;
1264 }
1265
1266 /* this is needed for ASCII cp to Unicode converts */
1267 if(volume_info.iocharset == NULL) {
1268 cifs_sb->local_nls = load_nls_default();
1269 /* load_nls_default can not return null */
1270 } else {
1271 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1272 if(cifs_sb->local_nls == NULL) {
1273 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1274 if(volume_info.UNC)
1275 kfree(volume_info.UNC);
1276 if(volume_info.password)
1277 kfree(volume_info.password);
1278 FreeXid(xid);
1279 return -ELIBACC;
1280 }
1281 }
1282
1283 if(address_type == AF_INET)
1284 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1285 NULL /* no ipv6 addr */,
1286 volume_info.username, &srvTcp);
1287 else if(address_type == AF_INET6)
1288 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1289 &sin_server6.sin6_addr,
1290 volume_info.username, &srvTcp);
1291 else {
1292 if(volume_info.UNC)
1293 kfree(volume_info.UNC);
1294 if(volume_info.password)
1295 kfree(volume_info.password);
1296 FreeXid(xid);
1297 return -EINVAL;
1298 }
1299
1300
1301 if (srvTcp) {
1302 cFYI(1, ("Existing tcp session with server found "));
1303 } else { /* create socket */
1304 if(volume_info.port)
1305 sin_server.sin_port = htons(volume_info.port);
1306 else
1307 sin_server.sin_port = 0;
1308 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1309 if (rc < 0) {
1310 cERROR(1,
1311 ("Error connecting to IPv4 socket. Aborting operation"));
1312 if(csocket != NULL)
1313 sock_release(csocket);
1314 if(volume_info.UNC)
1315 kfree(volume_info.UNC);
1316 if(volume_info.password)
1317 kfree(volume_info.password);
1318 FreeXid(xid);
1319 return rc;
1320 }
1321
1322 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1323 if (srvTcp == NULL) {
1324 rc = -ENOMEM;
1325 sock_release(csocket);
1326 if(volume_info.UNC)
1327 kfree(volume_info.UNC);
1328 if(volume_info.password)
1329 kfree(volume_info.password);
1330 FreeXid(xid);
1331 return rc;
1332 } else {
1333 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1334 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1335 atomic_set(&srvTcp->inFlight,0);
1336 /* BB Add code for ipv6 case too */
1337 srvTcp->ssocket = csocket;
1338 srvTcp->protocolType = IPV4;
1339 init_waitqueue_head(&srvTcp->response_q);
1340 init_waitqueue_head(&srvTcp->request_q);
1341 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1342 /* at this point we are the only ones with the pointer
1343 to the struct since the kernel thread not created yet
1344 so no need to spinlock this init of tcpStatus */
1345 srvTcp->tcpStatus = CifsNew;
1346 init_MUTEX(&srvTcp->tcpSem);
1347 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1348 CLONE_FS | CLONE_FILES | CLONE_VM);
1349 if(rc < 0) {
1350 rc = -ENOMEM;
1351 sock_release(csocket);
1352 if(volume_info.UNC)
1353 kfree(volume_info.UNC);
1354 if(volume_info.password)
1355 kfree(volume_info.password);
1356 FreeXid(xid);
1357 return rc;
1358 } else
1359 rc = 0;
1360 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
ad009ac9 1361 srvTcp->sequence_number = 0;
1da177e4
LT
1362 }
1363 }
1364
1365 if (existingCifsSes) {
1366 pSesInfo = existingCifsSes;
1367 cFYI(1, ("Existing smb sess found "));
1368 if(volume_info.password)
1369 kfree(volume_info.password);
1370 /* volume_info.UNC freed at end of function */
1371 } else if (!rc) {
1372 cFYI(1, ("Existing smb sess not found "));
1373 pSesInfo = sesInfoAlloc();
1374 if (pSesInfo == NULL)
1375 rc = -ENOMEM;
1376 else {
1377 pSesInfo->server = srvTcp;
1378 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1379 NIPQUAD(sin_server.sin_addr.s_addr));
1380 }
1381
1382 if (!rc){
1383 /* volume_info.password freed at unmount */
1384 if (volume_info.password)
1385 pSesInfo->password = volume_info.password;
1386 if (volume_info.username)
1387 strncpy(pSesInfo->userName,
1388 volume_info.username,MAX_USERNAME_SIZE);
1389 if (volume_info.domainname)
1390 strncpy(pSesInfo->domainName,
1391 volume_info.domainname,MAX_USERNAME_SIZE);
1392 pSesInfo->linux_uid = volume_info.linux_uid;
1393 down(&pSesInfo->sesSem);
1394 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1395 up(&pSesInfo->sesSem);
1396 if(!rc)
1397 atomic_inc(&srvTcp->socketUseCount);
1398 } else
1399 if(volume_info.password)
1400 kfree(volume_info.password);
1401 }
1402
1403 /* search for existing tcon to this server share */
1404 if (!rc) {
1405 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1406 cifs_sb->rsize = volume_info.rsize;
1407 else
1408 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1409 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1410 cifs_sb->wsize = volume_info.wsize;
1411 else
1412 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1413 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1414 cifs_sb->rsize = PAGE_CACHE_SIZE;
1415 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1416 }
1417 cifs_sb->mnt_uid = volume_info.linux_uid;
1418 cifs_sb->mnt_gid = volume_info.linux_gid;
1419 cifs_sb->mnt_file_mode = volume_info.file_mode;
1420 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1421 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1422
1423 if(volume_info.noperm)
1424 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1425 if(volume_info.setuids)
1426 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1427 if(volume_info.server_ino)
1428 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
6a0b4824
SF
1429 if(volume_info.remap)
1430 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
1da177e4
LT
1431 if(volume_info.no_xattr)
1432 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1433 if(volume_info.direct_io) {
1434 cERROR(1,("mounting share using direct i/o"));
1435 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1436 }
1437
1438 tcon =
1439 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1440 volume_info.username);
1441 if (tcon) {
1442 cFYI(1, ("Found match on UNC path "));
1443 /* we can have only one retry value for a connection
1444 to a share so for resources mounted more than once
1445 to the same server share the last value passed in
1446 for the retry flag is used */
1447 tcon->retry = volume_info.retry;
1448 } else {
1449 tcon = tconInfoAlloc();
1450 if (tcon == NULL)
1451 rc = -ENOMEM;
1452 else {
1453 /* check for null share name ie connect to dfs root */
1454
1455 /* BB check if this works for exactly length three strings */
1456 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1457 && (strchr(volume_info.UNC + 3, '/') ==
1458 NULL)) {
1459 rc = connect_to_dfs_path(xid,
1460 pSesInfo,
1461 "",
1462 cifs_sb->
1463 local_nls);
1464 if(volume_info.UNC)
1465 kfree(volume_info.UNC);
1466 FreeXid(xid);
1467 return -ENODEV;
1468 } else {
1469 rc = CIFSTCon(xid, pSesInfo,
1470 volume_info.UNC,
1471 tcon, cifs_sb->local_nls);
1472 cFYI(1, ("CIFS Tcon rc = %d", rc));
1473 }
1474 if (!rc) {
1475 atomic_inc(&pSesInfo->inUse);
1476 tcon->retry = volume_info.retry;
1477 }
1478 }
1479 }
1480 }
1481 if(pSesInfo) {
1482 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1483 sb->s_maxbytes = (u64) 1 << 63;
1484 } else
1485 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1486 }
1487
1488 sb->s_time_gran = 100;
1489
1490/* on error free sesinfo and tcon struct if needed */
1491 if (rc) {
1492 /* if session setup failed, use count is zero but
1493 we still need to free cifsd thread */
1494 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1495 spin_lock(&GlobalMid_Lock);
1496 srvTcp->tcpStatus = CifsExiting;
1497 spin_unlock(&GlobalMid_Lock);
1498 if(srvTcp->tsk)
1499 send_sig(SIGKILL,srvTcp->tsk,1);
1500 }
1501 /* If find_unc succeeded then rc == 0 so we can not end */
1502 if (tcon) /* up accidently freeing someone elses tcon struct */
1503 tconInfoFree(tcon);
1504 if (existingCifsSes == NULL) {
1505 if (pSesInfo) {
1506 if ((pSesInfo->server) &&
1507 (pSesInfo->status == CifsGood)) {
1508 int temp_rc;
1509 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1510 /* if the socketUseCount is now zero */
1511 if((temp_rc == -ESHUTDOWN) &&
1512 (pSesInfo->server->tsk))
1513 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1514 } else
1515 cFYI(1, ("No session or bad tcon"));
1516 sesInfoFree(pSesInfo);
1517 /* pSesInfo = NULL; */
1518 }
1519 }
1520 } else {
1521 atomic_inc(&tcon->useCount);
1522 cifs_sb->tcon = tcon;
1523 tcon->ses = pSesInfo;
1524
1525 /* do not care if following two calls succeed - informational only */
1526 CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
1527 CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
1528 if (tcon->ses->capabilities & CAP_UNIX) {
1529 if(!CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls)) {
1530 if(!volume_info.no_psx_acl) {
1531 if(CIFS_UNIX_POSIX_ACL_CAP &
1532 le64_to_cpu(tcon->fsUnixInfo.Capability))
1533 cFYI(1,("server negotiated posix acl support"));
1534 sb->s_flags |= MS_POSIXACL;
1535 }
1536 }
1537 }
1538 }
1539
1540 /* volume_info.password is freed above when existing session found
1541 (in which case it is not needed anymore) but when new sesion is created
1542 the password ptr is put in the new session structure (in which case the
1543 password will be freed at unmount time) */
1544 if(volume_info.UNC)
1545 kfree(volume_info.UNC);
1546 FreeXid(xid);
1547 return rc;
1548}
1549
1550static int
1551CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1552 char session_key[CIFS_SESSION_KEY_SIZE],
1553 const struct nls_table *nls_codepage)
1554{
1555 struct smb_hdr *smb_buffer;
1556 struct smb_hdr *smb_buffer_response;
1557 SESSION_SETUP_ANDX *pSMB;
1558 SESSION_SETUP_ANDX *pSMBr;
1559 char *bcc_ptr;
1560 char *user;
1561 char *domain;
1562 int rc = 0;
1563 int remaining_words = 0;
1564 int bytes_returned = 0;
1565 int len;
1566 __u32 capabilities;
1567 __u16 count;
1568
1569 cFYI(1, ("In sesssetup "));
1570 if(ses == NULL)
1571 return -EINVAL;
1572 user = ses->userName;
1573 domain = ses->domainName;
1574 smb_buffer = cifs_buf_get();
1575 if (smb_buffer == NULL) {
1576 return -ENOMEM;
1577 }
1578 smb_buffer_response = smb_buffer;
1579 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1580
1581 /* send SMBsessionSetup here */
1582 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1583 NULL /* no tCon exists yet */ , 13 /* wct */ );
1584
1585 pSMB->req_no_secext.AndXCommand = 0xFF;
1586 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1587 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1588
1589 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1590 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1591
1592 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1593 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1594 if (ses->capabilities & CAP_UNICODE) {
1595 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1596 capabilities |= CAP_UNICODE;
1597 }
1598 if (ses->capabilities & CAP_STATUS32) {
1599 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1600 capabilities |= CAP_STATUS32;
1601 }
1602 if (ses->capabilities & CAP_DFS) {
1603 smb_buffer->Flags2 |= SMBFLG2_DFS;
1604 capabilities |= CAP_DFS;
1605 }
1606 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1607
1608 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1609 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1610
1611 pSMB->req_no_secext.CaseSensitivePasswordLength =
1612 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1613 bcc_ptr = pByteArea(smb_buffer);
1614 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1615 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1616 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1617 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1618
1619 if (ses->capabilities & CAP_UNICODE) {
1620 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1621 *bcc_ptr = 0;
1622 bcc_ptr++;
1623 }
1624 if(user == NULL)
1625 bytes_returned = 0; /* skill null user */
1626 else
1627 bytes_returned =
1628 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1629 nls_codepage);
1630 /* convert number of 16 bit words to bytes */
1631 bcc_ptr += 2 * bytes_returned;
1632 bcc_ptr += 2; /* trailing null */
1633 if (domain == NULL)
1634 bytes_returned =
1635 cifs_strtoUCS((wchar_t *) bcc_ptr,
1636 "CIFS_LINUX_DOM", 32, nls_codepage);
1637 else
1638 bytes_returned =
1639 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1640 nls_codepage);
1641 bcc_ptr += 2 * bytes_returned;
1642 bcc_ptr += 2;
1643 bytes_returned =
1644 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1645 32, nls_codepage);
1646 bcc_ptr += 2 * bytes_returned;
1647 bytes_returned =
1648 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1649 32, nls_codepage);
1650 bcc_ptr += 2 * bytes_returned;
1651 bcc_ptr += 2;
1652 bytes_returned =
1653 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1654 64, nls_codepage);
1655 bcc_ptr += 2 * bytes_returned;
1656 bcc_ptr += 2;
1657 } else {
1658 if(user != NULL) {
1659 strncpy(bcc_ptr, user, 200);
1660 bcc_ptr += strnlen(user, 200);
1661 }
1662 *bcc_ptr = 0;
1663 bcc_ptr++;
1664 if (domain == NULL) {
1665 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1666 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1667 } else {
1668 strncpy(bcc_ptr, domain, 64);
1669 bcc_ptr += strnlen(domain, 64);
1670 *bcc_ptr = 0;
1671 bcc_ptr++;
1672 }
1673 strcpy(bcc_ptr, "Linux version ");
1674 bcc_ptr += strlen("Linux version ");
1675 strcpy(bcc_ptr, system_utsname.release);
1676 bcc_ptr += strlen(system_utsname.release) + 1;
1677 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1678 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1679 }
1680 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1681 smb_buffer->smb_buf_length += count;
1682 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
1683
1684 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1685 &bytes_returned, 1);
1686 if (rc) {
1687/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1688 } else if ((smb_buffer_response->WordCount == 3)
1689 || (smb_buffer_response->WordCount == 4)) {
1690 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1691 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1692 if (action & GUEST_LOGIN)
1693 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
1694 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1695 cFYI(1, ("UID = %d ", ses->Suid));
1696 /* response can have either 3 or 4 word count - Samba sends 3 */
1697 bcc_ptr = pByteArea(smb_buffer_response);
1698 if ((pSMBr->resp.hdr.WordCount == 3)
1699 || ((pSMBr->resp.hdr.WordCount == 4)
1700 && (blob_len < pSMBr->resp.ByteCount))) {
1701 if (pSMBr->resp.hdr.WordCount == 4)
1702 bcc_ptr += blob_len;
1703
1704 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1705 if ((long) (bcc_ptr) % 2) {
1706 remaining_words =
1707 (BCC(smb_buffer_response) - 1) /2;
1708 bcc_ptr++; /* Unicode strings must be word aligned */
1709 } else {
1710 remaining_words =
1711 BCC(smb_buffer_response) / 2;
1712 }
1713 len =
1714 UniStrnlen((wchar_t *) bcc_ptr,
1715 remaining_words - 1);
1716/* We look for obvious messed up bcc or strings in response so we do not go off
1717 the end since (at least) WIN2K and Windows XP have a major bug in not null
1718 terminating last Unicode string in response */
1719 ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
1720 cifs_strfromUCS_le(ses->serverOS,
1721 (wchar_t *)bcc_ptr, len,nls_codepage);
1722 bcc_ptr += 2 * (len + 1);
1723 remaining_words -= len + 1;
1724 ses->serverOS[2 * len] = 0;
1725 ses->serverOS[1 + (2 * len)] = 0;
1726 if (remaining_words > 0) {
1727 len = UniStrnlen((wchar_t *)bcc_ptr,
1728 remaining_words-1);
1729 ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL);
1730 cifs_strfromUCS_le(ses->serverNOS,
1731 (wchar_t *)bcc_ptr,len,nls_codepage);
1732 bcc_ptr += 2 * (len + 1);
1733 ses->serverNOS[2 * len] = 0;
1734 ses->serverNOS[1 + (2 * len)] = 0;
1735 if(strncmp(ses->serverNOS,
1736 "NT LAN Manager 4",16) == 0) {
1737 cFYI(1,("NT4 server"));
1738 ses->flags |= CIFS_SES_NT4;
1739 }
1740 remaining_words -= len + 1;
1741 if (remaining_words > 0) {
1742 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
1743 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1744 ses->serverDomain =
1745 cifs_kcalloc(2*(len+1),GFP_KERNEL);
1746 cifs_strfromUCS_le(ses->serverDomain,
1747 (wchar_t *)bcc_ptr,len,nls_codepage);
1748 bcc_ptr += 2 * (len + 1);
1749 ses->serverDomain[2*len] = 0;
1750 ses->serverDomain[1+(2*len)] = 0;
1751 } /* else no more room so create dummy domain string */
1752 else
1753 ses->serverDomain =
1754 cifs_kcalloc(2,
1755 GFP_KERNEL);
1756 } else { /* no room so create dummy domain and NOS string */
1757 ses->serverDomain =
1758 cifs_kcalloc(2, GFP_KERNEL);
1759 ses->serverNOS =
1760 cifs_kcalloc(2, GFP_KERNEL);
1761 }
1762 } else { /* ASCII */
1763 len = strnlen(bcc_ptr, 1024);
1764 if (((long) bcc_ptr + len) - (long)
1765 pByteArea(smb_buffer_response)
1766 <= BCC(smb_buffer_response)) {
1767 ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
1768 strncpy(ses->serverOS,bcc_ptr, len);
1769
1770 bcc_ptr += len;
1771 bcc_ptr[0] = 0; /* null terminate the string */
1772 bcc_ptr++;
1773
1774 len = strnlen(bcc_ptr, 1024);
1775 ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
1776 strncpy(ses->serverNOS, bcc_ptr, len);
1777 bcc_ptr += len;
1778 bcc_ptr[0] = 0;
1779 bcc_ptr++;
1780
1781 len = strnlen(bcc_ptr, 1024);
1782 ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL);
1783 strncpy(ses->serverDomain, bcc_ptr, len);
1784 bcc_ptr += len;
1785 bcc_ptr[0] = 0;
1786 bcc_ptr++;
1787 } else
1788 cFYI(1,
1789 ("Variable field of length %d extends beyond end of smb ",
1790 len));
1791 }
1792 } else {
1793 cERROR(1,
1794 (" Security Blob Length extends beyond end of SMB"));
1795 }
1796 } else {
1797 cERROR(1,
1798 (" Invalid Word count %d: ",
1799 smb_buffer_response->WordCount));
1800 rc = -EIO;
1801 }
1802
1803 if (smb_buffer)
1804 cifs_buf_release(smb_buffer);
1805
1806 return rc;
1807}
1808
1809static int
1810CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1811 char *SecurityBlob,int SecurityBlobLength,
1812 const struct nls_table *nls_codepage)
1813{
1814 struct smb_hdr *smb_buffer;
1815 struct smb_hdr *smb_buffer_response;
1816 SESSION_SETUP_ANDX *pSMB;
1817 SESSION_SETUP_ANDX *pSMBr;
1818 char *bcc_ptr;
1819 char *user;
1820 char *domain;
1821 int rc = 0;
1822 int remaining_words = 0;
1823 int bytes_returned = 0;
1824 int len;
1825 __u32 capabilities;
1826 __u16 count;
1827
1828 cFYI(1, ("In spnego sesssetup "));
1829 if(ses == NULL)
1830 return -EINVAL;
1831 user = ses->userName;
1832 domain = ses->domainName;
1833
1834 smb_buffer = cifs_buf_get();
1835 if (smb_buffer == NULL) {
1836 return -ENOMEM;
1837 }
1838 smb_buffer_response = smb_buffer;
1839 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1840
1841 /* send SMBsessionSetup here */
1842 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1843 NULL /* no tCon exists yet */ , 12 /* wct */ );
1844 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
1845 pSMB->req.AndXCommand = 0xFF;
1846 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1847 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1848
1849 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1850 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1851
1852 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1853 CAP_EXTENDED_SECURITY;
1854 if (ses->capabilities & CAP_UNICODE) {
1855 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1856 capabilities |= CAP_UNICODE;
1857 }
1858 if (ses->capabilities & CAP_STATUS32) {
1859 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1860 capabilities |= CAP_STATUS32;
1861 }
1862 if (ses->capabilities & CAP_DFS) {
1863 smb_buffer->Flags2 |= SMBFLG2_DFS;
1864 capabilities |= CAP_DFS;
1865 }
1866 pSMB->req.Capabilities = cpu_to_le32(capabilities);
1867
1868 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
1869 bcc_ptr = pByteArea(smb_buffer);
1870 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
1871 bcc_ptr += SecurityBlobLength;
1872
1873 if (ses->capabilities & CAP_UNICODE) {
1874 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
1875 *bcc_ptr = 0;
1876 bcc_ptr++;
1877 }
1878 bytes_returned =
1879 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
1880 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
1881 bcc_ptr += 2; /* trailing null */
1882 if (domain == NULL)
1883 bytes_returned =
1884 cifs_strtoUCS((wchar_t *) bcc_ptr,
1885 "CIFS_LINUX_DOM", 32, nls_codepage);
1886 else
1887 bytes_returned =
1888 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1889 nls_codepage);
1890 bcc_ptr += 2 * bytes_returned;
1891 bcc_ptr += 2;
1892 bytes_returned =
1893 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1894 32, nls_codepage);
1895 bcc_ptr += 2 * bytes_returned;
1896 bytes_returned =
1897 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
1898 nls_codepage);
1899 bcc_ptr += 2 * bytes_returned;
1900 bcc_ptr += 2;
1901 bytes_returned =
1902 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1903 64, nls_codepage);
1904 bcc_ptr += 2 * bytes_returned;
1905 bcc_ptr += 2;
1906 } else {
1907 strncpy(bcc_ptr, user, 200);
1908 bcc_ptr += strnlen(user, 200);
1909 *bcc_ptr = 0;
1910 bcc_ptr++;
1911 if (domain == NULL) {
1912 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1913 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1914 } else {
1915 strncpy(bcc_ptr, domain, 64);
1916 bcc_ptr += strnlen(domain, 64);
1917 *bcc_ptr = 0;
1918 bcc_ptr++;
1919 }
1920 strcpy(bcc_ptr, "Linux version ");
1921 bcc_ptr += strlen("Linux version ");
1922 strcpy(bcc_ptr, system_utsname.release);
1923 bcc_ptr += strlen(system_utsname.release) + 1;
1924 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1925 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1926 }
1927 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1928 smb_buffer->smb_buf_length += count;
1929 pSMB->req.ByteCount = cpu_to_le16(count);
1930
1931 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1932 &bytes_returned, 1);
1933 if (rc) {
1934/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
1935 } else if ((smb_buffer_response->WordCount == 3)
1936 || (smb_buffer_response->WordCount == 4)) {
1937 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1938 __u16 blob_len =
1939 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1940 if (action & GUEST_LOGIN)
1941 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
1942 if (ses) {
1943 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1944 cFYI(1, ("UID = %d ", ses->Suid));
1945 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
1946
1947 /* BB Fix below to make endian neutral !! */
1948
1949 if ((pSMBr->resp.hdr.WordCount == 3)
1950 || ((pSMBr->resp.hdr.WordCount == 4)
1951 && (blob_len <
1952 pSMBr->resp.ByteCount))) {
1953 if (pSMBr->resp.hdr.WordCount == 4) {
1954 bcc_ptr +=
1955 blob_len;
1956 cFYI(1,
1957 ("Security Blob Length %d ",
1958 blob_len));
1959 }
1960
1961 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1962 if ((long) (bcc_ptr) % 2) {
1963 remaining_words =
1964 (BCC(smb_buffer_response)
1965 - 1) / 2;
1966 bcc_ptr++; /* Unicode strings must be word aligned */
1967 } else {
1968 remaining_words =
1969 BCC
1970 (smb_buffer_response) / 2;
1971 }
1972 len =
1973 UniStrnlen((wchar_t *) bcc_ptr,
1974 remaining_words - 1);
1975/* We look for obvious messed up bcc or strings in response so we do not go off
1976 the end since (at least) WIN2K and Windows XP have a major bug in not null
1977 terminating last Unicode string in response */
1978 ses->serverOS =
1979 cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
1980 cifs_strfromUCS_le(ses->serverOS,
1981 (wchar_t *)
1982 bcc_ptr, len,
1983 nls_codepage);
1984 bcc_ptr += 2 * (len + 1);
1985 remaining_words -= len + 1;
1986 ses->serverOS[2 * len] = 0;
1987 ses->serverOS[1 + (2 * len)] = 0;
1988 if (remaining_words > 0) {
1989 len = UniStrnlen((wchar_t *)bcc_ptr,
1990 remaining_words
1991 - 1);
1992 ses->serverNOS =
1993 cifs_kcalloc(2 * (len + 1),
1994 GFP_KERNEL);
1995 cifs_strfromUCS_le(ses->serverNOS,
1996 (wchar_t *)bcc_ptr,
1997 len,
1998 nls_codepage);
1999 bcc_ptr += 2 * (len + 1);
2000 ses->serverNOS[2 * len] = 0;
2001 ses->serverNOS[1 + (2 * len)] = 0;
2002 remaining_words -= len + 1;
2003 if (remaining_words > 0) {
2004 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2005 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2006 ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL);
2007 cifs_strfromUCS_le(ses->serverDomain,
2008 (wchar_t *)bcc_ptr,
2009 len,
2010 nls_codepage);
2011 bcc_ptr += 2*(len+1);
2012 ses->serverDomain[2*len] = 0;
2013 ses->serverDomain[1+(2*len)] = 0;
2014 } /* else no more room so create dummy domain string */
2015 else
2016 ses->serverDomain =
2017 cifs_kcalloc(2,GFP_KERNEL);
2018 } else { /* no room so create dummy domain and NOS string */
2019 ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
2020 ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
2021 }
2022 } else { /* ASCII */
2023
2024 len = strnlen(bcc_ptr, 1024);
2025 if (((long) bcc_ptr + len) - (long)
2026 pByteArea(smb_buffer_response)
2027 <= BCC(smb_buffer_response)) {
2028 ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL);
2029 strncpy(ses->serverOS, bcc_ptr, len);
2030
2031 bcc_ptr += len;
2032 bcc_ptr[0] = 0; /* null terminate the string */
2033 bcc_ptr++;
2034
2035 len = strnlen(bcc_ptr, 1024);
2036 ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
2037 strncpy(ses->serverNOS, bcc_ptr, len);
2038 bcc_ptr += len;
2039 bcc_ptr[0] = 0;
2040 bcc_ptr++;
2041
2042 len = strnlen(bcc_ptr, 1024);
2043 ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL);
2044 strncpy(ses->serverDomain, bcc_ptr, len);
2045 bcc_ptr += len;
2046 bcc_ptr[0] = 0;
2047 bcc_ptr++;
2048 } else
2049 cFYI(1,
2050 ("Variable field of length %d extends beyond end of smb ",
2051 len));
2052 }
2053 } else {
2054 cERROR(1,
2055 (" Security Blob Length extends beyond end of SMB"));
2056 }
2057 } else {
2058 cERROR(1, ("No session structure passed in."));
2059 }
2060 } else {
2061 cERROR(1,
2062 (" Invalid Word count %d: ",
2063 smb_buffer_response->WordCount));
2064 rc = -EIO;
2065 }
2066
2067 if (smb_buffer)
2068 cifs_buf_release(smb_buffer);
2069
2070 return rc;
2071}
2072
2073static int
2074CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2075 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2076 const struct nls_table *nls_codepage)
2077{
2078 struct smb_hdr *smb_buffer;
2079 struct smb_hdr *smb_buffer_response;
2080 SESSION_SETUP_ANDX *pSMB;
2081 SESSION_SETUP_ANDX *pSMBr;
2082 char *bcc_ptr;
2083 char *domain;
2084 int rc = 0;
2085 int remaining_words = 0;
2086 int bytes_returned = 0;
2087 int len;
2088 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2089 PNEGOTIATE_MESSAGE SecurityBlob;
2090 PCHALLENGE_MESSAGE SecurityBlob2;
2091 __u32 negotiate_flags, capabilities;
2092 __u16 count;
2093
2094 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2095 if(ses == NULL)
2096 return -EINVAL;
2097 domain = ses->domainName;
2098 *pNTLMv2_flag = FALSE;
2099 smb_buffer = cifs_buf_get();
2100 if (smb_buffer == NULL) {
2101 return -ENOMEM;
2102 }
2103 smb_buffer_response = smb_buffer;
2104 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2105 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2106
2107 /* send SMBsessionSetup here */
2108 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2109 NULL /* no tCon exists yet */ , 12 /* wct */ );
2110 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2111 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2112
2113 pSMB->req.AndXCommand = 0xFF;
2114 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2115 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2116
2117 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2118 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2119
2120 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2121 CAP_EXTENDED_SECURITY;
2122 if (ses->capabilities & CAP_UNICODE) {
2123 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2124 capabilities |= CAP_UNICODE;
2125 }
2126 if (ses->capabilities & CAP_STATUS32) {
2127 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2128 capabilities |= CAP_STATUS32;
2129 }
2130 if (ses->capabilities & CAP_DFS) {
2131 smb_buffer->Flags2 |= SMBFLG2_DFS;
2132 capabilities |= CAP_DFS;
2133 }
2134 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2135
2136 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2137 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2138 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2139 SecurityBlob->MessageType = NtLmNegotiate;
2140 negotiate_flags =
2141 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2142 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2143 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2144 if(sign_CIFS_PDUs)
2145 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2146 if(ntlmv2_support)
2147 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2148 /* setup pointers to domain name and workstation name */
2149 bcc_ptr += SecurityBlobLength;
2150
2151 SecurityBlob->WorkstationName.Buffer = 0;
2152 SecurityBlob->WorkstationName.Length = 0;
2153 SecurityBlob->WorkstationName.MaximumLength = 0;
2154
2155 if (domain == NULL) {
2156 SecurityBlob->DomainName.Buffer = 0;
2157 SecurityBlob->DomainName.Length = 0;
2158 SecurityBlob->DomainName.MaximumLength = 0;
2159 } else {
2160 __u16 len;
2161 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2162 strncpy(bcc_ptr, domain, 63);
2163 len = strnlen(domain, 64);
2164 SecurityBlob->DomainName.MaximumLength =
2165 cpu_to_le16(len);
2166 SecurityBlob->DomainName.Buffer =
2167 cpu_to_le32((long) &SecurityBlob->
2168 DomainString -
2169 (long) &SecurityBlob->Signature);
2170 bcc_ptr += len;
2171 SecurityBlobLength += len;
2172 SecurityBlob->DomainName.Length =
2173 cpu_to_le16(len);
2174 }
2175 if (ses->capabilities & CAP_UNICODE) {
2176 if ((long) bcc_ptr % 2) {
2177 *bcc_ptr = 0;
2178 bcc_ptr++;
2179 }
2180
2181 bytes_returned =
2182 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2183 32, nls_codepage);
2184 bcc_ptr += 2 * bytes_returned;
2185 bytes_returned =
2186 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2187 nls_codepage);
2188 bcc_ptr += 2 * bytes_returned;
2189 bcc_ptr += 2; /* null terminate Linux version */
2190 bytes_returned =
2191 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2192 64, nls_codepage);
2193 bcc_ptr += 2 * bytes_returned;
2194 *(bcc_ptr + 1) = 0;
2195 *(bcc_ptr + 2) = 0;
2196 bcc_ptr += 2; /* null terminate network opsys string */
2197 *(bcc_ptr + 1) = 0;
2198 *(bcc_ptr + 2) = 0;
2199 bcc_ptr += 2; /* null domain */
2200 } else { /* ASCII */
2201 strcpy(bcc_ptr, "Linux version ");
2202 bcc_ptr += strlen("Linux version ");
2203 strcpy(bcc_ptr, system_utsname.release);
2204 bcc_ptr += strlen(system_utsname.release) + 1;
2205 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2206 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2207 bcc_ptr++; /* empty domain field */
2208 *bcc_ptr = 0;
2209 }
2210 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2211 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2212 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2213 smb_buffer->smb_buf_length += count;
2214 pSMB->req.ByteCount = cpu_to_le16(count);
2215
2216 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2217 &bytes_returned, 1);
2218
2219 if (smb_buffer_response->Status.CifsError ==
2220 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2221 rc = 0;
2222
2223 if (rc) {
2224/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2225 } else if ((smb_buffer_response->WordCount == 3)
2226 || (smb_buffer_response->WordCount == 4)) {
2227 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2228 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2229
2230 if (action & GUEST_LOGIN)
2231 cFYI(1, (" Guest login"));
2232 /* Do we want to set anything in SesInfo struct when guest login? */
2233
2234 bcc_ptr = pByteArea(smb_buffer_response);
2235 /* response can have either 3 or 4 word count - Samba sends 3 */
2236
2237 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2238 if (SecurityBlob2->MessageType != NtLmChallenge) {
2239 cFYI(1,
2240 ("Unexpected NTLMSSP message type received %d",
2241 SecurityBlob2->MessageType));
2242 } else if (ses) {
2243 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2244 cFYI(1, ("UID = %d ", ses->Suid));
2245 if ((pSMBr->resp.hdr.WordCount == 3)
2246 || ((pSMBr->resp.hdr.WordCount == 4)
2247 && (blob_len <
2248 pSMBr->resp.ByteCount))) {
2249
2250 if (pSMBr->resp.hdr.WordCount == 4) {
2251 bcc_ptr += blob_len;
2252 cFYI(1,
2253 ("Security Blob Length %d ",
2254 blob_len));
2255 }
2256
2257 cFYI(1, ("NTLMSSP Challenge rcvd "));
2258
2259 memcpy(ses->server->cryptKey,
2260 SecurityBlob2->Challenge,
2261 CIFS_CRYPTO_KEY_SIZE);
2262 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2263 *pNTLMv2_flag = TRUE;
2264
2265 if((SecurityBlob2->NegotiateFlags &
2266 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2267 || (sign_CIFS_PDUs > 1))
2268 ses->server->secMode |=
2269 SECMODE_SIGN_REQUIRED;
2270 if ((SecurityBlob2->NegotiateFlags &
2271 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2272 ses->server->secMode |=
2273 SECMODE_SIGN_ENABLED;
2274
2275 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2276 if ((long) (bcc_ptr) % 2) {
2277 remaining_words =
2278 (BCC(smb_buffer_response)
2279 - 1) / 2;
2280 bcc_ptr++; /* Unicode strings must be word aligned */
2281 } else {
2282 remaining_words =
2283 BCC
2284 (smb_buffer_response) / 2;
2285 }
2286 len =
2287 UniStrnlen((wchar_t *) bcc_ptr,
2288 remaining_words - 1);
2289/* We look for obvious messed up bcc or strings in response so we do not go off
2290 the end since (at least) WIN2K and Windows XP have a major bug in not null
2291 terminating last Unicode string in response */
2292 ses->serverOS =
2293 cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
2294 cifs_strfromUCS_le(ses->serverOS,
2295 (wchar_t *)
2296 bcc_ptr, len,
2297 nls_codepage);
2298 bcc_ptr += 2 * (len + 1);
2299 remaining_words -= len + 1;
2300 ses->serverOS[2 * len] = 0;
2301 ses->serverOS[1 + (2 * len)] = 0;
2302 if (remaining_words > 0) {
2303 len = UniStrnlen((wchar_t *)
2304 bcc_ptr,
2305 remaining_words
2306 - 1);
2307 ses->serverNOS =
2308 cifs_kcalloc(2 * (len + 1),
2309 GFP_KERNEL);
2310 cifs_strfromUCS_le(ses->
2311 serverNOS,
2312 (wchar_t *)
2313 bcc_ptr,
2314 len,
2315 nls_codepage);
2316 bcc_ptr += 2 * (len + 1);
2317 ses->serverNOS[2 * len] = 0;
2318 ses->serverNOS[1 +
2319 (2 * len)] = 0;
2320 remaining_words -= len + 1;
2321 if (remaining_words > 0) {
2322 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2323 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2324 ses->serverDomain =
2325 cifs_kcalloc(2 *
2326 (len +
2327 1),
2328 GFP_KERNEL);
2329 cifs_strfromUCS_le
2330 (ses->
2331 serverDomain,
2332 (wchar_t *)
2333 bcc_ptr, len,
2334 nls_codepage);
2335 bcc_ptr +=
2336 2 * (len + 1);
2337 ses->
2338 serverDomain[2
2339 * len]
2340 = 0;
2341 ses->
2342 serverDomain[1
2343 +
2344 (2
2345 *
2346 len)]
2347 = 0;
2348 } /* else no more room so create dummy domain string */
2349 else
2350 ses->serverDomain =
2351 cifs_kcalloc(2,
2352 GFP_KERNEL);
2353 } else { /* no room so create dummy domain and NOS string */
2354 ses->serverDomain =
2355 cifs_kcalloc(2, GFP_KERNEL);
2356 ses->serverNOS =
2357 cifs_kcalloc(2, GFP_KERNEL);
2358 }
2359 } else { /* ASCII */
2360 len = strnlen(bcc_ptr, 1024);
2361 if (((long) bcc_ptr + len) - (long)
2362 pByteArea(smb_buffer_response)
2363 <= BCC(smb_buffer_response)) {
2364 ses->serverOS =
2365 cifs_kcalloc(len + 1,
2366 GFP_KERNEL);
2367 strncpy(ses->serverOS,
2368 bcc_ptr, len);
2369
2370 bcc_ptr += len;
2371 bcc_ptr[0] = 0; /* null terminate string */
2372 bcc_ptr++;
2373
2374 len = strnlen(bcc_ptr, 1024);
2375 ses->serverNOS =
2376 cifs_kcalloc(len + 1,
2377 GFP_KERNEL);
2378 strncpy(ses->serverNOS, bcc_ptr, len);
2379 bcc_ptr += len;
2380 bcc_ptr[0] = 0;
2381 bcc_ptr++;
2382
2383 len = strnlen(bcc_ptr, 1024);
2384 ses->serverDomain =
2385 cifs_kcalloc(len + 1,
2386 GFP_KERNEL);
2387 strncpy(ses->serverDomain, bcc_ptr, len);
2388 bcc_ptr += len;
2389 bcc_ptr[0] = 0;
2390 bcc_ptr++;
2391 } else
2392 cFYI(1,
2393 ("Variable field of length %d extends beyond end of smb ",
2394 len));
2395 }
2396 } else {
2397 cERROR(1,
2398 (" Security Blob Length extends beyond end of SMB"));
2399 }
2400 } else {
2401 cERROR(1, ("No session structure passed in."));
2402 }
2403 } else {
2404 cERROR(1,
2405 (" Invalid Word count %d: ",
2406 smb_buffer_response->WordCount));
2407 rc = -EIO;
2408 }
2409
2410 if (smb_buffer)
2411 cifs_buf_release(smb_buffer);
2412
2413 return rc;
2414}
2415static int
2416CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2417 char *ntlm_session_key, int ntlmv2_flag,
2418 const struct nls_table *nls_codepage)
2419{
2420 struct smb_hdr *smb_buffer;
2421 struct smb_hdr *smb_buffer_response;
2422 SESSION_SETUP_ANDX *pSMB;
2423 SESSION_SETUP_ANDX *pSMBr;
2424 char *bcc_ptr;
2425 char *user;
2426 char *domain;
2427 int rc = 0;
2428 int remaining_words = 0;
2429 int bytes_returned = 0;
2430 int len;
2431 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2432 PAUTHENTICATE_MESSAGE SecurityBlob;
2433 __u32 negotiate_flags, capabilities;
2434 __u16 count;
2435
2436 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2437 if(ses == NULL)
2438 return -EINVAL;
2439 user = ses->userName;
2440 domain = ses->domainName;
2441 smb_buffer = cifs_buf_get();
2442 if (smb_buffer == NULL) {
2443 return -ENOMEM;
2444 }
2445 smb_buffer_response = smb_buffer;
2446 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2447 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2448
2449 /* send SMBsessionSetup here */
2450 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2451 NULL /* no tCon exists yet */ , 12 /* wct */ );
2452 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2453 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2454 pSMB->req.AndXCommand = 0xFF;
2455 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2456 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2457
2458 pSMB->req.hdr.Uid = ses->Suid;
2459
2460 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2461 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2462
2463 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2464 CAP_EXTENDED_SECURITY;
2465 if (ses->capabilities & CAP_UNICODE) {
2466 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2467 capabilities |= CAP_UNICODE;
2468 }
2469 if (ses->capabilities & CAP_STATUS32) {
2470 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2471 capabilities |= CAP_STATUS32;
2472 }
2473 if (ses->capabilities & CAP_DFS) {
2474 smb_buffer->Flags2 |= SMBFLG2_DFS;
2475 capabilities |= CAP_DFS;
2476 }
2477 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2478
2479 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2480 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2481 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2482 SecurityBlob->MessageType = NtLmAuthenticate;
2483 bcc_ptr += SecurityBlobLength;
2484 negotiate_flags =
2485 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2486 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2487 0x80000000 | NTLMSSP_NEGOTIATE_128;
2488 if(sign_CIFS_PDUs)
2489 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2490 if(ntlmv2_flag)
2491 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2492
2493/* setup pointers to domain name and workstation name */
2494
2495 SecurityBlob->WorkstationName.Buffer = 0;
2496 SecurityBlob->WorkstationName.Length = 0;
2497 SecurityBlob->WorkstationName.MaximumLength = 0;
2498 SecurityBlob->SessionKey.Length = 0;
2499 SecurityBlob->SessionKey.MaximumLength = 0;
2500 SecurityBlob->SessionKey.Buffer = 0;
2501
2502 SecurityBlob->LmChallengeResponse.Length = 0;
2503 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2504 SecurityBlob->LmChallengeResponse.Buffer = 0;
2505
2506 SecurityBlob->NtChallengeResponse.Length =
2507 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2508 SecurityBlob->NtChallengeResponse.MaximumLength =
2509 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2510 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2511 SecurityBlob->NtChallengeResponse.Buffer =
2512 cpu_to_le32(SecurityBlobLength);
2513 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2514 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2515
2516 if (ses->capabilities & CAP_UNICODE) {
2517 if (domain == NULL) {
2518 SecurityBlob->DomainName.Buffer = 0;
2519 SecurityBlob->DomainName.Length = 0;
2520 SecurityBlob->DomainName.MaximumLength = 0;
2521 } else {
2522 __u16 len =
2523 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2524 nls_codepage);
2525 len *= 2;
2526 SecurityBlob->DomainName.MaximumLength =
2527 cpu_to_le16(len);
2528 SecurityBlob->DomainName.Buffer =
2529 cpu_to_le32(SecurityBlobLength);
2530 bcc_ptr += len;
2531 SecurityBlobLength += len;
2532 SecurityBlob->DomainName.Length =
2533 cpu_to_le16(len);
2534 }
2535 if (user == NULL) {
2536 SecurityBlob->UserName.Buffer = 0;
2537 SecurityBlob->UserName.Length = 0;
2538 SecurityBlob->UserName.MaximumLength = 0;
2539 } else {
2540 __u16 len =
2541 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2542 nls_codepage);
2543 len *= 2;
2544 SecurityBlob->UserName.MaximumLength =
2545 cpu_to_le16(len);
2546 SecurityBlob->UserName.Buffer =
2547 cpu_to_le32(SecurityBlobLength);
2548 bcc_ptr += len;
2549 SecurityBlobLength += len;
2550 SecurityBlob->UserName.Length =
2551 cpu_to_le16(len);
2552 }
2553
2554 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2555 SecurityBlob->WorkstationName.Length *= 2;
2556 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2557 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2558 bcc_ptr += SecurityBlob->WorkstationName.Length;
2559 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2560 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2561
2562 if ((long) bcc_ptr % 2) {
2563 *bcc_ptr = 0;
2564 bcc_ptr++;
2565 }
2566 bytes_returned =
2567 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2568 32, nls_codepage);
2569 bcc_ptr += 2 * bytes_returned;
2570 bytes_returned =
2571 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2572 nls_codepage);
2573 bcc_ptr += 2 * bytes_returned;
2574 bcc_ptr += 2; /* null term version string */
2575 bytes_returned =
2576 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2577 64, nls_codepage);
2578 bcc_ptr += 2 * bytes_returned;
2579 *(bcc_ptr + 1) = 0;
2580 *(bcc_ptr + 2) = 0;
2581 bcc_ptr += 2; /* null terminate network opsys string */
2582 *(bcc_ptr + 1) = 0;
2583 *(bcc_ptr + 2) = 0;
2584 bcc_ptr += 2; /* null domain */
2585 } else { /* ASCII */
2586 if (domain == NULL) {
2587 SecurityBlob->DomainName.Buffer = 0;
2588 SecurityBlob->DomainName.Length = 0;
2589 SecurityBlob->DomainName.MaximumLength = 0;
2590 } else {
2591 __u16 len;
2592 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2593 strncpy(bcc_ptr, domain, 63);
2594 len = strnlen(domain, 64);
2595 SecurityBlob->DomainName.MaximumLength =
2596 cpu_to_le16(len);
2597 SecurityBlob->DomainName.Buffer =
2598 cpu_to_le32(SecurityBlobLength);
2599 bcc_ptr += len;
2600 SecurityBlobLength += len;
2601 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2602 }
2603 if (user == NULL) {
2604 SecurityBlob->UserName.Buffer = 0;
2605 SecurityBlob->UserName.Length = 0;
2606 SecurityBlob->UserName.MaximumLength = 0;
2607 } else {
2608 __u16 len;
2609 strncpy(bcc_ptr, user, 63);
2610 len = strnlen(user, 64);
2611 SecurityBlob->UserName.MaximumLength =
2612 cpu_to_le16(len);
2613 SecurityBlob->UserName.Buffer =
2614 cpu_to_le32(SecurityBlobLength);
2615 bcc_ptr += len;
2616 SecurityBlobLength += len;
2617 SecurityBlob->UserName.Length = cpu_to_le16(len);
2618 }
2619 /* BB fill in our workstation name if known BB */
2620
2621 strcpy(bcc_ptr, "Linux version ");
2622 bcc_ptr += strlen("Linux version ");
2623 strcpy(bcc_ptr, system_utsname.release);
2624 bcc_ptr += strlen(system_utsname.release) + 1;
2625 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2626 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2627 bcc_ptr++; /* null domain */
2628 *bcc_ptr = 0;
2629 }
2630 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2631 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2632 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2633 smb_buffer->smb_buf_length += count;
2634 pSMB->req.ByteCount = cpu_to_le16(count);
2635
2636 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2637 &bytes_returned, 1);
2638 if (rc) {
2639/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2640 } else if ((smb_buffer_response->WordCount == 3)
2641 || (smb_buffer_response->WordCount == 4)) {
2642 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2643 __u16 blob_len =
2644 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2645 if (action & GUEST_LOGIN)
2646 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2647/* if(SecurityBlob2->MessageType != NtLm??){
2648 cFYI("Unexpected message type on auth response is %d "));
2649 } */
2650 if (ses) {
2651 cFYI(1,
2652 ("Does UID on challenge %d match auth response UID %d ",
2653 ses->Suid, smb_buffer_response->Uid));
2654 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2655 bcc_ptr = pByteArea(smb_buffer_response);
2656 /* response can have either 3 or 4 word count - Samba sends 3 */
2657 if ((pSMBr->resp.hdr.WordCount == 3)
2658 || ((pSMBr->resp.hdr.WordCount == 4)
2659 && (blob_len <
2660 pSMBr->resp.ByteCount))) {
2661 if (pSMBr->resp.hdr.WordCount == 4) {
2662 bcc_ptr +=
2663 blob_len;
2664 cFYI(1,
2665 ("Security Blob Length %d ",
2666 blob_len));
2667 }
2668
2669 cFYI(1,
2670 ("NTLMSSP response to Authenticate "));
2671
2672 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2673 if ((long) (bcc_ptr) % 2) {
2674 remaining_words =
2675 (BCC(smb_buffer_response)
2676 - 1) / 2;
2677 bcc_ptr++; /* Unicode strings must be word aligned */
2678 } else {
2679 remaining_words = BCC(smb_buffer_response) / 2;
2680 }
2681 len =
2682 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2683/* We look for obvious messed up bcc or strings in response so we do not go off
2684 the end since (at least) WIN2K and Windows XP have a major bug in not null
2685 terminating last Unicode string in response */
2686 ses->serverOS =
2687 cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
2688 cifs_strfromUCS_le(ses->serverOS,
2689 (wchar_t *)
2690 bcc_ptr, len,
2691 nls_codepage);
2692 bcc_ptr += 2 * (len + 1);
2693 remaining_words -= len + 1;
2694 ses->serverOS[2 * len] = 0;
2695 ses->serverOS[1 + (2 * len)] = 0;
2696 if (remaining_words > 0) {
2697 len = UniStrnlen((wchar_t *)
2698 bcc_ptr,
2699 remaining_words
2700 - 1);
2701 ses->serverNOS =
2702 cifs_kcalloc(2 * (len + 1),
2703 GFP_KERNEL);
2704 cifs_strfromUCS_le(ses->
2705 serverNOS,
2706 (wchar_t *)
2707 bcc_ptr,
2708 len,
2709 nls_codepage);
2710 bcc_ptr += 2 * (len + 1);
2711 ses->serverNOS[2 * len] = 0;
2712 ses->serverNOS[1+(2*len)] = 0;
2713 remaining_words -= len + 1;
2714 if (remaining_words > 0) {
2715 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2716 /* last string not always null terminated (e.g. for Windows XP & 2000) */
2717 ses->serverDomain =
2718 cifs_kcalloc(2 *
2719 (len +
2720 1),
2721 GFP_KERNEL);
2722 cifs_strfromUCS_le
2723 (ses->
2724 serverDomain,
2725 (wchar_t *)
2726 bcc_ptr, len,
2727 nls_codepage);
2728 bcc_ptr +=
2729 2 * (len + 1);
2730 ses->
2731 serverDomain[2
2732 * len]
2733 = 0;
2734 ses->
2735 serverDomain[1
2736 +
2737 (2
2738 *
2739 len)]
2740 = 0;
2741 } /* else no more room so create dummy domain string */
2742 else
2743 ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL);
2744 } else { /* no room so create dummy domain and NOS string */
2745 ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
2746 ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
2747 }
2748 } else { /* ASCII */
2749 len = strnlen(bcc_ptr, 1024);
2750 if (((long) bcc_ptr + len) -
2751 (long) pByteArea(smb_buffer_response)
2752 <= BCC(smb_buffer_response)) {
2753 ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
2754 strncpy(ses->serverOS,bcc_ptr, len);
2755
2756 bcc_ptr += len;
2757 bcc_ptr[0] = 0; /* null terminate the string */
2758 bcc_ptr++;
2759
2760 len = strnlen(bcc_ptr, 1024);
2761 ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL);
2762 strncpy(ses->serverNOS, bcc_ptr, len);
2763 bcc_ptr += len;
2764 bcc_ptr[0] = 0;
2765 bcc_ptr++;
2766
2767 len = strnlen(bcc_ptr, 1024);
2768 ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL);
2769 strncpy(ses->serverDomain, bcc_ptr, len);
2770 bcc_ptr += len;
2771 bcc_ptr[0] = 0;
2772 bcc_ptr++;
2773 } else
2774 cFYI(1,
2775 ("Variable field of length %d extends beyond end of smb ",
2776 len));
2777 }
2778 } else {
2779 cERROR(1,
2780 (" Security Blob Length extends beyond end of SMB"));
2781 }
2782 } else {
2783 cERROR(1, ("No session structure passed in."));
2784 }
2785 } else {
2786 cERROR(1,
2787 (" Invalid Word count %d: ",
2788 smb_buffer_response->WordCount));
2789 rc = -EIO;
2790 }
2791
2792 if (smb_buffer)
2793 cifs_buf_release(smb_buffer);
2794
2795 return rc;
2796}
2797
2798int
2799CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2800 const char *tree, struct cifsTconInfo *tcon,
2801 const struct nls_table *nls_codepage)
2802{
2803 struct smb_hdr *smb_buffer;
2804 struct smb_hdr *smb_buffer_response;
2805 TCONX_REQ *pSMB;
2806 TCONX_RSP *pSMBr;
2807 unsigned char *bcc_ptr;
2808 int rc = 0;
2809 int length;
2810 __u16 count;
2811
2812 if (ses == NULL)
2813 return -EIO;
2814
2815 smb_buffer = cifs_buf_get();
2816 if (smb_buffer == NULL) {
2817 return -ENOMEM;
2818 }
2819 smb_buffer_response = smb_buffer;
2820
2821 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
2822 NULL /*no tid */ , 4 /*wct */ );
2823 smb_buffer->Uid = ses->Suid;
2824 pSMB = (TCONX_REQ *) smb_buffer;
2825 pSMBr = (TCONX_RSP *) smb_buffer_response;
2826
2827 pSMB->AndXCommand = 0xFF;
2828 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
2829 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
2830 bcc_ptr = &pSMB->Password[0];
2831 bcc_ptr++; /* skip password */
2832
2833 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2834 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2835
2836 if (ses->capabilities & CAP_STATUS32) {
2837 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2838 }
2839 if (ses->capabilities & CAP_DFS) {
2840 smb_buffer->Flags2 |= SMBFLG2_DFS;
2841 }
2842 if (ses->capabilities & CAP_UNICODE) {
2843 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2844 length =
2845 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
2846 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
2847 bcc_ptr += 2; /* skip trailing null */
2848 } else { /* ASCII */
2849
2850 strcpy(bcc_ptr, tree);
2851 bcc_ptr += strlen(tree) + 1;
2852 }
2853 strcpy(bcc_ptr, "?????");
2854 bcc_ptr += strlen("?????");
2855 bcc_ptr += 1;
2856 count = bcc_ptr - &pSMB->Password[0];
2857 pSMB->hdr.smb_buf_length += count;
2858 pSMB->ByteCount = cpu_to_le16(count);
2859
2860 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
2861
2862 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
2863 /* above now done in SendReceive */
2864 if ((rc == 0) && (tcon != NULL)) {
2865 tcon->tidStatus = CifsGood;
2866 tcon->tid = smb_buffer_response->Tid;
2867 bcc_ptr = pByteArea(smb_buffer_response);
2868 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
2869 /* skip service field (NB: this field is always ASCII) */
2870 bcc_ptr += length + 1;
2871 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
2872 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2873 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
2874 if ((bcc_ptr + (2 * length)) -
2875 pByteArea(smb_buffer_response) <=
2876 BCC(smb_buffer_response)) {
2877 if(tcon->nativeFileSystem)
2878 kfree(tcon->nativeFileSystem);
2879 tcon->nativeFileSystem =
2880 cifs_kcalloc(length + 2, GFP_KERNEL);
2881 cifs_strfromUCS_le(tcon->nativeFileSystem,
2882 (wchar_t *) bcc_ptr,
2883 length, nls_codepage);
2884 bcc_ptr += 2 * length;
2885 bcc_ptr[0] = 0; /* null terminate the string */
2886 bcc_ptr[1] = 0;
2887 bcc_ptr += 2;
2888 }
2889 /* else do not bother copying these informational fields */
2890 } else {
2891 length = strnlen(bcc_ptr, 1024);
2892 if ((bcc_ptr + length) -
2893 pByteArea(smb_buffer_response) <=
2894 BCC(smb_buffer_response)) {
2895 if(tcon->nativeFileSystem)
2896 kfree(tcon->nativeFileSystem);
2897 tcon->nativeFileSystem =
2898 cifs_kcalloc(length + 1, GFP_KERNEL);
2899 strncpy(tcon->nativeFileSystem, bcc_ptr,
2900 length);
2901 }
2902 /* else do not bother copying these informational fields */
2903 }
2904 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
2905 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
2906 } else if ((rc == 0) && tcon == NULL) {
2907 /* all we need to save for IPC$ connection */
2908 ses->ipc_tid = smb_buffer_response->Tid;
2909 }
2910
2911 if (smb_buffer)
2912 cifs_buf_release(smb_buffer);
2913 return rc;
2914}
2915
2916int
2917cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
2918{
2919 int rc = 0;
2920 int xid;
2921 struct cifsSesInfo *ses = NULL;
2922 struct task_struct *cifsd_task;
2923
2924 xid = GetXid();
2925
2926 if (cifs_sb->tcon) {
2927 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
2928 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
2929 if (rc == -EBUSY) {
2930 FreeXid(xid);
2931 return 0;
2932 }
2933 tconInfoFree(cifs_sb->tcon);
2934 if ((ses) && (ses->server)) {
2935 /* save off task so we do not refer to ses later */
2936 cifsd_task = ses->server->tsk;
2937 cFYI(1, ("About to do SMBLogoff "));
2938 rc = CIFSSMBLogoff(xid, ses);
2939 if (rc == -EBUSY) {
2940 FreeXid(xid);
2941 return 0;
2942 } else if (rc == -ESHUTDOWN) {
2943 cFYI(1,("Waking up socket by sending it signal"));
2944 if(cifsd_task)
2945 send_sig(SIGKILL,cifsd_task,1);
2946 rc = 0;
2947 } /* else - we have an smb session
2948 left on this socket do not kill cifsd */
2949 } else
2950 cFYI(1, ("No session or bad tcon"));
2951 }
2952
2953 cifs_sb->tcon = NULL;
2954 if (ses) {
2955 set_current_state(TASK_INTERRUPTIBLE);
2956 schedule_timeout(HZ / 2);
2957 }
2958 if (ses)
2959 sesInfoFree(ses);
2960
2961 FreeXid(xid);
2962 return rc; /* BB check if we should always return zero here */
2963}
2964
2965int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
2966 struct nls_table * nls_info)
2967{
2968 int rc = 0;
2969 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
2970 int ntlmv2_flag = FALSE;
ad009ac9 2971 int first_time = 0;
1da177e4
LT
2972
2973 /* what if server changes its buffer size after dropping the session? */
2974 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
2975 rc = CIFSSMBNegotiate(xid, pSesInfo);
2976 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
2977 rc = CIFSSMBNegotiate(xid, pSesInfo);
2978 if(rc == -EAGAIN)
2979 rc = -EHOSTDOWN;
2980 }
2981 if(rc == 0) {
2982 spin_lock(&GlobalMid_Lock);
2983 if(pSesInfo->server->tcpStatus != CifsExiting)
2984 pSesInfo->server->tcpStatus = CifsGood;
2985 else
2986 rc = -EHOSTDOWN;
2987 spin_unlock(&GlobalMid_Lock);
2988
2989 }
ad009ac9 2990 first_time = 1;
1da177e4
LT
2991 }
2992 if (!rc) {
2993 pSesInfo->capabilities = pSesInfo->server->capabilities;
2994 if(linuxExtEnabled == 0)
2995 pSesInfo->capabilities &= (~CAP_UNIX);
ad009ac9 2996 /* pSesInfo->sequence_number = 0;*/
1da177e4
LT
2997 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
2998 pSesInfo->server->secMode,
2999 pSesInfo->server->capabilities,
3000 pSesInfo->server->timeZone));
3001 if (extended_security
3002 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3003 && (pSesInfo->server->secType == NTLMSSP)) {
3004 cFYI(1, ("New style sesssetup "));
3005 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3006 NULL /* security blob */,
3007 0 /* blob length */,
3008 nls_info);
3009 } else if (extended_security
3010 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3011 && (pSesInfo->server->secType == RawNTLMSSP)) {
3012 cFYI(1, ("NTLMSSP sesssetup "));
3013 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3014 pSesInfo,
3015 &ntlmv2_flag,
3016 nls_info);
3017 if (!rc) {
3018 if(ntlmv2_flag) {
3019 char * v2_response;
3020 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3021 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3022 nls_info)) {
3023 rc = -ENOMEM;
3024 goto ss_err_exit;
3025 } else
3026 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3027 if(v2_response) {
3028 CalcNTLMv2_response(pSesInfo,v2_response);
ad009ac9
SF
3029 /* if(first_time)
3030 cifs_calculate_ntlmv2_mac_key(
3031 pSesInfo->server->mac_signing_key,
3032 response, ntlm_session_key, */
1da177e4
LT
3033 kfree(v2_response);
3034 /* BB Put dummy sig in SessSetup PDU? */
3035 } else {
3036 rc = -ENOMEM;
3037 goto ss_err_exit;
3038 }
3039
3040 } else {
3041 SMBNTencrypt(pSesInfo->password,
3042 pSesInfo->server->cryptKey,
3043 ntlm_session_key);
3044
ad009ac9
SF
3045 if(first_time)
3046 cifs_calculate_mac_key(
3047 pSesInfo->server->mac_signing_key,
3048 ntlm_session_key,
3049 pSesInfo->password);
1da177e4
LT
3050 }
3051 /* for better security the weaker lanman hash not sent
3052 in AuthSessSetup so we no longer calculate it */
3053
3054 rc = CIFSNTLMSSPAuthSessSetup(xid,
3055 pSesInfo,
3056 ntlm_session_key,
3057 ntlmv2_flag,
3058 nls_info);
3059 }
3060 } else { /* old style NTLM 0.12 session setup */
3061 SMBNTencrypt(pSesInfo->password,
3062 pSesInfo->server->cryptKey,
3063 ntlm_session_key);
3064
ad009ac9
SF
3065 if(first_time)
3066 cifs_calculate_mac_key(
3067 pSesInfo->server->mac_signing_key,
3068 ntlm_session_key, pSesInfo->password);
3069
1da177e4
LT
3070 rc = CIFSSessSetup(xid, pSesInfo,
3071 ntlm_session_key, nls_info);
3072 }
3073 if (rc) {
3074 cERROR(1,("Send error in SessSetup = %d",rc));
3075 } else {
3076 cFYI(1,("CIFS Session Established successfully"));
3077 pSesInfo->status = CifsGood;
3078 }
3079 }
3080ss_err_exit:
3081 return rc;
3082}
3083