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