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