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