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