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