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