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