blob: ac2c8bdc8e55a41812701c711e7b071bb0a48adc [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;
Steve Frenchd3485d32005-08-19 11:04:29 -07001051 /* turn off mandatory locking in mode
1052 if remote locking is turned off since the
1053 local vfs will do advisory */
1054 if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1055 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 } else if (strnicmp(data, "setuids", 7) == 0) {
1057 vol->setuids = 1;
1058 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1059 vol->setuids = 0;
1060 } else if (strnicmp(data, "nohard", 6) == 0) {
1061 vol->retry = 0;
1062 } else if (strnicmp(data, "nosoft", 6) == 0) {
1063 vol->retry = 1;
1064 } else if (strnicmp(data, "nointr", 6) == 0) {
1065 vol->intr = 0;
1066 } else if (strnicmp(data, "intr", 4) == 0) {
1067 vol->intr = 1;
1068 } else if (strnicmp(data, "serverino",7) == 0) {
1069 vol->server_ino = 1;
1070 } else if (strnicmp(data, "noserverino",9) == 0) {
1071 vol->server_ino = 0;
1072 } else if (strnicmp(data, "acl",3) == 0) {
1073 vol->no_psx_acl = 0;
1074 } else if (strnicmp(data, "noacl",5) == 0) {
1075 vol->no_psx_acl = 1;
1076 } else if (strnicmp(data, "direct",6) == 0) {
1077 vol->direct_io = 1;
1078 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1079 vol->direct_io = 1;
1080 } else if (strnicmp(data, "in6_addr",8) == 0) {
1081 if (!value || !*value) {
1082 vol->in6_addr = NULL;
1083 } else if (strnlen(value, 49) == 48) {
1084 vol->in6_addr = value;
1085 } else {
1086 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1087 return 1;
1088 }
1089 } else if (strnicmp(data, "noac", 4) == 0) {
1090 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1091 } else
1092 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1093 }
1094 if (vol->UNC == NULL) {
1095 if(devname == NULL) {
1096 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1097 return 1;
1098 }
1099 if ((temp_len = strnlen(devname, 300)) < 300) {
1100 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1101 if(vol->UNC == NULL)
1102 return 1;
1103 strcpy(vol->UNC,devname);
1104 if (strncmp(vol->UNC, "//", 2) == 0) {
1105 vol->UNC[0] = '\\';
1106 vol->UNC[1] = '\\';
1107 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1108 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1109 return 1;
1110 }
1111 } else {
1112 printk(KERN_WARNING "CIFS: UNC name too long\n");
1113 return 1;
1114 }
1115 }
1116 if(vol->UNCip == NULL)
1117 vol->UNCip = &vol->UNC[2];
1118
1119 return 0;
1120}
1121
1122static struct cifsSesInfo *
1123cifs_find_tcp_session(struct in_addr * target_ip_addr,
1124 struct in6_addr *target_ip6_addr,
1125 char *userName, struct TCP_Server_Info **psrvTcp)
1126{
1127 struct list_head *tmp;
1128 struct cifsSesInfo *ses;
1129 *psrvTcp = NULL;
1130 read_lock(&GlobalSMBSeslock);
1131
1132 list_for_each(tmp, &GlobalSMBSessionList) {
1133 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1134 if (ses->server) {
1135 if((target_ip_addr &&
1136 (ses->server->addr.sockAddr.sin_addr.s_addr
1137 == target_ip_addr->s_addr)) || (target_ip6_addr
1138 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1139 target_ip6_addr,sizeof(*target_ip6_addr)))){
1140 /* BB lock server and tcp session and increment use count here?? */
1141 *psrvTcp = ses->server; /* found a match on the TCP session */
1142 /* BB check if reconnection needed */
1143 if (strncmp
1144 (ses->userName, userName,
1145 MAX_USERNAME_SIZE) == 0){
1146 read_unlock(&GlobalSMBSeslock);
1147 return ses; /* found exact match on both tcp and SMB sessions */
1148 }
1149 }
1150 }
1151 /* else tcp and smb sessions need reconnection */
1152 }
1153 read_unlock(&GlobalSMBSeslock);
1154 return NULL;
1155}
1156
1157static struct cifsTconInfo *
1158find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1159{
1160 struct list_head *tmp;
1161 struct cifsTconInfo *tcon;
1162
1163 read_lock(&GlobalSMBSeslock);
1164 list_for_each(tmp, &GlobalTreeConnectionList) {
1165 cFYI(1, ("Next tcon - "));
1166 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1167 if (tcon->ses) {
1168 if (tcon->ses->server) {
1169 cFYI(1,
1170 (" old ip addr: %x == new ip %x ?",
1171 tcon->ses->server->addr.sockAddr.sin_addr.
1172 s_addr, new_target_ip_addr));
1173 if (tcon->ses->server->addr.sockAddr.sin_addr.
1174 s_addr == new_target_ip_addr) {
1175 /* BB lock tcon and server and tcp session and increment use count here? */
1176 /* found a match on the TCP session */
1177 /* BB check if reconnection needed */
1178 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1179 tcon->treeName, uncName));
1180 if (strncmp
1181 (tcon->treeName, uncName,
1182 MAX_TREE_SIZE) == 0) {
1183 cFYI(1,
1184 ("Matched UNC, old user: %s == new: %s ?",
1185 tcon->treeName, uncName));
1186 if (strncmp
1187 (tcon->ses->userName,
1188 userName,
1189 MAX_USERNAME_SIZE) == 0) {
1190 read_unlock(&GlobalSMBSeslock);
1191 return tcon;/* also matched user (smb session)*/
1192 }
1193 }
1194 }
1195 }
1196 }
1197 }
1198 read_unlock(&GlobalSMBSeslock);
1199 return NULL;
1200}
1201
1202int
1203connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001204 const char *old_path, const struct nls_table *nls_codepage,
1205 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206{
1207 unsigned char *referrals = NULL;
1208 unsigned int num_referrals;
1209 int rc = 0;
1210
1211 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001212 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
1214 /* BB Add in code to: if valid refrl, if not ip address contact
1215 the helper that resolves tcp names, mount to it, try to
1216 tcon to it unmount it if fail */
1217
1218 if(referrals)
1219 kfree(referrals);
1220
1221 return rc;
1222}
1223
1224int
1225get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1226 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001227 unsigned int *pnum_referrals,
1228 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229{
1230 char *temp_unc;
1231 int rc = 0;
1232
1233 *pnum_referrals = 0;
1234
1235 if (pSesInfo->ipc_tid == 0) {
1236 temp_unc = kmalloc(2 /* for slashes */ +
1237 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1238 + 1 + 4 /* slash IPC$ */ + 2,
1239 GFP_KERNEL);
1240 if (temp_unc == NULL)
1241 return -ENOMEM;
1242 temp_unc[0] = '\\';
1243 temp_unc[1] = '\\';
1244 strcpy(temp_unc + 2, pSesInfo->serverName);
1245 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1246 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1247 cFYI(1,
1248 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1249 kfree(temp_unc);
1250 }
1251 if (rc == 0)
1252 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001253 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254
1255 return rc;
1256}
1257
1258/* See RFC1001 section 14 on representation of Netbios names */
1259static void rfc1002mangle(char * target,char * source, unsigned int length)
1260{
1261 unsigned int i,j;
1262
1263 for(i=0,j=0;i<(length);i++) {
1264 /* mask a nibble at a time and encode */
1265 target[j] = 'A' + (0x0F & (source[i] >> 4));
1266 target[j+1] = 'A' + (0x0F & source[i]);
1267 j+=2;
1268 }
1269
1270}
1271
1272
1273static int
1274ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1275 char * netbios_name)
1276{
1277 int rc = 0;
1278 int connected = 0;
1279 __be16 orig_port = 0;
1280
1281 if(*csocket == NULL) {
1282 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1283 if (rc < 0) {
1284 cERROR(1, ("Error %d creating socket",rc));
1285 *csocket = NULL;
1286 return rc;
1287 } else {
1288 /* BB other socket options to set KEEPALIVE, NODELAY? */
1289 cFYI(1,("Socket created"));
1290 (*csocket)->sk->sk_allocation = GFP_NOFS;
1291 }
1292 }
1293
1294 psin_server->sin_family = AF_INET;
1295 if(psin_server->sin_port) { /* user overrode default port */
1296 rc = (*csocket)->ops->connect(*csocket,
1297 (struct sockaddr *) psin_server,
1298 sizeof (struct sockaddr_in),0);
1299 if (rc >= 0)
1300 connected = 1;
1301 }
1302
1303 if(!connected) {
1304 /* save original port so we can retry user specified port
1305 later if fall back ports fail this time */
1306 orig_port = psin_server->sin_port;
1307
1308 /* do not retry on the same port we just failed on */
1309 if(psin_server->sin_port != htons(CIFS_PORT)) {
1310 psin_server->sin_port = htons(CIFS_PORT);
1311
1312 rc = (*csocket)->ops->connect(*csocket,
1313 (struct sockaddr *) psin_server,
1314 sizeof (struct sockaddr_in),0);
1315 if (rc >= 0)
1316 connected = 1;
1317 }
1318 }
1319 if (!connected) {
1320 psin_server->sin_port = htons(RFC1001_PORT);
1321 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1322 psin_server, sizeof (struct sockaddr_in),0);
1323 if (rc >= 0)
1324 connected = 1;
1325 }
1326
1327 /* give up here - unless we want to retry on different
1328 protocol families some day */
1329 if (!connected) {
1330 if(orig_port)
1331 psin_server->sin_port = orig_port;
1332 cFYI(1,("Error %d connecting to server via ipv4",rc));
1333 sock_release(*csocket);
1334 *csocket = NULL;
1335 return rc;
1336 }
1337 /* Eventually check for other socket options to change from
1338 the default. sock_setsockopt not used because it expects
1339 user space buffer */
1340 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1341
1342 /* send RFC1001 sessinit */
1343
1344 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1345 /* some servers require RFC1001 sessinit before sending
1346 negprot - BB check reconnection in case where second
1347 sessinit is sent but no second negprot */
1348 struct rfc1002_session_packet * ses_init_buf;
1349 struct smb_hdr * smb_buf;
Steve French433dc242005-04-28 22:41:08 -07001350 ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 if(ses_init_buf) {
1352 ses_init_buf->trailer.session_req.called_len = 32;
1353 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1354 DEFAULT_CIFS_CALLED_NAME,16);
1355 ses_init_buf->trailer.session_req.calling_len = 32;
1356 /* calling name ends in null (byte 16) from old smb
1357 convention. */
1358 if(netbios_name && (netbios_name[0] !=0)) {
1359 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1360 netbios_name,16);
1361 } else {
1362 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1363 "LINUX_CIFS_CLNT",16);
1364 }
1365 ses_init_buf->trailer.session_req.scope1 = 0;
1366 ses_init_buf->trailer.session_req.scope2 = 0;
1367 smb_buf = (struct smb_hdr *)ses_init_buf;
1368 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1369 smb_buf->smb_buf_length = 0x81000044;
1370 rc = smb_send(*csocket, smb_buf, 0x44,
1371 (struct sockaddr *)psin_server);
1372 kfree(ses_init_buf);
1373 }
1374 /* else the negprot may still work without this
1375 even though malloc failed */
1376
1377 }
1378
1379 return rc;
1380}
1381
1382static int
1383ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1384{
1385 int rc = 0;
1386 int connected = 0;
1387 __be16 orig_port = 0;
1388
1389 if(*csocket == NULL) {
1390 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1391 if (rc < 0) {
1392 cERROR(1, ("Error %d creating ipv6 socket",rc));
1393 *csocket = NULL;
1394 return rc;
1395 } else {
1396 /* BB other socket options to set KEEPALIVE, NODELAY? */
1397 cFYI(1,("ipv6 Socket created"));
1398 (*csocket)->sk->sk_allocation = GFP_NOFS;
1399 }
1400 }
1401
1402 psin_server->sin6_family = AF_INET6;
1403
1404 if(psin_server->sin6_port) { /* user overrode default port */
1405 rc = (*csocket)->ops->connect(*csocket,
1406 (struct sockaddr *) psin_server,
1407 sizeof (struct sockaddr_in6),0);
1408 if (rc >= 0)
1409 connected = 1;
1410 }
1411
1412 if(!connected) {
1413 /* save original port so we can retry user specified port
1414 later if fall back ports fail this time */
1415
1416 orig_port = psin_server->sin6_port;
1417 /* do not retry on the same port we just failed on */
1418 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1419 psin_server->sin6_port = htons(CIFS_PORT);
1420
1421 rc = (*csocket)->ops->connect(*csocket,
1422 (struct sockaddr *) psin_server,
1423 sizeof (struct sockaddr_in6),0);
1424 if (rc >= 0)
1425 connected = 1;
1426 }
1427 }
1428 if (!connected) {
1429 psin_server->sin6_port = htons(RFC1001_PORT);
1430 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1431 psin_server, sizeof (struct sockaddr_in6),0);
1432 if (rc >= 0)
1433 connected = 1;
1434 }
1435
1436 /* give up here - unless we want to retry on different
1437 protocol families some day */
1438 if (!connected) {
1439 if(orig_port)
1440 psin_server->sin6_port = orig_port;
1441 cFYI(1,("Error %d connecting to server via ipv6",rc));
1442 sock_release(*csocket);
1443 *csocket = NULL;
1444 return rc;
1445 }
1446 /* Eventually check for other socket options to change from
1447 the default. sock_setsockopt not used because it expects
1448 user space buffer */
1449 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1450
1451 return rc;
1452}
1453
1454int
1455cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1456 char *mount_data, const char *devname)
1457{
1458 int rc = 0;
1459 int xid;
1460 int address_type = AF_INET;
1461 struct socket *csocket = NULL;
1462 struct sockaddr_in sin_server;
1463 struct sockaddr_in6 sin_server6;
1464 struct smb_vol volume_info;
1465 struct cifsSesInfo *pSesInfo = NULL;
1466 struct cifsSesInfo *existingCifsSes = NULL;
1467 struct cifsTconInfo *tcon = NULL;
1468 struct TCP_Server_Info *srvTcp = NULL;
1469
1470 xid = GetXid();
1471
1472/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1473
1474 memset(&volume_info,0,sizeof(struct smb_vol));
1475 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1476 if(volume_info.UNC)
1477 kfree(volume_info.UNC);
1478 if(volume_info.password)
1479 kfree(volume_info.password);
1480 FreeXid(xid);
1481 return -EINVAL;
1482 }
1483
1484 if (volume_info.username) {
1485 /* BB fixme parse for domain name here */
1486 cFYI(1, ("Username: %s ", volume_info.username));
1487
1488 } else {
1489 cifserror("No username specified ");
1490 /* In userspace mount helper we can get user name from alternate
1491 locations such as env variables and files on disk */
1492 if(volume_info.UNC)
1493 kfree(volume_info.UNC);
1494 if(volume_info.password)
1495 kfree(volume_info.password);
1496 FreeXid(xid);
1497 return -EINVAL;
1498 }
1499
1500 if (volume_info.UNCip && volume_info.UNC) {
1501 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1502
1503 if(rc <= 0) {
1504 /* not ipv4 address, try ipv6 */
1505 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1506 if(rc > 0)
1507 address_type = AF_INET6;
1508 } else {
1509 address_type = AF_INET;
1510 }
1511
1512 if(rc <= 0) {
1513 /* we failed translating address */
1514 if(volume_info.UNC)
1515 kfree(volume_info.UNC);
1516 if(volume_info.password)
1517 kfree(volume_info.password);
1518 FreeXid(xid);
1519 return -EINVAL;
1520 }
1521
1522 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1523 /* success */
1524 rc = 0;
1525 } else if (volume_info.UNCip){
1526 /* BB using ip addr as server name connect to the DFS root below */
1527 cERROR(1,("Connecting to DFS root not implemented yet"));
1528 if(volume_info.UNC)
1529 kfree(volume_info.UNC);
1530 if(volume_info.password)
1531 kfree(volume_info.password);
1532 FreeXid(xid);
1533 return -EINVAL;
1534 } else /* which servers DFS root would we conect to */ {
1535 cERROR(1,
1536 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1537 if(volume_info.UNC)
1538 kfree(volume_info.UNC);
1539 if(volume_info.password)
1540 kfree(volume_info.password);
1541 FreeXid(xid);
1542 return -EINVAL;
1543 }
1544
1545 /* this is needed for ASCII cp to Unicode converts */
1546 if(volume_info.iocharset == NULL) {
1547 cifs_sb->local_nls = load_nls_default();
1548 /* load_nls_default can not return null */
1549 } else {
1550 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1551 if(cifs_sb->local_nls == NULL) {
1552 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1553 if(volume_info.UNC)
1554 kfree(volume_info.UNC);
1555 if(volume_info.password)
1556 kfree(volume_info.password);
1557 FreeXid(xid);
1558 return -ELIBACC;
1559 }
1560 }
1561
1562 if(address_type == AF_INET)
1563 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1564 NULL /* no ipv6 addr */,
1565 volume_info.username, &srvTcp);
1566 else if(address_type == AF_INET6)
1567 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1568 &sin_server6.sin6_addr,
1569 volume_info.username, &srvTcp);
1570 else {
1571 if(volume_info.UNC)
1572 kfree(volume_info.UNC);
1573 if(volume_info.password)
1574 kfree(volume_info.password);
1575 FreeXid(xid);
1576 return -EINVAL;
1577 }
1578
1579
1580 if (srvTcp) {
1581 cFYI(1, ("Existing tcp session with server found "));
1582 } else { /* create socket */
1583 if(volume_info.port)
1584 sin_server.sin_port = htons(volume_info.port);
1585 else
1586 sin_server.sin_port = 0;
1587 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1588 if (rc < 0) {
1589 cERROR(1,
1590 ("Error connecting to IPv4 socket. Aborting operation"));
1591 if(csocket != NULL)
1592 sock_release(csocket);
1593 if(volume_info.UNC)
1594 kfree(volume_info.UNC);
1595 if(volume_info.password)
1596 kfree(volume_info.password);
1597 FreeXid(xid);
1598 return rc;
1599 }
1600
1601 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1602 if (srvTcp == NULL) {
1603 rc = -ENOMEM;
1604 sock_release(csocket);
1605 if(volume_info.UNC)
1606 kfree(volume_info.UNC);
1607 if(volume_info.password)
1608 kfree(volume_info.password);
1609 FreeXid(xid);
1610 return rc;
1611 } else {
1612 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1613 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1614 atomic_set(&srvTcp->inFlight,0);
1615 /* BB Add code for ipv6 case too */
1616 srvTcp->ssocket = csocket;
1617 srvTcp->protocolType = IPV4;
1618 init_waitqueue_head(&srvTcp->response_q);
1619 init_waitqueue_head(&srvTcp->request_q);
1620 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1621 /* at this point we are the only ones with the pointer
1622 to the struct since the kernel thread not created yet
1623 so no need to spinlock this init of tcpStatus */
1624 srvTcp->tcpStatus = CifsNew;
1625 init_MUTEX(&srvTcp->tcpSem);
1626 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1627 CLONE_FS | CLONE_FILES | CLONE_VM);
1628 if(rc < 0) {
1629 rc = -ENOMEM;
1630 sock_release(csocket);
1631 if(volume_info.UNC)
1632 kfree(volume_info.UNC);
1633 if(volume_info.password)
1634 kfree(volume_info.password);
1635 FreeXid(xid);
1636 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001637 }
1638 wait_for_completion(&cifsd_complete);
1639 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001641 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 }
1643 }
1644
1645 if (existingCifsSes) {
1646 pSesInfo = existingCifsSes;
1647 cFYI(1, ("Existing smb sess found "));
1648 if(volume_info.password)
1649 kfree(volume_info.password);
1650 /* volume_info.UNC freed at end of function */
1651 } else if (!rc) {
1652 cFYI(1, ("Existing smb sess not found "));
1653 pSesInfo = sesInfoAlloc();
1654 if (pSesInfo == NULL)
1655 rc = -ENOMEM;
1656 else {
1657 pSesInfo->server = srvTcp;
1658 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1659 NIPQUAD(sin_server.sin_addr.s_addr));
1660 }
1661
1662 if (!rc){
1663 /* volume_info.password freed at unmount */
1664 if (volume_info.password)
1665 pSesInfo->password = volume_info.password;
1666 if (volume_info.username)
1667 strncpy(pSesInfo->userName,
1668 volume_info.username,MAX_USERNAME_SIZE);
1669 if (volume_info.domainname)
1670 strncpy(pSesInfo->domainName,
1671 volume_info.domainname,MAX_USERNAME_SIZE);
1672 pSesInfo->linux_uid = volume_info.linux_uid;
1673 down(&pSesInfo->sesSem);
1674 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1675 up(&pSesInfo->sesSem);
1676 if(!rc)
1677 atomic_inc(&srvTcp->socketUseCount);
1678 } else
1679 if(volume_info.password)
1680 kfree(volume_info.password);
1681 }
1682
1683 /* search for existing tcon to this server share */
1684 if (!rc) {
1685 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1686 cifs_sb->rsize = volume_info.rsize;
1687 else
1688 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1689 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1690 cifs_sb->wsize = volume_info.wsize;
1691 else
1692 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1693 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1694 cifs_sb->rsize = PAGE_CACHE_SIZE;
1695 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1696 }
1697 cifs_sb->mnt_uid = volume_info.linux_uid;
1698 cifs_sb->mnt_gid = volume_info.linux_gid;
1699 cifs_sb->mnt_file_mode = volume_info.file_mode;
1700 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1701 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1702
1703 if(volume_info.noperm)
1704 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1705 if(volume_info.setuids)
1706 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1707 if(volume_info.server_ino)
1708 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001709 if(volume_info.remap)
1710 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 if(volume_info.no_xattr)
1712 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve Frenchd7245c22005-07-14 18:25:12 -05001713 if(volume_info.sfu_emul)
1714 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001715 if(volume_info.nobrl)
1716 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Jeremy Allisonac670552005-06-22 17:26:35 -07001717
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 if(volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001719 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1721 }
1722
1723 tcon =
1724 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1725 volume_info.username);
1726 if (tcon) {
1727 cFYI(1, ("Found match on UNC path "));
1728 /* we can have only one retry value for a connection
1729 to a share so for resources mounted more than once
1730 to the same server share the last value passed in
1731 for the retry flag is used */
1732 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001733 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 } else {
1735 tcon = tconInfoAlloc();
1736 if (tcon == NULL)
1737 rc = -ENOMEM;
1738 else {
1739 /* check for null share name ie connect to dfs root */
1740
1741 /* BB check if this works for exactly length three strings */
1742 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1743 && (strchr(volume_info.UNC + 3, '/') ==
1744 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001745 rc = connect_to_dfs_path(xid, pSesInfo,
1746 "", cifs_sb->local_nls,
1747 cifs_sb->mnt_cifs_flags &
1748 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 if(volume_info.UNC)
1750 kfree(volume_info.UNC);
1751 FreeXid(xid);
1752 return -ENODEV;
1753 } else {
1754 rc = CIFSTCon(xid, pSesInfo,
1755 volume_info.UNC,
1756 tcon, cifs_sb->local_nls);
1757 cFYI(1, ("CIFS Tcon rc = %d", rc));
1758 }
1759 if (!rc) {
1760 atomic_inc(&pSesInfo->inUse);
1761 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001762 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 }
1764 }
1765 }
1766 }
1767 if(pSesInfo) {
1768 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1769 sb->s_maxbytes = (u64) 1 << 63;
1770 } else
1771 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1772 }
1773
1774 sb->s_time_gran = 100;
1775
1776/* on error free sesinfo and tcon struct if needed */
1777 if (rc) {
1778 /* if session setup failed, use count is zero but
1779 we still need to free cifsd thread */
1780 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1781 spin_lock(&GlobalMid_Lock);
1782 srvTcp->tcpStatus = CifsExiting;
1783 spin_unlock(&GlobalMid_Lock);
Steve Frenchf1914012005-08-18 09:37:34 -07001784 if(srvTcp->tsk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 send_sig(SIGKILL,srvTcp->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001786 wait_for_completion(&cifsd_complete);
1787 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 }
1789 /* If find_unc succeeded then rc == 0 so we can not end */
1790 if (tcon) /* up accidently freeing someone elses tcon struct */
1791 tconInfoFree(tcon);
1792 if (existingCifsSes == NULL) {
1793 if (pSesInfo) {
1794 if ((pSesInfo->server) &&
1795 (pSesInfo->status == CifsGood)) {
1796 int temp_rc;
1797 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1798 /* if the socketUseCount is now zero */
1799 if((temp_rc == -ESHUTDOWN) &&
Steve Frenchf1914012005-08-18 09:37:34 -07001800 (pSesInfo->server->tsk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 send_sig(SIGKILL,pSesInfo->server->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001802 wait_for_completion(&cifsd_complete);
1803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 } else
1805 cFYI(1, ("No session or bad tcon"));
1806 sesInfoFree(pSesInfo);
1807 /* pSesInfo = NULL; */
1808 }
1809 }
1810 } else {
1811 atomic_inc(&tcon->useCount);
1812 cifs_sb->tcon = tcon;
1813 tcon->ses = pSesInfo;
1814
1815 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001816 CIFSSMBQFSDeviceInfo(xid, tcon);
1817 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001819 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 if(!volume_info.no_psx_acl) {
1821 if(CIFS_UNIX_POSIX_ACL_CAP &
1822 le64_to_cpu(tcon->fsUnixInfo.Capability))
1823 cFYI(1,("server negotiated posix acl support"));
1824 sb->s_flags |= MS_POSIXACL;
1825 }
Jeremy Allisonac670552005-06-22 17:26:35 -07001826
1827 /* Try and negotiate POSIX pathnames if we can. */
1828 if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
1829 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French45abc6e2005-06-23 13:42:03 -05001830 if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
Jeremy Allisonac670552005-06-22 17:26:35 -07001831 cFYI(1,("negotiated posix pathnames support"));
1832 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
1833 } else {
1834 cFYI(1,("posix pathnames support requested but not supported"));
1835 }
1836 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 }
1838 }
1839 }
1840
1841 /* volume_info.password is freed above when existing session found
1842 (in which case it is not needed anymore) but when new sesion is created
1843 the password ptr is put in the new session structure (in which case the
1844 password will be freed at unmount time) */
1845 if(volume_info.UNC)
1846 kfree(volume_info.UNC);
1847 FreeXid(xid);
1848 return rc;
1849}
1850
1851static int
1852CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1853 char session_key[CIFS_SESSION_KEY_SIZE],
1854 const struct nls_table *nls_codepage)
1855{
1856 struct smb_hdr *smb_buffer;
1857 struct smb_hdr *smb_buffer_response;
1858 SESSION_SETUP_ANDX *pSMB;
1859 SESSION_SETUP_ANDX *pSMBr;
1860 char *bcc_ptr;
1861 char *user;
1862 char *domain;
1863 int rc = 0;
1864 int remaining_words = 0;
1865 int bytes_returned = 0;
1866 int len;
1867 __u32 capabilities;
1868 __u16 count;
1869
1870 cFYI(1, ("In sesssetup "));
1871 if(ses == NULL)
1872 return -EINVAL;
1873 user = ses->userName;
1874 domain = ses->domainName;
1875 smb_buffer = cifs_buf_get();
1876 if (smb_buffer == NULL) {
1877 return -ENOMEM;
1878 }
1879 smb_buffer_response = smb_buffer;
1880 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1881
1882 /* send SMBsessionSetup here */
1883 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1884 NULL /* no tCon exists yet */ , 13 /* wct */ );
1885
Steve French1982c342005-08-17 12:38:22 -07001886 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 pSMB->req_no_secext.AndXCommand = 0xFF;
1888 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1889 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1890
1891 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1892 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1893
1894 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1895 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1896 if (ses->capabilities & CAP_UNICODE) {
1897 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1898 capabilities |= CAP_UNICODE;
1899 }
1900 if (ses->capabilities & CAP_STATUS32) {
1901 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1902 capabilities |= CAP_STATUS32;
1903 }
1904 if (ses->capabilities & CAP_DFS) {
1905 smb_buffer->Flags2 |= SMBFLG2_DFS;
1906 capabilities |= CAP_DFS;
1907 }
1908 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1909
1910 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1911 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1912
1913 pSMB->req_no_secext.CaseSensitivePasswordLength =
1914 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1915 bcc_ptr = pByteArea(smb_buffer);
1916 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1917 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1918 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1919 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1920
1921 if (ses->capabilities & CAP_UNICODE) {
1922 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1923 *bcc_ptr = 0;
1924 bcc_ptr++;
1925 }
1926 if(user == NULL)
1927 bytes_returned = 0; /* skill null user */
1928 else
1929 bytes_returned =
1930 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1931 nls_codepage);
1932 /* convert number of 16 bit words to bytes */
1933 bcc_ptr += 2 * bytes_returned;
1934 bcc_ptr += 2; /* trailing null */
1935 if (domain == NULL)
1936 bytes_returned =
1937 cifs_strtoUCS((wchar_t *) bcc_ptr,
1938 "CIFS_LINUX_DOM", 32, nls_codepage);
1939 else
1940 bytes_returned =
1941 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1942 nls_codepage);
1943 bcc_ptr += 2 * bytes_returned;
1944 bcc_ptr += 2;
1945 bytes_returned =
1946 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1947 32, nls_codepage);
1948 bcc_ptr += 2 * bytes_returned;
1949 bytes_returned =
1950 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1951 32, nls_codepage);
1952 bcc_ptr += 2 * bytes_returned;
1953 bcc_ptr += 2;
1954 bytes_returned =
1955 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1956 64, nls_codepage);
1957 bcc_ptr += 2 * bytes_returned;
1958 bcc_ptr += 2;
1959 } else {
1960 if(user != NULL) {
1961 strncpy(bcc_ptr, user, 200);
1962 bcc_ptr += strnlen(user, 200);
1963 }
1964 *bcc_ptr = 0;
1965 bcc_ptr++;
1966 if (domain == NULL) {
1967 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1968 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1969 } else {
1970 strncpy(bcc_ptr, domain, 64);
1971 bcc_ptr += strnlen(domain, 64);
1972 *bcc_ptr = 0;
1973 bcc_ptr++;
1974 }
1975 strcpy(bcc_ptr, "Linux version ");
1976 bcc_ptr += strlen("Linux version ");
1977 strcpy(bcc_ptr, system_utsname.release);
1978 bcc_ptr += strlen(system_utsname.release) + 1;
1979 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1980 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1981 }
1982 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1983 smb_buffer->smb_buf_length += count;
1984 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
1985
1986 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1987 &bytes_returned, 1);
1988 if (rc) {
1989/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1990 } else if ((smb_buffer_response->WordCount == 3)
1991 || (smb_buffer_response->WordCount == 4)) {
1992 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1993 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1994 if (action & GUEST_LOGIN)
1995 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
1996 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1997 cFYI(1, ("UID = %d ", ses->Suid));
1998 /* response can have either 3 or 4 word count - Samba sends 3 */
1999 bcc_ptr = pByteArea(smb_buffer_response);
2000 if ((pSMBr->resp.hdr.WordCount == 3)
2001 || ((pSMBr->resp.hdr.WordCount == 4)
2002 && (blob_len < pSMBr->resp.ByteCount))) {
2003 if (pSMBr->resp.hdr.WordCount == 4)
2004 bcc_ptr += blob_len;
2005
2006 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2007 if ((long) (bcc_ptr) % 2) {
2008 remaining_words =
2009 (BCC(smb_buffer_response) - 1) /2;
2010 bcc_ptr++; /* Unicode strings must be word aligned */
2011 } else {
2012 remaining_words =
2013 BCC(smb_buffer_response) / 2;
2014 }
2015 len =
2016 UniStrnlen((wchar_t *) bcc_ptr,
2017 remaining_words - 1);
2018/* We look for obvious messed up bcc or strings in response so we do not go off
2019 the end since (at least) WIN2K and Windows XP have a major bug in not null
2020 terminating last Unicode string in response */
Steve French433dc242005-04-28 22:41:08 -07002021 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2022 if(ses->serverOS == NULL)
2023 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 cifs_strfromUCS_le(ses->serverOS,
2025 (wchar_t *)bcc_ptr, len,nls_codepage);
2026 bcc_ptr += 2 * (len + 1);
2027 remaining_words -= len + 1;
2028 ses->serverOS[2 * len] = 0;
2029 ses->serverOS[1 + (2 * len)] = 0;
2030 if (remaining_words > 0) {
2031 len = UniStrnlen((wchar_t *)bcc_ptr,
2032 remaining_words-1);
Steve French433dc242005-04-28 22:41:08 -07002033 ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
2034 if(ses->serverNOS == NULL)
2035 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 cifs_strfromUCS_le(ses->serverNOS,
2037 (wchar_t *)bcc_ptr,len,nls_codepage);
2038 bcc_ptr += 2 * (len + 1);
2039 ses->serverNOS[2 * len] = 0;
2040 ses->serverNOS[1 + (2 * len)] = 0;
2041 if(strncmp(ses->serverNOS,
2042 "NT LAN Manager 4",16) == 0) {
2043 cFYI(1,("NT4 server"));
2044 ses->flags |= CIFS_SES_NT4;
2045 }
2046 remaining_words -= len + 1;
2047 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002048 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2050 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002051 kcalloc(1, 2*(len+1),GFP_KERNEL);
2052 if(ses->serverDomain == NULL)
2053 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 cifs_strfromUCS_le(ses->serverDomain,
2055 (wchar_t *)bcc_ptr,len,nls_codepage);
2056 bcc_ptr += 2 * (len + 1);
2057 ses->serverDomain[2*len] = 0;
2058 ses->serverDomain[1+(2*len)] = 0;
2059 } /* else no more room so create dummy domain string */
2060 else
Steve French433dc242005-04-28 22:41:08 -07002061 ses->serverDomain =
2062 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002064 /* if these kcallocs fail not much we
2065 can do, but better to not fail the
2066 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002068 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002070 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 }
2072 } else { /* ASCII */
2073 len = strnlen(bcc_ptr, 1024);
2074 if (((long) bcc_ptr + len) - (long)
2075 pByteArea(smb_buffer_response)
2076 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002077 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
2078 if(ses->serverOS == NULL)
2079 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 strncpy(ses->serverOS,bcc_ptr, len);
2081
2082 bcc_ptr += len;
2083 bcc_ptr[0] = 0; /* null terminate the string */
2084 bcc_ptr++;
2085
2086 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002087 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2088 if(ses->serverNOS == NULL)
2089 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 strncpy(ses->serverNOS, bcc_ptr, len);
2091 bcc_ptr += len;
2092 bcc_ptr[0] = 0;
2093 bcc_ptr++;
2094
2095 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002096 ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
2097 if(ses->serverDomain == NULL)
2098 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 strncpy(ses->serverDomain, bcc_ptr, len);
2100 bcc_ptr += len;
2101 bcc_ptr[0] = 0;
2102 bcc_ptr++;
2103 } else
2104 cFYI(1,
2105 ("Variable field of length %d extends beyond end of smb ",
2106 len));
2107 }
2108 } else {
2109 cERROR(1,
2110 (" Security Blob Length extends beyond end of SMB"));
2111 }
2112 } else {
2113 cERROR(1,
2114 (" Invalid Word count %d: ",
2115 smb_buffer_response->WordCount));
2116 rc = -EIO;
2117 }
Steve French433dc242005-04-28 22:41:08 -07002118sesssetup_nomem: /* do not return an error on nomem for the info strings,
2119 since that could make reconnection harder, and
2120 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 if (smb_buffer)
2122 cifs_buf_release(smb_buffer);
2123
2124 return rc;
2125}
2126
2127static int
2128CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2129 char *SecurityBlob,int SecurityBlobLength,
2130 const struct nls_table *nls_codepage)
2131{
2132 struct smb_hdr *smb_buffer;
2133 struct smb_hdr *smb_buffer_response;
2134 SESSION_SETUP_ANDX *pSMB;
2135 SESSION_SETUP_ANDX *pSMBr;
2136 char *bcc_ptr;
2137 char *user;
2138 char *domain;
2139 int rc = 0;
2140 int remaining_words = 0;
2141 int bytes_returned = 0;
2142 int len;
2143 __u32 capabilities;
2144 __u16 count;
2145
2146 cFYI(1, ("In spnego sesssetup "));
2147 if(ses == NULL)
2148 return -EINVAL;
2149 user = ses->userName;
2150 domain = ses->domainName;
2151
2152 smb_buffer = cifs_buf_get();
2153 if (smb_buffer == NULL) {
2154 return -ENOMEM;
2155 }
2156 smb_buffer_response = smb_buffer;
2157 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2158
2159 /* send SMBsessionSetup here */
2160 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2161 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002162
2163 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2165 pSMB->req.AndXCommand = 0xFF;
2166 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2167 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2168
2169 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2170 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2171
2172 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2173 CAP_EXTENDED_SECURITY;
2174 if (ses->capabilities & CAP_UNICODE) {
2175 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2176 capabilities |= CAP_UNICODE;
2177 }
2178 if (ses->capabilities & CAP_STATUS32) {
2179 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2180 capabilities |= CAP_STATUS32;
2181 }
2182 if (ses->capabilities & CAP_DFS) {
2183 smb_buffer->Flags2 |= SMBFLG2_DFS;
2184 capabilities |= CAP_DFS;
2185 }
2186 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2187
2188 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2189 bcc_ptr = pByteArea(smb_buffer);
2190 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2191 bcc_ptr += SecurityBlobLength;
2192
2193 if (ses->capabilities & CAP_UNICODE) {
2194 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2195 *bcc_ptr = 0;
2196 bcc_ptr++;
2197 }
2198 bytes_returned =
2199 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2200 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2201 bcc_ptr += 2; /* trailing null */
2202 if (domain == NULL)
2203 bytes_returned =
2204 cifs_strtoUCS((wchar_t *) bcc_ptr,
2205 "CIFS_LINUX_DOM", 32, nls_codepage);
2206 else
2207 bytes_returned =
2208 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2209 nls_codepage);
2210 bcc_ptr += 2 * bytes_returned;
2211 bcc_ptr += 2;
2212 bytes_returned =
2213 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2214 32, nls_codepage);
2215 bcc_ptr += 2 * bytes_returned;
2216 bytes_returned =
2217 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2218 nls_codepage);
2219 bcc_ptr += 2 * bytes_returned;
2220 bcc_ptr += 2;
2221 bytes_returned =
2222 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2223 64, nls_codepage);
2224 bcc_ptr += 2 * bytes_returned;
2225 bcc_ptr += 2;
2226 } else {
2227 strncpy(bcc_ptr, user, 200);
2228 bcc_ptr += strnlen(user, 200);
2229 *bcc_ptr = 0;
2230 bcc_ptr++;
2231 if (domain == NULL) {
2232 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2233 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2234 } else {
2235 strncpy(bcc_ptr, domain, 64);
2236 bcc_ptr += strnlen(domain, 64);
2237 *bcc_ptr = 0;
2238 bcc_ptr++;
2239 }
2240 strcpy(bcc_ptr, "Linux version ");
2241 bcc_ptr += strlen("Linux version ");
2242 strcpy(bcc_ptr, system_utsname.release);
2243 bcc_ptr += strlen(system_utsname.release) + 1;
2244 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2245 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2246 }
2247 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2248 smb_buffer->smb_buf_length += count;
2249 pSMB->req.ByteCount = cpu_to_le16(count);
2250
2251 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2252 &bytes_returned, 1);
2253 if (rc) {
2254/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2255 } else if ((smb_buffer_response->WordCount == 3)
2256 || (smb_buffer_response->WordCount == 4)) {
2257 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2258 __u16 blob_len =
2259 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2260 if (action & GUEST_LOGIN)
2261 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2262 if (ses) {
2263 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2264 cFYI(1, ("UID = %d ", ses->Suid));
2265 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2266
2267 /* BB Fix below to make endian neutral !! */
2268
2269 if ((pSMBr->resp.hdr.WordCount == 3)
2270 || ((pSMBr->resp.hdr.WordCount == 4)
2271 && (blob_len <
2272 pSMBr->resp.ByteCount))) {
2273 if (pSMBr->resp.hdr.WordCount == 4) {
2274 bcc_ptr +=
2275 blob_len;
2276 cFYI(1,
2277 ("Security Blob Length %d ",
2278 blob_len));
2279 }
2280
2281 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2282 if ((long) (bcc_ptr) % 2) {
2283 remaining_words =
2284 (BCC(smb_buffer_response)
2285 - 1) / 2;
2286 bcc_ptr++; /* Unicode strings must be word aligned */
2287 } else {
2288 remaining_words =
2289 BCC
2290 (smb_buffer_response) / 2;
2291 }
2292 len =
2293 UniStrnlen((wchar_t *) bcc_ptr,
2294 remaining_words - 1);
2295/* We look for obvious messed up bcc or strings in response so we do not go off
2296 the end since (at least) WIN2K and Windows XP have a major bug in not null
2297 terminating last Unicode string in response */
2298 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002299 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 cifs_strfromUCS_le(ses->serverOS,
2301 (wchar_t *)
2302 bcc_ptr, len,
2303 nls_codepage);
2304 bcc_ptr += 2 * (len + 1);
2305 remaining_words -= len + 1;
2306 ses->serverOS[2 * len] = 0;
2307 ses->serverOS[1 + (2 * len)] = 0;
2308 if (remaining_words > 0) {
2309 len = UniStrnlen((wchar_t *)bcc_ptr,
2310 remaining_words
2311 - 1);
2312 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002313 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 GFP_KERNEL);
2315 cifs_strfromUCS_le(ses->serverNOS,
2316 (wchar_t *)bcc_ptr,
2317 len,
2318 nls_codepage);
2319 bcc_ptr += 2 * (len + 1);
2320 ses->serverNOS[2 * len] = 0;
2321 ses->serverNOS[1 + (2 * len)] = 0;
2322 remaining_words -= len + 1;
2323 if (remaining_words > 0) {
2324 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2325 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve French433dc242005-04-28 22:41:08 -07002326 ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 cifs_strfromUCS_le(ses->serverDomain,
2328 (wchar_t *)bcc_ptr,
2329 len,
2330 nls_codepage);
2331 bcc_ptr += 2*(len+1);
2332 ses->serverDomain[2*len] = 0;
2333 ses->serverDomain[1+(2*len)] = 0;
2334 } /* else no more room so create dummy domain string */
2335 else
2336 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002337 kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002339 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2340 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 }
2342 } else { /* ASCII */
2343
2344 len = strnlen(bcc_ptr, 1024);
2345 if (((long) bcc_ptr + len) - (long)
2346 pByteArea(smb_buffer_response)
2347 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002348 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 strncpy(ses->serverOS, bcc_ptr, len);
2350
2351 bcc_ptr += len;
2352 bcc_ptr[0] = 0; /* null terminate the string */
2353 bcc_ptr++;
2354
2355 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002356 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 strncpy(ses->serverNOS, bcc_ptr, len);
2358 bcc_ptr += len;
2359 bcc_ptr[0] = 0;
2360 bcc_ptr++;
2361
2362 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002363 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 strncpy(ses->serverDomain, bcc_ptr, len);
2365 bcc_ptr += len;
2366 bcc_ptr[0] = 0;
2367 bcc_ptr++;
2368 } else
2369 cFYI(1,
2370 ("Variable field of length %d extends beyond end of smb ",
2371 len));
2372 }
2373 } else {
2374 cERROR(1,
2375 (" Security Blob Length extends beyond end of SMB"));
2376 }
2377 } else {
2378 cERROR(1, ("No session structure passed in."));
2379 }
2380 } else {
2381 cERROR(1,
2382 (" Invalid Word count %d: ",
2383 smb_buffer_response->WordCount));
2384 rc = -EIO;
2385 }
2386
2387 if (smb_buffer)
2388 cifs_buf_release(smb_buffer);
2389
2390 return rc;
2391}
2392
2393static int
2394CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2395 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2396 const struct nls_table *nls_codepage)
2397{
2398 struct smb_hdr *smb_buffer;
2399 struct smb_hdr *smb_buffer_response;
2400 SESSION_SETUP_ANDX *pSMB;
2401 SESSION_SETUP_ANDX *pSMBr;
2402 char *bcc_ptr;
2403 char *domain;
2404 int rc = 0;
2405 int remaining_words = 0;
2406 int bytes_returned = 0;
2407 int len;
2408 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2409 PNEGOTIATE_MESSAGE SecurityBlob;
2410 PCHALLENGE_MESSAGE SecurityBlob2;
2411 __u32 negotiate_flags, capabilities;
2412 __u16 count;
2413
2414 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2415 if(ses == NULL)
2416 return -EINVAL;
2417 domain = ses->domainName;
2418 *pNTLMv2_flag = FALSE;
2419 smb_buffer = cifs_buf_get();
2420 if (smb_buffer == NULL) {
2421 return -ENOMEM;
2422 }
2423 smb_buffer_response = smb_buffer;
2424 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2425 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2426
2427 /* send SMBsessionSetup here */
2428 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2429 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002430
2431 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2433 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2434
2435 pSMB->req.AndXCommand = 0xFF;
2436 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2437 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2438
2439 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2440 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2441
2442 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2443 CAP_EXTENDED_SECURITY;
2444 if (ses->capabilities & CAP_UNICODE) {
2445 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2446 capabilities |= CAP_UNICODE;
2447 }
2448 if (ses->capabilities & CAP_STATUS32) {
2449 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2450 capabilities |= CAP_STATUS32;
2451 }
2452 if (ses->capabilities & CAP_DFS) {
2453 smb_buffer->Flags2 |= SMBFLG2_DFS;
2454 capabilities |= CAP_DFS;
2455 }
2456 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2457
2458 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2459 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2460 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2461 SecurityBlob->MessageType = NtLmNegotiate;
2462 negotiate_flags =
2463 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2464 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2465 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2466 if(sign_CIFS_PDUs)
2467 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2468 if(ntlmv2_support)
2469 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2470 /* setup pointers to domain name and workstation name */
2471 bcc_ptr += SecurityBlobLength;
2472
2473 SecurityBlob->WorkstationName.Buffer = 0;
2474 SecurityBlob->WorkstationName.Length = 0;
2475 SecurityBlob->WorkstationName.MaximumLength = 0;
2476
2477 if (domain == NULL) {
2478 SecurityBlob->DomainName.Buffer = 0;
2479 SecurityBlob->DomainName.Length = 0;
2480 SecurityBlob->DomainName.MaximumLength = 0;
2481 } else {
2482 __u16 len;
2483 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2484 strncpy(bcc_ptr, domain, 63);
2485 len = strnlen(domain, 64);
2486 SecurityBlob->DomainName.MaximumLength =
2487 cpu_to_le16(len);
2488 SecurityBlob->DomainName.Buffer =
2489 cpu_to_le32((long) &SecurityBlob->
2490 DomainString -
2491 (long) &SecurityBlob->Signature);
2492 bcc_ptr += len;
2493 SecurityBlobLength += len;
2494 SecurityBlob->DomainName.Length =
2495 cpu_to_le16(len);
2496 }
2497 if (ses->capabilities & CAP_UNICODE) {
2498 if ((long) bcc_ptr % 2) {
2499 *bcc_ptr = 0;
2500 bcc_ptr++;
2501 }
2502
2503 bytes_returned =
2504 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2505 32, nls_codepage);
2506 bcc_ptr += 2 * bytes_returned;
2507 bytes_returned =
2508 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2509 nls_codepage);
2510 bcc_ptr += 2 * bytes_returned;
2511 bcc_ptr += 2; /* null terminate Linux version */
2512 bytes_returned =
2513 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2514 64, nls_codepage);
2515 bcc_ptr += 2 * bytes_returned;
2516 *(bcc_ptr + 1) = 0;
2517 *(bcc_ptr + 2) = 0;
2518 bcc_ptr += 2; /* null terminate network opsys string */
2519 *(bcc_ptr + 1) = 0;
2520 *(bcc_ptr + 2) = 0;
2521 bcc_ptr += 2; /* null domain */
2522 } else { /* ASCII */
2523 strcpy(bcc_ptr, "Linux version ");
2524 bcc_ptr += strlen("Linux version ");
2525 strcpy(bcc_ptr, system_utsname.release);
2526 bcc_ptr += strlen(system_utsname.release) + 1;
2527 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2528 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2529 bcc_ptr++; /* empty domain field */
2530 *bcc_ptr = 0;
2531 }
2532 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2533 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2534 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2535 smb_buffer->smb_buf_length += count;
2536 pSMB->req.ByteCount = cpu_to_le16(count);
2537
2538 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2539 &bytes_returned, 1);
2540
2541 if (smb_buffer_response->Status.CifsError ==
2542 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2543 rc = 0;
2544
2545 if (rc) {
2546/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2547 } else if ((smb_buffer_response->WordCount == 3)
2548 || (smb_buffer_response->WordCount == 4)) {
2549 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2550 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2551
2552 if (action & GUEST_LOGIN)
2553 cFYI(1, (" Guest login"));
2554 /* Do we want to set anything in SesInfo struct when guest login? */
2555
2556 bcc_ptr = pByteArea(smb_buffer_response);
2557 /* response can have either 3 or 4 word count - Samba sends 3 */
2558
2559 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2560 if (SecurityBlob2->MessageType != NtLmChallenge) {
2561 cFYI(1,
2562 ("Unexpected NTLMSSP message type received %d",
2563 SecurityBlob2->MessageType));
2564 } else if (ses) {
2565 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2566 cFYI(1, ("UID = %d ", ses->Suid));
2567 if ((pSMBr->resp.hdr.WordCount == 3)
2568 || ((pSMBr->resp.hdr.WordCount == 4)
2569 && (blob_len <
2570 pSMBr->resp.ByteCount))) {
2571
2572 if (pSMBr->resp.hdr.WordCount == 4) {
2573 bcc_ptr += blob_len;
2574 cFYI(1,
2575 ("Security Blob Length %d ",
2576 blob_len));
2577 }
2578
2579 cFYI(1, ("NTLMSSP Challenge rcvd "));
2580
2581 memcpy(ses->server->cryptKey,
2582 SecurityBlob2->Challenge,
2583 CIFS_CRYPTO_KEY_SIZE);
2584 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2585 *pNTLMv2_flag = TRUE;
2586
2587 if((SecurityBlob2->NegotiateFlags &
2588 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2589 || (sign_CIFS_PDUs > 1))
2590 ses->server->secMode |=
2591 SECMODE_SIGN_REQUIRED;
2592 if ((SecurityBlob2->NegotiateFlags &
2593 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2594 ses->server->secMode |=
2595 SECMODE_SIGN_ENABLED;
2596
2597 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2598 if ((long) (bcc_ptr) % 2) {
2599 remaining_words =
2600 (BCC(smb_buffer_response)
2601 - 1) / 2;
2602 bcc_ptr++; /* Unicode strings must be word aligned */
2603 } else {
2604 remaining_words =
2605 BCC
2606 (smb_buffer_response) / 2;
2607 }
2608 len =
2609 UniStrnlen((wchar_t *) bcc_ptr,
2610 remaining_words - 1);
2611/* We look for obvious messed up bcc or strings in response so we do not go off
2612 the end since (at least) WIN2K and Windows XP have a major bug in not null
2613 terminating last Unicode string in response */
2614 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002615 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 cifs_strfromUCS_le(ses->serverOS,
2617 (wchar_t *)
2618 bcc_ptr, len,
2619 nls_codepage);
2620 bcc_ptr += 2 * (len + 1);
2621 remaining_words -= len + 1;
2622 ses->serverOS[2 * len] = 0;
2623 ses->serverOS[1 + (2 * len)] = 0;
2624 if (remaining_words > 0) {
2625 len = UniStrnlen((wchar_t *)
2626 bcc_ptr,
2627 remaining_words
2628 - 1);
2629 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002630 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 GFP_KERNEL);
2632 cifs_strfromUCS_le(ses->
2633 serverNOS,
2634 (wchar_t *)
2635 bcc_ptr,
2636 len,
2637 nls_codepage);
2638 bcc_ptr += 2 * (len + 1);
2639 ses->serverNOS[2 * len] = 0;
2640 ses->serverNOS[1 +
2641 (2 * len)] = 0;
2642 remaining_words -= len + 1;
2643 if (remaining_words > 0) {
2644 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2645 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2646 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002647 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 (len +
2649 1),
2650 GFP_KERNEL);
2651 cifs_strfromUCS_le
2652 (ses->
2653 serverDomain,
2654 (wchar_t *)
2655 bcc_ptr, len,
2656 nls_codepage);
2657 bcc_ptr +=
2658 2 * (len + 1);
2659 ses->
2660 serverDomain[2
2661 * len]
2662 = 0;
2663 ses->
2664 serverDomain[1
2665 +
2666 (2
2667 *
2668 len)]
2669 = 0;
2670 } /* else no more room so create dummy domain string */
2671 else
2672 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002673 kcalloc(1, 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 GFP_KERNEL);
2675 } else { /* no room so create dummy domain and NOS string */
2676 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002677 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002679 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 }
2681 } else { /* ASCII */
2682 len = strnlen(bcc_ptr, 1024);
2683 if (((long) bcc_ptr + len) - (long)
2684 pByteArea(smb_buffer_response)
2685 <= BCC(smb_buffer_response)) {
2686 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002687 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 GFP_KERNEL);
2689 strncpy(ses->serverOS,
2690 bcc_ptr, len);
2691
2692 bcc_ptr += len;
2693 bcc_ptr[0] = 0; /* null terminate string */
2694 bcc_ptr++;
2695
2696 len = strnlen(bcc_ptr, 1024);
2697 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002698 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 GFP_KERNEL);
2700 strncpy(ses->serverNOS, bcc_ptr, len);
2701 bcc_ptr += len;
2702 bcc_ptr[0] = 0;
2703 bcc_ptr++;
2704
2705 len = strnlen(bcc_ptr, 1024);
2706 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002707 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 GFP_KERNEL);
2709 strncpy(ses->serverDomain, bcc_ptr, len);
2710 bcc_ptr += len;
2711 bcc_ptr[0] = 0;
2712 bcc_ptr++;
2713 } else
2714 cFYI(1,
2715 ("Variable field of length %d extends beyond end of smb ",
2716 len));
2717 }
2718 } else {
2719 cERROR(1,
2720 (" Security Blob Length extends beyond end of SMB"));
2721 }
2722 } else {
2723 cERROR(1, ("No session structure passed in."));
2724 }
2725 } else {
2726 cERROR(1,
2727 (" Invalid Word count %d: ",
2728 smb_buffer_response->WordCount));
2729 rc = -EIO;
2730 }
2731
2732 if (smb_buffer)
2733 cifs_buf_release(smb_buffer);
2734
2735 return rc;
2736}
2737static int
2738CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2739 char *ntlm_session_key, int ntlmv2_flag,
2740 const struct nls_table *nls_codepage)
2741{
2742 struct smb_hdr *smb_buffer;
2743 struct smb_hdr *smb_buffer_response;
2744 SESSION_SETUP_ANDX *pSMB;
2745 SESSION_SETUP_ANDX *pSMBr;
2746 char *bcc_ptr;
2747 char *user;
2748 char *domain;
2749 int rc = 0;
2750 int remaining_words = 0;
2751 int bytes_returned = 0;
2752 int len;
2753 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2754 PAUTHENTICATE_MESSAGE SecurityBlob;
2755 __u32 negotiate_flags, capabilities;
2756 __u16 count;
2757
2758 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2759 if(ses == NULL)
2760 return -EINVAL;
2761 user = ses->userName;
2762 domain = ses->domainName;
2763 smb_buffer = cifs_buf_get();
2764 if (smb_buffer == NULL) {
2765 return -ENOMEM;
2766 }
2767 smb_buffer_response = smb_buffer;
2768 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2769 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2770
2771 /* send SMBsessionSetup here */
2772 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2773 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002774
2775 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2777 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2778 pSMB->req.AndXCommand = 0xFF;
2779 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2780 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2781
2782 pSMB->req.hdr.Uid = ses->Suid;
2783
2784 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2785 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2786
2787 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2788 CAP_EXTENDED_SECURITY;
2789 if (ses->capabilities & CAP_UNICODE) {
2790 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2791 capabilities |= CAP_UNICODE;
2792 }
2793 if (ses->capabilities & CAP_STATUS32) {
2794 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2795 capabilities |= CAP_STATUS32;
2796 }
2797 if (ses->capabilities & CAP_DFS) {
2798 smb_buffer->Flags2 |= SMBFLG2_DFS;
2799 capabilities |= CAP_DFS;
2800 }
2801 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2802
2803 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2804 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2805 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2806 SecurityBlob->MessageType = NtLmAuthenticate;
2807 bcc_ptr += SecurityBlobLength;
2808 negotiate_flags =
2809 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2810 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2811 0x80000000 | NTLMSSP_NEGOTIATE_128;
2812 if(sign_CIFS_PDUs)
2813 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2814 if(ntlmv2_flag)
2815 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2816
2817/* setup pointers to domain name and workstation name */
2818
2819 SecurityBlob->WorkstationName.Buffer = 0;
2820 SecurityBlob->WorkstationName.Length = 0;
2821 SecurityBlob->WorkstationName.MaximumLength = 0;
2822 SecurityBlob->SessionKey.Length = 0;
2823 SecurityBlob->SessionKey.MaximumLength = 0;
2824 SecurityBlob->SessionKey.Buffer = 0;
2825
2826 SecurityBlob->LmChallengeResponse.Length = 0;
2827 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2828 SecurityBlob->LmChallengeResponse.Buffer = 0;
2829
2830 SecurityBlob->NtChallengeResponse.Length =
2831 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2832 SecurityBlob->NtChallengeResponse.MaximumLength =
2833 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2834 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2835 SecurityBlob->NtChallengeResponse.Buffer =
2836 cpu_to_le32(SecurityBlobLength);
2837 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2838 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2839
2840 if (ses->capabilities & CAP_UNICODE) {
2841 if (domain == NULL) {
2842 SecurityBlob->DomainName.Buffer = 0;
2843 SecurityBlob->DomainName.Length = 0;
2844 SecurityBlob->DomainName.MaximumLength = 0;
2845 } else {
2846 __u16 len =
2847 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2848 nls_codepage);
2849 len *= 2;
2850 SecurityBlob->DomainName.MaximumLength =
2851 cpu_to_le16(len);
2852 SecurityBlob->DomainName.Buffer =
2853 cpu_to_le32(SecurityBlobLength);
2854 bcc_ptr += len;
2855 SecurityBlobLength += len;
2856 SecurityBlob->DomainName.Length =
2857 cpu_to_le16(len);
2858 }
2859 if (user == NULL) {
2860 SecurityBlob->UserName.Buffer = 0;
2861 SecurityBlob->UserName.Length = 0;
2862 SecurityBlob->UserName.MaximumLength = 0;
2863 } else {
2864 __u16 len =
2865 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2866 nls_codepage);
2867 len *= 2;
2868 SecurityBlob->UserName.MaximumLength =
2869 cpu_to_le16(len);
2870 SecurityBlob->UserName.Buffer =
2871 cpu_to_le32(SecurityBlobLength);
2872 bcc_ptr += len;
2873 SecurityBlobLength += len;
2874 SecurityBlob->UserName.Length =
2875 cpu_to_le16(len);
2876 }
2877
2878 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2879 SecurityBlob->WorkstationName.Length *= 2;
2880 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2881 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2882 bcc_ptr += SecurityBlob->WorkstationName.Length;
2883 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2884 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2885
2886 if ((long) bcc_ptr % 2) {
2887 *bcc_ptr = 0;
2888 bcc_ptr++;
2889 }
2890 bytes_returned =
2891 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2892 32, nls_codepage);
2893 bcc_ptr += 2 * bytes_returned;
2894 bytes_returned =
2895 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2896 nls_codepage);
2897 bcc_ptr += 2 * bytes_returned;
2898 bcc_ptr += 2; /* null term version string */
2899 bytes_returned =
2900 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2901 64, nls_codepage);
2902 bcc_ptr += 2 * bytes_returned;
2903 *(bcc_ptr + 1) = 0;
2904 *(bcc_ptr + 2) = 0;
2905 bcc_ptr += 2; /* null terminate network opsys string */
2906 *(bcc_ptr + 1) = 0;
2907 *(bcc_ptr + 2) = 0;
2908 bcc_ptr += 2; /* null domain */
2909 } else { /* ASCII */
2910 if (domain == NULL) {
2911 SecurityBlob->DomainName.Buffer = 0;
2912 SecurityBlob->DomainName.Length = 0;
2913 SecurityBlob->DomainName.MaximumLength = 0;
2914 } else {
2915 __u16 len;
2916 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2917 strncpy(bcc_ptr, domain, 63);
2918 len = strnlen(domain, 64);
2919 SecurityBlob->DomainName.MaximumLength =
2920 cpu_to_le16(len);
2921 SecurityBlob->DomainName.Buffer =
2922 cpu_to_le32(SecurityBlobLength);
2923 bcc_ptr += len;
2924 SecurityBlobLength += len;
2925 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2926 }
2927 if (user == NULL) {
2928 SecurityBlob->UserName.Buffer = 0;
2929 SecurityBlob->UserName.Length = 0;
2930 SecurityBlob->UserName.MaximumLength = 0;
2931 } else {
2932 __u16 len;
2933 strncpy(bcc_ptr, user, 63);
2934 len = strnlen(user, 64);
2935 SecurityBlob->UserName.MaximumLength =
2936 cpu_to_le16(len);
2937 SecurityBlob->UserName.Buffer =
2938 cpu_to_le32(SecurityBlobLength);
2939 bcc_ptr += len;
2940 SecurityBlobLength += len;
2941 SecurityBlob->UserName.Length = cpu_to_le16(len);
2942 }
2943 /* BB fill in our workstation name if known BB */
2944
2945 strcpy(bcc_ptr, "Linux version ");
2946 bcc_ptr += strlen("Linux version ");
2947 strcpy(bcc_ptr, system_utsname.release);
2948 bcc_ptr += strlen(system_utsname.release) + 1;
2949 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2950 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2951 bcc_ptr++; /* null domain */
2952 *bcc_ptr = 0;
2953 }
2954 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2955 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2956 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2957 smb_buffer->smb_buf_length += count;
2958 pSMB->req.ByteCount = cpu_to_le16(count);
2959
2960 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2961 &bytes_returned, 1);
2962 if (rc) {
2963/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2964 } else if ((smb_buffer_response->WordCount == 3)
2965 || (smb_buffer_response->WordCount == 4)) {
2966 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2967 __u16 blob_len =
2968 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2969 if (action & GUEST_LOGIN)
2970 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2971/* if(SecurityBlob2->MessageType != NtLm??){
2972 cFYI("Unexpected message type on auth response is %d "));
2973 } */
2974 if (ses) {
2975 cFYI(1,
2976 ("Does UID on challenge %d match auth response UID %d ",
2977 ses->Suid, smb_buffer_response->Uid));
2978 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2979 bcc_ptr = pByteArea(smb_buffer_response);
2980 /* response can have either 3 or 4 word count - Samba sends 3 */
2981 if ((pSMBr->resp.hdr.WordCount == 3)
2982 || ((pSMBr->resp.hdr.WordCount == 4)
2983 && (blob_len <
2984 pSMBr->resp.ByteCount))) {
2985 if (pSMBr->resp.hdr.WordCount == 4) {
2986 bcc_ptr +=
2987 blob_len;
2988 cFYI(1,
2989 ("Security Blob Length %d ",
2990 blob_len));
2991 }
2992
2993 cFYI(1,
2994 ("NTLMSSP response to Authenticate "));
2995
2996 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2997 if ((long) (bcc_ptr) % 2) {
2998 remaining_words =
2999 (BCC(smb_buffer_response)
3000 - 1) / 2;
3001 bcc_ptr++; /* Unicode strings must be word aligned */
3002 } else {
3003 remaining_words = BCC(smb_buffer_response) / 2;
3004 }
3005 len =
3006 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3007/* We look for obvious messed up bcc or strings in response so we do not go off
3008 the end since (at least) WIN2K and Windows XP have a major bug in not null
3009 terminating last Unicode string in response */
3010 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07003011 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 cifs_strfromUCS_le(ses->serverOS,
3013 (wchar_t *)
3014 bcc_ptr, len,
3015 nls_codepage);
3016 bcc_ptr += 2 * (len + 1);
3017 remaining_words -= len + 1;
3018 ses->serverOS[2 * len] = 0;
3019 ses->serverOS[1 + (2 * len)] = 0;
3020 if (remaining_words > 0) {
3021 len = UniStrnlen((wchar_t *)
3022 bcc_ptr,
3023 remaining_words
3024 - 1);
3025 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07003026 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 GFP_KERNEL);
3028 cifs_strfromUCS_le(ses->
3029 serverNOS,
3030 (wchar_t *)
3031 bcc_ptr,
3032 len,
3033 nls_codepage);
3034 bcc_ptr += 2 * (len + 1);
3035 ses->serverNOS[2 * len] = 0;
3036 ses->serverNOS[1+(2*len)] = 0;
3037 remaining_words -= len + 1;
3038 if (remaining_words > 0) {
3039 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3040 /* last string not always null terminated (e.g. for Windows XP & 2000) */
3041 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07003042 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 (len +
3044 1),
3045 GFP_KERNEL);
3046 cifs_strfromUCS_le
3047 (ses->
3048 serverDomain,
3049 (wchar_t *)
3050 bcc_ptr, len,
3051 nls_codepage);
3052 bcc_ptr +=
3053 2 * (len + 1);
3054 ses->
3055 serverDomain[2
3056 * len]
3057 = 0;
3058 ses->
3059 serverDomain[1
3060 +
3061 (2
3062 *
3063 len)]
3064 = 0;
3065 } /* else no more room so create dummy domain string */
3066 else
Steve French433dc242005-04-28 22:41:08 -07003067 ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07003069 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
3070 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 }
3072 } else { /* ASCII */
3073 len = strnlen(bcc_ptr, 1024);
3074 if (((long) bcc_ptr + len) -
3075 (long) pByteArea(smb_buffer_response)
3076 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07003077 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 strncpy(ses->serverOS,bcc_ptr, len);
3079
3080 bcc_ptr += len;
3081 bcc_ptr[0] = 0; /* null terminate the string */
3082 bcc_ptr++;
3083
3084 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003085 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 strncpy(ses->serverNOS, bcc_ptr, len);
3087 bcc_ptr += len;
3088 bcc_ptr[0] = 0;
3089 bcc_ptr++;
3090
3091 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003092 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 strncpy(ses->serverDomain, bcc_ptr, len);
3094 bcc_ptr += len;
3095 bcc_ptr[0] = 0;
3096 bcc_ptr++;
3097 } else
3098 cFYI(1,
3099 ("Variable field of length %d extends beyond end of smb ",
3100 len));
3101 }
3102 } else {
3103 cERROR(1,
3104 (" Security Blob Length extends beyond end of SMB"));
3105 }
3106 } else {
3107 cERROR(1, ("No session structure passed in."));
3108 }
3109 } else {
3110 cERROR(1,
3111 (" Invalid Word count %d: ",
3112 smb_buffer_response->WordCount));
3113 rc = -EIO;
3114 }
3115
3116 if (smb_buffer)
3117 cifs_buf_release(smb_buffer);
3118
3119 return rc;
3120}
3121
3122int
3123CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3124 const char *tree, struct cifsTconInfo *tcon,
3125 const struct nls_table *nls_codepage)
3126{
3127 struct smb_hdr *smb_buffer;
3128 struct smb_hdr *smb_buffer_response;
3129 TCONX_REQ *pSMB;
3130 TCONX_RSP *pSMBr;
3131 unsigned char *bcc_ptr;
3132 int rc = 0;
3133 int length;
3134 __u16 count;
3135
3136 if (ses == NULL)
3137 return -EIO;
3138
3139 smb_buffer = cifs_buf_get();
3140 if (smb_buffer == NULL) {
3141 return -ENOMEM;
3142 }
3143 smb_buffer_response = smb_buffer;
3144
3145 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3146 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003147
3148 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 smb_buffer->Uid = ses->Suid;
3150 pSMB = (TCONX_REQ *) smb_buffer;
3151 pSMBr = (TCONX_RSP *) smb_buffer_response;
3152
3153 pSMB->AndXCommand = 0xFF;
3154 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3155 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3156 bcc_ptr = &pSMB->Password[0];
3157 bcc_ptr++; /* skip password */
3158
3159 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3160 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3161
3162 if (ses->capabilities & CAP_STATUS32) {
3163 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3164 }
3165 if (ses->capabilities & CAP_DFS) {
3166 smb_buffer->Flags2 |= SMBFLG2_DFS;
3167 }
3168 if (ses->capabilities & CAP_UNICODE) {
3169 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3170 length =
3171 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3172 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3173 bcc_ptr += 2; /* skip trailing null */
3174 } else { /* ASCII */
3175
3176 strcpy(bcc_ptr, tree);
3177 bcc_ptr += strlen(tree) + 1;
3178 }
3179 strcpy(bcc_ptr, "?????");
3180 bcc_ptr += strlen("?????");
3181 bcc_ptr += 1;
3182 count = bcc_ptr - &pSMB->Password[0];
3183 pSMB->hdr.smb_buf_length += count;
3184 pSMB->ByteCount = cpu_to_le16(count);
3185
3186 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3187
3188 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3189 /* above now done in SendReceive */
3190 if ((rc == 0) && (tcon != NULL)) {
3191 tcon->tidStatus = CifsGood;
3192 tcon->tid = smb_buffer_response->Tid;
3193 bcc_ptr = pByteArea(smb_buffer_response);
3194 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3195 /* skip service field (NB: this field is always ASCII) */
3196 bcc_ptr += length + 1;
3197 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3198 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3199 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3200 if ((bcc_ptr + (2 * length)) -
3201 pByteArea(smb_buffer_response) <=
3202 BCC(smb_buffer_response)) {
3203 if(tcon->nativeFileSystem)
3204 kfree(tcon->nativeFileSystem);
3205 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003206 kcalloc(1, length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 cifs_strfromUCS_le(tcon->nativeFileSystem,
3208 (wchar_t *) bcc_ptr,
3209 length, nls_codepage);
3210 bcc_ptr += 2 * length;
3211 bcc_ptr[0] = 0; /* null terminate the string */
3212 bcc_ptr[1] = 0;
3213 bcc_ptr += 2;
3214 }
3215 /* else do not bother copying these informational fields */
3216 } else {
3217 length = strnlen(bcc_ptr, 1024);
3218 if ((bcc_ptr + length) -
3219 pByteArea(smb_buffer_response) <=
3220 BCC(smb_buffer_response)) {
3221 if(tcon->nativeFileSystem)
3222 kfree(tcon->nativeFileSystem);
3223 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003224 kcalloc(1, length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 strncpy(tcon->nativeFileSystem, bcc_ptr,
3226 length);
3227 }
3228 /* else do not bother copying these informational fields */
3229 }
3230 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3231 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3232 } else if ((rc == 0) && tcon == NULL) {
3233 /* all we need to save for IPC$ connection */
3234 ses->ipc_tid = smb_buffer_response->Tid;
3235 }
3236
3237 if (smb_buffer)
3238 cifs_buf_release(smb_buffer);
3239 return rc;
3240}
3241
3242int
3243cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3244{
3245 int rc = 0;
3246 int xid;
3247 struct cifsSesInfo *ses = NULL;
3248 struct task_struct *cifsd_task;
3249
3250 xid = GetXid();
3251
3252 if (cifs_sb->tcon) {
3253 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3254 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3255 if (rc == -EBUSY) {
3256 FreeXid(xid);
3257 return 0;
3258 }
3259 tconInfoFree(cifs_sb->tcon);
3260 if ((ses) && (ses->server)) {
3261 /* save off task so we do not refer to ses later */
3262 cifsd_task = ses->server->tsk;
3263 cFYI(1, ("About to do SMBLogoff "));
3264 rc = CIFSSMBLogoff(xid, ses);
3265 if (rc == -EBUSY) {
3266 FreeXid(xid);
3267 return 0;
3268 } else if (rc == -ESHUTDOWN) {
3269 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf1914012005-08-18 09:37:34 -07003270 if(cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 send_sig(SIGKILL,cifsd_task,1);
Steve Frenchf1914012005-08-18 09:37:34 -07003272 wait_for_completion(&cifsd_complete);
3273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 rc = 0;
3275 } /* else - we have an smb session
3276 left on this socket do not kill cifsd */
3277 } else
3278 cFYI(1, ("No session or bad tcon"));
3279 }
3280
3281 cifs_sb->tcon = NULL;
3282 if (ses) {
3283 set_current_state(TASK_INTERRUPTIBLE);
3284 schedule_timeout(HZ / 2);
3285 }
3286 if (ses)
3287 sesInfoFree(ses);
3288
3289 FreeXid(xid);
3290 return rc; /* BB check if we should always return zero here */
3291}
3292
3293int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3294 struct nls_table * nls_info)
3295{
3296 int rc = 0;
3297 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3298 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003299 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300
3301 /* what if server changes its buffer size after dropping the session? */
3302 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3303 rc = CIFSSMBNegotiate(xid, pSesInfo);
3304 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3305 rc = CIFSSMBNegotiate(xid, pSesInfo);
3306 if(rc == -EAGAIN)
3307 rc = -EHOSTDOWN;
3308 }
3309 if(rc == 0) {
3310 spin_lock(&GlobalMid_Lock);
3311 if(pSesInfo->server->tcpStatus != CifsExiting)
3312 pSesInfo->server->tcpStatus = CifsGood;
3313 else
3314 rc = -EHOSTDOWN;
3315 spin_unlock(&GlobalMid_Lock);
3316
3317 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003318 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 }
3320 if (!rc) {
3321 pSesInfo->capabilities = pSesInfo->server->capabilities;
3322 if(linuxExtEnabled == 0)
3323 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003324 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3326 pSesInfo->server->secMode,
3327 pSesInfo->server->capabilities,
3328 pSesInfo->server->timeZone));
3329 if (extended_security
3330 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3331 && (pSesInfo->server->secType == NTLMSSP)) {
3332 cFYI(1, ("New style sesssetup "));
3333 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3334 NULL /* security blob */,
3335 0 /* blob length */,
3336 nls_info);
3337 } else if (extended_security
3338 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3339 && (pSesInfo->server->secType == RawNTLMSSP)) {
3340 cFYI(1, ("NTLMSSP sesssetup "));
3341 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3342 pSesInfo,
3343 &ntlmv2_flag,
3344 nls_info);
3345 if (!rc) {
3346 if(ntlmv2_flag) {
3347 char * v2_response;
3348 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3349 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3350 nls_info)) {
3351 rc = -ENOMEM;
3352 goto ss_err_exit;
3353 } else
3354 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3355 if(v2_response) {
3356 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003357 /* if(first_time)
3358 cifs_calculate_ntlmv2_mac_key(
3359 pSesInfo->server->mac_signing_key,
3360 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 kfree(v2_response);
3362 /* BB Put dummy sig in SessSetup PDU? */
3363 } else {
3364 rc = -ENOMEM;
3365 goto ss_err_exit;
3366 }
3367
3368 } else {
3369 SMBNTencrypt(pSesInfo->password,
3370 pSesInfo->server->cryptKey,
3371 ntlm_session_key);
3372
Steve Frenchad009ac2005-04-28 22:41:05 -07003373 if(first_time)
3374 cifs_calculate_mac_key(
3375 pSesInfo->server->mac_signing_key,
3376 ntlm_session_key,
3377 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 }
3379 /* for better security the weaker lanman hash not sent
3380 in AuthSessSetup so we no longer calculate it */
3381
3382 rc = CIFSNTLMSSPAuthSessSetup(xid,
3383 pSesInfo,
3384 ntlm_session_key,
3385 ntlmv2_flag,
3386 nls_info);
3387 }
3388 } else { /* old style NTLM 0.12 session setup */
3389 SMBNTencrypt(pSesInfo->password,
3390 pSesInfo->server->cryptKey,
3391 ntlm_session_key);
3392
Steve Frenchad009ac2005-04-28 22:41:05 -07003393 if(first_time)
3394 cifs_calculate_mac_key(
3395 pSesInfo->server->mac_signing_key,
3396 ntlm_session_key, pSesInfo->password);
3397
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 rc = CIFSSessSetup(xid, pSesInfo,
3399 ntlm_session_key, nls_info);
3400 }
3401 if (rc) {
3402 cERROR(1,("Send error in SessSetup = %d",rc));
3403 } else {
3404 cFYI(1,("CIFS Session Established successfully"));
3405 pSesInfo->status = CifsGood;
3406 }
3407 }
3408ss_err_exit:
3409 return rc;
3410}
3411