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