blob: 9d61844e89b6d854af3324277ae2d0322f7a2806 [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>
Steve Frenchf1914012005-08-18 09:37:34 -070032#include <linux/completion.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/uaccess.h>
34#include <asm/processor.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
37#include "cifsproto.h"
38#include "cifs_unicode.h"
39#include "cifs_debug.h"
40#include "cifs_fs_sb.h"
41#include "ntlmssp.h"
42#include "nterr.h"
43#include "rfc1002pdu.h"
44
45#define CIFS_PORT 445
46#define RFC1001_PORT 139
47
Steve Frenchf1914012005-08-18 09:37:34 -070048static DECLARE_COMPLETION(cifsd_complete);
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
51 unsigned char *p24);
52extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
53 unsigned char *p24);
54
55extern mempool_t *cifs_req_poolp;
56
57struct smb_vol {
58 char *username;
59 char *password;
60 char *domainname;
61 char *UNC;
62 char *UNCip;
63 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
64 char *iocharset; /* local code page for mapping to and from Unicode */
65 char source_rfc1001_name[16]; /* netbios name of client */
Steve Frencha10faeb22005-08-22 21:38:31 -070066 char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 uid_t linux_uid;
68 gid_t linux_gid;
69 mode_t file_mode;
70 mode_t dir_mode;
71 unsigned rw:1;
72 unsigned retry:1;
73 unsigned intr:1;
74 unsigned setuids:1;
75 unsigned noperm:1;
76 unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
77 unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
78 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
79 unsigned direct_io:1;
Steve French6a0b4822005-04-28 22:41:05 -070080 unsigned remap:1; /* set to remap seven reserved chars in filenames */
Jeremy Allisonac670552005-06-22 17:26:35 -070081 unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
Steve Frenchd7245c22005-07-14 18:25:12 -050082 unsigned sfu_emul:1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -070083 unsigned nocase; /* request case insensitive filenames */
84 unsigned nobrl; /* disable sending byte range locks to srv */
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 unsigned int rsize;
86 unsigned int wsize;
87 unsigned int sockopt;
88 unsigned short int port;
89};
90
91static int ipv4_connect(struct sockaddr_in *psin_server,
92 struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -070093 char * netb_name,
94 char * server_netb_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095static int ipv6_connect(struct sockaddr_in6 *psin_server,
96 struct socket **csocket);
97
98
99 /*
100 * cifs tcp session reconnection
101 *
102 * mark tcp session as reconnecting so temporarily locked
103 * mark all smb sessions as reconnecting for tcp session
104 * reconnect tcp session
105 * wake up waiters on reconnection? - (not needed currently)
106 */
107
108int
109cifs_reconnect(struct TCP_Server_Info *server)
110{
111 int rc = 0;
112 struct list_head *tmp;
113 struct cifsSesInfo *ses;
114 struct cifsTconInfo *tcon;
115 struct mid_q_entry * mid_entry;
116
117 spin_lock(&GlobalMid_Lock);
118 if(server->tcpStatus == CifsExiting) {
119 /* the demux thread will exit normally
120 next time through the loop */
121 spin_unlock(&GlobalMid_Lock);
122 return rc;
123 } else
124 server->tcpStatus = CifsNeedReconnect;
125 spin_unlock(&GlobalMid_Lock);
126 server->maxBuf = 0;
127
Steve Frenche4eb2952005-04-28 22:41:09 -0700128 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130 /* before reconnecting the tcp session, mark the smb session (uid)
131 and the tid bad so they are not used until reconnected */
132 read_lock(&GlobalSMBSeslock);
133 list_for_each(tmp, &GlobalSMBSessionList) {
134 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
135 if (ses->server) {
136 if (ses->server == server) {
137 ses->status = CifsNeedReconnect;
138 ses->ipc_tid = 0;
139 }
140 }
141 /* else tcp and smb sessions need reconnection */
142 }
143 list_for_each(tmp, &GlobalTreeConnectionList) {
144 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
145 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
146 tcon->tidStatus = CifsNeedReconnect;
147 }
148 }
149 read_unlock(&GlobalSMBSeslock);
150 /* do not want to be sending data on a socket we are freeing */
151 down(&server->tcpSem);
152 if(server->ssocket) {
153 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
154 server->ssocket->flags));
155 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
156 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
157 server->ssocket->flags));
158 sock_release(server->ssocket);
159 server->ssocket = NULL;
160 }
161
162 spin_lock(&GlobalMid_Lock);
163 list_for_each(tmp, &server->pending_mid_q) {
164 mid_entry = list_entry(tmp, struct
165 mid_q_entry,
166 qhead);
167 if(mid_entry) {
168 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700169 /* Mark other intransit requests as needing
170 retry so we do not immediately mark the
171 session bad again (ie after we reconnect
172 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 mid_entry->midState = MID_RETRY_NEEDED;
174 }
175 }
176 }
177 spin_unlock(&GlobalMid_Lock);
178 up(&server->tcpSem);
179
180 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
181 {
182 if(server->protocolType == IPV6) {
183 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
184 } else {
185 rc = ipv4_connect(&server->addr.sockAddr,
186 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700187 server->workstation_RFC1001_name,
188 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 }
190 if(rc) {
Steve French0cb766a2005-04-28 22:41:11 -0700191 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 } else {
193 atomic_inc(&tcpSesReconnectCount);
194 spin_lock(&GlobalMid_Lock);
195 if(server->tcpStatus != CifsExiting)
196 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700197 server->sequence_number = 0;
198 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 /* atomic_set(&server->inFlight,0);*/
200 wake_up(&server->response_q);
201 }
202 }
203 return rc;
204}
205
Steve Frenche4eb2952005-04-28 22:41:09 -0700206/*
207 return codes:
208 0 not a transact2, or all data present
209 >0 transact2 with that much data missing
210 -EINVAL = invalid transact2
211
212 */
213static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
214{
215 struct smb_t2_rsp * pSMBt;
216 int total_data_size;
217 int data_in_this_rsp;
218 int remaining;
219
220 if(pSMB->Command != SMB_COM_TRANSACTION2)
221 return 0;
222
223 /* check for plausible wct, bcc and t2 data and parm sizes */
224 /* check for parm and data offset going beyond end of smb */
225 if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
226 cFYI(1,("invalid transact2 word count"));
227 return -EINVAL;
228 }
229
230 pSMBt = (struct smb_t2_rsp *)pSMB;
231
232 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
233 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
234
235 remaining = total_data_size - data_in_this_rsp;
236
237 if(remaining == 0)
238 return 0;
239 else if(remaining < 0) {
240 cFYI(1,("total data %d smaller than data in frame %d",
241 total_data_size, data_in_this_rsp));
242 return -EINVAL;
243 } else {
244 cFYI(1,("missing %d bytes from transact2, check next response",
245 remaining));
246 if(total_data_size > maxBufSize) {
247 cERROR(1,("TotalDataSize %d is over maximum buffer %d",
248 total_data_size,maxBufSize));
249 return -EINVAL;
250 }
251 return remaining;
252 }
253}
254
255static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
256{
257 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
258 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
259 int total_data_size;
260 int total_in_buf;
261 int remaining;
262 int total_in_buf2;
263 char * data_area_of_target;
264 char * data_area_of_buf2;
265 __u16 byte_count;
266
267 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
268
269 if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
270 cFYI(1,("total data sizes of primary and secondary t2 differ"));
271 }
272
273 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
274
275 remaining = total_data_size - total_in_buf;
276
277 if(remaining < 0)
278 return -EINVAL;
279
280 if(remaining == 0) /* nothing to do, ignore */
281 return 0;
282
283 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
284 if(remaining < total_in_buf2) {
285 cFYI(1,("transact2 2nd response contains too much data"));
286 }
287
288 /* find end of first SMB data area */
289 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
290 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
291 /* validate target area */
292
293 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
294 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
295
296 data_area_of_target += total_in_buf;
297
298 /* copy second buffer into end of first buffer */
299 memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
300 total_in_buf += total_in_buf2;
301 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
302 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
303 byte_count += total_in_buf2;
304 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
305
306 byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
307 byte_count += total_in_buf2;
308
309 /* BB also add check that we are not beyond maximum buffer size */
310
311 pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
312
313 if(remaining == total_in_buf2) {
314 cFYI(1,("found the last secondary response"));
315 return 0; /* we are done */
316 } else /* more responses to go */
317 return 1;
318
319}
320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321static int
322cifs_demultiplex_thread(struct TCP_Server_Info *server)
323{
324 int length;
325 unsigned int pdu_length, total_read;
326 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700327 struct smb_hdr *bigbuf = NULL;
328 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 struct msghdr smb_msg;
330 struct kvec iov;
331 struct socket *csocket = server->ssocket;
332 struct list_head *tmp;
333 struct cifsSesInfo *ses;
334 struct task_struct *task_to_wake = NULL;
335 struct mid_q_entry *mid_entry;
336 char *temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700337 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700338 int isMultiRsp;
339 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
341 daemonize("cifsd");
342 allow_signal(SIGKILL);
343 current->flags |= PF_MEMALLOC;
344 server->tsk = current; /* save process info to wake at shutdown */
345 cFYI(1, ("Demultiplex PID: %d", current->pid));
346 write_lock(&GlobalSMBSeslock);
347 atomic_inc(&tcpSesAllocCount);
348 length = tcpSesAllocCount.counter;
349 write_unlock(&GlobalSMBSeslock);
Steve Frenchf1914012005-08-18 09:37:34 -0700350 complete(&cifsd_complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 if(length > 1) {
352 mempool_resize(cifs_req_poolp,
353 length + cifs_min_rcv,
354 GFP_KERNEL);
355 }
356
357 while (server->tcpStatus != CifsExiting) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700358 if (bigbuf == NULL) {
359 bigbuf = cifs_buf_get();
360 if(bigbuf == NULL) {
361 cERROR(1,("No memory for large SMB response"));
362 msleep(3000);
363 /* retry will check if exiting */
364 continue;
365 }
366 } else if(isLargeBuf) {
367 /* we are reusing a dirtry large buf, clear its start */
368 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700370
371 if (smallbuf == NULL) {
372 smallbuf = cifs_small_buf_get();
373 if(smallbuf == NULL) {
374 cERROR(1,("No memory for SMB response"));
375 msleep(1000);
376 /* retry will check if exiting */
377 continue;
378 }
379 /* beginning of smb buffer is cleared in our buf_get */
380 } else /* if existing small buf clear beginning */
381 memset(smallbuf, 0, sizeof (struct smb_hdr));
382
383 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700384 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700385 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 iov.iov_base = smb_buffer;
387 iov.iov_len = 4;
388 smb_msg.msg_control = NULL;
389 smb_msg.msg_controllen = 0;
390 length =
391 kernel_recvmsg(csocket, &smb_msg,
392 &iov, 1, 4, 0 /* BB see socket.h flags */);
393
394 if(server->tcpStatus == CifsExiting) {
395 break;
396 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French57337e42005-04-28 22:41:10 -0700397 cFYI(1,("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 cifs_reconnect(server);
399 cFYI(1,("call to reconnect done"));
400 csocket = server->ssocket;
401 continue;
402 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700403 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 allowing socket to clear and app threads to set
405 tcpStatus CifsNeedReconnect if server hung */
406 continue;
407 } else if (length <= 0) {
408 if(server->tcpStatus == CifsNew) {
Steve French57337e42005-04-28 22:41:10 -0700409 cFYI(1,("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700410 /* some servers kill the TCP session rather than
411 returning an SMB negprot error, in which
412 case reconnecting here is not going to help,
413 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 break;
415 }
416 if(length == -EINTR) {
417 cFYI(1,("cifsd thread killed"));
418 break;
419 }
Steve French57337e42005-04-28 22:41:10 -0700420 cFYI(1,("Reconnect after unexpected peek error %d",
421 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 cifs_reconnect(server);
423 csocket = server->ssocket;
424 wake_up(&server->response_q);
425 continue;
Steve French46810cb2005-04-28 22:41:09 -0700426 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700428 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 length));
430 cifs_reconnect(server);
431 csocket = server->ssocket;
432 wake_up(&server->response_q);
433 continue;
434 }
Steve French67010fb2005-04-28 22:41:09 -0700435
Steve French46810cb2005-04-28 22:41:09 -0700436 /* the right amount was read from socket - 4 bytes */
437
438 pdu_length = ntohl(smb_buffer->smb_buf_length);
439 cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
440
441 temp = (char *) smb_buffer;
442 if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700443 continue;
Steve French46810cb2005-04-28 22:41:09 -0700444 } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700445 cFYI(1,("Good RFC 1002 session rsp"));
446 continue;
Steve French46810cb2005-04-28 22:41:09 -0700447 } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
448 /* we get this from Windows 98 instead of
449 an error on SMB negprot response */
Steve Frenche4eb2952005-04-28 22:41:09 -0700450 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
451 temp[4]));
Steve French46810cb2005-04-28 22:41:09 -0700452 if(server->tcpStatus == CifsNew) {
453 /* if nack on negprot (rather than
454 ret of smb negprot error) reconnecting
455 not going to help, ret error to mount */
456 break;
457 } else {
458 /* give server a second to
459 clean up before reconnect attempt */
460 msleep(1000);
461 /* always try 445 first on reconnect
462 since we get NACK on some if we ever
463 connected to port 139 (the NACK is
464 since we do not begin with RFC1001
465 session initialize frame) */
466 server->addr.sockAddr.sin_port =
467 htons(CIFS_PORT);
468 cifs_reconnect(server);
469 csocket = server->ssocket;
470 wake_up(&server->response_q);
471 continue;
472 }
473 } else if (temp[0] != (char) 0) {
474 cERROR(1,("Unknown RFC 1002 frame"));
475 cifs_dump_mem(" Received Data: ", temp, length);
476 cifs_reconnect(server);
477 csocket = server->ssocket;
478 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700479 }
480
481 /* else we have an SMB response */
482 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700483 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700484 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700485 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700486 cifs_reconnect(server);
487 csocket = server->ssocket;
488 wake_up(&server->response_q);
489 continue;
490 }
491
492 /* else length ok */
493 reconnect = 0;
494
495 if(pdu_length > MAX_CIFS_HDR_SIZE - 4) {
496 isLargeBuf = TRUE;
497 memcpy(bigbuf, smallbuf, 4);
498 smb_buffer = bigbuf;
499 }
500 length = 0;
501 iov.iov_base = 4 + (char *)smb_buffer;
502 iov.iov_len = pdu_length;
503 for (total_read = 0; total_read < pdu_length;
504 total_read += length) {
505 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
506 pdu_length - total_read, 0);
507 if((server->tcpStatus == CifsExiting) ||
508 (length == -EINTR)) {
509 /* then will exit */
510 reconnect = 2;
511 break;
512 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700513 cifs_reconnect(server);
514 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700515 /* Reconnect wakes up rspns q */
516 /* Now we will reread sock */
517 reconnect = 1;
518 break;
519 } else if ((length == -ERESTARTSYS) ||
520 (length == -EAGAIN)) {
521 msleep(1); /* minimum sleep to prevent looping,
522 allowing socket to clear and app
523 threads to set tcpStatus
524 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700525 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700526 } else if (length <= 0) {
527 cERROR(1,("Received no data, expecting %d",
528 pdu_length - total_read));
529 cifs_reconnect(server);
530 csocket = server->ssocket;
531 reconnect = 1;
532 break;
Steve French46810cb2005-04-28 22:41:09 -0700533 }
534 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700535 if(reconnect == 2)
536 break;
537 else if(reconnect == 1)
538 continue;
539
540 length += 4; /* account for rfc1002 hdr */
541
542
543 dump_smb(smb_buffer, length);
544 if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
545 cERROR(1, ("Bad SMB Received "));
546 continue;
547 }
548
549
550 task_to_wake = NULL;
551 spin_lock(&GlobalMid_Lock);
552 list_for_each(tmp, &server->pending_mid_q) {
553 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
554
555 if ((mid_entry->mid == smb_buffer->Mid) &&
556 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
557 (mid_entry->command == smb_buffer->Command)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700558 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
559 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700560 isMultiRsp = TRUE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700561 if(mid_entry->resp_buf) {
562 /* merge response - fix up 1st*/
563 if(coalesce_t2(smb_buffer,
564 mid_entry->resp_buf)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700565 break;
566 } else {
567 /* all parts received */
568 goto multi_t2_fnd;
569 }
570 } else {
571 if(!isLargeBuf) {
572 cERROR(1,("1st trans2 resp needs bigbuf"));
573 /* BB maybe we can fix this up, switch
574 to already allocated large buffer? */
575 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700576 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700577 mid_entry->resp_buf =
578 smb_buffer;
579 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700580 bigbuf = NULL;
581 }
582 }
583 break;
584 }
585 mid_entry->resp_buf = smb_buffer;
586 if(isLargeBuf)
587 mid_entry->largeBuf = 1;
588 else
589 mid_entry->largeBuf = 0;
590multi_t2_fnd:
591 task_to_wake = mid_entry->tsk;
592 mid_entry->midState = MID_RESPONSE_RECEIVED;
593 break;
594 }
595 }
596 spin_unlock(&GlobalMid_Lock);
597 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700598 /* Was previous buf put in mpx struct for multi-rsp? */
599 if(!isMultiRsp) {
600 /* smb buffer will be freed by user thread */
601 if(isLargeBuf) {
602 bigbuf = NULL;
603 } else
604 smallbuf = NULL;
605 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700606 wake_up_process(task_to_wake);
Steve French57337e42005-04-28 22:41:10 -0700607 } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700608 && (isMultiRsp == FALSE)) {
609 cERROR(1, ("No task to wake, unknown frame rcvd!"));
610 cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
611 }
612 } /* end while !EXITING */
613
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 spin_lock(&GlobalMid_Lock);
615 server->tcpStatus = CifsExiting;
616 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700617 /* check if we have blocked requests that need to free */
618 /* Note that cifs_max_pending is normally 50, but
619 can be set at module install time to as little as two */
620 if(atomic_read(&server->inFlight) >= cifs_max_pending)
621 atomic_set(&server->inFlight, cifs_max_pending - 1);
622 /* We do not want to set the max_pending too low or we
623 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 spin_unlock(&GlobalMid_Lock);
625 /* Although there should not be any requests blocked on
626 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700627 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 to the same server - they now will see the session is in exit state
629 and get out of SendReceive. */
630 wake_up_all(&server->request_q);
631 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700632 msleep(125);
633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 if(server->ssocket) {
635 sock_release(csocket);
636 server->ssocket = NULL;
637 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700638 /* buffer usuallly freed in free_mid - need to free it here on exit */
639 if (bigbuf != NULL)
640 cifs_buf_release(bigbuf);
641 if (smallbuf != NULL)
642 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
644 read_lock(&GlobalSMBSeslock);
645 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700646 /* loop through server session structures attached to this and
647 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 list_for_each(tmp, &GlobalSMBSessionList) {
649 ses =
650 list_entry(tmp, struct cifsSesInfo,
651 cifsSessionList);
652 if (ses->server == server) {
653 ses->status = CifsExiting;
654 ses->server = NULL;
655 }
656 }
657 read_unlock(&GlobalSMBSeslock);
658 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700659 /* although we can not zero the server struct pointer yet,
660 since there are active requests which may depnd on them,
661 mark the corresponding SMB sessions as exiting too */
662 list_for_each(tmp, &GlobalSMBSessionList) {
663 ses = list_entry(tmp, struct cifsSesInfo,
664 cifsSessionList);
665 if (ses->server == server) {
666 ses->status = CifsExiting;
667 }
668 }
669
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 spin_lock(&GlobalMid_Lock);
671 list_for_each(tmp, &server->pending_mid_q) {
672 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
673 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
674 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700675 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 task_to_wake = mid_entry->tsk;
677 if(task_to_wake) {
678 wake_up_process(task_to_wake);
679 }
680 }
681 }
682 spin_unlock(&GlobalMid_Lock);
683 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700685 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 }
687
Steve Frenchf1914012005-08-18 09:37:34 -0700688 if (!list_empty(&server->pending_mid_q)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 /* mpx threads have not exited yet give them
690 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700691 /* due to delays on oplock break requests, we need
692 to wait at least 45 seconds before giving up
693 on a request getting a response and going ahead
694 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700696 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 /* if threads still have not exited they are probably never
698 coming home not much else we can do but free the memory */
699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
701 write_lock(&GlobalSMBSeslock);
702 atomic_dec(&tcpSesAllocCount);
703 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700704
705 /* last chance to mark ses pointers invalid
706 if there are any pointing to this (e.g
707 if a crazy root user tried to kill cifsd
708 kernel thread explicitly this might happen) */
709 list_for_each(tmp, &GlobalSMBSessionList) {
710 ses = list_entry(tmp, struct cifsSesInfo,
711 cifsSessionList);
712 if (ses->server == server) {
713 ses->server = NULL;
714 }
715 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700717
718 kfree(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 if(length > 0) {
720 mempool_resize(cifs_req_poolp,
721 length + cifs_min_rcv,
722 GFP_KERNEL);
723 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700724
Steve Frenchf1914012005-08-18 09:37:34 -0700725 complete_and_exit(&cifsd_complete, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return 0;
727}
728
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729static int
730cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
731{
732 char *value;
733 char *data;
734 unsigned int temp_len, i, j;
735 char separator[2];
736
737 separator[0] = ',';
738 separator[1] = 0;
739
740 memset(vol->source_rfc1001_name,0x20,15);
741 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
742 /* does not have to be a perfect mapping since the field is
743 informational, only used for servers that do not support
744 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700745 vol->source_rfc1001_name[i] =
746 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 }
748 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700749 /* null target name indicates to use *SMBSERVR default called name
750 if we end up sending RFC1001 session initialize */
751 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 vol->linux_uid = current->uid; /* current->euid instead? */
753 vol->linux_gid = current->gid;
754 vol->dir_mode = S_IRWXUGO;
755 /* 2767 perms indicate mandatory locking support */
756 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
757
758 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
759 vol->rw = TRUE;
760
Jeremy Allisonac670552005-06-22 17:26:35 -0700761 /* default is always to request posix paths. */
762 vol->posix_paths = 1;
763
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 if (!options)
765 return 1;
766
767 if(strncmp(options,"sep=",4) == 0) {
768 if(options[4] != 0) {
769 separator[0] = options[4];
770 options += 5;
771 } else {
772 cFYI(1,("Null separator not allowed"));
773 }
774 }
775
776 while ((data = strsep(&options, separator)) != NULL) {
777 if (!*data)
778 continue;
779 if ((value = strchr(data, '=')) != NULL)
780 *value++ = '\0';
781
782 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
783 vol->no_xattr = 0;
784 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
785 vol->no_xattr = 1;
786 } else if (strnicmp(data, "user", 4) == 0) {
787 if (!value || !*value) {
788 printk(KERN_WARNING
789 "CIFS: invalid or missing username\n");
790 return 1; /* needs_arg; */
791 }
792 if (strnlen(value, 200) < 200) {
793 vol->username = value;
794 } else {
795 printk(KERN_WARNING "CIFS: username too long\n");
796 return 1;
797 }
798 } else if (strnicmp(data, "pass", 4) == 0) {
799 if (!value) {
800 vol->password = NULL;
801 continue;
802 } else if(value[0] == 0) {
803 /* check if string begins with double comma
804 since that would mean the password really
805 does start with a comma, and would not
806 indicate an empty string */
807 if(value[1] != separator[0]) {
808 vol->password = NULL;
809 continue;
810 }
811 }
812 temp_len = strlen(value);
813 /* removed password length check, NTLM passwords
814 can be arbitrarily long */
815
816 /* if comma in password, the string will be
817 prematurely null terminated. Commas in password are
818 specified across the cifs mount interface by a double
819 comma ie ,, and a comma used as in other cases ie ','
820 as a parameter delimiter/separator is single and due
821 to the strsep above is temporarily zeroed. */
822
823 /* NB: password legally can have multiple commas and
824 the only illegal character in a password is null */
825
Steve French09d1db52005-04-28 22:41:08 -0700826 if ((value[temp_len] == 0) &&
827 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 /* reinsert comma */
829 value[temp_len] = separator[0];
830 temp_len+=2; /* move after the second comma */
831 while(value[temp_len] != 0) {
832 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700833 if (value[temp_len+1] ==
834 separator[0]) {
835 /* skip second comma */
836 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 } else {
838 /* single comma indicating start
839 of next parm */
840 break;
841 }
842 }
843 temp_len++;
844 }
845 if(value[temp_len] == 0) {
846 options = NULL;
847 } else {
848 value[temp_len] = 0;
849 /* point option to start of next parm */
850 options = value + temp_len + 1;
851 }
852 /* go from value to value + temp_len condensing
853 double commas to singles. Note that this ends up
854 allocating a few bytes too many, which is ok */
Steve French433dc242005-04-28 22:41:08 -0700855 vol->password = kcalloc(1, temp_len, GFP_KERNEL);
856 if(vol->password == NULL) {
857 printk("CIFS: no memory for pass\n");
858 return 1;
859 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 for(i=0,j=0;i<temp_len;i++,j++) {
861 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700862 if(value[i] == separator[0]
863 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 /* skip second comma */
865 i++;
866 }
867 }
868 vol->password[j] = 0;
869 } else {
Steve French09d1db52005-04-28 22:41:08 -0700870 vol->password = kcalloc(1, temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700871 if(vol->password == NULL) {
872 printk("CIFS: no memory for pass\n");
873 return 1;
874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 strcpy(vol->password, value);
876 }
877 } else if (strnicmp(data, "ip", 2) == 0) {
878 if (!value || !*value) {
879 vol->UNCip = NULL;
880 } else if (strnlen(value, 35) < 35) {
881 vol->UNCip = value;
882 } else {
883 printk(KERN_WARNING "CIFS: ip address too long\n");
884 return 1;
885 }
886 } else if ((strnicmp(data, "unc", 3) == 0)
887 || (strnicmp(data, "target", 6) == 0)
888 || (strnicmp(data, "path", 4) == 0)) {
889 if (!value || !*value) {
890 printk(KERN_WARNING
891 "CIFS: invalid path to network resource\n");
892 return 1; /* needs_arg; */
893 }
894 if ((temp_len = strnlen(value, 300)) < 300) {
895 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
896 if(vol->UNC == NULL)
897 return 1;
898 strcpy(vol->UNC,value);
899 if (strncmp(vol->UNC, "//", 2) == 0) {
900 vol->UNC[0] = '\\';
901 vol->UNC[1] = '\\';
902 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
903 printk(KERN_WARNING
904 "CIFS: UNC Path does not begin with // or \\\\ \n");
905 return 1;
906 }
907 } else {
908 printk(KERN_WARNING "CIFS: UNC name too long\n");
909 return 1;
910 }
911 } else if ((strnicmp(data, "domain", 3) == 0)
912 || (strnicmp(data, "workgroup", 5) == 0)) {
913 if (!value || !*value) {
914 printk(KERN_WARNING "CIFS: invalid domain name\n");
915 return 1; /* needs_arg; */
916 }
917 /* BB are there cases in which a comma can be valid in
918 a domain name and need special handling? */
919 if (strnlen(value, 65) < 65) {
920 vol->domainname = value;
921 cFYI(1, ("Domain name set"));
922 } else {
923 printk(KERN_WARNING "CIFS: domain name too long\n");
924 return 1;
925 }
926 } else if (strnicmp(data, "iocharset", 9) == 0) {
927 if (!value || !*value) {
928 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
929 return 1; /* needs_arg; */
930 }
931 if (strnlen(value, 65) < 65) {
932 if(strnicmp(value,"default",7))
933 vol->iocharset = value;
934 /* if iocharset not set load_nls_default used by caller */
935 cFYI(1, ("iocharset set to %s",value));
936 } else {
937 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
938 return 1;
939 }
940 } else if (strnicmp(data, "uid", 3) == 0) {
941 if (value && *value) {
942 vol->linux_uid =
943 simple_strtoul(value, &value, 0);
944 }
945 } else if (strnicmp(data, "gid", 3) == 0) {
946 if (value && *value) {
947 vol->linux_gid =
948 simple_strtoul(value, &value, 0);
949 }
950 } else if (strnicmp(data, "file_mode", 4) == 0) {
951 if (value && *value) {
952 vol->file_mode =
953 simple_strtoul(value, &value, 0);
954 }
955 } else if (strnicmp(data, "dir_mode", 4) == 0) {
956 if (value && *value) {
957 vol->dir_mode =
958 simple_strtoul(value, &value, 0);
959 }
960 } else if (strnicmp(data, "dirmode", 4) == 0) {
961 if (value && *value) {
962 vol->dir_mode =
963 simple_strtoul(value, &value, 0);
964 }
965 } else if (strnicmp(data, "port", 4) == 0) {
966 if (value && *value) {
967 vol->port =
968 simple_strtoul(value, &value, 0);
969 }
970 } else if (strnicmp(data, "rsize", 5) == 0) {
971 if (value && *value) {
972 vol->rsize =
973 simple_strtoul(value, &value, 0);
974 }
975 } else if (strnicmp(data, "wsize", 5) == 0) {
976 if (value && *value) {
977 vol->wsize =
978 simple_strtoul(value, &value, 0);
979 }
980 } else if (strnicmp(data, "sockopt", 5) == 0) {
981 if (value && *value) {
982 vol->sockopt =
983 simple_strtoul(value, &value, 0);
984 }
985 } else if (strnicmp(data, "netbiosname", 4) == 0) {
986 if (!value || !*value || (*value == ' ')) {
987 cFYI(1,("invalid (empty) netbiosname specified"));
988 } else {
989 memset(vol->source_rfc1001_name,0x20,15);
990 for(i=0;i<15;i++) {
991 /* BB are there cases in which a comma can be
992 valid in this workstation netbios name (and need
993 special handling)? */
994
995 /* We do not uppercase netbiosname for user */
996 if (value[i]==0)
997 break;
998 else
999 vol->source_rfc1001_name[i] = value[i];
1000 }
1001 /* The string has 16th byte zero still from
1002 set at top of the function */
1003 if((i==15) && (value[i] != 0))
Steve Frencha10faeb22005-08-22 21:38:31 -07001004 printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
1005 }
1006 } else if (strnicmp(data, "servern", 7) == 0) {
1007 /* servernetbiosname specified override *SMBSERVER */
1008 if (!value || !*value || (*value == ' ')) {
1009 cFYI(1,("empty server netbiosname specified"));
1010 } else {
1011 /* last byte, type, is 0x20 for servr type */
1012 memset(vol->target_rfc1001_name,0x20,16);
1013
1014 for(i=0;i<15;i++) {
1015 /* BB are there cases in which a comma can be
1016 valid in this workstation netbios name (and need
1017 special handling)? */
1018
1019 /* user or mount helper must uppercase netbiosname */
1020 if (value[i]==0)
1021 break;
1022 else
1023 vol->target_rfc1001_name[i] = value[i];
1024 }
1025 /* The string has 16th byte zero still from
1026 set at top of the function */
1027 if((i==15) && (value[i] != 0))
1028 printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 }
1030 } else if (strnicmp(data, "credentials", 4) == 0) {
1031 /* ignore */
1032 } else if (strnicmp(data, "version", 3) == 0) {
1033 /* ignore */
1034 } else if (strnicmp(data, "guest",5) == 0) {
1035 /* ignore */
1036 } else if (strnicmp(data, "rw", 2) == 0) {
1037 vol->rw = TRUE;
1038 } else if ((strnicmp(data, "suid", 4) == 0) ||
1039 (strnicmp(data, "nosuid", 6) == 0) ||
1040 (strnicmp(data, "exec", 4) == 0) ||
1041 (strnicmp(data, "noexec", 6) == 0) ||
1042 (strnicmp(data, "nodev", 5) == 0) ||
1043 (strnicmp(data, "noauto", 6) == 0) ||
1044 (strnicmp(data, "dev", 3) == 0)) {
1045 /* The mount tool or mount.cifs helper (if present)
1046 uses these opts to set flags, and the flags are read
1047 by the kernel vfs layer before we get here (ie
1048 before read super) so there is no point trying to
1049 parse these options again and set anything and it
1050 is ok to just ignore them */
1051 continue;
1052 } else if (strnicmp(data, "ro", 2) == 0) {
1053 vol->rw = FALSE;
1054 } else if (strnicmp(data, "hard", 4) == 0) {
1055 vol->retry = 1;
1056 } else if (strnicmp(data, "soft", 4) == 0) {
1057 vol->retry = 0;
1058 } else if (strnicmp(data, "perm", 4) == 0) {
1059 vol->noperm = 0;
1060 } else if (strnicmp(data, "noperm", 6) == 0) {
1061 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001062 } else if (strnicmp(data, "mapchars", 8) == 0) {
1063 vol->remap = 1;
1064 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1065 vol->remap = 0;
Steve Frenchd7245c22005-07-14 18:25:12 -05001066 } else if (strnicmp(data, "sfu", 3) == 0) {
1067 vol->sfu_emul = 1;
1068 } else if (strnicmp(data, "nosfu", 5) == 0) {
1069 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001070 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1071 vol->posix_paths = 1;
1072 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1073 vol->posix_paths = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001074 } else if ((strnicmp(data, "nocase", 6) == 0) ||
1075 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001076 vol->nocase = 1;
1077 } else if (strnicmp(data, "brl", 3) == 0) {
1078 vol->nobrl = 0;
1079 } else if (strnicmp(data, "nobrl", 5) == 0) {
1080 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001081 /* turn off mandatory locking in mode
1082 if remote locking is turned off since the
1083 local vfs will do advisory */
1084 if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1085 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 } else if (strnicmp(data, "setuids", 7) == 0) {
1087 vol->setuids = 1;
1088 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1089 vol->setuids = 0;
1090 } else if (strnicmp(data, "nohard", 6) == 0) {
1091 vol->retry = 0;
1092 } else if (strnicmp(data, "nosoft", 6) == 0) {
1093 vol->retry = 1;
1094 } else if (strnicmp(data, "nointr", 6) == 0) {
1095 vol->intr = 0;
1096 } else if (strnicmp(data, "intr", 4) == 0) {
1097 vol->intr = 1;
1098 } else if (strnicmp(data, "serverino",7) == 0) {
1099 vol->server_ino = 1;
1100 } else if (strnicmp(data, "noserverino",9) == 0) {
1101 vol->server_ino = 0;
1102 } else if (strnicmp(data, "acl",3) == 0) {
1103 vol->no_psx_acl = 0;
1104 } else if (strnicmp(data, "noacl",5) == 0) {
1105 vol->no_psx_acl = 1;
1106 } else if (strnicmp(data, "direct",6) == 0) {
1107 vol->direct_io = 1;
1108 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1109 vol->direct_io = 1;
1110 } else if (strnicmp(data, "in6_addr",8) == 0) {
1111 if (!value || !*value) {
1112 vol->in6_addr = NULL;
1113 } else if (strnlen(value, 49) == 48) {
1114 vol->in6_addr = value;
1115 } else {
1116 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1117 return 1;
1118 }
1119 } else if (strnicmp(data, "noac", 4) == 0) {
1120 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1121 } else
1122 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1123 }
1124 if (vol->UNC == NULL) {
1125 if(devname == NULL) {
1126 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1127 return 1;
1128 }
1129 if ((temp_len = strnlen(devname, 300)) < 300) {
1130 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1131 if(vol->UNC == NULL)
1132 return 1;
1133 strcpy(vol->UNC,devname);
1134 if (strncmp(vol->UNC, "//", 2) == 0) {
1135 vol->UNC[0] = '\\';
1136 vol->UNC[1] = '\\';
1137 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1138 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1139 return 1;
1140 }
1141 } else {
1142 printk(KERN_WARNING "CIFS: UNC name too long\n");
1143 return 1;
1144 }
1145 }
1146 if(vol->UNCip == NULL)
1147 vol->UNCip = &vol->UNC[2];
1148
1149 return 0;
1150}
1151
1152static struct cifsSesInfo *
1153cifs_find_tcp_session(struct in_addr * target_ip_addr,
1154 struct in6_addr *target_ip6_addr,
1155 char *userName, struct TCP_Server_Info **psrvTcp)
1156{
1157 struct list_head *tmp;
1158 struct cifsSesInfo *ses;
1159 *psrvTcp = NULL;
1160 read_lock(&GlobalSMBSeslock);
1161
1162 list_for_each(tmp, &GlobalSMBSessionList) {
1163 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1164 if (ses->server) {
1165 if((target_ip_addr &&
1166 (ses->server->addr.sockAddr.sin_addr.s_addr
1167 == target_ip_addr->s_addr)) || (target_ip6_addr
1168 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1169 target_ip6_addr,sizeof(*target_ip6_addr)))){
1170 /* BB lock server and tcp session and increment use count here?? */
1171 *psrvTcp = ses->server; /* found a match on the TCP session */
1172 /* BB check if reconnection needed */
1173 if (strncmp
1174 (ses->userName, userName,
1175 MAX_USERNAME_SIZE) == 0){
1176 read_unlock(&GlobalSMBSeslock);
1177 return ses; /* found exact match on both tcp and SMB sessions */
1178 }
1179 }
1180 }
1181 /* else tcp and smb sessions need reconnection */
1182 }
1183 read_unlock(&GlobalSMBSeslock);
1184 return NULL;
1185}
1186
1187static struct cifsTconInfo *
1188find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1189{
1190 struct list_head *tmp;
1191 struct cifsTconInfo *tcon;
1192
1193 read_lock(&GlobalSMBSeslock);
1194 list_for_each(tmp, &GlobalTreeConnectionList) {
1195 cFYI(1, ("Next tcon - "));
1196 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1197 if (tcon->ses) {
1198 if (tcon->ses->server) {
1199 cFYI(1,
1200 (" old ip addr: %x == new ip %x ?",
1201 tcon->ses->server->addr.sockAddr.sin_addr.
1202 s_addr, new_target_ip_addr));
1203 if (tcon->ses->server->addr.sockAddr.sin_addr.
1204 s_addr == new_target_ip_addr) {
1205 /* BB lock tcon and server and tcp session and increment use count here? */
1206 /* found a match on the TCP session */
1207 /* BB check if reconnection needed */
1208 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1209 tcon->treeName, uncName));
1210 if (strncmp
1211 (tcon->treeName, uncName,
1212 MAX_TREE_SIZE) == 0) {
1213 cFYI(1,
1214 ("Matched UNC, old user: %s == new: %s ?",
1215 tcon->treeName, uncName));
1216 if (strncmp
1217 (tcon->ses->userName,
1218 userName,
1219 MAX_USERNAME_SIZE) == 0) {
1220 read_unlock(&GlobalSMBSeslock);
1221 return tcon;/* also matched user (smb session)*/
1222 }
1223 }
1224 }
1225 }
1226 }
1227 }
1228 read_unlock(&GlobalSMBSeslock);
1229 return NULL;
1230}
1231
1232int
1233connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001234 const char *old_path, const struct nls_table *nls_codepage,
1235 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236{
1237 unsigned char *referrals = NULL;
1238 unsigned int num_referrals;
1239 int rc = 0;
1240
1241 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001242 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243
1244 /* BB Add in code to: if valid refrl, if not ip address contact
1245 the helper that resolves tcp names, mount to it, try to
1246 tcon to it unmount it if fail */
1247
1248 if(referrals)
1249 kfree(referrals);
1250
1251 return rc;
1252}
1253
1254int
1255get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1256 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001257 unsigned int *pnum_referrals,
1258 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259{
1260 char *temp_unc;
1261 int rc = 0;
1262
1263 *pnum_referrals = 0;
1264
1265 if (pSesInfo->ipc_tid == 0) {
1266 temp_unc = kmalloc(2 /* for slashes */ +
1267 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1268 + 1 + 4 /* slash IPC$ */ + 2,
1269 GFP_KERNEL);
1270 if (temp_unc == NULL)
1271 return -ENOMEM;
1272 temp_unc[0] = '\\';
1273 temp_unc[1] = '\\';
1274 strcpy(temp_unc + 2, pSesInfo->serverName);
1275 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1276 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1277 cFYI(1,
1278 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1279 kfree(temp_unc);
1280 }
1281 if (rc == 0)
1282 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001283 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
1285 return rc;
1286}
1287
1288/* See RFC1001 section 14 on representation of Netbios names */
1289static void rfc1002mangle(char * target,char * source, unsigned int length)
1290{
1291 unsigned int i,j;
1292
1293 for(i=0,j=0;i<(length);i++) {
1294 /* mask a nibble at a time and encode */
1295 target[j] = 'A' + (0x0F & (source[i] >> 4));
1296 target[j+1] = 'A' + (0x0F & source[i]);
1297 j+=2;
1298 }
1299
1300}
1301
1302
1303static int
1304ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001305 char * netbios_name, char * target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306{
1307 int rc = 0;
1308 int connected = 0;
1309 __be16 orig_port = 0;
1310
1311 if(*csocket == NULL) {
1312 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1313 if (rc < 0) {
1314 cERROR(1, ("Error %d creating socket",rc));
1315 *csocket = NULL;
1316 return rc;
1317 } else {
1318 /* BB other socket options to set KEEPALIVE, NODELAY? */
1319 cFYI(1,("Socket created"));
1320 (*csocket)->sk->sk_allocation = GFP_NOFS;
1321 }
1322 }
1323
1324 psin_server->sin_family = AF_INET;
1325 if(psin_server->sin_port) { /* user overrode default port */
1326 rc = (*csocket)->ops->connect(*csocket,
1327 (struct sockaddr *) psin_server,
1328 sizeof (struct sockaddr_in),0);
1329 if (rc >= 0)
1330 connected = 1;
1331 }
1332
1333 if(!connected) {
1334 /* save original port so we can retry user specified port
1335 later if fall back ports fail this time */
1336 orig_port = psin_server->sin_port;
1337
1338 /* do not retry on the same port we just failed on */
1339 if(psin_server->sin_port != htons(CIFS_PORT)) {
1340 psin_server->sin_port = htons(CIFS_PORT);
1341
1342 rc = (*csocket)->ops->connect(*csocket,
1343 (struct sockaddr *) psin_server,
1344 sizeof (struct sockaddr_in),0);
1345 if (rc >= 0)
1346 connected = 1;
1347 }
1348 }
1349 if (!connected) {
1350 psin_server->sin_port = htons(RFC1001_PORT);
1351 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1352 psin_server, sizeof (struct sockaddr_in),0);
1353 if (rc >= 0)
1354 connected = 1;
1355 }
1356
1357 /* give up here - unless we want to retry on different
1358 protocol families some day */
1359 if (!connected) {
1360 if(orig_port)
1361 psin_server->sin_port = orig_port;
1362 cFYI(1,("Error %d connecting to server via ipv4",rc));
1363 sock_release(*csocket);
1364 *csocket = NULL;
1365 return rc;
1366 }
1367 /* Eventually check for other socket options to change from
1368 the default. sock_setsockopt not used because it expects
1369 user space buffer */
1370 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1371
1372 /* send RFC1001 sessinit */
1373
1374 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1375 /* some servers require RFC1001 sessinit before sending
1376 negprot - BB check reconnection in case where second
1377 sessinit is sent but no second negprot */
1378 struct rfc1002_session_packet * ses_init_buf;
1379 struct smb_hdr * smb_buf;
Steve French433dc242005-04-28 22:41:08 -07001380 ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 if(ses_init_buf) {
1382 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frencha10faeb22005-08-22 21:38:31 -07001383 if(target_name && (target_name[0] != 0)) {
1384 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1385 target_name, 16);
1386 } else {
1387 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1388 DEFAULT_CIFS_CALLED_NAME,16);
1389 }
1390
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 ses_init_buf->trailer.session_req.calling_len = 32;
1392 /* calling name ends in null (byte 16) from old smb
1393 convention. */
1394 if(netbios_name && (netbios_name[0] !=0)) {
1395 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1396 netbios_name,16);
1397 } else {
1398 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1399 "LINUX_CIFS_CLNT",16);
1400 }
1401 ses_init_buf->trailer.session_req.scope1 = 0;
1402 ses_init_buf->trailer.session_req.scope2 = 0;
1403 smb_buf = (struct smb_hdr *)ses_init_buf;
1404 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1405 smb_buf->smb_buf_length = 0x81000044;
1406 rc = smb_send(*csocket, smb_buf, 0x44,
1407 (struct sockaddr *)psin_server);
1408 kfree(ses_init_buf);
1409 }
1410 /* else the negprot may still work without this
1411 even though malloc failed */
1412
1413 }
1414
1415 return rc;
1416}
1417
1418static int
1419ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1420{
1421 int rc = 0;
1422 int connected = 0;
1423 __be16 orig_port = 0;
1424
1425 if(*csocket == NULL) {
1426 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1427 if (rc < 0) {
1428 cERROR(1, ("Error %d creating ipv6 socket",rc));
1429 *csocket = NULL;
1430 return rc;
1431 } else {
1432 /* BB other socket options to set KEEPALIVE, NODELAY? */
1433 cFYI(1,("ipv6 Socket created"));
1434 (*csocket)->sk->sk_allocation = GFP_NOFS;
1435 }
1436 }
1437
1438 psin_server->sin6_family = AF_INET6;
1439
1440 if(psin_server->sin6_port) { /* user overrode default port */
1441 rc = (*csocket)->ops->connect(*csocket,
1442 (struct sockaddr *) psin_server,
1443 sizeof (struct sockaddr_in6),0);
1444 if (rc >= 0)
1445 connected = 1;
1446 }
1447
1448 if(!connected) {
1449 /* save original port so we can retry user specified port
1450 later if fall back ports fail this time */
1451
1452 orig_port = psin_server->sin6_port;
1453 /* do not retry on the same port we just failed on */
1454 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1455 psin_server->sin6_port = htons(CIFS_PORT);
1456
1457 rc = (*csocket)->ops->connect(*csocket,
1458 (struct sockaddr *) psin_server,
1459 sizeof (struct sockaddr_in6),0);
1460 if (rc >= 0)
1461 connected = 1;
1462 }
1463 }
1464 if (!connected) {
1465 psin_server->sin6_port = htons(RFC1001_PORT);
1466 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1467 psin_server, sizeof (struct sockaddr_in6),0);
1468 if (rc >= 0)
1469 connected = 1;
1470 }
1471
1472 /* give up here - unless we want to retry on different
1473 protocol families some day */
1474 if (!connected) {
1475 if(orig_port)
1476 psin_server->sin6_port = orig_port;
1477 cFYI(1,("Error %d connecting to server via ipv6",rc));
1478 sock_release(*csocket);
1479 *csocket = NULL;
1480 return rc;
1481 }
1482 /* Eventually check for other socket options to change from
1483 the default. sock_setsockopt not used because it expects
1484 user space buffer */
1485 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1486
1487 return rc;
1488}
1489
1490int
1491cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1492 char *mount_data, const char *devname)
1493{
1494 int rc = 0;
1495 int xid;
1496 int address_type = AF_INET;
1497 struct socket *csocket = NULL;
1498 struct sockaddr_in sin_server;
1499 struct sockaddr_in6 sin_server6;
1500 struct smb_vol volume_info;
1501 struct cifsSesInfo *pSesInfo = NULL;
1502 struct cifsSesInfo *existingCifsSes = NULL;
1503 struct cifsTconInfo *tcon = NULL;
1504 struct TCP_Server_Info *srvTcp = NULL;
1505
1506 xid = GetXid();
1507
1508/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1509
1510 memset(&volume_info,0,sizeof(struct smb_vol));
1511 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1512 if(volume_info.UNC)
1513 kfree(volume_info.UNC);
1514 if(volume_info.password)
1515 kfree(volume_info.password);
1516 FreeXid(xid);
1517 return -EINVAL;
1518 }
1519
1520 if (volume_info.username) {
1521 /* BB fixme parse for domain name here */
1522 cFYI(1, ("Username: %s ", volume_info.username));
1523
1524 } else {
1525 cifserror("No username specified ");
1526 /* In userspace mount helper we can get user name from alternate
1527 locations such as env variables and files on disk */
1528 if(volume_info.UNC)
1529 kfree(volume_info.UNC);
1530 if(volume_info.password)
1531 kfree(volume_info.password);
1532 FreeXid(xid);
1533 return -EINVAL;
1534 }
1535
1536 if (volume_info.UNCip && volume_info.UNC) {
1537 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1538
1539 if(rc <= 0) {
1540 /* not ipv4 address, try ipv6 */
1541 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1542 if(rc > 0)
1543 address_type = AF_INET6;
1544 } else {
1545 address_type = AF_INET;
1546 }
1547
1548 if(rc <= 0) {
1549 /* we failed translating address */
1550 if(volume_info.UNC)
1551 kfree(volume_info.UNC);
1552 if(volume_info.password)
1553 kfree(volume_info.password);
1554 FreeXid(xid);
1555 return -EINVAL;
1556 }
1557
1558 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1559 /* success */
1560 rc = 0;
1561 } else if (volume_info.UNCip){
1562 /* BB using ip addr as server name connect to the DFS root below */
1563 cERROR(1,("Connecting to DFS root not implemented yet"));
1564 if(volume_info.UNC)
1565 kfree(volume_info.UNC);
1566 if(volume_info.password)
1567 kfree(volume_info.password);
1568 FreeXid(xid);
1569 return -EINVAL;
1570 } else /* which servers DFS root would we conect to */ {
1571 cERROR(1,
1572 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
1573 if(volume_info.UNC)
1574 kfree(volume_info.UNC);
1575 if(volume_info.password)
1576 kfree(volume_info.password);
1577 FreeXid(xid);
1578 return -EINVAL;
1579 }
1580
1581 /* this is needed for ASCII cp to Unicode converts */
1582 if(volume_info.iocharset == NULL) {
1583 cifs_sb->local_nls = load_nls_default();
1584 /* load_nls_default can not return null */
1585 } else {
1586 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1587 if(cifs_sb->local_nls == NULL) {
1588 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
1589 if(volume_info.UNC)
1590 kfree(volume_info.UNC);
1591 if(volume_info.password)
1592 kfree(volume_info.password);
1593 FreeXid(xid);
1594 return -ELIBACC;
1595 }
1596 }
1597
1598 if(address_type == AF_INET)
1599 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1600 NULL /* no ipv6 addr */,
1601 volume_info.username, &srvTcp);
1602 else if(address_type == AF_INET6)
1603 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1604 &sin_server6.sin6_addr,
1605 volume_info.username, &srvTcp);
1606 else {
1607 if(volume_info.UNC)
1608 kfree(volume_info.UNC);
1609 if(volume_info.password)
1610 kfree(volume_info.password);
1611 FreeXid(xid);
1612 return -EINVAL;
1613 }
1614
1615
1616 if (srvTcp) {
1617 cFYI(1, ("Existing tcp session with server found "));
1618 } else { /* create socket */
1619 if(volume_info.port)
1620 sin_server.sin_port = htons(volume_info.port);
1621 else
1622 sin_server.sin_port = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001623 rc = ipv4_connect(&sin_server,&csocket,
1624 volume_info.source_rfc1001_name,
1625 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 if (rc < 0) {
1627 cERROR(1,
1628 ("Error connecting to IPv4 socket. Aborting operation"));
1629 if(csocket != NULL)
1630 sock_release(csocket);
1631 if(volume_info.UNC)
1632 kfree(volume_info.UNC);
1633 if(volume_info.password)
1634 kfree(volume_info.password);
1635 FreeXid(xid);
1636 return rc;
1637 }
1638
1639 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1640 if (srvTcp == NULL) {
1641 rc = -ENOMEM;
1642 sock_release(csocket);
1643 if(volume_info.UNC)
1644 kfree(volume_info.UNC);
1645 if(volume_info.password)
1646 kfree(volume_info.password);
1647 FreeXid(xid);
1648 return rc;
1649 } else {
1650 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1651 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1652 atomic_set(&srvTcp->inFlight,0);
1653 /* BB Add code for ipv6 case too */
1654 srvTcp->ssocket = csocket;
1655 srvTcp->protocolType = IPV4;
1656 init_waitqueue_head(&srvTcp->response_q);
1657 init_waitqueue_head(&srvTcp->request_q);
1658 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1659 /* at this point we are the only ones with the pointer
1660 to the struct since the kernel thread not created yet
1661 so no need to spinlock this init of tcpStatus */
1662 srvTcp->tcpStatus = CifsNew;
1663 init_MUTEX(&srvTcp->tcpSem);
1664 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1665 CLONE_FS | CLONE_FILES | CLONE_VM);
1666 if(rc < 0) {
1667 rc = -ENOMEM;
1668 sock_release(csocket);
1669 if(volume_info.UNC)
1670 kfree(volume_info.UNC);
1671 if(volume_info.password)
1672 kfree(volume_info.password);
1673 FreeXid(xid);
1674 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001675 }
1676 wait_for_completion(&cifsd_complete);
1677 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001679 memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001680 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 }
1682 }
1683
1684 if (existingCifsSes) {
1685 pSesInfo = existingCifsSes;
1686 cFYI(1, ("Existing smb sess found "));
1687 if(volume_info.password)
1688 kfree(volume_info.password);
1689 /* volume_info.UNC freed at end of function */
1690 } else if (!rc) {
1691 cFYI(1, ("Existing smb sess not found "));
1692 pSesInfo = sesInfoAlloc();
1693 if (pSesInfo == NULL)
1694 rc = -ENOMEM;
1695 else {
1696 pSesInfo->server = srvTcp;
1697 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1698 NIPQUAD(sin_server.sin_addr.s_addr));
1699 }
1700
1701 if (!rc){
1702 /* volume_info.password freed at unmount */
1703 if (volume_info.password)
1704 pSesInfo->password = volume_info.password;
1705 if (volume_info.username)
1706 strncpy(pSesInfo->userName,
1707 volume_info.username,MAX_USERNAME_SIZE);
1708 if (volume_info.domainname)
1709 strncpy(pSesInfo->domainName,
1710 volume_info.domainname,MAX_USERNAME_SIZE);
1711 pSesInfo->linux_uid = volume_info.linux_uid;
1712 down(&pSesInfo->sesSem);
1713 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1714 up(&pSesInfo->sesSem);
1715 if(!rc)
1716 atomic_inc(&srvTcp->socketUseCount);
1717 } else
1718 if(volume_info.password)
1719 kfree(volume_info.password);
1720 }
1721
1722 /* search for existing tcon to this server share */
1723 if (!rc) {
1724 if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
1725 cifs_sb->rsize = volume_info.rsize;
1726 else
1727 cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
1728 if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
1729 cifs_sb->wsize = volume_info.wsize;
1730 else
1731 cifs_sb->wsize = CIFSMaxBufSize; /* default */
1732 if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
1733 cifs_sb->rsize = PAGE_CACHE_SIZE;
1734 cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
1735 }
1736 cifs_sb->mnt_uid = volume_info.linux_uid;
1737 cifs_sb->mnt_gid = volume_info.linux_gid;
1738 cifs_sb->mnt_file_mode = volume_info.file_mode;
1739 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1740 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1741
1742 if(volume_info.noperm)
1743 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1744 if(volume_info.setuids)
1745 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1746 if(volume_info.server_ino)
1747 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001748 if(volume_info.remap)
1749 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 if(volume_info.no_xattr)
1751 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve Frenchd7245c22005-07-14 18:25:12 -05001752 if(volume_info.sfu_emul)
1753 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001754 if(volume_info.nobrl)
1755 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Jeremy Allisonac670552005-06-22 17:26:35 -07001756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 if(volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001758 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1760 }
1761
1762 tcon =
1763 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1764 volume_info.username);
1765 if (tcon) {
1766 cFYI(1, ("Found match on UNC path "));
1767 /* we can have only one retry value for a connection
1768 to a share so for resources mounted more than once
1769 to the same server share the last value passed in
1770 for the retry flag is used */
1771 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001772 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 } else {
1774 tcon = tconInfoAlloc();
1775 if (tcon == NULL)
1776 rc = -ENOMEM;
1777 else {
1778 /* check for null share name ie connect to dfs root */
1779
1780 /* BB check if this works for exactly length three strings */
1781 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1782 && (strchr(volume_info.UNC + 3, '/') ==
1783 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001784 rc = connect_to_dfs_path(xid, pSesInfo,
1785 "", cifs_sb->local_nls,
1786 cifs_sb->mnt_cifs_flags &
1787 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 if(volume_info.UNC)
1789 kfree(volume_info.UNC);
1790 FreeXid(xid);
1791 return -ENODEV;
1792 } else {
1793 rc = CIFSTCon(xid, pSesInfo,
1794 volume_info.UNC,
1795 tcon, cifs_sb->local_nls);
1796 cFYI(1, ("CIFS Tcon rc = %d", rc));
1797 }
1798 if (!rc) {
1799 atomic_inc(&pSesInfo->inUse);
1800 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001801 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 }
1803 }
1804 }
1805 }
1806 if(pSesInfo) {
1807 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1808 sb->s_maxbytes = (u64) 1 << 63;
1809 } else
1810 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1811 }
1812
1813 sb->s_time_gran = 100;
1814
1815/* on error free sesinfo and tcon struct if needed */
1816 if (rc) {
1817 /* if session setup failed, use count is zero but
1818 we still need to free cifsd thread */
1819 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1820 spin_lock(&GlobalMid_Lock);
1821 srvTcp->tcpStatus = CifsExiting;
1822 spin_unlock(&GlobalMid_Lock);
Steve Frenchf1914012005-08-18 09:37:34 -07001823 if(srvTcp->tsk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 send_sig(SIGKILL,srvTcp->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001825 wait_for_completion(&cifsd_complete);
1826 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 }
1828 /* If find_unc succeeded then rc == 0 so we can not end */
1829 if (tcon) /* up accidently freeing someone elses tcon struct */
1830 tconInfoFree(tcon);
1831 if (existingCifsSes == NULL) {
1832 if (pSesInfo) {
1833 if ((pSesInfo->server) &&
1834 (pSesInfo->status == CifsGood)) {
1835 int temp_rc;
1836 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1837 /* if the socketUseCount is now zero */
1838 if((temp_rc == -ESHUTDOWN) &&
Steve Frenchf1914012005-08-18 09:37:34 -07001839 (pSesInfo->server->tsk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 send_sig(SIGKILL,pSesInfo->server->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001841 wait_for_completion(&cifsd_complete);
1842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 } else
1844 cFYI(1, ("No session or bad tcon"));
1845 sesInfoFree(pSesInfo);
1846 /* pSesInfo = NULL; */
1847 }
1848 }
1849 } else {
1850 atomic_inc(&tcon->useCount);
1851 cifs_sb->tcon = tcon;
1852 tcon->ses = pSesInfo;
1853
1854 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001855 CIFSSMBQFSDeviceInfo(xid, tcon);
1856 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001858 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 if(!volume_info.no_psx_acl) {
1860 if(CIFS_UNIX_POSIX_ACL_CAP &
1861 le64_to_cpu(tcon->fsUnixInfo.Capability))
1862 cFYI(1,("server negotiated posix acl support"));
1863 sb->s_flags |= MS_POSIXACL;
1864 }
Jeremy Allisonac670552005-06-22 17:26:35 -07001865
1866 /* Try and negotiate POSIX pathnames if we can. */
1867 if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
1868 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French45abc6e2005-06-23 13:42:03 -05001869 if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
Jeremy Allisonac670552005-06-22 17:26:35 -07001870 cFYI(1,("negotiated posix pathnames support"));
1871 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
1872 } else {
1873 cFYI(1,("posix pathnames support requested but not supported"));
1874 }
1875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 }
1877 }
1878 }
1879
1880 /* volume_info.password is freed above when existing session found
1881 (in which case it is not needed anymore) but when new sesion is created
1882 the password ptr is put in the new session structure (in which case the
1883 password will be freed at unmount time) */
1884 if(volume_info.UNC)
1885 kfree(volume_info.UNC);
1886 FreeXid(xid);
1887 return rc;
1888}
1889
1890static int
1891CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1892 char session_key[CIFS_SESSION_KEY_SIZE],
1893 const struct nls_table *nls_codepage)
1894{
1895 struct smb_hdr *smb_buffer;
1896 struct smb_hdr *smb_buffer_response;
1897 SESSION_SETUP_ANDX *pSMB;
1898 SESSION_SETUP_ANDX *pSMBr;
1899 char *bcc_ptr;
1900 char *user;
1901 char *domain;
1902 int rc = 0;
1903 int remaining_words = 0;
1904 int bytes_returned = 0;
1905 int len;
1906 __u32 capabilities;
1907 __u16 count;
1908
1909 cFYI(1, ("In sesssetup "));
1910 if(ses == NULL)
1911 return -EINVAL;
1912 user = ses->userName;
1913 domain = ses->domainName;
1914 smb_buffer = cifs_buf_get();
1915 if (smb_buffer == NULL) {
1916 return -ENOMEM;
1917 }
1918 smb_buffer_response = smb_buffer;
1919 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1920
1921 /* send SMBsessionSetup here */
1922 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1923 NULL /* no tCon exists yet */ , 13 /* wct */ );
1924
Steve French1982c342005-08-17 12:38:22 -07001925 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 pSMB->req_no_secext.AndXCommand = 0xFF;
1927 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1928 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1929
1930 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1931 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1932
1933 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1934 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1935 if (ses->capabilities & CAP_UNICODE) {
1936 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1937 capabilities |= CAP_UNICODE;
1938 }
1939 if (ses->capabilities & CAP_STATUS32) {
1940 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1941 capabilities |= CAP_STATUS32;
1942 }
1943 if (ses->capabilities & CAP_DFS) {
1944 smb_buffer->Flags2 |= SMBFLG2_DFS;
1945 capabilities |= CAP_DFS;
1946 }
1947 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1948
1949 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1950 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1951
1952 pSMB->req_no_secext.CaseSensitivePasswordLength =
1953 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1954 bcc_ptr = pByteArea(smb_buffer);
1955 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1956 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1957 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1958 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1959
1960 if (ses->capabilities & CAP_UNICODE) {
1961 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1962 *bcc_ptr = 0;
1963 bcc_ptr++;
1964 }
1965 if(user == NULL)
1966 bytes_returned = 0; /* skill null user */
1967 else
1968 bytes_returned =
1969 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1970 nls_codepage);
1971 /* convert number of 16 bit words to bytes */
1972 bcc_ptr += 2 * bytes_returned;
1973 bcc_ptr += 2; /* trailing null */
1974 if (domain == NULL)
1975 bytes_returned =
1976 cifs_strtoUCS((wchar_t *) bcc_ptr,
1977 "CIFS_LINUX_DOM", 32, nls_codepage);
1978 else
1979 bytes_returned =
1980 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1981 nls_codepage);
1982 bcc_ptr += 2 * bytes_returned;
1983 bcc_ptr += 2;
1984 bytes_returned =
1985 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1986 32, nls_codepage);
1987 bcc_ptr += 2 * bytes_returned;
1988 bytes_returned =
1989 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1990 32, nls_codepage);
1991 bcc_ptr += 2 * bytes_returned;
1992 bcc_ptr += 2;
1993 bytes_returned =
1994 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1995 64, nls_codepage);
1996 bcc_ptr += 2 * bytes_returned;
1997 bcc_ptr += 2;
1998 } else {
1999 if(user != NULL) {
2000 strncpy(bcc_ptr, user, 200);
2001 bcc_ptr += strnlen(user, 200);
2002 }
2003 *bcc_ptr = 0;
2004 bcc_ptr++;
2005 if (domain == NULL) {
2006 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2007 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2008 } else {
2009 strncpy(bcc_ptr, domain, 64);
2010 bcc_ptr += strnlen(domain, 64);
2011 *bcc_ptr = 0;
2012 bcc_ptr++;
2013 }
2014 strcpy(bcc_ptr, "Linux version ");
2015 bcc_ptr += strlen("Linux version ");
2016 strcpy(bcc_ptr, system_utsname.release);
2017 bcc_ptr += strlen(system_utsname.release) + 1;
2018 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2019 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2020 }
2021 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2022 smb_buffer->smb_buf_length += count;
2023 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2024
2025 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2026 &bytes_returned, 1);
2027 if (rc) {
2028/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2029 } else if ((smb_buffer_response->WordCount == 3)
2030 || (smb_buffer_response->WordCount == 4)) {
2031 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2032 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2033 if (action & GUEST_LOGIN)
2034 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2035 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2036 cFYI(1, ("UID = %d ", ses->Suid));
2037 /* response can have either 3 or 4 word count - Samba sends 3 */
2038 bcc_ptr = pByteArea(smb_buffer_response);
2039 if ((pSMBr->resp.hdr.WordCount == 3)
2040 || ((pSMBr->resp.hdr.WordCount == 4)
2041 && (blob_len < pSMBr->resp.ByteCount))) {
2042 if (pSMBr->resp.hdr.WordCount == 4)
2043 bcc_ptr += blob_len;
2044
2045 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2046 if ((long) (bcc_ptr) % 2) {
2047 remaining_words =
2048 (BCC(smb_buffer_response) - 1) /2;
2049 bcc_ptr++; /* Unicode strings must be word aligned */
2050 } else {
2051 remaining_words =
2052 BCC(smb_buffer_response) / 2;
2053 }
2054 len =
2055 UniStrnlen((wchar_t *) bcc_ptr,
2056 remaining_words - 1);
2057/* We look for obvious messed up bcc or strings in response so we do not go off
2058 the end since (at least) WIN2K and Windows XP have a major bug in not null
2059 terminating last Unicode string in response */
Steve French433dc242005-04-28 22:41:08 -07002060 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2061 if(ses->serverOS == NULL)
2062 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 cifs_strfromUCS_le(ses->serverOS,
2064 (wchar_t *)bcc_ptr, len,nls_codepage);
2065 bcc_ptr += 2 * (len + 1);
2066 remaining_words -= len + 1;
2067 ses->serverOS[2 * len] = 0;
2068 ses->serverOS[1 + (2 * len)] = 0;
2069 if (remaining_words > 0) {
2070 len = UniStrnlen((wchar_t *)bcc_ptr,
2071 remaining_words-1);
Steve French433dc242005-04-28 22:41:08 -07002072 ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
2073 if(ses->serverNOS == NULL)
2074 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 cifs_strfromUCS_le(ses->serverNOS,
2076 (wchar_t *)bcc_ptr,len,nls_codepage);
2077 bcc_ptr += 2 * (len + 1);
2078 ses->serverNOS[2 * len] = 0;
2079 ses->serverNOS[1 + (2 * len)] = 0;
2080 if(strncmp(ses->serverNOS,
2081 "NT LAN Manager 4",16) == 0) {
2082 cFYI(1,("NT4 server"));
2083 ses->flags |= CIFS_SES_NT4;
2084 }
2085 remaining_words -= len + 1;
2086 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002087 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2089 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002090 kcalloc(1, 2*(len+1),GFP_KERNEL);
2091 if(ses->serverDomain == NULL)
2092 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 cifs_strfromUCS_le(ses->serverDomain,
2094 (wchar_t *)bcc_ptr,len,nls_codepage);
2095 bcc_ptr += 2 * (len + 1);
2096 ses->serverDomain[2*len] = 0;
2097 ses->serverDomain[1+(2*len)] = 0;
2098 } /* else no more room so create dummy domain string */
2099 else
Steve French433dc242005-04-28 22:41:08 -07002100 ses->serverDomain =
2101 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002103 /* if these kcallocs fail not much we
2104 can do, but better to not fail the
2105 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002107 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002109 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 }
2111 } else { /* ASCII */
2112 len = strnlen(bcc_ptr, 1024);
2113 if (((long) bcc_ptr + len) - (long)
2114 pByteArea(smb_buffer_response)
2115 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002116 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
2117 if(ses->serverOS == NULL)
2118 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 strncpy(ses->serverOS,bcc_ptr, len);
2120
2121 bcc_ptr += len;
2122 bcc_ptr[0] = 0; /* null terminate the string */
2123 bcc_ptr++;
2124
2125 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002126 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2127 if(ses->serverNOS == NULL)
2128 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 strncpy(ses->serverNOS, bcc_ptr, len);
2130 bcc_ptr += len;
2131 bcc_ptr[0] = 0;
2132 bcc_ptr++;
2133
2134 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002135 ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
2136 if(ses->serverDomain == NULL)
2137 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 strncpy(ses->serverDomain, bcc_ptr, len);
2139 bcc_ptr += len;
2140 bcc_ptr[0] = 0;
2141 bcc_ptr++;
2142 } else
2143 cFYI(1,
2144 ("Variable field of length %d extends beyond end of smb ",
2145 len));
2146 }
2147 } else {
2148 cERROR(1,
2149 (" Security Blob Length extends beyond end of SMB"));
2150 }
2151 } else {
2152 cERROR(1,
2153 (" Invalid Word count %d: ",
2154 smb_buffer_response->WordCount));
2155 rc = -EIO;
2156 }
Steve French433dc242005-04-28 22:41:08 -07002157sesssetup_nomem: /* do not return an error on nomem for the info strings,
2158 since that could make reconnection harder, and
2159 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 if (smb_buffer)
2161 cifs_buf_release(smb_buffer);
2162
2163 return rc;
2164}
2165
2166static int
2167CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2168 char *SecurityBlob,int SecurityBlobLength,
2169 const struct nls_table *nls_codepage)
2170{
2171 struct smb_hdr *smb_buffer;
2172 struct smb_hdr *smb_buffer_response;
2173 SESSION_SETUP_ANDX *pSMB;
2174 SESSION_SETUP_ANDX *pSMBr;
2175 char *bcc_ptr;
2176 char *user;
2177 char *domain;
2178 int rc = 0;
2179 int remaining_words = 0;
2180 int bytes_returned = 0;
2181 int len;
2182 __u32 capabilities;
2183 __u16 count;
2184
2185 cFYI(1, ("In spnego sesssetup "));
2186 if(ses == NULL)
2187 return -EINVAL;
2188 user = ses->userName;
2189 domain = ses->domainName;
2190
2191 smb_buffer = cifs_buf_get();
2192 if (smb_buffer == NULL) {
2193 return -ENOMEM;
2194 }
2195 smb_buffer_response = smb_buffer;
2196 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2197
2198 /* send SMBsessionSetup here */
2199 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2200 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002201
2202 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2204 pSMB->req.AndXCommand = 0xFF;
2205 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2206 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2207
2208 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2209 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2210
2211 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2212 CAP_EXTENDED_SECURITY;
2213 if (ses->capabilities & CAP_UNICODE) {
2214 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2215 capabilities |= CAP_UNICODE;
2216 }
2217 if (ses->capabilities & CAP_STATUS32) {
2218 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2219 capabilities |= CAP_STATUS32;
2220 }
2221 if (ses->capabilities & CAP_DFS) {
2222 smb_buffer->Flags2 |= SMBFLG2_DFS;
2223 capabilities |= CAP_DFS;
2224 }
2225 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2226
2227 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2228 bcc_ptr = pByteArea(smb_buffer);
2229 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2230 bcc_ptr += SecurityBlobLength;
2231
2232 if (ses->capabilities & CAP_UNICODE) {
2233 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2234 *bcc_ptr = 0;
2235 bcc_ptr++;
2236 }
2237 bytes_returned =
2238 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2239 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2240 bcc_ptr += 2; /* trailing null */
2241 if (domain == NULL)
2242 bytes_returned =
2243 cifs_strtoUCS((wchar_t *) bcc_ptr,
2244 "CIFS_LINUX_DOM", 32, nls_codepage);
2245 else
2246 bytes_returned =
2247 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2248 nls_codepage);
2249 bcc_ptr += 2 * bytes_returned;
2250 bcc_ptr += 2;
2251 bytes_returned =
2252 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2253 32, nls_codepage);
2254 bcc_ptr += 2 * bytes_returned;
2255 bytes_returned =
2256 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2257 nls_codepage);
2258 bcc_ptr += 2 * bytes_returned;
2259 bcc_ptr += 2;
2260 bytes_returned =
2261 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2262 64, nls_codepage);
2263 bcc_ptr += 2 * bytes_returned;
2264 bcc_ptr += 2;
2265 } else {
2266 strncpy(bcc_ptr, user, 200);
2267 bcc_ptr += strnlen(user, 200);
2268 *bcc_ptr = 0;
2269 bcc_ptr++;
2270 if (domain == NULL) {
2271 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2272 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2273 } else {
2274 strncpy(bcc_ptr, domain, 64);
2275 bcc_ptr += strnlen(domain, 64);
2276 *bcc_ptr = 0;
2277 bcc_ptr++;
2278 }
2279 strcpy(bcc_ptr, "Linux version ");
2280 bcc_ptr += strlen("Linux version ");
2281 strcpy(bcc_ptr, system_utsname.release);
2282 bcc_ptr += strlen(system_utsname.release) + 1;
2283 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2284 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2285 }
2286 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2287 smb_buffer->smb_buf_length += count;
2288 pSMB->req.ByteCount = cpu_to_le16(count);
2289
2290 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2291 &bytes_returned, 1);
2292 if (rc) {
2293/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2294 } else if ((smb_buffer_response->WordCount == 3)
2295 || (smb_buffer_response->WordCount == 4)) {
2296 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2297 __u16 blob_len =
2298 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2299 if (action & GUEST_LOGIN)
2300 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2301 if (ses) {
2302 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2303 cFYI(1, ("UID = %d ", ses->Suid));
2304 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2305
2306 /* BB Fix below to make endian neutral !! */
2307
2308 if ((pSMBr->resp.hdr.WordCount == 3)
2309 || ((pSMBr->resp.hdr.WordCount == 4)
2310 && (blob_len <
2311 pSMBr->resp.ByteCount))) {
2312 if (pSMBr->resp.hdr.WordCount == 4) {
2313 bcc_ptr +=
2314 blob_len;
2315 cFYI(1,
2316 ("Security Blob Length %d ",
2317 blob_len));
2318 }
2319
2320 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2321 if ((long) (bcc_ptr) % 2) {
2322 remaining_words =
2323 (BCC(smb_buffer_response)
2324 - 1) / 2;
2325 bcc_ptr++; /* Unicode strings must be word aligned */
2326 } else {
2327 remaining_words =
2328 BCC
2329 (smb_buffer_response) / 2;
2330 }
2331 len =
2332 UniStrnlen((wchar_t *) bcc_ptr,
2333 remaining_words - 1);
2334/* We look for obvious messed up bcc or strings in response so we do not go off
2335 the end since (at least) WIN2K and Windows XP have a major bug in not null
2336 terminating last Unicode string in response */
2337 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002338 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 cifs_strfromUCS_le(ses->serverOS,
2340 (wchar_t *)
2341 bcc_ptr, len,
2342 nls_codepage);
2343 bcc_ptr += 2 * (len + 1);
2344 remaining_words -= len + 1;
2345 ses->serverOS[2 * len] = 0;
2346 ses->serverOS[1 + (2 * len)] = 0;
2347 if (remaining_words > 0) {
2348 len = UniStrnlen((wchar_t *)bcc_ptr,
2349 remaining_words
2350 - 1);
2351 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002352 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 GFP_KERNEL);
2354 cifs_strfromUCS_le(ses->serverNOS,
2355 (wchar_t *)bcc_ptr,
2356 len,
2357 nls_codepage);
2358 bcc_ptr += 2 * (len + 1);
2359 ses->serverNOS[2 * len] = 0;
2360 ses->serverNOS[1 + (2 * len)] = 0;
2361 remaining_words -= len + 1;
2362 if (remaining_words > 0) {
2363 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2364 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve French433dc242005-04-28 22:41:08 -07002365 ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 cifs_strfromUCS_le(ses->serverDomain,
2367 (wchar_t *)bcc_ptr,
2368 len,
2369 nls_codepage);
2370 bcc_ptr += 2*(len+1);
2371 ses->serverDomain[2*len] = 0;
2372 ses->serverDomain[1+(2*len)] = 0;
2373 } /* else no more room so create dummy domain string */
2374 else
2375 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002376 kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002378 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2379 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 }
2381 } else { /* ASCII */
2382
2383 len = strnlen(bcc_ptr, 1024);
2384 if (((long) bcc_ptr + len) - (long)
2385 pByteArea(smb_buffer_response)
2386 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002387 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 strncpy(ses->serverOS, bcc_ptr, len);
2389
2390 bcc_ptr += len;
2391 bcc_ptr[0] = 0; /* null terminate the string */
2392 bcc_ptr++;
2393
2394 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002395 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 strncpy(ses->serverNOS, bcc_ptr, len);
2397 bcc_ptr += len;
2398 bcc_ptr[0] = 0;
2399 bcc_ptr++;
2400
2401 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002402 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 strncpy(ses->serverDomain, bcc_ptr, len);
2404 bcc_ptr += len;
2405 bcc_ptr[0] = 0;
2406 bcc_ptr++;
2407 } else
2408 cFYI(1,
2409 ("Variable field of length %d extends beyond end of smb ",
2410 len));
2411 }
2412 } else {
2413 cERROR(1,
2414 (" Security Blob Length extends beyond end of SMB"));
2415 }
2416 } else {
2417 cERROR(1, ("No session structure passed in."));
2418 }
2419 } else {
2420 cERROR(1,
2421 (" Invalid Word count %d: ",
2422 smb_buffer_response->WordCount));
2423 rc = -EIO;
2424 }
2425
2426 if (smb_buffer)
2427 cifs_buf_release(smb_buffer);
2428
2429 return rc;
2430}
2431
2432static int
2433CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2434 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2435 const struct nls_table *nls_codepage)
2436{
2437 struct smb_hdr *smb_buffer;
2438 struct smb_hdr *smb_buffer_response;
2439 SESSION_SETUP_ANDX *pSMB;
2440 SESSION_SETUP_ANDX *pSMBr;
2441 char *bcc_ptr;
2442 char *domain;
2443 int rc = 0;
2444 int remaining_words = 0;
2445 int bytes_returned = 0;
2446 int len;
2447 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2448 PNEGOTIATE_MESSAGE SecurityBlob;
2449 PCHALLENGE_MESSAGE SecurityBlob2;
2450 __u32 negotiate_flags, capabilities;
2451 __u16 count;
2452
2453 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2454 if(ses == NULL)
2455 return -EINVAL;
2456 domain = ses->domainName;
2457 *pNTLMv2_flag = FALSE;
2458 smb_buffer = cifs_buf_get();
2459 if (smb_buffer == NULL) {
2460 return -ENOMEM;
2461 }
2462 smb_buffer_response = smb_buffer;
2463 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2464 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2465
2466 /* send SMBsessionSetup here */
2467 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2468 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002469
2470 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2472 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2473
2474 pSMB->req.AndXCommand = 0xFF;
2475 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2476 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2477
2478 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2479 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2480
2481 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2482 CAP_EXTENDED_SECURITY;
2483 if (ses->capabilities & CAP_UNICODE) {
2484 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2485 capabilities |= CAP_UNICODE;
2486 }
2487 if (ses->capabilities & CAP_STATUS32) {
2488 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2489 capabilities |= CAP_STATUS32;
2490 }
2491 if (ses->capabilities & CAP_DFS) {
2492 smb_buffer->Flags2 |= SMBFLG2_DFS;
2493 capabilities |= CAP_DFS;
2494 }
2495 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2496
2497 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2498 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2499 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2500 SecurityBlob->MessageType = NtLmNegotiate;
2501 negotiate_flags =
2502 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2503 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2504 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2505 if(sign_CIFS_PDUs)
2506 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2507 if(ntlmv2_support)
2508 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2509 /* setup pointers to domain name and workstation name */
2510 bcc_ptr += SecurityBlobLength;
2511
2512 SecurityBlob->WorkstationName.Buffer = 0;
2513 SecurityBlob->WorkstationName.Length = 0;
2514 SecurityBlob->WorkstationName.MaximumLength = 0;
2515
2516 if (domain == NULL) {
2517 SecurityBlob->DomainName.Buffer = 0;
2518 SecurityBlob->DomainName.Length = 0;
2519 SecurityBlob->DomainName.MaximumLength = 0;
2520 } else {
2521 __u16 len;
2522 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2523 strncpy(bcc_ptr, domain, 63);
2524 len = strnlen(domain, 64);
2525 SecurityBlob->DomainName.MaximumLength =
2526 cpu_to_le16(len);
2527 SecurityBlob->DomainName.Buffer =
2528 cpu_to_le32((long) &SecurityBlob->
2529 DomainString -
2530 (long) &SecurityBlob->Signature);
2531 bcc_ptr += len;
2532 SecurityBlobLength += len;
2533 SecurityBlob->DomainName.Length =
2534 cpu_to_le16(len);
2535 }
2536 if (ses->capabilities & CAP_UNICODE) {
2537 if ((long) bcc_ptr % 2) {
2538 *bcc_ptr = 0;
2539 bcc_ptr++;
2540 }
2541
2542 bytes_returned =
2543 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2544 32, nls_codepage);
2545 bcc_ptr += 2 * bytes_returned;
2546 bytes_returned =
2547 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2548 nls_codepage);
2549 bcc_ptr += 2 * bytes_returned;
2550 bcc_ptr += 2; /* null terminate Linux version */
2551 bytes_returned =
2552 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2553 64, nls_codepage);
2554 bcc_ptr += 2 * bytes_returned;
2555 *(bcc_ptr + 1) = 0;
2556 *(bcc_ptr + 2) = 0;
2557 bcc_ptr += 2; /* null terminate network opsys string */
2558 *(bcc_ptr + 1) = 0;
2559 *(bcc_ptr + 2) = 0;
2560 bcc_ptr += 2; /* null domain */
2561 } else { /* ASCII */
2562 strcpy(bcc_ptr, "Linux version ");
2563 bcc_ptr += strlen("Linux version ");
2564 strcpy(bcc_ptr, system_utsname.release);
2565 bcc_ptr += strlen(system_utsname.release) + 1;
2566 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2567 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2568 bcc_ptr++; /* empty domain field */
2569 *bcc_ptr = 0;
2570 }
2571 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2572 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2573 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2574 smb_buffer->smb_buf_length += count;
2575 pSMB->req.ByteCount = cpu_to_le16(count);
2576
2577 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2578 &bytes_returned, 1);
2579
2580 if (smb_buffer_response->Status.CifsError ==
2581 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2582 rc = 0;
2583
2584 if (rc) {
2585/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2586 } else if ((smb_buffer_response->WordCount == 3)
2587 || (smb_buffer_response->WordCount == 4)) {
2588 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2589 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2590
2591 if (action & GUEST_LOGIN)
2592 cFYI(1, (" Guest login"));
2593 /* Do we want to set anything in SesInfo struct when guest login? */
2594
2595 bcc_ptr = pByteArea(smb_buffer_response);
2596 /* response can have either 3 or 4 word count - Samba sends 3 */
2597
2598 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2599 if (SecurityBlob2->MessageType != NtLmChallenge) {
2600 cFYI(1,
2601 ("Unexpected NTLMSSP message type received %d",
2602 SecurityBlob2->MessageType));
2603 } else if (ses) {
2604 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2605 cFYI(1, ("UID = %d ", ses->Suid));
2606 if ((pSMBr->resp.hdr.WordCount == 3)
2607 || ((pSMBr->resp.hdr.WordCount == 4)
2608 && (blob_len <
2609 pSMBr->resp.ByteCount))) {
2610
2611 if (pSMBr->resp.hdr.WordCount == 4) {
2612 bcc_ptr += blob_len;
2613 cFYI(1,
2614 ("Security Blob Length %d ",
2615 blob_len));
2616 }
2617
2618 cFYI(1, ("NTLMSSP Challenge rcvd "));
2619
2620 memcpy(ses->server->cryptKey,
2621 SecurityBlob2->Challenge,
2622 CIFS_CRYPTO_KEY_SIZE);
2623 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2624 *pNTLMv2_flag = TRUE;
2625
2626 if((SecurityBlob2->NegotiateFlags &
2627 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2628 || (sign_CIFS_PDUs > 1))
2629 ses->server->secMode |=
2630 SECMODE_SIGN_REQUIRED;
2631 if ((SecurityBlob2->NegotiateFlags &
2632 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2633 ses->server->secMode |=
2634 SECMODE_SIGN_ENABLED;
2635
2636 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2637 if ((long) (bcc_ptr) % 2) {
2638 remaining_words =
2639 (BCC(smb_buffer_response)
2640 - 1) / 2;
2641 bcc_ptr++; /* Unicode strings must be word aligned */
2642 } else {
2643 remaining_words =
2644 BCC
2645 (smb_buffer_response) / 2;
2646 }
2647 len =
2648 UniStrnlen((wchar_t *) bcc_ptr,
2649 remaining_words - 1);
2650/* We look for obvious messed up bcc or strings in response so we do not go off
2651 the end since (at least) WIN2K and Windows XP have a major bug in not null
2652 terminating last Unicode string in response */
2653 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002654 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 cifs_strfromUCS_le(ses->serverOS,
2656 (wchar_t *)
2657 bcc_ptr, len,
2658 nls_codepage);
2659 bcc_ptr += 2 * (len + 1);
2660 remaining_words -= len + 1;
2661 ses->serverOS[2 * len] = 0;
2662 ses->serverOS[1 + (2 * len)] = 0;
2663 if (remaining_words > 0) {
2664 len = UniStrnlen((wchar_t *)
2665 bcc_ptr,
2666 remaining_words
2667 - 1);
2668 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002669 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 GFP_KERNEL);
2671 cifs_strfromUCS_le(ses->
2672 serverNOS,
2673 (wchar_t *)
2674 bcc_ptr,
2675 len,
2676 nls_codepage);
2677 bcc_ptr += 2 * (len + 1);
2678 ses->serverNOS[2 * len] = 0;
2679 ses->serverNOS[1 +
2680 (2 * len)] = 0;
2681 remaining_words -= len + 1;
2682 if (remaining_words > 0) {
2683 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2684 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2685 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002686 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 (len +
2688 1),
2689 GFP_KERNEL);
2690 cifs_strfromUCS_le
2691 (ses->
2692 serverDomain,
2693 (wchar_t *)
2694 bcc_ptr, len,
2695 nls_codepage);
2696 bcc_ptr +=
2697 2 * (len + 1);
2698 ses->
2699 serverDomain[2
2700 * len]
2701 = 0;
2702 ses->
2703 serverDomain[1
2704 +
2705 (2
2706 *
2707 len)]
2708 = 0;
2709 } /* else no more room so create dummy domain string */
2710 else
2711 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002712 kcalloc(1, 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 GFP_KERNEL);
2714 } else { /* no room so create dummy domain and NOS string */
2715 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002716 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002718 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 }
2720 } else { /* ASCII */
2721 len = strnlen(bcc_ptr, 1024);
2722 if (((long) bcc_ptr + len) - (long)
2723 pByteArea(smb_buffer_response)
2724 <= BCC(smb_buffer_response)) {
2725 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002726 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 GFP_KERNEL);
2728 strncpy(ses->serverOS,
2729 bcc_ptr, len);
2730
2731 bcc_ptr += len;
2732 bcc_ptr[0] = 0; /* null terminate string */
2733 bcc_ptr++;
2734
2735 len = strnlen(bcc_ptr, 1024);
2736 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002737 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 GFP_KERNEL);
2739 strncpy(ses->serverNOS, bcc_ptr, len);
2740 bcc_ptr += len;
2741 bcc_ptr[0] = 0;
2742 bcc_ptr++;
2743
2744 len = strnlen(bcc_ptr, 1024);
2745 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002746 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 GFP_KERNEL);
2748 strncpy(ses->serverDomain, bcc_ptr, len);
2749 bcc_ptr += len;
2750 bcc_ptr[0] = 0;
2751 bcc_ptr++;
2752 } else
2753 cFYI(1,
2754 ("Variable field of length %d extends beyond end of smb ",
2755 len));
2756 }
2757 } else {
2758 cERROR(1,
2759 (" Security Blob Length extends beyond end of SMB"));
2760 }
2761 } else {
2762 cERROR(1, ("No session structure passed in."));
2763 }
2764 } else {
2765 cERROR(1,
2766 (" Invalid Word count %d: ",
2767 smb_buffer_response->WordCount));
2768 rc = -EIO;
2769 }
2770
2771 if (smb_buffer)
2772 cifs_buf_release(smb_buffer);
2773
2774 return rc;
2775}
2776static int
2777CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2778 char *ntlm_session_key, int ntlmv2_flag,
2779 const struct nls_table *nls_codepage)
2780{
2781 struct smb_hdr *smb_buffer;
2782 struct smb_hdr *smb_buffer_response;
2783 SESSION_SETUP_ANDX *pSMB;
2784 SESSION_SETUP_ANDX *pSMBr;
2785 char *bcc_ptr;
2786 char *user;
2787 char *domain;
2788 int rc = 0;
2789 int remaining_words = 0;
2790 int bytes_returned = 0;
2791 int len;
2792 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2793 PAUTHENTICATE_MESSAGE SecurityBlob;
2794 __u32 negotiate_flags, capabilities;
2795 __u16 count;
2796
2797 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2798 if(ses == NULL)
2799 return -EINVAL;
2800 user = ses->userName;
2801 domain = ses->domainName;
2802 smb_buffer = cifs_buf_get();
2803 if (smb_buffer == NULL) {
2804 return -ENOMEM;
2805 }
2806 smb_buffer_response = smb_buffer;
2807 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2808 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2809
2810 /* send SMBsessionSetup here */
2811 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2812 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002813
2814 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2816 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2817 pSMB->req.AndXCommand = 0xFF;
2818 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2819 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2820
2821 pSMB->req.hdr.Uid = ses->Suid;
2822
2823 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2824 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2825
2826 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2827 CAP_EXTENDED_SECURITY;
2828 if (ses->capabilities & CAP_UNICODE) {
2829 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2830 capabilities |= CAP_UNICODE;
2831 }
2832 if (ses->capabilities & CAP_STATUS32) {
2833 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2834 capabilities |= CAP_STATUS32;
2835 }
2836 if (ses->capabilities & CAP_DFS) {
2837 smb_buffer->Flags2 |= SMBFLG2_DFS;
2838 capabilities |= CAP_DFS;
2839 }
2840 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2841
2842 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2843 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2844 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2845 SecurityBlob->MessageType = NtLmAuthenticate;
2846 bcc_ptr += SecurityBlobLength;
2847 negotiate_flags =
2848 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2849 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2850 0x80000000 | NTLMSSP_NEGOTIATE_128;
2851 if(sign_CIFS_PDUs)
2852 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2853 if(ntlmv2_flag)
2854 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2855
2856/* setup pointers to domain name and workstation name */
2857
2858 SecurityBlob->WorkstationName.Buffer = 0;
2859 SecurityBlob->WorkstationName.Length = 0;
2860 SecurityBlob->WorkstationName.MaximumLength = 0;
2861 SecurityBlob->SessionKey.Length = 0;
2862 SecurityBlob->SessionKey.MaximumLength = 0;
2863 SecurityBlob->SessionKey.Buffer = 0;
2864
2865 SecurityBlob->LmChallengeResponse.Length = 0;
2866 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2867 SecurityBlob->LmChallengeResponse.Buffer = 0;
2868
2869 SecurityBlob->NtChallengeResponse.Length =
2870 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2871 SecurityBlob->NtChallengeResponse.MaximumLength =
2872 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2873 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2874 SecurityBlob->NtChallengeResponse.Buffer =
2875 cpu_to_le32(SecurityBlobLength);
2876 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2877 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2878
2879 if (ses->capabilities & CAP_UNICODE) {
2880 if (domain == NULL) {
2881 SecurityBlob->DomainName.Buffer = 0;
2882 SecurityBlob->DomainName.Length = 0;
2883 SecurityBlob->DomainName.MaximumLength = 0;
2884 } else {
2885 __u16 len =
2886 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2887 nls_codepage);
2888 len *= 2;
2889 SecurityBlob->DomainName.MaximumLength =
2890 cpu_to_le16(len);
2891 SecurityBlob->DomainName.Buffer =
2892 cpu_to_le32(SecurityBlobLength);
2893 bcc_ptr += len;
2894 SecurityBlobLength += len;
2895 SecurityBlob->DomainName.Length =
2896 cpu_to_le16(len);
2897 }
2898 if (user == NULL) {
2899 SecurityBlob->UserName.Buffer = 0;
2900 SecurityBlob->UserName.Length = 0;
2901 SecurityBlob->UserName.MaximumLength = 0;
2902 } else {
2903 __u16 len =
2904 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2905 nls_codepage);
2906 len *= 2;
2907 SecurityBlob->UserName.MaximumLength =
2908 cpu_to_le16(len);
2909 SecurityBlob->UserName.Buffer =
2910 cpu_to_le32(SecurityBlobLength);
2911 bcc_ptr += len;
2912 SecurityBlobLength += len;
2913 SecurityBlob->UserName.Length =
2914 cpu_to_le16(len);
2915 }
2916
2917 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2918 SecurityBlob->WorkstationName.Length *= 2;
2919 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2920 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2921 bcc_ptr += SecurityBlob->WorkstationName.Length;
2922 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2923 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2924
2925 if ((long) bcc_ptr % 2) {
2926 *bcc_ptr = 0;
2927 bcc_ptr++;
2928 }
2929 bytes_returned =
2930 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2931 32, nls_codepage);
2932 bcc_ptr += 2 * bytes_returned;
2933 bytes_returned =
2934 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2935 nls_codepage);
2936 bcc_ptr += 2 * bytes_returned;
2937 bcc_ptr += 2; /* null term version string */
2938 bytes_returned =
2939 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2940 64, nls_codepage);
2941 bcc_ptr += 2 * bytes_returned;
2942 *(bcc_ptr + 1) = 0;
2943 *(bcc_ptr + 2) = 0;
2944 bcc_ptr += 2; /* null terminate network opsys string */
2945 *(bcc_ptr + 1) = 0;
2946 *(bcc_ptr + 2) = 0;
2947 bcc_ptr += 2; /* null domain */
2948 } else { /* ASCII */
2949 if (domain == NULL) {
2950 SecurityBlob->DomainName.Buffer = 0;
2951 SecurityBlob->DomainName.Length = 0;
2952 SecurityBlob->DomainName.MaximumLength = 0;
2953 } else {
2954 __u16 len;
2955 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2956 strncpy(bcc_ptr, domain, 63);
2957 len = strnlen(domain, 64);
2958 SecurityBlob->DomainName.MaximumLength =
2959 cpu_to_le16(len);
2960 SecurityBlob->DomainName.Buffer =
2961 cpu_to_le32(SecurityBlobLength);
2962 bcc_ptr += len;
2963 SecurityBlobLength += len;
2964 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2965 }
2966 if (user == NULL) {
2967 SecurityBlob->UserName.Buffer = 0;
2968 SecurityBlob->UserName.Length = 0;
2969 SecurityBlob->UserName.MaximumLength = 0;
2970 } else {
2971 __u16 len;
2972 strncpy(bcc_ptr, user, 63);
2973 len = strnlen(user, 64);
2974 SecurityBlob->UserName.MaximumLength =
2975 cpu_to_le16(len);
2976 SecurityBlob->UserName.Buffer =
2977 cpu_to_le32(SecurityBlobLength);
2978 bcc_ptr += len;
2979 SecurityBlobLength += len;
2980 SecurityBlob->UserName.Length = cpu_to_le16(len);
2981 }
2982 /* BB fill in our workstation name if known BB */
2983
2984 strcpy(bcc_ptr, "Linux version ");
2985 bcc_ptr += strlen("Linux version ");
2986 strcpy(bcc_ptr, system_utsname.release);
2987 bcc_ptr += strlen(system_utsname.release) + 1;
2988 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2989 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2990 bcc_ptr++; /* null domain */
2991 *bcc_ptr = 0;
2992 }
2993 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2994 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2995 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2996 smb_buffer->smb_buf_length += count;
2997 pSMB->req.ByteCount = cpu_to_le16(count);
2998
2999 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3000 &bytes_returned, 1);
3001 if (rc) {
3002/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3003 } else if ((smb_buffer_response->WordCount == 3)
3004 || (smb_buffer_response->WordCount == 4)) {
3005 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3006 __u16 blob_len =
3007 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3008 if (action & GUEST_LOGIN)
3009 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
3010/* if(SecurityBlob2->MessageType != NtLm??){
3011 cFYI("Unexpected message type on auth response is %d "));
3012 } */
3013 if (ses) {
3014 cFYI(1,
3015 ("Does UID on challenge %d match auth response UID %d ",
3016 ses->Suid, smb_buffer_response->Uid));
3017 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
3018 bcc_ptr = pByteArea(smb_buffer_response);
3019 /* response can have either 3 or 4 word count - Samba sends 3 */
3020 if ((pSMBr->resp.hdr.WordCount == 3)
3021 || ((pSMBr->resp.hdr.WordCount == 4)
3022 && (blob_len <
3023 pSMBr->resp.ByteCount))) {
3024 if (pSMBr->resp.hdr.WordCount == 4) {
3025 bcc_ptr +=
3026 blob_len;
3027 cFYI(1,
3028 ("Security Blob Length %d ",
3029 blob_len));
3030 }
3031
3032 cFYI(1,
3033 ("NTLMSSP response to Authenticate "));
3034
3035 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3036 if ((long) (bcc_ptr) % 2) {
3037 remaining_words =
3038 (BCC(smb_buffer_response)
3039 - 1) / 2;
3040 bcc_ptr++; /* Unicode strings must be word aligned */
3041 } else {
3042 remaining_words = BCC(smb_buffer_response) / 2;
3043 }
3044 len =
3045 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3046/* We look for obvious messed up bcc or strings in response so we do not go off
3047 the end since (at least) WIN2K and Windows XP have a major bug in not null
3048 terminating last Unicode string in response */
3049 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07003050 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 cifs_strfromUCS_le(ses->serverOS,
3052 (wchar_t *)
3053 bcc_ptr, len,
3054 nls_codepage);
3055 bcc_ptr += 2 * (len + 1);
3056 remaining_words -= len + 1;
3057 ses->serverOS[2 * len] = 0;
3058 ses->serverOS[1 + (2 * len)] = 0;
3059 if (remaining_words > 0) {
3060 len = UniStrnlen((wchar_t *)
3061 bcc_ptr,
3062 remaining_words
3063 - 1);
3064 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07003065 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 GFP_KERNEL);
3067 cifs_strfromUCS_le(ses->
3068 serverNOS,
3069 (wchar_t *)
3070 bcc_ptr,
3071 len,
3072 nls_codepage);
3073 bcc_ptr += 2 * (len + 1);
3074 ses->serverNOS[2 * len] = 0;
3075 ses->serverNOS[1+(2*len)] = 0;
3076 remaining_words -= len + 1;
3077 if (remaining_words > 0) {
3078 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3079 /* last string not always null terminated (e.g. for Windows XP & 2000) */
3080 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07003081 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 (len +
3083 1),
3084 GFP_KERNEL);
3085 cifs_strfromUCS_le
3086 (ses->
3087 serverDomain,
3088 (wchar_t *)
3089 bcc_ptr, len,
3090 nls_codepage);
3091 bcc_ptr +=
3092 2 * (len + 1);
3093 ses->
3094 serverDomain[2
3095 * len]
3096 = 0;
3097 ses->
3098 serverDomain[1
3099 +
3100 (2
3101 *
3102 len)]
3103 = 0;
3104 } /* else no more room so create dummy domain string */
3105 else
Steve French433dc242005-04-28 22:41:08 -07003106 ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07003108 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
3109 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 }
3111 } else { /* ASCII */
3112 len = strnlen(bcc_ptr, 1024);
3113 if (((long) bcc_ptr + len) -
3114 (long) pByteArea(smb_buffer_response)
3115 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07003116 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 strncpy(ses->serverOS,bcc_ptr, len);
3118
3119 bcc_ptr += len;
3120 bcc_ptr[0] = 0; /* null terminate the string */
3121 bcc_ptr++;
3122
3123 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003124 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 strncpy(ses->serverNOS, bcc_ptr, len);
3126 bcc_ptr += len;
3127 bcc_ptr[0] = 0;
3128 bcc_ptr++;
3129
3130 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003131 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 strncpy(ses->serverDomain, bcc_ptr, len);
3133 bcc_ptr += len;
3134 bcc_ptr[0] = 0;
3135 bcc_ptr++;
3136 } else
3137 cFYI(1,
3138 ("Variable field of length %d extends beyond end of smb ",
3139 len));
3140 }
3141 } else {
3142 cERROR(1,
3143 (" Security Blob Length extends beyond end of SMB"));
3144 }
3145 } else {
3146 cERROR(1, ("No session structure passed in."));
3147 }
3148 } else {
3149 cERROR(1,
3150 (" Invalid Word count %d: ",
3151 smb_buffer_response->WordCount));
3152 rc = -EIO;
3153 }
3154
3155 if (smb_buffer)
3156 cifs_buf_release(smb_buffer);
3157
3158 return rc;
3159}
3160
3161int
3162CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3163 const char *tree, struct cifsTconInfo *tcon,
3164 const struct nls_table *nls_codepage)
3165{
3166 struct smb_hdr *smb_buffer;
3167 struct smb_hdr *smb_buffer_response;
3168 TCONX_REQ *pSMB;
3169 TCONX_RSP *pSMBr;
3170 unsigned char *bcc_ptr;
3171 int rc = 0;
3172 int length;
3173 __u16 count;
3174
3175 if (ses == NULL)
3176 return -EIO;
3177
3178 smb_buffer = cifs_buf_get();
3179 if (smb_buffer == NULL) {
3180 return -ENOMEM;
3181 }
3182 smb_buffer_response = smb_buffer;
3183
3184 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3185 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003186
3187 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 smb_buffer->Uid = ses->Suid;
3189 pSMB = (TCONX_REQ *) smb_buffer;
3190 pSMBr = (TCONX_RSP *) smb_buffer_response;
3191
3192 pSMB->AndXCommand = 0xFF;
3193 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3194 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3195 bcc_ptr = &pSMB->Password[0];
3196 bcc_ptr++; /* skip password */
3197
3198 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3199 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3200
3201 if (ses->capabilities & CAP_STATUS32) {
3202 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3203 }
3204 if (ses->capabilities & CAP_DFS) {
3205 smb_buffer->Flags2 |= SMBFLG2_DFS;
3206 }
3207 if (ses->capabilities & CAP_UNICODE) {
3208 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3209 length =
3210 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3211 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3212 bcc_ptr += 2; /* skip trailing null */
3213 } else { /* ASCII */
3214
3215 strcpy(bcc_ptr, tree);
3216 bcc_ptr += strlen(tree) + 1;
3217 }
3218 strcpy(bcc_ptr, "?????");
3219 bcc_ptr += strlen("?????");
3220 bcc_ptr += 1;
3221 count = bcc_ptr - &pSMB->Password[0];
3222 pSMB->hdr.smb_buf_length += count;
3223 pSMB->ByteCount = cpu_to_le16(count);
3224
3225 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3226
3227 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3228 /* above now done in SendReceive */
3229 if ((rc == 0) && (tcon != NULL)) {
3230 tcon->tidStatus = CifsGood;
3231 tcon->tid = smb_buffer_response->Tid;
3232 bcc_ptr = pByteArea(smb_buffer_response);
3233 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3234 /* skip service field (NB: this field is always ASCII) */
3235 bcc_ptr += length + 1;
3236 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3237 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3238 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3239 if ((bcc_ptr + (2 * length)) -
3240 pByteArea(smb_buffer_response) <=
3241 BCC(smb_buffer_response)) {
3242 if(tcon->nativeFileSystem)
3243 kfree(tcon->nativeFileSystem);
3244 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003245 kcalloc(1, length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 cifs_strfromUCS_le(tcon->nativeFileSystem,
3247 (wchar_t *) bcc_ptr,
3248 length, nls_codepage);
3249 bcc_ptr += 2 * length;
3250 bcc_ptr[0] = 0; /* null terminate the string */
3251 bcc_ptr[1] = 0;
3252 bcc_ptr += 2;
3253 }
3254 /* else do not bother copying these informational fields */
3255 } else {
3256 length = strnlen(bcc_ptr, 1024);
3257 if ((bcc_ptr + length) -
3258 pByteArea(smb_buffer_response) <=
3259 BCC(smb_buffer_response)) {
3260 if(tcon->nativeFileSystem)
3261 kfree(tcon->nativeFileSystem);
3262 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003263 kcalloc(1, length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 strncpy(tcon->nativeFileSystem, bcc_ptr,
3265 length);
3266 }
3267 /* else do not bother copying these informational fields */
3268 }
3269 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3270 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3271 } else if ((rc == 0) && tcon == NULL) {
3272 /* all we need to save for IPC$ connection */
3273 ses->ipc_tid = smb_buffer_response->Tid;
3274 }
3275
3276 if (smb_buffer)
3277 cifs_buf_release(smb_buffer);
3278 return rc;
3279}
3280
3281int
3282cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3283{
3284 int rc = 0;
3285 int xid;
3286 struct cifsSesInfo *ses = NULL;
3287 struct task_struct *cifsd_task;
3288
3289 xid = GetXid();
3290
3291 if (cifs_sb->tcon) {
3292 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3293 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3294 if (rc == -EBUSY) {
3295 FreeXid(xid);
3296 return 0;
3297 }
3298 tconInfoFree(cifs_sb->tcon);
3299 if ((ses) && (ses->server)) {
3300 /* save off task so we do not refer to ses later */
3301 cifsd_task = ses->server->tsk;
3302 cFYI(1, ("About to do SMBLogoff "));
3303 rc = CIFSSMBLogoff(xid, ses);
3304 if (rc == -EBUSY) {
3305 FreeXid(xid);
3306 return 0;
3307 } else if (rc == -ESHUTDOWN) {
3308 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf1914012005-08-18 09:37:34 -07003309 if(cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 send_sig(SIGKILL,cifsd_task,1);
Steve Frenchf1914012005-08-18 09:37:34 -07003311 wait_for_completion(&cifsd_complete);
3312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 rc = 0;
3314 } /* else - we have an smb session
3315 left on this socket do not kill cifsd */
3316 } else
3317 cFYI(1, ("No session or bad tcon"));
3318 }
3319
3320 cifs_sb->tcon = NULL;
3321 if (ses) {
3322 set_current_state(TASK_INTERRUPTIBLE);
3323 schedule_timeout(HZ / 2);
3324 }
3325 if (ses)
3326 sesInfoFree(ses);
3327
3328 FreeXid(xid);
3329 return rc; /* BB check if we should always return zero here */
3330}
3331
3332int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3333 struct nls_table * nls_info)
3334{
3335 int rc = 0;
3336 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3337 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003338 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
3340 /* what if server changes its buffer size after dropping the session? */
3341 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3342 rc = CIFSSMBNegotiate(xid, pSesInfo);
3343 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3344 rc = CIFSSMBNegotiate(xid, pSesInfo);
3345 if(rc == -EAGAIN)
3346 rc = -EHOSTDOWN;
3347 }
3348 if(rc == 0) {
3349 spin_lock(&GlobalMid_Lock);
3350 if(pSesInfo->server->tcpStatus != CifsExiting)
3351 pSesInfo->server->tcpStatus = CifsGood;
3352 else
3353 rc = -EHOSTDOWN;
3354 spin_unlock(&GlobalMid_Lock);
3355
3356 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003357 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 }
3359 if (!rc) {
3360 pSesInfo->capabilities = pSesInfo->server->capabilities;
3361 if(linuxExtEnabled == 0)
3362 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003363 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3365 pSesInfo->server->secMode,
3366 pSesInfo->server->capabilities,
3367 pSesInfo->server->timeZone));
3368 if (extended_security
3369 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3370 && (pSesInfo->server->secType == NTLMSSP)) {
3371 cFYI(1, ("New style sesssetup "));
3372 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3373 NULL /* security blob */,
3374 0 /* blob length */,
3375 nls_info);
3376 } else if (extended_security
3377 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3378 && (pSesInfo->server->secType == RawNTLMSSP)) {
3379 cFYI(1, ("NTLMSSP sesssetup "));
3380 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3381 pSesInfo,
3382 &ntlmv2_flag,
3383 nls_info);
3384 if (!rc) {
3385 if(ntlmv2_flag) {
3386 char * v2_response;
3387 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3388 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3389 nls_info)) {
3390 rc = -ENOMEM;
3391 goto ss_err_exit;
3392 } else
3393 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3394 if(v2_response) {
3395 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003396 /* if(first_time)
3397 cifs_calculate_ntlmv2_mac_key(
3398 pSesInfo->server->mac_signing_key,
3399 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 kfree(v2_response);
3401 /* BB Put dummy sig in SessSetup PDU? */
3402 } else {
3403 rc = -ENOMEM;
3404 goto ss_err_exit;
3405 }
3406
3407 } else {
3408 SMBNTencrypt(pSesInfo->password,
3409 pSesInfo->server->cryptKey,
3410 ntlm_session_key);
3411
Steve Frenchad009ac2005-04-28 22:41:05 -07003412 if(first_time)
3413 cifs_calculate_mac_key(
3414 pSesInfo->server->mac_signing_key,
3415 ntlm_session_key,
3416 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 }
3418 /* for better security the weaker lanman hash not sent
3419 in AuthSessSetup so we no longer calculate it */
3420
3421 rc = CIFSNTLMSSPAuthSessSetup(xid,
3422 pSesInfo,
3423 ntlm_session_key,
3424 ntlmv2_flag,
3425 nls_info);
3426 }
3427 } else { /* old style NTLM 0.12 session setup */
3428 SMBNTencrypt(pSesInfo->password,
3429 pSesInfo->server->cryptKey,
3430 ntlm_session_key);
3431
Steve Frenchad009ac2005-04-28 22:41:05 -07003432 if(first_time)
3433 cifs_calculate_mac_key(
3434 pSesInfo->server->mac_signing_key,
3435 ntlm_session_key, pSesInfo->password);
3436
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 rc = CIFSSessSetup(xid, pSesInfo,
3438 ntlm_session_key, nls_info);
3439 }
3440 if (rc) {
3441 cERROR(1,("Send error in SessSetup = %d",rc));
3442 } else {
3443 cFYI(1,("CIFS Session Established successfully"));
3444 pSesInfo->status = CifsGood;
3445 }
3446 }
3447ss_err_exit:
3448 return rc;
3449}
3450