blob: 6b21f6aa9f609e4b2a8045f3e2e68d896e00289e [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>
Steve Frenchf1914012005-08-18 09:37:34 -070032#include <linux/completion.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/uaccess.h>
34#include <asm/processor.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
37#include "cifsproto.h"
38#include "cifs_unicode.h"
39#include "cifs_debug.h"
40#include "cifs_fs_sb.h"
41#include "ntlmssp.h"
42#include "nterr.h"
43#include "rfc1002pdu.h"
44
45#define CIFS_PORT 445
46#define RFC1001_PORT 139
47
Steve Frenchf1914012005-08-18 09:37:34 -070048static DECLARE_COMPLETION(cifsd_complete);
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
51 unsigned char *p24);
52extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
53 unsigned char *p24);
54
55extern mempool_t *cifs_req_poolp;
56
57struct smb_vol {
58 char *username;
59 char *password;
60 char *domainname;
61 char *UNC;
62 char *UNCip;
63 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
64 char *iocharset; /* local code page for mapping to and from Unicode */
65 char source_rfc1001_name[16]; /* netbios name of client */
66 uid_t linux_uid;
67 gid_t linux_gid;
68 mode_t file_mode;
69 mode_t dir_mode;
70 unsigned rw:1;
71 unsigned retry:1;
72 unsigned intr:1;
73 unsigned setuids:1;
74 unsigned noperm:1;
75 unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
76 unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
77 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
78 unsigned direct_io:1;
Steve French6a0b4822005-04-28 22:41:05 -070079 unsigned remap:1; /* set to remap seven reserved chars in filenames */
Jeremy Allisonac670552005-06-22 17:26:35 -070080 unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
Steve Frenchd7245c22005-07-14 18:25:12 -050081 unsigned sfu_emul:1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -070082 unsigned nocase; /* request case insensitive filenames */
83 unsigned nobrl; /* disable sending byte range locks to srv */
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 unsigned int rsize;
85 unsigned int wsize;
86 unsigned int sockopt;
87 unsigned short int port;
88};
89
90static int ipv4_connect(struct sockaddr_in *psin_server,
91 struct socket **csocket,
92 char * netb_name);
93static int ipv6_connect(struct sockaddr_in6 *psin_server,
94 struct socket **csocket);
95
96
97 /*
98 * cifs tcp session reconnection
99 *
100 * mark tcp session as reconnecting so temporarily locked
101 * mark all smb sessions as reconnecting for tcp session
102 * reconnect tcp session
103 * wake up waiters on reconnection? - (not needed currently)
104 */
105
106int
107cifs_reconnect(struct TCP_Server_Info *server)
108{
109 int rc = 0;
110 struct list_head *tmp;
111 struct cifsSesInfo *ses;
112 struct cifsTconInfo *tcon;
113 struct mid_q_entry * mid_entry;
114
115 spin_lock(&GlobalMid_Lock);
116 if(server->tcpStatus == CifsExiting) {
117 /* the demux thread will exit normally
118 next time through the loop */
119 spin_unlock(&GlobalMid_Lock);
120 return rc;
121 } else
122 server->tcpStatus = CifsNeedReconnect;
123 spin_unlock(&GlobalMid_Lock);
124 server->maxBuf = 0;
125
Steve Frenche4eb2952005-04-28 22:41:09 -0700126 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128 /* before reconnecting the tcp session, mark the smb session (uid)
129 and the tid bad so they are not used until reconnected */
130 read_lock(&GlobalSMBSeslock);
131 list_for_each(tmp, &GlobalSMBSessionList) {
132 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
133 if (ses->server) {
134 if (ses->server == server) {
135 ses->status = CifsNeedReconnect;
136 ses->ipc_tid = 0;
137 }
138 }
139 /* else tcp and smb sessions need reconnection */
140 }
141 list_for_each(tmp, &GlobalTreeConnectionList) {
142 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
143 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
144 tcon->tidStatus = CifsNeedReconnect;
145 }
146 }
147 read_unlock(&GlobalSMBSeslock);
148 /* do not want to be sending data on a socket we are freeing */
149 down(&server->tcpSem);
150 if(server->ssocket) {
151 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
152 server->ssocket->flags));
153 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
154 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
155 server->ssocket->flags));
156 sock_release(server->ssocket);
157 server->ssocket = NULL;
158 }
159
160 spin_lock(&GlobalMid_Lock);
161 list_for_each(tmp, &server->pending_mid_q) {
162 mid_entry = list_entry(tmp, struct
163 mid_q_entry,
164 qhead);
165 if(mid_entry) {
166 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700167 /* Mark other intransit requests as needing
168 retry so we do not immediately mark the
169 session bad again (ie after we reconnect
170 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 mid_entry->midState = MID_RETRY_NEEDED;
172 }
173 }
174 }
175 spin_unlock(&GlobalMid_Lock);
176 up(&server->tcpSem);
177
178 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
179 {
180 if(server->protocolType == IPV6) {
181 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
182 } else {
183 rc = ipv4_connect(&server->addr.sockAddr,
184 &server->ssocket,
185 server->workstation_RFC1001_name);
186 }
187 if(rc) {
Steve French0cb766a2005-04-28 22:41:11 -0700188 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 } else {
190 atomic_inc(&tcpSesReconnectCount);
191 spin_lock(&GlobalMid_Lock);
192 if(server->tcpStatus != CifsExiting)
193 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700194 server->sequence_number = 0;
195 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 /* atomic_set(&server->inFlight,0);*/
197 wake_up(&server->response_q);
198 }
199 }
200 return rc;
201}
202
Steve Frenche4eb2952005-04-28 22:41:09 -0700203/*
204 return codes:
205 0 not a transact2, or all data present
206 >0 transact2 with that much data missing
207 -EINVAL = invalid transact2
208
209 */
210static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
211{
212 struct smb_t2_rsp * pSMBt;
213 int total_data_size;
214 int data_in_this_rsp;
215 int remaining;
216
217 if(pSMB->Command != SMB_COM_TRANSACTION2)
218 return 0;
219
220 /* check for plausible wct, bcc and t2 data and parm sizes */
221 /* check for parm and data offset going beyond end of smb */
222 if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
223 cFYI(1,("invalid transact2 word count"));
224 return -EINVAL;
225 }
226
227 pSMBt = (struct smb_t2_rsp *)pSMB;
228
229 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
230 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
231
232 remaining = total_data_size - data_in_this_rsp;
233
234 if(remaining == 0)
235 return 0;
236 else if(remaining < 0) {
237 cFYI(1,("total data %d smaller than data in frame %d",
238 total_data_size, data_in_this_rsp));
239 return -EINVAL;
240 } else {
241 cFYI(1,("missing %d bytes from transact2, check next response",
242 remaining));
243 if(total_data_size > maxBufSize) {
244 cERROR(1,("TotalDataSize %d is over maximum buffer %d",
245 total_data_size,maxBufSize));
246 return -EINVAL;
247 }
248 return remaining;
249 }
250}
251
252static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
253{
254 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
255 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
256 int total_data_size;
257 int total_in_buf;
258 int remaining;
259 int total_in_buf2;
260 char * data_area_of_target;
261 char * data_area_of_buf2;
262 __u16 byte_count;
263
264 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
265
266 if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
267 cFYI(1,("total data sizes of primary and secondary t2 differ"));
268 }
269
270 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
271
272 remaining = total_data_size - total_in_buf;
273
274 if(remaining < 0)
275 return -EINVAL;
276
277 if(remaining == 0) /* nothing to do, ignore */
278 return 0;
279
280 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
281 if(remaining < total_in_buf2) {
282 cFYI(1,("transact2 2nd response contains too much data"));
283 }
284
285 /* find end of first SMB data area */
286 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
287 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
288 /* validate target area */
289
290 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
291 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
292
293 data_area_of_target += total_in_buf;
294
295 /* copy second buffer into end of first buffer */
296 memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
297 total_in_buf += total_in_buf2;
298 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
299 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
300 byte_count += total_in_buf2;
301 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
302
303 byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
304 byte_count += total_in_buf2;
305
306 /* BB also add check that we are not beyond maximum buffer size */
307
308 pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
309
310 if(remaining == total_in_buf2) {
311 cFYI(1,("found the last secondary response"));
312 return 0; /* we are done */
313 } else /* more responses to go */
314 return 1;
315
316}
317
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318static int
319cifs_demultiplex_thread(struct TCP_Server_Info *server)
320{
321 int length;
322 unsigned int pdu_length, total_read;
323 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700324 struct smb_hdr *bigbuf = NULL;
325 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 struct msghdr smb_msg;
327 struct kvec iov;
328 struct socket *csocket = server->ssocket;
329 struct list_head *tmp;
330 struct cifsSesInfo *ses;
331 struct task_struct *task_to_wake = NULL;
332 struct mid_q_entry *mid_entry;
333 char *temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700334 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700335 int isMultiRsp;
336 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
338 daemonize("cifsd");
339 allow_signal(SIGKILL);
340 current->flags |= PF_MEMALLOC;
341 server->tsk = current; /* save process info to wake at shutdown */
342 cFYI(1, ("Demultiplex PID: %d", current->pid));
343 write_lock(&GlobalSMBSeslock);
344 atomic_inc(&tcpSesAllocCount);
345 length = tcpSesAllocCount.counter;
346 write_unlock(&GlobalSMBSeslock);
Steve Frenchf1914012005-08-18 09:37:34 -0700347 complete(&cifsd_complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 if(length > 1) {
349 mempool_resize(cifs_req_poolp,
350 length + cifs_min_rcv,
351 GFP_KERNEL);
352 }
353
354 while (server->tcpStatus != CifsExiting) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700355 if (bigbuf == NULL) {
356 bigbuf = cifs_buf_get();
357 if(bigbuf == NULL) {
358 cERROR(1,("No memory for large SMB response"));
359 msleep(3000);
360 /* retry will check if exiting */
361 continue;
362 }
363 } else if(isLargeBuf) {
364 /* we are reusing a dirtry large buf, clear its start */
365 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700367
368 if (smallbuf == NULL) {
369 smallbuf = cifs_small_buf_get();
370 if(smallbuf == NULL) {
371 cERROR(1,("No memory for SMB response"));
372 msleep(1000);
373 /* retry will check if exiting */
374 continue;
375 }
376 /* beginning of smb buffer is cleared in our buf_get */
377 } else /* if existing small buf clear beginning */
378 memset(smallbuf, 0, sizeof (struct smb_hdr));
379
380 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700381 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700382 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 iov.iov_base = smb_buffer;
384 iov.iov_len = 4;
385 smb_msg.msg_control = NULL;
386 smb_msg.msg_controllen = 0;
387 length =
388 kernel_recvmsg(csocket, &smb_msg,
389 &iov, 1, 4, 0 /* BB see socket.h flags */);
390
391 if(server->tcpStatus == CifsExiting) {
392 break;
393 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French57337e42005-04-28 22:41:10 -0700394 cFYI(1,("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 cifs_reconnect(server);
396 cFYI(1,("call to reconnect done"));
397 csocket = server->ssocket;
398 continue;
399 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700400 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 allowing socket to clear and app threads to set
402 tcpStatus CifsNeedReconnect if server hung */
403 continue;
404 } else if (length <= 0) {
405 if(server->tcpStatus == CifsNew) {
Steve French57337e42005-04-28 22:41:10 -0700406 cFYI(1,("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700407 /* some servers kill the TCP session rather than
408 returning an SMB negprot error, in which
409 case reconnecting here is not going to help,
410 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 break;
412 }
413 if(length == -EINTR) {
414 cFYI(1,("cifsd thread killed"));
415 break;
416 }
Steve French57337e42005-04-28 22:41:10 -0700417 cFYI(1,("Reconnect after unexpected peek error %d",
418 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 cifs_reconnect(server);
420 csocket = server->ssocket;
421 wake_up(&server->response_q);
422 continue;
Steve French46810cb2005-04-28 22:41:09 -0700423 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700425 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 length));
427 cifs_reconnect(server);
428 csocket = server->ssocket;
429 wake_up(&server->response_q);
430 continue;
431 }
Steve French67010fb2005-04-28 22:41:09 -0700432
Steve French46810cb2005-04-28 22:41:09 -0700433 /* the right amount was read from socket - 4 bytes */
434
435 pdu_length = ntohl(smb_buffer->smb_buf_length);
436 cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
437
438 temp = (char *) smb_buffer;
439 if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700440 continue;
Steve French46810cb2005-04-28 22:41:09 -0700441 } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700442 cFYI(1,("Good RFC 1002 session rsp"));
443 continue;
Steve French46810cb2005-04-28 22:41:09 -0700444 } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
445 /* we get this from Windows 98 instead of
446 an error on SMB negprot response */
Steve Frenche4eb2952005-04-28 22:41:09 -0700447 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
448 temp[4]));
Steve French46810cb2005-04-28 22:41:09 -0700449 if(server->tcpStatus == CifsNew) {
450 /* if nack on negprot (rather than
451 ret of smb negprot error) reconnecting
452 not going to help, ret error to mount */
453 break;
454 } else {
455 /* give server a second to
456 clean up before reconnect attempt */
457 msleep(1000);
458 /* always try 445 first on reconnect
459 since we get NACK on some if we ever
460 connected to port 139 (the NACK is
461 since we do not begin with RFC1001
462 session initialize frame) */
463 server->addr.sockAddr.sin_port =
464 htons(CIFS_PORT);
465 cifs_reconnect(server);
466 csocket = server->ssocket;
467 wake_up(&server->response_q);
468 continue;
469 }
470 } else if (temp[0] != (char) 0) {
471 cERROR(1,("Unknown RFC 1002 frame"));
472 cifs_dump_mem(" Received Data: ", temp, length);
473 cifs_reconnect(server);
474 csocket = server->ssocket;
475 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700476 }
477
478 /* else we have an SMB response */
479 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700480 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700481 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700482 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700483 cifs_reconnect(server);
484 csocket = server->ssocket;
485 wake_up(&server->response_q);
486 continue;
487 }
488
489 /* else length ok */
490 reconnect = 0;
491
492 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
493 isLargeBuf = TRUE;
494 memcpy(bigbuf, smallbuf, 4);
495 smb_buffer = bigbuf;
496 }
497 length = 0;
498 iov.iov_base = 4 + (char *)smb_buffer;
499 iov.iov_len = pdu_length;
500 for (total_read = 0; total_read < pdu_length;
501 total_read += length) {
502 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
503 pdu_length - total_read, 0);
504 if((server->tcpStatus == CifsExiting) ||
505 (length == -EINTR)) {
506 /* then will exit */
507 reconnect = 2;
508 break;
509 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700510 cifs_reconnect(server);
511 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700512 /* Reconnect wakes up rspns q */
513 /* Now we will reread sock */
514 reconnect = 1;
515 break;
516 } else if ((length == -ERESTARTSYS) ||
517 (length == -EAGAIN)) {
518 msleep(1); /* minimum sleep to prevent looping,
519 allowing socket to clear and app
520 threads to set tcpStatus
521 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700522 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700523 } else if (length <= 0) {
524 cERROR(1,("Received no data, expecting %d",
525 pdu_length - total_read));
526 cifs_reconnect(server);
527 csocket = server->ssocket;
528 reconnect = 1;
529 break;
Steve French46810cb2005-04-28 22:41:09 -0700530 }
531 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700532 if(reconnect == 2)
533 break;
534 else if(reconnect == 1)
535 continue;
536
537 length += 4; /* account for rfc1002 hdr */
538
539
540 dump_smb(smb_buffer, length);
541 if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
542 cERROR(1, ("Bad SMB Received "));
543 continue;
544 }
545
546
547 task_to_wake = NULL;
548 spin_lock(&GlobalMid_Lock);
549 list_for_each(tmp, &server->pending_mid_q) {
550 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
551
552 if ((mid_entry->mid == smb_buffer->Mid) &&
553 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
554 (mid_entry->command == smb_buffer->Command)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700555 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
556 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700557 isMultiRsp = TRUE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700558 if(mid_entry->resp_buf) {
559 /* merge response - fix up 1st*/
560 if(coalesce_t2(smb_buffer,
561 mid_entry->resp_buf)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700562 break;
563 } else {
564 /* all parts received */
565 goto multi_t2_fnd;
566 }
567 } else {
568 if(!isLargeBuf) {
569 cERROR(1,("1st trans2 resp needs bigbuf"));
570 /* BB maybe we can fix this up, switch
571 to already allocated large buffer? */
572 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700573 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700574 mid_entry->resp_buf =
575 smb_buffer;
576 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700577 bigbuf = NULL;
578 }
579 }
580 break;
581 }
582 mid_entry->resp_buf = smb_buffer;
583 if(isLargeBuf)
584 mid_entry->largeBuf = 1;
585 else
586 mid_entry->largeBuf = 0;
587multi_t2_fnd:
588 task_to_wake = mid_entry->tsk;
589 mid_entry->midState = MID_RESPONSE_RECEIVED;
590 break;
591 }
592 }
593 spin_unlock(&GlobalMid_Lock);
594 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700595 /* Was previous buf put in mpx struct for multi-rsp? */
596 if(!isMultiRsp) {
597 /* smb buffer will be freed by user thread */
598 if(isLargeBuf) {
599 bigbuf = NULL;
600 } else
601 smallbuf = NULL;
602 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700603 wake_up_process(task_to_wake);
Steve French57337e42005-04-28 22:41:10 -0700604 } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700605 && (isMultiRsp == FALSE)) {
606 cERROR(1, ("No task to wake, unknown frame rcvd!"));
607 cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
608 }
609 } /* end while !EXITING */
610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 spin_lock(&GlobalMid_Lock);
612 server->tcpStatus = CifsExiting;
613 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700614 /* check if we have blocked requests that need to free */
615 /* Note that cifs_max_pending is normally 50, but
616 can be set at module install time to as little as two */
617 if(atomic_read(&server->inFlight) >= cifs_max_pending)
618 atomic_set(&server->inFlight, cifs_max_pending - 1);
619 /* We do not want to set the max_pending too low or we
620 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 spin_unlock(&GlobalMid_Lock);
622 /* Although there should not be any requests blocked on
623 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700624 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 to the same server - they now will see the session is in exit state
626 and get out of SendReceive. */
627 wake_up_all(&server->request_q);
628 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700629 msleep(125);
630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 if(server->ssocket) {
632 sock_release(csocket);
633 server->ssocket = NULL;
634 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700635 /* buffer usuallly freed in free_mid - need to free it here on exit */
636 if (bigbuf != NULL)
637 cifs_buf_release(bigbuf);
638 if (smallbuf != NULL)
639 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
641 read_lock(&GlobalSMBSeslock);
642 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700643 /* loop through server session structures attached to this and
644 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 list_for_each(tmp, &GlobalSMBSessionList) {
646 ses =
647 list_entry(tmp, struct cifsSesInfo,
648 cifsSessionList);
649 if (ses->server == server) {
650 ses->status = CifsExiting;
651 ses->server = NULL;
652 }
653 }
654 read_unlock(&GlobalSMBSeslock);
655 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700656 /* although we can not zero the server struct pointer yet,
657 since there are active requests which may depnd on them,
658 mark the corresponding SMB sessions as exiting too */
659 list_for_each(tmp, &GlobalSMBSessionList) {
660 ses = list_entry(tmp, struct cifsSesInfo,
661 cifsSessionList);
662 if (ses->server == server) {
663 ses->status = CifsExiting;
664 }
665 }
666
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 spin_lock(&GlobalMid_Lock);
668 list_for_each(tmp, &server->pending_mid_q) {
669 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
670 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
671 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700672 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 task_to_wake = mid_entry->tsk;
674 if(task_to_wake) {
675 wake_up_process(task_to_wake);
676 }
677 }
678 }
679 spin_unlock(&GlobalMid_Lock);
680 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700682 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 }
684
Steve Frenchf1914012005-08-18 09:37:34 -0700685 if (!list_empty(&server->pending_mid_q)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 /* mpx threads have not exited yet give them
687 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700688 /* due to delays on oplock break requests, we need
689 to wait at least 45 seconds before giving up
690 on a request getting a response and going ahead
691 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700693 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 /* if threads still have not exited they are probably never
695 coming home not much else we can do but free the memory */
696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
698 write_lock(&GlobalSMBSeslock);
699 atomic_dec(&tcpSesAllocCount);
700 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700701
702 /* last chance to mark ses pointers invalid
703 if there are any pointing to this (e.g
704 if a crazy root user tried to kill cifsd
705 kernel thread explicitly this might happen) */
706 list_for_each(tmp, &GlobalSMBSessionList) {
707 ses = list_entry(tmp, struct cifsSesInfo,
708 cifsSessionList);
709 if (ses->server == server) {
710 ses->server = NULL;
711 }
712 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700714
715 kfree(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 if(length > 0) {
717 mempool_resize(cifs_req_poolp,
718 length + cifs_min_rcv,
719 GFP_KERNEL);
720 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700721
Steve Frenchf1914012005-08-18 09:37:34 -0700722 complete_and_exit(&cifsd_complete, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return 0;
724}
725
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726static int
727cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
728{
729 char *value;
730 char *data;
731 unsigned int temp_len, i, j;
732 char separator[2];
733
734 separator[0] = ',';
735 separator[1] = 0;
736
737 memset(vol->source_rfc1001_name,0x20,15);
738 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
739 /* does not have to be a perfect mapping since the field is
740 informational, only used for servers that do not support
741 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700742 vol->source_rfc1001_name[i] =
743 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 }
745 vol->source_rfc1001_name[15] = 0;
746
747 vol->linux_uid = current->uid; /* current->euid instead? */
748 vol->linux_gid = current->gid;
749 vol->dir_mode = S_IRWXUGO;
750 /* 2767 perms indicate mandatory locking support */
751 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
752
753 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
754 vol->rw = TRUE;
755
Jeremy Allisonac670552005-06-22 17:26:35 -0700756 /* default is always to request posix paths. */
757 vol->posix_paths = 1;
758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 if (!options)
760 return 1;
761
762 if(strncmp(options,"sep=",4) == 0) {
763 if(options[4] != 0) {
764 separator[0] = options[4];
765 options += 5;
766 } else {
767 cFYI(1,("Null separator not allowed"));
768 }
769 }
770
771 while ((data = strsep(&options, separator)) != NULL) {
772 if (!*data)
773 continue;
774 if ((value = strchr(data, '=')) != NULL)
775 *value++ = '\0';
776
777 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
778 vol->no_xattr = 0;
779 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
780 vol->no_xattr = 1;
781 } else if (strnicmp(data, "user", 4) == 0) {
782 if (!value || !*value) {
783 printk(KERN_WARNING
784 "CIFS: invalid or missing username\n");
785 return 1; /* needs_arg; */
786 }
787 if (strnlen(value, 200) < 200) {
788 vol->username = value;
789 } else {
790 printk(KERN_WARNING "CIFS: username too long\n");
791 return 1;
792 }
793 } else if (strnicmp(data, "pass", 4) == 0) {
794 if (!value) {
795 vol->password = NULL;
796 continue;
797 } else if(value[0] == 0) {
798 /* check if string begins with double comma
799 since that would mean the password really
800 does start with a comma, and would not
801 indicate an empty string */
802 if(value[1] != separator[0]) {
803 vol->password = NULL;
804 continue;
805 }
806 }
807 temp_len = strlen(value);
808 /* removed password length check, NTLM passwords
809 can be arbitrarily long */
810
811 /* if comma in password, the string will be
812 prematurely null terminated. Commas in password are
813 specified across the cifs mount interface by a double
814 comma ie ,, and a comma used as in other cases ie ','
815 as a parameter delimiter/separator is single and due
816 to the strsep above is temporarily zeroed. */
817
818 /* NB: password legally can have multiple commas and
819 the only illegal character in a password is null */
820
Steve French09d1db52005-04-28 22:41:08 -0700821 if ((value[temp_len] == 0) &&
822 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 /* reinsert comma */
824 value[temp_len] = separator[0];
825 temp_len+=2; /* move after the second comma */
826 while(value[temp_len] != 0) {
827 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700828 if (value[temp_len+1] ==
829 separator[0]) {
830 /* skip second comma */
831 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 } else {
833 /* single comma indicating start
834 of next parm */
835 break;
836 }
837 }
838 temp_len++;
839 }
840 if(value[temp_len] == 0) {
841 options = NULL;
842 } else {
843 value[temp_len] = 0;
844 /* point option to start of next parm */
845 options = value + temp_len + 1;
846 }
847 /* go from value to value + temp_len condensing
848 double commas to singles. Note that this ends up
849 allocating a few bytes too many, which is ok */
Steve French433dc242005-04-28 22:41:08 -0700850 vol->password = kcalloc(1, temp_len, GFP_KERNEL);
851 if(vol->password == NULL) {
852 printk("CIFS: no memory for pass\n");
853 return 1;
854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 for(i=0,j=0;i<temp_len;i++,j++) {
856 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700857 if(value[i] == separator[0]
858 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 /* skip second comma */
860 i++;
861 }
862 }
863 vol->password[j] = 0;
864 } else {
Steve French09d1db52005-04-28 22:41:08 -0700865 vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700866 if(vol->password == NULL) {
867 printk("CIFS: no memory for pass\n");
868 return 1;
869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 strcpy(vol->password, value);
871 }
872 } else if (strnicmp(data, "ip", 2) == 0) {
873 if (!value || !*value) {
874 vol->UNCip = NULL;
875 } else if (strnlen(value, 35) < 35) {
876 vol->UNCip = value;
877 } else {
878 printk(KERN_WARNING "CIFS: ip address too long\n");
879 return 1;
880 }
881 } else if ((strnicmp(data, "unc", 3) == 0)
882 || (strnicmp(data, "target", 6) == 0)
883 || (strnicmp(data, "path", 4) == 0)) {
884 if (!value || !*value) {
885 printk(KERN_WARNING
886 "CIFS: invalid path to network resource\n");
887 return 1; /* needs_arg; */
888 }
889 if ((temp_len = strnlen(value, 300)) < 300) {
890 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
891 if(vol->UNC == NULL)
892 return 1;
893 strcpy(vol->UNC,value);
894 if (strncmp(vol->UNC, "//", 2) == 0) {
895 vol->UNC[0] = '\\';
896 vol->UNC[1] = '\\';
897 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
898 printk(KERN_WARNING
899 "CIFS: UNC Path does not begin with // or \\\\ \n");
900 return 1;
901 }
902 } else {
903 printk(KERN_WARNING "CIFS: UNC name too long\n");
904 return 1;
905 }
906 } else if ((strnicmp(data, "domain", 3) == 0)
907 || (strnicmp(data, "workgroup", 5) == 0)) {
908 if (!value || !*value) {
909 printk(KERN_WARNING "CIFS: invalid domain name\n");
910 return 1; /* needs_arg; */
911 }
912 /* BB are there cases in which a comma can be valid in
913 a domain name and need special handling? */
914 if (strnlen(value, 65) < 65) {
915 vol->domainname = value;
916 cFYI(1, ("Domain name set"));
917 } else {
918 printk(KERN_WARNING "CIFS: domain name too long\n");
919 return 1;
920 }
921 } else if (strnicmp(data, "iocharset", 9) == 0) {
922 if (!value || !*value) {
923 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
924 return 1; /* needs_arg; */
925 }
926 if (strnlen(value, 65) < 65) {
927 if(strnicmp(value,"default",7))
928 vol->iocharset = value;
929 /* if iocharset not set load_nls_default used by caller */
930 cFYI(1, ("iocharset set to %s",value));
931 } else {
932 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
933 return 1;
934 }
935 } else if (strnicmp(data, "uid", 3) == 0) {
936 if (value && *value) {
937 vol->linux_uid =
938 simple_strtoul(value, &value, 0);
939 }
940 } else if (strnicmp(data, "gid", 3) == 0) {
941 if (value && *value) {
942 vol->linux_gid =
943 simple_strtoul(value, &value, 0);
944 }
945 } else if (strnicmp(data, "file_mode", 4) == 0) {
946 if (value && *value) {
947 vol->file_mode =
948 simple_strtoul(value, &value, 0);
949 }
950 } else if (strnicmp(data, "dir_mode", 4) == 0) {
951 if (value && *value) {
952 vol->dir_mode =
953 simple_strtoul(value, &value, 0);
954 }
955 } else if (strnicmp(data, "dirmode", 4) == 0) {
956 if (value && *value) {
957 vol->dir_mode =
958 simple_strtoul(value, &value, 0);
959 }
960 } else if (strnicmp(data, "port", 4) == 0) {
961 if (value && *value) {
962 vol->port =
963 simple_strtoul(value, &value, 0);
964 }
965 } else if (strnicmp(data, "rsize", 5) == 0) {
966 if (value && *value) {
967 vol->rsize =
968 simple_strtoul(value, &value, 0);
969 }
970 } else if (strnicmp(data, "wsize", 5) == 0) {
971 if (value && *value) {
972 vol->wsize =
973 simple_strtoul(value, &value, 0);
974 }
975 } else if (strnicmp(data, "sockopt", 5) == 0) {
976 if (value && *value) {
977 vol->sockopt =
978 simple_strtoul(value, &value, 0);
979 }
980 } else if (strnicmp(data, "netbiosname", 4) == 0) {
981 if (!value || !*value || (*value == ' ')) {
982 cFYI(1,("invalid (empty) netbiosname specified"));
983 } else {
984 memset(vol->source_rfc1001_name,0x20,15);
985 for(i=0;i<15;i++) {
986 /* BB are there cases in which a comma can be
987 valid in this workstation netbios name (and need
988 special handling)? */
989
990 /* We do not uppercase netbiosname for user */
991 if (value[i]==0)
992 break;
993 else
994 vol->source_rfc1001_name[i] = value[i];
995 }
996 /* The string has 16th byte zero still from
997 set at top of the function */
998 if((i==15) && (value[i] != 0))
999 printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
1000 }
1001 } else if (strnicmp(data, "credentials", 4) == 0) {
1002 /* ignore */
1003 } else if (strnicmp(data, "version", 3) == 0) {
1004 /* ignore */
1005 } else if (strnicmp(data, "guest",5) == 0) {
1006 /* ignore */
1007 } else if (strnicmp(data, "rw", 2) == 0) {
1008 vol->rw = TRUE;
1009 } else if ((strnicmp(data, "suid", 4) == 0) ||
1010 (strnicmp(data, "nosuid", 6) == 0) ||
1011 (strnicmp(data, "exec", 4) == 0) ||
1012 (strnicmp(data, "noexec", 6) == 0) ||
1013 (strnicmp(data, "nodev", 5) == 0) ||
1014 (strnicmp(data, "noauto", 6) == 0) ||
1015 (strnicmp(data, "dev", 3) == 0)) {
1016 /* The mount tool or mount.cifs helper (if present)
1017 uses these opts to set flags, and the flags are read
1018 by the kernel vfs layer before we get here (ie
1019 before read super) so there is no point trying to
1020 parse these options again and set anything and it
1021 is ok to just ignore them */
1022 continue;
1023 } else if (strnicmp(data, "ro", 2) == 0) {
1024 vol->rw = FALSE;
1025 } else if (strnicmp(data, "hard", 4) == 0) {
1026 vol->retry = 1;
1027 } else if (strnicmp(data, "soft", 4) == 0) {
1028 vol->retry = 0;
1029 } else if (strnicmp(data, "perm", 4) == 0) {
1030 vol->noperm = 0;
1031 } else if (strnicmp(data, "noperm", 6) == 0) {
1032 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001033 } else if (strnicmp(data, "mapchars", 8) == 0) {
1034 vol->remap = 1;
1035 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1036 vol->remap = 0;
Steve Frenchd7245c22005-07-14 18:25:12 -05001037 } else if (strnicmp(data, "sfu", 3) == 0) {
1038 vol->sfu_emul = 1;
1039 } else if (strnicmp(data, "nosfu", 5) == 0) {
1040 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001041 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1042 vol->posix_paths = 1;
1043 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1044 vol->posix_paths = 0;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001045 } else if (strnicmp(data, "nocase", 6) == 0) {
1046 vol->nocase = 1;
1047 } else if (strnicmp(data, "brl", 3) == 0) {
1048 vol->nobrl = 0;
1049 } else if (strnicmp(data, "nobrl", 5) == 0) {
1050 vol->nobrl = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 } else if (strnicmp(data, "setuids", 7) == 0) {
1052 vol->setuids = 1;
1053 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1054 vol->setuids = 0;
1055 } else if (strnicmp(data, "nohard", 6) == 0) {
1056 vol->retry = 0;
1057 } else if (strnicmp(data, "nosoft", 6) == 0) {
1058 vol->retry = 1;
1059 } else if (strnicmp(data, "nointr", 6) == 0) {
1060 vol->intr = 0;
1061 } else if (strnicmp(data, "intr", 4) == 0) {
1062 vol->intr = 1;
1063 } else if (strnicmp(data, "serverino",7) == 0) {
1064 vol->server_ino = 1;
1065 } else if (strnicmp(data, "noserverino",9) == 0) {
1066 vol->server_ino = 0;
1067 } else if (strnicmp(data, "acl",3) == 0) {
1068 vol->no_psx_acl = 0;
1069 } else if (strnicmp(data, "noacl",5) == 0) {
1070 vol->no_psx_acl = 1;
1071 } else if (strnicmp(data, "direct",6) == 0) {
1072 vol->direct_io = 1;
1073 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1074 vol->direct_io = 1;
1075 } else if (strnicmp(data, "in6_addr",8) == 0) {
1076 if (!value || !*value) {
1077 vol->in6_addr = NULL;
1078 } else if (strnlen(value, 49) == 48) {
1079 vol->in6_addr = value;
1080 } else {
1081 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1082 return 1;
1083 }
1084 } else if (strnicmp(data, "noac", 4) == 0) {
1085 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1086 } else
1087 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1088 }
1089 if (vol->UNC == NULL) {
1090 if(devname == NULL) {
1091 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1092 return 1;
1093 }
1094 if ((temp_len = strnlen(devname, 300)) < 300) {
1095 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1096 if(vol->UNC == NULL)
1097 return 1;
1098 strcpy(vol->UNC,devname);
1099 if (strncmp(vol->UNC, "//", 2) == 0) {
1100 vol->UNC[0] = '\\';
1101 vol->UNC[1] = '\\';
1102 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1103 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1104 return 1;
1105 }
1106 } else {
1107 printk(KERN_WARNING "CIFS: UNC name too long\n");
1108 return 1;
1109 }
1110 }
1111 if(vol->UNCip == NULL)
1112 vol->UNCip = &vol->UNC[2];
1113
1114 return 0;
1115}
1116
1117static struct cifsSesInfo *
1118cifs_find_tcp_session(struct in_addr * target_ip_addr,
1119 struct in6_addr *target_ip6_addr,
1120 char *userName, struct TCP_Server_Info **psrvTcp)
1121{
1122 struct list_head *tmp;
1123 struct cifsSesInfo *ses;
1124 *psrvTcp = NULL;
1125 read_lock(&GlobalSMBSeslock);
1126
1127 list_for_each(tmp, &GlobalSMBSessionList) {
1128 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1129 if (ses->server) {
1130 if((target_ip_addr &&
1131 (ses->server->addr.sockAddr.sin_addr.s_addr
1132 == target_ip_addr->s_addr)) || (target_ip6_addr
1133 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1134 target_ip6_addr,sizeof(*target_ip6_addr)))){
1135 /* BB lock server and tcp session and increment use count here?? */
1136 *psrvTcp = ses->server; /* found a match on the TCP session */
1137 /* BB check if reconnection needed */
1138 if (strncmp
1139 (ses->userName, userName,
1140 MAX_USERNAME_SIZE) == 0){
1141 read_unlock(&GlobalSMBSeslock);
1142 return ses; /* found exact match on both tcp and SMB sessions */
1143 }
1144 }
1145 }
1146 /* else tcp and smb sessions need reconnection */
1147 }
1148 read_unlock(&GlobalSMBSeslock);
1149 return NULL;
1150}
1151
1152static struct cifsTconInfo *
1153find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1154{
1155 struct list_head *tmp;
1156 struct cifsTconInfo *tcon;
1157
1158 read_lock(&GlobalSMBSeslock);
1159 list_for_each(tmp, &GlobalTreeConnectionList) {
1160 cFYI(1, ("Next tcon - "));
1161 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1162 if (tcon->ses) {
1163 if (tcon->ses->server) {
1164 cFYI(1,
1165 (" old ip addr: %x == new ip %x ?",
1166 tcon->ses->server->addr.sockAddr.sin_addr.
1167 s_addr, new_target_ip_addr));
1168 if (tcon->ses->server->addr.sockAddr.sin_addr.
1169 s_addr == new_target_ip_addr) {
1170 /* BB lock tcon and server and tcp session and increment use count here? */
1171 /* found a match on the TCP session */
1172 /* BB check if reconnection needed */
1173 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1174 tcon->treeName, uncName));
1175 if (strncmp
1176 (tcon->treeName, uncName,
1177 MAX_TREE_SIZE) == 0) {
1178 cFYI(1,
1179 ("Matched UNC, old user: %s == new: %s ?",
1180 tcon->treeName, uncName));
1181 if (strncmp
1182 (tcon->ses->userName,
1183 userName,
1184 MAX_USERNAME_SIZE) == 0) {
1185 read_unlock(&GlobalSMBSeslock);
1186 return tcon;/* also matched user (smb session)*/
1187 }
1188 }
1189 }
1190 }
1191 }
1192 }
1193 read_unlock(&GlobalSMBSeslock);
1194 return NULL;
1195}
1196
1197int
1198connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001199 const char *old_path, const struct nls_table *nls_codepage,
1200 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201{
1202 unsigned char *referrals = NULL;
1203 unsigned int num_referrals;
1204 int rc = 0;
1205
1206 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001207 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
1209 /* BB Add in code to: if valid refrl, if not ip address contact
1210 the helper that resolves tcp names, mount to it, try to
1211 tcon to it unmount it if fail */
1212
1213 if(referrals)
1214 kfree(referrals);
1215
1216 return rc;
1217}
1218
1219int
1220get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1221 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001222 unsigned int *pnum_referrals,
1223 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224{
1225 char *temp_unc;
1226 int rc = 0;
1227
1228 *pnum_referrals = 0;
1229
1230 if (pSesInfo->ipc_tid == 0) {
1231 temp_unc = kmalloc(2 /* for slashes */ +
1232 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1233 + 1 + 4 /* slash IPC$ */ + 2,
1234 GFP_KERNEL);
1235 if (temp_unc == NULL)
1236 return -ENOMEM;
1237 temp_unc[0] = '\\';
1238 temp_unc[1] = '\\';
1239 strcpy(temp_unc + 2, pSesInfo->serverName);
1240 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1241 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1242 cFYI(1,
1243 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1244 kfree(temp_unc);
1245 }
1246 if (rc == 0)
1247 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001248 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250 return rc;
1251}
1252
1253/* See RFC1001 section 14 on representation of Netbios names */
1254static void rfc1002mangle(char * target,char * source, unsigned int length)
1255{
1256 unsigned int i,j;
1257
1258 for(i=0,j=0;i<(length);i++) {
1259 /* mask a nibble at a time and encode */
1260 target[j] = 'A' + (0x0F & (source[i] >> 4));
1261 target[j+1] = 'A' + (0x0F & source[i]);
1262 j+=2;
1263 }
1264
1265}
1266
1267
1268static int
1269ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1270 char * netbios_name)
1271{
1272 int rc = 0;
1273 int connected = 0;
1274 __be16 orig_port = 0;
1275
1276 if(*csocket == NULL) {
1277 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1278 if (rc < 0) {
1279 cERROR(1, ("Error %d creating socket",rc));
1280 *csocket = NULL;
1281 return rc;
1282 } else {
1283 /* BB other socket options to set KEEPALIVE, NODELAY? */
1284 cFYI(1,("Socket created"));
1285 (*csocket)->sk->sk_allocation = GFP_NOFS;
1286 }
1287 }
1288
1289 psin_server->sin_family = AF_INET;
1290 if(psin_server->sin_port) { /* user overrode default port */
1291 rc = (*csocket)->ops->connect(*csocket,
1292 (struct sockaddr *) psin_server,
1293 sizeof (struct sockaddr_in),0);
1294 if (rc >= 0)
1295 connected = 1;
1296 }
1297
1298 if(!connected) {
1299 /* save original port so we can retry user specified port
1300 later if fall back ports fail this time */
1301 orig_port = psin_server->sin_port;
1302
1303 /* do not retry on the same port we just failed on */
1304 if(psin_server->sin_port != htons(CIFS_PORT)) {
1305 psin_server->sin_port = htons(CIFS_PORT);
1306
1307 rc = (*csocket)->ops->connect(*csocket,
1308 (struct sockaddr *) psin_server,
1309 sizeof (struct sockaddr_in),0);
1310 if (rc >= 0)
1311 connected = 1;
1312 }
1313 }
1314 if (!connected) {
1315 psin_server->sin_port = htons(RFC1001_PORT);
1316 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1317 psin_server, sizeof (struct sockaddr_in),0);
1318 if (rc >= 0)
1319 connected = 1;
1320 }
1321
1322 /* give up here - unless we want to retry on different
1323 protocol families some day */
1324 if (!connected) {
1325 if(orig_port)
1326 psin_server->sin_port = orig_port;
1327 cFYI(1,("Error %d connecting to server via ipv4",rc));
1328 sock_release(*csocket);
1329 *csocket = NULL;
1330 return rc;
1331 }
1332 /* Eventually check for other socket options to change from
1333 the default. sock_setsockopt not used because it expects
1334 user space buffer */
1335 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1336
1337 /* send RFC1001 sessinit */
1338
1339 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1340 /* some servers require RFC1001 sessinit before sending
1341 negprot - BB check reconnection in case where second
1342 sessinit is sent but no second negprot */
1343 struct rfc1002_session_packet * ses_init_buf;
1344 struct smb_hdr * smb_buf;
Steve French433dc242005-04-28 22:41:08 -07001345 ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 if(ses_init_buf) {
1347 ses_init_buf->trailer.session_req.called_len = 32;
1348 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1349 DEFAULT_CIFS_CALLED_NAME,16);
1350 ses_init_buf->trailer.session_req.calling_len = 32;
1351 /* calling name ends in null (byte 16) from old smb
1352 convention. */
1353 if(netbios_name && (netbios_name[0] !=0)) {
1354 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1355 netbios_name,16);
1356 } else {
1357 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1358 "LINUX_CIFS_CLNT",16);
1359 }
1360 ses_init_buf->trailer.session_req.scope1 = 0;
1361 ses_init_buf->trailer.session_req.scope2 = 0;
1362 smb_buf = (struct smb_hdr *)ses_init_buf;
1363 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1364 smb_buf->smb_buf_length = 0x81000044;
1365 rc = smb_send(*csocket, smb_buf, 0x44,
1366 (struct sockaddr *)psin_server);
1367 kfree(ses_init_buf);
1368 }
1369 /* else the negprot may still work without this
1370 even though malloc failed */
1371
1372 }
1373
1374 return rc;
1375}
1376
1377static int
1378ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1379{
1380 int rc = 0;
1381 int connected = 0;
1382 __be16 orig_port = 0;
1383
1384 if(*csocket == NULL) {
1385 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1386 if (rc < 0) {
1387 cERROR(1, ("Error %d creating ipv6 socket",rc));
1388 *csocket = NULL;
1389 return rc;
1390 } else {
1391 /* BB other socket options to set KEEPALIVE, NODELAY? */
1392 cFYI(1,("ipv6 Socket created"));
1393 (*csocket)->sk->sk_allocation = GFP_NOFS;
1394 }
1395 }
1396
1397 psin_server->sin6_family = AF_INET6;
1398
1399 if(psin_server->sin6_port) { /* user overrode default port */
1400 rc = (*csocket)->ops->connect(*csocket,
1401 (struct sockaddr *) psin_server,
1402 sizeof (struct sockaddr_in6),0);
1403 if (rc >= 0)
1404 connected = 1;
1405 }
1406
1407 if(!connected) {
1408 /* save original port so we can retry user specified port
1409 later if fall back ports fail this time */
1410
1411 orig_port = psin_server->sin6_port;
1412 /* do not retry on the same port we just failed on */
1413 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1414 psin_server->sin6_port = htons(CIFS_PORT);
1415
1416 rc = (*csocket)->ops->connect(*csocket,
1417 (struct sockaddr *) psin_server,
1418 sizeof (struct sockaddr_in6),0);
1419 if (rc >= 0)
1420 connected = 1;
1421 }
1422 }
1423 if (!connected) {
1424 psin_server->sin6_port = htons(RFC1001_PORT);
1425 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1426 psin_server, sizeof (struct sockaddr_in6),0);
1427 if (rc >= 0)
1428 connected = 1;
1429 }
1430
1431 /* give up here - unless we want to retry on different
1432 protocol families some day */
1433 if (!connected) {
1434 if(orig_port)
1435 psin_server->sin6_port = orig_port;
1436 cFYI(1,("Error %d connecting to server via ipv6",rc));
1437 sock_release(*csocket);
1438 *csocket = NULL;
1439 return rc;
1440 }
1441 /* Eventually check for other socket options to change from
1442 the default. sock_setsockopt not used because it expects
1443 user space buffer */
1444 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1445
1446 return rc;
1447}
1448
1449int
1450cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1451 char *mount_data, const char *devname)
1452{
1453 int rc = 0;
1454 int xid;
1455 int address_type = AF_INET;
1456 struct socket *csocket = NULL;
1457 struct sockaddr_in sin_server;
1458 struct sockaddr_in6 sin_server6;
1459 struct smb_vol volume_info;
1460 struct cifsSesInfo *pSesInfo = NULL;
1461 struct cifsSesInfo *existingCifsSes = NULL;
1462 struct cifsTconInfo *tcon = NULL;
1463 struct TCP_Server_Info *srvTcp = NULL;
1464
1465 xid = GetXid();
1466
1467/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1468
1469 memset(&volume_info,0,sizeof(struct smb_vol));
1470 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1471 if(volume_info.UNC)
1472 kfree(volume_info.UNC);
1473 if(volume_info.password)
1474 kfree(volume_info.password);
1475 FreeXid(xid);
1476 return -EINVAL;
1477 }
1478
1479 if (volume_info.username) {
1480 /* BB fixme parse for domain name here */
1481 cFYI(1, ("Username: %s ", volume_info.username));
1482
1483 } else {
1484 cifserror("No username specified ");
1485 /* In userspace mount helper we can get user name from alternate
1486 locations such as env variables and files on disk */
1487 if(volume_info.UNC)
1488 kfree(volume_info.UNC);
1489 if(volume_info.password)
1490 kfree(volume_info.password);
1491 FreeXid(xid);
1492 return -EINVAL;
1493 }
1494
1495 if (volume_info.UNCip && volume_info.UNC) {
1496 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1497
1498 if(rc <= 0) {
1499 /* not ipv4 address, try ipv6 */
1500 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1501 if(rc > 0)
1502 address_type = AF_INET6;
1503 } else {
1504 address_type = AF_INET;
1505 }
1506
1507 if(rc <= 0) {
1508 /* we failed translating address */
1509 if(volume_info.UNC)
1510 kfree(volume_info.UNC);
1511 if(volume_info.password)
1512 kfree(volume_info.password);
1513 FreeXid(xid);
1514 return -EINVAL;
1515 }
1516
1517 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1518 /* success */
1519 rc = 0;
1520 } else if (volume_info.UNCip){
1521 /* BB using ip addr as server name connect to the DFS root below */
1522 cERROR(1,("Connecting to DFS root not implemented yet"));
1523 if(volume_info.UNC)
1524 kfree(volume_info.UNC);
1525 if(volume_info.password)
1526 kfree(volume_info.password);
1527 FreeXid(xid);
1528 return -EINVAL;
1529 } else /* which servers DFS root would we conect to */ {
1530 cERROR(1,
1531 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1532 if(volume_info.UNC)
1533 kfree(volume_info.UNC);
1534 if(volume_info.password)
1535 kfree(volume_info.password);
1536 FreeXid(xid);
1537 return -EINVAL;
1538 }
1539
1540 /* this is needed for ASCII cp to Unicode converts */
1541 if(volume_info.iocharset == NULL) {
1542 cifs_sb->local_nls = load_nls_default();
1543 /* load_nls_default can not return null */
1544 } else {
1545 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1546 if(cifs_sb->local_nls == NULL) {
1547 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1548 if(volume_info.UNC)
1549 kfree(volume_info.UNC);
1550 if(volume_info.password)
1551 kfree(volume_info.password);
1552 FreeXid(xid);
1553 return -ELIBACC;
1554 }
1555 }
1556
1557 if(address_type == AF_INET)
1558 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1559 NULL /* no ipv6 addr */,
1560 volume_info.username, &srvTcp);
1561 else if(address_type == AF_INET6)
1562 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1563 &sin_server6.sin6_addr,
1564 volume_info.username, &srvTcp);
1565 else {
1566 if(volume_info.UNC)
1567 kfree(volume_info.UNC);
1568 if(volume_info.password)
1569 kfree(volume_info.password);
1570 FreeXid(xid);
1571 return -EINVAL;
1572 }
1573
1574
1575 if (srvTcp) {
1576 cFYI(1, ("Existing tcp session with server found "));
1577 } else { /* create socket */
1578 if(volume_info.port)
1579 sin_server.sin_port = htons(volume_info.port);
1580 else
1581 sin_server.sin_port = 0;
1582 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1583 if (rc < 0) {
1584 cERROR(1,
1585 ("Error connecting to IPv4 socket. Aborting operation"));
1586 if(csocket != NULL)
1587 sock_release(csocket);
1588 if(volume_info.UNC)
1589 kfree(volume_info.UNC);
1590 if(volume_info.password)
1591 kfree(volume_info.password);
1592 FreeXid(xid);
1593 return rc;
1594 }
1595
1596 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1597 if (srvTcp == NULL) {
1598 rc = -ENOMEM;
1599 sock_release(csocket);
1600 if(volume_info.UNC)
1601 kfree(volume_info.UNC);
1602 if(volume_info.password)
1603 kfree(volume_info.password);
1604 FreeXid(xid);
1605 return rc;
1606 } else {
1607 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1608 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1609 atomic_set(&srvTcp->inFlight,0);
1610 /* BB Add code for ipv6 case too */
1611 srvTcp->ssocket = csocket;
1612 srvTcp->protocolType = IPV4;
1613 init_waitqueue_head(&srvTcp->response_q);
1614 init_waitqueue_head(&srvTcp->request_q);
1615 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1616 /* at this point we are the only ones with the pointer
1617 to the struct since the kernel thread not created yet
1618 so no need to spinlock this init of tcpStatus */
1619 srvTcp->tcpStatus = CifsNew;
1620 init_MUTEX(&srvTcp->tcpSem);
1621 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1622 CLONE_FS | CLONE_FILES | CLONE_VM);
1623 if(rc < 0) {
1624 rc = -ENOMEM;
1625 sock_release(csocket);
1626 if(volume_info.UNC)
1627 kfree(volume_info.UNC);
1628 if(volume_info.password)
1629 kfree(volume_info.password);
1630 FreeXid(xid);
1631 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001632 }
1633 wait_for_completion(&cifsd_complete);
1634 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001636 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 }
1638 }
1639
1640 if (existingCifsSes) {
1641 pSesInfo = existingCifsSes;
1642 cFYI(1, ("Existing smb sess found "));
1643 if(volume_info.password)
1644 kfree(volume_info.password);
1645 /* volume_info.UNC freed at end of function */
1646 } else if (!rc) {
1647 cFYI(1, ("Existing smb sess not found "));
1648 pSesInfo = sesInfoAlloc();
1649 if (pSesInfo == NULL)
1650 rc = -ENOMEM;
1651 else {
1652 pSesInfo->server = srvTcp;
1653 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1654 NIPQUAD(sin_server.sin_addr.s_addr));
1655 }
1656
1657 if (!rc){
1658 /* volume_info.password freed at unmount */
1659 if (volume_info.password)
1660 pSesInfo->password = volume_info.password;
1661 if (volume_info.username)
1662 strncpy(pSesInfo->userName,
1663 volume_info.username,MAX_USERNAME_SIZE);
1664 if (volume_info.domainname)
1665 strncpy(pSesInfo->domainName,
1666 volume_info.domainname,MAX_USERNAME_SIZE);
1667 pSesInfo->linux_uid = volume_info.linux_uid;
1668 down(&pSesInfo->sesSem);
1669 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1670 up(&pSesInfo->sesSem);
1671 if(!rc)
1672 atomic_inc(&srvTcp->socketUseCount);
1673 } else
1674 if(volume_info.password)
1675 kfree(volume_info.password);
1676 }
1677
1678 /* search for existing tcon to this server share */
1679 if (!rc) {
1680 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1681 cifs_sb->rsize = volume_info.rsize;
1682 else
1683 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1684 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1685 cifs_sb->wsize = volume_info.wsize;
1686 else
1687 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1688 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1689 cifs_sb->rsize = PAGE_CACHE_SIZE;
1690 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1691 }
1692 cifs_sb->mnt_uid = volume_info.linux_uid;
1693 cifs_sb->mnt_gid = volume_info.linux_gid;
1694 cifs_sb->mnt_file_mode = volume_info.file_mode;
1695 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1696 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1697
1698 if(volume_info.noperm)
1699 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1700 if(volume_info.setuids)
1701 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1702 if(volume_info.server_ino)
1703 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001704 if(volume_info.remap)
1705 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 if(volume_info.no_xattr)
1707 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve Frenchd7245c22005-07-14 18:25:12 -05001708 if(volume_info.sfu_emul)
1709 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001710 if(volume_info.nocase)
1711 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CASE_INSENS;
1712 if(volume_info.nobrl)
1713 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Jeremy Allisonac670552005-06-22 17:26:35 -07001714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 if(volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001716 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1718 }
1719
1720 tcon =
1721 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1722 volume_info.username);
1723 if (tcon) {
1724 cFYI(1, ("Found match on UNC path "));
1725 /* we can have only one retry value for a connection
1726 to a share so for resources mounted more than once
1727 to the same server share the last value passed in
1728 for the retry flag is used */
1729 tcon->retry = volume_info.retry;
1730 } else {
1731 tcon = tconInfoAlloc();
1732 if (tcon == NULL)
1733 rc = -ENOMEM;
1734 else {
1735 /* check for null share name ie connect to dfs root */
1736
1737 /* BB check if this works for exactly length three strings */
1738 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1739 && (strchr(volume_info.UNC + 3, '/') ==
1740 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001741 rc = connect_to_dfs_path(xid, pSesInfo,
1742 "", cifs_sb->local_nls,
1743 cifs_sb->mnt_cifs_flags &
1744 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 if(volume_info.UNC)
1746 kfree(volume_info.UNC);
1747 FreeXid(xid);
1748 return -ENODEV;
1749 } else {
1750 rc = CIFSTCon(xid, pSesInfo,
1751 volume_info.UNC,
1752 tcon, cifs_sb->local_nls);
1753 cFYI(1, ("CIFS Tcon rc = %d", rc));
1754 }
1755 if (!rc) {
1756 atomic_inc(&pSesInfo->inUse);
1757 tcon->retry = volume_info.retry;
1758 }
1759 }
1760 }
1761 }
1762 if(pSesInfo) {
1763 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1764 sb->s_maxbytes = (u64) 1 << 63;
1765 } else
1766 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1767 }
1768
1769 sb->s_time_gran = 100;
1770
1771/* on error free sesinfo and tcon struct if needed */
1772 if (rc) {
1773 /* if session setup failed, use count is zero but
1774 we still need to free cifsd thread */
1775 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1776 spin_lock(&GlobalMid_Lock);
1777 srvTcp->tcpStatus = CifsExiting;
1778 spin_unlock(&GlobalMid_Lock);
Steve Frenchf1914012005-08-18 09:37:34 -07001779 if(srvTcp->tsk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 send_sig(SIGKILL,srvTcp->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001781 wait_for_completion(&cifsd_complete);
1782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 }
1784 /* If find_unc succeeded then rc == 0 so we can not end */
1785 if (tcon) /* up accidently freeing someone elses tcon struct */
1786 tconInfoFree(tcon);
1787 if (existingCifsSes == NULL) {
1788 if (pSesInfo) {
1789 if ((pSesInfo->server) &&
1790 (pSesInfo->status == CifsGood)) {
1791 int temp_rc;
1792 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1793 /* if the socketUseCount is now zero */
1794 if((temp_rc == -ESHUTDOWN) &&
Steve Frenchf1914012005-08-18 09:37:34 -07001795 (pSesInfo->server->tsk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 send_sig(SIGKILL,pSesInfo->server->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001797 wait_for_completion(&cifsd_complete);
1798 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 } else
1800 cFYI(1, ("No session or bad tcon"));
1801 sesInfoFree(pSesInfo);
1802 /* pSesInfo = NULL; */
1803 }
1804 }
1805 } else {
1806 atomic_inc(&tcon->useCount);
1807 cifs_sb->tcon = tcon;
1808 tcon->ses = pSesInfo;
1809
1810 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001811 CIFSSMBQFSDeviceInfo(xid, tcon);
1812 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001814 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 if(!volume_info.no_psx_acl) {
1816 if(CIFS_UNIX_POSIX_ACL_CAP &
1817 le64_to_cpu(tcon->fsUnixInfo.Capability))
1818 cFYI(1,("server negotiated posix acl support"));
1819 sb->s_flags |= MS_POSIXACL;
1820 }
Jeremy Allisonac670552005-06-22 17:26:35 -07001821
1822 /* Try and negotiate POSIX pathnames if we can. */
1823 if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
1824 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French45abc6e2005-06-23 13:42:03 -05001825 if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
Jeremy Allisonac670552005-06-22 17:26:35 -07001826 cFYI(1,("negotiated posix pathnames support"));
1827 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
1828 } else {
1829 cFYI(1,("posix pathnames support requested but not supported"));
1830 }
1831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 }
1833 }
1834 }
1835
1836 /* volume_info.password is freed above when existing session found
1837 (in which case it is not needed anymore) but when new sesion is created
1838 the password ptr is put in the new session structure (in which case the
1839 password will be freed at unmount time) */
1840 if(volume_info.UNC)
1841 kfree(volume_info.UNC);
1842 FreeXid(xid);
1843 return rc;
1844}
1845
1846static int
1847CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1848 char session_key[CIFS_SESSION_KEY_SIZE],
1849 const struct nls_table *nls_codepage)
1850{
1851 struct smb_hdr *smb_buffer;
1852 struct smb_hdr *smb_buffer_response;
1853 SESSION_SETUP_ANDX *pSMB;
1854 SESSION_SETUP_ANDX *pSMBr;
1855 char *bcc_ptr;
1856 char *user;
1857 char *domain;
1858 int rc = 0;
1859 int remaining_words = 0;
1860 int bytes_returned = 0;
1861 int len;
1862 __u32 capabilities;
1863 __u16 count;
1864
1865 cFYI(1, ("In sesssetup "));
1866 if(ses == NULL)
1867 return -EINVAL;
1868 user = ses->userName;
1869 domain = ses->domainName;
1870 smb_buffer = cifs_buf_get();
1871 if (smb_buffer == NULL) {
1872 return -ENOMEM;
1873 }
1874 smb_buffer_response = smb_buffer;
1875 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1876
1877 /* send SMBsessionSetup here */
1878 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1879 NULL /* no tCon exists yet */ , 13 /* wct */ );
1880
Steve French1982c342005-08-17 12:38:22 -07001881 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 pSMB->req_no_secext.AndXCommand = 0xFF;
1883 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1884 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1885
1886 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1887 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1888
1889 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1890 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1891 if (ses->capabilities & CAP_UNICODE) {
1892 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1893 capabilities |= CAP_UNICODE;
1894 }
1895 if (ses->capabilities & CAP_STATUS32) {
1896 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1897 capabilities |= CAP_STATUS32;
1898 }
1899 if (ses->capabilities & CAP_DFS) {
1900 smb_buffer->Flags2 |= SMBFLG2_DFS;
1901 capabilities |= CAP_DFS;
1902 }
1903 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1904
1905 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1906 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1907
1908 pSMB->req_no_secext.CaseSensitivePasswordLength =
1909 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1910 bcc_ptr = pByteArea(smb_buffer);
1911 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1912 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1913 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1914 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1915
1916 if (ses->capabilities & CAP_UNICODE) {
1917 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1918 *bcc_ptr = 0;
1919 bcc_ptr++;
1920 }
1921 if(user == NULL)
1922 bytes_returned = 0; /* skill null user */
1923 else
1924 bytes_returned =
1925 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1926 nls_codepage);
1927 /* convert number of 16 bit words to bytes */
1928 bcc_ptr += 2 * bytes_returned;
1929 bcc_ptr += 2; /* trailing null */
1930 if (domain == NULL)
1931 bytes_returned =
1932 cifs_strtoUCS((wchar_t *) bcc_ptr,
1933 "CIFS_LINUX_DOM", 32, nls_codepage);
1934 else
1935 bytes_returned =
1936 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1937 nls_codepage);
1938 bcc_ptr += 2 * bytes_returned;
1939 bcc_ptr += 2;
1940 bytes_returned =
1941 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1942 32, nls_codepage);
1943 bcc_ptr += 2 * bytes_returned;
1944 bytes_returned =
1945 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1946 32, nls_codepage);
1947 bcc_ptr += 2 * bytes_returned;
1948 bcc_ptr += 2;
1949 bytes_returned =
1950 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1951 64, nls_codepage);
1952 bcc_ptr += 2 * bytes_returned;
1953 bcc_ptr += 2;
1954 } else {
1955 if(user != NULL) {
1956 strncpy(bcc_ptr, user, 200);
1957 bcc_ptr += strnlen(user, 200);
1958 }
1959 *bcc_ptr = 0;
1960 bcc_ptr++;
1961 if (domain == NULL) {
1962 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1963 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1964 } else {
1965 strncpy(bcc_ptr, domain, 64);
1966 bcc_ptr += strnlen(domain, 64);
1967 *bcc_ptr = 0;
1968 bcc_ptr++;
1969 }
1970 strcpy(bcc_ptr, "Linux version ");
1971 bcc_ptr += strlen("Linux version ");
1972 strcpy(bcc_ptr, system_utsname.release);
1973 bcc_ptr += strlen(system_utsname.release) + 1;
1974 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1975 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1976 }
1977 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1978 smb_buffer->smb_buf_length += count;
1979 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
1980
1981 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1982 &bytes_returned, 1);
1983 if (rc) {
1984/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1985 } else if ((smb_buffer_response->WordCount == 3)
1986 || (smb_buffer_response->WordCount == 4)) {
1987 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1988 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1989 if (action & GUEST_LOGIN)
1990 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
1991 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1992 cFYI(1, ("UID = %d ", ses->Suid));
1993 /* response can have either 3 or 4 word count - Samba sends 3 */
1994 bcc_ptr = pByteArea(smb_buffer_response);
1995 if ((pSMBr->resp.hdr.WordCount == 3)
1996 || ((pSMBr->resp.hdr.WordCount == 4)
1997 && (blob_len < pSMBr->resp.ByteCount))) {
1998 if (pSMBr->resp.hdr.WordCount == 4)
1999 bcc_ptr += blob_len;
2000
2001 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2002 if ((long) (bcc_ptr) % 2) {
2003 remaining_words =
2004 (BCC(smb_buffer_response) - 1) /2;
2005 bcc_ptr++; /* Unicode strings must be word aligned */
2006 } else {
2007 remaining_words =
2008 BCC(smb_buffer_response) / 2;
2009 }
2010 len =
2011 UniStrnlen((wchar_t *) bcc_ptr,
2012 remaining_words - 1);
2013/* We look for obvious messed up bcc or strings in response so we do not go off
2014 the end since (at least) WIN2K and Windows XP have a major bug in not null
2015 terminating last Unicode string in response */
Steve French433dc242005-04-28 22:41:08 -07002016 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2017 if(ses->serverOS == NULL)
2018 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 cifs_strfromUCS_le(ses->serverOS,
2020 (wchar_t *)bcc_ptr, len,nls_codepage);
2021 bcc_ptr += 2 * (len + 1);
2022 remaining_words -= len + 1;
2023 ses->serverOS[2 * len] = 0;
2024 ses->serverOS[1 + (2 * len)] = 0;
2025 if (remaining_words > 0) {
2026 len = UniStrnlen((wchar_t *)bcc_ptr,
2027 remaining_words-1);
Steve French433dc242005-04-28 22:41:08 -07002028 ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
2029 if(ses->serverNOS == NULL)
2030 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 cifs_strfromUCS_le(ses->serverNOS,
2032 (wchar_t *)bcc_ptr,len,nls_codepage);
2033 bcc_ptr += 2 * (len + 1);
2034 ses->serverNOS[2 * len] = 0;
2035 ses->serverNOS[1 + (2 * len)] = 0;
2036 if(strncmp(ses->serverNOS,
2037 "NT LAN Manager 4",16) == 0) {
2038 cFYI(1,("NT4 server"));
2039 ses->flags |= CIFS_SES_NT4;
2040 }
2041 remaining_words -= len + 1;
2042 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002043 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2045 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002046 kcalloc(1, 2*(len+1),GFP_KERNEL);
2047 if(ses->serverDomain == NULL)
2048 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 cifs_strfromUCS_le(ses->serverDomain,
2050 (wchar_t *)bcc_ptr,len,nls_codepage);
2051 bcc_ptr += 2 * (len + 1);
2052 ses->serverDomain[2*len] = 0;
2053 ses->serverDomain[1+(2*len)] = 0;
2054 } /* else no more room so create dummy domain string */
2055 else
Steve French433dc242005-04-28 22:41:08 -07002056 ses->serverDomain =
2057 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002059 /* if these kcallocs fail not much we
2060 can do, but better to not fail the
2061 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002063 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002065 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 }
2067 } else { /* ASCII */
2068 len = strnlen(bcc_ptr, 1024);
2069 if (((long) bcc_ptr + len) - (long)
2070 pByteArea(smb_buffer_response)
2071 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002072 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
2073 if(ses->serverOS == NULL)
2074 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 strncpy(ses->serverOS,bcc_ptr, len);
2076
2077 bcc_ptr += len;
2078 bcc_ptr[0] = 0; /* null terminate the string */
2079 bcc_ptr++;
2080
2081 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002082 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2083 if(ses->serverNOS == NULL)
2084 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 strncpy(ses->serverNOS, bcc_ptr, len);
2086 bcc_ptr += len;
2087 bcc_ptr[0] = 0;
2088 bcc_ptr++;
2089
2090 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002091 ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
2092 if(ses->serverDomain == NULL)
2093 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 strncpy(ses->serverDomain, bcc_ptr, len);
2095 bcc_ptr += len;
2096 bcc_ptr[0] = 0;
2097 bcc_ptr++;
2098 } else
2099 cFYI(1,
2100 ("Variable field of length %d extends beyond end of smb ",
2101 len));
2102 }
2103 } else {
2104 cERROR(1,
2105 (" Security Blob Length extends beyond end of SMB"));
2106 }
2107 } else {
2108 cERROR(1,
2109 (" Invalid Word count %d: ",
2110 smb_buffer_response->WordCount));
2111 rc = -EIO;
2112 }
Steve French433dc242005-04-28 22:41:08 -07002113sesssetup_nomem: /* do not return an error on nomem for the info strings,
2114 since that could make reconnection harder, and
2115 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 if (smb_buffer)
2117 cifs_buf_release(smb_buffer);
2118
2119 return rc;
2120}
2121
2122static int
2123CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2124 char *SecurityBlob,int SecurityBlobLength,
2125 const struct nls_table *nls_codepage)
2126{
2127 struct smb_hdr *smb_buffer;
2128 struct smb_hdr *smb_buffer_response;
2129 SESSION_SETUP_ANDX *pSMB;
2130 SESSION_SETUP_ANDX *pSMBr;
2131 char *bcc_ptr;
2132 char *user;
2133 char *domain;
2134 int rc = 0;
2135 int remaining_words = 0;
2136 int bytes_returned = 0;
2137 int len;
2138 __u32 capabilities;
2139 __u16 count;
2140
2141 cFYI(1, ("In spnego sesssetup "));
2142 if(ses == NULL)
2143 return -EINVAL;
2144 user = ses->userName;
2145 domain = ses->domainName;
2146
2147 smb_buffer = cifs_buf_get();
2148 if (smb_buffer == NULL) {
2149 return -ENOMEM;
2150 }
2151 smb_buffer_response = smb_buffer;
2152 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2153
2154 /* send SMBsessionSetup here */
2155 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2156 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002157
2158 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2160 pSMB->req.AndXCommand = 0xFF;
2161 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2162 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2163
2164 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2165 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2166
2167 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2168 CAP_EXTENDED_SECURITY;
2169 if (ses->capabilities & CAP_UNICODE) {
2170 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2171 capabilities |= CAP_UNICODE;
2172 }
2173 if (ses->capabilities & CAP_STATUS32) {
2174 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2175 capabilities |= CAP_STATUS32;
2176 }
2177 if (ses->capabilities & CAP_DFS) {
2178 smb_buffer->Flags2 |= SMBFLG2_DFS;
2179 capabilities |= CAP_DFS;
2180 }
2181 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2182
2183 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2184 bcc_ptr = pByteArea(smb_buffer);
2185 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2186 bcc_ptr += SecurityBlobLength;
2187
2188 if (ses->capabilities & CAP_UNICODE) {
2189 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2190 *bcc_ptr = 0;
2191 bcc_ptr++;
2192 }
2193 bytes_returned =
2194 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2195 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2196 bcc_ptr += 2; /* trailing null */
2197 if (domain == NULL)
2198 bytes_returned =
2199 cifs_strtoUCS((wchar_t *) bcc_ptr,
2200 "CIFS_LINUX_DOM", 32, nls_codepage);
2201 else
2202 bytes_returned =
2203 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2204 nls_codepage);
2205 bcc_ptr += 2 * bytes_returned;
2206 bcc_ptr += 2;
2207 bytes_returned =
2208 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2209 32, nls_codepage);
2210 bcc_ptr += 2 * bytes_returned;
2211 bytes_returned =
2212 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2213 nls_codepage);
2214 bcc_ptr += 2 * bytes_returned;
2215 bcc_ptr += 2;
2216 bytes_returned =
2217 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2218 64, nls_codepage);
2219 bcc_ptr += 2 * bytes_returned;
2220 bcc_ptr += 2;
2221 } else {
2222 strncpy(bcc_ptr, user, 200);
2223 bcc_ptr += strnlen(user, 200);
2224 *bcc_ptr = 0;
2225 bcc_ptr++;
2226 if (domain == NULL) {
2227 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2228 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2229 } else {
2230 strncpy(bcc_ptr, domain, 64);
2231 bcc_ptr += strnlen(domain, 64);
2232 *bcc_ptr = 0;
2233 bcc_ptr++;
2234 }
2235 strcpy(bcc_ptr, "Linux version ");
2236 bcc_ptr += strlen("Linux version ");
2237 strcpy(bcc_ptr, system_utsname.release);
2238 bcc_ptr += strlen(system_utsname.release) + 1;
2239 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2240 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2241 }
2242 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2243 smb_buffer->smb_buf_length += count;
2244 pSMB->req.ByteCount = cpu_to_le16(count);
2245
2246 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2247 &bytes_returned, 1);
2248 if (rc) {
2249/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2250 } else if ((smb_buffer_response->WordCount == 3)
2251 || (smb_buffer_response->WordCount == 4)) {
2252 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2253 __u16 blob_len =
2254 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2255 if (action & GUEST_LOGIN)
2256 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2257 if (ses) {
2258 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2259 cFYI(1, ("UID = %d ", ses->Suid));
2260 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2261
2262 /* BB Fix below to make endian neutral !! */
2263
2264 if ((pSMBr->resp.hdr.WordCount == 3)
2265 || ((pSMBr->resp.hdr.WordCount == 4)
2266 && (blob_len <
2267 pSMBr->resp.ByteCount))) {
2268 if (pSMBr->resp.hdr.WordCount == 4) {
2269 bcc_ptr +=
2270 blob_len;
2271 cFYI(1,
2272 ("Security Blob Length %d ",
2273 blob_len));
2274 }
2275
2276 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2277 if ((long) (bcc_ptr) % 2) {
2278 remaining_words =
2279 (BCC(smb_buffer_response)
2280 - 1) / 2;
2281 bcc_ptr++; /* Unicode strings must be word aligned */
2282 } else {
2283 remaining_words =
2284 BCC
2285 (smb_buffer_response) / 2;
2286 }
2287 len =
2288 UniStrnlen((wchar_t *) bcc_ptr,
2289 remaining_words - 1);
2290/* We look for obvious messed up bcc or strings in response so we do not go off
2291 the end since (at least) WIN2K and Windows XP have a major bug in not null
2292 terminating last Unicode string in response */
2293 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002294 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 cifs_strfromUCS_le(ses->serverOS,
2296 (wchar_t *)
2297 bcc_ptr, len,
2298 nls_codepage);
2299 bcc_ptr += 2 * (len + 1);
2300 remaining_words -= len + 1;
2301 ses->serverOS[2 * len] = 0;
2302 ses->serverOS[1 + (2 * len)] = 0;
2303 if (remaining_words > 0) {
2304 len = UniStrnlen((wchar_t *)bcc_ptr,
2305 remaining_words
2306 - 1);
2307 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002308 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 GFP_KERNEL);
2310 cifs_strfromUCS_le(ses->serverNOS,
2311 (wchar_t *)bcc_ptr,
2312 len,
2313 nls_codepage);
2314 bcc_ptr += 2 * (len + 1);
2315 ses->serverNOS[2 * len] = 0;
2316 ses->serverNOS[1 + (2 * len)] = 0;
2317 remaining_words -= len + 1;
2318 if (remaining_words > 0) {
2319 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2320 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve French433dc242005-04-28 22:41:08 -07002321 ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 cifs_strfromUCS_le(ses->serverDomain,
2323 (wchar_t *)bcc_ptr,
2324 len,
2325 nls_codepage);
2326 bcc_ptr += 2*(len+1);
2327 ses->serverDomain[2*len] = 0;
2328 ses->serverDomain[1+(2*len)] = 0;
2329 } /* else no more room so create dummy domain string */
2330 else
2331 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002332 kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002334 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2335 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 }
2337 } else { /* ASCII */
2338
2339 len = strnlen(bcc_ptr, 1024);
2340 if (((long) bcc_ptr + len) - (long)
2341 pByteArea(smb_buffer_response)
2342 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002343 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 strncpy(ses->serverOS, bcc_ptr, len);
2345
2346 bcc_ptr += len;
2347 bcc_ptr[0] = 0; /* null terminate the string */
2348 bcc_ptr++;
2349
2350 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002351 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 strncpy(ses->serverNOS, bcc_ptr, len);
2353 bcc_ptr += len;
2354 bcc_ptr[0] = 0;
2355 bcc_ptr++;
2356
2357 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002358 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 strncpy(ses->serverDomain, bcc_ptr, len);
2360 bcc_ptr += len;
2361 bcc_ptr[0] = 0;
2362 bcc_ptr++;
2363 } else
2364 cFYI(1,
2365 ("Variable field of length %d extends beyond end of smb ",
2366 len));
2367 }
2368 } else {
2369 cERROR(1,
2370 (" Security Blob Length extends beyond end of SMB"));
2371 }
2372 } else {
2373 cERROR(1, ("No session structure passed in."));
2374 }
2375 } else {
2376 cERROR(1,
2377 (" Invalid Word count %d: ",
2378 smb_buffer_response->WordCount));
2379 rc = -EIO;
2380 }
2381
2382 if (smb_buffer)
2383 cifs_buf_release(smb_buffer);
2384
2385 return rc;
2386}
2387
2388static int
2389CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2390 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2391 const struct nls_table *nls_codepage)
2392{
2393 struct smb_hdr *smb_buffer;
2394 struct smb_hdr *smb_buffer_response;
2395 SESSION_SETUP_ANDX *pSMB;
2396 SESSION_SETUP_ANDX *pSMBr;
2397 char *bcc_ptr;
2398 char *domain;
2399 int rc = 0;
2400 int remaining_words = 0;
2401 int bytes_returned = 0;
2402 int len;
2403 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2404 PNEGOTIATE_MESSAGE SecurityBlob;
2405 PCHALLENGE_MESSAGE SecurityBlob2;
2406 __u32 negotiate_flags, capabilities;
2407 __u16 count;
2408
2409 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2410 if(ses == NULL)
2411 return -EINVAL;
2412 domain = ses->domainName;
2413 *pNTLMv2_flag = FALSE;
2414 smb_buffer = cifs_buf_get();
2415 if (smb_buffer == NULL) {
2416 return -ENOMEM;
2417 }
2418 smb_buffer_response = smb_buffer;
2419 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2420 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2421
2422 /* send SMBsessionSetup here */
2423 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2424 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002425
2426 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2428 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2429
2430 pSMB->req.AndXCommand = 0xFF;
2431 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2432 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2433
2434 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2435 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2436
2437 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2438 CAP_EXTENDED_SECURITY;
2439 if (ses->capabilities & CAP_UNICODE) {
2440 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2441 capabilities |= CAP_UNICODE;
2442 }
2443 if (ses->capabilities & CAP_STATUS32) {
2444 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2445 capabilities |= CAP_STATUS32;
2446 }
2447 if (ses->capabilities & CAP_DFS) {
2448 smb_buffer->Flags2 |= SMBFLG2_DFS;
2449 capabilities |= CAP_DFS;
2450 }
2451 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2452
2453 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2454 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2455 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2456 SecurityBlob->MessageType = NtLmNegotiate;
2457 negotiate_flags =
2458 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2459 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2460 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2461 if(sign_CIFS_PDUs)
2462 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2463 if(ntlmv2_support)
2464 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2465 /* setup pointers to domain name and workstation name */
2466 bcc_ptr += SecurityBlobLength;
2467
2468 SecurityBlob->WorkstationName.Buffer = 0;
2469 SecurityBlob->WorkstationName.Length = 0;
2470 SecurityBlob->WorkstationName.MaximumLength = 0;
2471
2472 if (domain == NULL) {
2473 SecurityBlob->DomainName.Buffer = 0;
2474 SecurityBlob->DomainName.Length = 0;
2475 SecurityBlob->DomainName.MaximumLength = 0;
2476 } else {
2477 __u16 len;
2478 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2479 strncpy(bcc_ptr, domain, 63);
2480 len = strnlen(domain, 64);
2481 SecurityBlob->DomainName.MaximumLength =
2482 cpu_to_le16(len);
2483 SecurityBlob->DomainName.Buffer =
2484 cpu_to_le32((long) &SecurityBlob->
2485 DomainString -
2486 (long) &SecurityBlob->Signature);
2487 bcc_ptr += len;
2488 SecurityBlobLength += len;
2489 SecurityBlob->DomainName.Length =
2490 cpu_to_le16(len);
2491 }
2492 if (ses->capabilities & CAP_UNICODE) {
2493 if ((long) bcc_ptr % 2) {
2494 *bcc_ptr = 0;
2495 bcc_ptr++;
2496 }
2497
2498 bytes_returned =
2499 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2500 32, nls_codepage);
2501 bcc_ptr += 2 * bytes_returned;
2502 bytes_returned =
2503 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2504 nls_codepage);
2505 bcc_ptr += 2 * bytes_returned;
2506 bcc_ptr += 2; /* null terminate Linux version */
2507 bytes_returned =
2508 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2509 64, nls_codepage);
2510 bcc_ptr += 2 * bytes_returned;
2511 *(bcc_ptr + 1) = 0;
2512 *(bcc_ptr + 2) = 0;
2513 bcc_ptr += 2; /* null terminate network opsys string */
2514 *(bcc_ptr + 1) = 0;
2515 *(bcc_ptr + 2) = 0;
2516 bcc_ptr += 2; /* null domain */
2517 } else { /* ASCII */
2518 strcpy(bcc_ptr, "Linux version ");
2519 bcc_ptr += strlen("Linux version ");
2520 strcpy(bcc_ptr, system_utsname.release);
2521 bcc_ptr += strlen(system_utsname.release) + 1;
2522 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2523 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2524 bcc_ptr++; /* empty domain field */
2525 *bcc_ptr = 0;
2526 }
2527 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2528 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2529 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2530 smb_buffer->smb_buf_length += count;
2531 pSMB->req.ByteCount = cpu_to_le16(count);
2532
2533 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2534 &bytes_returned, 1);
2535
2536 if (smb_buffer_response->Status.CifsError ==
2537 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2538 rc = 0;
2539
2540 if (rc) {
2541/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2542 } else if ((smb_buffer_response->WordCount == 3)
2543 || (smb_buffer_response->WordCount == 4)) {
2544 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2545 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2546
2547 if (action & GUEST_LOGIN)
2548 cFYI(1, (" Guest login"));
2549 /* Do we want to set anything in SesInfo struct when guest login? */
2550
2551 bcc_ptr = pByteArea(smb_buffer_response);
2552 /* response can have either 3 or 4 word count - Samba sends 3 */
2553
2554 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2555 if (SecurityBlob2->MessageType != NtLmChallenge) {
2556 cFYI(1,
2557 ("Unexpected NTLMSSP message type received %d",
2558 SecurityBlob2->MessageType));
2559 } else if (ses) {
2560 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2561 cFYI(1, ("UID = %d ", ses->Suid));
2562 if ((pSMBr->resp.hdr.WordCount == 3)
2563 || ((pSMBr->resp.hdr.WordCount == 4)
2564 && (blob_len <
2565 pSMBr->resp.ByteCount))) {
2566
2567 if (pSMBr->resp.hdr.WordCount == 4) {
2568 bcc_ptr += blob_len;
2569 cFYI(1,
2570 ("Security Blob Length %d ",
2571 blob_len));
2572 }
2573
2574 cFYI(1, ("NTLMSSP Challenge rcvd "));
2575
2576 memcpy(ses->server->cryptKey,
2577 SecurityBlob2->Challenge,
2578 CIFS_CRYPTO_KEY_SIZE);
2579 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2580 *pNTLMv2_flag = TRUE;
2581
2582 if((SecurityBlob2->NegotiateFlags &
2583 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2584 || (sign_CIFS_PDUs > 1))
2585 ses->server->secMode |=
2586 SECMODE_SIGN_REQUIRED;
2587 if ((SecurityBlob2->NegotiateFlags &
2588 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2589 ses->server->secMode |=
2590 SECMODE_SIGN_ENABLED;
2591
2592 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2593 if ((long) (bcc_ptr) % 2) {
2594 remaining_words =
2595 (BCC(smb_buffer_response)
2596 - 1) / 2;
2597 bcc_ptr++; /* Unicode strings must be word aligned */
2598 } else {
2599 remaining_words =
2600 BCC
2601 (smb_buffer_response) / 2;
2602 }
2603 len =
2604 UniStrnlen((wchar_t *) bcc_ptr,
2605 remaining_words - 1);
2606/* We look for obvious messed up bcc or strings in response so we do not go off
2607 the end since (at least) WIN2K and Windows XP have a major bug in not null
2608 terminating last Unicode string in response */
2609 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002610 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 cifs_strfromUCS_le(ses->serverOS,
2612 (wchar_t *)
2613 bcc_ptr, len,
2614 nls_codepage);
2615 bcc_ptr += 2 * (len + 1);
2616 remaining_words -= len + 1;
2617 ses->serverOS[2 * len] = 0;
2618 ses->serverOS[1 + (2 * len)] = 0;
2619 if (remaining_words > 0) {
2620 len = UniStrnlen((wchar_t *)
2621 bcc_ptr,
2622 remaining_words
2623 - 1);
2624 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002625 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 GFP_KERNEL);
2627 cifs_strfromUCS_le(ses->
2628 serverNOS,
2629 (wchar_t *)
2630 bcc_ptr,
2631 len,
2632 nls_codepage);
2633 bcc_ptr += 2 * (len + 1);
2634 ses->serverNOS[2 * len] = 0;
2635 ses->serverNOS[1 +
2636 (2 * len)] = 0;
2637 remaining_words -= len + 1;
2638 if (remaining_words > 0) {
2639 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2640 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2641 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002642 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 (len +
2644 1),
2645 GFP_KERNEL);
2646 cifs_strfromUCS_le
2647 (ses->
2648 serverDomain,
2649 (wchar_t *)
2650 bcc_ptr, len,
2651 nls_codepage);
2652 bcc_ptr +=
2653 2 * (len + 1);
2654 ses->
2655 serverDomain[2
2656 * len]
2657 = 0;
2658 ses->
2659 serverDomain[1
2660 +
2661 (2
2662 *
2663 len)]
2664 = 0;
2665 } /* else no more room so create dummy domain string */
2666 else
2667 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002668 kcalloc(1, 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 GFP_KERNEL);
2670 } else { /* no room so create dummy domain and NOS string */
2671 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002672 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002674 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 }
2676 } else { /* ASCII */
2677 len = strnlen(bcc_ptr, 1024);
2678 if (((long) bcc_ptr + len) - (long)
2679 pByteArea(smb_buffer_response)
2680 <= BCC(smb_buffer_response)) {
2681 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002682 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 GFP_KERNEL);
2684 strncpy(ses->serverOS,
2685 bcc_ptr, len);
2686
2687 bcc_ptr += len;
2688 bcc_ptr[0] = 0; /* null terminate string */
2689 bcc_ptr++;
2690
2691 len = strnlen(bcc_ptr, 1024);
2692 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002693 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 GFP_KERNEL);
2695 strncpy(ses->serverNOS, bcc_ptr, len);
2696 bcc_ptr += len;
2697 bcc_ptr[0] = 0;
2698 bcc_ptr++;
2699
2700 len = strnlen(bcc_ptr, 1024);
2701 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002702 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 GFP_KERNEL);
2704 strncpy(ses->serverDomain, bcc_ptr, len);
2705 bcc_ptr += len;
2706 bcc_ptr[0] = 0;
2707 bcc_ptr++;
2708 } else
2709 cFYI(1,
2710 ("Variable field of length %d extends beyond end of smb ",
2711 len));
2712 }
2713 } else {
2714 cERROR(1,
2715 (" Security Blob Length extends beyond end of SMB"));
2716 }
2717 } else {
2718 cERROR(1, ("No session structure passed in."));
2719 }
2720 } else {
2721 cERROR(1,
2722 (" Invalid Word count %d: ",
2723 smb_buffer_response->WordCount));
2724 rc = -EIO;
2725 }
2726
2727 if (smb_buffer)
2728 cifs_buf_release(smb_buffer);
2729
2730 return rc;
2731}
2732static int
2733CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2734 char *ntlm_session_key, int ntlmv2_flag,
2735 const struct nls_table *nls_codepage)
2736{
2737 struct smb_hdr *smb_buffer;
2738 struct smb_hdr *smb_buffer_response;
2739 SESSION_SETUP_ANDX *pSMB;
2740 SESSION_SETUP_ANDX *pSMBr;
2741 char *bcc_ptr;
2742 char *user;
2743 char *domain;
2744 int rc = 0;
2745 int remaining_words = 0;
2746 int bytes_returned = 0;
2747 int len;
2748 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2749 PAUTHENTICATE_MESSAGE SecurityBlob;
2750 __u32 negotiate_flags, capabilities;
2751 __u16 count;
2752
2753 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2754 if(ses == NULL)
2755 return -EINVAL;
2756 user = ses->userName;
2757 domain = ses->domainName;
2758 smb_buffer = cifs_buf_get();
2759 if (smb_buffer == NULL) {
2760 return -ENOMEM;
2761 }
2762 smb_buffer_response = smb_buffer;
2763 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2764 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2765
2766 /* send SMBsessionSetup here */
2767 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2768 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002769
2770 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2772 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2773 pSMB->req.AndXCommand = 0xFF;
2774 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2775 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2776
2777 pSMB->req.hdr.Uid = ses->Suid;
2778
2779 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2780 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2781
2782 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2783 CAP_EXTENDED_SECURITY;
2784 if (ses->capabilities & CAP_UNICODE) {
2785 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2786 capabilities |= CAP_UNICODE;
2787 }
2788 if (ses->capabilities & CAP_STATUS32) {
2789 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2790 capabilities |= CAP_STATUS32;
2791 }
2792 if (ses->capabilities & CAP_DFS) {
2793 smb_buffer->Flags2 |= SMBFLG2_DFS;
2794 capabilities |= CAP_DFS;
2795 }
2796 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2797
2798 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2799 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2800 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2801 SecurityBlob->MessageType = NtLmAuthenticate;
2802 bcc_ptr += SecurityBlobLength;
2803 negotiate_flags =
2804 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2805 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2806 0x80000000 | NTLMSSP_NEGOTIATE_128;
2807 if(sign_CIFS_PDUs)
2808 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2809 if(ntlmv2_flag)
2810 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2811
2812/* setup pointers to domain name and workstation name */
2813
2814 SecurityBlob->WorkstationName.Buffer = 0;
2815 SecurityBlob->WorkstationName.Length = 0;
2816 SecurityBlob->WorkstationName.MaximumLength = 0;
2817 SecurityBlob->SessionKey.Length = 0;
2818 SecurityBlob->SessionKey.MaximumLength = 0;
2819 SecurityBlob->SessionKey.Buffer = 0;
2820
2821 SecurityBlob->LmChallengeResponse.Length = 0;
2822 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2823 SecurityBlob->LmChallengeResponse.Buffer = 0;
2824
2825 SecurityBlob->NtChallengeResponse.Length =
2826 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2827 SecurityBlob->NtChallengeResponse.MaximumLength =
2828 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2829 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2830 SecurityBlob->NtChallengeResponse.Buffer =
2831 cpu_to_le32(SecurityBlobLength);
2832 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2833 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2834
2835 if (ses->capabilities & CAP_UNICODE) {
2836 if (domain == NULL) {
2837 SecurityBlob->DomainName.Buffer = 0;
2838 SecurityBlob->DomainName.Length = 0;
2839 SecurityBlob->DomainName.MaximumLength = 0;
2840 } else {
2841 __u16 len =
2842 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2843 nls_codepage);
2844 len *= 2;
2845 SecurityBlob->DomainName.MaximumLength =
2846 cpu_to_le16(len);
2847 SecurityBlob->DomainName.Buffer =
2848 cpu_to_le32(SecurityBlobLength);
2849 bcc_ptr += len;
2850 SecurityBlobLength += len;
2851 SecurityBlob->DomainName.Length =
2852 cpu_to_le16(len);
2853 }
2854 if (user == NULL) {
2855 SecurityBlob->UserName.Buffer = 0;
2856 SecurityBlob->UserName.Length = 0;
2857 SecurityBlob->UserName.MaximumLength = 0;
2858 } else {
2859 __u16 len =
2860 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2861 nls_codepage);
2862 len *= 2;
2863 SecurityBlob->UserName.MaximumLength =
2864 cpu_to_le16(len);
2865 SecurityBlob->UserName.Buffer =
2866 cpu_to_le32(SecurityBlobLength);
2867 bcc_ptr += len;
2868 SecurityBlobLength += len;
2869 SecurityBlob->UserName.Length =
2870 cpu_to_le16(len);
2871 }
2872
2873 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2874 SecurityBlob->WorkstationName.Length *= 2;
2875 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2876 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2877 bcc_ptr += SecurityBlob->WorkstationName.Length;
2878 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2879 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2880
2881 if ((long) bcc_ptr % 2) {
2882 *bcc_ptr = 0;
2883 bcc_ptr++;
2884 }
2885 bytes_returned =
2886 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2887 32, nls_codepage);
2888 bcc_ptr += 2 * bytes_returned;
2889 bytes_returned =
2890 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2891 nls_codepage);
2892 bcc_ptr += 2 * bytes_returned;
2893 bcc_ptr += 2; /* null term version string */
2894 bytes_returned =
2895 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2896 64, nls_codepage);
2897 bcc_ptr += 2 * bytes_returned;
2898 *(bcc_ptr + 1) = 0;
2899 *(bcc_ptr + 2) = 0;
2900 bcc_ptr += 2; /* null terminate network opsys string */
2901 *(bcc_ptr + 1) = 0;
2902 *(bcc_ptr + 2) = 0;
2903 bcc_ptr += 2; /* null domain */
2904 } else { /* ASCII */
2905 if (domain == NULL) {
2906 SecurityBlob->DomainName.Buffer = 0;
2907 SecurityBlob->DomainName.Length = 0;
2908 SecurityBlob->DomainName.MaximumLength = 0;
2909 } else {
2910 __u16 len;
2911 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2912 strncpy(bcc_ptr, domain, 63);
2913 len = strnlen(domain, 64);
2914 SecurityBlob->DomainName.MaximumLength =
2915 cpu_to_le16(len);
2916 SecurityBlob->DomainName.Buffer =
2917 cpu_to_le32(SecurityBlobLength);
2918 bcc_ptr += len;
2919 SecurityBlobLength += len;
2920 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2921 }
2922 if (user == NULL) {
2923 SecurityBlob->UserName.Buffer = 0;
2924 SecurityBlob->UserName.Length = 0;
2925 SecurityBlob->UserName.MaximumLength = 0;
2926 } else {
2927 __u16 len;
2928 strncpy(bcc_ptr, user, 63);
2929 len = strnlen(user, 64);
2930 SecurityBlob->UserName.MaximumLength =
2931 cpu_to_le16(len);
2932 SecurityBlob->UserName.Buffer =
2933 cpu_to_le32(SecurityBlobLength);
2934 bcc_ptr += len;
2935 SecurityBlobLength += len;
2936 SecurityBlob->UserName.Length = cpu_to_le16(len);
2937 }
2938 /* BB fill in our workstation name if known BB */
2939
2940 strcpy(bcc_ptr, "Linux version ");
2941 bcc_ptr += strlen("Linux version ");
2942 strcpy(bcc_ptr, system_utsname.release);
2943 bcc_ptr += strlen(system_utsname.release) + 1;
2944 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2945 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2946 bcc_ptr++; /* null domain */
2947 *bcc_ptr = 0;
2948 }
2949 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2950 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2951 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2952 smb_buffer->smb_buf_length += count;
2953 pSMB->req.ByteCount = cpu_to_le16(count);
2954
2955 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2956 &bytes_returned, 1);
2957 if (rc) {
2958/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2959 } else if ((smb_buffer_response->WordCount == 3)
2960 || (smb_buffer_response->WordCount == 4)) {
2961 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2962 __u16 blob_len =
2963 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2964 if (action & GUEST_LOGIN)
2965 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2966/* if(SecurityBlob2->MessageType != NtLm??){
2967 cFYI("Unexpected message type on auth response is %d "));
2968 } */
2969 if (ses) {
2970 cFYI(1,
2971 ("Does UID on challenge %d match auth response UID %d ",
2972 ses->Suid, smb_buffer_response->Uid));
2973 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2974 bcc_ptr = pByteArea(smb_buffer_response);
2975 /* response can have either 3 or 4 word count - Samba sends 3 */
2976 if ((pSMBr->resp.hdr.WordCount == 3)
2977 || ((pSMBr->resp.hdr.WordCount == 4)
2978 && (blob_len <
2979 pSMBr->resp.ByteCount))) {
2980 if (pSMBr->resp.hdr.WordCount == 4) {
2981 bcc_ptr +=
2982 blob_len;
2983 cFYI(1,
2984 ("Security Blob Length %d ",
2985 blob_len));
2986 }
2987
2988 cFYI(1,
2989 ("NTLMSSP response to Authenticate "));
2990
2991 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2992 if ((long) (bcc_ptr) % 2) {
2993 remaining_words =
2994 (BCC(smb_buffer_response)
2995 - 1) / 2;
2996 bcc_ptr++; /* Unicode strings must be word aligned */
2997 } else {
2998 remaining_words = BCC(smb_buffer_response) / 2;
2999 }
3000 len =
3001 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3002/* We look for obvious messed up bcc or strings in response so we do not go off
3003 the end since (at least) WIN2K and Windows XP have a major bug in not null
3004 terminating last Unicode string in response */
3005 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07003006 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 cifs_strfromUCS_le(ses->serverOS,
3008 (wchar_t *)
3009 bcc_ptr, len,
3010 nls_codepage);
3011 bcc_ptr += 2 * (len + 1);
3012 remaining_words -= len + 1;
3013 ses->serverOS[2 * len] = 0;
3014 ses->serverOS[1 + (2 * len)] = 0;
3015 if (remaining_words > 0) {
3016 len = UniStrnlen((wchar_t *)
3017 bcc_ptr,
3018 remaining_words
3019 - 1);
3020 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07003021 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 GFP_KERNEL);
3023 cifs_strfromUCS_le(ses->
3024 serverNOS,
3025 (wchar_t *)
3026 bcc_ptr,
3027 len,
3028 nls_codepage);
3029 bcc_ptr += 2 * (len + 1);
3030 ses->serverNOS[2 * len] = 0;
3031 ses->serverNOS[1+(2*len)] = 0;
3032 remaining_words -= len + 1;
3033 if (remaining_words > 0) {
3034 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3035 /* last string not always null terminated (e.g. for Windows XP & 2000) */
3036 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07003037 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 (len +
3039 1),
3040 GFP_KERNEL);
3041 cifs_strfromUCS_le
3042 (ses->
3043 serverDomain,
3044 (wchar_t *)
3045 bcc_ptr, len,
3046 nls_codepage);
3047 bcc_ptr +=
3048 2 * (len + 1);
3049 ses->
3050 serverDomain[2
3051 * len]
3052 = 0;
3053 ses->
3054 serverDomain[1
3055 +
3056 (2
3057 *
3058 len)]
3059 = 0;
3060 } /* else no more room so create dummy domain string */
3061 else
Steve French433dc242005-04-28 22:41:08 -07003062 ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07003064 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
3065 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 }
3067 } else { /* ASCII */
3068 len = strnlen(bcc_ptr, 1024);
3069 if (((long) bcc_ptr + len) -
3070 (long) pByteArea(smb_buffer_response)
3071 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07003072 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 strncpy(ses->serverOS,bcc_ptr, len);
3074
3075 bcc_ptr += len;
3076 bcc_ptr[0] = 0; /* null terminate the string */
3077 bcc_ptr++;
3078
3079 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003080 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 strncpy(ses->serverNOS, bcc_ptr, len);
3082 bcc_ptr += len;
3083 bcc_ptr[0] = 0;
3084 bcc_ptr++;
3085
3086 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003087 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 strncpy(ses->serverDomain, bcc_ptr, len);
3089 bcc_ptr += len;
3090 bcc_ptr[0] = 0;
3091 bcc_ptr++;
3092 } else
3093 cFYI(1,
3094 ("Variable field of length %d extends beyond end of smb ",
3095 len));
3096 }
3097 } else {
3098 cERROR(1,
3099 (" Security Blob Length extends beyond end of SMB"));
3100 }
3101 } else {
3102 cERROR(1, ("No session structure passed in."));
3103 }
3104 } else {
3105 cERROR(1,
3106 (" Invalid Word count %d: ",
3107 smb_buffer_response->WordCount));
3108 rc = -EIO;
3109 }
3110
3111 if (smb_buffer)
3112 cifs_buf_release(smb_buffer);
3113
3114 return rc;
3115}
3116
3117int
3118CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3119 const char *tree, struct cifsTconInfo *tcon,
3120 const struct nls_table *nls_codepage)
3121{
3122 struct smb_hdr *smb_buffer;
3123 struct smb_hdr *smb_buffer_response;
3124 TCONX_REQ *pSMB;
3125 TCONX_RSP *pSMBr;
3126 unsigned char *bcc_ptr;
3127 int rc = 0;
3128 int length;
3129 __u16 count;
3130
3131 if (ses == NULL)
3132 return -EIO;
3133
3134 smb_buffer = cifs_buf_get();
3135 if (smb_buffer == NULL) {
3136 return -ENOMEM;
3137 }
3138 smb_buffer_response = smb_buffer;
3139
3140 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3141 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003142
3143 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 smb_buffer->Uid = ses->Suid;
3145 pSMB = (TCONX_REQ *) smb_buffer;
3146 pSMBr = (TCONX_RSP *) smb_buffer_response;
3147
3148 pSMB->AndXCommand = 0xFF;
3149 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3150 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3151 bcc_ptr = &pSMB->Password[0];
3152 bcc_ptr++; /* skip password */
3153
3154 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3155 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3156
3157 if (ses->capabilities & CAP_STATUS32) {
3158 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3159 }
3160 if (ses->capabilities & CAP_DFS) {
3161 smb_buffer->Flags2 |= SMBFLG2_DFS;
3162 }
3163 if (ses->capabilities & CAP_UNICODE) {
3164 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3165 length =
3166 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3167 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3168 bcc_ptr += 2; /* skip trailing null */
3169 } else { /* ASCII */
3170
3171 strcpy(bcc_ptr, tree);
3172 bcc_ptr += strlen(tree) + 1;
3173 }
3174 strcpy(bcc_ptr, "?????");
3175 bcc_ptr += strlen("?????");
3176 bcc_ptr += 1;
3177 count = bcc_ptr - &pSMB->Password[0];
3178 pSMB->hdr.smb_buf_length += count;
3179 pSMB->ByteCount = cpu_to_le16(count);
3180
3181 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3182
3183 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3184 /* above now done in SendReceive */
3185 if ((rc == 0) && (tcon != NULL)) {
3186 tcon->tidStatus = CifsGood;
3187 tcon->tid = smb_buffer_response->Tid;
3188 bcc_ptr = pByteArea(smb_buffer_response);
3189 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3190 /* skip service field (NB: this field is always ASCII) */
3191 bcc_ptr += length + 1;
3192 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3193 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3194 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3195 if ((bcc_ptr + (2 * length)) -
3196 pByteArea(smb_buffer_response) <=
3197 BCC(smb_buffer_response)) {
3198 if(tcon->nativeFileSystem)
3199 kfree(tcon->nativeFileSystem);
3200 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003201 kcalloc(1, length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 cifs_strfromUCS_le(tcon->nativeFileSystem,
3203 (wchar_t *) bcc_ptr,
3204 length, nls_codepage);
3205 bcc_ptr += 2 * length;
3206 bcc_ptr[0] = 0; /* null terminate the string */
3207 bcc_ptr[1] = 0;
3208 bcc_ptr += 2;
3209 }
3210 /* else do not bother copying these informational fields */
3211 } else {
3212 length = strnlen(bcc_ptr, 1024);
3213 if ((bcc_ptr + length) -
3214 pByteArea(smb_buffer_response) <=
3215 BCC(smb_buffer_response)) {
3216 if(tcon->nativeFileSystem)
3217 kfree(tcon->nativeFileSystem);
3218 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003219 kcalloc(1, length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 strncpy(tcon->nativeFileSystem, bcc_ptr,
3221 length);
3222 }
3223 /* else do not bother copying these informational fields */
3224 }
3225 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3226 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3227 } else if ((rc == 0) && tcon == NULL) {
3228 /* all we need to save for IPC$ connection */
3229 ses->ipc_tid = smb_buffer_response->Tid;
3230 }
3231
3232 if (smb_buffer)
3233 cifs_buf_release(smb_buffer);
3234 return rc;
3235}
3236
3237int
3238cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3239{
3240 int rc = 0;
3241 int xid;
3242 struct cifsSesInfo *ses = NULL;
3243 struct task_struct *cifsd_task;
3244
3245 xid = GetXid();
3246
3247 if (cifs_sb->tcon) {
3248 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3249 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3250 if (rc == -EBUSY) {
3251 FreeXid(xid);
3252 return 0;
3253 }
3254 tconInfoFree(cifs_sb->tcon);
3255 if ((ses) && (ses->server)) {
3256 /* save off task so we do not refer to ses later */
3257 cifsd_task = ses->server->tsk;
3258 cFYI(1, ("About to do SMBLogoff "));
3259 rc = CIFSSMBLogoff(xid, ses);
3260 if (rc == -EBUSY) {
3261 FreeXid(xid);
3262 return 0;
3263 } else if (rc == -ESHUTDOWN) {
3264 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf1914012005-08-18 09:37:34 -07003265 if(cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 send_sig(SIGKILL,cifsd_task,1);
Steve Frenchf1914012005-08-18 09:37:34 -07003267 wait_for_completion(&cifsd_complete);
3268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 rc = 0;
3270 } /* else - we have an smb session
3271 left on this socket do not kill cifsd */
3272 } else
3273 cFYI(1, ("No session or bad tcon"));
3274 }
3275
3276 cifs_sb->tcon = NULL;
3277 if (ses) {
3278 set_current_state(TASK_INTERRUPTIBLE);
3279 schedule_timeout(HZ / 2);
3280 }
3281 if (ses)
3282 sesInfoFree(ses);
3283
3284 FreeXid(xid);
3285 return rc; /* BB check if we should always return zero here */
3286}
3287
3288int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3289 struct nls_table * nls_info)
3290{
3291 int rc = 0;
3292 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3293 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003294 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295
3296 /* what if server changes its buffer size after dropping the session? */
3297 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3298 rc = CIFSSMBNegotiate(xid, pSesInfo);
3299 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3300 rc = CIFSSMBNegotiate(xid, pSesInfo);
3301 if(rc == -EAGAIN)
3302 rc = -EHOSTDOWN;
3303 }
3304 if(rc == 0) {
3305 spin_lock(&GlobalMid_Lock);
3306 if(pSesInfo->server->tcpStatus != CifsExiting)
3307 pSesInfo->server->tcpStatus = CifsGood;
3308 else
3309 rc = -EHOSTDOWN;
3310 spin_unlock(&GlobalMid_Lock);
3311
3312 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003313 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 }
3315 if (!rc) {
3316 pSesInfo->capabilities = pSesInfo->server->capabilities;
3317 if(linuxExtEnabled == 0)
3318 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003319 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3321 pSesInfo->server->secMode,
3322 pSesInfo->server->capabilities,
3323 pSesInfo->server->timeZone));
3324 if (extended_security
3325 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3326 && (pSesInfo->server->secType == NTLMSSP)) {
3327 cFYI(1, ("New style sesssetup "));
3328 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3329 NULL /* security blob */,
3330 0 /* blob length */,
3331 nls_info);
3332 } else if (extended_security
3333 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3334 && (pSesInfo->server->secType == RawNTLMSSP)) {
3335 cFYI(1, ("NTLMSSP sesssetup "));
3336 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3337 pSesInfo,
3338 &ntlmv2_flag,
3339 nls_info);
3340 if (!rc) {
3341 if(ntlmv2_flag) {
3342 char * v2_response;
3343 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3344 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3345 nls_info)) {
3346 rc = -ENOMEM;
3347 goto ss_err_exit;
3348 } else
3349 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3350 if(v2_response) {
3351 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003352 /* if(first_time)
3353 cifs_calculate_ntlmv2_mac_key(
3354 pSesInfo->server->mac_signing_key,
3355 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 kfree(v2_response);
3357 /* BB Put dummy sig in SessSetup PDU? */
3358 } else {
3359 rc = -ENOMEM;
3360 goto ss_err_exit;
3361 }
3362
3363 } else {
3364 SMBNTencrypt(pSesInfo->password,
3365 pSesInfo->server->cryptKey,
3366 ntlm_session_key);
3367
Steve Frenchad009ac2005-04-28 22:41:05 -07003368 if(first_time)
3369 cifs_calculate_mac_key(
3370 pSesInfo->server->mac_signing_key,
3371 ntlm_session_key,
3372 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 }
3374 /* for better security the weaker lanman hash not sent
3375 in AuthSessSetup so we no longer calculate it */
3376
3377 rc = CIFSNTLMSSPAuthSessSetup(xid,
3378 pSesInfo,
3379 ntlm_session_key,
3380 ntlmv2_flag,
3381 nls_info);
3382 }
3383 } else { /* old style NTLM 0.12 session setup */
3384 SMBNTencrypt(pSesInfo->password,
3385 pSesInfo->server->cryptKey,
3386 ntlm_session_key);
3387
Steve Frenchad009ac2005-04-28 22:41:05 -07003388 if(first_time)
3389 cifs_calculate_mac_key(
3390 pSesInfo->server->mac_signing_key,
3391 ntlm_session_key, pSesInfo->password);
3392
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 rc = CIFSSessSetup(xid, pSesInfo,
3394 ntlm_session_key, nls_info);
3395 }
3396 if (rc) {
3397 cERROR(1,("Send error in SessSetup = %d",rc));
3398 } else {
3399 cFYI(1,("CIFS Session Established successfully"));
3400 pSesInfo->status = CifsGood;
3401 }
3402 }
3403ss_err_exit:
3404 return rc;
3405}
3406