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