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