blob: c75bae1242dcceaeb2873db3fc075ced44cf0c89 [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) {
Steve French6b8edfe2005-08-23 20:26:03 -07001733 cifs_sb->rsize = PAGE_CACHE_SIZE;
1734 /* Windows ME does this */
1735 cFYI(1,("Attempt to set readsize for mount to less than one page (4096)"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 }
1737 cifs_sb->mnt_uid = volume_info.linux_uid;
1738 cifs_sb->mnt_gid = volume_info.linux_gid;
1739 cifs_sb->mnt_file_mode = volume_info.file_mode;
1740 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
1741 cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
1742
1743 if(volume_info.noperm)
1744 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1745 if(volume_info.setuids)
1746 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1747 if(volume_info.server_ino)
1748 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001749 if(volume_info.remap)
1750 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 if(volume_info.no_xattr)
1752 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve Frenchd7245c22005-07-14 18:25:12 -05001753 if(volume_info.sfu_emul)
1754 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001755 if(volume_info.nobrl)
1756 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Jeremy Allisonac670552005-06-22 17:26:35 -07001757
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if(volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001759 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1761 }
1762
1763 tcon =
1764 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1765 volume_info.username);
1766 if (tcon) {
1767 cFYI(1, ("Found match on UNC path "));
1768 /* we can have only one retry value for a connection
1769 to a share so for resources mounted more than once
1770 to the same server share the last value passed in
1771 for the retry flag is used */
1772 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001773 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 } else {
1775 tcon = tconInfoAlloc();
1776 if (tcon == NULL)
1777 rc = -ENOMEM;
1778 else {
1779 /* check for null share name ie connect to dfs root */
1780
1781 /* BB check if this works for exactly length three strings */
1782 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1783 && (strchr(volume_info.UNC + 3, '/') ==
1784 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001785 rc = connect_to_dfs_path(xid, pSesInfo,
1786 "", cifs_sb->local_nls,
1787 cifs_sb->mnt_cifs_flags &
1788 CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 if(volume_info.UNC)
1790 kfree(volume_info.UNC);
1791 FreeXid(xid);
1792 return -ENODEV;
1793 } else {
1794 rc = CIFSTCon(xid, pSesInfo,
1795 volume_info.UNC,
1796 tcon, cifs_sb->local_nls);
1797 cFYI(1, ("CIFS Tcon rc = %d", rc));
1798 }
1799 if (!rc) {
1800 atomic_inc(&pSesInfo->inUse);
1801 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001802 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 }
1804 }
1805 }
1806 }
1807 if(pSesInfo) {
1808 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1809 sb->s_maxbytes = (u64) 1 << 63;
1810 } else
1811 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1812 }
1813
1814 sb->s_time_gran = 100;
1815
1816/* on error free sesinfo and tcon struct if needed */
1817 if (rc) {
1818 /* if session setup failed, use count is zero but
1819 we still need to free cifsd thread */
1820 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1821 spin_lock(&GlobalMid_Lock);
1822 srvTcp->tcpStatus = CifsExiting;
1823 spin_unlock(&GlobalMid_Lock);
Steve Frenchf1914012005-08-18 09:37:34 -07001824 if(srvTcp->tsk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 send_sig(SIGKILL,srvTcp->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001826 wait_for_completion(&cifsd_complete);
1827 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 }
1829 /* If find_unc succeeded then rc == 0 so we can not end */
1830 if (tcon) /* up accidently freeing someone elses tcon struct */
1831 tconInfoFree(tcon);
1832 if (existingCifsSes == NULL) {
1833 if (pSesInfo) {
1834 if ((pSesInfo->server) &&
1835 (pSesInfo->status == CifsGood)) {
1836 int temp_rc;
1837 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1838 /* if the socketUseCount is now zero */
1839 if((temp_rc == -ESHUTDOWN) &&
Steve Frenchf1914012005-08-18 09:37:34 -07001840 (pSesInfo->server->tsk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 send_sig(SIGKILL,pSesInfo->server->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001842 wait_for_completion(&cifsd_complete);
1843 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 } else
1845 cFYI(1, ("No session or bad tcon"));
1846 sesInfoFree(pSesInfo);
1847 /* pSesInfo = NULL; */
1848 }
1849 }
1850 } else {
1851 atomic_inc(&tcon->useCount);
1852 cifs_sb->tcon = tcon;
1853 tcon->ses = pSesInfo;
1854
1855 /* do not care if following two calls succeed - informational only */
Steve French737b7582005-04-28 22:41:06 -07001856 CIFSSMBQFSDeviceInfo(xid, tcon);
1857 CIFSSMBQFSAttributeInfo(xid, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001859 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 if(!volume_info.no_psx_acl) {
1861 if(CIFS_UNIX_POSIX_ACL_CAP &
1862 le64_to_cpu(tcon->fsUnixInfo.Capability))
1863 cFYI(1,("server negotiated posix acl support"));
1864 sb->s_flags |= MS_POSIXACL;
1865 }
Jeremy Allisonac670552005-06-22 17:26:35 -07001866
1867 /* Try and negotiate POSIX pathnames if we can. */
1868 if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
1869 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French45abc6e2005-06-23 13:42:03 -05001870 if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
Jeremy Allisonac670552005-06-22 17:26:35 -07001871 cFYI(1,("negotiated posix pathnames support"));
1872 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
1873 } else {
1874 cFYI(1,("posix pathnames support requested but not supported"));
1875 }
1876 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 }
1878 }
1879 }
1880
1881 /* volume_info.password is freed above when existing session found
1882 (in which case it is not needed anymore) but when new sesion is created
1883 the password ptr is put in the new session structure (in which case the
1884 password will be freed at unmount time) */
1885 if(volume_info.UNC)
1886 kfree(volume_info.UNC);
1887 FreeXid(xid);
1888 return rc;
1889}
1890
1891static int
1892CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
1893 char session_key[CIFS_SESSION_KEY_SIZE],
1894 const struct nls_table *nls_codepage)
1895{
1896 struct smb_hdr *smb_buffer;
1897 struct smb_hdr *smb_buffer_response;
1898 SESSION_SETUP_ANDX *pSMB;
1899 SESSION_SETUP_ANDX *pSMBr;
1900 char *bcc_ptr;
1901 char *user;
1902 char *domain;
1903 int rc = 0;
1904 int remaining_words = 0;
1905 int bytes_returned = 0;
1906 int len;
1907 __u32 capabilities;
1908 __u16 count;
1909
1910 cFYI(1, ("In sesssetup "));
1911 if(ses == NULL)
1912 return -EINVAL;
1913 user = ses->userName;
1914 domain = ses->domainName;
1915 smb_buffer = cifs_buf_get();
1916 if (smb_buffer == NULL) {
1917 return -ENOMEM;
1918 }
1919 smb_buffer_response = smb_buffer;
1920 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
1921
1922 /* send SMBsessionSetup here */
1923 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
1924 NULL /* no tCon exists yet */ , 13 /* wct */ );
1925
Steve French1982c342005-08-17 12:38:22 -07001926 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 pSMB->req_no_secext.AndXCommand = 0xFF;
1928 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
1929 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
1930
1931 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
1932 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1933
1934 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
1935 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
1936 if (ses->capabilities & CAP_UNICODE) {
1937 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
1938 capabilities |= CAP_UNICODE;
1939 }
1940 if (ses->capabilities & CAP_STATUS32) {
1941 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
1942 capabilities |= CAP_STATUS32;
1943 }
1944 if (ses->capabilities & CAP_DFS) {
1945 smb_buffer->Flags2 |= SMBFLG2_DFS;
1946 capabilities |= CAP_DFS;
1947 }
1948 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
1949
1950 pSMB->req_no_secext.CaseInsensitivePasswordLength =
1951 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1952
1953 pSMB->req_no_secext.CaseSensitivePasswordLength =
1954 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
1955 bcc_ptr = pByteArea(smb_buffer);
1956 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1957 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1958 memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
1959 bcc_ptr += CIFS_SESSION_KEY_SIZE;
1960
1961 if (ses->capabilities & CAP_UNICODE) {
1962 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
1963 *bcc_ptr = 0;
1964 bcc_ptr++;
1965 }
1966 if(user == NULL)
1967 bytes_returned = 0; /* skill null user */
1968 else
1969 bytes_returned =
1970 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
1971 nls_codepage);
1972 /* convert number of 16 bit words to bytes */
1973 bcc_ptr += 2 * bytes_returned;
1974 bcc_ptr += 2; /* trailing null */
1975 if (domain == NULL)
1976 bytes_returned =
1977 cifs_strtoUCS((wchar_t *) bcc_ptr,
1978 "CIFS_LINUX_DOM", 32, nls_codepage);
1979 else
1980 bytes_returned =
1981 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
1982 nls_codepage);
1983 bcc_ptr += 2 * bytes_returned;
1984 bcc_ptr += 2;
1985 bytes_returned =
1986 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
1987 32, nls_codepage);
1988 bcc_ptr += 2 * bytes_returned;
1989 bytes_returned =
1990 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release,
1991 32, nls_codepage);
1992 bcc_ptr += 2 * bytes_returned;
1993 bcc_ptr += 2;
1994 bytes_returned =
1995 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
1996 64, nls_codepage);
1997 bcc_ptr += 2 * bytes_returned;
1998 bcc_ptr += 2;
1999 } else {
2000 if(user != NULL) {
2001 strncpy(bcc_ptr, user, 200);
2002 bcc_ptr += strnlen(user, 200);
2003 }
2004 *bcc_ptr = 0;
2005 bcc_ptr++;
2006 if (domain == NULL) {
2007 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2008 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2009 } else {
2010 strncpy(bcc_ptr, domain, 64);
2011 bcc_ptr += strnlen(domain, 64);
2012 *bcc_ptr = 0;
2013 bcc_ptr++;
2014 }
2015 strcpy(bcc_ptr, "Linux version ");
2016 bcc_ptr += strlen("Linux version ");
2017 strcpy(bcc_ptr, system_utsname.release);
2018 bcc_ptr += strlen(system_utsname.release) + 1;
2019 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2020 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2021 }
2022 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2023 smb_buffer->smb_buf_length += count;
2024 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2025
2026 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2027 &bytes_returned, 1);
2028 if (rc) {
2029/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2030 } else if ((smb_buffer_response->WordCount == 3)
2031 || (smb_buffer_response->WordCount == 4)) {
2032 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2033 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2034 if (action & GUEST_LOGIN)
2035 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2036 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2037 cFYI(1, ("UID = %d ", ses->Suid));
2038 /* response can have either 3 or 4 word count - Samba sends 3 */
2039 bcc_ptr = pByteArea(smb_buffer_response);
2040 if ((pSMBr->resp.hdr.WordCount == 3)
2041 || ((pSMBr->resp.hdr.WordCount == 4)
2042 && (blob_len < pSMBr->resp.ByteCount))) {
2043 if (pSMBr->resp.hdr.WordCount == 4)
2044 bcc_ptr += blob_len;
2045
2046 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2047 if ((long) (bcc_ptr) % 2) {
2048 remaining_words =
2049 (BCC(smb_buffer_response) - 1) /2;
2050 bcc_ptr++; /* Unicode strings must be word aligned */
2051 } else {
2052 remaining_words =
2053 BCC(smb_buffer_response) / 2;
2054 }
2055 len =
2056 UniStrnlen((wchar_t *) bcc_ptr,
2057 remaining_words - 1);
2058/* We look for obvious messed up bcc or strings in response so we do not go off
2059 the end since (at least) WIN2K and Windows XP have a major bug in not null
2060 terminating last Unicode string in response */
Steve French433dc242005-04-28 22:41:08 -07002061 ses->serverOS = kcalloc(1, 2 * (len + 1), GFP_KERNEL);
2062 if(ses->serverOS == NULL)
2063 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 cifs_strfromUCS_le(ses->serverOS,
2065 (wchar_t *)bcc_ptr, len,nls_codepage);
2066 bcc_ptr += 2 * (len + 1);
2067 remaining_words -= len + 1;
2068 ses->serverOS[2 * len] = 0;
2069 ses->serverOS[1 + (2 * len)] = 0;
2070 if (remaining_words > 0) {
2071 len = UniStrnlen((wchar_t *)bcc_ptr,
2072 remaining_words-1);
Steve French433dc242005-04-28 22:41:08 -07002073 ses->serverNOS = kcalloc(1, 2 * (len + 1),GFP_KERNEL);
2074 if(ses->serverNOS == NULL)
2075 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 cifs_strfromUCS_le(ses->serverNOS,
2077 (wchar_t *)bcc_ptr,len,nls_codepage);
2078 bcc_ptr += 2 * (len + 1);
2079 ses->serverNOS[2 * len] = 0;
2080 ses->serverNOS[1 + (2 * len)] = 0;
2081 if(strncmp(ses->serverNOS,
2082 "NT LAN Manager 4",16) == 0) {
2083 cFYI(1,("NT4 server"));
2084 ses->flags |= CIFS_SES_NT4;
2085 }
2086 remaining_words -= len + 1;
2087 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002088 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2090 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002091 kcalloc(1, 2*(len+1),GFP_KERNEL);
2092 if(ses->serverDomain == NULL)
2093 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 cifs_strfromUCS_le(ses->serverDomain,
2095 (wchar_t *)bcc_ptr,len,nls_codepage);
2096 bcc_ptr += 2 * (len + 1);
2097 ses->serverDomain[2*len] = 0;
2098 ses->serverDomain[1+(2*len)] = 0;
2099 } /* else no more room so create dummy domain string */
2100 else
Steve French433dc242005-04-28 22:41:08 -07002101 ses->serverDomain =
2102 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002104 /* if these kcallocs fail not much we
2105 can do, but better to not fail the
2106 sesssetup itself */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002108 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002110 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 }
2112 } else { /* ASCII */
2113 len = strnlen(bcc_ptr, 1024);
2114 if (((long) bcc_ptr + len) - (long)
2115 pByteArea(smb_buffer_response)
2116 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002117 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
2118 if(ses->serverOS == NULL)
2119 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 strncpy(ses->serverOS,bcc_ptr, len);
2121
2122 bcc_ptr += len;
2123 bcc_ptr[0] = 0; /* null terminate the string */
2124 bcc_ptr++;
2125
2126 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002127 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
2128 if(ses->serverNOS == NULL)
2129 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 strncpy(ses->serverNOS, bcc_ptr, len);
2131 bcc_ptr += len;
2132 bcc_ptr[0] = 0;
2133 bcc_ptr++;
2134
2135 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002136 ses->serverDomain = kcalloc(1, len + 1,GFP_KERNEL);
2137 if(ses->serverDomain == NULL)
2138 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 strncpy(ses->serverDomain, bcc_ptr, len);
2140 bcc_ptr += len;
2141 bcc_ptr[0] = 0;
2142 bcc_ptr++;
2143 } else
2144 cFYI(1,
2145 ("Variable field of length %d extends beyond end of smb ",
2146 len));
2147 }
2148 } else {
2149 cERROR(1,
2150 (" Security Blob Length extends beyond end of SMB"));
2151 }
2152 } else {
2153 cERROR(1,
2154 (" Invalid Word count %d: ",
2155 smb_buffer_response->WordCount));
2156 rc = -EIO;
2157 }
Steve French433dc242005-04-28 22:41:08 -07002158sesssetup_nomem: /* do not return an error on nomem for the info strings,
2159 since that could make reconnection harder, and
2160 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 if (smb_buffer)
2162 cifs_buf_release(smb_buffer);
2163
2164 return rc;
2165}
2166
2167static int
2168CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2169 char *SecurityBlob,int SecurityBlobLength,
2170 const struct nls_table *nls_codepage)
2171{
2172 struct smb_hdr *smb_buffer;
2173 struct smb_hdr *smb_buffer_response;
2174 SESSION_SETUP_ANDX *pSMB;
2175 SESSION_SETUP_ANDX *pSMBr;
2176 char *bcc_ptr;
2177 char *user;
2178 char *domain;
2179 int rc = 0;
2180 int remaining_words = 0;
2181 int bytes_returned = 0;
2182 int len;
2183 __u32 capabilities;
2184 __u16 count;
2185
2186 cFYI(1, ("In spnego sesssetup "));
2187 if(ses == NULL)
2188 return -EINVAL;
2189 user = ses->userName;
2190 domain = ses->domainName;
2191
2192 smb_buffer = cifs_buf_get();
2193 if (smb_buffer == NULL) {
2194 return -ENOMEM;
2195 }
2196 smb_buffer_response = smb_buffer;
2197 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2198
2199 /* send SMBsessionSetup here */
2200 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2201 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002202
2203 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2205 pSMB->req.AndXCommand = 0xFF;
2206 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2207 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2208
2209 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2210 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2211
2212 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2213 CAP_EXTENDED_SECURITY;
2214 if (ses->capabilities & CAP_UNICODE) {
2215 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2216 capabilities |= CAP_UNICODE;
2217 }
2218 if (ses->capabilities & CAP_STATUS32) {
2219 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2220 capabilities |= CAP_STATUS32;
2221 }
2222 if (ses->capabilities & CAP_DFS) {
2223 smb_buffer->Flags2 |= SMBFLG2_DFS;
2224 capabilities |= CAP_DFS;
2225 }
2226 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2227
2228 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2229 bcc_ptr = pByteArea(smb_buffer);
2230 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2231 bcc_ptr += SecurityBlobLength;
2232
2233 if (ses->capabilities & CAP_UNICODE) {
2234 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2235 *bcc_ptr = 0;
2236 bcc_ptr++;
2237 }
2238 bytes_returned =
2239 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
2240 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2241 bcc_ptr += 2; /* trailing null */
2242 if (domain == NULL)
2243 bytes_returned =
2244 cifs_strtoUCS((wchar_t *) bcc_ptr,
2245 "CIFS_LINUX_DOM", 32, nls_codepage);
2246 else
2247 bytes_returned =
2248 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2249 nls_codepage);
2250 bcc_ptr += 2 * bytes_returned;
2251 bcc_ptr += 2;
2252 bytes_returned =
2253 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2254 32, nls_codepage);
2255 bcc_ptr += 2 * bytes_returned;
2256 bytes_returned =
2257 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2258 nls_codepage);
2259 bcc_ptr += 2 * bytes_returned;
2260 bcc_ptr += 2;
2261 bytes_returned =
2262 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2263 64, nls_codepage);
2264 bcc_ptr += 2 * bytes_returned;
2265 bcc_ptr += 2;
2266 } else {
2267 strncpy(bcc_ptr, user, 200);
2268 bcc_ptr += strnlen(user, 200);
2269 *bcc_ptr = 0;
2270 bcc_ptr++;
2271 if (domain == NULL) {
2272 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2273 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2274 } else {
2275 strncpy(bcc_ptr, domain, 64);
2276 bcc_ptr += strnlen(domain, 64);
2277 *bcc_ptr = 0;
2278 bcc_ptr++;
2279 }
2280 strcpy(bcc_ptr, "Linux version ");
2281 bcc_ptr += strlen("Linux version ");
2282 strcpy(bcc_ptr, system_utsname.release);
2283 bcc_ptr += strlen(system_utsname.release) + 1;
2284 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2285 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2286 }
2287 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2288 smb_buffer->smb_buf_length += count;
2289 pSMB->req.ByteCount = cpu_to_le16(count);
2290
2291 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2292 &bytes_returned, 1);
2293 if (rc) {
2294/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2295 } else if ((smb_buffer_response->WordCount == 3)
2296 || (smb_buffer_response->WordCount == 4)) {
2297 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2298 __u16 blob_len =
2299 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2300 if (action & GUEST_LOGIN)
2301 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2302 if (ses) {
2303 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2304 cFYI(1, ("UID = %d ", ses->Suid));
2305 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2306
2307 /* BB Fix below to make endian neutral !! */
2308
2309 if ((pSMBr->resp.hdr.WordCount == 3)
2310 || ((pSMBr->resp.hdr.WordCount == 4)
2311 && (blob_len <
2312 pSMBr->resp.ByteCount))) {
2313 if (pSMBr->resp.hdr.WordCount == 4) {
2314 bcc_ptr +=
2315 blob_len;
2316 cFYI(1,
2317 ("Security Blob Length %d ",
2318 blob_len));
2319 }
2320
2321 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2322 if ((long) (bcc_ptr) % 2) {
2323 remaining_words =
2324 (BCC(smb_buffer_response)
2325 - 1) / 2;
2326 bcc_ptr++; /* Unicode strings must be word aligned */
2327 } else {
2328 remaining_words =
2329 BCC
2330 (smb_buffer_response) / 2;
2331 }
2332 len =
2333 UniStrnlen((wchar_t *) bcc_ptr,
2334 remaining_words - 1);
2335/* We look for obvious messed up bcc or strings in response so we do not go off
2336 the end since (at least) WIN2K and Windows XP have a major bug in not null
2337 terminating last Unicode string in response */
2338 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002339 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 cifs_strfromUCS_le(ses->serverOS,
2341 (wchar_t *)
2342 bcc_ptr, len,
2343 nls_codepage);
2344 bcc_ptr += 2 * (len + 1);
2345 remaining_words -= len + 1;
2346 ses->serverOS[2 * len] = 0;
2347 ses->serverOS[1 + (2 * len)] = 0;
2348 if (remaining_words > 0) {
2349 len = UniStrnlen((wchar_t *)bcc_ptr,
2350 remaining_words
2351 - 1);
2352 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002353 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 GFP_KERNEL);
2355 cifs_strfromUCS_le(ses->serverNOS,
2356 (wchar_t *)bcc_ptr,
2357 len,
2358 nls_codepage);
2359 bcc_ptr += 2 * (len + 1);
2360 ses->serverNOS[2 * len] = 0;
2361 ses->serverNOS[1 + (2 * len)] = 0;
2362 remaining_words -= len + 1;
2363 if (remaining_words > 0) {
2364 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2365 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve French433dc242005-04-28 22:41:08 -07002366 ses->serverDomain = kcalloc(1, 2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 cifs_strfromUCS_le(ses->serverDomain,
2368 (wchar_t *)bcc_ptr,
2369 len,
2370 nls_codepage);
2371 bcc_ptr += 2*(len+1);
2372 ses->serverDomain[2*len] = 0;
2373 ses->serverDomain[1+(2*len)] = 0;
2374 } /* else no more room so create dummy domain string */
2375 else
2376 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002377 kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002379 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
2380 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 }
2382 } else { /* ASCII */
2383
2384 len = strnlen(bcc_ptr, 1024);
2385 if (((long) bcc_ptr + len) - (long)
2386 pByteArea(smb_buffer_response)
2387 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07002388 ses->serverOS = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 strncpy(ses->serverOS, bcc_ptr, len);
2390
2391 bcc_ptr += len;
2392 bcc_ptr[0] = 0; /* null terminate the string */
2393 bcc_ptr++;
2394
2395 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002396 ses->serverNOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 strncpy(ses->serverNOS, bcc_ptr, len);
2398 bcc_ptr += len;
2399 bcc_ptr[0] = 0;
2400 bcc_ptr++;
2401
2402 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07002403 ses->serverDomain = kcalloc(1, len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 strncpy(ses->serverDomain, bcc_ptr, len);
2405 bcc_ptr += len;
2406 bcc_ptr[0] = 0;
2407 bcc_ptr++;
2408 } else
2409 cFYI(1,
2410 ("Variable field of length %d extends beyond end of smb ",
2411 len));
2412 }
2413 } else {
2414 cERROR(1,
2415 (" Security Blob Length extends beyond end of SMB"));
2416 }
2417 } else {
2418 cERROR(1, ("No session structure passed in."));
2419 }
2420 } else {
2421 cERROR(1,
2422 (" Invalid Word count %d: ",
2423 smb_buffer_response->WordCount));
2424 rc = -EIO;
2425 }
2426
2427 if (smb_buffer)
2428 cifs_buf_release(smb_buffer);
2429
2430 return rc;
2431}
2432
2433static int
2434CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2435 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2436 const struct nls_table *nls_codepage)
2437{
2438 struct smb_hdr *smb_buffer;
2439 struct smb_hdr *smb_buffer_response;
2440 SESSION_SETUP_ANDX *pSMB;
2441 SESSION_SETUP_ANDX *pSMBr;
2442 char *bcc_ptr;
2443 char *domain;
2444 int rc = 0;
2445 int remaining_words = 0;
2446 int bytes_returned = 0;
2447 int len;
2448 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2449 PNEGOTIATE_MESSAGE SecurityBlob;
2450 PCHALLENGE_MESSAGE SecurityBlob2;
2451 __u32 negotiate_flags, capabilities;
2452 __u16 count;
2453
2454 cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
2455 if(ses == NULL)
2456 return -EINVAL;
2457 domain = ses->domainName;
2458 *pNTLMv2_flag = FALSE;
2459 smb_buffer = cifs_buf_get();
2460 if (smb_buffer == NULL) {
2461 return -ENOMEM;
2462 }
2463 smb_buffer_response = smb_buffer;
2464 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2465 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2466
2467 /* send SMBsessionSetup here */
2468 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2469 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002470
2471 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2473 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2474
2475 pSMB->req.AndXCommand = 0xFF;
2476 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2477 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2478
2479 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2480 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2481
2482 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2483 CAP_EXTENDED_SECURITY;
2484 if (ses->capabilities & CAP_UNICODE) {
2485 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2486 capabilities |= CAP_UNICODE;
2487 }
2488 if (ses->capabilities & CAP_STATUS32) {
2489 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2490 capabilities |= CAP_STATUS32;
2491 }
2492 if (ses->capabilities & CAP_DFS) {
2493 smb_buffer->Flags2 |= SMBFLG2_DFS;
2494 capabilities |= CAP_DFS;
2495 }
2496 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2497
2498 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2499 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2500 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2501 SecurityBlob->MessageType = NtLmNegotiate;
2502 negotiate_flags =
2503 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
2504 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
2505 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2506 if(sign_CIFS_PDUs)
2507 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
2508 if(ntlmv2_support)
2509 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2510 /* setup pointers to domain name and workstation name */
2511 bcc_ptr += SecurityBlobLength;
2512
2513 SecurityBlob->WorkstationName.Buffer = 0;
2514 SecurityBlob->WorkstationName.Length = 0;
2515 SecurityBlob->WorkstationName.MaximumLength = 0;
2516
2517 if (domain == NULL) {
2518 SecurityBlob->DomainName.Buffer = 0;
2519 SecurityBlob->DomainName.Length = 0;
2520 SecurityBlob->DomainName.MaximumLength = 0;
2521 } else {
2522 __u16 len;
2523 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2524 strncpy(bcc_ptr, domain, 63);
2525 len = strnlen(domain, 64);
2526 SecurityBlob->DomainName.MaximumLength =
2527 cpu_to_le16(len);
2528 SecurityBlob->DomainName.Buffer =
2529 cpu_to_le32((long) &SecurityBlob->
2530 DomainString -
2531 (long) &SecurityBlob->Signature);
2532 bcc_ptr += len;
2533 SecurityBlobLength += len;
2534 SecurityBlob->DomainName.Length =
2535 cpu_to_le16(len);
2536 }
2537 if (ses->capabilities & CAP_UNICODE) {
2538 if ((long) bcc_ptr % 2) {
2539 *bcc_ptr = 0;
2540 bcc_ptr++;
2541 }
2542
2543 bytes_returned =
2544 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2545 32, nls_codepage);
2546 bcc_ptr += 2 * bytes_returned;
2547 bytes_returned =
2548 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2549 nls_codepage);
2550 bcc_ptr += 2 * bytes_returned;
2551 bcc_ptr += 2; /* null terminate Linux version */
2552 bytes_returned =
2553 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2554 64, nls_codepage);
2555 bcc_ptr += 2 * bytes_returned;
2556 *(bcc_ptr + 1) = 0;
2557 *(bcc_ptr + 2) = 0;
2558 bcc_ptr += 2; /* null terminate network opsys string */
2559 *(bcc_ptr + 1) = 0;
2560 *(bcc_ptr + 2) = 0;
2561 bcc_ptr += 2; /* null domain */
2562 } else { /* ASCII */
2563 strcpy(bcc_ptr, "Linux version ");
2564 bcc_ptr += strlen("Linux version ");
2565 strcpy(bcc_ptr, system_utsname.release);
2566 bcc_ptr += strlen(system_utsname.release) + 1;
2567 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2568 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2569 bcc_ptr++; /* empty domain field */
2570 *bcc_ptr = 0;
2571 }
2572 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2573 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2574 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2575 smb_buffer->smb_buf_length += count;
2576 pSMB->req.ByteCount = cpu_to_le16(count);
2577
2578 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2579 &bytes_returned, 1);
2580
2581 if (smb_buffer_response->Status.CifsError ==
2582 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2583 rc = 0;
2584
2585 if (rc) {
2586/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2587 } else if ((smb_buffer_response->WordCount == 3)
2588 || (smb_buffer_response->WordCount == 4)) {
2589 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2590 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2591
2592 if (action & GUEST_LOGIN)
2593 cFYI(1, (" Guest login"));
2594 /* Do we want to set anything in SesInfo struct when guest login? */
2595
2596 bcc_ptr = pByteArea(smb_buffer_response);
2597 /* response can have either 3 or 4 word count - Samba sends 3 */
2598
2599 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2600 if (SecurityBlob2->MessageType != NtLmChallenge) {
2601 cFYI(1,
2602 ("Unexpected NTLMSSP message type received %d",
2603 SecurityBlob2->MessageType));
2604 } else if (ses) {
2605 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
2606 cFYI(1, ("UID = %d ", ses->Suid));
2607 if ((pSMBr->resp.hdr.WordCount == 3)
2608 || ((pSMBr->resp.hdr.WordCount == 4)
2609 && (blob_len <
2610 pSMBr->resp.ByteCount))) {
2611
2612 if (pSMBr->resp.hdr.WordCount == 4) {
2613 bcc_ptr += blob_len;
2614 cFYI(1,
2615 ("Security Blob Length %d ",
2616 blob_len));
2617 }
2618
2619 cFYI(1, ("NTLMSSP Challenge rcvd "));
2620
2621 memcpy(ses->server->cryptKey,
2622 SecurityBlob2->Challenge,
2623 CIFS_CRYPTO_KEY_SIZE);
2624 if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
2625 *pNTLMv2_flag = TRUE;
2626
2627 if((SecurityBlob2->NegotiateFlags &
2628 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2629 || (sign_CIFS_PDUs > 1))
2630 ses->server->secMode |=
2631 SECMODE_SIGN_REQUIRED;
2632 if ((SecurityBlob2->NegotiateFlags &
2633 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2634 ses->server->secMode |=
2635 SECMODE_SIGN_ENABLED;
2636
2637 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2638 if ((long) (bcc_ptr) % 2) {
2639 remaining_words =
2640 (BCC(smb_buffer_response)
2641 - 1) / 2;
2642 bcc_ptr++; /* Unicode strings must be word aligned */
2643 } else {
2644 remaining_words =
2645 BCC
2646 (smb_buffer_response) / 2;
2647 }
2648 len =
2649 UniStrnlen((wchar_t *) bcc_ptr,
2650 remaining_words - 1);
2651/* We look for obvious messed up bcc or strings in response so we do not go off
2652 the end since (at least) WIN2K and Windows XP have a major bug in not null
2653 terminating last Unicode string in response */
2654 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002655 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 cifs_strfromUCS_le(ses->serverOS,
2657 (wchar_t *)
2658 bcc_ptr, len,
2659 nls_codepage);
2660 bcc_ptr += 2 * (len + 1);
2661 remaining_words -= len + 1;
2662 ses->serverOS[2 * len] = 0;
2663 ses->serverOS[1 + (2 * len)] = 0;
2664 if (remaining_words > 0) {
2665 len = UniStrnlen((wchar_t *)
2666 bcc_ptr,
2667 remaining_words
2668 - 1);
2669 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002670 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 GFP_KERNEL);
2672 cifs_strfromUCS_le(ses->
2673 serverNOS,
2674 (wchar_t *)
2675 bcc_ptr,
2676 len,
2677 nls_codepage);
2678 bcc_ptr += 2 * (len + 1);
2679 ses->serverNOS[2 * len] = 0;
2680 ses->serverNOS[1 +
2681 (2 * len)] = 0;
2682 remaining_words -= len + 1;
2683 if (remaining_words > 0) {
2684 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2685 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
2686 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002687 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 (len +
2689 1),
2690 GFP_KERNEL);
2691 cifs_strfromUCS_le
2692 (ses->
2693 serverDomain,
2694 (wchar_t *)
2695 bcc_ptr, len,
2696 nls_codepage);
2697 bcc_ptr +=
2698 2 * (len + 1);
2699 ses->
2700 serverDomain[2
2701 * len]
2702 = 0;
2703 ses->
2704 serverDomain[1
2705 +
2706 (2
2707 *
2708 len)]
2709 = 0;
2710 } /* else no more room so create dummy domain string */
2711 else
2712 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002713 kcalloc(1, 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 GFP_KERNEL);
2715 } else { /* no room so create dummy domain and NOS string */
2716 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002717 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002719 kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 }
2721 } else { /* ASCII */
2722 len = strnlen(bcc_ptr, 1024);
2723 if (((long) bcc_ptr + len) - (long)
2724 pByteArea(smb_buffer_response)
2725 <= BCC(smb_buffer_response)) {
2726 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07002727 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 GFP_KERNEL);
2729 strncpy(ses->serverOS,
2730 bcc_ptr, len);
2731
2732 bcc_ptr += len;
2733 bcc_ptr[0] = 0; /* null terminate string */
2734 bcc_ptr++;
2735
2736 len = strnlen(bcc_ptr, 1024);
2737 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07002738 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 GFP_KERNEL);
2740 strncpy(ses->serverNOS, bcc_ptr, len);
2741 bcc_ptr += len;
2742 bcc_ptr[0] = 0;
2743 bcc_ptr++;
2744
2745 len = strnlen(bcc_ptr, 1024);
2746 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07002747 kcalloc(1, len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 GFP_KERNEL);
2749 strncpy(ses->serverDomain, bcc_ptr, len);
2750 bcc_ptr += len;
2751 bcc_ptr[0] = 0;
2752 bcc_ptr++;
2753 } else
2754 cFYI(1,
2755 ("Variable field of length %d extends beyond end of smb ",
2756 len));
2757 }
2758 } else {
2759 cERROR(1,
2760 (" Security Blob Length extends beyond end of SMB"));
2761 }
2762 } else {
2763 cERROR(1, ("No session structure passed in."));
2764 }
2765 } else {
2766 cERROR(1,
2767 (" Invalid Word count %d: ",
2768 smb_buffer_response->WordCount));
2769 rc = -EIO;
2770 }
2771
2772 if (smb_buffer)
2773 cifs_buf_release(smb_buffer);
2774
2775 return rc;
2776}
2777static int
2778CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2779 char *ntlm_session_key, int ntlmv2_flag,
2780 const struct nls_table *nls_codepage)
2781{
2782 struct smb_hdr *smb_buffer;
2783 struct smb_hdr *smb_buffer_response;
2784 SESSION_SETUP_ANDX *pSMB;
2785 SESSION_SETUP_ANDX *pSMBr;
2786 char *bcc_ptr;
2787 char *user;
2788 char *domain;
2789 int rc = 0;
2790 int remaining_words = 0;
2791 int bytes_returned = 0;
2792 int len;
2793 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2794 PAUTHENTICATE_MESSAGE SecurityBlob;
2795 __u32 negotiate_flags, capabilities;
2796 __u16 count;
2797
2798 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2799 if(ses == NULL)
2800 return -EINVAL;
2801 user = ses->userName;
2802 domain = ses->domainName;
2803 smb_buffer = cifs_buf_get();
2804 if (smb_buffer == NULL) {
2805 return -ENOMEM;
2806 }
2807 smb_buffer_response = smb_buffer;
2808 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2809 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2810
2811 /* send SMBsessionSetup here */
2812 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2813 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002814
2815 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2817 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2818 pSMB->req.AndXCommand = 0xFF;
2819 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2820 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2821
2822 pSMB->req.hdr.Uid = ses->Suid;
2823
2824 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2825 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2826
2827 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2828 CAP_EXTENDED_SECURITY;
2829 if (ses->capabilities & CAP_UNICODE) {
2830 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2831 capabilities |= CAP_UNICODE;
2832 }
2833 if (ses->capabilities & CAP_STATUS32) {
2834 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2835 capabilities |= CAP_STATUS32;
2836 }
2837 if (ses->capabilities & CAP_DFS) {
2838 smb_buffer->Flags2 |= SMBFLG2_DFS;
2839 capabilities |= CAP_DFS;
2840 }
2841 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2842
2843 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2844 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2845 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2846 SecurityBlob->MessageType = NtLmAuthenticate;
2847 bcc_ptr += SecurityBlobLength;
2848 negotiate_flags =
2849 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2850 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2851 0x80000000 | NTLMSSP_NEGOTIATE_128;
2852 if(sign_CIFS_PDUs)
2853 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2854 if(ntlmv2_flag)
2855 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2856
2857/* setup pointers to domain name and workstation name */
2858
2859 SecurityBlob->WorkstationName.Buffer = 0;
2860 SecurityBlob->WorkstationName.Length = 0;
2861 SecurityBlob->WorkstationName.MaximumLength = 0;
2862 SecurityBlob->SessionKey.Length = 0;
2863 SecurityBlob->SessionKey.MaximumLength = 0;
2864 SecurityBlob->SessionKey.Buffer = 0;
2865
2866 SecurityBlob->LmChallengeResponse.Length = 0;
2867 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2868 SecurityBlob->LmChallengeResponse.Buffer = 0;
2869
2870 SecurityBlob->NtChallengeResponse.Length =
2871 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2872 SecurityBlob->NtChallengeResponse.MaximumLength =
2873 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
2874 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
2875 SecurityBlob->NtChallengeResponse.Buffer =
2876 cpu_to_le32(SecurityBlobLength);
2877 SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
2878 bcc_ptr += CIFS_SESSION_KEY_SIZE;
2879
2880 if (ses->capabilities & CAP_UNICODE) {
2881 if (domain == NULL) {
2882 SecurityBlob->DomainName.Buffer = 0;
2883 SecurityBlob->DomainName.Length = 0;
2884 SecurityBlob->DomainName.MaximumLength = 0;
2885 } else {
2886 __u16 len =
2887 cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
2888 nls_codepage);
2889 len *= 2;
2890 SecurityBlob->DomainName.MaximumLength =
2891 cpu_to_le16(len);
2892 SecurityBlob->DomainName.Buffer =
2893 cpu_to_le32(SecurityBlobLength);
2894 bcc_ptr += len;
2895 SecurityBlobLength += len;
2896 SecurityBlob->DomainName.Length =
2897 cpu_to_le16(len);
2898 }
2899 if (user == NULL) {
2900 SecurityBlob->UserName.Buffer = 0;
2901 SecurityBlob->UserName.Length = 0;
2902 SecurityBlob->UserName.MaximumLength = 0;
2903 } else {
2904 __u16 len =
2905 cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
2906 nls_codepage);
2907 len *= 2;
2908 SecurityBlob->UserName.MaximumLength =
2909 cpu_to_le16(len);
2910 SecurityBlob->UserName.Buffer =
2911 cpu_to_le32(SecurityBlobLength);
2912 bcc_ptr += len;
2913 SecurityBlobLength += len;
2914 SecurityBlob->UserName.Length =
2915 cpu_to_le16(len);
2916 }
2917
2918 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
2919 SecurityBlob->WorkstationName.Length *= 2;
2920 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2921 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2922 bcc_ptr += SecurityBlob->WorkstationName.Length;
2923 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2924 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2925
2926 if ((long) bcc_ptr % 2) {
2927 *bcc_ptr = 0;
2928 bcc_ptr++;
2929 }
2930 bytes_returned =
2931 cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
2932 32, nls_codepage);
2933 bcc_ptr += 2 * bytes_returned;
2934 bytes_returned =
2935 cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
2936 nls_codepage);
2937 bcc_ptr += 2 * bytes_returned;
2938 bcc_ptr += 2; /* null term version string */
2939 bytes_returned =
2940 cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
2941 64, nls_codepage);
2942 bcc_ptr += 2 * bytes_returned;
2943 *(bcc_ptr + 1) = 0;
2944 *(bcc_ptr + 2) = 0;
2945 bcc_ptr += 2; /* null terminate network opsys string */
2946 *(bcc_ptr + 1) = 0;
2947 *(bcc_ptr + 2) = 0;
2948 bcc_ptr += 2; /* null domain */
2949 } else { /* ASCII */
2950 if (domain == NULL) {
2951 SecurityBlob->DomainName.Buffer = 0;
2952 SecurityBlob->DomainName.Length = 0;
2953 SecurityBlob->DomainName.MaximumLength = 0;
2954 } else {
2955 __u16 len;
2956 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2957 strncpy(bcc_ptr, domain, 63);
2958 len = strnlen(domain, 64);
2959 SecurityBlob->DomainName.MaximumLength =
2960 cpu_to_le16(len);
2961 SecurityBlob->DomainName.Buffer =
2962 cpu_to_le32(SecurityBlobLength);
2963 bcc_ptr += len;
2964 SecurityBlobLength += len;
2965 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2966 }
2967 if (user == NULL) {
2968 SecurityBlob->UserName.Buffer = 0;
2969 SecurityBlob->UserName.Length = 0;
2970 SecurityBlob->UserName.MaximumLength = 0;
2971 } else {
2972 __u16 len;
2973 strncpy(bcc_ptr, user, 63);
2974 len = strnlen(user, 64);
2975 SecurityBlob->UserName.MaximumLength =
2976 cpu_to_le16(len);
2977 SecurityBlob->UserName.Buffer =
2978 cpu_to_le32(SecurityBlobLength);
2979 bcc_ptr += len;
2980 SecurityBlobLength += len;
2981 SecurityBlob->UserName.Length = cpu_to_le16(len);
2982 }
2983 /* BB fill in our workstation name if known BB */
2984
2985 strcpy(bcc_ptr, "Linux version ");
2986 bcc_ptr += strlen("Linux version ");
2987 strcpy(bcc_ptr, system_utsname.release);
2988 bcc_ptr += strlen(system_utsname.release) + 1;
2989 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2990 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2991 bcc_ptr++; /* null domain */
2992 *bcc_ptr = 0;
2993 }
2994 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2995 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2996 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2997 smb_buffer->smb_buf_length += count;
2998 pSMB->req.ByteCount = cpu_to_le16(count);
2999
3000 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3001 &bytes_returned, 1);
3002 if (rc) {
3003/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3004 } else if ((smb_buffer_response->WordCount == 3)
3005 || (smb_buffer_response->WordCount == 4)) {
3006 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3007 __u16 blob_len =
3008 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3009 if (action & GUEST_LOGIN)
3010 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
3011/* if(SecurityBlob2->MessageType != NtLm??){
3012 cFYI("Unexpected message type on auth response is %d "));
3013 } */
3014 if (ses) {
3015 cFYI(1,
3016 ("Does UID on challenge %d match auth response UID %d ",
3017 ses->Suid, smb_buffer_response->Uid));
3018 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
3019 bcc_ptr = pByteArea(smb_buffer_response);
3020 /* response can have either 3 or 4 word count - Samba sends 3 */
3021 if ((pSMBr->resp.hdr.WordCount == 3)
3022 || ((pSMBr->resp.hdr.WordCount == 4)
3023 && (blob_len <
3024 pSMBr->resp.ByteCount))) {
3025 if (pSMBr->resp.hdr.WordCount == 4) {
3026 bcc_ptr +=
3027 blob_len;
3028 cFYI(1,
3029 ("Security Blob Length %d ",
3030 blob_len));
3031 }
3032
3033 cFYI(1,
3034 ("NTLMSSP response to Authenticate "));
3035
3036 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3037 if ((long) (bcc_ptr) % 2) {
3038 remaining_words =
3039 (BCC(smb_buffer_response)
3040 - 1) / 2;
3041 bcc_ptr++; /* Unicode strings must be word aligned */
3042 } else {
3043 remaining_words = BCC(smb_buffer_response) / 2;
3044 }
3045 len =
3046 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3047/* We look for obvious messed up bcc or strings in response so we do not go off
3048 the end since (at least) WIN2K and Windows XP have a major bug in not null
3049 terminating last Unicode string in response */
3050 ses->serverOS =
Steve French433dc242005-04-28 22:41:08 -07003051 kcalloc(1, 2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 cifs_strfromUCS_le(ses->serverOS,
3053 (wchar_t *)
3054 bcc_ptr, len,
3055 nls_codepage);
3056 bcc_ptr += 2 * (len + 1);
3057 remaining_words -= len + 1;
3058 ses->serverOS[2 * len] = 0;
3059 ses->serverOS[1 + (2 * len)] = 0;
3060 if (remaining_words > 0) {
3061 len = UniStrnlen((wchar_t *)
3062 bcc_ptr,
3063 remaining_words
3064 - 1);
3065 ses->serverNOS =
Steve French433dc242005-04-28 22:41:08 -07003066 kcalloc(1, 2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 GFP_KERNEL);
3068 cifs_strfromUCS_le(ses->
3069 serverNOS,
3070 (wchar_t *)
3071 bcc_ptr,
3072 len,
3073 nls_codepage);
3074 bcc_ptr += 2 * (len + 1);
3075 ses->serverNOS[2 * len] = 0;
3076 ses->serverNOS[1+(2*len)] = 0;
3077 remaining_words -= len + 1;
3078 if (remaining_words > 0) {
3079 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3080 /* last string not always null terminated (e.g. for Windows XP & 2000) */
3081 ses->serverDomain =
Steve French433dc242005-04-28 22:41:08 -07003082 kcalloc(1, 2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 (len +
3084 1),
3085 GFP_KERNEL);
3086 cifs_strfromUCS_le
3087 (ses->
3088 serverDomain,
3089 (wchar_t *)
3090 bcc_ptr, len,
3091 nls_codepage);
3092 bcc_ptr +=
3093 2 * (len + 1);
3094 ses->
3095 serverDomain[2
3096 * len]
3097 = 0;
3098 ses->
3099 serverDomain[1
3100 +
3101 (2
3102 *
3103 len)]
3104 = 0;
3105 } /* else no more room so create dummy domain string */
3106 else
Steve French433dc242005-04-28 22:41:08 -07003107 ses->serverDomain = kcalloc(1, 2,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07003109 ses->serverDomain = kcalloc(1, 2, GFP_KERNEL);
3110 ses->serverNOS = kcalloc(1, 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 }
3112 } else { /* ASCII */
3113 len = strnlen(bcc_ptr, 1024);
3114 if (((long) bcc_ptr + len) -
3115 (long) pByteArea(smb_buffer_response)
3116 <= BCC(smb_buffer_response)) {
Steve French433dc242005-04-28 22:41:08 -07003117 ses->serverOS = kcalloc(1, len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 strncpy(ses->serverOS,bcc_ptr, len);
3119
3120 bcc_ptr += len;
3121 bcc_ptr[0] = 0; /* null terminate the string */
3122 bcc_ptr++;
3123
3124 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003125 ses->serverNOS = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 strncpy(ses->serverNOS, bcc_ptr, len);
3127 bcc_ptr += len;
3128 bcc_ptr[0] = 0;
3129 bcc_ptr++;
3130
3131 len = strnlen(bcc_ptr, 1024);
Steve French433dc242005-04-28 22:41:08 -07003132 ses->serverDomain = kcalloc(1, len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 strncpy(ses->serverDomain, bcc_ptr, len);
3134 bcc_ptr += len;
3135 bcc_ptr[0] = 0;
3136 bcc_ptr++;
3137 } else
3138 cFYI(1,
3139 ("Variable field of length %d extends beyond end of smb ",
3140 len));
3141 }
3142 } else {
3143 cERROR(1,
3144 (" Security Blob Length extends beyond end of SMB"));
3145 }
3146 } else {
3147 cERROR(1, ("No session structure passed in."));
3148 }
3149 } else {
3150 cERROR(1,
3151 (" Invalid Word count %d: ",
3152 smb_buffer_response->WordCount));
3153 rc = -EIO;
3154 }
3155
3156 if (smb_buffer)
3157 cifs_buf_release(smb_buffer);
3158
3159 return rc;
3160}
3161
3162int
3163CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3164 const char *tree, struct cifsTconInfo *tcon,
3165 const struct nls_table *nls_codepage)
3166{
3167 struct smb_hdr *smb_buffer;
3168 struct smb_hdr *smb_buffer_response;
3169 TCONX_REQ *pSMB;
3170 TCONX_RSP *pSMBr;
3171 unsigned char *bcc_ptr;
3172 int rc = 0;
3173 int length;
3174 __u16 count;
3175
3176 if (ses == NULL)
3177 return -EIO;
3178
3179 smb_buffer = cifs_buf_get();
3180 if (smb_buffer == NULL) {
3181 return -ENOMEM;
3182 }
3183 smb_buffer_response = smb_buffer;
3184
3185 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3186 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003187
3188 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 smb_buffer->Uid = ses->Suid;
3190 pSMB = (TCONX_REQ *) smb_buffer;
3191 pSMBr = (TCONX_RSP *) smb_buffer_response;
3192
3193 pSMB->AndXCommand = 0xFF;
3194 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
3195 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
3196 bcc_ptr = &pSMB->Password[0];
3197 bcc_ptr++; /* skip password */
3198
3199 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3200 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3201
3202 if (ses->capabilities & CAP_STATUS32) {
3203 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3204 }
3205 if (ses->capabilities & CAP_DFS) {
3206 smb_buffer->Flags2 |= SMBFLG2_DFS;
3207 }
3208 if (ses->capabilities & CAP_UNICODE) {
3209 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3210 length =
3211 cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
3212 bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
3213 bcc_ptr += 2; /* skip trailing null */
3214 } else { /* ASCII */
3215
3216 strcpy(bcc_ptr, tree);
3217 bcc_ptr += strlen(tree) + 1;
3218 }
3219 strcpy(bcc_ptr, "?????");
3220 bcc_ptr += strlen("?????");
3221 bcc_ptr += 1;
3222 count = bcc_ptr - &pSMB->Password[0];
3223 pSMB->hdr.smb_buf_length += count;
3224 pSMB->ByteCount = cpu_to_le16(count);
3225
3226 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3227
3228 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3229 /* above now done in SendReceive */
3230 if ((rc == 0) && (tcon != NULL)) {
3231 tcon->tidStatus = CifsGood;
3232 tcon->tid = smb_buffer_response->Tid;
3233 bcc_ptr = pByteArea(smb_buffer_response);
3234 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3235 /* skip service field (NB: this field is always ASCII) */
3236 bcc_ptr += length + 1;
3237 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3238 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3239 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3240 if ((bcc_ptr + (2 * length)) -
3241 pByteArea(smb_buffer_response) <=
3242 BCC(smb_buffer_response)) {
3243 if(tcon->nativeFileSystem)
3244 kfree(tcon->nativeFileSystem);
3245 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003246 kcalloc(1, length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 cifs_strfromUCS_le(tcon->nativeFileSystem,
3248 (wchar_t *) bcc_ptr,
3249 length, nls_codepage);
3250 bcc_ptr += 2 * length;
3251 bcc_ptr[0] = 0; /* null terminate the string */
3252 bcc_ptr[1] = 0;
3253 bcc_ptr += 2;
3254 }
3255 /* else do not bother copying these informational fields */
3256 } else {
3257 length = strnlen(bcc_ptr, 1024);
3258 if ((bcc_ptr + length) -
3259 pByteArea(smb_buffer_response) <=
3260 BCC(smb_buffer_response)) {
3261 if(tcon->nativeFileSystem)
3262 kfree(tcon->nativeFileSystem);
3263 tcon->nativeFileSystem =
Steve French433dc242005-04-28 22:41:08 -07003264 kcalloc(1, length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 strncpy(tcon->nativeFileSystem, bcc_ptr,
3266 length);
3267 }
3268 /* else do not bother copying these informational fields */
3269 }
3270 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3271 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3272 } else if ((rc == 0) && tcon == NULL) {
3273 /* all we need to save for IPC$ connection */
3274 ses->ipc_tid = smb_buffer_response->Tid;
3275 }
3276
3277 if (smb_buffer)
3278 cifs_buf_release(smb_buffer);
3279 return rc;
3280}
3281
3282int
3283cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3284{
3285 int rc = 0;
3286 int xid;
3287 struct cifsSesInfo *ses = NULL;
3288 struct task_struct *cifsd_task;
3289
3290 xid = GetXid();
3291
3292 if (cifs_sb->tcon) {
3293 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3294 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3295 if (rc == -EBUSY) {
3296 FreeXid(xid);
3297 return 0;
3298 }
3299 tconInfoFree(cifs_sb->tcon);
3300 if ((ses) && (ses->server)) {
3301 /* save off task so we do not refer to ses later */
3302 cifsd_task = ses->server->tsk;
3303 cFYI(1, ("About to do SMBLogoff "));
3304 rc = CIFSSMBLogoff(xid, ses);
3305 if (rc == -EBUSY) {
3306 FreeXid(xid);
3307 return 0;
3308 } else if (rc == -ESHUTDOWN) {
3309 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf1914012005-08-18 09:37:34 -07003310 if(cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 send_sig(SIGKILL,cifsd_task,1);
Steve Frenchf1914012005-08-18 09:37:34 -07003312 wait_for_completion(&cifsd_complete);
3313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 rc = 0;
3315 } /* else - we have an smb session
3316 left on this socket do not kill cifsd */
3317 } else
3318 cFYI(1, ("No session or bad tcon"));
3319 }
3320
3321 cifs_sb->tcon = NULL;
3322 if (ses) {
3323 set_current_state(TASK_INTERRUPTIBLE);
3324 schedule_timeout(HZ / 2);
3325 }
3326 if (ses)
3327 sesInfoFree(ses);
3328
3329 FreeXid(xid);
3330 return rc; /* BB check if we should always return zero here */
3331}
3332
3333int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3334 struct nls_table * nls_info)
3335{
3336 int rc = 0;
3337 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
3338 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003339 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340
3341 /* what if server changes its buffer size after dropping the session? */
3342 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3343 rc = CIFSSMBNegotiate(xid, pSesInfo);
3344 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3345 rc = CIFSSMBNegotiate(xid, pSesInfo);
3346 if(rc == -EAGAIN)
3347 rc = -EHOSTDOWN;
3348 }
3349 if(rc == 0) {
3350 spin_lock(&GlobalMid_Lock);
3351 if(pSesInfo->server->tcpStatus != CifsExiting)
3352 pSesInfo->server->tcpStatus = CifsGood;
3353 else
3354 rc = -EHOSTDOWN;
3355 spin_unlock(&GlobalMid_Lock);
3356
3357 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003358 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 }
3360 if (!rc) {
3361 pSesInfo->capabilities = pSesInfo->server->capabilities;
3362 if(linuxExtEnabled == 0)
3363 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003364 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3366 pSesInfo->server->secMode,
3367 pSesInfo->server->capabilities,
3368 pSesInfo->server->timeZone));
3369 if (extended_security
3370 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3371 && (pSesInfo->server->secType == NTLMSSP)) {
3372 cFYI(1, ("New style sesssetup "));
3373 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3374 NULL /* security blob */,
3375 0 /* blob length */,
3376 nls_info);
3377 } else if (extended_security
3378 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3379 && (pSesInfo->server->secType == RawNTLMSSP)) {
3380 cFYI(1, ("NTLMSSP sesssetup "));
3381 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3382 pSesInfo,
3383 &ntlmv2_flag,
3384 nls_info);
3385 if (!rc) {
3386 if(ntlmv2_flag) {
3387 char * v2_response;
3388 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3389 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3390 nls_info)) {
3391 rc = -ENOMEM;
3392 goto ss_err_exit;
3393 } else
3394 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3395 if(v2_response) {
3396 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003397 /* if(first_time)
3398 cifs_calculate_ntlmv2_mac_key(
3399 pSesInfo->server->mac_signing_key,
3400 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 kfree(v2_response);
3402 /* BB Put dummy sig in SessSetup PDU? */
3403 } else {
3404 rc = -ENOMEM;
3405 goto ss_err_exit;
3406 }
3407
3408 } else {
3409 SMBNTencrypt(pSesInfo->password,
3410 pSesInfo->server->cryptKey,
3411 ntlm_session_key);
3412
Steve Frenchad009ac2005-04-28 22:41:05 -07003413 if(first_time)
3414 cifs_calculate_mac_key(
3415 pSesInfo->server->mac_signing_key,
3416 ntlm_session_key,
3417 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 }
3419 /* for better security the weaker lanman hash not sent
3420 in AuthSessSetup so we no longer calculate it */
3421
3422 rc = CIFSNTLMSSPAuthSessSetup(xid,
3423 pSesInfo,
3424 ntlm_session_key,
3425 ntlmv2_flag,
3426 nls_info);
3427 }
3428 } else { /* old style NTLM 0.12 session setup */
3429 SMBNTencrypt(pSesInfo->password,
3430 pSesInfo->server->cryptKey,
3431 ntlm_session_key);
3432
Steve Frenchad009ac2005-04-28 22:41:05 -07003433 if(first_time)
3434 cifs_calculate_mac_key(
3435 pSesInfo->server->mac_signing_key,
3436 ntlm_session_key, pSesInfo->password);
3437
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 rc = CIFSSessSetup(xid, pSesInfo,
3439 ntlm_session_key, nls_info);
3440 }
3441 if (rc) {
3442 cERROR(1,("Send error in SessSetup = %d",rc));
3443 } else {
3444 cFYI(1,("CIFS Session Established successfully"));
3445 pSesInfo->status = CifsGood;
3446 }
3447 }
3448ss_err_exit:
3449 return rc;
3450}
3451