blob: 47360156cc54f40a3f9d469725c8dc19331a106f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve Frenchb8643e12005-04-28 22:41:07 -07004 * Copyright (C) International Business Machines Corp., 2002,2005
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <linux/fs.h>
22#include <linux/net.h>
23#include <linux/string.h>
24#include <linux/list.h>
25#include <linux/wait.h>
26#include <linux/ipv6.h>
27#include <linux/pagemap.h>
28#include <linux/ctype.h>
29#include <linux/utsname.h>
30#include <linux/mempool.h>
Steve Frenchb8643e12005-04-28 22:41:07 -070031#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/uaccess.h>
33#include <asm/processor.h>
34#include "cifspdu.h"
35#include "cifsglob.h"
36#include "cifsproto.h"
37#include "cifs_unicode.h"
38#include "cifs_debug.h"
39#include "cifs_fs_sb.h"
40#include "ntlmssp.h"
41#include "nterr.h"
42#include "rfc1002pdu.h"
43
44#define CIFS_PORT 445
45#define RFC1001_PORT 139
46
47extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
48 unsigned char *p24);
49extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
50 unsigned char *p24);
51
52extern mempool_t *cifs_req_poolp;
53
54struct smb_vol {
55 char *username;
56 char *password;
57 char *domainname;
58 char *UNC;
59 char *UNCip;
60 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
61 char *iocharset; /* local code page for mapping to and from Unicode */
62 char source_rfc1001_name[16]; /* netbios name of client */
63 uid_t linux_uid;
64 gid_t linux_gid;
65 mode_t file_mode;
66 mode_t dir_mode;
67 unsigned rw:1;
68 unsigned retry:1;
69 unsigned intr:1;
70 unsigned setuids:1;
71 unsigned noperm:1;
72 unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
73 unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
74 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
75 unsigned direct_io:1;
Steve French6a0b4822005-04-28 22:41:05 -070076 unsigned remap:1; /* set to remap seven reserved chars in filenames */
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 unsigned int rsize;
78 unsigned int wsize;
79 unsigned int sockopt;
80 unsigned short int port;
81};
82
83static int ipv4_connect(struct sockaddr_in *psin_server,
84 struct socket **csocket,
85 char * netb_name);
86static int ipv6_connect(struct sockaddr_in6 *psin_server,
87 struct socket **csocket);
88
89
90 /*
91 * cifs tcp session reconnection
92 *
93 * mark tcp session as reconnecting so temporarily locked
94 * mark all smb sessions as reconnecting for tcp session
95 * reconnect tcp session
96 * wake up waiters on reconnection? - (not needed currently)
97 */
98
99int
100cifs_reconnect(struct TCP_Server_Info *server)
101{
102 int rc = 0;
103 struct list_head *tmp;
104 struct cifsSesInfo *ses;
105 struct cifsTconInfo *tcon;
106 struct mid_q_entry * mid_entry;
107
108 spin_lock(&GlobalMid_Lock);
109 if(server->tcpStatus == CifsExiting) {
110 /* the demux thread will exit normally
111 next time through the loop */
112 spin_unlock(&GlobalMid_Lock);
113 return rc;
114 } else
115 server->tcpStatus = CifsNeedReconnect;
116 spin_unlock(&GlobalMid_Lock);
117 server->maxBuf = 0;
118
Steve Frenche4eb2952005-04-28 22:41:09 -0700119 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
121 /* before reconnecting the tcp session, mark the smb session (uid)
122 and the tid bad so they are not used until reconnected */
123 read_lock(&GlobalSMBSeslock);
124 list_for_each(tmp, &GlobalSMBSessionList) {
125 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
126 if (ses->server) {
127 if (ses->server == server) {
128 ses->status = CifsNeedReconnect;
129 ses->ipc_tid = 0;
130 }
131 }
132 /* else tcp and smb sessions need reconnection */
133 }
134 list_for_each(tmp, &GlobalTreeConnectionList) {
135 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
136 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
137 tcon->tidStatus = CifsNeedReconnect;
138 }
139 }
140 read_unlock(&GlobalSMBSeslock);
141 /* do not want to be sending data on a socket we are freeing */
142 down(&server->tcpSem);
143 if(server->ssocket) {
144 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
145 server->ssocket->flags));
146 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
147 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
148 server->ssocket->flags));
149 sock_release(server->ssocket);
150 server->ssocket = NULL;
151 }
152
153 spin_lock(&GlobalMid_Lock);
154 list_for_each(tmp, &server->pending_mid_q) {
155 mid_entry = list_entry(tmp, struct
156 mid_q_entry,
157 qhead);
158 if(mid_entry) {
159 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700160 /* Mark other intransit requests as needing
161 retry so we do not immediately mark the
162 session bad again (ie after we reconnect
163 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 mid_entry->midState = MID_RETRY_NEEDED;
165 }
166 }
167 }
168 spin_unlock(&GlobalMid_Lock);
169 up(&server->tcpSem);
170
171 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
172 {
173 if(server->protocolType == IPV6) {
174 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
175 } else {
176 rc = ipv4_connect(&server->addr.sockAddr,
177 &server->ssocket,
178 server->workstation_RFC1001_name);
179 }
180 if(rc) {
Steve French0cb766a2005-04-28 22:41:11 -0700181 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 } else {
183 atomic_inc(&tcpSesReconnectCount);
184 spin_lock(&GlobalMid_Lock);
185 if(server->tcpStatus != CifsExiting)
186 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700187 server->sequence_number = 0;
188 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 /* atomic_set(&server->inFlight,0);*/
190 wake_up(&server->response_q);
191 }
192 }
193 return rc;
194}
195
Steve Frenche4eb2952005-04-28 22:41:09 -0700196/*
197 return codes:
198 0 not a transact2, or all data present
199 >0 transact2 with that much data missing
200 -EINVAL = invalid transact2
201
202 */
203static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
204{
205 struct smb_t2_rsp * pSMBt;
206 int total_data_size;
207 int data_in_this_rsp;
208 int remaining;
209
210 if(pSMB->Command != SMB_COM_TRANSACTION2)
211 return 0;
212
213 /* check for plausible wct, bcc and t2 data and parm sizes */
214 /* check for parm and data offset going beyond end of smb */
215 if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
216 cFYI(1,("invalid transact2 word count"));
217 return -EINVAL;
218 }
219
220 pSMBt = (struct smb_t2_rsp *)pSMB;
221
222 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
223 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
224
225 remaining = total_data_size - data_in_this_rsp;
226
227 if(remaining == 0)
228 return 0;
229 else if(remaining < 0) {
230 cFYI(1,("total data %d smaller than data in frame %d",
231 total_data_size, data_in_this_rsp));
232 return -EINVAL;
233 } else {
234 cFYI(1,("missing %d bytes from transact2, check next response",
235 remaining));
236 if(total_data_size > maxBufSize) {
237 cERROR(1,("TotalDataSize %d is over maximum buffer %d",
238 total_data_size,maxBufSize));
239 return -EINVAL;
240 }
241 return remaining;
242 }
243}
244
245static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
246{
247 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
248 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
249 int total_data_size;
250 int total_in_buf;
251 int remaining;
252 int total_in_buf2;
253 char * data_area_of_target;
254 char * data_area_of_buf2;
255 __u16 byte_count;
256
257 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
258
259 if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
260 cFYI(1,("total data sizes of primary and secondary t2 differ"));
261 }
262
263 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
264
265 remaining = total_data_size - total_in_buf;
266
267 if(remaining < 0)
268 return -EINVAL;
269
270 if(remaining == 0) /* nothing to do, ignore */
271 return 0;
272
273 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
274 if(remaining < total_in_buf2) {
275 cFYI(1,("transact2 2nd response contains too much data"));
276 }
277
278 /* find end of first SMB data area */
279 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
280 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
281 /* validate target area */
282
283 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
284 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
285
286 data_area_of_target += total_in_buf;
287
288 /* copy second buffer into end of first buffer */
289 memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
290 total_in_buf += total_in_buf2;
291 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
292 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
293 byte_count += total_in_buf2;
294 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
295
296 byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
297 byte_count += total_in_buf2;
298
299 /* BB also add check that we are not beyond maximum buffer size */
300
301 pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
302
303 if(remaining == total_in_buf2) {
304 cFYI(1,("found the last secondary response"));
305 return 0; /* we are done */
306 } else /* more responses to go */
307 return 1;
308
309}
310
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311static int
312cifs_demultiplex_thread(struct TCP_Server_Info *server)
313{
314 int length;
315 unsigned int pdu_length, total_read;
316 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700317 struct smb_hdr *bigbuf = NULL;
318 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 struct msghdr smb_msg;
320 struct kvec iov;
321 struct socket *csocket = server->ssocket;
322 struct list_head *tmp;
323 struct cifsSesInfo *ses;
324 struct task_struct *task_to_wake = NULL;
325 struct mid_q_entry *mid_entry;
326 char *temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700327 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700328 int isMultiRsp;
329 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 daemonize("cifsd");
332 allow_signal(SIGKILL);
333 current->flags |= PF_MEMALLOC;
334 server->tsk = current; /* save process info to wake at shutdown */
335 cFYI(1, ("Demultiplex PID: %d", current->pid));
336 write_lock(&GlobalSMBSeslock);
337 atomic_inc(&tcpSesAllocCount);
338 length = tcpSesAllocCount.counter;
339 write_unlock(&GlobalSMBSeslock);
340 if(length > 1) {
341 mempool_resize(cifs_req_poolp,
342 length + cifs_min_rcv,
343 GFP_KERNEL);
344 }
345
346 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700347 if (try_to_freeze())
348 continue;
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
750 if (!options)
751 return 1;
752
753 if(strncmp(options,"sep=",4) == 0) {
754 if(options[4] != 0) {
755 separator[0] = options[4];
756 options += 5;
757 } else {
758 cFYI(1,("Null separator not allowed"));
759 }
760 }
761
762 while ((data = strsep(&options, separator)) != NULL) {
763 if (!*data)
764 continue;
765 if ((value = strchr(data, '=')) != NULL)
766 *value++ = '\0';
767
768 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
769 vol->no_xattr = 0;
770 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
771 vol->no_xattr = 1;
772 } else if (strnicmp(data, "user", 4) == 0) {
773 if (!value || !*value) {
774 printk(KERN_WARNING
775 "CIFS: invalid or missing username\n");
776 return 1; /* needs_arg; */
777 }
778 if (strnlen(value, 200) < 200) {
779 vol->username = value;
780 } else {
781 printk(KERN_WARNING "CIFS: username too long\n");
782 return 1;
783 }
784 } else if (strnicmp(data, "pass", 4) == 0) {
785 if (!value) {
786 vol->password = NULL;
787 continue;
788 } else if(value[0] == 0) {
789 /* check if string begins with double comma
790 since that would mean the password really
791 does start with a comma, and would not
792 indicate an empty string */
793 if(value[1] != separator[0]) {
794 vol->password = NULL;
795 continue;
796 }
797 }
798 temp_len = strlen(value);
799 /* removed password length check, NTLM passwords
800 can be arbitrarily long */
801
802 /* if comma in password, the string will be
803 prematurely null terminated. Commas in password are
804 specified across the cifs mount interface by a double
805 comma ie ,, and a comma used as in other cases ie ','
806 as a parameter delimiter/separator is single and due
807 to the strsep above is temporarily zeroed. */
808
809 /* NB: password legally can have multiple commas and
810 the only illegal character in a password is null */
811
Steve French09d1db52005-04-28 22:41:08 -0700812 if ((value[temp_len] == 0) &&
813 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 /* reinsert comma */
815 value[temp_len] = separator[0];
816 temp_len+=2; /* move after the second comma */
817 while(value[temp_len] != 0) {
818 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700819 if (value[temp_len+1] ==
820 separator[0]) {
821 /* skip second comma */
822 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 } else {
824 /* single comma indicating start
825 of next parm */
826 break;
827 }
828 }
829 temp_len++;
830 }
831 if(value[temp_len] == 0) {
832 options = NULL;
833 } else {
834 value[temp_len] = 0;
835 /* point option to start of next parm */
836 options = value + temp_len + 1;
837 }
838 /* go from value to value + temp_len condensing
839 double commas to singles. Note that this ends up
840 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700841 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700842 if(vol->password == NULL) {
843 printk("CIFS: no memory for pass\n");
844 return 1;
845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 for(i=0,j=0;i<temp_len;i++,j++) {
847 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700848 if(value[i] == separator[0]
849 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 /* skip second comma */
851 i++;
852 }
853 }
854 vol->password[j] = 0;
855 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700856 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700857 if(vol->password == NULL) {
858 printk("CIFS: no memory for pass\n");
859 return 1;
860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 strcpy(vol->password, value);
862 }
863 } else if (strnicmp(data, "ip", 2) == 0) {
864 if (!value || !*value) {
865 vol->UNCip = NULL;
866 } else if (strnlen(value, 35) < 35) {
867 vol->UNCip = value;
868 } else {
869 printk(KERN_WARNING "CIFS: ip address too long\n");
870 return 1;
871 }
872 } else if ((strnicmp(data, "unc", 3) == 0)
873 || (strnicmp(data, "target", 6) == 0)
874 || (strnicmp(data, "path", 4) == 0)) {
875 if (!value || !*value) {
876 printk(KERN_WARNING
877 "CIFS: invalid path to network resource\n");
878 return 1; /* needs_arg; */
879 }
880 if ((temp_len = strnlen(value, 300)) < 300) {
881 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
882 if(vol->UNC == NULL)
883 return 1;
884 strcpy(vol->UNC,value);
885 if (strncmp(vol->UNC, "//", 2) == 0) {
886 vol->UNC[0] = '\\';
887 vol->UNC[1] = '\\';
888 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
889 printk(KERN_WARNING
890 "CIFS: UNC Path does not begin with // or \\\\ \n");
891 return 1;
892 }
893 } else {
894 printk(KERN_WARNING "CIFS: UNC name too long\n");
895 return 1;
896 }
897 } else if ((strnicmp(data, "domain", 3) == 0)
898 || (strnicmp(data, "workgroup", 5) == 0)) {
899 if (!value || !*value) {
900 printk(KERN_WARNING "CIFS: invalid domain name\n");
901 return 1; /* needs_arg; */
902 }
903 /* BB are there cases in which a comma can be valid in
904 a domain name and need special handling? */
905 if (strnlen(value, 65) < 65) {
906 vol->domainname = value;
907 cFYI(1, ("Domain name set"));
908 } else {
909 printk(KERN_WARNING "CIFS: domain name too long\n");
910 return 1;
911 }
912 } else if (strnicmp(data, "iocharset", 9) == 0) {
913 if (!value || !*value) {
914 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
915 return 1; /* needs_arg; */
916 }
917 if (strnlen(value, 65) < 65) {
918 if(strnicmp(value,"default",7))
919 vol->iocharset = value;
920 /* if iocharset not set load_nls_default used by caller */
921 cFYI(1, ("iocharset set to %s",value));
922 } else {
923 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
924 return 1;
925 }
926 } else if (strnicmp(data, "uid", 3) == 0) {
927 if (value && *value) {
928 vol->linux_uid =
929 simple_strtoul(value, &value, 0);
930 }
931 } else if (strnicmp(data, "gid", 3) == 0) {
932 if (value && *value) {
933 vol->linux_gid =
934 simple_strtoul(value, &value, 0);
935 }
936 } else if (strnicmp(data, "file_mode", 4) == 0) {
937 if (value && *value) {
938 vol->file_mode =
939 simple_strtoul(value, &value, 0);
940 }
941 } else if (strnicmp(data, "dir_mode", 4) == 0) {
942 if (value && *value) {
943 vol->dir_mode =
944 simple_strtoul(value, &value, 0);
945 }
946 } else if (strnicmp(data, "dirmode", 4) == 0) {
947 if (value && *value) {
948 vol->dir_mode =
949 simple_strtoul(value, &value, 0);
950 }
951 } else if (strnicmp(data, "port", 4) == 0) {
952 if (value && *value) {
953 vol->port =
954 simple_strtoul(value, &value, 0);
955 }
956 } else if (strnicmp(data, "rsize", 5) == 0) {
957 if (value && *value) {
958 vol->rsize =
959 simple_strtoul(value, &value, 0);
960 }
961 } else if (strnicmp(data, "wsize", 5) == 0) {
962 if (value && *value) {
963 vol->wsize =
964 simple_strtoul(value, &value, 0);
965 }
966 } else if (strnicmp(data, "sockopt", 5) == 0) {
967 if (value && *value) {
968 vol->sockopt =
969 simple_strtoul(value, &value, 0);
970 }
971 } else if (strnicmp(data, "netbiosname", 4) == 0) {
972 if (!value || !*value || (*value == ' ')) {
973 cFYI(1,("invalid (empty) netbiosname specified"));
974 } else {
975 memset(vol->source_rfc1001_name,0x20,15);
976 for(i=0;i<15;i++) {
977 /* BB are there cases in which a comma can be
978 valid in this workstation netbios name (and need
979 special handling)? */
980
981 /* We do not uppercase netbiosname for user */
982 if (value[i]==0)
983 break;
984 else
985 vol->source_rfc1001_name[i] = value[i];
986 }
987 /* The string has 16th byte zero still from
988 set at top of the function */
989 if((i==15) && (value[i] != 0))
990 printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
991 }
992 } else if (strnicmp(data, "credentials", 4) == 0) {
993 /* ignore */
994 } else if (strnicmp(data, "version", 3) == 0) {
995 /* ignore */
996 } else if (strnicmp(data, "guest",5) == 0) {
997 /* ignore */
998 } else if (strnicmp(data, "rw", 2) == 0) {
999 vol->rw = TRUE;
1000 } else if ((strnicmp(data, "suid", 4) == 0) ||
1001 (strnicmp(data, "nosuid", 6) == 0) ||
1002 (strnicmp(data, "exec", 4) == 0) ||
1003 (strnicmp(data, "noexec", 6) == 0) ||
1004 (strnicmp(data, "nodev", 5) == 0) ||
1005 (strnicmp(data, "noauto", 6) == 0) ||
1006 (strnicmp(data, "dev", 3) == 0)) {
1007 /* The mount tool or mount.cifs helper (if present)
1008 uses these opts to set flags, and the flags are read
1009 by the kernel vfs layer before we get here (ie
1010 before read super) so there is no point trying to
1011 parse these options again and set anything and it
1012 is ok to just ignore them */
1013 continue;
1014 } else if (strnicmp(data, "ro", 2) == 0) {
1015 vol->rw = FALSE;
1016 } else if (strnicmp(data, "hard", 4) == 0) {
1017 vol->retry = 1;
1018 } else if (strnicmp(data, "soft", 4) == 0) {
1019 vol->retry = 0;
1020 } else if (strnicmp(data, "perm", 4) == 0) {
1021 vol->noperm = 0;
1022 } else if (strnicmp(data, "noperm", 6) == 0) {
1023 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001024 } else if (strnicmp(data, "mapchars", 8) == 0) {
1025 vol->remap = 1;
1026 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1027 vol->remap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 } else if (strnicmp(data, "setuids", 7) == 0) {
1029 vol->setuids = 1;
1030 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1031 vol->setuids = 0;
1032 } else if (strnicmp(data, "nohard", 6) == 0) {
1033 vol->retry = 0;
1034 } else if (strnicmp(data, "nosoft", 6) == 0) {
1035 vol->retry = 1;
1036 } else if (strnicmp(data, "nointr", 6) == 0) {
1037 vol->intr = 0;
1038 } else if (strnicmp(data, "intr", 4) == 0) {
1039 vol->intr = 1;
1040 } else if (strnicmp(data, "serverino",7) == 0) {
1041 vol->server_ino = 1;
1042 } else if (strnicmp(data, "noserverino",9) == 0) {
1043 vol->server_ino = 0;
1044 } else if (strnicmp(data, "acl",3) == 0) {
1045 vol->no_psx_acl = 0;
1046 } else if (strnicmp(data, "noacl",5) == 0) {
1047 vol->no_psx_acl = 1;
1048 } else if (strnicmp(data, "direct",6) == 0) {
1049 vol->direct_io = 1;
1050 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1051 vol->direct_io = 1;
1052 } else if (strnicmp(data, "in6_addr",8) == 0) {
1053 if (!value || !*value) {
1054 vol->in6_addr = NULL;
1055 } else if (strnlen(value, 49) == 48) {
1056 vol->in6_addr = value;
1057 } else {
1058 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1059 return 1;
1060 }
1061 } else if (strnicmp(data, "noac", 4) == 0) {
1062 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1063 } else
1064 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1065 }
1066 if (vol->UNC == NULL) {
1067 if(devname == NULL) {
1068 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1069 return 1;
1070 }
1071 if ((temp_len = strnlen(devname, 300)) < 300) {
1072 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1073 if(vol->UNC == NULL)
1074 return 1;
1075 strcpy(vol->UNC,devname);
1076 if (strncmp(vol->UNC, "//", 2) == 0) {
1077 vol->UNC[0] = '\\';
1078 vol->UNC[1] = '\\';
1079 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1080 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1081 return 1;
1082 }
1083 } else {
1084 printk(KERN_WARNING "CIFS: UNC name too long\n");
1085 return 1;
1086 }
1087 }
1088 if(vol->UNCip == NULL)
1089 vol->UNCip = &vol->UNC[2];
1090
1091 return 0;
1092}
1093
1094static struct cifsSesInfo *
1095cifs_find_tcp_session(struct in_addr * target_ip_addr,
1096 struct in6_addr *target_ip6_addr,
1097 char *userName, struct TCP_Server_Info **psrvTcp)
1098{
1099 struct list_head *tmp;
1100 struct cifsSesInfo *ses;
1101 *psrvTcp = NULL;
1102 read_lock(&GlobalSMBSeslock);
1103
1104 list_for_each(tmp, &GlobalSMBSessionList) {
1105 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1106 if (ses->server) {
1107 if((target_ip_addr &&
1108 (ses->server->addr.sockAddr.sin_addr.s_addr
1109 == target_ip_addr->s_addr)) || (target_ip6_addr
1110 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1111 target_ip6_addr,sizeof(*target_ip6_addr)))){
1112 /* BB lock server and tcp session and increment use count here?? */
1113 *psrvTcp = ses->server; /* found a match on the TCP session */
1114 /* BB check if reconnection needed */
1115 if (strncmp
1116 (ses->userName, userName,
1117 MAX_USERNAME_SIZE) == 0){
1118 read_unlock(&GlobalSMBSeslock);
1119 return ses; /* found exact match on both tcp and SMB sessions */
1120 }
1121 }
1122 }
1123 /* else tcp and smb sessions need reconnection */
1124 }
1125 read_unlock(&GlobalSMBSeslock);
1126 return NULL;
1127}
1128
1129static struct cifsTconInfo *
1130find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1131{
1132 struct list_head *tmp;
1133 struct cifsTconInfo *tcon;
1134
1135 read_lock(&GlobalSMBSeslock);
1136 list_for_each(tmp, &GlobalTreeConnectionList) {
1137 cFYI(1, ("Next tcon - "));
1138 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1139 if (tcon->ses) {
1140 if (tcon->ses->server) {
1141 cFYI(1,
1142 (" old ip addr: %x == new ip %x ?",
1143 tcon->ses->server->addr.sockAddr.sin_addr.
1144 s_addr, new_target_ip_addr));
1145 if (tcon->ses->server->addr.sockAddr.sin_addr.
1146 s_addr == new_target_ip_addr) {
1147 /* BB lock tcon and server and tcp session and increment use count here? */
1148 /* found a match on the TCP session */
1149 /* BB check if reconnection needed */
1150 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1151 tcon->treeName, uncName));
1152 if (strncmp
1153 (tcon->treeName, uncName,
1154 MAX_TREE_SIZE) == 0) {
1155 cFYI(1,
1156 ("Matched UNC, old user: %s == new: %s ?",
1157 tcon->treeName, uncName));
1158 if (strncmp
1159 (tcon->ses->userName,
1160 userName,
1161 MAX_USERNAME_SIZE) == 0) {
1162 read_unlock(&GlobalSMBSeslock);
1163 return tcon;/* also matched user (smb session)*/
1164 }
1165 }
1166 }
1167 }
1168 }
1169 }
1170 read_unlock(&GlobalSMBSeslock);
1171 return NULL;
1172}
1173
1174int
1175connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001176 const char *old_path, const struct nls_table *nls_codepage,
1177 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178{
1179 unsigned char *referrals = NULL;
1180 unsigned int num_referrals;
1181 int rc = 0;
1182
1183 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001184 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185
1186 /* BB Add in code to: if valid refrl, if not ip address contact
1187 the helper that resolves tcp names, mount to it, try to
1188 tcon to it unmount it if fail */
1189
1190 if(referrals)
1191 kfree(referrals);
1192
1193 return rc;
1194}
1195
1196int
1197get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1198 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001199 unsigned int *pnum_referrals,
1200 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201{
1202 char *temp_unc;
1203 int rc = 0;
1204
1205 *pnum_referrals = 0;
1206
1207 if (pSesInfo->ipc_tid == 0) {
1208 temp_unc = kmalloc(2 /* for slashes */ +
1209 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1210 + 1 + 4 /* slash IPC$ */ + 2,
1211 GFP_KERNEL);
1212 if (temp_unc == NULL)
1213 return -ENOMEM;
1214 temp_unc[0] = '\\';
1215 temp_unc[1] = '\\';
1216 strcpy(temp_unc + 2, pSesInfo->serverName);
1217 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1218 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1219 cFYI(1,
1220 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1221 kfree(temp_unc);
1222 }
1223 if (rc == 0)
1224 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001225 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227 return rc;
1228}
1229
1230/* See RFC1001 section 14 on representation of Netbios names */
1231static void rfc1002mangle(char * target,char * source, unsigned int length)
1232{
1233 unsigned int i,j;
1234
1235 for(i=0,j=0;i<(length);i++) {
1236 /* mask a nibble at a time and encode */
1237 target[j] = 'A' + (0x0F & (source[i] >> 4));
1238 target[j+1] = 'A' + (0x0F & source[i]);
1239 j+=2;
1240 }
1241
1242}
1243
1244
1245static int
1246ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1247 char * netbios_name)
1248{
1249 int rc = 0;
1250 int connected = 0;
1251 __be16 orig_port = 0;
1252
1253 if(*csocket == NULL) {
1254 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1255 if (rc < 0) {
1256 cERROR(1, ("Error %d creating socket",rc));
1257 *csocket = NULL;
1258 return rc;
1259 } else {
1260 /* BB other socket options to set KEEPALIVE, NODELAY? */
1261 cFYI(1,("Socket created"));
1262 (*csocket)->sk->sk_allocation = GFP_NOFS;
1263 }
1264 }
1265
1266 psin_server->sin_family = AF_INET;
1267 if(psin_server->sin_port) { /* user overrode default port */
1268 rc = (*csocket)->ops->connect(*csocket,
1269 (struct sockaddr *) psin_server,
1270 sizeof (struct sockaddr_in),0);
1271 if (rc >= 0)
1272 connected = 1;
1273 }
1274
1275 if(!connected) {
1276 /* save original port so we can retry user specified port
1277 later if fall back ports fail this time */
1278 orig_port = psin_server->sin_port;
1279
1280 /* do not retry on the same port we just failed on */
1281 if(psin_server->sin_port != htons(CIFS_PORT)) {
1282 psin_server->sin_port = htons(CIFS_PORT);
1283
1284 rc = (*csocket)->ops->connect(*csocket,
1285 (struct sockaddr *) psin_server,
1286 sizeof (struct sockaddr_in),0);
1287 if (rc >= 0)
1288 connected = 1;
1289 }
1290 }
1291 if (!connected) {
1292 psin_server->sin_port = htons(RFC1001_PORT);
1293 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1294 psin_server, sizeof (struct sockaddr_in),0);
1295 if (rc >= 0)
1296 connected = 1;
1297 }
1298
1299 /* give up here - unless we want to retry on different
1300 protocol families some day */
1301 if (!connected) {
1302 if(orig_port)
1303 psin_server->sin_port = orig_port;
1304 cFYI(1,("Error %d connecting to server via ipv4",rc));
1305 sock_release(*csocket);
1306 *csocket = NULL;
1307 return rc;
1308 }
1309 /* Eventually check for other socket options to change from
1310 the default. sock_setsockopt not used because it expects
1311 user space buffer */
1312 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1313
1314 /* send RFC1001 sessinit */
1315
1316 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1317 /* some servers require RFC1001 sessinit before sending
1318 negprot - BB check reconnection in case where second
1319 sessinit is sent but no second negprot */
1320 struct rfc1002_session_packet * ses_init_buf;
1321 struct smb_hdr * smb_buf;
Pekka Enberge915fc42005-09-06 15:18:35 -07001322 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 if(ses_init_buf) {
1324 ses_init_buf->trailer.session_req.called_len = 32;
1325 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1326 DEFAULT_CIFS_CALLED_NAME,16);
1327 ses_init_buf->trailer.session_req.calling_len = 32;
1328 /* calling name ends in null (byte 16) from old smb
1329 convention. */
1330 if(netbios_name && (netbios_name[0] !=0)) {
1331 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1332 netbios_name,16);
1333 } else {
1334 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1335 "LINUX_CIFS_CLNT",16);
1336 }
1337 ses_init_buf->trailer.session_req.scope1 = 0;
1338 ses_init_buf->trailer.session_req.scope2 = 0;
1339 smb_buf = (struct smb_hdr *)ses_init_buf;
1340 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1341 smb_buf->smb_buf_length = 0x81000044;
1342 rc = smb_send(*csocket, smb_buf, 0x44,
1343 (struct sockaddr *)psin_server);
1344 kfree(ses_init_buf);
1345 }
1346 /* else the negprot may still work without this
1347 even though malloc failed */
1348
1349 }
1350
1351 return rc;
1352}
1353
1354static int
1355ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1356{
1357 int rc = 0;
1358 int connected = 0;
1359 __be16 orig_port = 0;
1360
1361 if(*csocket == NULL) {
1362 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1363 if (rc < 0) {
1364 cERROR(1, ("Error %d creating ipv6 socket",rc));
1365 *csocket = NULL;
1366 return rc;
1367 } else {
1368 /* BB other socket options to set KEEPALIVE, NODELAY? */
1369 cFYI(1,("ipv6 Socket created"));
1370 (*csocket)->sk->sk_allocation = GFP_NOFS;
1371 }
1372 }
1373
1374 psin_server->sin6_family = AF_INET6;
1375
1376 if(psin_server->sin6_port) { /* user overrode default port */
1377 rc = (*csocket)->ops->connect(*csocket,
1378 (struct sockaddr *) psin_server,
1379 sizeof (struct sockaddr_in6),0);
1380 if (rc >= 0)
1381 connected = 1;
1382 }
1383
1384 if(!connected) {
1385 /* save original port so we can retry user specified port
1386 later if fall back ports fail this time */
1387
1388 orig_port = psin_server->sin6_port;
1389 /* do not retry on the same port we just failed on */
1390 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1391 psin_server->sin6_port = htons(CIFS_PORT);
1392
1393 rc = (*csocket)->ops->connect(*csocket,
1394 (struct sockaddr *) psin_server,
1395 sizeof (struct sockaddr_in6),0);
1396 if (rc >= 0)
1397 connected = 1;
1398 }
1399 }
1400 if (!connected) {
1401 psin_server->sin6_port = htons(RFC1001_PORT);
1402 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1403 psin_server, sizeof (struct sockaddr_in6),0);
1404 if (rc >= 0)
1405 connected = 1;
1406 }
1407
1408 /* give up here - unless we want to retry on different
1409 protocol families some day */
1410 if (!connected) {
1411 if(orig_port)
1412 psin_server->sin6_port = orig_port;
1413 cFYI(1,("Error %d connecting to server via ipv6",rc));
1414 sock_release(*csocket);
1415 *csocket = NULL;
1416 return rc;
1417 }
1418 /* Eventually check for other socket options to change from
1419 the default. sock_setsockopt not used because it expects
1420 user space buffer */
1421 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1422
1423 return rc;
1424}
1425
1426int
1427cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1428 char *mount_data, const char *devname)
1429{
1430 int rc = 0;
1431 int xid;
1432 int address_type = AF_INET;
1433 struct socket *csocket = NULL;
1434 struct sockaddr_in sin_server;
1435 struct sockaddr_in6 sin_server6;
1436 struct smb_vol volume_info;
1437 struct cifsSesInfo *pSesInfo = NULL;
1438 struct cifsSesInfo *existingCifsSes = NULL;
1439 struct cifsTconInfo *tcon = NULL;
1440 struct TCP_Server_Info *srvTcp = NULL;
1441
1442 xid = GetXid();
1443
1444/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1445
1446 memset(&volume_info,0,sizeof(struct smb_vol));
1447 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1448 if(volume_info.UNC)
1449 kfree(volume_info.UNC);
1450 if(volume_info.password)
1451 kfree(volume_info.password);
1452 FreeXid(xid);
1453 return -EINVAL;
1454 }
1455
1456 if (volume_info.username) {
1457 /* BB fixme parse for domain name here */
1458 cFYI(1, ("Username: %s ", volume_info.username));
1459
1460 } else {
1461 cifserror("No username specified ");
1462 /* In userspace mount helper we can get user name from alternate
1463 locations such as env variables and files on disk */
1464 if(volume_info.UNC)
1465 kfree(volume_info.UNC);
1466 if(volume_info.password)
1467 kfree(volume_info.password);
1468 FreeXid(xid);
1469 return -EINVAL;
1470 }
1471
1472 if (volume_info.UNCip && volume_info.UNC) {
1473 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1474
1475 if(rc <= 0) {
1476 /* not ipv4 address, try ipv6 */
1477 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1478 if(rc > 0)
1479 address_type = AF_INET6;
1480 } else {
1481 address_type = AF_INET;
1482 }
1483
1484 if(rc <= 0) {
1485 /* we failed translating address */
1486 if(volume_info.UNC)
1487 kfree(volume_info.UNC);
1488 if(volume_info.password)
1489 kfree(volume_info.password);
1490 FreeXid(xid);
1491 return -EINVAL;
1492 }
1493
1494 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1495 /* success */
1496 rc = 0;
1497 } else if (volume_info.UNCip){
1498 /* BB using ip addr as server name connect to the DFS root below */
1499 cERROR(1,("Connecting to DFS root not implemented yet"));
1500 if(volume_info.UNC)
1501 kfree(volume_info.UNC);
1502 if(volume_info.password)
1503 kfree(volume_info.password);
1504 FreeXid(xid);
1505 return -EINVAL;
1506 } else /* which servers DFS root would we conect to */ {
1507 cERROR(1,
1508 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1509 if(volume_info.UNC)
1510 kfree(volume_info.UNC);
1511 if(volume_info.password)
1512 kfree(volume_info.password);
1513 FreeXid(xid);
1514 return -EINVAL;
1515 }
1516
1517 /* this is needed for ASCII cp to Unicode converts */
1518 if(volume_info.iocharset == NULL) {
1519 cifs_sb->local_nls = load_nls_default();
1520 /* load_nls_default can not return null */
1521 } else {
1522 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1523 if(cifs_sb->local_nls == NULL) {
1524 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1525 if(volume_info.UNC)
1526 kfree(volume_info.UNC);
1527 if(volume_info.password)
1528 kfree(volume_info.password);
1529 FreeXid(xid);
1530 return -ELIBACC;
1531 }
1532 }
1533
1534 if(address_type == AF_INET)
1535 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1536 NULL /* no ipv6 addr */,
1537 volume_info.username, &srvTcp);
1538 else if(address_type == AF_INET6)
1539 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1540 &sin_server6.sin6_addr,
1541 volume_info.username, &srvTcp);
1542 else {
1543 if(volume_info.UNC)
1544 kfree(volume_info.UNC);
1545 if(volume_info.password)
1546 kfree(volume_info.password);
1547 FreeXid(xid);
1548 return -EINVAL;
1549 }
1550
1551
1552 if (srvTcp) {
1553 cFYI(1, ("Existing tcp session with server found "));
1554 } else { /* create socket */
1555 if(volume_info.port)
1556 sin_server.sin_port = htons(volume_info.port);
1557 else
1558 sin_server.sin_port = 0;
1559 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1560 if (rc < 0) {
1561 cERROR(1,
1562 ("Error connecting to IPv4 socket. Aborting operation"));
1563 if(csocket != NULL)
1564 sock_release(csocket);
1565 if(volume_info.UNC)
1566 kfree(volume_info.UNC);
1567 if(volume_info.password)
1568 kfree(volume_info.password);
1569 FreeXid(xid);
1570 return rc;
1571 }
1572
1573 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1574 if (srvTcp == NULL) {
1575 rc = -ENOMEM;
1576 sock_release(csocket);
1577 if(volume_info.UNC)
1578 kfree(volume_info.UNC);
1579 if(volume_info.password)
1580 kfree(volume_info.password);
1581 FreeXid(xid);
1582 return rc;
1583 } else {
1584 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1585 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1586 atomic_set(&srvTcp->inFlight,0);
1587 /* BB Add code for ipv6 case too */
1588 srvTcp->ssocket = csocket;
1589 srvTcp->protocolType = IPV4;
1590 init_waitqueue_head(&srvTcp->response_q);
1591 init_waitqueue_head(&srvTcp->request_q);
1592 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1593 /* at this point we are the only ones with the pointer
1594 to the struct since the kernel thread not created yet
1595 so no need to spinlock this init of tcpStatus */
1596 srvTcp->tcpStatus = CifsNew;
1597 init_MUTEX(&srvTcp->tcpSem);
1598 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1599 CLONE_FS | CLONE_FILES | CLONE_VM);
1600 if(rc < 0) {
1601 rc = -ENOMEM;
1602 sock_release(csocket);
1603 if(volume_info.UNC)
1604 kfree(volume_info.UNC);
1605 if(volume_info.password)
1606 kfree(volume_info.password);
1607 FreeXid(xid);
1608 return rc;
1609 } else
1610 rc = 0;
1611 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001612 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 }
1614 }
1615
1616 if (existingCifsSes) {
1617 pSesInfo = existingCifsSes;
1618 cFYI(1, ("Existing smb sess found "));
1619 if(volume_info.password)
1620 kfree(volume_info.password);
1621 /* volume_info.UNC freed at end of function */
1622 } else if (!rc) {
1623 cFYI(1, ("Existing smb sess not found "));
1624 pSesInfo = sesInfoAlloc();
1625 if (pSesInfo == NULL)
1626 rc = -ENOMEM;
1627 else {
1628 pSesInfo->server = srvTcp;
1629 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1630 NIPQUAD(sin_server.sin_addr.s_addr));
1631 }
1632
1633 if (!rc){
1634 /* volume_info.password freed at unmount */
1635 if (volume_info.password)
1636 pSesInfo->password = volume_info.password;
1637 if (volume_info.username)
1638 strncpy(pSesInfo->userName,
1639 volume_info.username,MAX_USERNAME_SIZE);
1640 if (volume_info.domainname)
1641 strncpy(pSesInfo->domainName,
1642 volume_info.domainname,MAX_USERNAME_SIZE);
1643 pSesInfo->linux_uid = volume_info.linux_uid;
1644 down(&pSesInfo->sesSem);
1645 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1646 up(&pSesInfo->sesSem);
1647 if(!rc)
1648 atomic_inc(&srvTcp->socketUseCount);
1649 } else
1650 if(volume_info.password)
1651 kfree(volume_info.password);
1652 }
1653
1654 /* search for existing tcon to this server share */
1655 if (!rc) {
1656 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1657 cifs_sb->rsize = volume_info.rsize;
1658 else
1659 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1660 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1661 cifs_sb->wsize = volume_info.wsize;
1662 else
1663 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1664 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1665 cifs_sb->rsize = PAGE_CACHE_SIZE;
1666 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1667 }
1668 cifs_sb->mnt_uid = volume_info.linux_uid;
1669 cifs_sb->mnt_gid = volume_info.linux_gid;
1670 cifs_sb->mnt_file_mode = volume_info.file_mode;
1671 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1672 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1673
1674 if(volume_info.noperm)
1675 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1676 if(volume_info.setuids)
1677 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1678 if(volume_info.server_ino)
1679 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001680 if(volume_info.remap)
1681 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 if(volume_info.no_xattr)
1683 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1684 if(volume_info.direct_io) {
1685 cERROR(1,("mounting share using direct i/o"));
1686 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1687 }
1688
1689 tcon =
1690 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1691 volume_info.username);
1692 if (tcon) {
1693 cFYI(1, ("Found match on UNC path "));
1694 /* we can have only one retry value for a connection
1695 to a share so for resources mounted more than once
1696 to the same server share the last value passed in
1697 for the retry flag is used */
1698 tcon->retry = volume_info.retry;
1699 } else {
1700 tcon = tconInfoAlloc();
1701 if (tcon == NULL)
1702 rc = -ENOMEM;
1703 else {
1704 /* check for null share name ie connect to dfs root */
1705
1706 /* BB check if this works for exactly length three strings */
1707 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1708 && (strchr(volume_info.UNC + 3, '/') ==
1709 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001710 rc = connect_to_dfs_path(xid, pSesInfo,
1711 "", cifs_sb->local_nls,
1712 cifs_sb->mnt_cifs_flags &
1713 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 if(volume_info.UNC)
1715 kfree(volume_info.UNC);
1716 FreeXid(xid);
1717 return -ENODEV;
1718 } else {
1719 rc = CIFSTCon(xid, pSesInfo,
1720 volume_info.UNC,
1721 tcon, cifs_sb->local_nls);
1722 cFYI(1, ("CIFS Tcon rc = %d", rc));
1723 }
1724 if (!rc) {
1725 atomic_inc(&pSesInfo->inUse);
1726 tcon->retry = volume_info.retry;
1727 }
1728 }
1729 }
1730 }
1731 if(pSesInfo) {
1732 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1733 sb->s_maxbytes = (u64) 1 << 63;
1734 } else
1735 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1736 }
1737
1738 sb->s_time_gran = 100;
1739
1740/* on error free sesinfo and tcon struct if needed */
1741 if (rc) {
1742 /* if session setup failed, use count is zero but
1743 we still need to free cifsd thread */
1744 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1745 spin_lock(&GlobalMid_Lock);
1746 srvTcp->tcpStatus = CifsExiting;
1747 spin_unlock(&GlobalMid_Lock);
1748 if(srvTcp->tsk)
1749 send_sig(SIGKILL,srvTcp->tsk,1);
1750 }
1751 /* If find_unc succeeded then rc == 0 so we can not end */
1752 if (tcon) /* up accidently freeing someone elses tcon struct */
1753 tconInfoFree(tcon);
1754 if (existingCifsSes == NULL) {
1755 if (pSesInfo) {
1756 if ((pSesInfo->server) &&
1757 (pSesInfo->status == CifsGood)) {
1758 int temp_rc;
1759 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1760 /* if the socketUseCount is now zero */
1761 if((temp_rc == -ESHUTDOWN) &&
1762 (pSesInfo->server->tsk))
1763 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1764 } else
1765 cFYI(1, ("No session or bad tcon"));
1766 sesInfoFree(pSesInfo);
1767 /* pSesInfo = NULL; */
1768 }
1769 }
1770 } else {
1771 atomic_inc(&tcon->useCount);
1772 cifs_sb->tcon = tcon;
1773 tcon->ses = pSesInfo;
1774
1775 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001776 CIFSSMBQFSDeviceInfo(xid, tcon);
1777 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001779 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 if(!volume_info.no_psx_acl) {
1781 if(CIFS_UNIX_POSIX_ACL_CAP &
1782 le64_to_cpu(tcon->fsUnixInfo.Capability))
1783 cFYI(1,("server negotiated posix acl support"));
1784 sb->s_flags |= MS_POSIXACL;
1785 }
1786 }
1787 }
1788 }
1789
1790 /* volume_info.password is freed above when existing session found
1791 (in which case it is not needed anymore) but when new sesion is created
1792 the password ptr is put in the new session structure (in which case the
1793 password will be freed at unmount time) */
1794 if(volume_info.UNC)
1795 kfree(volume_info.UNC);
1796 FreeXid(xid);
1797 return rc;
1798}
1799
1800static int
1801CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1802 char session_key[CIFS_SESSION_KEY_SIZE],
1803 const struct nls_table *nls_codepage)
1804{
1805 struct smb_hdr *smb_buffer;
1806 struct smb_hdr *smb_buffer_response;
1807 SESSION_SETUP_ANDX *pSMB;
1808 SESSION_SETUP_ANDX *pSMBr;
1809 char *bcc_ptr;
1810 char *user;
1811 char *domain;
1812 int rc = 0;
1813 int remaining_words = 0;
1814 int bytes_returned = 0;
1815 int len;
1816 __u32 capabilities;
1817 __u16 count;
1818
1819 cFYI(1, ("In sesssetup "));
1820 if(ses == NULL)
1821 return -EINVAL;
1822 user = ses->userName;
1823 domain = ses->domainName;
1824 smb_buffer = cifs_buf_get();
1825 if (smb_buffer == NULL) {
1826 return -ENOMEM;
1827 }
1828 smb_buffer_response = smb_buffer;
1829 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1830
1831 /* send SMBsessionSetup here */
1832 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1833 NULL /* no tCon exists yet */ , 13 /* wct */ );
1834
1835 pSMB->req_no_secext.AndXCommand = 0xFF;
1836 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1837 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1838
1839 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1840 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1841
1842 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1843 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1844 if (ses->capabilities & CAP_UNICODE) {
1845 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1846 capabilities |= CAP_UNICODE;
1847 }
1848 if (ses->capabilities & CAP_STATUS32) {
1849 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1850 capabilities |= CAP_STATUS32;
1851 }
1852 if (ses->capabilities & CAP_DFS) {
1853 smb_buffer->Flags2 |= SMBFLG2_DFS;
1854 capabilities |= CAP_DFS;
1855 }
1856 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1857
1858 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1859 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1860
1861 pSMB->req_no_secext.CaseSensitivePasswordLength =
1862 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1863 bcc_ptr = pByteArea(smb_buffer);
1864 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1865 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1866 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1867 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1868
1869 if (ses->capabilities & CAP_UNICODE) {
1870 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1871 *bcc_ptr = 0;
1872 bcc_ptr++;
1873 }
1874 if(user == NULL)
1875 bytes_returned = 0; /* skill null user */
1876 else
1877 bytes_returned =
1878 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1879 nls_codepage);
1880 /* convert number of 16 bit words to bytes */
1881 bcc_ptr += 2 * bytes_returned;
1882 bcc_ptr += 2; /* trailing null */
1883 if (domain == NULL)
1884 bytes_returned =
1885 cifs_strtoUCS((wchar_t *) bcc_ptr,
1886 "CIFS_LINUX_DOM", 32, nls_codepage);
1887 else
1888 bytes_returned =
1889 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1890 nls_codepage);
1891 bcc_ptr += 2 * bytes_returned;
1892 bcc_ptr += 2;
1893 bytes_returned =
1894 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1895 32, nls_codepage);
1896 bcc_ptr += 2 * bytes_returned;
1897 bytes_returned =
1898 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1899 32, nls_codepage);
1900 bcc_ptr += 2 * bytes_returned;
1901 bcc_ptr += 2;
1902 bytes_returned =
1903 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1904 64, nls_codepage);
1905 bcc_ptr += 2 * bytes_returned;
1906 bcc_ptr += 2;
1907 } else {
1908 if(user != NULL) {
1909 strncpy(bcc_ptr, user, 200);
1910 bcc_ptr += strnlen(user, 200);
1911 }
1912 *bcc_ptr = 0;
1913 bcc_ptr++;
1914 if (domain == NULL) {
1915 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1916 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1917 } else {
1918 strncpy(bcc_ptr, domain, 64);
1919 bcc_ptr += strnlen(domain, 64);
1920 *bcc_ptr = 0;
1921 bcc_ptr++;
1922 }
1923 strcpy(bcc_ptr, "Linux version ");
1924 bcc_ptr += strlen("Linux version ");
1925 strcpy(bcc_ptr, system_utsname.release);
1926 bcc_ptr += strlen(system_utsname.release) + 1;
1927 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1928 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1929 }
1930 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1931 smb_buffer->smb_buf_length += count;
1932 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
1933
1934 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1935 &bytes_returned, 1);
1936 if (rc) {
1937/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1938 } else if ((smb_buffer_response->WordCount == 3)
1939 || (smb_buffer_response->WordCount == 4)) {
1940 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1941 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1942 if (action & GUEST_LOGIN)
1943 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
1944 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1945 cFYI(1, ("UID = %d ", ses->Suid));
1946 /* response can have either 3 or 4 word count - Samba sends 3 */
1947 bcc_ptr = pByteArea(smb_buffer_response);
1948 if ((pSMBr->resp.hdr.WordCount == 3)
1949 || ((pSMBr->resp.hdr.WordCount == 4)
1950 && (blob_len < pSMBr->resp.ByteCount))) {
1951 if (pSMBr->resp.hdr.WordCount == 4)
1952 bcc_ptr += blob_len;
1953
1954 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1955 if ((long) (bcc_ptr) % 2) {
1956 remaining_words =
1957 (BCC(smb_buffer_response) - 1) /2;
1958 bcc_ptr++; /* Unicode strings must be word aligned */
1959 } else {
1960 remaining_words =
1961 BCC(smb_buffer_response) / 2;
1962 }
1963 len =
1964 UniStrnlen((wchar_t *) bcc_ptr,
1965 remaining_words - 1);
1966/* We look for obvious messed up bcc or strings in response so we do not go off
1967 the end since (at least) WIN2K and Windows XP have a major bug in not null
1968 terminating last Unicode string in response */
Pekka Enberge915fc42005-09-06 15:18:35 -07001969 ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07001970 if(ses->serverOS == NULL)
1971 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 cifs_strfromUCS_le(ses->serverOS,
1973 (wchar_t *)bcc_ptr, len,nls_codepage);
1974 bcc_ptr += 2 * (len + 1);
1975 remaining_words -= len + 1;
1976 ses->serverOS[2 * len] = 0;
1977 ses->serverOS[1 + (2 * len)] = 0;
1978 if (remaining_words > 0) {
1979 len = UniStrnlen((wchar_t *)bcc_ptr,
1980 remaining_words-1);
Pekka Enberge915fc42005-09-06 15:18:35 -07001981 ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07001982 if(ses->serverNOS == NULL)
1983 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 cifs_strfromUCS_le(ses->serverNOS,
1985 (wchar_t *)bcc_ptr,len,nls_codepage);
1986 bcc_ptr += 2 * (len + 1);
1987 ses->serverNOS[2 * len] = 0;
1988 ses->serverNOS[1 + (2 * len)] = 0;
1989 if(strncmp(ses->serverNOS,
1990 "NT LAN Manager 4",16) == 0) {
1991 cFYI(1,("NT4 server"));
1992 ses->flags |= CIFS_SES_NT4;
1993 }
1994 remaining_words -= len + 1;
1995 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07001996 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1998 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07001999 kzalloc(2*(len+1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002000 if(ses->serverDomain == NULL)
2001 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 cifs_strfromUCS_le(ses->serverDomain,
2003 (wchar_t *)bcc_ptr,len,nls_codepage);
2004 bcc_ptr += 2 * (len + 1);
2005 ses->serverDomain[2*len] = 0;
2006 ses->serverDomain[1+(2*len)] = 0;
2007 } /* else no more room so create dummy domain string */
2008 else
Steve French433dc242005-04-28 22:41:08 -07002009 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002010 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002012 /* if these kcallocs fail not much we
2013 can do, but better to not fail the
2014 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002016 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002018 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 }
2020 } else { /* ASCII */
2021 len = strnlen(bcc_ptr, 1024);
2022 if (((long) bcc_ptr + len) - (long)
2023 pByteArea(smb_buffer_response)
2024 <= BCC(smb_buffer_response)) {
Pekka Enberge915fc42005-09-06 15:18:35 -07002025 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002026 if(ses->serverOS == NULL)
2027 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 strncpy(ses->serverOS,bcc_ptr, len);
2029
2030 bcc_ptr += len;
2031 bcc_ptr[0] = 0; /* null terminate the string */
2032 bcc_ptr++;
2033
2034 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002035 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002036 if(ses->serverNOS == NULL)
2037 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 strncpy(ses->serverNOS, bcc_ptr, len);
2039 bcc_ptr += len;
2040 bcc_ptr[0] = 0;
2041 bcc_ptr++;
2042
2043 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002044 ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002045 if(ses->serverDomain == NULL)
2046 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 strncpy(ses->serverDomain, bcc_ptr, len);
2048 bcc_ptr += len;
2049 bcc_ptr[0] = 0;
2050 bcc_ptr++;
2051 } else
2052 cFYI(1,
2053 ("Variable field of length %d extends beyond end of smb ",
2054 len));
2055 }
2056 } else {
2057 cERROR(1,
2058 (" Security Blob Length extends beyond end of SMB"));
2059 }
2060 } else {
2061 cERROR(1,
2062 (" Invalid Word count %d: ",
2063 smb_buffer_response->WordCount));
2064 rc = -EIO;
2065 }
Steve French433dc242005-04-28 22:41:08 -07002066sesssetup_nomem: /* do not return an error on nomem for the info strings,
2067 since that could make reconnection harder, and
2068 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 if (smb_buffer)
2070 cifs_buf_release(smb_buffer);
2071
2072 return rc;
2073}
2074
2075static int
2076CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2077 char *SecurityBlob,int SecurityBlobLength,
2078 const struct nls_table *nls_codepage)
2079{
2080 struct smb_hdr *smb_buffer;
2081 struct smb_hdr *smb_buffer_response;
2082 SESSION_SETUP_ANDX *pSMB;
2083 SESSION_SETUP_ANDX *pSMBr;
2084 char *bcc_ptr;
2085 char *user;
2086 char *domain;
2087 int rc = 0;
2088 int remaining_words = 0;
2089 int bytes_returned = 0;
2090 int len;
2091 __u32 capabilities;
2092 __u16 count;
2093
2094 cFYI(1, ("In spnego sesssetup "));
2095 if(ses == NULL)
2096 return -EINVAL;
2097 user = ses->userName;
2098 domain = ses->domainName;
2099
2100 smb_buffer = cifs_buf_get();
2101 if (smb_buffer == NULL) {
2102 return -ENOMEM;
2103 }
2104 smb_buffer_response = smb_buffer;
2105 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2106
2107 /* send SMBsessionSetup here */
2108 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2109 NULL /* no tCon exists yet */ , 12 /* wct */ );
2110 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2111 pSMB->req.AndXCommand = 0xFF;
2112 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2113 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2114
2115 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2116 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2117
2118 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2119 CAP_EXTENDED_SECURITY;
2120 if (ses->capabilities & CAP_UNICODE) {
2121 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2122 capabilities |= CAP_UNICODE;
2123 }
2124 if (ses->capabilities & CAP_STATUS32) {
2125 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2126 capabilities |= CAP_STATUS32;
2127 }
2128 if (ses->capabilities & CAP_DFS) {
2129 smb_buffer->Flags2 |= SMBFLG2_DFS;
2130 capabilities |= CAP_DFS;
2131 }
2132 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2133
2134 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2135 bcc_ptr = pByteArea(smb_buffer);
2136 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2137 bcc_ptr += SecurityBlobLength;
2138
2139 if (ses->capabilities & CAP_UNICODE) {
2140 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2141 *bcc_ptr = 0;
2142 bcc_ptr++;
2143 }
2144 bytes_returned =
2145 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2146 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2147 bcc_ptr += 2; /* trailing null */
2148 if (domain == NULL)
2149 bytes_returned =
2150 cifs_strtoUCS((wchar_t *) bcc_ptr,
2151 "CIFS_LINUX_DOM", 32, nls_codepage);
2152 else
2153 bytes_returned =
2154 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2155 nls_codepage);
2156 bcc_ptr += 2 * bytes_returned;
2157 bcc_ptr += 2;
2158 bytes_returned =
2159 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2160 32, nls_codepage);
2161 bcc_ptr += 2 * bytes_returned;
2162 bytes_returned =
2163 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2164 nls_codepage);
2165 bcc_ptr += 2 * bytes_returned;
2166 bcc_ptr += 2;
2167 bytes_returned =
2168 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2169 64, nls_codepage);
2170 bcc_ptr += 2 * bytes_returned;
2171 bcc_ptr += 2;
2172 } else {
2173 strncpy(bcc_ptr, user, 200);
2174 bcc_ptr += strnlen(user, 200);
2175 *bcc_ptr = 0;
2176 bcc_ptr++;
2177 if (domain == NULL) {
2178 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2179 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2180 } else {
2181 strncpy(bcc_ptr, domain, 64);
2182 bcc_ptr += strnlen(domain, 64);
2183 *bcc_ptr = 0;
2184 bcc_ptr++;
2185 }
2186 strcpy(bcc_ptr, "Linux version ");
2187 bcc_ptr += strlen("Linux version ");
2188 strcpy(bcc_ptr, system_utsname.release);
2189 bcc_ptr += strlen(system_utsname.release) + 1;
2190 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2191 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2192 }
2193 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2194 smb_buffer->smb_buf_length += count;
2195 pSMB->req.ByteCount = cpu_to_le16(count);
2196
2197 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2198 &bytes_returned, 1);
2199 if (rc) {
2200/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2201 } else if ((smb_buffer_response->WordCount == 3)
2202 || (smb_buffer_response->WordCount == 4)) {
2203 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2204 __u16 blob_len =
2205 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2206 if (action & GUEST_LOGIN)
2207 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2208 if (ses) {
2209 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2210 cFYI(1, ("UID = %d ", ses->Suid));
2211 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2212
2213 /* BB Fix below to make endian neutral !! */
2214
2215 if ((pSMBr->resp.hdr.WordCount == 3)
2216 || ((pSMBr->resp.hdr.WordCount == 4)
2217 && (blob_len <
2218 pSMBr->resp.ByteCount))) {
2219 if (pSMBr->resp.hdr.WordCount == 4) {
2220 bcc_ptr +=
2221 blob_len;
2222 cFYI(1,
2223 ("Security Blob Length %d ",
2224 blob_len));
2225 }
2226
2227 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2228 if ((long) (bcc_ptr) % 2) {
2229 remaining_words =
2230 (BCC(smb_buffer_response)
2231 - 1) / 2;
2232 bcc_ptr++; /* Unicode strings must be word aligned */
2233 } else {
2234 remaining_words =
2235 BCC
2236 (smb_buffer_response) / 2;
2237 }
2238 len =
2239 UniStrnlen((wchar_t *) bcc_ptr,
2240 remaining_words - 1);
2241/* We look for obvious messed up bcc or strings in response so we do not go off
2242 the end since (at least) WIN2K and Windows XP have a major bug in not null
2243 terminating last Unicode string in response */
2244 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002245 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 cifs_strfromUCS_le(ses->serverOS,
2247 (wchar_t *)
2248 bcc_ptr, len,
2249 nls_codepage);
2250 bcc_ptr += 2 * (len + 1);
2251 remaining_words -= len + 1;
2252 ses->serverOS[2 * len] = 0;
2253 ses->serverOS[1 + (2 * len)] = 0;
2254 if (remaining_words > 0) {
2255 len = UniStrnlen((wchar_t *)bcc_ptr,
2256 remaining_words
2257 - 1);
2258 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002259 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 GFP_KERNEL);
2261 cifs_strfromUCS_le(ses->serverNOS,
2262 (wchar_t *)bcc_ptr,
2263 len,
2264 nls_codepage);
2265 bcc_ptr += 2 * (len + 1);
2266 ses->serverNOS[2 * len] = 0;
2267 ses->serverNOS[1 + (2 * len)] = 0;
2268 remaining_words -= len + 1;
2269 if (remaining_words > 0) {
2270 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2271 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Pekka Enberge915fc42005-09-06 15:18:35 -07002272 ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 cifs_strfromUCS_le(ses->serverDomain,
2274 (wchar_t *)bcc_ptr,
2275 len,
2276 nls_codepage);
2277 bcc_ptr += 2*(len+1);
2278 ses->serverDomain[2*len] = 0;
2279 ses->serverDomain[1+(2*len)] = 0;
2280 } /* else no more room so create dummy domain string */
2281 else
2282 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002283 kzalloc(2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 } else { /* no room so create dummy domain and NOS string */
Pekka Enberge915fc42005-09-06 15:18:35 -07002285 ses->serverDomain = kzalloc(2, GFP_KERNEL);
2286 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 }
2288 } else { /* ASCII */
2289
2290 len = strnlen(bcc_ptr, 1024);
2291 if (((long) bcc_ptr + len) - (long)
2292 pByteArea(smb_buffer_response)
2293 <= BCC(smb_buffer_response)) {
Pekka Enberge915fc42005-09-06 15:18:35 -07002294 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 strncpy(ses->serverOS, bcc_ptr, len);
2296
2297 bcc_ptr += len;
2298 bcc_ptr[0] = 0; /* null terminate the string */
2299 bcc_ptr++;
2300
2301 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002302 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 strncpy(ses->serverNOS, bcc_ptr, len);
2304 bcc_ptr += len;
2305 bcc_ptr[0] = 0;
2306 bcc_ptr++;
2307
2308 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002309 ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 strncpy(ses->serverDomain, bcc_ptr, len);
2311 bcc_ptr += len;
2312 bcc_ptr[0] = 0;
2313 bcc_ptr++;
2314 } else
2315 cFYI(1,
2316 ("Variable field of length %d extends beyond end of smb ",
2317 len));
2318 }
2319 } else {
2320 cERROR(1,
2321 (" Security Blob Length extends beyond end of SMB"));
2322 }
2323 } else {
2324 cERROR(1, ("No session structure passed in."));
2325 }
2326 } else {
2327 cERROR(1,
2328 (" Invalid Word count %d: ",
2329 smb_buffer_response->WordCount));
2330 rc = -EIO;
2331 }
2332
2333 if (smb_buffer)
2334 cifs_buf_release(smb_buffer);
2335
2336 return rc;
2337}
2338
2339static int
2340CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2341 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2342 const struct nls_table *nls_codepage)
2343{
2344 struct smb_hdr *smb_buffer;
2345 struct smb_hdr *smb_buffer_response;
2346 SESSION_SETUP_ANDX *pSMB;
2347 SESSION_SETUP_ANDX *pSMBr;
2348 char *bcc_ptr;
2349 char *domain;
2350 int rc = 0;
2351 int remaining_words = 0;
2352 int bytes_returned = 0;
2353 int len;
2354 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2355 PNEGOTIATE_MESSAGE SecurityBlob;
2356 PCHALLENGE_MESSAGE SecurityBlob2;
2357 __u32 negotiate_flags, capabilities;
2358 __u16 count;
2359
2360 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2361 if(ses == NULL)
2362 return -EINVAL;
2363 domain = ses->domainName;
2364 *pNTLMv2_flag = FALSE;
2365 smb_buffer = cifs_buf_get();
2366 if (smb_buffer == NULL) {
2367 return -ENOMEM;
2368 }
2369 smb_buffer_response = smb_buffer;
2370 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2371 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2372
2373 /* send SMBsessionSetup here */
2374 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2375 NULL /* no tCon exists yet */ , 12 /* wct */ );
2376 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2377 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2378
2379 pSMB->req.AndXCommand = 0xFF;
2380 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2381 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2382
2383 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2384 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2385
2386 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2387 CAP_EXTENDED_SECURITY;
2388 if (ses->capabilities & CAP_UNICODE) {
2389 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2390 capabilities |= CAP_UNICODE;
2391 }
2392 if (ses->capabilities & CAP_STATUS32) {
2393 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2394 capabilities |= CAP_STATUS32;
2395 }
2396 if (ses->capabilities & CAP_DFS) {
2397 smb_buffer->Flags2 |= SMBFLG2_DFS;
2398 capabilities |= CAP_DFS;
2399 }
2400 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2401
2402 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2403 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2404 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2405 SecurityBlob->MessageType = NtLmNegotiate;
2406 negotiate_flags =
2407 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2408 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2409 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2410 if(sign_CIFS_PDUs)
2411 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2412 if(ntlmv2_support)
2413 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2414 /* setup pointers to domain name and workstation name */
2415 bcc_ptr += SecurityBlobLength;
2416
2417 SecurityBlob->WorkstationName.Buffer = 0;
2418 SecurityBlob->WorkstationName.Length = 0;
2419 SecurityBlob->WorkstationName.MaximumLength = 0;
2420
2421 if (domain == NULL) {
2422 SecurityBlob->DomainName.Buffer = 0;
2423 SecurityBlob->DomainName.Length = 0;
2424 SecurityBlob->DomainName.MaximumLength = 0;
2425 } else {
2426 __u16 len;
2427 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2428 strncpy(bcc_ptr, domain, 63);
2429 len = strnlen(domain, 64);
2430 SecurityBlob->DomainName.MaximumLength =
2431 cpu_to_le16(len);
2432 SecurityBlob->DomainName.Buffer =
2433 cpu_to_le32((long) &SecurityBlob->
2434 DomainString -
2435 (long) &SecurityBlob->Signature);
2436 bcc_ptr += len;
2437 SecurityBlobLength += len;
2438 SecurityBlob->DomainName.Length =
2439 cpu_to_le16(len);
2440 }
2441 if (ses->capabilities & CAP_UNICODE) {
2442 if ((long) bcc_ptr % 2) {
2443 *bcc_ptr = 0;
2444 bcc_ptr++;
2445 }
2446
2447 bytes_returned =
2448 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2449 32, nls_codepage);
2450 bcc_ptr += 2 * bytes_returned;
2451 bytes_returned =
2452 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2453 nls_codepage);
2454 bcc_ptr += 2 * bytes_returned;
2455 bcc_ptr += 2; /* null terminate Linux version */
2456 bytes_returned =
2457 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2458 64, nls_codepage);
2459 bcc_ptr += 2 * bytes_returned;
2460 *(bcc_ptr + 1) = 0;
2461 *(bcc_ptr + 2) = 0;
2462 bcc_ptr += 2; /* null terminate network opsys string */
2463 *(bcc_ptr + 1) = 0;
2464 *(bcc_ptr + 2) = 0;
2465 bcc_ptr += 2; /* null domain */
2466 } else { /* ASCII */
2467 strcpy(bcc_ptr, "Linux version ");
2468 bcc_ptr += strlen("Linux version ");
2469 strcpy(bcc_ptr, system_utsname.release);
2470 bcc_ptr += strlen(system_utsname.release) + 1;
2471 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2472 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2473 bcc_ptr++; /* empty domain field */
2474 *bcc_ptr = 0;
2475 }
2476 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2477 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2478 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2479 smb_buffer->smb_buf_length += count;
2480 pSMB->req.ByteCount = cpu_to_le16(count);
2481
2482 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2483 &bytes_returned, 1);
2484
2485 if (smb_buffer_response->Status.CifsError ==
2486 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2487 rc = 0;
2488
2489 if (rc) {
2490/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2491 } else if ((smb_buffer_response->WordCount == 3)
2492 || (smb_buffer_response->WordCount == 4)) {
2493 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2494 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2495
2496 if (action & GUEST_LOGIN)
2497 cFYI(1, (" Guest login"));
2498 /* Do we want to set anything in SesInfo struct when guest login? */
2499
2500 bcc_ptr = pByteArea(smb_buffer_response);
2501 /* response can have either 3 or 4 word count - Samba sends 3 */
2502
2503 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2504 if (SecurityBlob2->MessageType != NtLmChallenge) {
2505 cFYI(1,
2506 ("Unexpected NTLMSSP message type received %d",
2507 SecurityBlob2->MessageType));
2508 } else if (ses) {
2509 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2510 cFYI(1, ("UID = %d ", ses->Suid));
2511 if ((pSMBr->resp.hdr.WordCount == 3)
2512 || ((pSMBr->resp.hdr.WordCount == 4)
2513 && (blob_len <
2514 pSMBr->resp.ByteCount))) {
2515
2516 if (pSMBr->resp.hdr.WordCount == 4) {
2517 bcc_ptr += blob_len;
2518 cFYI(1,
2519 ("Security Blob Length %d ",
2520 blob_len));
2521 }
2522
2523 cFYI(1, ("NTLMSSP Challenge rcvd "));
2524
2525 memcpy(ses->server->cryptKey,
2526 SecurityBlob2->Challenge,
2527 CIFS_CRYPTO_KEY_SIZE);
2528 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2529 *pNTLMv2_flag = TRUE;
2530
2531 if((SecurityBlob2->NegotiateFlags &
2532 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2533 || (sign_CIFS_PDUs > 1))
2534 ses->server->secMode |=
2535 SECMODE_SIGN_REQUIRED;
2536 if ((SecurityBlob2->NegotiateFlags &
2537 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2538 ses->server->secMode |=
2539 SECMODE_SIGN_ENABLED;
2540
2541 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2542 if ((long) (bcc_ptr) % 2) {
2543 remaining_words =
2544 (BCC(smb_buffer_response)
2545 - 1) / 2;
2546 bcc_ptr++; /* Unicode strings must be word aligned */
2547 } else {
2548 remaining_words =
2549 BCC
2550 (smb_buffer_response) / 2;
2551 }
2552 len =
2553 UniStrnlen((wchar_t *) bcc_ptr,
2554 remaining_words - 1);
2555/* We look for obvious messed up bcc or strings in response so we do not go off
2556 the end since (at least) WIN2K and Windows XP have a major bug in not null
2557 terminating last Unicode string in response */
2558 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002559 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 cifs_strfromUCS_le(ses->serverOS,
2561 (wchar_t *)
2562 bcc_ptr, len,
2563 nls_codepage);
2564 bcc_ptr += 2 * (len + 1);
2565 remaining_words -= len + 1;
2566 ses->serverOS[2 * len] = 0;
2567 ses->serverOS[1 + (2 * len)] = 0;
2568 if (remaining_words > 0) {
2569 len = UniStrnlen((wchar_t *)
2570 bcc_ptr,
2571 remaining_words
2572 - 1);
2573 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002574 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 GFP_KERNEL);
2576 cifs_strfromUCS_le(ses->
2577 serverNOS,
2578 (wchar_t *)
2579 bcc_ptr,
2580 len,
2581 nls_codepage);
2582 bcc_ptr += 2 * (len + 1);
2583 ses->serverNOS[2 * len] = 0;
2584 ses->serverNOS[1 +
2585 (2 * len)] = 0;
2586 remaining_words -= len + 1;
2587 if (remaining_words > 0) {
2588 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2589 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2590 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002591 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 (len +
2593 1),
2594 GFP_KERNEL);
2595 cifs_strfromUCS_le
2596 (ses->
2597 serverDomain,
2598 (wchar_t *)
2599 bcc_ptr, len,
2600 nls_codepage);
2601 bcc_ptr +=
2602 2 * (len + 1);
2603 ses->
2604 serverDomain[2
2605 * len]
2606 = 0;
2607 ses->
2608 serverDomain[1
2609 +
2610 (2
2611 *
2612 len)]
2613 = 0;
2614 } /* else no more room so create dummy domain string */
2615 else
2616 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002617 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 GFP_KERNEL);
2619 } else { /* no room so create dummy domain and NOS string */
2620 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002621 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002623 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 }
2625 } else { /* ASCII */
2626 len = strnlen(bcc_ptr, 1024);
2627 if (((long) bcc_ptr + len) - (long)
2628 pByteArea(smb_buffer_response)
2629 <= BCC(smb_buffer_response)) {
2630 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002631 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 GFP_KERNEL);
2633 strncpy(ses->serverOS,
2634 bcc_ptr, len);
2635
2636 bcc_ptr += len;
2637 bcc_ptr[0] = 0; /* null terminate string */
2638 bcc_ptr++;
2639
2640 len = strnlen(bcc_ptr, 1024);
2641 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002642 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 GFP_KERNEL);
2644 strncpy(ses->serverNOS, bcc_ptr, len);
2645 bcc_ptr += len;
2646 bcc_ptr[0] = 0;
2647 bcc_ptr++;
2648
2649 len = strnlen(bcc_ptr, 1024);
2650 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002651 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 GFP_KERNEL);
2653 strncpy(ses->serverDomain, bcc_ptr, len);
2654 bcc_ptr += len;
2655 bcc_ptr[0] = 0;
2656 bcc_ptr++;
2657 } else
2658 cFYI(1,
2659 ("Variable field of length %d extends beyond end of smb ",
2660 len));
2661 }
2662 } else {
2663 cERROR(1,
2664 (" Security Blob Length extends beyond end of SMB"));
2665 }
2666 } else {
2667 cERROR(1, ("No session structure passed in."));
2668 }
2669 } else {
2670 cERROR(1,
2671 (" Invalid Word count %d: ",
2672 smb_buffer_response->WordCount));
2673 rc = -EIO;
2674 }
2675
2676 if (smb_buffer)
2677 cifs_buf_release(smb_buffer);
2678
2679 return rc;
2680}
2681static int
2682CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2683 char *ntlm_session_key, int ntlmv2_flag,
2684 const struct nls_table *nls_codepage)
2685{
2686 struct smb_hdr *smb_buffer;
2687 struct smb_hdr *smb_buffer_response;
2688 SESSION_SETUP_ANDX *pSMB;
2689 SESSION_SETUP_ANDX *pSMBr;
2690 char *bcc_ptr;
2691 char *user;
2692 char *domain;
2693 int rc = 0;
2694 int remaining_words = 0;
2695 int bytes_returned = 0;
2696 int len;
2697 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2698 PAUTHENTICATE_MESSAGE SecurityBlob;
2699 __u32 negotiate_flags, capabilities;
2700 __u16 count;
2701
2702 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2703 if(ses == NULL)
2704 return -EINVAL;
2705 user = ses->userName;
2706 domain = ses->domainName;
2707 smb_buffer = cifs_buf_get();
2708 if (smb_buffer == NULL) {
2709 return -ENOMEM;
2710 }
2711 smb_buffer_response = smb_buffer;
2712 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2713 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2714
2715 /* send SMBsessionSetup here */
2716 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2717 NULL /* no tCon exists yet */ , 12 /* wct */ );
2718 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2719 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2720 pSMB->req.AndXCommand = 0xFF;
2721 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2722 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2723
2724 pSMB->req.hdr.Uid = ses->Suid;
2725
2726 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2727 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2728
2729 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2730 CAP_EXTENDED_SECURITY;
2731 if (ses->capabilities & CAP_UNICODE) {
2732 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2733 capabilities |= CAP_UNICODE;
2734 }
2735 if (ses->capabilities & CAP_STATUS32) {
2736 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2737 capabilities |= CAP_STATUS32;
2738 }
2739 if (ses->capabilities & CAP_DFS) {
2740 smb_buffer->Flags2 |= SMBFLG2_DFS;
2741 capabilities |= CAP_DFS;
2742 }
2743 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2744
2745 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2746 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2747 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2748 SecurityBlob->MessageType = NtLmAuthenticate;
2749 bcc_ptr += SecurityBlobLength;
2750 negotiate_flags =
2751 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2752 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2753 0x80000000 | NTLMSSP_NEGOTIATE_128;
2754 if(sign_CIFS_PDUs)
2755 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2756 if(ntlmv2_flag)
2757 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2758
2759/* setup pointers to domain name and workstation name */
2760
2761 SecurityBlob->WorkstationName.Buffer = 0;
2762 SecurityBlob->WorkstationName.Length = 0;
2763 SecurityBlob->WorkstationName.MaximumLength = 0;
2764 SecurityBlob->SessionKey.Length = 0;
2765 SecurityBlob->SessionKey.MaximumLength = 0;
2766 SecurityBlob->SessionKey.Buffer = 0;
2767
2768 SecurityBlob->LmChallengeResponse.Length = 0;
2769 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2770 SecurityBlob->LmChallengeResponse.Buffer = 0;
2771
2772 SecurityBlob->NtChallengeResponse.Length =
2773 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2774 SecurityBlob->NtChallengeResponse.MaximumLength =
2775 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2776 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2777 SecurityBlob->NtChallengeResponse.Buffer =
2778 cpu_to_le32(SecurityBlobLength);
2779 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2780 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2781
2782 if (ses->capabilities & CAP_UNICODE) {
2783 if (domain == NULL) {
2784 SecurityBlob->DomainName.Buffer = 0;
2785 SecurityBlob->DomainName.Length = 0;
2786 SecurityBlob->DomainName.MaximumLength = 0;
2787 } else {
2788 __u16 len =
2789 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2790 nls_codepage);
2791 len *= 2;
2792 SecurityBlob->DomainName.MaximumLength =
2793 cpu_to_le16(len);
2794 SecurityBlob->DomainName.Buffer =
2795 cpu_to_le32(SecurityBlobLength);
2796 bcc_ptr += len;
2797 SecurityBlobLength += len;
2798 SecurityBlob->DomainName.Length =
2799 cpu_to_le16(len);
2800 }
2801 if (user == NULL) {
2802 SecurityBlob->UserName.Buffer = 0;
2803 SecurityBlob->UserName.Length = 0;
2804 SecurityBlob->UserName.MaximumLength = 0;
2805 } else {
2806 __u16 len =
2807 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2808 nls_codepage);
2809 len *= 2;
2810 SecurityBlob->UserName.MaximumLength =
2811 cpu_to_le16(len);
2812 SecurityBlob->UserName.Buffer =
2813 cpu_to_le32(SecurityBlobLength);
2814 bcc_ptr += len;
2815 SecurityBlobLength += len;
2816 SecurityBlob->UserName.Length =
2817 cpu_to_le16(len);
2818 }
2819
2820 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2821 SecurityBlob->WorkstationName.Length *= 2;
2822 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2823 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2824 bcc_ptr += SecurityBlob->WorkstationName.Length;
2825 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2826 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2827
2828 if ((long) bcc_ptr % 2) {
2829 *bcc_ptr = 0;
2830 bcc_ptr++;
2831 }
2832 bytes_returned =
2833 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2834 32, nls_codepage);
2835 bcc_ptr += 2 * bytes_returned;
2836 bytes_returned =
2837 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2838 nls_codepage);
2839 bcc_ptr += 2 * bytes_returned;
2840 bcc_ptr += 2; /* null term version string */
2841 bytes_returned =
2842 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2843 64, nls_codepage);
2844 bcc_ptr += 2 * bytes_returned;
2845 *(bcc_ptr + 1) = 0;
2846 *(bcc_ptr + 2) = 0;
2847 bcc_ptr += 2; /* null terminate network opsys string */
2848 *(bcc_ptr + 1) = 0;
2849 *(bcc_ptr + 2) = 0;
2850 bcc_ptr += 2; /* null domain */
2851 } else { /* ASCII */
2852 if (domain == NULL) {
2853 SecurityBlob->DomainName.Buffer = 0;
2854 SecurityBlob->DomainName.Length = 0;
2855 SecurityBlob->DomainName.MaximumLength = 0;
2856 } else {
2857 __u16 len;
2858 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2859 strncpy(bcc_ptr, domain, 63);
2860 len = strnlen(domain, 64);
2861 SecurityBlob->DomainName.MaximumLength =
2862 cpu_to_le16(len);
2863 SecurityBlob->DomainName.Buffer =
2864 cpu_to_le32(SecurityBlobLength);
2865 bcc_ptr += len;
2866 SecurityBlobLength += len;
2867 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2868 }
2869 if (user == NULL) {
2870 SecurityBlob->UserName.Buffer = 0;
2871 SecurityBlob->UserName.Length = 0;
2872 SecurityBlob->UserName.MaximumLength = 0;
2873 } else {
2874 __u16 len;
2875 strncpy(bcc_ptr, user, 63);
2876 len = strnlen(user, 64);
2877 SecurityBlob->UserName.MaximumLength =
2878 cpu_to_le16(len);
2879 SecurityBlob->UserName.Buffer =
2880 cpu_to_le32(SecurityBlobLength);
2881 bcc_ptr += len;
2882 SecurityBlobLength += len;
2883 SecurityBlob->UserName.Length = cpu_to_le16(len);
2884 }
2885 /* BB fill in our workstation name if known BB */
2886
2887 strcpy(bcc_ptr, "Linux version ");
2888 bcc_ptr += strlen("Linux version ");
2889 strcpy(bcc_ptr, system_utsname.release);
2890 bcc_ptr += strlen(system_utsname.release) + 1;
2891 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2892 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2893 bcc_ptr++; /* null domain */
2894 *bcc_ptr = 0;
2895 }
2896 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2897 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2898 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2899 smb_buffer->smb_buf_length += count;
2900 pSMB->req.ByteCount = cpu_to_le16(count);
2901
2902 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2903 &bytes_returned, 1);
2904 if (rc) {
2905/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2906 } else if ((smb_buffer_response->WordCount == 3)
2907 || (smb_buffer_response->WordCount == 4)) {
2908 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2909 __u16 blob_len =
2910 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2911 if (action & GUEST_LOGIN)
2912 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2913/* if(SecurityBlob2->MessageType != NtLm??){
2914 cFYI("Unexpected message type on auth response is %d "));
2915 } */
2916 if (ses) {
2917 cFYI(1,
2918 ("Does UID on challenge %d match auth response UID %d ",
2919 ses->Suid, smb_buffer_response->Uid));
2920 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2921 bcc_ptr = pByteArea(smb_buffer_response);
2922 /* response can have either 3 or 4 word count - Samba sends 3 */
2923 if ((pSMBr->resp.hdr.WordCount == 3)
2924 || ((pSMBr->resp.hdr.WordCount == 4)
2925 && (blob_len <
2926 pSMBr->resp.ByteCount))) {
2927 if (pSMBr->resp.hdr.WordCount == 4) {
2928 bcc_ptr +=
2929 blob_len;
2930 cFYI(1,
2931 ("Security Blob Length %d ",
2932 blob_len));
2933 }
2934
2935 cFYI(1,
2936 ("NTLMSSP response to Authenticate "));
2937
2938 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2939 if ((long) (bcc_ptr) % 2) {
2940 remaining_words =
2941 (BCC(smb_buffer_response)
2942 - 1) / 2;
2943 bcc_ptr++; /* Unicode strings must be word aligned */
2944 } else {
2945 remaining_words = BCC(smb_buffer_response) / 2;
2946 }
2947 len =
2948 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2949/* We look for obvious messed up bcc or strings in response so we do not go off
2950 the end since (at least) WIN2K and Windows XP have a major bug in not null
2951 terminating last Unicode string in response */
2952 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002953 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 cifs_strfromUCS_le(ses->serverOS,
2955 (wchar_t *)
2956 bcc_ptr, len,
2957 nls_codepage);
2958 bcc_ptr += 2 * (len + 1);
2959 remaining_words -= len + 1;
2960 ses->serverOS[2 * len] = 0;
2961 ses->serverOS[1 + (2 * len)] = 0;
2962 if (remaining_words > 0) {
2963 len = UniStrnlen((wchar_t *)
2964 bcc_ptr,
2965 remaining_words
2966 - 1);
2967 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002968 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 GFP_KERNEL);
2970 cifs_strfromUCS_le(ses->
2971 serverNOS,
2972 (wchar_t *)
2973 bcc_ptr,
2974 len,
2975 nls_codepage);
2976 bcc_ptr += 2 * (len + 1);
2977 ses->serverNOS[2 * len] = 0;
2978 ses->serverNOS[1+(2*len)] = 0;
2979 remaining_words -= len + 1;
2980 if (remaining_words > 0) {
2981 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2982 /* last string not always null terminated (e.g. for Windows XP & 2000) */
2983 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002984 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 (len +
2986 1),
2987 GFP_KERNEL);
2988 cifs_strfromUCS_le
2989 (ses->
2990 serverDomain,
2991 (wchar_t *)
2992 bcc_ptr, len,
2993 nls_codepage);
2994 bcc_ptr +=
2995 2 * (len + 1);
2996 ses->
2997 serverDomain[2
2998 * len]
2999 = 0;
3000 ses->
3001 serverDomain[1
3002 +
3003 (2
3004 *
3005 len)]
3006 = 0;
3007 } /* else no more room so create dummy domain string */
3008 else
Pekka Enberge915fc42005-09-06 15:18:35 -07003009 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 } else { /* no room so create dummy domain and NOS string */
Pekka Enberge915fc42005-09-06 15:18:35 -07003011 ses->serverDomain = kzalloc(2, GFP_KERNEL);
3012 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 }
3014 } else { /* ASCII */
3015 len = strnlen(bcc_ptr, 1024);
3016 if (((long) bcc_ptr + len) -
3017 (long) pByteArea(smb_buffer_response)
3018 <= BCC(smb_buffer_response)) {
Pekka Enberge915fc42005-09-06 15:18:35 -07003019 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 strncpy(ses->serverOS,bcc_ptr, len);
3021
3022 bcc_ptr += len;
3023 bcc_ptr[0] = 0; /* null terminate the string */
3024 bcc_ptr++;
3025
3026 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07003027 ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 strncpy(ses->serverNOS, bcc_ptr, len);
3029 bcc_ptr += len;
3030 bcc_ptr[0] = 0;
3031 bcc_ptr++;
3032
3033 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07003034 ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 strncpy(ses->serverDomain, bcc_ptr, len);
3036 bcc_ptr += len;
3037 bcc_ptr[0] = 0;
3038 bcc_ptr++;
3039 } else
3040 cFYI(1,
3041 ("Variable field of length %d extends beyond end of smb ",
3042 len));
3043 }
3044 } else {
3045 cERROR(1,
3046 (" Security Blob Length extends beyond end of SMB"));
3047 }
3048 } else {
3049 cERROR(1, ("No session structure passed in."));
3050 }
3051 } else {
3052 cERROR(1,
3053 (" Invalid Word count %d: ",
3054 smb_buffer_response->WordCount));
3055 rc = -EIO;
3056 }
3057
3058 if (smb_buffer)
3059 cifs_buf_release(smb_buffer);
3060
3061 return rc;
3062}
3063
3064int
3065CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3066 const char *tree, struct cifsTconInfo *tcon,
3067 const struct nls_table *nls_codepage)
3068{
3069 struct smb_hdr *smb_buffer;
3070 struct smb_hdr *smb_buffer_response;
3071 TCONX_REQ *pSMB;
3072 TCONX_RSP *pSMBr;
3073 unsigned char *bcc_ptr;
3074 int rc = 0;
3075 int length;
3076 __u16 count;
3077
3078 if (ses == NULL)
3079 return -EIO;
3080
3081 smb_buffer = cifs_buf_get();
3082 if (smb_buffer == NULL) {
3083 return -ENOMEM;
3084 }
3085 smb_buffer_response = smb_buffer;
3086
3087 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3088 NULL /*no tid */ , 4 /*wct */ );
3089 smb_buffer->Uid = ses->Suid;
3090 pSMB = (TCONX_REQ *) smb_buffer;
3091 pSMBr = (TCONX_RSP *) smb_buffer_response;
3092
3093 pSMB->AndXCommand = 0xFF;
3094 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3095 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3096 bcc_ptr = &pSMB->Password[0];
3097 bcc_ptr++; /* skip password */
3098
3099 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3100 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3101
3102 if (ses->capabilities & CAP_STATUS32) {
3103 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3104 }
3105 if (ses->capabilities & CAP_DFS) {
3106 smb_buffer->Flags2 |= SMBFLG2_DFS;
3107 }
3108 if (ses->capabilities & CAP_UNICODE) {
3109 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3110 length =
3111 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3112 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3113 bcc_ptr += 2; /* skip trailing null */
3114 } else { /* ASCII */
3115
3116 strcpy(bcc_ptr, tree);
3117 bcc_ptr += strlen(tree) + 1;
3118 }
3119 strcpy(bcc_ptr, "?????");
3120 bcc_ptr += strlen("?????");
3121 bcc_ptr += 1;
3122 count = bcc_ptr - &pSMB->Password[0];
3123 pSMB->hdr.smb_buf_length += count;
3124 pSMB->ByteCount = cpu_to_le16(count);
3125
3126 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3127
3128 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3129 /* above now done in SendReceive */
3130 if ((rc == 0) && (tcon != NULL)) {
3131 tcon->tidStatus = CifsGood;
3132 tcon->tid = smb_buffer_response->Tid;
3133 bcc_ptr = pByteArea(smb_buffer_response);
3134 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3135 /* skip service field (NB: this field is always ASCII) */
3136 bcc_ptr += length + 1;
3137 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3138 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3139 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3140 if ((bcc_ptr + (2 * length)) -
3141 pByteArea(smb_buffer_response) <=
3142 BCC(smb_buffer_response)) {
3143 if(tcon->nativeFileSystem)
3144 kfree(tcon->nativeFileSystem);
3145 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003146 kzalloc(length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 cifs_strfromUCS_le(tcon->nativeFileSystem,
3148 (wchar_t *) bcc_ptr,
3149 length, nls_codepage);
3150 bcc_ptr += 2 * length;
3151 bcc_ptr[0] = 0; /* null terminate the string */
3152 bcc_ptr[1] = 0;
3153 bcc_ptr += 2;
3154 }
3155 /* else do not bother copying these informational fields */
3156 } else {
3157 length = strnlen(bcc_ptr, 1024);
3158 if ((bcc_ptr + length) -
3159 pByteArea(smb_buffer_response) <=
3160 BCC(smb_buffer_response)) {
3161 if(tcon->nativeFileSystem)
3162 kfree(tcon->nativeFileSystem);
3163 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003164 kzalloc(length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 strncpy(tcon->nativeFileSystem, bcc_ptr,
3166 length);
3167 }
3168 /* else do not bother copying these informational fields */
3169 }
3170 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3171 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3172 } else if ((rc == 0) && tcon == NULL) {
3173 /* all we need to save for IPC$ connection */
3174 ses->ipc_tid = smb_buffer_response->Tid;
3175 }
3176
3177 if (smb_buffer)
3178 cifs_buf_release(smb_buffer);
3179 return rc;
3180}
3181
3182int
3183cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3184{
3185 int rc = 0;
3186 int xid;
3187 struct cifsSesInfo *ses = NULL;
3188 struct task_struct *cifsd_task;
3189
3190 xid = GetXid();
3191
3192 if (cifs_sb->tcon) {
3193 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3194 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3195 if (rc == -EBUSY) {
3196 FreeXid(xid);
3197 return 0;
3198 }
3199 tconInfoFree(cifs_sb->tcon);
3200 if ((ses) && (ses->server)) {
3201 /* save off task so we do not refer to ses later */
3202 cifsd_task = ses->server->tsk;
3203 cFYI(1, ("About to do SMBLogoff "));
3204 rc = CIFSSMBLogoff(xid, ses);
3205 if (rc == -EBUSY) {
3206 FreeXid(xid);
3207 return 0;
3208 } else if (rc == -ESHUTDOWN) {
3209 cFYI(1,("Waking up socket by sending it signal"));
3210 if(cifsd_task)
3211 send_sig(SIGKILL,cifsd_task,1);
3212 rc = 0;
3213 } /* else - we have an smb session
3214 left on this socket do not kill cifsd */
3215 } else
3216 cFYI(1, ("No session or bad tcon"));
3217 }
3218
3219 cifs_sb->tcon = NULL;
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003220 if (ses)
3221 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 if (ses)
3223 sesInfoFree(ses);
3224
3225 FreeXid(xid);
3226 return rc; /* BB check if we should always return zero here */
3227}
3228
3229int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3230 struct nls_table * nls_info)
3231{
3232 int rc = 0;
3233 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3234 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003235 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236
3237 /* what if server changes its buffer size after dropping the session? */
3238 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3239 rc = CIFSSMBNegotiate(xid, pSesInfo);
3240 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3241 rc = CIFSSMBNegotiate(xid, pSesInfo);
3242 if(rc == -EAGAIN)
3243 rc = -EHOSTDOWN;
3244 }
3245 if(rc == 0) {
3246 spin_lock(&GlobalMid_Lock);
3247 if(pSesInfo->server->tcpStatus != CifsExiting)
3248 pSesInfo->server->tcpStatus = CifsGood;
3249 else
3250 rc = -EHOSTDOWN;
3251 spin_unlock(&GlobalMid_Lock);
3252
3253 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003254 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 }
3256 if (!rc) {
3257 pSesInfo->capabilities = pSesInfo->server->capabilities;
3258 if(linuxExtEnabled == 0)
3259 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003260 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3262 pSesInfo->server->secMode,
3263 pSesInfo->server->capabilities,
3264 pSesInfo->server->timeZone));
3265 if (extended_security
3266 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3267 && (pSesInfo->server->secType == NTLMSSP)) {
3268 cFYI(1, ("New style sesssetup "));
3269 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3270 NULL /* security blob */,
3271 0 /* blob length */,
3272 nls_info);
3273 } else if (extended_security
3274 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3275 && (pSesInfo->server->secType == RawNTLMSSP)) {
3276 cFYI(1, ("NTLMSSP sesssetup "));
3277 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3278 pSesInfo,
3279 &ntlmv2_flag,
3280 nls_info);
3281 if (!rc) {
3282 if(ntlmv2_flag) {
3283 char * v2_response;
3284 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3285 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3286 nls_info)) {
3287 rc = -ENOMEM;
3288 goto ss_err_exit;
3289 } else
3290 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3291 if(v2_response) {
3292 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003293 /* if(first_time)
3294 cifs_calculate_ntlmv2_mac_key(
3295 pSesInfo->server->mac_signing_key,
3296 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 kfree(v2_response);
3298 /* BB Put dummy sig in SessSetup PDU? */
3299 } else {
3300 rc = -ENOMEM;
3301 goto ss_err_exit;
3302 }
3303
3304 } else {
3305 SMBNTencrypt(pSesInfo->password,
3306 pSesInfo->server->cryptKey,
3307 ntlm_session_key);
3308
Steve Frenchad009ac2005-04-28 22:41:05 -07003309 if(first_time)
3310 cifs_calculate_mac_key(
3311 pSesInfo->server->mac_signing_key,
3312 ntlm_session_key,
3313 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 }
3315 /* for better security the weaker lanman hash not sent
3316 in AuthSessSetup so we no longer calculate it */
3317
3318 rc = CIFSNTLMSSPAuthSessSetup(xid,
3319 pSesInfo,
3320 ntlm_session_key,
3321 ntlmv2_flag,
3322 nls_info);
3323 }
3324 } else { /* old style NTLM 0.12 session setup */
3325 SMBNTencrypt(pSesInfo->password,
3326 pSesInfo->server->cryptKey,
3327 ntlm_session_key);
3328
Steve Frenchad009ac2005-04-28 22:41:05 -07003329 if(first_time)
3330 cifs_calculate_mac_key(
3331 pSesInfo->server->mac_signing_key,
3332 ntlm_session_key, pSesInfo->password);
3333
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 rc = CIFSSessSetup(xid, pSesInfo,
3335 ntlm_session_key, nls_info);
3336 }
3337 if (rc) {
3338 cERROR(1,("Send error in SessSetup = %d",rc));
3339 } else {
3340 cFYI(1,("CIFS Session Established successfully"));
3341 pSesInfo->status = CifsGood;
3342 }
3343 }
3344ss_err_exit:
3345 return rc;
3346}
3347