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