blob: 2335f14a15830902f1fff25c248d720cba799338 [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 Frenchb8643e12005-04-28 22:41:07 -0700347 if (bigbuf == NULL) {
348 bigbuf = cifs_buf_get();
349 if(bigbuf == NULL) {
350 cERROR(1,("No memory for large SMB response"));
351 msleep(3000);
352 /* retry will check if exiting */
353 continue;
354 }
355 } else if(isLargeBuf) {
356 /* we are reusing a dirtry large buf, clear its start */
357 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700359
360 if (smallbuf == NULL) {
361 smallbuf = cifs_small_buf_get();
362 if(smallbuf == NULL) {
363 cERROR(1,("No memory for SMB response"));
364 msleep(1000);
365 /* retry will check if exiting */
366 continue;
367 }
368 /* beginning of smb buffer is cleared in our buf_get */
369 } else /* if existing small buf clear beginning */
370 memset(smallbuf, 0, sizeof (struct smb_hdr));
371
372 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700373 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700374 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 iov.iov_base = smb_buffer;
376 iov.iov_len = 4;
377 smb_msg.msg_control = NULL;
378 smb_msg.msg_controllen = 0;
379 length =
380 kernel_recvmsg(csocket, &smb_msg,
381 &iov, 1, 4, 0 /* BB see socket.h flags */);
382
383 if(server->tcpStatus == CifsExiting) {
384 break;
385 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French57337e42005-04-28 22:41:10 -0700386 cFYI(1,("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 cifs_reconnect(server);
388 cFYI(1,("call to reconnect done"));
389 csocket = server->ssocket;
390 continue;
391 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700392 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 allowing socket to clear and app threads to set
394 tcpStatus CifsNeedReconnect if server hung */
395 continue;
396 } else if (length <= 0) {
397 if(server->tcpStatus == CifsNew) {
Steve French57337e42005-04-28 22:41:10 -0700398 cFYI(1,("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700399 /* some servers kill the TCP session rather than
400 returning an SMB negprot error, in which
401 case reconnecting here is not going to help,
402 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 break;
404 }
405 if(length == -EINTR) {
406 cFYI(1,("cifsd thread killed"));
407 break;
408 }
Steve French57337e42005-04-28 22:41:10 -0700409 cFYI(1,("Reconnect after unexpected peek error %d",
410 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 cifs_reconnect(server);
412 csocket = server->ssocket;
413 wake_up(&server->response_q);
414 continue;
Steve French46810cb2005-04-28 22:41:09 -0700415 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700417 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 length));
419 cifs_reconnect(server);
420 csocket = server->ssocket;
421 wake_up(&server->response_q);
422 continue;
423 }
Steve French67010fb2005-04-28 22:41:09 -0700424
Steve French46810cb2005-04-28 22:41:09 -0700425 /* the right amount was read from socket - 4 bytes */
426
427 pdu_length = ntohl(smb_buffer->smb_buf_length);
428 cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
429
430 temp = (char *) smb_buffer;
431 if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700432 continue;
Steve French46810cb2005-04-28 22:41:09 -0700433 } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700434 cFYI(1,("Good RFC 1002 session rsp"));
435 continue;
Steve French46810cb2005-04-28 22:41:09 -0700436 } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
437 /* we get this from Windows 98 instead of
438 an error on SMB negprot response */
Steve Frenche4eb2952005-04-28 22:41:09 -0700439 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
440 temp[4]));
Steve French46810cb2005-04-28 22:41:09 -0700441 if(server->tcpStatus == CifsNew) {
442 /* if nack on negprot (rather than
443 ret of smb negprot error) reconnecting
444 not going to help, ret error to mount */
445 break;
446 } else {
447 /* give server a second to
448 clean up before reconnect attempt */
449 msleep(1000);
450 /* always try 445 first on reconnect
451 since we get NACK on some if we ever
452 connected to port 139 (the NACK is
453 since we do not begin with RFC1001
454 session initialize frame) */
455 server->addr.sockAddr.sin_port =
456 htons(CIFS_PORT);
457 cifs_reconnect(server);
458 csocket = server->ssocket;
459 wake_up(&server->response_q);
460 continue;
461 }
462 } else if (temp[0] != (char) 0) {
463 cERROR(1,("Unknown RFC 1002 frame"));
464 cifs_dump_mem(" Received Data: ", temp, length);
465 cifs_reconnect(server);
466 csocket = server->ssocket;
467 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700468 }
469
470 /* else we have an SMB response */
471 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700472 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700473 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700474 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700475 cifs_reconnect(server);
476 csocket = server->ssocket;
477 wake_up(&server->response_q);
478 continue;
479 }
480
481 /* else length ok */
482 reconnect = 0;
483
484 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
485 isLargeBuf = TRUE;
486 memcpy(bigbuf, smallbuf, 4);
487 smb_buffer = bigbuf;
488 }
489 length = 0;
490 iov.iov_base = 4 + (char *)smb_buffer;
491 iov.iov_len = pdu_length;
492 for (total_read = 0; total_read < pdu_length;
493 total_read += length) {
494 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
495 pdu_length - total_read, 0);
496 if((server->tcpStatus == CifsExiting) ||
497 (length == -EINTR)) {
498 /* then will exit */
499 reconnect = 2;
500 break;
501 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700502 cifs_reconnect(server);
503 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700504 /* Reconnect wakes up rspns q */
505 /* Now we will reread sock */
506 reconnect = 1;
507 break;
508 } else if ((length == -ERESTARTSYS) ||
509 (length == -EAGAIN)) {
510 msleep(1); /* minimum sleep to prevent looping,
511 allowing socket to clear and app
512 threads to set tcpStatus
513 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700514 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700515 } else if (length <= 0) {
516 cERROR(1,("Received no data, expecting %d",
517 pdu_length - total_read));
518 cifs_reconnect(server);
519 csocket = server->ssocket;
520 reconnect = 1;
521 break;
Steve French46810cb2005-04-28 22:41:09 -0700522 }
523 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700524 if(reconnect == 2)
525 break;
526 else if(reconnect == 1)
527 continue;
528
529 length += 4; /* account for rfc1002 hdr */
530
531
532 dump_smb(smb_buffer, length);
533 if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
534 cERROR(1, ("Bad SMB Received "));
535 continue;
536 }
537
538
539 task_to_wake = NULL;
540 spin_lock(&GlobalMid_Lock);
541 list_for_each(tmp, &server->pending_mid_q) {
542 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
543
544 if ((mid_entry->mid == smb_buffer->Mid) &&
545 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
546 (mid_entry->command == smb_buffer->Command)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700547 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
548 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700549 isMultiRsp = TRUE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700550 if(mid_entry->resp_buf) {
551 /* merge response - fix up 1st*/
552 if(coalesce_t2(smb_buffer,
553 mid_entry->resp_buf)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700554 break;
555 } else {
556 /* all parts received */
557 goto multi_t2_fnd;
558 }
559 } else {
560 if(!isLargeBuf) {
561 cERROR(1,("1st trans2 resp needs bigbuf"));
562 /* BB maybe we can fix this up, switch
563 to already allocated large buffer? */
564 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700565 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700566 mid_entry->resp_buf =
567 smb_buffer;
568 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700569 bigbuf = NULL;
570 }
571 }
572 break;
573 }
574 mid_entry->resp_buf = smb_buffer;
575 if(isLargeBuf)
576 mid_entry->largeBuf = 1;
577 else
578 mid_entry->largeBuf = 0;
579multi_t2_fnd:
580 task_to_wake = mid_entry->tsk;
581 mid_entry->midState = MID_RESPONSE_RECEIVED;
582 break;
583 }
584 }
585 spin_unlock(&GlobalMid_Lock);
586 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700587 /* Was previous buf put in mpx struct for multi-rsp? */
588 if(!isMultiRsp) {
589 /* smb buffer will be freed by user thread */
590 if(isLargeBuf) {
591 bigbuf = NULL;
592 } else
593 smallbuf = NULL;
594 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700595 wake_up_process(task_to_wake);
Steve French57337e42005-04-28 22:41:10 -0700596 } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700597 && (isMultiRsp == FALSE)) {
598 cERROR(1, ("No task to wake, unknown frame rcvd!"));
599 cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
600 }
601 } /* end while !EXITING */
602
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 spin_lock(&GlobalMid_Lock);
604 server->tcpStatus = CifsExiting;
605 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700606 /* check if we have blocked requests that need to free */
607 /* Note that cifs_max_pending is normally 50, but
608 can be set at module install time to as little as two */
609 if(atomic_read(&server->inFlight) >= cifs_max_pending)
610 atomic_set(&server->inFlight, cifs_max_pending - 1);
611 /* We do not want to set the max_pending too low or we
612 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 spin_unlock(&GlobalMid_Lock);
614 /* Although there should not be any requests blocked on
615 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700616 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 to the same server - they now will see the session is in exit state
618 and get out of SendReceive. */
619 wake_up_all(&server->request_q);
620 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700621 msleep(125);
622
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 if(server->ssocket) {
624 sock_release(csocket);
625 server->ssocket = NULL;
626 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700627 /* buffer usuallly freed in free_mid - need to free it here on exit */
628 if (bigbuf != NULL)
629 cifs_buf_release(bigbuf);
630 if (smallbuf != NULL)
631 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633 read_lock(&GlobalSMBSeslock);
634 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700635 /* loop through server session structures attached to this and
636 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 list_for_each(tmp, &GlobalSMBSessionList) {
638 ses =
639 list_entry(tmp, struct cifsSesInfo,
640 cifsSessionList);
641 if (ses->server == server) {
642 ses->status = CifsExiting;
643 ses->server = NULL;
644 }
645 }
646 read_unlock(&GlobalSMBSeslock);
647 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700648 /* although we can not zero the server struct pointer yet,
649 since there are active requests which may depnd on them,
650 mark the corresponding SMB sessions as exiting too */
651 list_for_each(tmp, &GlobalSMBSessionList) {
652 ses = list_entry(tmp, struct cifsSesInfo,
653 cifsSessionList);
654 if (ses->server == server) {
655 ses->status = CifsExiting;
656 }
657 }
658
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 spin_lock(&GlobalMid_Lock);
660 list_for_each(tmp, &server->pending_mid_q) {
661 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
662 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
663 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700664 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 task_to_wake = mid_entry->tsk;
666 if(task_to_wake) {
667 wake_up_process(task_to_wake);
668 }
669 }
670 }
671 spin_unlock(&GlobalMid_Lock);
672 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700674 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 }
676
677 if (list_empty(&server->pending_mid_q)) {
678 /* mpx threads have not exited yet give them
679 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700680 /* due to delays on oplock break requests, we need
681 to wait at least 45 seconds before giving up
682 on a request getting a response and going ahead
683 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700685 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 /* if threads still have not exited they are probably never
687 coming home not much else we can do but free the memory */
688 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690 write_lock(&GlobalSMBSeslock);
691 atomic_dec(&tcpSesAllocCount);
692 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700693
694 /* last chance to mark ses pointers invalid
695 if there are any pointing to this (e.g
696 if a crazy root user tried to kill cifsd
697 kernel thread explicitly this might happen) */
698 list_for_each(tmp, &GlobalSMBSessionList) {
699 ses = list_entry(tmp, struct cifsSesInfo,
700 cifsSessionList);
701 if (ses->server == server) {
702 ses->server = NULL;
703 }
704 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700706
707 kfree(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 if(length > 0) {
709 mempool_resize(cifs_req_poolp,
710 length + cifs_min_rcv,
711 GFP_KERNEL);
712 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700713
714 msleep(250);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 return 0;
716}
717
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718static int
719cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
720{
721 char *value;
722 char *data;
723 unsigned int temp_len, i, j;
724 char separator[2];
725
726 separator[0] = ',';
727 separator[1] = 0;
728
729 memset(vol->source_rfc1001_name,0x20,15);
730 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
731 /* does not have to be a perfect mapping since the field is
732 informational, only used for servers that do not support
733 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700734 vol->source_rfc1001_name[i] =
735 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 }
737 vol->source_rfc1001_name[15] = 0;
738
739 vol->linux_uid = current->uid; /* current->euid instead? */
740 vol->linux_gid = current->gid;
741 vol->dir_mode = S_IRWXUGO;
742 /* 2767 perms indicate mandatory locking support */
743 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
744
745 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
746 vol->rw = TRUE;
747
748 if (!options)
749 return 1;
750
751 if(strncmp(options,"sep=",4) == 0) {
752 if(options[4] != 0) {
753 separator[0] = options[4];
754 options += 5;
755 } else {
756 cFYI(1,("Null separator not allowed"));
757 }
758 }
759
760 while ((data = strsep(&options, separator)) != NULL) {
761 if (!*data)
762 continue;
763 if ((value = strchr(data, '=')) != NULL)
764 *value++ = '\0';
765
766 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
767 vol->no_xattr = 0;
768 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
769 vol->no_xattr = 1;
770 } else if (strnicmp(data, "user", 4) == 0) {
771 if (!value || !*value) {
772 printk(KERN_WARNING
773 "CIFS: invalid or missing username\n");
774 return 1; /* needs_arg; */
775 }
776 if (strnlen(value, 200) < 200) {
777 vol->username = value;
778 } else {
779 printk(KERN_WARNING "CIFS: username too long\n");
780 return 1;
781 }
782 } else if (strnicmp(data, "pass", 4) == 0) {
783 if (!value) {
784 vol->password = NULL;
785 continue;
786 } else if(value[0] == 0) {
787 /* check if string begins with double comma
788 since that would mean the password really
789 does start with a comma, and would not
790 indicate an empty string */
791 if(value[1] != separator[0]) {
792 vol->password = NULL;
793 continue;
794 }
795 }
796 temp_len = strlen(value);
797 /* removed password length check, NTLM passwords
798 can be arbitrarily long */
799
800 /* if comma in password, the string will be
801 prematurely null terminated. Commas in password are
802 specified across the cifs mount interface by a double
803 comma ie ,, and a comma used as in other cases ie ','
804 as a parameter delimiter/separator is single and due
805 to the strsep above is temporarily zeroed. */
806
807 /* NB: password legally can have multiple commas and
808 the only illegal character in a password is null */
809
Steve French09d1db52005-04-28 22:41:08 -0700810 if ((value[temp_len] == 0) &&
811 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 /* reinsert comma */
813 value[temp_len] = separator[0];
814 temp_len+=2; /* move after the second comma */
815 while(value[temp_len] != 0) {
816 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700817 if (value[temp_len+1] ==
818 separator[0]) {
819 /* skip second comma */
820 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 } else {
822 /* single comma indicating start
823 of next parm */
824 break;
825 }
826 }
827 temp_len++;
828 }
829 if(value[temp_len] == 0) {
830 options = NULL;
831 } else {
832 value[temp_len] = 0;
833 /* point option to start of next parm */
834 options = value + temp_len + 1;
835 }
836 /* go from value to value + temp_len condensing
837 double commas to singles. Note that this ends up
838 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700839 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700840 if(vol->password == NULL) {
841 printk("CIFS: no memory for pass\n");
842 return 1;
843 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 for(i=0,j=0;i<temp_len;i++,j++) {
845 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700846 if(value[i] == separator[0]
847 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 /* skip second comma */
849 i++;
850 }
851 }
852 vol->password[j] = 0;
853 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700854 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700855 if(vol->password == NULL) {
856 printk("CIFS: no memory for pass\n");
857 return 1;
858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 strcpy(vol->password, value);
860 }
861 } else if (strnicmp(data, "ip", 2) == 0) {
862 if (!value || !*value) {
863 vol->UNCip = NULL;
864 } else if (strnlen(value, 35) < 35) {
865 vol->UNCip = value;
866 } else {
867 printk(KERN_WARNING "CIFS: ip address too long\n");
868 return 1;
869 }
870 } else if ((strnicmp(data, "unc", 3) == 0)
871 || (strnicmp(data, "target", 6) == 0)
872 || (strnicmp(data, "path", 4) == 0)) {
873 if (!value || !*value) {
874 printk(KERN_WARNING
875 "CIFS: invalid path to network resource\n");
876 return 1; /* needs_arg; */
877 }
878 if ((temp_len = strnlen(value, 300)) < 300) {
879 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
880 if(vol->UNC == NULL)
881 return 1;
882 strcpy(vol->UNC,value);
883 if (strncmp(vol->UNC, "//", 2) == 0) {
884 vol->UNC[0] = '\\';
885 vol->UNC[1] = '\\';
886 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
887 printk(KERN_WARNING
888 "CIFS: UNC Path does not begin with // or \\\\ \n");
889 return 1;
890 }
891 } else {
892 printk(KERN_WARNING "CIFS: UNC name too long\n");
893 return 1;
894 }
895 } else if ((strnicmp(data, "domain", 3) == 0)
896 || (strnicmp(data, "workgroup", 5) == 0)) {
897 if (!value || !*value) {
898 printk(KERN_WARNING "CIFS: invalid domain name\n");
899 return 1; /* needs_arg; */
900 }
901 /* BB are there cases in which a comma can be valid in
902 a domain name and need special handling? */
903 if (strnlen(value, 65) < 65) {
904 vol->domainname = value;
905 cFYI(1, ("Domain name set"));
906 } else {
907 printk(KERN_WARNING "CIFS: domain name too long\n");
908 return 1;
909 }
910 } else if (strnicmp(data, "iocharset", 9) == 0) {
911 if (!value || !*value) {
912 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
913 return 1; /* needs_arg; */
914 }
915 if (strnlen(value, 65) < 65) {
916 if(strnicmp(value,"default",7))
917 vol->iocharset = value;
918 /* if iocharset not set load_nls_default used by caller */
919 cFYI(1, ("iocharset set to %s",value));
920 } else {
921 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
922 return 1;
923 }
924 } else if (strnicmp(data, "uid", 3) == 0) {
925 if (value && *value) {
926 vol->linux_uid =
927 simple_strtoul(value, &value, 0);
928 }
929 } else if (strnicmp(data, "gid", 3) == 0) {
930 if (value && *value) {
931 vol->linux_gid =
932 simple_strtoul(value, &value, 0);
933 }
934 } else if (strnicmp(data, "file_mode", 4) == 0) {
935 if (value && *value) {
936 vol->file_mode =
937 simple_strtoul(value, &value, 0);
938 }
939 } else if (strnicmp(data, "dir_mode", 4) == 0) {
940 if (value && *value) {
941 vol->dir_mode =
942 simple_strtoul(value, &value, 0);
943 }
944 } else if (strnicmp(data, "dirmode", 4) == 0) {
945 if (value && *value) {
946 vol->dir_mode =
947 simple_strtoul(value, &value, 0);
948 }
949 } else if (strnicmp(data, "port", 4) == 0) {
950 if (value && *value) {
951 vol->port =
952 simple_strtoul(value, &value, 0);
953 }
954 } else if (strnicmp(data, "rsize", 5) == 0) {
955 if (value && *value) {
956 vol->rsize =
957 simple_strtoul(value, &value, 0);
958 }
959 } else if (strnicmp(data, "wsize", 5) == 0) {
960 if (value && *value) {
961 vol->wsize =
962 simple_strtoul(value, &value, 0);
963 }
964 } else if (strnicmp(data, "sockopt", 5) == 0) {
965 if (value && *value) {
966 vol->sockopt =
967 simple_strtoul(value, &value, 0);
968 }
969 } else if (strnicmp(data, "netbiosname", 4) == 0) {
970 if (!value || !*value || (*value == ' ')) {
971 cFYI(1,("invalid (empty) netbiosname specified"));
972 } else {
973 memset(vol->source_rfc1001_name,0x20,15);
974 for(i=0;i<15;i++) {
975 /* BB are there cases in which a comma can be
976 valid in this workstation netbios name (and need
977 special handling)? */
978
979 /* We do not uppercase netbiosname for user */
980 if (value[i]==0)
981 break;
982 else
983 vol->source_rfc1001_name[i] = value[i];
984 }
985 /* The string has 16th byte zero still from
986 set at top of the function */
987 if((i==15) && (value[i] != 0))
988 printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
989 }
990 } else if (strnicmp(data, "credentials", 4) == 0) {
991 /* ignore */
992 } else if (strnicmp(data, "version", 3) == 0) {
993 /* ignore */
994 } else if (strnicmp(data, "guest",5) == 0) {
995 /* ignore */
996 } else if (strnicmp(data, "rw", 2) == 0) {
997 vol->rw = TRUE;
998 } else if ((strnicmp(data, "suid", 4) == 0) ||
999 (strnicmp(data, "nosuid", 6) == 0) ||
1000 (strnicmp(data, "exec", 4) == 0) ||
1001 (strnicmp(data, "noexec", 6) == 0) ||
1002 (strnicmp(data, "nodev", 5) == 0) ||
1003 (strnicmp(data, "noauto", 6) == 0) ||
1004 (strnicmp(data, "dev", 3) == 0)) {
1005 /* The mount tool or mount.cifs helper (if present)
1006 uses these opts to set flags, and the flags are read
1007 by the kernel vfs layer before we get here (ie
1008 before read super) so there is no point trying to
1009 parse these options again and set anything and it
1010 is ok to just ignore them */
1011 continue;
1012 } else if (strnicmp(data, "ro", 2) == 0) {
1013 vol->rw = FALSE;
1014 } else if (strnicmp(data, "hard", 4) == 0) {
1015 vol->retry = 1;
1016 } else if (strnicmp(data, "soft", 4) == 0) {
1017 vol->retry = 0;
1018 } else if (strnicmp(data, "perm", 4) == 0) {
1019 vol->noperm = 0;
1020 } else if (strnicmp(data, "noperm", 6) == 0) {
1021 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001022 } else if (strnicmp(data, "mapchars", 8) == 0) {
1023 vol->remap = 1;
1024 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1025 vol->remap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 } else if (strnicmp(data, "setuids", 7) == 0) {
1027 vol->setuids = 1;
1028 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1029 vol->setuids = 0;
1030 } else if (strnicmp(data, "nohard", 6) == 0) {
1031 vol->retry = 0;
1032 } else if (strnicmp(data, "nosoft", 6) == 0) {
1033 vol->retry = 1;
1034 } else if (strnicmp(data, "nointr", 6) == 0) {
1035 vol->intr = 0;
1036 } else if (strnicmp(data, "intr", 4) == 0) {
1037 vol->intr = 1;
1038 } else if (strnicmp(data, "serverino",7) == 0) {
1039 vol->server_ino = 1;
1040 } else if (strnicmp(data, "noserverino",9) == 0) {
1041 vol->server_ino = 0;
1042 } else if (strnicmp(data, "acl",3) == 0) {
1043 vol->no_psx_acl = 0;
1044 } else if (strnicmp(data, "noacl",5) == 0) {
1045 vol->no_psx_acl = 1;
1046 } else if (strnicmp(data, "direct",6) == 0) {
1047 vol->direct_io = 1;
1048 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1049 vol->direct_io = 1;
1050 } else if (strnicmp(data, "in6_addr",8) == 0) {
1051 if (!value || !*value) {
1052 vol->in6_addr = NULL;
1053 } else if (strnlen(value, 49) == 48) {
1054 vol->in6_addr = value;
1055 } else {
1056 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1057 return 1;
1058 }
1059 } else if (strnicmp(data, "noac", 4) == 0) {
1060 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1061 } else
1062 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1063 }
1064 if (vol->UNC == NULL) {
1065 if(devname == NULL) {
1066 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1067 return 1;
1068 }
1069 if ((temp_len = strnlen(devname, 300)) < 300) {
1070 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1071 if(vol->UNC == NULL)
1072 return 1;
1073 strcpy(vol->UNC,devname);
1074 if (strncmp(vol->UNC, "//", 2) == 0) {
1075 vol->UNC[0] = '\\';
1076 vol->UNC[1] = '\\';
1077 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1078 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1079 return 1;
1080 }
1081 } else {
1082 printk(KERN_WARNING "CIFS: UNC name too long\n");
1083 return 1;
1084 }
1085 }
1086 if(vol->UNCip == NULL)
1087 vol->UNCip = &vol->UNC[2];
1088
1089 return 0;
1090}
1091
1092static struct cifsSesInfo *
1093cifs_find_tcp_session(struct in_addr * target_ip_addr,
1094 struct in6_addr *target_ip6_addr,
1095 char *userName, struct TCP_Server_Info **psrvTcp)
1096{
1097 struct list_head *tmp;
1098 struct cifsSesInfo *ses;
1099 *psrvTcp = NULL;
1100 read_lock(&GlobalSMBSeslock);
1101
1102 list_for_each(tmp, &GlobalSMBSessionList) {
1103 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1104 if (ses->server) {
1105 if((target_ip_addr &&
1106 (ses->server->addr.sockAddr.sin_addr.s_addr
1107 == target_ip_addr->s_addr)) || (target_ip6_addr
1108 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1109 target_ip6_addr,sizeof(*target_ip6_addr)))){
1110 /* BB lock server and tcp session and increment use count here?? */
1111 *psrvTcp = ses->server; /* found a match on the TCP session */
1112 /* BB check if reconnection needed */
1113 if (strncmp
1114 (ses->userName, userName,
1115 MAX_USERNAME_SIZE) == 0){
1116 read_unlock(&GlobalSMBSeslock);
1117 return ses; /* found exact match on both tcp and SMB sessions */
1118 }
1119 }
1120 }
1121 /* else tcp and smb sessions need reconnection */
1122 }
1123 read_unlock(&GlobalSMBSeslock);
1124 return NULL;
1125}
1126
1127static struct cifsTconInfo *
1128find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1129{
1130 struct list_head *tmp;
1131 struct cifsTconInfo *tcon;
1132
1133 read_lock(&GlobalSMBSeslock);
1134 list_for_each(tmp, &GlobalTreeConnectionList) {
1135 cFYI(1, ("Next tcon - "));
1136 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1137 if (tcon->ses) {
1138 if (tcon->ses->server) {
1139 cFYI(1,
1140 (" old ip addr: %x == new ip %x ?",
1141 tcon->ses->server->addr.sockAddr.sin_addr.
1142 s_addr, new_target_ip_addr));
1143 if (tcon->ses->server->addr.sockAddr.sin_addr.
1144 s_addr == new_target_ip_addr) {
1145 /* BB lock tcon and server and tcp session and increment use count here? */
1146 /* found a match on the TCP session */
1147 /* BB check if reconnection needed */
1148 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1149 tcon->treeName, uncName));
1150 if (strncmp
1151 (tcon->treeName, uncName,
1152 MAX_TREE_SIZE) == 0) {
1153 cFYI(1,
1154 ("Matched UNC, old user: %s == new: %s ?",
1155 tcon->treeName, uncName));
1156 if (strncmp
1157 (tcon->ses->userName,
1158 userName,
1159 MAX_USERNAME_SIZE) == 0) {
1160 read_unlock(&GlobalSMBSeslock);
1161 return tcon;/* also matched user (smb session)*/
1162 }
1163 }
1164 }
1165 }
1166 }
1167 }
1168 read_unlock(&GlobalSMBSeslock);
1169 return NULL;
1170}
1171
1172int
1173connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001174 const char *old_path, const struct nls_table *nls_codepage,
1175 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176{
1177 unsigned char *referrals = NULL;
1178 unsigned int num_referrals;
1179 int rc = 0;
1180
1181 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001182 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
1184 /* BB Add in code to: if valid refrl, if not ip address contact
1185 the helper that resolves tcp names, mount to it, try to
1186 tcon to it unmount it if fail */
1187
1188 if(referrals)
1189 kfree(referrals);
1190
1191 return rc;
1192}
1193
1194int
1195get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1196 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001197 unsigned int *pnum_referrals,
1198 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199{
1200 char *temp_unc;
1201 int rc = 0;
1202
1203 *pnum_referrals = 0;
1204
1205 if (pSesInfo->ipc_tid == 0) {
1206 temp_unc = kmalloc(2 /* for slashes */ +
1207 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1208 + 1 + 4 /* slash IPC$ */ + 2,
1209 GFP_KERNEL);
1210 if (temp_unc == NULL)
1211 return -ENOMEM;
1212 temp_unc[0] = '\\';
1213 temp_unc[1] = '\\';
1214 strcpy(temp_unc + 2, pSesInfo->serverName);
1215 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1216 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1217 cFYI(1,
1218 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1219 kfree(temp_unc);
1220 }
1221 if (rc == 0)
1222 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001223 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
1225 return rc;
1226}
1227
1228/* See RFC1001 section 14 on representation of Netbios names */
1229static void rfc1002mangle(char * target,char * source, unsigned int length)
1230{
1231 unsigned int i,j;
1232
1233 for(i=0,j=0;i<(length);i++) {
1234 /* mask a nibble at a time and encode */
1235 target[j] = 'A' + (0x0F & (source[i] >> 4));
1236 target[j+1] = 'A' + (0x0F & source[i]);
1237 j+=2;
1238 }
1239
1240}
1241
1242
1243static int
1244ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1245 char * netbios_name)
1246{
1247 int rc = 0;
1248 int connected = 0;
1249 __be16 orig_port = 0;
1250
1251 if(*csocket == NULL) {
1252 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1253 if (rc < 0) {
1254 cERROR(1, ("Error %d creating socket",rc));
1255 *csocket = NULL;
1256 return rc;
1257 } else {
1258 /* BB other socket options to set KEEPALIVE, NODELAY? */
1259 cFYI(1,("Socket created"));
1260 (*csocket)->sk->sk_allocation = GFP_NOFS;
1261 }
1262 }
1263
1264 psin_server->sin_family = AF_INET;
1265 if(psin_server->sin_port) { /* user overrode default port */
1266 rc = (*csocket)->ops->connect(*csocket,
1267 (struct sockaddr *) psin_server,
1268 sizeof (struct sockaddr_in),0);
1269 if (rc >= 0)
1270 connected = 1;
1271 }
1272
1273 if(!connected) {
1274 /* save original port so we can retry user specified port
1275 later if fall back ports fail this time */
1276 orig_port = psin_server->sin_port;
1277
1278 /* do not retry on the same port we just failed on */
1279 if(psin_server->sin_port != htons(CIFS_PORT)) {
1280 psin_server->sin_port = htons(CIFS_PORT);
1281
1282 rc = (*csocket)->ops->connect(*csocket,
1283 (struct sockaddr *) psin_server,
1284 sizeof (struct sockaddr_in),0);
1285 if (rc >= 0)
1286 connected = 1;
1287 }
1288 }
1289 if (!connected) {
1290 psin_server->sin_port = htons(RFC1001_PORT);
1291 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1292 psin_server, sizeof (struct sockaddr_in),0);
1293 if (rc >= 0)
1294 connected = 1;
1295 }
1296
1297 /* give up here - unless we want to retry on different
1298 protocol families some day */
1299 if (!connected) {
1300 if(orig_port)
1301 psin_server->sin_port = orig_port;
1302 cFYI(1,("Error %d connecting to server via ipv4",rc));
1303 sock_release(*csocket);
1304 *csocket = NULL;
1305 return rc;
1306 }
1307 /* Eventually check for other socket options to change from
1308 the default. sock_setsockopt not used because it expects
1309 user space buffer */
1310 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1311
1312 /* send RFC1001 sessinit */
1313
1314 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1315 /* some servers require RFC1001 sessinit before sending
1316 negprot - BB check reconnection in case where second
1317 sessinit is sent but no second negprot */
1318 struct rfc1002_session_packet * ses_init_buf;
1319 struct smb_hdr * smb_buf;
Pekka Enberge915fc42005-09-06 15:18:35 -07001320 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 if(ses_init_buf) {
1322 ses_init_buf->trailer.session_req.called_len = 32;
1323 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1324 DEFAULT_CIFS_CALLED_NAME,16);
1325 ses_init_buf->trailer.session_req.calling_len = 32;
1326 /* calling name ends in null (byte 16) from old smb
1327 convention. */
1328 if(netbios_name && (netbios_name[0] !=0)) {
1329 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1330 netbios_name,16);
1331 } else {
1332 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1333 "LINUX_CIFS_CLNT",16);
1334 }
1335 ses_init_buf->trailer.session_req.scope1 = 0;
1336 ses_init_buf->trailer.session_req.scope2 = 0;
1337 smb_buf = (struct smb_hdr *)ses_init_buf;
1338 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1339 smb_buf->smb_buf_length = 0x81000044;
1340 rc = smb_send(*csocket, smb_buf, 0x44,
1341 (struct sockaddr *)psin_server);
1342 kfree(ses_init_buf);
1343 }
1344 /* else the negprot may still work without this
1345 even though malloc failed */
1346
1347 }
1348
1349 return rc;
1350}
1351
1352static int
1353ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1354{
1355 int rc = 0;
1356 int connected = 0;
1357 __be16 orig_port = 0;
1358
1359 if(*csocket == NULL) {
1360 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1361 if (rc < 0) {
1362 cERROR(1, ("Error %d creating ipv6 socket",rc));
1363 *csocket = NULL;
1364 return rc;
1365 } else {
1366 /* BB other socket options to set KEEPALIVE, NODELAY? */
1367 cFYI(1,("ipv6 Socket created"));
1368 (*csocket)->sk->sk_allocation = GFP_NOFS;
1369 }
1370 }
1371
1372 psin_server->sin6_family = AF_INET6;
1373
1374 if(psin_server->sin6_port) { /* user overrode default port */
1375 rc = (*csocket)->ops->connect(*csocket,
1376 (struct sockaddr *) psin_server,
1377 sizeof (struct sockaddr_in6),0);
1378 if (rc >= 0)
1379 connected = 1;
1380 }
1381
1382 if(!connected) {
1383 /* save original port so we can retry user specified port
1384 later if fall back ports fail this time */
1385
1386 orig_port = psin_server->sin6_port;
1387 /* do not retry on the same port we just failed on */
1388 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1389 psin_server->sin6_port = htons(CIFS_PORT);
1390
1391 rc = (*csocket)->ops->connect(*csocket,
1392 (struct sockaddr *) psin_server,
1393 sizeof (struct sockaddr_in6),0);
1394 if (rc >= 0)
1395 connected = 1;
1396 }
1397 }
1398 if (!connected) {
1399 psin_server->sin6_port = htons(RFC1001_PORT);
1400 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1401 psin_server, sizeof (struct sockaddr_in6),0);
1402 if (rc >= 0)
1403 connected = 1;
1404 }
1405
1406 /* give up here - unless we want to retry on different
1407 protocol families some day */
1408 if (!connected) {
1409 if(orig_port)
1410 psin_server->sin6_port = orig_port;
1411 cFYI(1,("Error %d connecting to server via ipv6",rc));
1412 sock_release(*csocket);
1413 *csocket = NULL;
1414 return rc;
1415 }
1416 /* Eventually check for other socket options to change from
1417 the default. sock_setsockopt not used because it expects
1418 user space buffer */
1419 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1420
1421 return rc;
1422}
1423
1424int
1425cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1426 char *mount_data, const char *devname)
1427{
1428 int rc = 0;
1429 int xid;
1430 int address_type = AF_INET;
1431 struct socket *csocket = NULL;
1432 struct sockaddr_in sin_server;
1433 struct sockaddr_in6 sin_server6;
1434 struct smb_vol volume_info;
1435 struct cifsSesInfo *pSesInfo = NULL;
1436 struct cifsSesInfo *existingCifsSes = NULL;
1437 struct cifsTconInfo *tcon = NULL;
1438 struct TCP_Server_Info *srvTcp = NULL;
1439
1440 xid = GetXid();
1441
1442/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1443
1444 memset(&volume_info,0,sizeof(struct smb_vol));
1445 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1446 if(volume_info.UNC)
1447 kfree(volume_info.UNC);
1448 if(volume_info.password)
1449 kfree(volume_info.password);
1450 FreeXid(xid);
1451 return -EINVAL;
1452 }
1453
1454 if (volume_info.username) {
1455 /* BB fixme parse for domain name here */
1456 cFYI(1, ("Username: %s ", volume_info.username));
1457
1458 } else {
1459 cifserror("No username specified ");
1460 /* In userspace mount helper we can get user name from alternate
1461 locations such as env variables and files on disk */
1462 if(volume_info.UNC)
1463 kfree(volume_info.UNC);
1464 if(volume_info.password)
1465 kfree(volume_info.password);
1466 FreeXid(xid);
1467 return -EINVAL;
1468 }
1469
1470 if (volume_info.UNCip && volume_info.UNC) {
1471 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1472
1473 if(rc <= 0) {
1474 /* not ipv4 address, try ipv6 */
1475 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1476 if(rc > 0)
1477 address_type = AF_INET6;
1478 } else {
1479 address_type = AF_INET;
1480 }
1481
1482 if(rc <= 0) {
1483 /* we failed translating address */
1484 if(volume_info.UNC)
1485 kfree(volume_info.UNC);
1486 if(volume_info.password)
1487 kfree(volume_info.password);
1488 FreeXid(xid);
1489 return -EINVAL;
1490 }
1491
1492 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1493 /* success */
1494 rc = 0;
1495 } else if (volume_info.UNCip){
1496 /* BB using ip addr as server name connect to the DFS root below */
1497 cERROR(1,("Connecting to DFS root not implemented yet"));
1498 if(volume_info.UNC)
1499 kfree(volume_info.UNC);
1500 if(volume_info.password)
1501 kfree(volume_info.password);
1502 FreeXid(xid);
1503 return -EINVAL;
1504 } else /* which servers DFS root would we conect to */ {
1505 cERROR(1,
1506 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1507 if(volume_info.UNC)
1508 kfree(volume_info.UNC);
1509 if(volume_info.password)
1510 kfree(volume_info.password);
1511 FreeXid(xid);
1512 return -EINVAL;
1513 }
1514
1515 /* this is needed for ASCII cp to Unicode converts */
1516 if(volume_info.iocharset == NULL) {
1517 cifs_sb->local_nls = load_nls_default();
1518 /* load_nls_default can not return null */
1519 } else {
1520 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1521 if(cifs_sb->local_nls == NULL) {
1522 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1523 if(volume_info.UNC)
1524 kfree(volume_info.UNC);
1525 if(volume_info.password)
1526 kfree(volume_info.password);
1527 FreeXid(xid);
1528 return -ELIBACC;
1529 }
1530 }
1531
1532 if(address_type == AF_INET)
1533 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1534 NULL /* no ipv6 addr */,
1535 volume_info.username, &srvTcp);
1536 else if(address_type == AF_INET6)
1537 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1538 &sin_server6.sin6_addr,
1539 volume_info.username, &srvTcp);
1540 else {
1541 if(volume_info.UNC)
1542 kfree(volume_info.UNC);
1543 if(volume_info.password)
1544 kfree(volume_info.password);
1545 FreeXid(xid);
1546 return -EINVAL;
1547 }
1548
1549
1550 if (srvTcp) {
1551 cFYI(1, ("Existing tcp session with server found "));
1552 } else { /* create socket */
1553 if(volume_info.port)
1554 sin_server.sin_port = htons(volume_info.port);
1555 else
1556 sin_server.sin_port = 0;
1557 rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
1558 if (rc < 0) {
1559 cERROR(1,
1560 ("Error connecting to IPv4 socket. Aborting operation"));
1561 if(csocket != NULL)
1562 sock_release(csocket);
1563 if(volume_info.UNC)
1564 kfree(volume_info.UNC);
1565 if(volume_info.password)
1566 kfree(volume_info.password);
1567 FreeXid(xid);
1568 return rc;
1569 }
1570
1571 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1572 if (srvTcp == NULL) {
1573 rc = -ENOMEM;
1574 sock_release(csocket);
1575 if(volume_info.UNC)
1576 kfree(volume_info.UNC);
1577 if(volume_info.password)
1578 kfree(volume_info.password);
1579 FreeXid(xid);
1580 return rc;
1581 } else {
1582 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1583 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1584 atomic_set(&srvTcp->inFlight,0);
1585 /* BB Add code for ipv6 case too */
1586 srvTcp->ssocket = csocket;
1587 srvTcp->protocolType = IPV4;
1588 init_waitqueue_head(&srvTcp->response_q);
1589 init_waitqueue_head(&srvTcp->request_q);
1590 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1591 /* at this point we are the only ones with the pointer
1592 to the struct since the kernel thread not created yet
1593 so no need to spinlock this init of tcpStatus */
1594 srvTcp->tcpStatus = CifsNew;
1595 init_MUTEX(&srvTcp->tcpSem);
1596 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1597 CLONE_FS | CLONE_FILES | CLONE_VM);
1598 if(rc < 0) {
1599 rc = -ENOMEM;
1600 sock_release(csocket);
1601 if(volume_info.UNC)
1602 kfree(volume_info.UNC);
1603 if(volume_info.password)
1604 kfree(volume_info.password);
1605 FreeXid(xid);
1606 return rc;
1607 } else
1608 rc = 0;
1609 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001610 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 }
1612 }
1613
1614 if (existingCifsSes) {
1615 pSesInfo = existingCifsSes;
1616 cFYI(1, ("Existing smb sess found "));
1617 if(volume_info.password)
1618 kfree(volume_info.password);
1619 /* volume_info.UNC freed at end of function */
1620 } else if (!rc) {
1621 cFYI(1, ("Existing smb sess not found "));
1622 pSesInfo = sesInfoAlloc();
1623 if (pSesInfo == NULL)
1624 rc = -ENOMEM;
1625 else {
1626 pSesInfo->server = srvTcp;
1627 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1628 NIPQUAD(sin_server.sin_addr.s_addr));
1629 }
1630
1631 if (!rc){
1632 /* volume_info.password freed at unmount */
1633 if (volume_info.password)
1634 pSesInfo->password = volume_info.password;
1635 if (volume_info.username)
1636 strncpy(pSesInfo->userName,
1637 volume_info.username,MAX_USERNAME_SIZE);
1638 if (volume_info.domainname)
1639 strncpy(pSesInfo->domainName,
1640 volume_info.domainname,MAX_USERNAME_SIZE);
1641 pSesInfo->linux_uid = volume_info.linux_uid;
1642 down(&pSesInfo->sesSem);
1643 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1644 up(&pSesInfo->sesSem);
1645 if(!rc)
1646 atomic_inc(&srvTcp->socketUseCount);
1647 } else
1648 if(volume_info.password)
1649 kfree(volume_info.password);
1650 }
1651
1652 /* search for existing tcon to this server share */
1653 if (!rc) {
1654 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1655 cifs_sb->rsize = volume_info.rsize;
1656 else
1657 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1658 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1659 cifs_sb->wsize = volume_info.wsize;
1660 else
1661 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1662 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1663 cifs_sb->rsize = PAGE_CACHE_SIZE;
1664 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1665 }
1666 cifs_sb->mnt_uid = volume_info.linux_uid;
1667 cifs_sb->mnt_gid = volume_info.linux_gid;
1668 cifs_sb->mnt_file_mode = volume_info.file_mode;
1669 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1670 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1671
1672 if(volume_info.noperm)
1673 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1674 if(volume_info.setuids)
1675 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1676 if(volume_info.server_ino)
1677 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001678 if(volume_info.remap)
1679 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 if(volume_info.no_xattr)
1681 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1682 if(volume_info.direct_io) {
1683 cERROR(1,("mounting share using direct i/o"));
1684 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1685 }
1686
1687 tcon =
1688 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1689 volume_info.username);
1690 if (tcon) {
1691 cFYI(1, ("Found match on UNC path "));
1692 /* we can have only one retry value for a connection
1693 to a share so for resources mounted more than once
1694 to the same server share the last value passed in
1695 for the retry flag is used */
1696 tcon->retry = volume_info.retry;
1697 } else {
1698 tcon = tconInfoAlloc();
1699 if (tcon == NULL)
1700 rc = -ENOMEM;
1701 else {
1702 /* check for null share name ie connect to dfs root */
1703
1704 /* BB check if this works for exactly length three strings */
1705 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1706 && (strchr(volume_info.UNC + 3, '/') ==
1707 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001708 rc = connect_to_dfs_path(xid, pSesInfo,
1709 "", cifs_sb->local_nls,
1710 cifs_sb->mnt_cifs_flags &
1711 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 if(volume_info.UNC)
1713 kfree(volume_info.UNC);
1714 FreeXid(xid);
1715 return -ENODEV;
1716 } else {
1717 rc = CIFSTCon(xid, pSesInfo,
1718 volume_info.UNC,
1719 tcon, cifs_sb->local_nls);
1720 cFYI(1, ("CIFS Tcon rc = %d", rc));
1721 }
1722 if (!rc) {
1723 atomic_inc(&pSesInfo->inUse);
1724 tcon->retry = volume_info.retry;
1725 }
1726 }
1727 }
1728 }
1729 if(pSesInfo) {
1730 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1731 sb->s_maxbytes = (u64) 1 << 63;
1732 } else
1733 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1734 }
1735
1736 sb->s_time_gran = 100;
1737
1738/* on error free sesinfo and tcon struct if needed */
1739 if (rc) {
1740 /* if session setup failed, use count is zero but
1741 we still need to free cifsd thread */
1742 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1743 spin_lock(&GlobalMid_Lock);
1744 srvTcp->tcpStatus = CifsExiting;
1745 spin_unlock(&GlobalMid_Lock);
1746 if(srvTcp->tsk)
1747 send_sig(SIGKILL,srvTcp->tsk,1);
1748 }
1749 /* If find_unc succeeded then rc == 0 so we can not end */
1750 if (tcon) /* up accidently freeing someone elses tcon struct */
1751 tconInfoFree(tcon);
1752 if (existingCifsSes == NULL) {
1753 if (pSesInfo) {
1754 if ((pSesInfo->server) &&
1755 (pSesInfo->status == CifsGood)) {
1756 int temp_rc;
1757 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1758 /* if the socketUseCount is now zero */
1759 if((temp_rc == -ESHUTDOWN) &&
1760 (pSesInfo->server->tsk))
1761 send_sig(SIGKILL,pSesInfo->server->tsk,1);
1762 } else
1763 cFYI(1, ("No session or bad tcon"));
1764 sesInfoFree(pSesInfo);
1765 /* pSesInfo = NULL; */
1766 }
1767 }
1768 } else {
1769 atomic_inc(&tcon->useCount);
1770 cifs_sb->tcon = tcon;
1771 tcon->ses = pSesInfo;
1772
1773 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001774 CIFSSMBQFSDeviceInfo(xid, tcon);
1775 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001777 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 if(!volume_info.no_psx_acl) {
1779 if(CIFS_UNIX_POSIX_ACL_CAP &
1780 le64_to_cpu(tcon->fsUnixInfo.Capability))
1781 cFYI(1,("server negotiated posix acl support"));
1782 sb->s_flags |= MS_POSIXACL;
1783 }
1784 }
1785 }
1786 }
1787
1788 /* volume_info.password is freed above when existing session found
1789 (in which case it is not needed anymore) but when new sesion is created
1790 the password ptr is put in the new session structure (in which case the
1791 password will be freed at unmount time) */
1792 if(volume_info.UNC)
1793 kfree(volume_info.UNC);
1794 FreeXid(xid);
1795 return rc;
1796}
1797
1798static int
1799CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1800 char session_key[CIFS_SESSION_KEY_SIZE],
1801 const struct nls_table *nls_codepage)
1802{
1803 struct smb_hdr *smb_buffer;
1804 struct smb_hdr *smb_buffer_response;
1805 SESSION_SETUP_ANDX *pSMB;
1806 SESSION_SETUP_ANDX *pSMBr;
1807 char *bcc_ptr;
1808 char *user;
1809 char *domain;
1810 int rc = 0;
1811 int remaining_words = 0;
1812 int bytes_returned = 0;
1813 int len;
1814 __u32 capabilities;
1815 __u16 count;
1816
1817 cFYI(1, ("In sesssetup "));
1818 if(ses == NULL)
1819 return -EINVAL;
1820 user = ses->userName;
1821 domain = ses->domainName;
1822 smb_buffer = cifs_buf_get();
1823 if (smb_buffer == NULL) {
1824 return -ENOMEM;
1825 }
1826 smb_buffer_response = smb_buffer;
1827 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1828
1829 /* send SMBsessionSetup here */
1830 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1831 NULL /* no tCon exists yet */ , 13 /* wct */ );
1832
1833 pSMB->req_no_secext.AndXCommand = 0xFF;
1834 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1835 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1836
1837 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1838 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1839
1840 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1841 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1842 if (ses->capabilities & CAP_UNICODE) {
1843 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1844 capabilities |= CAP_UNICODE;
1845 }
1846 if (ses->capabilities & CAP_STATUS32) {
1847 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1848 capabilities |= CAP_STATUS32;
1849 }
1850 if (ses->capabilities & CAP_DFS) {
1851 smb_buffer->Flags2 |= SMBFLG2_DFS;
1852 capabilities |= CAP_DFS;
1853 }
1854 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1855
1856 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1857 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1858
1859 pSMB->req_no_secext.CaseSensitivePasswordLength =
1860 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1861 bcc_ptr = pByteArea(smb_buffer);
1862 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1863 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1864 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1865 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1866
1867 if (ses->capabilities & CAP_UNICODE) {
1868 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1869 *bcc_ptr = 0;
1870 bcc_ptr++;
1871 }
1872 if(user == NULL)
1873 bytes_returned = 0; /* skill null user */
1874 else
1875 bytes_returned =
1876 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1877 nls_codepage);
1878 /* convert number of 16 bit words to bytes */
1879 bcc_ptr += 2 * bytes_returned;
1880 bcc_ptr += 2; /* trailing null */
1881 if (domain == NULL)
1882 bytes_returned =
1883 cifs_strtoUCS((wchar_t *) bcc_ptr,
1884 "CIFS_LINUX_DOM", 32, nls_codepage);
1885 else
1886 bytes_returned =
1887 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1888 nls_codepage);
1889 bcc_ptr += 2 * bytes_returned;
1890 bcc_ptr += 2;
1891 bytes_returned =
1892 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1893 32, nls_codepage);
1894 bcc_ptr += 2 * bytes_returned;
1895 bytes_returned =
1896 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1897 32, nls_codepage);
1898 bcc_ptr += 2 * bytes_returned;
1899 bcc_ptr += 2;
1900 bytes_returned =
1901 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1902 64, nls_codepage);
1903 bcc_ptr += 2 * bytes_returned;
1904 bcc_ptr += 2;
1905 } else {
1906 if(user != NULL) {
1907 strncpy(bcc_ptr, user, 200);
1908 bcc_ptr += strnlen(user, 200);
1909 }
1910 *bcc_ptr = 0;
1911 bcc_ptr++;
1912 if (domain == NULL) {
1913 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
1914 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
1915 } else {
1916 strncpy(bcc_ptr, domain, 64);
1917 bcc_ptr += strnlen(domain, 64);
1918 *bcc_ptr = 0;
1919 bcc_ptr++;
1920 }
1921 strcpy(bcc_ptr, "Linux version ");
1922 bcc_ptr += strlen("Linux version ");
1923 strcpy(bcc_ptr, system_utsname.release);
1924 bcc_ptr += strlen(system_utsname.release) + 1;
1925 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
1926 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
1927 }
1928 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
1929 smb_buffer->smb_buf_length += count;
1930 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
1931
1932 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
1933 &bytes_returned, 1);
1934 if (rc) {
1935/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
1936 } else if ((smb_buffer_response->WordCount == 3)
1937 || (smb_buffer_response->WordCount == 4)) {
1938 __u16 action = le16_to_cpu(pSMBr->resp.Action);
1939 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
1940 if (action & GUEST_LOGIN)
1941 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
1942 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
1943 cFYI(1, ("UID = %d ", ses->Suid));
1944 /* response can have either 3 or 4 word count - Samba sends 3 */
1945 bcc_ptr = pByteArea(smb_buffer_response);
1946 if ((pSMBr->resp.hdr.WordCount == 3)
1947 || ((pSMBr->resp.hdr.WordCount == 4)
1948 && (blob_len < pSMBr->resp.ByteCount))) {
1949 if (pSMBr->resp.hdr.WordCount == 4)
1950 bcc_ptr += blob_len;
1951
1952 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
1953 if ((long) (bcc_ptr) % 2) {
1954 remaining_words =
1955 (BCC(smb_buffer_response) - 1) /2;
1956 bcc_ptr++; /* Unicode strings must be word aligned */
1957 } else {
1958 remaining_words =
1959 BCC(smb_buffer_response) / 2;
1960 }
1961 len =
1962 UniStrnlen((wchar_t *) bcc_ptr,
1963 remaining_words - 1);
1964/* We look for obvious messed up bcc or strings in response so we do not go off
1965 the end since (at least) WIN2K and Windows XP have a major bug in not null
1966 terminating last Unicode string in response */
Pekka Enberge915fc42005-09-06 15:18:35 -07001967 ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07001968 if(ses->serverOS == NULL)
1969 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 cifs_strfromUCS_le(ses->serverOS,
1971 (wchar_t *)bcc_ptr, len,nls_codepage);
1972 bcc_ptr += 2 * (len + 1);
1973 remaining_words -= len + 1;
1974 ses->serverOS[2 * len] = 0;
1975 ses->serverOS[1 + (2 * len)] = 0;
1976 if (remaining_words > 0) {
1977 len = UniStrnlen((wchar_t *)bcc_ptr,
1978 remaining_words-1);
Pekka Enberge915fc42005-09-06 15:18:35 -07001979 ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07001980 if(ses->serverNOS == NULL)
1981 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 cifs_strfromUCS_le(ses->serverNOS,
1983 (wchar_t *)bcc_ptr,len,nls_codepage);
1984 bcc_ptr += 2 * (len + 1);
1985 ses->serverNOS[2 * len] = 0;
1986 ses->serverNOS[1 + (2 * len)] = 0;
1987 if(strncmp(ses->serverNOS,
1988 "NT LAN Manager 4",16) == 0) {
1989 cFYI(1,("NT4 server"));
1990 ses->flags |= CIFS_SES_NT4;
1991 }
1992 remaining_words -= len + 1;
1993 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07001994 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
1996 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07001997 kzalloc(2*(len+1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07001998 if(ses->serverDomain == NULL)
1999 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 cifs_strfromUCS_le(ses->serverDomain,
2001 (wchar_t *)bcc_ptr,len,nls_codepage);
2002 bcc_ptr += 2 * (len + 1);
2003 ses->serverDomain[2*len] = 0;
2004 ses->serverDomain[1+(2*len)] = 0;
2005 } /* else no more room so create dummy domain string */
2006 else
Steve French433dc242005-04-28 22:41:08 -07002007 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002008 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002010 /* if these kcallocs fail not much we
2011 can do, but better to not fail the
2012 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002014 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002016 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 }
2018 } else { /* ASCII */
2019 len = strnlen(bcc_ptr, 1024);
2020 if (((long) bcc_ptr + len) - (long)
2021 pByteArea(smb_buffer_response)
2022 <= BCC(smb_buffer_response)) {
Pekka Enberge915fc42005-09-06 15:18:35 -07002023 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002024 if(ses->serverOS == NULL)
2025 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 strncpy(ses->serverOS,bcc_ptr, len);
2027
2028 bcc_ptr += len;
2029 bcc_ptr[0] = 0; /* null terminate the string */
2030 bcc_ptr++;
2031
2032 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002033 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002034 if(ses->serverNOS == NULL)
2035 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 strncpy(ses->serverNOS, bcc_ptr, len);
2037 bcc_ptr += len;
2038 bcc_ptr[0] = 0;
2039 bcc_ptr++;
2040
2041 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002042 ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002043 if(ses->serverDomain == NULL)
2044 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 strncpy(ses->serverDomain, bcc_ptr, len);
2046 bcc_ptr += len;
2047 bcc_ptr[0] = 0;
2048 bcc_ptr++;
2049 } else
2050 cFYI(1,
2051 ("Variable field of length %d extends beyond end of smb ",
2052 len));
2053 }
2054 } else {
2055 cERROR(1,
2056 (" Security Blob Length extends beyond end of SMB"));
2057 }
2058 } else {
2059 cERROR(1,
2060 (" Invalid Word count %d: ",
2061 smb_buffer_response->WordCount));
2062 rc = -EIO;
2063 }
Steve French433dc242005-04-28 22:41:08 -07002064sesssetup_nomem: /* do not return an error on nomem for the info strings,
2065 since that could make reconnection harder, and
2066 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 if (smb_buffer)
2068 cifs_buf_release(smb_buffer);
2069
2070 return rc;
2071}
2072
2073static int
2074CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2075 char *SecurityBlob,int SecurityBlobLength,
2076 const struct nls_table *nls_codepage)
2077{
2078 struct smb_hdr *smb_buffer;
2079 struct smb_hdr *smb_buffer_response;
2080 SESSION_SETUP_ANDX *pSMB;
2081 SESSION_SETUP_ANDX *pSMBr;
2082 char *bcc_ptr;
2083 char *user;
2084 char *domain;
2085 int rc = 0;
2086 int remaining_words = 0;
2087 int bytes_returned = 0;
2088 int len;
2089 __u32 capabilities;
2090 __u16 count;
2091
2092 cFYI(1, ("In spnego sesssetup "));
2093 if(ses == NULL)
2094 return -EINVAL;
2095 user = ses->userName;
2096 domain = ses->domainName;
2097
2098 smb_buffer = cifs_buf_get();
2099 if (smb_buffer == NULL) {
2100 return -ENOMEM;
2101 }
2102 smb_buffer_response = smb_buffer;
2103 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2104
2105 /* send SMBsessionSetup here */
2106 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2107 NULL /* no tCon exists yet */ , 12 /* wct */ );
2108 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2109 pSMB->req.AndXCommand = 0xFF;
2110 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2111 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2112
2113 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2114 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2115
2116 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2117 CAP_EXTENDED_SECURITY;
2118 if (ses->capabilities & CAP_UNICODE) {
2119 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2120 capabilities |= CAP_UNICODE;
2121 }
2122 if (ses->capabilities & CAP_STATUS32) {
2123 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2124 capabilities |= CAP_STATUS32;
2125 }
2126 if (ses->capabilities & CAP_DFS) {
2127 smb_buffer->Flags2 |= SMBFLG2_DFS;
2128 capabilities |= CAP_DFS;
2129 }
2130 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2131
2132 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2133 bcc_ptr = pByteArea(smb_buffer);
2134 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2135 bcc_ptr += SecurityBlobLength;
2136
2137 if (ses->capabilities & CAP_UNICODE) {
2138 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2139 *bcc_ptr = 0;
2140 bcc_ptr++;
2141 }
2142 bytes_returned =
2143 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2144 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2145 bcc_ptr += 2; /* trailing null */
2146 if (domain == NULL)
2147 bytes_returned =
2148 cifs_strtoUCS((wchar_t *) bcc_ptr,
2149 "CIFS_LINUX_DOM", 32, nls_codepage);
2150 else
2151 bytes_returned =
2152 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2153 nls_codepage);
2154 bcc_ptr += 2 * bytes_returned;
2155 bcc_ptr += 2;
2156 bytes_returned =
2157 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2158 32, nls_codepage);
2159 bcc_ptr += 2 * bytes_returned;
2160 bytes_returned =
2161 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2162 nls_codepage);
2163 bcc_ptr += 2 * bytes_returned;
2164 bcc_ptr += 2;
2165 bytes_returned =
2166 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2167 64, nls_codepage);
2168 bcc_ptr += 2 * bytes_returned;
2169 bcc_ptr += 2;
2170 } else {
2171 strncpy(bcc_ptr, user, 200);
2172 bcc_ptr += strnlen(user, 200);
2173 *bcc_ptr = 0;
2174 bcc_ptr++;
2175 if (domain == NULL) {
2176 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2177 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2178 } else {
2179 strncpy(bcc_ptr, domain, 64);
2180 bcc_ptr += strnlen(domain, 64);
2181 *bcc_ptr = 0;
2182 bcc_ptr++;
2183 }
2184 strcpy(bcc_ptr, "Linux version ");
2185 bcc_ptr += strlen("Linux version ");
2186 strcpy(bcc_ptr, system_utsname.release);
2187 bcc_ptr += strlen(system_utsname.release) + 1;
2188 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2189 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2190 }
2191 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2192 smb_buffer->smb_buf_length += count;
2193 pSMB->req.ByteCount = cpu_to_le16(count);
2194
2195 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2196 &bytes_returned, 1);
2197 if (rc) {
2198/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2199 } else if ((smb_buffer_response->WordCount == 3)
2200 || (smb_buffer_response->WordCount == 4)) {
2201 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2202 __u16 blob_len =
2203 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2204 if (action & GUEST_LOGIN)
2205 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2206 if (ses) {
2207 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2208 cFYI(1, ("UID = %d ", ses->Suid));
2209 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2210
2211 /* BB Fix below to make endian neutral !! */
2212
2213 if ((pSMBr->resp.hdr.WordCount == 3)
2214 || ((pSMBr->resp.hdr.WordCount == 4)
2215 && (blob_len <
2216 pSMBr->resp.ByteCount))) {
2217 if (pSMBr->resp.hdr.WordCount == 4) {
2218 bcc_ptr +=
2219 blob_len;
2220 cFYI(1,
2221 ("Security Blob Length %d ",
2222 blob_len));
2223 }
2224
2225 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2226 if ((long) (bcc_ptr) % 2) {
2227 remaining_words =
2228 (BCC(smb_buffer_response)
2229 - 1) / 2;
2230 bcc_ptr++; /* Unicode strings must be word aligned */
2231 } else {
2232 remaining_words =
2233 BCC
2234 (smb_buffer_response) / 2;
2235 }
2236 len =
2237 UniStrnlen((wchar_t *) bcc_ptr,
2238 remaining_words - 1);
2239/* We look for obvious messed up bcc or strings in response so we do not go off
2240 the end since (at least) WIN2K and Windows XP have a major bug in not null
2241 terminating last Unicode string in response */
2242 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002243 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 cifs_strfromUCS_le(ses->serverOS,
2245 (wchar_t *)
2246 bcc_ptr, len,
2247 nls_codepage);
2248 bcc_ptr += 2 * (len + 1);
2249 remaining_words -= len + 1;
2250 ses->serverOS[2 * len] = 0;
2251 ses->serverOS[1 + (2 * len)] = 0;
2252 if (remaining_words > 0) {
2253 len = UniStrnlen((wchar_t *)bcc_ptr,
2254 remaining_words
2255 - 1);
2256 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002257 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 GFP_KERNEL);
2259 cifs_strfromUCS_le(ses->serverNOS,
2260 (wchar_t *)bcc_ptr,
2261 len,
2262 nls_codepage);
2263 bcc_ptr += 2 * (len + 1);
2264 ses->serverNOS[2 * len] = 0;
2265 ses->serverNOS[1 + (2 * len)] = 0;
2266 remaining_words -= len + 1;
2267 if (remaining_words > 0) {
2268 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2269 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Pekka Enberge915fc42005-09-06 15:18:35 -07002270 ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 cifs_strfromUCS_le(ses->serverDomain,
2272 (wchar_t *)bcc_ptr,
2273 len,
2274 nls_codepage);
2275 bcc_ptr += 2*(len+1);
2276 ses->serverDomain[2*len] = 0;
2277 ses->serverDomain[1+(2*len)] = 0;
2278 } /* else no more room so create dummy domain string */
2279 else
2280 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002281 kzalloc(2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 } else { /* no room so create dummy domain and NOS string */
Pekka Enberge915fc42005-09-06 15:18:35 -07002283 ses->serverDomain = kzalloc(2, GFP_KERNEL);
2284 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 }
2286 } else { /* ASCII */
2287
2288 len = strnlen(bcc_ptr, 1024);
2289 if (((long) bcc_ptr + len) - (long)
2290 pByteArea(smb_buffer_response)
2291 <= BCC(smb_buffer_response)) {
Pekka Enberge915fc42005-09-06 15:18:35 -07002292 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 strncpy(ses->serverOS, bcc_ptr, len);
2294
2295 bcc_ptr += len;
2296 bcc_ptr[0] = 0; /* null terminate the string */
2297 bcc_ptr++;
2298
2299 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002300 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 strncpy(ses->serverNOS, bcc_ptr, len);
2302 bcc_ptr += len;
2303 bcc_ptr[0] = 0;
2304 bcc_ptr++;
2305
2306 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07002307 ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 strncpy(ses->serverDomain, bcc_ptr, len);
2309 bcc_ptr += len;
2310 bcc_ptr[0] = 0;
2311 bcc_ptr++;
2312 } else
2313 cFYI(1,
2314 ("Variable field of length %d extends beyond end of smb ",
2315 len));
2316 }
2317 } else {
2318 cERROR(1,
2319 (" Security Blob Length extends beyond end of SMB"));
2320 }
2321 } else {
2322 cERROR(1, ("No session structure passed in."));
2323 }
2324 } else {
2325 cERROR(1,
2326 (" Invalid Word count %d: ",
2327 smb_buffer_response->WordCount));
2328 rc = -EIO;
2329 }
2330
2331 if (smb_buffer)
2332 cifs_buf_release(smb_buffer);
2333
2334 return rc;
2335}
2336
2337static int
2338CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2339 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2340 const struct nls_table *nls_codepage)
2341{
2342 struct smb_hdr *smb_buffer;
2343 struct smb_hdr *smb_buffer_response;
2344 SESSION_SETUP_ANDX *pSMB;
2345 SESSION_SETUP_ANDX *pSMBr;
2346 char *bcc_ptr;
2347 char *domain;
2348 int rc = 0;
2349 int remaining_words = 0;
2350 int bytes_returned = 0;
2351 int len;
2352 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2353 PNEGOTIATE_MESSAGE SecurityBlob;
2354 PCHALLENGE_MESSAGE SecurityBlob2;
2355 __u32 negotiate_flags, capabilities;
2356 __u16 count;
2357
2358 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2359 if(ses == NULL)
2360 return -EINVAL;
2361 domain = ses->domainName;
2362 *pNTLMv2_flag = FALSE;
2363 smb_buffer = cifs_buf_get();
2364 if (smb_buffer == NULL) {
2365 return -ENOMEM;
2366 }
2367 smb_buffer_response = smb_buffer;
2368 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2369 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2370
2371 /* send SMBsessionSetup here */
2372 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2373 NULL /* no tCon exists yet */ , 12 /* wct */ );
2374 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2375 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2376
2377 pSMB->req.AndXCommand = 0xFF;
2378 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2379 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2380
2381 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2382 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2383
2384 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2385 CAP_EXTENDED_SECURITY;
2386 if (ses->capabilities & CAP_UNICODE) {
2387 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2388 capabilities |= CAP_UNICODE;
2389 }
2390 if (ses->capabilities & CAP_STATUS32) {
2391 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2392 capabilities |= CAP_STATUS32;
2393 }
2394 if (ses->capabilities & CAP_DFS) {
2395 smb_buffer->Flags2 |= SMBFLG2_DFS;
2396 capabilities |= CAP_DFS;
2397 }
2398 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2399
2400 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2401 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2402 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2403 SecurityBlob->MessageType = NtLmNegotiate;
2404 negotiate_flags =
2405 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2406 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2407 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2408 if(sign_CIFS_PDUs)
2409 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2410 if(ntlmv2_support)
2411 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2412 /* setup pointers to domain name and workstation name */
2413 bcc_ptr += SecurityBlobLength;
2414
2415 SecurityBlob->WorkstationName.Buffer = 0;
2416 SecurityBlob->WorkstationName.Length = 0;
2417 SecurityBlob->WorkstationName.MaximumLength = 0;
2418
2419 if (domain == NULL) {
2420 SecurityBlob->DomainName.Buffer = 0;
2421 SecurityBlob->DomainName.Length = 0;
2422 SecurityBlob->DomainName.MaximumLength = 0;
2423 } else {
2424 __u16 len;
2425 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2426 strncpy(bcc_ptr, domain, 63);
2427 len = strnlen(domain, 64);
2428 SecurityBlob->DomainName.MaximumLength =
2429 cpu_to_le16(len);
2430 SecurityBlob->DomainName.Buffer =
2431 cpu_to_le32((long) &SecurityBlob->
2432 DomainString -
2433 (long) &SecurityBlob->Signature);
2434 bcc_ptr += len;
2435 SecurityBlobLength += len;
2436 SecurityBlob->DomainName.Length =
2437 cpu_to_le16(len);
2438 }
2439 if (ses->capabilities & CAP_UNICODE) {
2440 if ((long) bcc_ptr % 2) {
2441 *bcc_ptr = 0;
2442 bcc_ptr++;
2443 }
2444
2445 bytes_returned =
2446 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2447 32, nls_codepage);
2448 bcc_ptr += 2 * bytes_returned;
2449 bytes_returned =
2450 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2451 nls_codepage);
2452 bcc_ptr += 2 * bytes_returned;
2453 bcc_ptr += 2; /* null terminate Linux version */
2454 bytes_returned =
2455 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2456 64, nls_codepage);
2457 bcc_ptr += 2 * bytes_returned;
2458 *(bcc_ptr + 1) = 0;
2459 *(bcc_ptr + 2) = 0;
2460 bcc_ptr += 2; /* null terminate network opsys string */
2461 *(bcc_ptr + 1) = 0;
2462 *(bcc_ptr + 2) = 0;
2463 bcc_ptr += 2; /* null domain */
2464 } else { /* ASCII */
2465 strcpy(bcc_ptr, "Linux version ");
2466 bcc_ptr += strlen("Linux version ");
2467 strcpy(bcc_ptr, system_utsname.release);
2468 bcc_ptr += strlen(system_utsname.release) + 1;
2469 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2470 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2471 bcc_ptr++; /* empty domain field */
2472 *bcc_ptr = 0;
2473 }
2474 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2475 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2476 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2477 smb_buffer->smb_buf_length += count;
2478 pSMB->req.ByteCount = cpu_to_le16(count);
2479
2480 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2481 &bytes_returned, 1);
2482
2483 if (smb_buffer_response->Status.CifsError ==
2484 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2485 rc = 0;
2486
2487 if (rc) {
2488/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2489 } else if ((smb_buffer_response->WordCount == 3)
2490 || (smb_buffer_response->WordCount == 4)) {
2491 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2492 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2493
2494 if (action & GUEST_LOGIN)
2495 cFYI(1, (" Guest login"));
2496 /* Do we want to set anything in SesInfo struct when guest login? */
2497
2498 bcc_ptr = pByteArea(smb_buffer_response);
2499 /* response can have either 3 or 4 word count - Samba sends 3 */
2500
2501 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2502 if (SecurityBlob2->MessageType != NtLmChallenge) {
2503 cFYI(1,
2504 ("Unexpected NTLMSSP message type received %d",
2505 SecurityBlob2->MessageType));
2506 } else if (ses) {
2507 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2508 cFYI(1, ("UID = %d ", ses->Suid));
2509 if ((pSMBr->resp.hdr.WordCount == 3)
2510 || ((pSMBr->resp.hdr.WordCount == 4)
2511 && (blob_len <
2512 pSMBr->resp.ByteCount))) {
2513
2514 if (pSMBr->resp.hdr.WordCount == 4) {
2515 bcc_ptr += blob_len;
2516 cFYI(1,
2517 ("Security Blob Length %d ",
2518 blob_len));
2519 }
2520
2521 cFYI(1, ("NTLMSSP Challenge rcvd "));
2522
2523 memcpy(ses->server->cryptKey,
2524 SecurityBlob2->Challenge,
2525 CIFS_CRYPTO_KEY_SIZE);
2526 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2527 *pNTLMv2_flag = TRUE;
2528
2529 if((SecurityBlob2->NegotiateFlags &
2530 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2531 || (sign_CIFS_PDUs > 1))
2532 ses->server->secMode |=
2533 SECMODE_SIGN_REQUIRED;
2534 if ((SecurityBlob2->NegotiateFlags &
2535 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2536 ses->server->secMode |=
2537 SECMODE_SIGN_ENABLED;
2538
2539 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2540 if ((long) (bcc_ptr) % 2) {
2541 remaining_words =
2542 (BCC(smb_buffer_response)
2543 - 1) / 2;
2544 bcc_ptr++; /* Unicode strings must be word aligned */
2545 } else {
2546 remaining_words =
2547 BCC
2548 (smb_buffer_response) / 2;
2549 }
2550 len =
2551 UniStrnlen((wchar_t *) bcc_ptr,
2552 remaining_words - 1);
2553/* We look for obvious messed up bcc or strings in response so we do not go off
2554 the end since (at least) WIN2K and Windows XP have a major bug in not null
2555 terminating last Unicode string in response */
2556 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002557 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 cifs_strfromUCS_le(ses->serverOS,
2559 (wchar_t *)
2560 bcc_ptr, len,
2561 nls_codepage);
2562 bcc_ptr += 2 * (len + 1);
2563 remaining_words -= len + 1;
2564 ses->serverOS[2 * len] = 0;
2565 ses->serverOS[1 + (2 * len)] = 0;
2566 if (remaining_words > 0) {
2567 len = UniStrnlen((wchar_t *)
2568 bcc_ptr,
2569 remaining_words
2570 - 1);
2571 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002572 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 GFP_KERNEL);
2574 cifs_strfromUCS_le(ses->
2575 serverNOS,
2576 (wchar_t *)
2577 bcc_ptr,
2578 len,
2579 nls_codepage);
2580 bcc_ptr += 2 * (len + 1);
2581 ses->serverNOS[2 * len] = 0;
2582 ses->serverNOS[1 +
2583 (2 * len)] = 0;
2584 remaining_words -= len + 1;
2585 if (remaining_words > 0) {
2586 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2587 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2588 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002589 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 (len +
2591 1),
2592 GFP_KERNEL);
2593 cifs_strfromUCS_le
2594 (ses->
2595 serverDomain,
2596 (wchar_t *)
2597 bcc_ptr, len,
2598 nls_codepage);
2599 bcc_ptr +=
2600 2 * (len + 1);
2601 ses->
2602 serverDomain[2
2603 * len]
2604 = 0;
2605 ses->
2606 serverDomain[1
2607 +
2608 (2
2609 *
2610 len)]
2611 = 0;
2612 } /* else no more room so create dummy domain string */
2613 else
2614 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002615 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 GFP_KERNEL);
2617 } else { /* no room so create dummy domain and NOS string */
2618 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002619 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002621 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 }
2623 } else { /* ASCII */
2624 len = strnlen(bcc_ptr, 1024);
2625 if (((long) bcc_ptr + len) - (long)
2626 pByteArea(smb_buffer_response)
2627 <= BCC(smb_buffer_response)) {
2628 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002629 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 GFP_KERNEL);
2631 strncpy(ses->serverOS,
2632 bcc_ptr, len);
2633
2634 bcc_ptr += len;
2635 bcc_ptr[0] = 0; /* null terminate string */
2636 bcc_ptr++;
2637
2638 len = strnlen(bcc_ptr, 1024);
2639 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002640 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 GFP_KERNEL);
2642 strncpy(ses->serverNOS, bcc_ptr, len);
2643 bcc_ptr += len;
2644 bcc_ptr[0] = 0;
2645 bcc_ptr++;
2646
2647 len = strnlen(bcc_ptr, 1024);
2648 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002649 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 GFP_KERNEL);
2651 strncpy(ses->serverDomain, bcc_ptr, len);
2652 bcc_ptr += len;
2653 bcc_ptr[0] = 0;
2654 bcc_ptr++;
2655 } else
2656 cFYI(1,
2657 ("Variable field of length %d extends beyond end of smb ",
2658 len));
2659 }
2660 } else {
2661 cERROR(1,
2662 (" Security Blob Length extends beyond end of SMB"));
2663 }
2664 } else {
2665 cERROR(1, ("No session structure passed in."));
2666 }
2667 } else {
2668 cERROR(1,
2669 (" Invalid Word count %d: ",
2670 smb_buffer_response->WordCount));
2671 rc = -EIO;
2672 }
2673
2674 if (smb_buffer)
2675 cifs_buf_release(smb_buffer);
2676
2677 return rc;
2678}
2679static int
2680CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2681 char *ntlm_session_key, int ntlmv2_flag,
2682 const struct nls_table *nls_codepage)
2683{
2684 struct smb_hdr *smb_buffer;
2685 struct smb_hdr *smb_buffer_response;
2686 SESSION_SETUP_ANDX *pSMB;
2687 SESSION_SETUP_ANDX *pSMBr;
2688 char *bcc_ptr;
2689 char *user;
2690 char *domain;
2691 int rc = 0;
2692 int remaining_words = 0;
2693 int bytes_returned = 0;
2694 int len;
2695 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2696 PAUTHENTICATE_MESSAGE SecurityBlob;
2697 __u32 negotiate_flags, capabilities;
2698 __u16 count;
2699
2700 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2701 if(ses == NULL)
2702 return -EINVAL;
2703 user = ses->userName;
2704 domain = ses->domainName;
2705 smb_buffer = cifs_buf_get();
2706 if (smb_buffer == NULL) {
2707 return -ENOMEM;
2708 }
2709 smb_buffer_response = smb_buffer;
2710 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2711 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2712
2713 /* send SMBsessionSetup here */
2714 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2715 NULL /* no tCon exists yet */ , 12 /* wct */ );
2716 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2717 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2718 pSMB->req.AndXCommand = 0xFF;
2719 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2720 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2721
2722 pSMB->req.hdr.Uid = ses->Suid;
2723
2724 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2725 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2726
2727 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2728 CAP_EXTENDED_SECURITY;
2729 if (ses->capabilities & CAP_UNICODE) {
2730 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2731 capabilities |= CAP_UNICODE;
2732 }
2733 if (ses->capabilities & CAP_STATUS32) {
2734 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2735 capabilities |= CAP_STATUS32;
2736 }
2737 if (ses->capabilities & CAP_DFS) {
2738 smb_buffer->Flags2 |= SMBFLG2_DFS;
2739 capabilities |= CAP_DFS;
2740 }
2741 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2742
2743 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2744 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2745 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2746 SecurityBlob->MessageType = NtLmAuthenticate;
2747 bcc_ptr += SecurityBlobLength;
2748 negotiate_flags =
2749 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2750 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2751 0x80000000 | NTLMSSP_NEGOTIATE_128;
2752 if(sign_CIFS_PDUs)
2753 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2754 if(ntlmv2_flag)
2755 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2756
2757/* setup pointers to domain name and workstation name */
2758
2759 SecurityBlob->WorkstationName.Buffer = 0;
2760 SecurityBlob->WorkstationName.Length = 0;
2761 SecurityBlob->WorkstationName.MaximumLength = 0;
2762 SecurityBlob->SessionKey.Length = 0;
2763 SecurityBlob->SessionKey.MaximumLength = 0;
2764 SecurityBlob->SessionKey.Buffer = 0;
2765
2766 SecurityBlob->LmChallengeResponse.Length = 0;
2767 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2768 SecurityBlob->LmChallengeResponse.Buffer = 0;
2769
2770 SecurityBlob->NtChallengeResponse.Length =
2771 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2772 SecurityBlob->NtChallengeResponse.MaximumLength =
2773 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2774 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2775 SecurityBlob->NtChallengeResponse.Buffer =
2776 cpu_to_le32(SecurityBlobLength);
2777 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2778 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2779
2780 if (ses->capabilities & CAP_UNICODE) {
2781 if (domain == NULL) {
2782 SecurityBlob->DomainName.Buffer = 0;
2783 SecurityBlob->DomainName.Length = 0;
2784 SecurityBlob->DomainName.MaximumLength = 0;
2785 } else {
2786 __u16 len =
2787 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2788 nls_codepage);
2789 len *= 2;
2790 SecurityBlob->DomainName.MaximumLength =
2791 cpu_to_le16(len);
2792 SecurityBlob->DomainName.Buffer =
2793 cpu_to_le32(SecurityBlobLength);
2794 bcc_ptr += len;
2795 SecurityBlobLength += len;
2796 SecurityBlob->DomainName.Length =
2797 cpu_to_le16(len);
2798 }
2799 if (user == NULL) {
2800 SecurityBlob->UserName.Buffer = 0;
2801 SecurityBlob->UserName.Length = 0;
2802 SecurityBlob->UserName.MaximumLength = 0;
2803 } else {
2804 __u16 len =
2805 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2806 nls_codepage);
2807 len *= 2;
2808 SecurityBlob->UserName.MaximumLength =
2809 cpu_to_le16(len);
2810 SecurityBlob->UserName.Buffer =
2811 cpu_to_le32(SecurityBlobLength);
2812 bcc_ptr += len;
2813 SecurityBlobLength += len;
2814 SecurityBlob->UserName.Length =
2815 cpu_to_le16(len);
2816 }
2817
2818 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2819 SecurityBlob->WorkstationName.Length *= 2;
2820 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2821 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2822 bcc_ptr += SecurityBlob->WorkstationName.Length;
2823 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2824 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2825
2826 if ((long) bcc_ptr % 2) {
2827 *bcc_ptr = 0;
2828 bcc_ptr++;
2829 }
2830 bytes_returned =
2831 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2832 32, nls_codepage);
2833 bcc_ptr += 2 * bytes_returned;
2834 bytes_returned =
2835 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2836 nls_codepage);
2837 bcc_ptr += 2 * bytes_returned;
2838 bcc_ptr += 2; /* null term version string */
2839 bytes_returned =
2840 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2841 64, nls_codepage);
2842 bcc_ptr += 2 * bytes_returned;
2843 *(bcc_ptr + 1) = 0;
2844 *(bcc_ptr + 2) = 0;
2845 bcc_ptr += 2; /* null terminate network opsys string */
2846 *(bcc_ptr + 1) = 0;
2847 *(bcc_ptr + 2) = 0;
2848 bcc_ptr += 2; /* null domain */
2849 } else { /* ASCII */
2850 if (domain == NULL) {
2851 SecurityBlob->DomainName.Buffer = 0;
2852 SecurityBlob->DomainName.Length = 0;
2853 SecurityBlob->DomainName.MaximumLength = 0;
2854 } else {
2855 __u16 len;
2856 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2857 strncpy(bcc_ptr, domain, 63);
2858 len = strnlen(domain, 64);
2859 SecurityBlob->DomainName.MaximumLength =
2860 cpu_to_le16(len);
2861 SecurityBlob->DomainName.Buffer =
2862 cpu_to_le32(SecurityBlobLength);
2863 bcc_ptr += len;
2864 SecurityBlobLength += len;
2865 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2866 }
2867 if (user == NULL) {
2868 SecurityBlob->UserName.Buffer = 0;
2869 SecurityBlob->UserName.Length = 0;
2870 SecurityBlob->UserName.MaximumLength = 0;
2871 } else {
2872 __u16 len;
2873 strncpy(bcc_ptr, user, 63);
2874 len = strnlen(user, 64);
2875 SecurityBlob->UserName.MaximumLength =
2876 cpu_to_le16(len);
2877 SecurityBlob->UserName.Buffer =
2878 cpu_to_le32(SecurityBlobLength);
2879 bcc_ptr += len;
2880 SecurityBlobLength += len;
2881 SecurityBlob->UserName.Length = cpu_to_le16(len);
2882 }
2883 /* BB fill in our workstation name if known BB */
2884
2885 strcpy(bcc_ptr, "Linux version ");
2886 bcc_ptr += strlen("Linux version ");
2887 strcpy(bcc_ptr, system_utsname.release);
2888 bcc_ptr += strlen(system_utsname.release) + 1;
2889 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2890 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2891 bcc_ptr++; /* null domain */
2892 *bcc_ptr = 0;
2893 }
2894 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2895 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2896 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2897 smb_buffer->smb_buf_length += count;
2898 pSMB->req.ByteCount = cpu_to_le16(count);
2899
2900 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2901 &bytes_returned, 1);
2902 if (rc) {
2903/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2904 } else if ((smb_buffer_response->WordCount == 3)
2905 || (smb_buffer_response->WordCount == 4)) {
2906 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2907 __u16 blob_len =
2908 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2909 if (action & GUEST_LOGIN)
2910 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2911/* if(SecurityBlob2->MessageType != NtLm??){
2912 cFYI("Unexpected message type on auth response is %d "));
2913 } */
2914 if (ses) {
2915 cFYI(1,
2916 ("Does UID on challenge %d match auth response UID %d ",
2917 ses->Suid, smb_buffer_response->Uid));
2918 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2919 bcc_ptr = pByteArea(smb_buffer_response);
2920 /* response can have either 3 or 4 word count - Samba sends 3 */
2921 if ((pSMBr->resp.hdr.WordCount == 3)
2922 || ((pSMBr->resp.hdr.WordCount == 4)
2923 && (blob_len <
2924 pSMBr->resp.ByteCount))) {
2925 if (pSMBr->resp.hdr.WordCount == 4) {
2926 bcc_ptr +=
2927 blob_len;
2928 cFYI(1,
2929 ("Security Blob Length %d ",
2930 blob_len));
2931 }
2932
2933 cFYI(1,
2934 ("NTLMSSP response to Authenticate "));
2935
2936 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2937 if ((long) (bcc_ptr) % 2) {
2938 remaining_words =
2939 (BCC(smb_buffer_response)
2940 - 1) / 2;
2941 bcc_ptr++; /* Unicode strings must be word aligned */
2942 } else {
2943 remaining_words = BCC(smb_buffer_response) / 2;
2944 }
2945 len =
2946 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2947/* We look for obvious messed up bcc or strings in response so we do not go off
2948 the end since (at least) WIN2K and Windows XP have a major bug in not null
2949 terminating last Unicode string in response */
2950 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002951 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 cifs_strfromUCS_le(ses->serverOS,
2953 (wchar_t *)
2954 bcc_ptr, len,
2955 nls_codepage);
2956 bcc_ptr += 2 * (len + 1);
2957 remaining_words -= len + 1;
2958 ses->serverOS[2 * len] = 0;
2959 ses->serverOS[1 + (2 * len)] = 0;
2960 if (remaining_words > 0) {
2961 len = UniStrnlen((wchar_t *)
2962 bcc_ptr,
2963 remaining_words
2964 - 1);
2965 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002966 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 GFP_KERNEL);
2968 cifs_strfromUCS_le(ses->
2969 serverNOS,
2970 (wchar_t *)
2971 bcc_ptr,
2972 len,
2973 nls_codepage);
2974 bcc_ptr += 2 * (len + 1);
2975 ses->serverNOS[2 * len] = 0;
2976 ses->serverNOS[1+(2*len)] = 0;
2977 remaining_words -= len + 1;
2978 if (remaining_words > 0) {
2979 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2980 /* last string not always null terminated (e.g. for Windows XP & 2000) */
2981 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002982 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 (len +
2984 1),
2985 GFP_KERNEL);
2986 cifs_strfromUCS_le
2987 (ses->
2988 serverDomain,
2989 (wchar_t *)
2990 bcc_ptr, len,
2991 nls_codepage);
2992 bcc_ptr +=
2993 2 * (len + 1);
2994 ses->
2995 serverDomain[2
2996 * len]
2997 = 0;
2998 ses->
2999 serverDomain[1
3000 +
3001 (2
3002 *
3003 len)]
3004 = 0;
3005 } /* else no more room so create dummy domain string */
3006 else
Pekka Enberge915fc42005-09-06 15:18:35 -07003007 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 } else { /* no room so create dummy domain and NOS string */
Pekka Enberge915fc42005-09-06 15:18:35 -07003009 ses->serverDomain = kzalloc(2, GFP_KERNEL);
3010 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 }
3012 } else { /* ASCII */
3013 len = strnlen(bcc_ptr, 1024);
3014 if (((long) bcc_ptr + len) -
3015 (long) pByteArea(smb_buffer_response)
3016 <= BCC(smb_buffer_response)) {
Pekka Enberge915fc42005-09-06 15:18:35 -07003017 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 strncpy(ses->serverOS,bcc_ptr, len);
3019
3020 bcc_ptr += len;
3021 bcc_ptr[0] = 0; /* null terminate the string */
3022 bcc_ptr++;
3023
3024 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07003025 ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 strncpy(ses->serverNOS, bcc_ptr, len);
3027 bcc_ptr += len;
3028 bcc_ptr[0] = 0;
3029 bcc_ptr++;
3030
3031 len = strnlen(bcc_ptr, 1024);
Pekka Enberge915fc42005-09-06 15:18:35 -07003032 ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 strncpy(ses->serverDomain, bcc_ptr, len);
3034 bcc_ptr += len;
3035 bcc_ptr[0] = 0;
3036 bcc_ptr++;
3037 } else
3038 cFYI(1,
3039 ("Variable field of length %d extends beyond end of smb ",
3040 len));
3041 }
3042 } else {
3043 cERROR(1,
3044 (" Security Blob Length extends beyond end of SMB"));
3045 }
3046 } else {
3047 cERROR(1, ("No session structure passed in."));
3048 }
3049 } else {
3050 cERROR(1,
3051 (" Invalid Word count %d: ",
3052 smb_buffer_response->WordCount));
3053 rc = -EIO;
3054 }
3055
3056 if (smb_buffer)
3057 cifs_buf_release(smb_buffer);
3058
3059 return rc;
3060}
3061
3062int
3063CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3064 const char *tree, struct cifsTconInfo *tcon,
3065 const struct nls_table *nls_codepage)
3066{
3067 struct smb_hdr *smb_buffer;
3068 struct smb_hdr *smb_buffer_response;
3069 TCONX_REQ *pSMB;
3070 TCONX_RSP *pSMBr;
3071 unsigned char *bcc_ptr;
3072 int rc = 0;
3073 int length;
3074 __u16 count;
3075
3076 if (ses == NULL)
3077 return -EIO;
3078
3079 smb_buffer = cifs_buf_get();
3080 if (smb_buffer == NULL) {
3081 return -ENOMEM;
3082 }
3083 smb_buffer_response = smb_buffer;
3084
3085 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3086 NULL /*no tid */ , 4 /*wct */ );
3087 smb_buffer->Uid = ses->Suid;
3088 pSMB = (TCONX_REQ *) smb_buffer;
3089 pSMBr = (TCONX_RSP *) smb_buffer_response;
3090
3091 pSMB->AndXCommand = 0xFF;
3092 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3093 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3094 bcc_ptr = &pSMB->Password[0];
3095 bcc_ptr++; /* skip password */
3096
3097 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3098 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3099
3100 if (ses->capabilities & CAP_STATUS32) {
3101 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3102 }
3103 if (ses->capabilities & CAP_DFS) {
3104 smb_buffer->Flags2 |= SMBFLG2_DFS;
3105 }
3106 if (ses->capabilities & CAP_UNICODE) {
3107 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3108 length =
3109 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3110 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3111 bcc_ptr += 2; /* skip trailing null */
3112 } else { /* ASCII */
3113
3114 strcpy(bcc_ptr, tree);
3115 bcc_ptr += strlen(tree) + 1;
3116 }
3117 strcpy(bcc_ptr, "?????");
3118 bcc_ptr += strlen("?????");
3119 bcc_ptr += 1;
3120 count = bcc_ptr - &pSMB->Password[0];
3121 pSMB->hdr.smb_buf_length += count;
3122 pSMB->ByteCount = cpu_to_le16(count);
3123
3124 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3125
3126 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3127 /* above now done in SendReceive */
3128 if ((rc == 0) && (tcon != NULL)) {
3129 tcon->tidStatus = CifsGood;
3130 tcon->tid = smb_buffer_response->Tid;
3131 bcc_ptr = pByteArea(smb_buffer_response);
3132 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3133 /* skip service field (NB: this field is always ASCII) */
3134 bcc_ptr += length + 1;
3135 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3136 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3137 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3138 if ((bcc_ptr + (2 * length)) -
3139 pByteArea(smb_buffer_response) <=
3140 BCC(smb_buffer_response)) {
3141 if(tcon->nativeFileSystem)
3142 kfree(tcon->nativeFileSystem);
3143 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003144 kzalloc(length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 cifs_strfromUCS_le(tcon->nativeFileSystem,
3146 (wchar_t *) bcc_ptr,
3147 length, nls_codepage);
3148 bcc_ptr += 2 * length;
3149 bcc_ptr[0] = 0; /* null terminate the string */
3150 bcc_ptr[1] = 0;
3151 bcc_ptr += 2;
3152 }
3153 /* else do not bother copying these informational fields */
3154 } else {
3155 length = strnlen(bcc_ptr, 1024);
3156 if ((bcc_ptr + length) -
3157 pByteArea(smb_buffer_response) <=
3158 BCC(smb_buffer_response)) {
3159 if(tcon->nativeFileSystem)
3160 kfree(tcon->nativeFileSystem);
3161 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003162 kzalloc(length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 strncpy(tcon->nativeFileSystem, bcc_ptr,
3164 length);
3165 }
3166 /* else do not bother copying these informational fields */
3167 }
3168 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3169 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3170 } else if ((rc == 0) && tcon == NULL) {
3171 /* all we need to save for IPC$ connection */
3172 ses->ipc_tid = smb_buffer_response->Tid;
3173 }
3174
3175 if (smb_buffer)
3176 cifs_buf_release(smb_buffer);
3177 return rc;
3178}
3179
3180int
3181cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3182{
3183 int rc = 0;
3184 int xid;
3185 struct cifsSesInfo *ses = NULL;
3186 struct task_struct *cifsd_task;
3187
3188 xid = GetXid();
3189
3190 if (cifs_sb->tcon) {
3191 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3192 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3193 if (rc == -EBUSY) {
3194 FreeXid(xid);
3195 return 0;
3196 }
3197 tconInfoFree(cifs_sb->tcon);
3198 if ((ses) && (ses->server)) {
3199 /* save off task so we do not refer to ses later */
3200 cifsd_task = ses->server->tsk;
3201 cFYI(1, ("About to do SMBLogoff "));
3202 rc = CIFSSMBLogoff(xid, ses);
3203 if (rc == -EBUSY) {
3204 FreeXid(xid);
3205 return 0;
3206 } else if (rc == -ESHUTDOWN) {
3207 cFYI(1,("Waking up socket by sending it signal"));
3208 if(cifsd_task)
3209 send_sig(SIGKILL,cifsd_task,1);
3210 rc = 0;
3211 } /* else - we have an smb session
3212 left on this socket do not kill cifsd */
3213 } else
3214 cFYI(1, ("No session or bad tcon"));
3215 }
3216
3217 cifs_sb->tcon = NULL;
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003218 if (ses)
3219 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 if (ses)
3221 sesInfoFree(ses);
3222
3223 FreeXid(xid);
3224 return rc; /* BB check if we should always return zero here */
3225}
3226
3227int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3228 struct nls_table * nls_info)
3229{
3230 int rc = 0;
3231 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3232 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003233 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234
3235 /* what if server changes its buffer size after dropping the session? */
3236 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3237 rc = CIFSSMBNegotiate(xid, pSesInfo);
3238 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3239 rc = CIFSSMBNegotiate(xid, pSesInfo);
3240 if(rc == -EAGAIN)
3241 rc = -EHOSTDOWN;
3242 }
3243 if(rc == 0) {
3244 spin_lock(&GlobalMid_Lock);
3245 if(pSesInfo->server->tcpStatus != CifsExiting)
3246 pSesInfo->server->tcpStatus = CifsGood;
3247 else
3248 rc = -EHOSTDOWN;
3249 spin_unlock(&GlobalMid_Lock);
3250
3251 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003252 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 }
3254 if (!rc) {
3255 pSesInfo->capabilities = pSesInfo->server->capabilities;
3256 if(linuxExtEnabled == 0)
3257 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003258 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3260 pSesInfo->server->secMode,
3261 pSesInfo->server->capabilities,
3262 pSesInfo->server->timeZone));
3263 if (extended_security
3264 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3265 && (pSesInfo->server->secType == NTLMSSP)) {
3266 cFYI(1, ("New style sesssetup "));
3267 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3268 NULL /* security blob */,
3269 0 /* blob length */,
3270 nls_info);
3271 } else if (extended_security
3272 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3273 && (pSesInfo->server->secType == RawNTLMSSP)) {
3274 cFYI(1, ("NTLMSSP sesssetup "));
3275 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3276 pSesInfo,
3277 &ntlmv2_flag,
3278 nls_info);
3279 if (!rc) {
3280 if(ntlmv2_flag) {
3281 char * v2_response;
3282 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3283 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3284 nls_info)) {
3285 rc = -ENOMEM;
3286 goto ss_err_exit;
3287 } else
3288 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3289 if(v2_response) {
3290 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003291 /* if(first_time)
3292 cifs_calculate_ntlmv2_mac_key(
3293 pSesInfo->server->mac_signing_key,
3294 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 kfree(v2_response);
3296 /* BB Put dummy sig in SessSetup PDU? */
3297 } else {
3298 rc = -ENOMEM;
3299 goto ss_err_exit;
3300 }
3301
3302 } else {
3303 SMBNTencrypt(pSesInfo->password,
3304 pSesInfo->server->cryptKey,
3305 ntlm_session_key);
3306
Steve Frenchad009ac2005-04-28 22:41:05 -07003307 if(first_time)
3308 cifs_calculate_mac_key(
3309 pSesInfo->server->mac_signing_key,
3310 ntlm_session_key,
3311 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 }
3313 /* for better security the weaker lanman hash not sent
3314 in AuthSessSetup so we no longer calculate it */
3315
3316 rc = CIFSNTLMSSPAuthSessSetup(xid,
3317 pSesInfo,
3318 ntlm_session_key,
3319 ntlmv2_flag,
3320 nls_info);
3321 }
3322 } else { /* old style NTLM 0.12 session setup */
3323 SMBNTencrypt(pSesInfo->password,
3324 pSesInfo->server->cryptKey,
3325 ntlm_session_key);
3326
Steve Frenchad009ac2005-04-28 22:41:05 -07003327 if(first_time)
3328 cifs_calculate_mac_key(
3329 pSesInfo->server->mac_signing_key,
3330 ntlm_session_key, pSesInfo->password);
3331
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 rc = CIFSSessSetup(xid, pSesInfo,
3333 ntlm_session_key, nls_info);
3334 }
3335 if (rc) {
3336 cERROR(1,("Send error in SessSetup = %d",rc));
3337 } else {
3338 cFYI(1,("CIFS Session Established successfully"));
3339 pSesInfo->status = CifsGood;
3340 }
3341 }
3342ss_err_exit:
3343 return rc;
3344}
3345