blob: faaf9eb15b9f8a72084ea676a496e480ccc5813f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve French5815449d2006-02-14 01:36:20 +00004 * Copyright (C) International Business Machines Corp., 2002,2006
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>
Steve French0ae0efa2005-10-10 10:57:19 -070033#include <linux/pagevec.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <asm/uaccess.h>
35#include <asm/processor.h>
36#include "cifspdu.h"
37#include "cifsglob.h"
38#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41#include "cifs_fs_sb.h"
42#include "ntlmssp.h"
43#include "nterr.h"
44#include "rfc1002pdu.h"
Steve Frencha2653eb2005-11-10 15:33:38 -080045#include "cn_cifs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#define CIFS_PORT 445
48#define RFC1001_PORT 139
49
Steve Frenchf1914012005-08-18 09:37:34 -070050static DECLARE_COMPLETION(cifsd_complete);
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052extern 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 */
Steve French0a4b92c2006-01-12 15:44:21 -080077 unsigned cifs_acl:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
79 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
80 unsigned direct_io:1;
Steve French6a0b4822005-04-28 22:41:05 -070081 unsigned remap:1; /* set to remap seven reserved chars in filenames */
Jeremy Allisonac670552005-06-22 17:26:35 -070082 unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
Steve Frenchd7245c22005-07-14 18:25:12 -050083 unsigned sfu_emul:1;
Steve Frenchbf820672005-12-01 22:32:42 -080084 unsigned krb5:1;
85 unsigned ntlm:1;
86 unsigned ntlmv2:1;
87 unsigned nullauth:1; /* attempt to authenticate with null user */
88 unsigned sign:1;
89 unsigned seal:1; /* encrypt */
Steve Frenchc46fa8a2005-08-18 20:49:57 -070090 unsigned nocase; /* request case insensitive filenames */
91 unsigned nobrl; /* disable sending byte range locks to srv */
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 unsigned int rsize;
93 unsigned int wsize;
94 unsigned int sockopt;
95 unsigned short int port;
96};
97
98static int ipv4_connect(struct sockaddr_in *psin_server,
99 struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700100 char * netb_name,
101 char * server_netb_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102static int ipv6_connect(struct sockaddr_in6 *psin_server,
103 struct socket **csocket);
104
105
106 /*
107 * cifs tcp session reconnection
108 *
109 * mark tcp session as reconnecting so temporarily locked
110 * mark all smb sessions as reconnecting for tcp session
111 * reconnect tcp session
112 * wake up waiters on reconnection? - (not needed currently)
113 */
114
115int
116cifs_reconnect(struct TCP_Server_Info *server)
117{
118 int rc = 0;
119 struct list_head *tmp;
120 struct cifsSesInfo *ses;
121 struct cifsTconInfo *tcon;
122 struct mid_q_entry * mid_entry;
123
124 spin_lock(&GlobalMid_Lock);
125 if(server->tcpStatus == CifsExiting) {
126 /* the demux thread will exit normally
127 next time through the loop */
128 spin_unlock(&GlobalMid_Lock);
129 return rc;
130 } else
131 server->tcpStatus = CifsNeedReconnect;
132 spin_unlock(&GlobalMid_Lock);
133 server->maxBuf = 0;
134
Steve Frenche4eb2952005-04-28 22:41:09 -0700135 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137 /* before reconnecting the tcp session, mark the smb session (uid)
138 and the tid bad so they are not used until reconnected */
139 read_lock(&GlobalSMBSeslock);
140 list_for_each(tmp, &GlobalSMBSessionList) {
141 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
142 if (ses->server) {
143 if (ses->server == server) {
144 ses->status = CifsNeedReconnect;
145 ses->ipc_tid = 0;
146 }
147 }
148 /* else tcp and smb sessions need reconnection */
149 }
150 list_for_each(tmp, &GlobalTreeConnectionList) {
151 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
152 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
153 tcon->tidStatus = CifsNeedReconnect;
154 }
155 }
156 read_unlock(&GlobalSMBSeslock);
157 /* do not want to be sending data on a socket we are freeing */
158 down(&server->tcpSem);
159 if(server->ssocket) {
160 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
161 server->ssocket->flags));
162 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
163 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
164 server->ssocket->flags));
165 sock_release(server->ssocket);
166 server->ssocket = NULL;
167 }
168
169 spin_lock(&GlobalMid_Lock);
170 list_for_each(tmp, &server->pending_mid_q) {
171 mid_entry = list_entry(tmp, struct
172 mid_q_entry,
173 qhead);
174 if(mid_entry) {
175 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700176 /* Mark other intransit requests as needing
177 retry so we do not immediately mark the
178 session bad again (ie after we reconnect
179 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 mid_entry->midState = MID_RETRY_NEEDED;
181 }
182 }
183 }
184 spin_unlock(&GlobalMid_Lock);
185 up(&server->tcpSem);
186
187 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
188 {
189 if(server->protocolType == IPV6) {
190 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
191 } else {
192 rc = ipv4_connect(&server->addr.sockAddr,
193 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700194 server->workstation_RFC1001_name,
195 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 }
197 if(rc) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700198 cFYI(1,("reconnect error %d",rc));
Steve French0cb766a2005-04-28 22:41:11 -0700199 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 } else {
201 atomic_inc(&tcpSesReconnectCount);
202 spin_lock(&GlobalMid_Lock);
203 if(server->tcpStatus != CifsExiting)
204 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700205 server->sequence_number = 0;
206 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 /* atomic_set(&server->inFlight,0);*/
208 wake_up(&server->response_q);
209 }
210 }
211 return rc;
212}
213
Steve Frenche4eb2952005-04-28 22:41:09 -0700214/*
215 return codes:
216 0 not a transact2, or all data present
217 >0 transact2 with that much data missing
218 -EINVAL = invalid transact2
219
220 */
221static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
222{
223 struct smb_t2_rsp * pSMBt;
224 int total_data_size;
225 int data_in_this_rsp;
226 int remaining;
227
228 if(pSMB->Command != SMB_COM_TRANSACTION2)
229 return 0;
230
231 /* check for plausible wct, bcc and t2 data and parm sizes */
232 /* check for parm and data offset going beyond end of smb */
233 if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
234 cFYI(1,("invalid transact2 word count"));
235 return -EINVAL;
236 }
237
238 pSMBt = (struct smb_t2_rsp *)pSMB;
239
240 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
241 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
242
243 remaining = total_data_size - data_in_this_rsp;
244
245 if(remaining == 0)
246 return 0;
247 else if(remaining < 0) {
248 cFYI(1,("total data %d smaller than data in frame %d",
249 total_data_size, data_in_this_rsp));
250 return -EINVAL;
251 } else {
252 cFYI(1,("missing %d bytes from transact2, check next response",
253 remaining));
254 if(total_data_size > maxBufSize) {
255 cERROR(1,("TotalDataSize %d is over maximum buffer %d",
256 total_data_size,maxBufSize));
257 return -EINVAL;
258 }
259 return remaining;
260 }
261}
262
263static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
264{
265 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
266 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
267 int total_data_size;
268 int total_in_buf;
269 int remaining;
270 int total_in_buf2;
271 char * data_area_of_target;
272 char * data_area_of_buf2;
273 __u16 byte_count;
274
275 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
276
277 if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
278 cFYI(1,("total data sizes of primary and secondary t2 differ"));
279 }
280
281 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
282
283 remaining = total_data_size - total_in_buf;
284
285 if(remaining < 0)
286 return -EINVAL;
287
288 if(remaining == 0) /* nothing to do, ignore */
289 return 0;
290
291 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
292 if(remaining < total_in_buf2) {
293 cFYI(1,("transact2 2nd response contains too much data"));
294 }
295
296 /* find end of first SMB data area */
297 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
298 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
299 /* validate target area */
300
301 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
302 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
303
304 data_area_of_target += total_in_buf;
305
306 /* copy second buffer into end of first buffer */
307 memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
308 total_in_buf += total_in_buf2;
309 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
310 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
311 byte_count += total_in_buf2;
312 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
313
Steve French70ca7342005-09-22 16:32:06 -0700314 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700315 byte_count += total_in_buf2;
316
317 /* BB also add check that we are not beyond maximum buffer size */
318
Steve French70ca7342005-09-22 16:32:06 -0700319 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700320
321 if(remaining == total_in_buf2) {
322 cFYI(1,("found the last secondary response"));
323 return 0; /* we are done */
324 } else /* more responses to go */
325 return 1;
326
327}
328
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329static int
330cifs_demultiplex_thread(struct TCP_Server_Info *server)
331{
332 int length;
333 unsigned int pdu_length, total_read;
334 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700335 struct smb_hdr *bigbuf = NULL;
336 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 struct msghdr smb_msg;
338 struct kvec iov;
339 struct socket *csocket = server->ssocket;
340 struct list_head *tmp;
341 struct cifsSesInfo *ses;
342 struct task_struct *task_to_wake = NULL;
343 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700344 char temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700345 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700346 int isMultiRsp;
347 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 daemonize("cifsd");
350 allow_signal(SIGKILL);
351 current->flags |= PF_MEMALLOC;
352 server->tsk = current; /* save process info to wake at shutdown */
353 cFYI(1, ("Demultiplex PID: %d", current->pid));
354 write_lock(&GlobalSMBSeslock);
355 atomic_inc(&tcpSesAllocCount);
356 length = tcpSesAllocCount.counter;
357 write_unlock(&GlobalSMBSeslock);
Steve Frenchf1914012005-08-18 09:37:34 -0700358 complete(&cifsd_complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 if(length > 1) {
360 mempool_resize(cifs_req_poolp,
361 length + cifs_min_rcv,
362 GFP_KERNEL);
363 }
364
365 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700366 if (try_to_freeze())
367 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700368 if (bigbuf == NULL) {
369 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000370 if (!bigbuf) {
371 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700372 msleep(3000);
373 /* retry will check if exiting */
374 continue;
375 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000376 } else if (isLargeBuf) {
377 /* we are reusing a dirty large buf, clear its start */
Steve Frenchb8643e12005-04-28 22:41:07 -0700378 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700380
381 if (smallbuf == NULL) {
382 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000383 if (!smallbuf) {
384 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700385 msleep(1000);
386 /* retry will check if exiting */
387 continue;
388 }
389 /* beginning of smb buffer is cleared in our buf_get */
390 } else /* if existing small buf clear beginning */
391 memset(smallbuf, 0, sizeof (struct smb_hdr));
392
393 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700394 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700395 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 iov.iov_base = smb_buffer;
397 iov.iov_len = 4;
398 smb_msg.msg_control = NULL;
399 smb_msg.msg_controllen = 0;
400 length =
401 kernel_recvmsg(csocket, &smb_msg,
402 &iov, 1, 4, 0 /* BB see socket.h flags */);
403
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000404 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 break;
406 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000407 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000409 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 csocket = server->ssocket;
411 continue;
412 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700413 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 allowing socket to clear and app threads to set
415 tcpStatus CifsNeedReconnect if server hung */
416 continue;
417 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000418 if (server->tcpStatus == CifsNew) {
419 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700420 /* some servers kill the TCP session rather than
421 returning an SMB negprot error, in which
422 case reconnecting here is not going to help,
423 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 break;
425 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000426 if (!try_to_freeze() && (length == -EINTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 cFYI(1,("cifsd thread killed"));
428 break;
429 }
Steve French57337e42005-04-28 22:41:10 -0700430 cFYI(1,("Reconnect after unexpected peek error %d",
431 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 cifs_reconnect(server);
433 csocket = server->ssocket;
434 wake_up(&server->response_q);
435 continue;
Steve French46810cb2005-04-28 22:41:09 -0700436 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700438 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 length));
440 cifs_reconnect(server);
441 csocket = server->ssocket;
442 wake_up(&server->response_q);
443 continue;
444 }
Steve French67010fb2005-04-28 22:41:09 -0700445
Steve French70ca7342005-09-22 16:32:06 -0700446 /* The right amount was read from socket - 4 bytes */
447 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700448
Steve French70ca7342005-09-22 16:32:06 -0700449 /* the first byte big endian of the length field,
450 is actually not part of the length but the type
451 with the most common, zero, as regular data */
452 temp = *((char *) smb_buffer);
453
454 /* Note that FC 1001 length is big endian on the wire,
455 but we convert it here so it is always manipulated
456 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700457 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700458 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700459
Steve French70ca7342005-09-22 16:32:06 -0700460 cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
461
462 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700463 continue;
Steve French70ca7342005-09-22 16:32:06 -0700464 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700465 cFYI(1,("Good RFC 1002 session rsp"));
466 continue;
Steve French70ca7342005-09-22 16:32:06 -0700467 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve French46810cb2005-04-28 22:41:09 -0700468 /* we get this from Windows 98 instead of
469 an error on SMB negprot response */
Steve Frenche4eb2952005-04-28 22:41:09 -0700470 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700471 pdu_length));
Steve French46810cb2005-04-28 22:41:09 -0700472 if(server->tcpStatus == CifsNew) {
473 /* if nack on negprot (rather than
474 ret of smb negprot error) reconnecting
475 not going to help, ret error to mount */
476 break;
477 } else {
478 /* give server a second to
479 clean up before reconnect attempt */
480 msleep(1000);
481 /* always try 445 first on reconnect
482 since we get NACK on some if we ever
483 connected to port 139 (the NACK is
484 since we do not begin with RFC1001
485 session initialize frame) */
486 server->addr.sockAddr.sin_port =
487 htons(CIFS_PORT);
488 cifs_reconnect(server);
489 csocket = server->ssocket;
490 wake_up(&server->response_q);
491 continue;
492 }
Steve French70ca7342005-09-22 16:32:06 -0700493 } else if (temp != (char) 0) {
Steve French46810cb2005-04-28 22:41:09 -0700494 cERROR(1,("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700495 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
496 length);
Steve French46810cb2005-04-28 22:41:09 -0700497 cifs_reconnect(server);
498 csocket = server->ssocket;
499 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700500 }
501
502 /* else we have an SMB response */
503 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700504 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700505 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700506 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700507 cifs_reconnect(server);
508 csocket = server->ssocket;
509 wake_up(&server->response_q);
510 continue;
511 }
512
513 /* else length ok */
514 reconnect = 0;
515
Steve Frenchec637e32005-12-12 20:53:18 -0800516 if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700517 isLargeBuf = TRUE;
518 memcpy(bigbuf, smallbuf, 4);
519 smb_buffer = bigbuf;
520 }
521 length = 0;
522 iov.iov_base = 4 + (char *)smb_buffer;
523 iov.iov_len = pdu_length;
524 for (total_read = 0; total_read < pdu_length;
525 total_read += length) {
526 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
527 pdu_length - total_read, 0);
528 if((server->tcpStatus == CifsExiting) ||
529 (length == -EINTR)) {
530 /* then will exit */
531 reconnect = 2;
532 break;
533 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700534 cifs_reconnect(server);
535 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700536 /* Reconnect wakes up rspns q */
537 /* Now we will reread sock */
538 reconnect = 1;
539 break;
540 } else if ((length == -ERESTARTSYS) ||
541 (length == -EAGAIN)) {
542 msleep(1); /* minimum sleep to prevent looping,
543 allowing socket to clear and app
544 threads to set tcpStatus
545 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700546 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700547 } else if (length <= 0) {
548 cERROR(1,("Received no data, expecting %d",
549 pdu_length - total_read));
550 cifs_reconnect(server);
551 csocket = server->ssocket;
552 reconnect = 1;
553 break;
Steve French46810cb2005-04-28 22:41:09 -0700554 }
555 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700556 if(reconnect == 2)
557 break;
558 else if(reconnect == 1)
559 continue;
560
561 length += 4; /* account for rfc1002 hdr */
562
563
564 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000565 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700566 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700567 continue;
568 }
569
570
571 task_to_wake = NULL;
572 spin_lock(&GlobalMid_Lock);
573 list_for_each(tmp, &server->pending_mid_q) {
574 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
575
576 if ((mid_entry->mid == smb_buffer->Mid) &&
577 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
578 (mid_entry->command == smb_buffer->Command)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700579 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
580 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700581 isMultiRsp = TRUE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700582 if(mid_entry->resp_buf) {
583 /* merge response - fix up 1st*/
584 if(coalesce_t2(smb_buffer,
585 mid_entry->resp_buf)) {
Steve French39798772006-05-31 22:40:51 +0000586 mid_entry->multiRsp = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700587 break;
588 } else {
589 /* all parts received */
Steve French39798772006-05-31 22:40:51 +0000590 mid_entry->multiEnd = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700591 goto multi_t2_fnd;
592 }
593 } else {
594 if(!isLargeBuf) {
595 cERROR(1,("1st trans2 resp needs bigbuf"));
596 /* BB maybe we can fix this up, switch
597 to already allocated large buffer? */
598 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700599 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700600 mid_entry->resp_buf =
601 smb_buffer;
602 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700603 bigbuf = NULL;
604 }
605 }
606 break;
607 }
608 mid_entry->resp_buf = smb_buffer;
609 if(isLargeBuf)
610 mid_entry->largeBuf = 1;
611 else
612 mid_entry->largeBuf = 0;
613multi_t2_fnd:
614 task_to_wake = mid_entry->tsk;
615 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700616#ifdef CONFIG_CIFS_STATS2
617 mid_entry->when_received = jiffies;
618#endif
Steve Frenche4eb2952005-04-28 22:41:09 -0700619 break;
620 }
621 }
622 spin_unlock(&GlobalMid_Lock);
623 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700624 /* Was previous buf put in mpx struct for multi-rsp? */
625 if(!isMultiRsp) {
626 /* smb buffer will be freed by user thread */
627 if(isLargeBuf) {
628 bigbuf = NULL;
629 } else
630 smallbuf = NULL;
631 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700632 wake_up_process(task_to_wake);
Steve Frenchd7c8c942006-03-03 10:43:49 +0000633 } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700634 && (isMultiRsp == FALSE)) {
Steve French39798772006-05-31 22:40:51 +0000635 cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
Steve French70ca7342005-09-22 16:32:06 -0700636 cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
637 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000638#ifdef CONFIG_CIFS_DEBUG2
639 cifs_dump_detail(smb_buffer);
640 cifs_dump_mids(server);
641#endif /* CIFS_DEBUG2 */
642
Steve Frenche4eb2952005-04-28 22:41:09 -0700643 }
644 } /* end while !EXITING */
645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 spin_lock(&GlobalMid_Lock);
647 server->tcpStatus = CifsExiting;
648 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700649 /* check if we have blocked requests that need to free */
650 /* Note that cifs_max_pending is normally 50, but
651 can be set at module install time to as little as two */
652 if(atomic_read(&server->inFlight) >= cifs_max_pending)
653 atomic_set(&server->inFlight, cifs_max_pending - 1);
654 /* We do not want to set the max_pending too low or we
655 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 spin_unlock(&GlobalMid_Lock);
657 /* Although there should not be any requests blocked on
658 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700659 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 to the same server - they now will see the session is in exit state
661 and get out of SendReceive. */
662 wake_up_all(&server->request_q);
663 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700664 msleep(125);
665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 if(server->ssocket) {
667 sock_release(csocket);
668 server->ssocket = NULL;
669 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700670 /* buffer usuallly freed in free_mid - need to free it here on exit */
671 if (bigbuf != NULL)
672 cifs_buf_release(bigbuf);
673 if (smallbuf != NULL)
674 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
676 read_lock(&GlobalSMBSeslock);
677 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700678 /* loop through server session structures attached to this and
679 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 list_for_each(tmp, &GlobalSMBSessionList) {
681 ses =
682 list_entry(tmp, struct cifsSesInfo,
683 cifsSessionList);
684 if (ses->server == server) {
685 ses->status = CifsExiting;
686 ses->server = NULL;
687 }
688 }
689 read_unlock(&GlobalSMBSeslock);
690 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700691 /* although we can not zero the server struct pointer yet,
692 since there are active requests which may depnd on them,
693 mark the corresponding SMB sessions as exiting too */
694 list_for_each(tmp, &GlobalSMBSessionList) {
695 ses = list_entry(tmp, struct cifsSesInfo,
696 cifsSessionList);
697 if (ses->server == server) {
698 ses->status = CifsExiting;
699 }
700 }
701
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 spin_lock(&GlobalMid_Lock);
703 list_for_each(tmp, &server->pending_mid_q) {
704 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
705 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
706 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700707 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 task_to_wake = mid_entry->tsk;
709 if(task_to_wake) {
710 wake_up_process(task_to_wake);
711 }
712 }
713 }
714 spin_unlock(&GlobalMid_Lock);
715 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700717 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 }
719
Steve Frenchf1914012005-08-18 09:37:34 -0700720 if (!list_empty(&server->pending_mid_q)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 /* mpx threads have not exited yet give them
722 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700723 /* due to delays on oplock break requests, we need
724 to wait at least 45 seconds before giving up
725 on a request getting a response and going ahead
726 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700728 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 /* if threads still have not exited they are probably never
730 coming home not much else we can do but free the memory */
731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
733 write_lock(&GlobalSMBSeslock);
734 atomic_dec(&tcpSesAllocCount);
735 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700736
737 /* last chance to mark ses pointers invalid
738 if there are any pointing to this (e.g
739 if a crazy root user tried to kill cifsd
740 kernel thread explicitly this might happen) */
741 list_for_each(tmp, &GlobalSMBSessionList) {
742 ses = list_entry(tmp, struct cifsSesInfo,
743 cifsSessionList);
744 if (ses->server == server) {
745 ses->server = NULL;
746 }
747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700749
750 kfree(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if(length > 0) {
752 mempool_resize(cifs_req_poolp,
753 length + cifs_min_rcv,
754 GFP_KERNEL);
755 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700756
Steve Frenchf1914012005-08-18 09:37:34 -0700757 complete_and_exit(&cifsd_complete, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 return 0;
759}
760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761static int
762cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
763{
764 char *value;
765 char *data;
766 unsigned int temp_len, i, j;
767 char separator[2];
768
769 separator[0] = ',';
770 separator[1] = 0;
771
772 memset(vol->source_rfc1001_name,0x20,15);
773 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
774 /* does not have to be a perfect mapping since the field is
775 informational, only used for servers that do not support
776 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700777 vol->source_rfc1001_name[i] =
778 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
780 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700781 /* null target name indicates to use *SMBSERVR default called name
782 if we end up sending RFC1001 session initialize */
783 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 vol->linux_uid = current->uid; /* current->euid instead? */
785 vol->linux_gid = current->gid;
786 vol->dir_mode = S_IRWXUGO;
787 /* 2767 perms indicate mandatory locking support */
788 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
789
790 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
791 vol->rw = TRUE;
Steve Frenchbf820672005-12-01 22:32:42 -0800792 vol->ntlm = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700793 /* default is always to request posix paths. */
794 vol->posix_paths = 1;
795
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 if (!options)
797 return 1;
798
799 if(strncmp(options,"sep=",4) == 0) {
800 if(options[4] != 0) {
801 separator[0] = options[4];
802 options += 5;
803 } else {
804 cFYI(1,("Null separator not allowed"));
805 }
806 }
807
808 while ((data = strsep(&options, separator)) != NULL) {
809 if (!*data)
810 continue;
811 if ((value = strchr(data, '=')) != NULL)
812 *value++ = '\0';
813
814 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
815 vol->no_xattr = 0;
816 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
817 vol->no_xattr = 1;
818 } else if (strnicmp(data, "user", 4) == 0) {
819 if (!value || !*value) {
820 printk(KERN_WARNING
821 "CIFS: invalid or missing username\n");
822 return 1; /* needs_arg; */
823 }
824 if (strnlen(value, 200) < 200) {
825 vol->username = value;
826 } else {
827 printk(KERN_WARNING "CIFS: username too long\n");
828 return 1;
829 }
830 } else if (strnicmp(data, "pass", 4) == 0) {
831 if (!value) {
832 vol->password = NULL;
833 continue;
834 } else if(value[0] == 0) {
835 /* check if string begins with double comma
836 since that would mean the password really
837 does start with a comma, and would not
838 indicate an empty string */
839 if(value[1] != separator[0]) {
840 vol->password = NULL;
841 continue;
842 }
843 }
844 temp_len = strlen(value);
845 /* removed password length check, NTLM passwords
846 can be arbitrarily long */
847
848 /* if comma in password, the string will be
849 prematurely null terminated. Commas in password are
850 specified across the cifs mount interface by a double
851 comma ie ,, and a comma used as in other cases ie ','
852 as a parameter delimiter/separator is single and due
853 to the strsep above is temporarily zeroed. */
854
855 /* NB: password legally can have multiple commas and
856 the only illegal character in a password is null */
857
Steve French09d1db52005-04-28 22:41:08 -0700858 if ((value[temp_len] == 0) &&
859 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 /* reinsert comma */
861 value[temp_len] = separator[0];
862 temp_len+=2; /* move after the second comma */
863 while(value[temp_len] != 0) {
864 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700865 if (value[temp_len+1] ==
866 separator[0]) {
867 /* skip second comma */
868 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 } else {
870 /* single comma indicating start
871 of next parm */
872 break;
873 }
874 }
875 temp_len++;
876 }
877 if(value[temp_len] == 0) {
878 options = NULL;
879 } else {
880 value[temp_len] = 0;
881 /* point option to start of next parm */
882 options = value + temp_len + 1;
883 }
884 /* go from value to value + temp_len condensing
885 double commas to singles. Note that this ends up
886 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700887 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700888 if(vol->password == NULL) {
889 printk("CIFS: no memory for pass\n");
890 return 1;
891 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 for(i=0,j=0;i<temp_len;i++,j++) {
893 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700894 if(value[i] == separator[0]
895 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 /* skip second comma */
897 i++;
898 }
899 }
900 vol->password[j] = 0;
901 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700902 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700903 if(vol->password == NULL) {
904 printk("CIFS: no memory for pass\n");
905 return 1;
906 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 strcpy(vol->password, value);
908 }
909 } else if (strnicmp(data, "ip", 2) == 0) {
910 if (!value || !*value) {
911 vol->UNCip = NULL;
912 } else if (strnlen(value, 35) < 35) {
913 vol->UNCip = value;
914 } else {
915 printk(KERN_WARNING "CIFS: ip address too long\n");
916 return 1;
917 }
Steve Frenchbf820672005-12-01 22:32:42 -0800918 } else if (strnicmp(data, "sec", 3) == 0) {
919 if (!value || !*value) {
920 cERROR(1,("no security value specified"));
921 continue;
922 } else if (strnicmp(value, "krb5i", 5) == 0) {
923 vol->sign = 1;
924 vol->krb5 = 1;
925 } else if (strnicmp(value, "krb5p", 5) == 0) {
926 /* vol->seal = 1;
927 vol->krb5 = 1; */
928 cERROR(1,("Krb5 cifs privacy not supported"));
929 return 1;
930 } else if (strnicmp(value, "krb5", 4) == 0) {
931 vol->krb5 = 1;
932 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
933 vol->ntlmv2 = 1;
934 vol->sign = 1;
935 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
936 vol->ntlmv2 = 1;
937 } else if (strnicmp(value, "ntlmi", 5) == 0) {
938 vol->ntlm = 1;
939 vol->sign = 1;
940 } else if (strnicmp(value, "ntlm", 4) == 0) {
941 /* ntlm is default so can be turned off too */
942 vol->ntlm = 1;
943 } else if (strnicmp(value, "nontlm", 6) == 0) {
944 vol->ntlm = 0;
945 } else if (strnicmp(value, "none", 4) == 0) {
946 vol->nullauth = 1;
947 } else {
948 cERROR(1,("bad security option: %s", value));
949 return 1;
950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 } else if ((strnicmp(data, "unc", 3) == 0)
952 || (strnicmp(data, "target", 6) == 0)
953 || (strnicmp(data, "path", 4) == 0)) {
954 if (!value || !*value) {
955 printk(KERN_WARNING
956 "CIFS: invalid path to network resource\n");
957 return 1; /* needs_arg; */
958 }
959 if ((temp_len = strnlen(value, 300)) < 300) {
960 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
961 if(vol->UNC == NULL)
962 return 1;
963 strcpy(vol->UNC,value);
964 if (strncmp(vol->UNC, "//", 2) == 0) {
965 vol->UNC[0] = '\\';
966 vol->UNC[1] = '\\';
967 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
968 printk(KERN_WARNING
969 "CIFS: UNC Path does not begin with // or \\\\ \n");
970 return 1;
971 }
972 } else {
973 printk(KERN_WARNING "CIFS: UNC name too long\n");
974 return 1;
975 }
976 } else if ((strnicmp(data, "domain", 3) == 0)
977 || (strnicmp(data, "workgroup", 5) == 0)) {
978 if (!value || !*value) {
979 printk(KERN_WARNING "CIFS: invalid domain name\n");
980 return 1; /* needs_arg; */
981 }
982 /* BB are there cases in which a comma can be valid in
983 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +0000984 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 vol->domainname = value;
986 cFYI(1, ("Domain name set"));
987 } else {
988 printk(KERN_WARNING "CIFS: domain name too long\n");
989 return 1;
990 }
991 } else if (strnicmp(data, "iocharset", 9) == 0) {
992 if (!value || !*value) {
993 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
994 return 1; /* needs_arg; */
995 }
996 if (strnlen(value, 65) < 65) {
997 if(strnicmp(value,"default",7))
998 vol->iocharset = value;
999 /* if iocharset not set load_nls_default used by caller */
1000 cFYI(1, ("iocharset set to %s",value));
1001 } else {
1002 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
1003 return 1;
1004 }
1005 } else if (strnicmp(data, "uid", 3) == 0) {
1006 if (value && *value) {
1007 vol->linux_uid =
1008 simple_strtoul(value, &value, 0);
1009 }
1010 } else if (strnicmp(data, "gid", 3) == 0) {
1011 if (value && *value) {
1012 vol->linux_gid =
1013 simple_strtoul(value, &value, 0);
1014 }
1015 } else if (strnicmp(data, "file_mode", 4) == 0) {
1016 if (value && *value) {
1017 vol->file_mode =
1018 simple_strtoul(value, &value, 0);
1019 }
1020 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1021 if (value && *value) {
1022 vol->dir_mode =
1023 simple_strtoul(value, &value, 0);
1024 }
1025 } else if (strnicmp(data, "dirmode", 4) == 0) {
1026 if (value && *value) {
1027 vol->dir_mode =
1028 simple_strtoul(value, &value, 0);
1029 }
1030 } else if (strnicmp(data, "port", 4) == 0) {
1031 if (value && *value) {
1032 vol->port =
1033 simple_strtoul(value, &value, 0);
1034 }
1035 } else if (strnicmp(data, "rsize", 5) == 0) {
1036 if (value && *value) {
1037 vol->rsize =
1038 simple_strtoul(value, &value, 0);
1039 }
1040 } else if (strnicmp(data, "wsize", 5) == 0) {
1041 if (value && *value) {
1042 vol->wsize =
1043 simple_strtoul(value, &value, 0);
1044 }
1045 } else if (strnicmp(data, "sockopt", 5) == 0) {
1046 if (value && *value) {
1047 vol->sockopt =
1048 simple_strtoul(value, &value, 0);
1049 }
1050 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1051 if (!value || !*value || (*value == ' ')) {
1052 cFYI(1,("invalid (empty) netbiosname specified"));
1053 } else {
1054 memset(vol->source_rfc1001_name,0x20,15);
1055 for(i=0;i<15;i++) {
1056 /* BB are there cases in which a comma can be
1057 valid in this workstation netbios name (and need
1058 special handling)? */
1059
1060 /* We do not uppercase netbiosname for user */
1061 if (value[i]==0)
1062 break;
1063 else
1064 vol->source_rfc1001_name[i] = value[i];
1065 }
1066 /* The string has 16th byte zero still from
1067 set at top of the function */
1068 if((i==15) && (value[i] != 0))
Steve Frencha10faeb22005-08-22 21:38:31 -07001069 printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
1070 }
1071 } else if (strnicmp(data, "servern", 7) == 0) {
1072 /* servernetbiosname specified override *SMBSERVER */
1073 if (!value || !*value || (*value == ' ')) {
1074 cFYI(1,("empty server netbiosname specified"));
1075 } else {
1076 /* last byte, type, is 0x20 for servr type */
1077 memset(vol->target_rfc1001_name,0x20,16);
1078
1079 for(i=0;i<15;i++) {
1080 /* BB are there cases in which a comma can be
1081 valid in this workstation netbios name (and need
1082 special handling)? */
1083
1084 /* user or mount helper must uppercase netbiosname */
1085 if (value[i]==0)
1086 break;
1087 else
1088 vol->target_rfc1001_name[i] = value[i];
1089 }
1090 /* The string has 16th byte zero still from
1091 set at top of the function */
1092 if((i==15) && (value[i] != 0))
1093 printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 }
1095 } else if (strnicmp(data, "credentials", 4) == 0) {
1096 /* ignore */
1097 } else if (strnicmp(data, "version", 3) == 0) {
1098 /* ignore */
1099 } else if (strnicmp(data, "guest",5) == 0) {
1100 /* ignore */
1101 } else if (strnicmp(data, "rw", 2) == 0) {
1102 vol->rw = TRUE;
1103 } else if ((strnicmp(data, "suid", 4) == 0) ||
1104 (strnicmp(data, "nosuid", 6) == 0) ||
1105 (strnicmp(data, "exec", 4) == 0) ||
1106 (strnicmp(data, "noexec", 6) == 0) ||
1107 (strnicmp(data, "nodev", 5) == 0) ||
1108 (strnicmp(data, "noauto", 6) == 0) ||
1109 (strnicmp(data, "dev", 3) == 0)) {
1110 /* The mount tool or mount.cifs helper (if present)
1111 uses these opts to set flags, and the flags are read
1112 by the kernel vfs layer before we get here (ie
1113 before read super) so there is no point trying to
1114 parse these options again and set anything and it
1115 is ok to just ignore them */
1116 continue;
1117 } else if (strnicmp(data, "ro", 2) == 0) {
1118 vol->rw = FALSE;
1119 } else if (strnicmp(data, "hard", 4) == 0) {
1120 vol->retry = 1;
1121 } else if (strnicmp(data, "soft", 4) == 0) {
1122 vol->retry = 0;
1123 } else if (strnicmp(data, "perm", 4) == 0) {
1124 vol->noperm = 0;
1125 } else if (strnicmp(data, "noperm", 6) == 0) {
1126 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001127 } else if (strnicmp(data, "mapchars", 8) == 0) {
1128 vol->remap = 1;
1129 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1130 vol->remap = 0;
Steve Frenchd7245c22005-07-14 18:25:12 -05001131 } else if (strnicmp(data, "sfu", 3) == 0) {
1132 vol->sfu_emul = 1;
1133 } else if (strnicmp(data, "nosfu", 5) == 0) {
1134 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001135 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1136 vol->posix_paths = 1;
1137 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1138 vol->posix_paths = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001139 } else if ((strnicmp(data, "nocase", 6) == 0) ||
1140 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001141 vol->nocase = 1;
1142 } else if (strnicmp(data, "brl", 3) == 0) {
1143 vol->nobrl = 0;
Steve Frenchcb8be642005-08-30 15:25:52 -07001144 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001145 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001146 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001147 /* turn off mandatory locking in mode
1148 if remote locking is turned off since the
1149 local vfs will do advisory */
1150 if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1151 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 } else if (strnicmp(data, "setuids", 7) == 0) {
1153 vol->setuids = 1;
1154 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1155 vol->setuids = 0;
1156 } else if (strnicmp(data, "nohard", 6) == 0) {
1157 vol->retry = 0;
1158 } else if (strnicmp(data, "nosoft", 6) == 0) {
1159 vol->retry = 1;
1160 } else if (strnicmp(data, "nointr", 6) == 0) {
1161 vol->intr = 0;
1162 } else if (strnicmp(data, "intr", 4) == 0) {
1163 vol->intr = 1;
1164 } else if (strnicmp(data, "serverino",7) == 0) {
1165 vol->server_ino = 1;
1166 } else if (strnicmp(data, "noserverino",9) == 0) {
1167 vol->server_ino = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08001168 } else if (strnicmp(data, "cifsacl",7) == 0) {
1169 vol->cifs_acl = 1;
1170 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1171 vol->cifs_acl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 } else if (strnicmp(data, "acl",3) == 0) {
1173 vol->no_psx_acl = 0;
1174 } else if (strnicmp(data, "noacl",5) == 0) {
1175 vol->no_psx_acl = 1;
1176 } else if (strnicmp(data, "direct",6) == 0) {
1177 vol->direct_io = 1;
1178 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1179 vol->direct_io = 1;
1180 } else if (strnicmp(data, "in6_addr",8) == 0) {
1181 if (!value || !*value) {
1182 vol->in6_addr = NULL;
1183 } else if (strnlen(value, 49) == 48) {
1184 vol->in6_addr = value;
1185 } else {
1186 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1187 return 1;
1188 }
1189 } else if (strnicmp(data, "noac", 4) == 0) {
1190 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1191 } else
1192 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1193 }
1194 if (vol->UNC == NULL) {
1195 if(devname == NULL) {
1196 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1197 return 1;
1198 }
1199 if ((temp_len = strnlen(devname, 300)) < 300) {
1200 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1201 if(vol->UNC == NULL)
1202 return 1;
1203 strcpy(vol->UNC,devname);
1204 if (strncmp(vol->UNC, "//", 2) == 0) {
1205 vol->UNC[0] = '\\';
1206 vol->UNC[1] = '\\';
1207 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1208 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1209 return 1;
1210 }
1211 } else {
1212 printk(KERN_WARNING "CIFS: UNC name too long\n");
1213 return 1;
1214 }
1215 }
1216 if(vol->UNCip == NULL)
1217 vol->UNCip = &vol->UNC[2];
1218
1219 return 0;
1220}
1221
1222static struct cifsSesInfo *
1223cifs_find_tcp_session(struct in_addr * target_ip_addr,
1224 struct in6_addr *target_ip6_addr,
1225 char *userName, struct TCP_Server_Info **psrvTcp)
1226{
1227 struct list_head *tmp;
1228 struct cifsSesInfo *ses;
1229 *psrvTcp = NULL;
1230 read_lock(&GlobalSMBSeslock);
1231
1232 list_for_each(tmp, &GlobalSMBSessionList) {
1233 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1234 if (ses->server) {
1235 if((target_ip_addr &&
1236 (ses->server->addr.sockAddr.sin_addr.s_addr
1237 == target_ip_addr->s_addr)) || (target_ip6_addr
1238 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1239 target_ip6_addr,sizeof(*target_ip6_addr)))){
1240 /* BB lock server and tcp session and increment use count here?? */
1241 *psrvTcp = ses->server; /* found a match on the TCP session */
1242 /* BB check if reconnection needed */
1243 if (strncmp
1244 (ses->userName, userName,
1245 MAX_USERNAME_SIZE) == 0){
1246 read_unlock(&GlobalSMBSeslock);
1247 return ses; /* found exact match on both tcp and SMB sessions */
1248 }
1249 }
1250 }
1251 /* else tcp and smb sessions need reconnection */
1252 }
1253 read_unlock(&GlobalSMBSeslock);
1254 return NULL;
1255}
1256
1257static struct cifsTconInfo *
1258find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1259{
1260 struct list_head *tmp;
1261 struct cifsTconInfo *tcon;
1262
1263 read_lock(&GlobalSMBSeslock);
1264 list_for_each(tmp, &GlobalTreeConnectionList) {
1265 cFYI(1, ("Next tcon - "));
1266 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1267 if (tcon->ses) {
1268 if (tcon->ses->server) {
1269 cFYI(1,
1270 (" old ip addr: %x == new ip %x ?",
1271 tcon->ses->server->addr.sockAddr.sin_addr.
1272 s_addr, new_target_ip_addr));
1273 if (tcon->ses->server->addr.sockAddr.sin_addr.
1274 s_addr == new_target_ip_addr) {
1275 /* BB lock tcon and server and tcp session and increment use count here? */
1276 /* found a match on the TCP session */
1277 /* BB check if reconnection needed */
1278 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1279 tcon->treeName, uncName));
1280 if (strncmp
1281 (tcon->treeName, uncName,
1282 MAX_TREE_SIZE) == 0) {
1283 cFYI(1,
1284 ("Matched UNC, old user: %s == new: %s ?",
1285 tcon->treeName, uncName));
1286 if (strncmp
1287 (tcon->ses->userName,
1288 userName,
1289 MAX_USERNAME_SIZE) == 0) {
1290 read_unlock(&GlobalSMBSeslock);
1291 return tcon;/* also matched user (smb session)*/
1292 }
1293 }
1294 }
1295 }
1296 }
1297 }
1298 read_unlock(&GlobalSMBSeslock);
1299 return NULL;
1300}
1301
1302int
1303connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001304 const char *old_path, const struct nls_table *nls_codepage,
1305 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306{
1307 unsigned char *referrals = NULL;
1308 unsigned int num_referrals;
1309 int rc = 0;
1310
1311 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001312 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313
1314 /* BB Add in code to: if valid refrl, if not ip address contact
1315 the helper that resolves tcp names, mount to it, try to
1316 tcon to it unmount it if fail */
1317
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001318 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
1320 return rc;
1321}
1322
1323int
1324get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1325 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001326 unsigned int *pnum_referrals,
1327 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328{
1329 char *temp_unc;
1330 int rc = 0;
1331
1332 *pnum_referrals = 0;
1333
1334 if (pSesInfo->ipc_tid == 0) {
1335 temp_unc = kmalloc(2 /* for slashes */ +
1336 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1337 + 1 + 4 /* slash IPC$ */ + 2,
1338 GFP_KERNEL);
1339 if (temp_unc == NULL)
1340 return -ENOMEM;
1341 temp_unc[0] = '\\';
1342 temp_unc[1] = '\\';
1343 strcpy(temp_unc + 2, pSesInfo->serverName);
1344 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1345 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1346 cFYI(1,
1347 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1348 kfree(temp_unc);
1349 }
1350 if (rc == 0)
1351 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001352 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
1354 return rc;
1355}
1356
1357/* See RFC1001 section 14 on representation of Netbios names */
1358static void rfc1002mangle(char * target,char * source, unsigned int length)
1359{
1360 unsigned int i,j;
1361
1362 for(i=0,j=0;i<(length);i++) {
1363 /* mask a nibble at a time and encode */
1364 target[j] = 'A' + (0x0F & (source[i] >> 4));
1365 target[j+1] = 'A' + (0x0F & source[i]);
1366 j+=2;
1367 }
1368
1369}
1370
1371
1372static int
1373ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001374 char * netbios_name, char * target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375{
1376 int rc = 0;
1377 int connected = 0;
1378 __be16 orig_port = 0;
1379
1380 if(*csocket == NULL) {
1381 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1382 if (rc < 0) {
1383 cERROR(1, ("Error %d creating socket",rc));
1384 *csocket = NULL;
1385 return rc;
1386 } else {
1387 /* BB other socket options to set KEEPALIVE, NODELAY? */
1388 cFYI(1,("Socket created"));
1389 (*csocket)->sk->sk_allocation = GFP_NOFS;
1390 }
1391 }
1392
1393 psin_server->sin_family = AF_INET;
1394 if(psin_server->sin_port) { /* user overrode default port */
1395 rc = (*csocket)->ops->connect(*csocket,
1396 (struct sockaddr *) psin_server,
1397 sizeof (struct sockaddr_in),0);
1398 if (rc >= 0)
1399 connected = 1;
1400 }
1401
1402 if(!connected) {
1403 /* save original port so we can retry user specified port
1404 later if fall back ports fail this time */
1405 orig_port = psin_server->sin_port;
1406
1407 /* do not retry on the same port we just failed on */
1408 if(psin_server->sin_port != htons(CIFS_PORT)) {
1409 psin_server->sin_port = htons(CIFS_PORT);
1410
1411 rc = (*csocket)->ops->connect(*csocket,
1412 (struct sockaddr *) psin_server,
1413 sizeof (struct sockaddr_in),0);
1414 if (rc >= 0)
1415 connected = 1;
1416 }
1417 }
1418 if (!connected) {
1419 psin_server->sin_port = htons(RFC1001_PORT);
1420 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1421 psin_server, sizeof (struct sockaddr_in),0);
1422 if (rc >= 0)
1423 connected = 1;
1424 }
1425
1426 /* give up here - unless we want to retry on different
1427 protocol families some day */
1428 if (!connected) {
1429 if(orig_port)
1430 psin_server->sin_port = orig_port;
1431 cFYI(1,("Error %d connecting to server via ipv4",rc));
1432 sock_release(*csocket);
1433 *csocket = NULL;
1434 return rc;
1435 }
1436 /* Eventually check for other socket options to change from
1437 the default. sock_setsockopt not used because it expects
1438 user space buffer */
Steve Frenchb387eae2005-10-10 14:21:15 -07001439 cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
1440 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001442 /* make the bufsizes depend on wsize/rsize and max requests */
1443 if((*csocket)->sk->sk_sndbuf < (200 * 1024))
1444 (*csocket)->sk->sk_sndbuf = 200 * 1024;
1445 if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
1446 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447
1448 /* send RFC1001 sessinit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1450 /* some servers require RFC1001 sessinit before sending
1451 negprot - BB check reconnection in case where second
1452 sessinit is sent but no second negprot */
1453 struct rfc1002_session_packet * ses_init_buf;
1454 struct smb_hdr * smb_buf;
Pekka Enberge915fc42005-09-06 15:18:35 -07001455 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 if(ses_init_buf) {
1457 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frencha10faeb22005-08-22 21:38:31 -07001458 if(target_name && (target_name[0] != 0)) {
1459 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1460 target_name, 16);
1461 } else {
1462 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1463 DEFAULT_CIFS_CALLED_NAME,16);
1464 }
1465
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 ses_init_buf->trailer.session_req.calling_len = 32;
1467 /* calling name ends in null (byte 16) from old smb
1468 convention. */
1469 if(netbios_name && (netbios_name[0] !=0)) {
1470 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1471 netbios_name,16);
1472 } else {
1473 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1474 "LINUX_CIFS_CLNT",16);
1475 }
1476 ses_init_buf->trailer.session_req.scope1 = 0;
1477 ses_init_buf->trailer.session_req.scope2 = 0;
1478 smb_buf = (struct smb_hdr *)ses_init_buf;
1479 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1480 smb_buf->smb_buf_length = 0x81000044;
1481 rc = smb_send(*csocket, smb_buf, 0x44,
1482 (struct sockaddr *)psin_server);
1483 kfree(ses_init_buf);
Steve French083d3a22006-03-03 09:53:36 +00001484 msleep(1); /* RFC1001 layer in at least one server
1485 requires very short break before negprot
1486 presumably because not expecting negprot
1487 to follow so fast. This is a simple
1488 solution that works without
1489 complicating the code and causes no
1490 significant slowing down on mount
1491 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 }
1493 /* else the negprot may still work without this
1494 even though malloc failed */
1495
1496 }
1497
1498 return rc;
1499}
1500
1501static int
1502ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1503{
1504 int rc = 0;
1505 int connected = 0;
1506 __be16 orig_port = 0;
1507
1508 if(*csocket == NULL) {
1509 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1510 if (rc < 0) {
1511 cERROR(1, ("Error %d creating ipv6 socket",rc));
1512 *csocket = NULL;
1513 return rc;
1514 } else {
1515 /* BB other socket options to set KEEPALIVE, NODELAY? */
1516 cFYI(1,("ipv6 Socket created"));
1517 (*csocket)->sk->sk_allocation = GFP_NOFS;
1518 }
1519 }
1520
1521 psin_server->sin6_family = AF_INET6;
1522
1523 if(psin_server->sin6_port) { /* user overrode default port */
1524 rc = (*csocket)->ops->connect(*csocket,
1525 (struct sockaddr *) psin_server,
1526 sizeof (struct sockaddr_in6),0);
1527 if (rc >= 0)
1528 connected = 1;
1529 }
1530
1531 if(!connected) {
1532 /* save original port so we can retry user specified port
1533 later if fall back ports fail this time */
1534
1535 orig_port = psin_server->sin6_port;
1536 /* do not retry on the same port we just failed on */
1537 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1538 psin_server->sin6_port = htons(CIFS_PORT);
1539
1540 rc = (*csocket)->ops->connect(*csocket,
1541 (struct sockaddr *) psin_server,
1542 sizeof (struct sockaddr_in6),0);
1543 if (rc >= 0)
1544 connected = 1;
1545 }
1546 }
1547 if (!connected) {
1548 psin_server->sin6_port = htons(RFC1001_PORT);
1549 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1550 psin_server, sizeof (struct sockaddr_in6),0);
1551 if (rc >= 0)
1552 connected = 1;
1553 }
1554
1555 /* give up here - unless we want to retry on different
1556 protocol families some day */
1557 if (!connected) {
1558 if(orig_port)
1559 psin_server->sin6_port = orig_port;
1560 cFYI(1,("Error %d connecting to server via ipv6",rc));
1561 sock_release(*csocket);
1562 *csocket = NULL;
1563 return rc;
1564 }
1565 /* Eventually check for other socket options to change from
1566 the default. sock_setsockopt not used because it expects
1567 user space buffer */
1568 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1569
1570 return rc;
1571}
1572
1573int
1574cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1575 char *mount_data, const char *devname)
1576{
1577 int rc = 0;
1578 int xid;
1579 int address_type = AF_INET;
1580 struct socket *csocket = NULL;
1581 struct sockaddr_in sin_server;
1582 struct sockaddr_in6 sin_server6;
1583 struct smb_vol volume_info;
1584 struct cifsSesInfo *pSesInfo = NULL;
1585 struct cifsSesInfo *existingCifsSes = NULL;
1586 struct cifsTconInfo *tcon = NULL;
1587 struct TCP_Server_Info *srvTcp = NULL;
1588
1589 xid = GetXid();
1590
1591/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1592
1593 memset(&volume_info,0,sizeof(struct smb_vol));
1594 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001595 kfree(volume_info.UNC);
1596 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 FreeXid(xid);
1598 return -EINVAL;
1599 }
1600
1601 if (volume_info.username) {
1602 /* BB fixme parse for domain name here */
1603 cFYI(1, ("Username: %s ", volume_info.username));
1604
1605 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001606 cifserror("No username specified");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 /* In userspace mount helper we can get user name from alternate
1608 locations such as env variables and files on disk */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001609 kfree(volume_info.UNC);
1610 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 FreeXid(xid);
1612 return -EINVAL;
1613 }
1614
1615 if (volume_info.UNCip && volume_info.UNC) {
1616 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1617
1618 if(rc <= 0) {
1619 /* not ipv4 address, try ipv6 */
1620 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1621 if(rc > 0)
1622 address_type = AF_INET6;
1623 } else {
1624 address_type = AF_INET;
1625 }
1626
1627 if(rc <= 0) {
1628 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001629 kfree(volume_info.UNC);
1630 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 FreeXid(xid);
1632 return -EINVAL;
1633 }
1634
1635 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1636 /* success */
1637 rc = 0;
1638 } else if (volume_info.UNCip){
1639 /* BB using ip addr as server name connect to the DFS root below */
1640 cERROR(1,("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001641 kfree(volume_info.UNC);
1642 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 FreeXid(xid);
1644 return -EINVAL;
1645 } else /* which servers DFS root would we conect to */ {
1646 cERROR(1,
Steve Frenchbf820672005-12-01 22:32:42 -08001647 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001648 kfree(volume_info.UNC);
1649 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 FreeXid(xid);
1651 return -EINVAL;
1652 }
1653
1654 /* this is needed for ASCII cp to Unicode converts */
1655 if(volume_info.iocharset == NULL) {
1656 cifs_sb->local_nls = load_nls_default();
1657 /* load_nls_default can not return null */
1658 } else {
1659 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1660 if(cifs_sb->local_nls == NULL) {
1661 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001662 kfree(volume_info.UNC);
1663 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 FreeXid(xid);
1665 return -ELIBACC;
1666 }
1667 }
1668
1669 if(address_type == AF_INET)
1670 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1671 NULL /* no ipv6 addr */,
1672 volume_info.username, &srvTcp);
1673 else if(address_type == AF_INET6)
1674 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1675 &sin_server6.sin6_addr,
1676 volume_info.username, &srvTcp);
1677 else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001678 kfree(volume_info.UNC);
1679 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 FreeXid(xid);
1681 return -EINVAL;
1682 }
1683
1684
1685 if (srvTcp) {
Steve Frenchbf820672005-12-01 22:32:42 -08001686 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 } else { /* create socket */
1688 if(volume_info.port)
1689 sin_server.sin_port = htons(volume_info.port);
1690 else
1691 sin_server.sin_port = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001692 rc = ipv4_connect(&sin_server,&csocket,
1693 volume_info.source_rfc1001_name,
1694 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 if (rc < 0) {
1696 cERROR(1,
1697 ("Error connecting to IPv4 socket. Aborting operation"));
1698 if(csocket != NULL)
1699 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001700 kfree(volume_info.UNC);
1701 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 FreeXid(xid);
1703 return rc;
1704 }
1705
1706 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1707 if (srvTcp == NULL) {
1708 rc = -ENOMEM;
1709 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001710 kfree(volume_info.UNC);
1711 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 FreeXid(xid);
1713 return rc;
1714 } else {
1715 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1716 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1717 atomic_set(&srvTcp->inFlight,0);
1718 /* BB Add code for ipv6 case too */
1719 srvTcp->ssocket = csocket;
1720 srvTcp->protocolType = IPV4;
1721 init_waitqueue_head(&srvTcp->response_q);
1722 init_waitqueue_head(&srvTcp->request_q);
1723 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1724 /* at this point we are the only ones with the pointer
1725 to the struct since the kernel thread not created yet
1726 so no need to spinlock this init of tcpStatus */
1727 srvTcp->tcpStatus = CifsNew;
1728 init_MUTEX(&srvTcp->tcpSem);
1729 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1730 CLONE_FS | CLONE_FILES | CLONE_VM);
1731 if(rc < 0) {
1732 rc = -ENOMEM;
1733 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001734 kfree(volume_info.UNC);
1735 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 FreeXid(xid);
1737 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001738 }
1739 wait_for_completion(&cifsd_complete);
1740 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001742 memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001743 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 }
1745 }
1746
1747 if (existingCifsSes) {
1748 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001749 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001750 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 /* volume_info.UNC freed at end of function */
1752 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001753 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 pSesInfo = sesInfoAlloc();
1755 if (pSesInfo == NULL)
1756 rc = -ENOMEM;
1757 else {
1758 pSesInfo->server = srvTcp;
1759 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1760 NIPQUAD(sin_server.sin_addr.s_addr));
1761 }
1762
1763 if (!rc){
1764 /* volume_info.password freed at unmount */
1765 if (volume_info.password)
1766 pSesInfo->password = volume_info.password;
1767 if (volume_info.username)
1768 strncpy(pSesInfo->userName,
1769 volume_info.username,MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001770 if (volume_info.domainname) {
1771 int len = strlen(volume_info.domainname);
1772 pSesInfo->domainName =
1773 kmalloc(len + 1, GFP_KERNEL);
1774 if(pSesInfo->domainName)
1775 strcpy(pSesInfo->domainName,
1776 volume_info.domainname);
1777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 pSesInfo->linux_uid = volume_info.linux_uid;
1779 down(&pSesInfo->sesSem);
1780 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1781 up(&pSesInfo->sesSem);
1782 if(!rc)
1783 atomic_inc(&srvTcp->socketUseCount);
1784 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001785 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 }
1787
1788 /* search for existing tcon to this server share */
1789 if (!rc) {
Steve French0ae0efa2005-10-10 10:57:19 -07001790 if(volume_info.rsize > CIFSMaxBufSize) {
1791 cERROR(1,("rsize %d too large, using MaxBufSize",
1792 volume_info.rsize));
1793 cifs_sb->rsize = CIFSMaxBufSize;
1794 } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07001796 else /* default */
1797 cifs_sb->rsize = CIFSMaxBufSize;
1798
1799 if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
1800 cERROR(1,("wsize %d too large using 4096 instead",
1801 volume_info.wsize));
1802 cifs_sb->wsize = 4096;
1803 } else if(volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 cifs_sb->wsize = volume_info.wsize;
1805 else
Steve French17cbbaf2006-01-24 20:26:48 -08001806 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08001807 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
1808 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08001809 /* old default of CIFSMaxBufSize was too small now
1810 that SMB Write2 can send multiple pages in kvec.
1811 RFC1001 does not describe what happens when frame
1812 bigger than 128K is sent so use that as max in
1813 conjunction with 52K kvec constraint on arch with 4K
1814 page size */
1815
Steve French6cec2ae2006-02-22 17:31:52 -06001816 if(cifs_sb->rsize < 2048) {
1817 cifs_sb->rsize = 2048;
1818 /* Windows ME may prefer this */
1819 cFYI(1,("readsize set to minimum 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 }
1821 cifs_sb->mnt_uid = volume_info.linux_uid;
1822 cifs_sb->mnt_gid = volume_info.linux_gid;
1823 cifs_sb->mnt_file_mode = volume_info.file_mode;
1824 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve Frencheeac8042006-01-13 21:34:58 -08001825 cFYI(1,("file mode: 0x%x dir mode: 0x%x",
1826 cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
1828 if(volume_info.noperm)
1829 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1830 if(volume_info.setuids)
1831 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1832 if(volume_info.server_ino)
1833 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001834 if(volume_info.remap)
1835 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 if(volume_info.no_xattr)
1837 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve Frenchd7245c22005-07-14 18:25:12 -05001838 if(volume_info.sfu_emul)
1839 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001840 if(volume_info.nobrl)
1841 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French0a4b92c2006-01-12 15:44:21 -08001842 if(volume_info.cifs_acl)
1843 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Jeremy Allisonac670552005-06-22 17:26:35 -07001844
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 if(volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001846 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1848 }
1849
1850 tcon =
1851 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1852 volume_info.username);
1853 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08001854 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 /* we can have only one retry value for a connection
1856 to a share so for resources mounted more than once
1857 to the same server share the last value passed in
1858 for the retry flag is used */
1859 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001860 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 } else {
1862 tcon = tconInfoAlloc();
1863 if (tcon == NULL)
1864 rc = -ENOMEM;
1865 else {
1866 /* check for null share name ie connect to dfs root */
1867
1868 /* BB check if this works for exactly length three strings */
1869 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1870 && (strchr(volume_info.UNC + 3, '/') ==
1871 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001872 rc = connect_to_dfs_path(xid, pSesInfo,
1873 "", cifs_sb->local_nls,
1874 cifs_sb->mnt_cifs_flags &
1875 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001876 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 FreeXid(xid);
1878 return -ENODEV;
1879 } else {
1880 rc = CIFSTCon(xid, pSesInfo,
1881 volume_info.UNC,
1882 tcon, cifs_sb->local_nls);
1883 cFYI(1, ("CIFS Tcon rc = %d", rc));
1884 }
1885 if (!rc) {
1886 atomic_inc(&pSesInfo->inUse);
1887 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001888 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 }
1890 }
1891 }
1892 }
1893 if(pSesInfo) {
1894 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1895 sb->s_maxbytes = (u64) 1 << 63;
1896 } else
1897 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1898 }
1899
1900 sb->s_time_gran = 100;
1901
1902/* on error free sesinfo and tcon struct if needed */
1903 if (rc) {
1904 /* if session setup failed, use count is zero but
1905 we still need to free cifsd thread */
1906 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1907 spin_lock(&GlobalMid_Lock);
1908 srvTcp->tcpStatus = CifsExiting;
1909 spin_unlock(&GlobalMid_Lock);
Steve Frenchf1914012005-08-18 09:37:34 -07001910 if(srvTcp->tsk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 send_sig(SIGKILL,srvTcp->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001912 wait_for_completion(&cifsd_complete);
1913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 }
1915 /* If find_unc succeeded then rc == 0 so we can not end */
1916 if (tcon) /* up accidently freeing someone elses tcon struct */
1917 tconInfoFree(tcon);
1918 if (existingCifsSes == NULL) {
1919 if (pSesInfo) {
1920 if ((pSesInfo->server) &&
1921 (pSesInfo->status == CifsGood)) {
1922 int temp_rc;
1923 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1924 /* if the socketUseCount is now zero */
1925 if((temp_rc == -ESHUTDOWN) &&
Steve Frenchf1914012005-08-18 09:37:34 -07001926 (pSesInfo->server->tsk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 send_sig(SIGKILL,pSesInfo->server->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001928 wait_for_completion(&cifsd_complete);
1929 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 } else
1931 cFYI(1, ("No session or bad tcon"));
1932 sesInfoFree(pSesInfo);
1933 /* pSesInfo = NULL; */
1934 }
1935 }
1936 } else {
1937 atomic_inc(&tcon->useCount);
1938 cifs_sb->tcon = tcon;
1939 tcon->ses = pSesInfo;
1940
Steve French82940a42006-03-02 03:24:57 +00001941 /* do not care if following two calls succeed - informational */
Steve French737b7582005-04-28 22:41:06 -07001942 CIFSSMBQFSDeviceInfo(xid, tcon);
1943 CIFSSMBQFSAttributeInfo(xid, tcon);
Steve French82940a42006-03-02 03:24:57 +00001944
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001946 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French82940a42006-03-02 03:24:57 +00001947 __u64 cap =
1948 le64_to_cpu(tcon->fsUnixInfo.Capability);
1949 cap &= CIFS_UNIX_CAP_MASK;
1950 if(volume_info.no_psx_acl)
1951 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1952 else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
1953 cFYI(1,("negotiated posix acl support"));
1954 sb->s_flags |= MS_POSIXACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 }
Jeremy Allisonac670552005-06-22 17:26:35 -07001956
Steve French82940a42006-03-02 03:24:57 +00001957 if(volume_info.posix_paths == 0)
1958 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
1959 else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
1960 cFYI(1,("negotiate posix pathnames"));
1961 cifs_sb->mnt_cifs_flags |=
1962 CIFS_MOUNT_POSIX_PATHS;
1963 }
1964
1965 cFYI(1,("Negotiate caps 0x%x",(int)cap));
1966
1967 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
1968 cFYI(1,("setting capabilities failed"));
Jeremy Allisonac670552005-06-22 17:26:35 -07001969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 }
1971 }
Steve French3e844692005-10-03 13:37:24 -07001972 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
1973 cifs_sb->wsize = min(cifs_sb->wsize,
1974 (tcon->ses->server->maxBuf -
1975 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07001976 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
1977 cifs_sb->rsize = min(cifs_sb->rsize,
1978 (tcon->ses->server->maxBuf -
1979 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 }
1981
1982 /* volume_info.password is freed above when existing session found
1983 (in which case it is not needed anymore) but when new sesion is created
1984 the password ptr is put in the new session structure (in which case the
1985 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001986 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 FreeXid(xid);
1988 return rc;
1989}
1990
1991static int
1992CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00001993 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 const struct nls_table *nls_codepage)
1995{
1996 struct smb_hdr *smb_buffer;
1997 struct smb_hdr *smb_buffer_response;
1998 SESSION_SETUP_ANDX *pSMB;
1999 SESSION_SETUP_ANDX *pSMBr;
2000 char *bcc_ptr;
2001 char *user;
2002 char *domain;
2003 int rc = 0;
2004 int remaining_words = 0;
2005 int bytes_returned = 0;
2006 int len;
2007 __u32 capabilities;
2008 __u16 count;
2009
Steve Frencheeac8042006-01-13 21:34:58 -08002010 cFYI(1, ("In sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 if(ses == NULL)
2012 return -EINVAL;
2013 user = ses->userName;
2014 domain = ses->domainName;
2015 smb_buffer = cifs_buf_get();
2016 if (smb_buffer == NULL) {
2017 return -ENOMEM;
2018 }
2019 smb_buffer_response = smb_buffer;
2020 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2021
2022 /* send SMBsessionSetup here */
2023 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2024 NULL /* no tCon exists yet */ , 13 /* wct */ );
2025
Steve French1982c342005-08-17 12:38:22 -07002026 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 pSMB->req_no_secext.AndXCommand = 0xFF;
2028 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2029 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2030
2031 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2032 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2033
2034 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2035 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2036 if (ses->capabilities & CAP_UNICODE) {
2037 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2038 capabilities |= CAP_UNICODE;
2039 }
2040 if (ses->capabilities & CAP_STATUS32) {
2041 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2042 capabilities |= CAP_STATUS32;
2043 }
2044 if (ses->capabilities & CAP_DFS) {
2045 smb_buffer->Flags2 |= SMBFLG2_DFS;
2046 capabilities |= CAP_DFS;
2047 }
2048 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2049
2050 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002051 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052
2053 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002054 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002056 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2057 bcc_ptr += CIFS_SESS_KEY_SIZE;
2058 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2059 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060
2061 if (ses->capabilities & CAP_UNICODE) {
2062 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2063 *bcc_ptr = 0;
2064 bcc_ptr++;
2065 }
2066 if(user == NULL)
Steve French39798772006-05-31 22:40:51 +00002067 bytes_returned = 0; /* skip null user */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 else
2069 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002070 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 nls_codepage);
2072 /* convert number of 16 bit words to bytes */
2073 bcc_ptr += 2 * bytes_returned;
2074 bcc_ptr += 2; /* trailing null */
2075 if (domain == NULL)
2076 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002077 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 "CIFS_LINUX_DOM", 32, nls_codepage);
2079 else
2080 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002081 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 nls_codepage);
2083 bcc_ptr += 2 * bytes_returned;
2084 bcc_ptr += 2;
2085 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002086 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 32, nls_codepage);
2088 bcc_ptr += 2 * bytes_returned;
2089 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002090 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 32, nls_codepage);
2092 bcc_ptr += 2 * bytes_returned;
2093 bcc_ptr += 2;
2094 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002095 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 64, nls_codepage);
2097 bcc_ptr += 2 * bytes_returned;
2098 bcc_ptr += 2;
2099 } else {
2100 if(user != NULL) {
2101 strncpy(bcc_ptr, user, 200);
2102 bcc_ptr += strnlen(user, 200);
2103 }
2104 *bcc_ptr = 0;
2105 bcc_ptr++;
2106 if (domain == NULL) {
2107 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2108 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2109 } else {
2110 strncpy(bcc_ptr, domain, 64);
2111 bcc_ptr += strnlen(domain, 64);
2112 *bcc_ptr = 0;
2113 bcc_ptr++;
2114 }
2115 strcpy(bcc_ptr, "Linux version ");
2116 bcc_ptr += strlen("Linux version ");
2117 strcpy(bcc_ptr, system_utsname.release);
2118 bcc_ptr += strlen(system_utsname.release) + 1;
2119 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2120 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2121 }
2122 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2123 smb_buffer->smb_buf_length += count;
2124 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2125
2126 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2127 &bytes_returned, 1);
2128 if (rc) {
2129/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2130 } else if ((smb_buffer_response->WordCount == 3)
2131 || (smb_buffer_response->WordCount == 4)) {
2132 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2133 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2134 if (action & GUEST_LOGIN)
2135 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2136 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2137 cFYI(1, ("UID = %d ", ses->Suid));
2138 /* response can have either 3 or 4 word count - Samba sends 3 */
2139 bcc_ptr = pByteArea(smb_buffer_response);
2140 if ((pSMBr->resp.hdr.WordCount == 3)
2141 || ((pSMBr->resp.hdr.WordCount == 4)
2142 && (blob_len < pSMBr->resp.ByteCount))) {
2143 if (pSMBr->resp.hdr.WordCount == 4)
2144 bcc_ptr += blob_len;
2145
2146 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2147 if ((long) (bcc_ptr) % 2) {
2148 remaining_words =
2149 (BCC(smb_buffer_response) - 1) /2;
2150 bcc_ptr++; /* Unicode strings must be word aligned */
2151 } else {
2152 remaining_words =
2153 BCC(smb_buffer_response) / 2;
2154 }
2155 len =
2156 UniStrnlen((wchar_t *) bcc_ptr,
2157 remaining_words - 1);
2158/* We look for obvious messed up bcc or strings in response so we do not go off
2159 the end since (at least) WIN2K and Windows XP have a major bug in not null
2160 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002161 if(ses->serverOS)
2162 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002163 ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002164 if(ses->serverOS == NULL)
2165 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002167 (__le16 *)bcc_ptr, len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 bcc_ptr += 2 * (len + 1);
2169 remaining_words -= len + 1;
2170 ses->serverOS[2 * len] = 0;
2171 ses->serverOS[1 + (2 * len)] = 0;
2172 if (remaining_words > 0) {
2173 len = UniStrnlen((wchar_t *)bcc_ptr,
2174 remaining_words-1);
Steve Frencha424f8b2006-05-30 18:06:04 +00002175 if(ses->serverNOS)
2176 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002177 ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002178 if(ses->serverNOS == NULL)
2179 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 cifs_strfromUCS_le(ses->serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002181 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 bcc_ptr += 2 * (len + 1);
2183 ses->serverNOS[2 * len] = 0;
2184 ses->serverNOS[1 + (2 * len)] = 0;
2185 if(strncmp(ses->serverNOS,
2186 "NT LAN Manager 4",16) == 0) {
2187 cFYI(1,("NT4 server"));
2188 ses->flags |= CIFS_SES_NT4;
2189 }
2190 remaining_words -= len + 1;
2191 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002192 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00002194 if(ses->serverDomain)
2195 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002197 kzalloc(2*(len+1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002198 if(ses->serverDomain == NULL)
2199 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 cifs_strfromUCS_le(ses->serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002201 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 bcc_ptr += 2 * (len + 1);
2203 ses->serverDomain[2*len] = 0;
2204 ses->serverDomain[1+(2*len)] = 0;
2205 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002206 else {
2207 if(ses->serverDomain)
2208 kfree(ses->serverDomain);
Steve French433dc242005-04-28 22:41:08 -07002209 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002210 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002211 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002213 /* if these kcallocs fail not much we
2214 can do, but better to not fail the
2215 sesssetup itself */
Steve Frencha424f8b2006-05-30 18:06:04 +00002216 if(ses->serverDomain)
2217 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002219 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002220 if(ses->serverNOS)
2221 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002223 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 }
2225 } else { /* ASCII */
2226 len = strnlen(bcc_ptr, 1024);
2227 if (((long) bcc_ptr + len) - (long)
2228 pByteArea(smb_buffer_response)
2229 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00002230 if(ses->serverOS)
2231 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002232 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002233 if(ses->serverOS == NULL)
2234 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 strncpy(ses->serverOS,bcc_ptr, len);
2236
2237 bcc_ptr += len;
2238 bcc_ptr[0] = 0; /* null terminate the string */
2239 bcc_ptr++;
2240
2241 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002242 if(ses->serverNOS)
2243 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002244 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002245 if(ses->serverNOS == NULL)
2246 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 strncpy(ses->serverNOS, bcc_ptr, len);
2248 bcc_ptr += len;
2249 bcc_ptr[0] = 0;
2250 bcc_ptr++;
2251
2252 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002253 if(ses->serverDomain)
2254 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07002255 ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002256 if(ses->serverDomain == NULL)
2257 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 strncpy(ses->serverDomain, bcc_ptr, len);
2259 bcc_ptr += len;
2260 bcc_ptr[0] = 0;
2261 bcc_ptr++;
2262 } else
2263 cFYI(1,
2264 ("Variable field of length %d extends beyond end of smb ",
2265 len));
2266 }
2267 } else {
2268 cERROR(1,
2269 (" Security Blob Length extends beyond end of SMB"));
2270 }
2271 } else {
2272 cERROR(1,
2273 (" Invalid Word count %d: ",
2274 smb_buffer_response->WordCount));
2275 rc = -EIO;
2276 }
Steve French433dc242005-04-28 22:41:08 -07002277sesssetup_nomem: /* do not return an error on nomem for the info strings,
2278 since that could make reconnection harder, and
2279 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 if (smb_buffer)
2281 cifs_buf_release(smb_buffer);
2282
2283 return rc;
2284}
2285
2286static int
2287CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2288 char *SecurityBlob,int SecurityBlobLength,
2289 const struct nls_table *nls_codepage)
2290{
2291 struct smb_hdr *smb_buffer;
2292 struct smb_hdr *smb_buffer_response;
2293 SESSION_SETUP_ANDX *pSMB;
2294 SESSION_SETUP_ANDX *pSMBr;
2295 char *bcc_ptr;
2296 char *user;
2297 char *domain;
2298 int rc = 0;
2299 int remaining_words = 0;
2300 int bytes_returned = 0;
2301 int len;
2302 __u32 capabilities;
2303 __u16 count;
2304
2305 cFYI(1, ("In spnego sesssetup "));
2306 if(ses == NULL)
2307 return -EINVAL;
2308 user = ses->userName;
2309 domain = ses->domainName;
2310
2311 smb_buffer = cifs_buf_get();
2312 if (smb_buffer == NULL) {
2313 return -ENOMEM;
2314 }
2315 smb_buffer_response = smb_buffer;
2316 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2317
2318 /* send SMBsessionSetup here */
2319 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2320 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002321
2322 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2324 pSMB->req.AndXCommand = 0xFF;
Steve French184ed212006-02-24 06:15:11 +00002325 if(ses->server->maxBuf > 64*1024)
2326 ses->server->maxBuf = (64*1023);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2328 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2329
2330 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2331 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2332
2333 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2334 CAP_EXTENDED_SECURITY;
2335 if (ses->capabilities & CAP_UNICODE) {
2336 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2337 capabilities |= CAP_UNICODE;
2338 }
2339 if (ses->capabilities & CAP_STATUS32) {
2340 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2341 capabilities |= CAP_STATUS32;
2342 }
2343 if (ses->capabilities & CAP_DFS) {
2344 smb_buffer->Flags2 |= SMBFLG2_DFS;
2345 capabilities |= CAP_DFS;
2346 }
2347 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2348
2349 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2350 bcc_ptr = pByteArea(smb_buffer);
2351 memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
2352 bcc_ptr += SecurityBlobLength;
2353
2354 if (ses->capabilities & CAP_UNICODE) {
2355 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
2356 *bcc_ptr = 0;
2357 bcc_ptr++;
2358 }
2359 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002360 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
2362 bcc_ptr += 2; /* trailing null */
2363 if (domain == NULL)
2364 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002365 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 "CIFS_LINUX_DOM", 32, nls_codepage);
2367 else
2368 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002369 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 nls_codepage);
2371 bcc_ptr += 2 * bytes_returned;
2372 bcc_ptr += 2;
2373 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002374 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 32, nls_codepage);
2376 bcc_ptr += 2 * bytes_returned;
2377 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002378 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 nls_codepage);
2380 bcc_ptr += 2 * bytes_returned;
2381 bcc_ptr += 2;
2382 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002383 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 64, nls_codepage);
2385 bcc_ptr += 2 * bytes_returned;
2386 bcc_ptr += 2;
2387 } else {
2388 strncpy(bcc_ptr, user, 200);
2389 bcc_ptr += strnlen(user, 200);
2390 *bcc_ptr = 0;
2391 bcc_ptr++;
2392 if (domain == NULL) {
2393 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2394 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2395 } else {
2396 strncpy(bcc_ptr, domain, 64);
2397 bcc_ptr += strnlen(domain, 64);
2398 *bcc_ptr = 0;
2399 bcc_ptr++;
2400 }
2401 strcpy(bcc_ptr, "Linux version ");
2402 bcc_ptr += strlen("Linux version ");
2403 strcpy(bcc_ptr, system_utsname.release);
2404 bcc_ptr += strlen(system_utsname.release) + 1;
2405 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2406 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2407 }
2408 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2409 smb_buffer->smb_buf_length += count;
2410 pSMB->req.ByteCount = cpu_to_le16(count);
2411
2412 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2413 &bytes_returned, 1);
2414 if (rc) {
2415/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2416 } else if ((smb_buffer_response->WordCount == 3)
2417 || (smb_buffer_response->WordCount == 4)) {
2418 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2419 __u16 blob_len =
2420 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2421 if (action & GUEST_LOGIN)
2422 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2423 if (ses) {
2424 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2425 cFYI(1, ("UID = %d ", ses->Suid));
2426 bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
2427
2428 /* BB Fix below to make endian neutral !! */
2429
2430 if ((pSMBr->resp.hdr.WordCount == 3)
2431 || ((pSMBr->resp.hdr.WordCount == 4)
2432 && (blob_len <
2433 pSMBr->resp.ByteCount))) {
2434 if (pSMBr->resp.hdr.WordCount == 4) {
2435 bcc_ptr +=
2436 blob_len;
2437 cFYI(1,
2438 ("Security Blob Length %d ",
2439 blob_len));
2440 }
2441
2442 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2443 if ((long) (bcc_ptr) % 2) {
2444 remaining_words =
2445 (BCC(smb_buffer_response)
2446 - 1) / 2;
2447 bcc_ptr++; /* Unicode strings must be word aligned */
2448 } else {
2449 remaining_words =
2450 BCC
2451 (smb_buffer_response) / 2;
2452 }
2453 len =
2454 UniStrnlen((wchar_t *) bcc_ptr,
2455 remaining_words - 1);
2456/* We look for obvious messed up bcc or strings in response so we do not go off
2457 the end since (at least) WIN2K and Windows XP have a major bug in not null
2458 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002459 if(ses->serverOS)
2460 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002462 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002464 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 bcc_ptr, len,
2466 nls_codepage);
2467 bcc_ptr += 2 * (len + 1);
2468 remaining_words -= len + 1;
2469 ses->serverOS[2 * len] = 0;
2470 ses->serverOS[1 + (2 * len)] = 0;
2471 if (remaining_words > 0) {
2472 len = UniStrnlen((wchar_t *)bcc_ptr,
2473 remaining_words
2474 - 1);
Steve Frencha424f8b2006-05-30 18:06:04 +00002475 if(ses->serverNOS)
2476 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002478 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 GFP_KERNEL);
2480 cifs_strfromUCS_le(ses->serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002481 (__le16 *)bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 len,
2483 nls_codepage);
2484 bcc_ptr += 2 * (len + 1);
2485 ses->serverNOS[2 * len] = 0;
2486 ses->serverNOS[1 + (2 * len)] = 0;
2487 remaining_words -= len + 1;
2488 if (remaining_words > 0) {
2489 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve Frencha424f8b2006-05-30 18:06:04 +00002490 /* last string not null terminated (e.g.Windows XP/2000) */
2491 if(ses->serverDomain)
2492 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07002493 ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 cifs_strfromUCS_le(ses->serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002495 (__le16 *)bcc_ptr,
2496 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 bcc_ptr += 2*(len+1);
2498 ses->serverDomain[2*len] = 0;
2499 ses->serverDomain[1+(2*len)] = 0;
2500 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002501 else {
2502 if(ses->serverDomain)
Steve French08775832006-05-30 18:08:26 +00002503 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002505 kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002506 }
2507 } else {/* no room use dummy domain&NOS */
2508 if(ses->serverDomain)
2509 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07002510 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002511 if(ses->serverNOS)
2512 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002513 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 }
2515 } else { /* ASCII */
2516
2517 len = strnlen(bcc_ptr, 1024);
2518 if (((long) bcc_ptr + len) - (long)
2519 pByteArea(smb_buffer_response)
2520 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00002521 if(ses->serverOS)
2522 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002523 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 strncpy(ses->serverOS, bcc_ptr, len);
2525
2526 bcc_ptr += len;
2527 bcc_ptr[0] = 0; /* null terminate the string */
2528 bcc_ptr++;
2529
2530 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002531 if(ses->serverNOS)
2532 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002533 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 strncpy(ses->serverNOS, bcc_ptr, len);
2535 bcc_ptr += len;
2536 bcc_ptr[0] = 0;
2537 bcc_ptr++;
2538
2539 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002540 if(ses->serverDomain)
Steve French08775832006-05-30 18:08:26 +00002541 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07002542 ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 strncpy(ses->serverDomain, bcc_ptr, len);
2544 bcc_ptr += len;
2545 bcc_ptr[0] = 0;
2546 bcc_ptr++;
2547 } else
2548 cFYI(1,
2549 ("Variable field of length %d extends beyond end of smb ",
2550 len));
2551 }
2552 } else {
2553 cERROR(1,
2554 (" Security Blob Length extends beyond end of SMB"));
2555 }
2556 } else {
2557 cERROR(1, ("No session structure passed in."));
2558 }
2559 } else {
2560 cERROR(1,
2561 (" Invalid Word count %d: ",
2562 smb_buffer_response->WordCount));
2563 rc = -EIO;
2564 }
2565
2566 if (smb_buffer)
2567 cifs_buf_release(smb_buffer);
2568
2569 return rc;
2570}
2571
2572static int
2573CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2574 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2575 const struct nls_table *nls_codepage)
2576{
2577 struct smb_hdr *smb_buffer;
2578 struct smb_hdr *smb_buffer_response;
2579 SESSION_SETUP_ANDX *pSMB;
2580 SESSION_SETUP_ANDX *pSMBr;
2581 char *bcc_ptr;
2582 char *domain;
2583 int rc = 0;
2584 int remaining_words = 0;
2585 int bytes_returned = 0;
2586 int len;
2587 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2588 PNEGOTIATE_MESSAGE SecurityBlob;
2589 PCHALLENGE_MESSAGE SecurityBlob2;
2590 __u32 negotiate_flags, capabilities;
2591 __u16 count;
2592
Steve French12b3b8f2006-02-09 21:12:47 +00002593 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 if(ses == NULL)
2595 return -EINVAL;
2596 domain = ses->domainName;
2597 *pNTLMv2_flag = FALSE;
2598 smb_buffer = cifs_buf_get();
2599 if (smb_buffer == NULL) {
2600 return -ENOMEM;
2601 }
2602 smb_buffer_response = smb_buffer;
2603 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2604 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2605
2606 /* send SMBsessionSetup here */
2607 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2608 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002609
2610 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2612 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2613
2614 pSMB->req.AndXCommand = 0xFF;
2615 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2616 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2617
2618 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2619 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2620
2621 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2622 CAP_EXTENDED_SECURITY;
2623 if (ses->capabilities & CAP_UNICODE) {
2624 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2625 capabilities |= CAP_UNICODE;
2626 }
2627 if (ses->capabilities & CAP_STATUS32) {
2628 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2629 capabilities |= CAP_STATUS32;
2630 }
2631 if (ses->capabilities & CAP_DFS) {
2632 smb_buffer->Flags2 |= SMBFLG2_DFS;
2633 capabilities |= CAP_DFS;
2634 }
2635 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2636
2637 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2638 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2639 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2640 SecurityBlob->MessageType = NtLmNegotiate;
2641 negotiate_flags =
2642 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002643 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2644 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2646 if(sign_CIFS_PDUs)
2647 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve French39798772006-05-31 22:40:51 +00002648/* if(ntlmv2_support)
2649 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 /* setup pointers to domain name and workstation name */
2651 bcc_ptr += SecurityBlobLength;
2652
2653 SecurityBlob->WorkstationName.Buffer = 0;
2654 SecurityBlob->WorkstationName.Length = 0;
2655 SecurityBlob->WorkstationName.MaximumLength = 0;
2656
Steve French12b3b8f2006-02-09 21:12:47 +00002657 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2658 along with username on auth request (ie the response to challenge) */
2659 SecurityBlob->DomainName.Buffer = 0;
2660 SecurityBlob->DomainName.Length = 0;
2661 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 if (ses->capabilities & CAP_UNICODE) {
2663 if ((long) bcc_ptr % 2) {
2664 *bcc_ptr = 0;
2665 bcc_ptr++;
2666 }
2667
2668 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002669 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 32, nls_codepage);
2671 bcc_ptr += 2 * bytes_returned;
2672 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002673 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 nls_codepage);
2675 bcc_ptr += 2 * bytes_returned;
2676 bcc_ptr += 2; /* null terminate Linux version */
2677 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002678 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 64, nls_codepage);
2680 bcc_ptr += 2 * bytes_returned;
2681 *(bcc_ptr + 1) = 0;
2682 *(bcc_ptr + 2) = 0;
2683 bcc_ptr += 2; /* null terminate network opsys string */
2684 *(bcc_ptr + 1) = 0;
2685 *(bcc_ptr + 2) = 0;
2686 bcc_ptr += 2; /* null domain */
2687 } else { /* ASCII */
2688 strcpy(bcc_ptr, "Linux version ");
2689 bcc_ptr += strlen("Linux version ");
2690 strcpy(bcc_ptr, system_utsname.release);
2691 bcc_ptr += strlen(system_utsname.release) + 1;
2692 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2693 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2694 bcc_ptr++; /* empty domain field */
2695 *bcc_ptr = 0;
2696 }
2697 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2698 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2699 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2700 smb_buffer->smb_buf_length += count;
2701 pSMB->req.ByteCount = cpu_to_le16(count);
2702
2703 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2704 &bytes_returned, 1);
2705
2706 if (smb_buffer_response->Status.CifsError ==
2707 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2708 rc = 0;
2709
2710 if (rc) {
2711/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2712 } else if ((smb_buffer_response->WordCount == 3)
2713 || (smb_buffer_response->WordCount == 4)) {
2714 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2715 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2716
2717 if (action & GUEST_LOGIN)
2718 cFYI(1, (" Guest login"));
2719 /* Do we want to set anything in SesInfo struct when guest login? */
2720
2721 bcc_ptr = pByteArea(smb_buffer_response);
2722 /* response can have either 3 or 4 word count - Samba sends 3 */
2723
2724 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2725 if (SecurityBlob2->MessageType != NtLmChallenge) {
2726 cFYI(1,
2727 ("Unexpected NTLMSSP message type received %d",
2728 SecurityBlob2->MessageType));
2729 } else if (ses) {
2730 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002731 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 if ((pSMBr->resp.hdr.WordCount == 3)
2733 || ((pSMBr->resp.hdr.WordCount == 4)
2734 && (blob_len <
2735 pSMBr->resp.ByteCount))) {
2736
2737 if (pSMBr->resp.hdr.WordCount == 4) {
2738 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002739 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 blob_len));
2741 }
2742
Steve French12b3b8f2006-02-09 21:12:47 +00002743 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744
2745 memcpy(ses->server->cryptKey,
2746 SecurityBlob2->Challenge,
2747 CIFS_CRYPTO_KEY_SIZE);
Steve French12b3b8f2006-02-09 21:12:47 +00002748 if(SecurityBlob2->NegotiateFlags &
2749 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 *pNTLMv2_flag = TRUE;
2751
2752 if((SecurityBlob2->NegotiateFlags &
2753 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2754 || (sign_CIFS_PDUs > 1))
2755 ses->server->secMode |=
2756 SECMODE_SIGN_REQUIRED;
2757 if ((SecurityBlob2->NegotiateFlags &
2758 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2759 ses->server->secMode |=
2760 SECMODE_SIGN_ENABLED;
2761
2762 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2763 if ((long) (bcc_ptr) % 2) {
2764 remaining_words =
2765 (BCC(smb_buffer_response)
2766 - 1) / 2;
2767 bcc_ptr++; /* Unicode strings must be word aligned */
2768 } else {
2769 remaining_words =
2770 BCC
2771 (smb_buffer_response) / 2;
2772 }
2773 len =
2774 UniStrnlen((wchar_t *) bcc_ptr,
2775 remaining_words - 1);
2776/* We look for obvious messed up bcc or strings in response so we do not go off
2777 the end since (at least) WIN2K and Windows XP have a major bug in not null
2778 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002779 if(ses->serverOS)
2780 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002782 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002784 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 bcc_ptr, len,
2786 nls_codepage);
2787 bcc_ptr += 2 * (len + 1);
2788 remaining_words -= len + 1;
2789 ses->serverOS[2 * len] = 0;
2790 ses->serverOS[1 + (2 * len)] = 0;
2791 if (remaining_words > 0) {
2792 len = UniStrnlen((wchar_t *)
2793 bcc_ptr,
2794 remaining_words
2795 - 1);
Steve Frencha424f8b2006-05-30 18:06:04 +00002796 if(ses->serverNOS)
2797 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002799 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 GFP_KERNEL);
2801 cifs_strfromUCS_le(ses->
2802 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002803 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 bcc_ptr,
2805 len,
2806 nls_codepage);
2807 bcc_ptr += 2 * (len + 1);
2808 ses->serverNOS[2 * len] = 0;
2809 ses->serverNOS[1 +
2810 (2 * len)] = 0;
2811 remaining_words -= len + 1;
2812 if (remaining_words > 0) {
2813 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2814 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00002815 if(ses->serverDomain)
2816 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002818 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 (len +
2820 1),
2821 GFP_KERNEL);
2822 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002823 (ses->serverDomain,
2824 (__le16 *)bcc_ptr,
2825 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 bcc_ptr +=
2827 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002828 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002830 ses->serverDomain
2831 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 = 0;
2833 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002834 else {
2835 if(ses->serverDomain)
2836 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002838 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 } else { /* no room so create dummy domain and NOS string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002842 if(ses->serverDomain);
2843 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002845 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002846 if(ses->serverNOS)
2847 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002849 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 }
2851 } else { /* ASCII */
2852 len = strnlen(bcc_ptr, 1024);
2853 if (((long) bcc_ptr + len) - (long)
2854 pByteArea(smb_buffer_response)
2855 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00002856 if(ses->serverOS)
2857 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002859 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 GFP_KERNEL);
2861 strncpy(ses->serverOS,
2862 bcc_ptr, len);
2863
2864 bcc_ptr += len;
2865 bcc_ptr[0] = 0; /* null terminate string */
2866 bcc_ptr++;
2867
2868 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002869 if(ses->serverNOS)
2870 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002872 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 GFP_KERNEL);
2874 strncpy(ses->serverNOS, bcc_ptr, len);
2875 bcc_ptr += len;
2876 bcc_ptr[0] = 0;
2877 bcc_ptr++;
2878
2879 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002880 if(ses->serverDomain)
2881 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002883 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 GFP_KERNEL);
2885 strncpy(ses->serverDomain, bcc_ptr, len);
2886 bcc_ptr += len;
2887 bcc_ptr[0] = 0;
2888 bcc_ptr++;
2889 } else
2890 cFYI(1,
Steve French12b3b8f2006-02-09 21:12:47 +00002891 ("Variable field of length %d extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 len));
2893 }
2894 } else {
2895 cERROR(1,
2896 (" Security Blob Length extends beyond end of SMB"));
2897 }
2898 } else {
2899 cERROR(1, ("No session structure passed in."));
2900 }
2901 } else {
2902 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002903 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 smb_buffer_response->WordCount));
2905 rc = -EIO;
2906 }
2907
2908 if (smb_buffer)
2909 cifs_buf_release(smb_buffer);
2910
2911 return rc;
2912}
2913static int
2914CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2915 char *ntlm_session_key, int ntlmv2_flag,
2916 const struct nls_table *nls_codepage)
2917{
2918 struct smb_hdr *smb_buffer;
2919 struct smb_hdr *smb_buffer_response;
2920 SESSION_SETUP_ANDX *pSMB;
2921 SESSION_SETUP_ANDX *pSMBr;
2922 char *bcc_ptr;
2923 char *user;
2924 char *domain;
2925 int rc = 0;
2926 int remaining_words = 0;
2927 int bytes_returned = 0;
2928 int len;
2929 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2930 PAUTHENTICATE_MESSAGE SecurityBlob;
2931 __u32 negotiate_flags, capabilities;
2932 __u16 count;
2933
2934 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2935 if(ses == NULL)
2936 return -EINVAL;
2937 user = ses->userName;
2938 domain = ses->domainName;
2939 smb_buffer = cifs_buf_get();
2940 if (smb_buffer == NULL) {
2941 return -ENOMEM;
2942 }
2943 smb_buffer_response = smb_buffer;
2944 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2945 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2946
2947 /* send SMBsessionSetup here */
2948 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2949 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002950
2951 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2953 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2954 pSMB->req.AndXCommand = 0xFF;
2955 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2956 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2957
2958 pSMB->req.hdr.Uid = ses->Suid;
2959
2960 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2961 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2962
2963 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2964 CAP_EXTENDED_SECURITY;
2965 if (ses->capabilities & CAP_UNICODE) {
2966 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2967 capabilities |= CAP_UNICODE;
2968 }
2969 if (ses->capabilities & CAP_STATUS32) {
2970 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2971 capabilities |= CAP_STATUS32;
2972 }
2973 if (ses->capabilities & CAP_DFS) {
2974 smb_buffer->Flags2 |= SMBFLG2_DFS;
2975 capabilities |= CAP_DFS;
2976 }
2977 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2978
2979 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2980 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2981 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2982 SecurityBlob->MessageType = NtLmAuthenticate;
2983 bcc_ptr += SecurityBlobLength;
2984 negotiate_flags =
2985 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2986 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2987 0x80000000 | NTLMSSP_NEGOTIATE_128;
2988 if(sign_CIFS_PDUs)
2989 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2990 if(ntlmv2_flag)
2991 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2992
2993/* setup pointers to domain name and workstation name */
2994
2995 SecurityBlob->WorkstationName.Buffer = 0;
2996 SecurityBlob->WorkstationName.Length = 0;
2997 SecurityBlob->WorkstationName.MaximumLength = 0;
2998 SecurityBlob->SessionKey.Length = 0;
2999 SecurityBlob->SessionKey.MaximumLength = 0;
3000 SecurityBlob->SessionKey.Buffer = 0;
3001
3002 SecurityBlob->LmChallengeResponse.Length = 0;
3003 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3004 SecurityBlob->LmChallengeResponse.Buffer = 0;
3005
3006 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003007 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003009 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3010 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 SecurityBlob->NtChallengeResponse.Buffer =
3012 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003013 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3014 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015
3016 if (ses->capabilities & CAP_UNICODE) {
3017 if (domain == NULL) {
3018 SecurityBlob->DomainName.Buffer = 0;
3019 SecurityBlob->DomainName.Length = 0;
3020 SecurityBlob->DomainName.MaximumLength = 0;
3021 } else {
3022 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08003023 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 nls_codepage);
3025 len *= 2;
3026 SecurityBlob->DomainName.MaximumLength =
3027 cpu_to_le16(len);
3028 SecurityBlob->DomainName.Buffer =
3029 cpu_to_le32(SecurityBlobLength);
3030 bcc_ptr += len;
3031 SecurityBlobLength += len;
3032 SecurityBlob->DomainName.Length =
3033 cpu_to_le16(len);
3034 }
3035 if (user == NULL) {
3036 SecurityBlob->UserName.Buffer = 0;
3037 SecurityBlob->UserName.Length = 0;
3038 SecurityBlob->UserName.MaximumLength = 0;
3039 } else {
3040 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08003041 cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 nls_codepage);
3043 len *= 2;
3044 SecurityBlob->UserName.MaximumLength =
3045 cpu_to_le16(len);
3046 SecurityBlob->UserName.Buffer =
3047 cpu_to_le32(SecurityBlobLength);
3048 bcc_ptr += len;
3049 SecurityBlobLength += len;
3050 SecurityBlob->UserName.Length =
3051 cpu_to_le16(len);
3052 }
3053
Steve Frenche89dc922005-11-11 15:18:19 -08003054 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 SecurityBlob->WorkstationName.Length *= 2;
3056 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
3057 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
3058 bcc_ptr += SecurityBlob->WorkstationName.Length;
3059 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
3060 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
3061
3062 if ((long) bcc_ptr % 2) {
3063 *bcc_ptr = 0;
3064 bcc_ptr++;
3065 }
3066 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003067 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 32, nls_codepage);
3069 bcc_ptr += 2 * bytes_returned;
3070 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003071 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 nls_codepage);
3073 bcc_ptr += 2 * bytes_returned;
3074 bcc_ptr += 2; /* null term version string */
3075 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003076 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 64, nls_codepage);
3078 bcc_ptr += 2 * bytes_returned;
3079 *(bcc_ptr + 1) = 0;
3080 *(bcc_ptr + 2) = 0;
3081 bcc_ptr += 2; /* null terminate network opsys string */
3082 *(bcc_ptr + 1) = 0;
3083 *(bcc_ptr + 2) = 0;
3084 bcc_ptr += 2; /* null domain */
3085 } else { /* ASCII */
3086 if (domain == NULL) {
3087 SecurityBlob->DomainName.Buffer = 0;
3088 SecurityBlob->DomainName.Length = 0;
3089 SecurityBlob->DomainName.MaximumLength = 0;
3090 } else {
3091 __u16 len;
3092 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3093 strncpy(bcc_ptr, domain, 63);
3094 len = strnlen(domain, 64);
3095 SecurityBlob->DomainName.MaximumLength =
3096 cpu_to_le16(len);
3097 SecurityBlob->DomainName.Buffer =
3098 cpu_to_le32(SecurityBlobLength);
3099 bcc_ptr += len;
3100 SecurityBlobLength += len;
3101 SecurityBlob->DomainName.Length = cpu_to_le16(len);
3102 }
3103 if (user == NULL) {
3104 SecurityBlob->UserName.Buffer = 0;
3105 SecurityBlob->UserName.Length = 0;
3106 SecurityBlob->UserName.MaximumLength = 0;
3107 } else {
3108 __u16 len;
3109 strncpy(bcc_ptr, user, 63);
3110 len = strnlen(user, 64);
3111 SecurityBlob->UserName.MaximumLength =
3112 cpu_to_le16(len);
3113 SecurityBlob->UserName.Buffer =
3114 cpu_to_le32(SecurityBlobLength);
3115 bcc_ptr += len;
3116 SecurityBlobLength += len;
3117 SecurityBlob->UserName.Length = cpu_to_le16(len);
3118 }
3119 /* BB fill in our workstation name if known BB */
3120
3121 strcpy(bcc_ptr, "Linux version ");
3122 bcc_ptr += strlen("Linux version ");
3123 strcpy(bcc_ptr, system_utsname.release);
3124 bcc_ptr += strlen(system_utsname.release) + 1;
3125 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3126 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3127 bcc_ptr++; /* null domain */
3128 *bcc_ptr = 0;
3129 }
3130 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3131 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3132 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3133 smb_buffer->smb_buf_length += count;
3134 pSMB->req.ByteCount = cpu_to_le16(count);
3135
3136 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3137 &bytes_returned, 1);
3138 if (rc) {
3139/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3140 } else if ((smb_buffer_response->WordCount == 3)
3141 || (smb_buffer_response->WordCount == 4)) {
3142 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3143 __u16 blob_len =
3144 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3145 if (action & GUEST_LOGIN)
3146 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
3147/* if(SecurityBlob2->MessageType != NtLm??){
3148 cFYI("Unexpected message type on auth response is %d "));
3149 } */
3150 if (ses) {
3151 cFYI(1,
3152 ("Does UID on challenge %d match auth response UID %d ",
3153 ses->Suid, smb_buffer_response->Uid));
3154 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
3155 bcc_ptr = pByteArea(smb_buffer_response);
3156 /* response can have either 3 or 4 word count - Samba sends 3 */
3157 if ((pSMBr->resp.hdr.WordCount == 3)
3158 || ((pSMBr->resp.hdr.WordCount == 4)
3159 && (blob_len <
3160 pSMBr->resp.ByteCount))) {
3161 if (pSMBr->resp.hdr.WordCount == 4) {
3162 bcc_ptr +=
3163 blob_len;
3164 cFYI(1,
3165 ("Security Blob Length %d ",
3166 blob_len));
3167 }
3168
3169 cFYI(1,
3170 ("NTLMSSP response to Authenticate "));
3171
3172 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3173 if ((long) (bcc_ptr) % 2) {
3174 remaining_words =
3175 (BCC(smb_buffer_response)
3176 - 1) / 2;
3177 bcc_ptr++; /* Unicode strings must be word aligned */
3178 } else {
3179 remaining_words = BCC(smb_buffer_response) / 2;
3180 }
3181 len =
3182 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3183/* We look for obvious messed up bcc or strings in response so we do not go off
3184 the end since (at least) WIN2K and Windows XP have a major bug in not null
3185 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00003186 if(ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003187 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003189 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003191 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 bcc_ptr, len,
3193 nls_codepage);
3194 bcc_ptr += 2 * (len + 1);
3195 remaining_words -= len + 1;
3196 ses->serverOS[2 * len] = 0;
3197 ses->serverOS[1 + (2 * len)] = 0;
3198 if (remaining_words > 0) {
3199 len = UniStrnlen((wchar_t *)
3200 bcc_ptr,
3201 remaining_words
3202 - 1);
Steve Frencha424f8b2006-05-30 18:06:04 +00003203 if(ses->serverNOS)
3204 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003206 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 GFP_KERNEL);
3208 cifs_strfromUCS_le(ses->
3209 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003210 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 bcc_ptr,
3212 len,
3213 nls_codepage);
3214 bcc_ptr += 2 * (len + 1);
3215 ses->serverNOS[2 * len] = 0;
3216 ses->serverNOS[1+(2*len)] = 0;
3217 remaining_words -= len + 1;
3218 if (remaining_words > 0) {
3219 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3220 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00003221 if(ses->serverDomain)
3222 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003224 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 (len +
3226 1),
3227 GFP_KERNEL);
3228 cifs_strfromUCS_le
3229 (ses->
3230 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003231 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 bcc_ptr, len,
3233 nls_codepage);
3234 bcc_ptr +=
3235 2 * (len + 1);
3236 ses->
3237 serverDomain[2
3238 * len]
3239 = 0;
3240 ses->
3241 serverDomain[1
3242 +
3243 (2
3244 *
3245 len)]
3246 = 0;
3247 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003248 else {
3249 if(ses->serverDomain)
3250 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003251 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 } else { /* no room so create dummy domain and NOS string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003254 if(ses->serverDomain)
3255 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003256 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003257 if(ses->serverNOS)
3258 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003259 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 }
3261 } else { /* ASCII */
3262 len = strnlen(bcc_ptr, 1024);
3263 if (((long) bcc_ptr + len) -
3264 (long) pByteArea(smb_buffer_response)
3265 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00003266 if(ses->serverOS)
3267 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003268 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 strncpy(ses->serverOS,bcc_ptr, len);
3270
3271 bcc_ptr += len;
3272 bcc_ptr[0] = 0; /* null terminate the string */
3273 bcc_ptr++;
3274
3275 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00003276 if(ses->serverNOS)
3277 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003278 ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 strncpy(ses->serverNOS, bcc_ptr, len);
3280 bcc_ptr += len;
3281 bcc_ptr[0] = 0;
3282 bcc_ptr++;
3283
3284 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00003285 if(ses->serverDomain)
3286 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003287 ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 strncpy(ses->serverDomain, bcc_ptr, len);
3289 bcc_ptr += len;
3290 bcc_ptr[0] = 0;
3291 bcc_ptr++;
3292 } else
3293 cFYI(1,
3294 ("Variable field of length %d extends beyond end of smb ",
3295 len));
3296 }
3297 } else {
3298 cERROR(1,
3299 (" Security Blob Length extends beyond end of SMB"));
3300 }
3301 } else {
3302 cERROR(1, ("No session structure passed in."));
3303 }
3304 } else {
3305 cERROR(1,
3306 (" Invalid Word count %d: ",
3307 smb_buffer_response->WordCount));
3308 rc = -EIO;
3309 }
3310
3311 if (smb_buffer)
3312 cifs_buf_release(smb_buffer);
3313
3314 return rc;
3315}
3316
3317int
3318CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3319 const char *tree, struct cifsTconInfo *tcon,
3320 const struct nls_table *nls_codepage)
3321{
3322 struct smb_hdr *smb_buffer;
3323 struct smb_hdr *smb_buffer_response;
3324 TCONX_REQ *pSMB;
3325 TCONX_RSP *pSMBr;
3326 unsigned char *bcc_ptr;
3327 int rc = 0;
3328 int length;
3329 __u16 count;
3330
3331 if (ses == NULL)
3332 return -EIO;
3333
3334 smb_buffer = cifs_buf_get();
3335 if (smb_buffer == NULL) {
3336 return -ENOMEM;
3337 }
3338 smb_buffer_response = smb_buffer;
3339
3340 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3341 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003342
3343 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 smb_buffer->Uid = ses->Suid;
3345 pSMB = (TCONX_REQ *) smb_buffer;
3346 pSMBr = (TCONX_RSP *) smb_buffer_response;
3347
3348 pSMB->AndXCommand = 0xFF;
3349 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 bcc_ptr = &pSMB->Password[0];
Steve Frencheeac8042006-01-13 21:34:58 -08003351 if((ses->server->secMode) & SECMODE_USER) {
3352 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003353 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003354 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003355 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003356 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003357 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003358 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3359 specified as required (when that support is added to
3360 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003361 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003362 by Samba (not sure whether other servers allow
3363 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003364#ifdef CONFIG_CIFS_WEAK_PW_HASH
3365 if((extended_security & CIFSSEC_MAY_LANMAN) &&
3366 (ses->server->secType == LANMAN))
3367 calc_lanman_hash(ses, bcc_ptr);
3368 else
3369#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003370 SMBNTencrypt(ses->password,
3371 ses->server->cryptKey,
3372 bcc_ptr);
3373
Steve French7c7b25b2006-06-01 19:20:10 +00003374 bcc_ptr += CIFS_SESS_KEY_SIZE;
3375 if(ses->capabilities & CAP_UNICODE) {
3376 /* must align unicode strings */
3377 *bcc_ptr = 0; /* null byte password */
3378 bcc_ptr++;
3379 }
Steve Frencheeac8042006-01-13 21:34:58 -08003380 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381
Steve Frencha878fb22006-05-30 18:04:19 +00003382 if(ses->server->secMode &
3383 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3385
3386 if (ses->capabilities & CAP_STATUS32) {
3387 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3388 }
3389 if (ses->capabilities & CAP_DFS) {
3390 smb_buffer->Flags2 |= SMBFLG2_DFS;
3391 }
3392 if (ses->capabilities & CAP_UNICODE) {
3393 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3394 length =
Steve Frencha878fb22006-05-30 18:04:19 +00003395 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3396 6 /* max utf8 char length in bytes */ *
3397 (/* server len*/ + 256 /* share len */), nls_codepage);
3398 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 bcc_ptr += 2; /* skip trailing null */
3400 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 strcpy(bcc_ptr, tree);
3402 bcc_ptr += strlen(tree) + 1;
3403 }
3404 strcpy(bcc_ptr, "?????");
3405 bcc_ptr += strlen("?????");
3406 bcc_ptr += 1;
3407 count = bcc_ptr - &pSMB->Password[0];
3408 pSMB->hdr.smb_buf_length += count;
3409 pSMB->ByteCount = cpu_to_le16(count);
3410
3411 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3412
3413 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3414 /* above now done in SendReceive */
3415 if ((rc == 0) && (tcon != NULL)) {
3416 tcon->tidStatus = CifsGood;
3417 tcon->tid = smb_buffer_response->Tid;
3418 bcc_ptr = pByteArea(smb_buffer_response);
3419 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3420 /* skip service field (NB: this field is always ASCII) */
3421 bcc_ptr += length + 1;
3422 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3423 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3424 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3425 if ((bcc_ptr + (2 * length)) -
3426 pByteArea(smb_buffer_response) <=
3427 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003428 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003430 kzalloc(length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 cifs_strfromUCS_le(tcon->nativeFileSystem,
Steve Frenche89dc922005-11-11 15:18:19 -08003432 (__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 length, nls_codepage);
3434 bcc_ptr += 2 * length;
3435 bcc_ptr[0] = 0; /* null terminate the string */
3436 bcc_ptr[1] = 0;
3437 bcc_ptr += 2;
3438 }
3439 /* else do not bother copying these informational fields */
3440 } else {
3441 length = strnlen(bcc_ptr, 1024);
3442 if ((bcc_ptr + length) -
3443 pByteArea(smb_buffer_response) <=
3444 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003445 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003447 kzalloc(length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 strncpy(tcon->nativeFileSystem, bcc_ptr,
3449 length);
3450 }
3451 /* else do not bother copying these informational fields */
3452 }
Steve French39798772006-05-31 22:40:51 +00003453 if(smb_buffer_response->WordCount == 3)
3454 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3455 else
3456 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3458 } else if ((rc == 0) && tcon == NULL) {
3459 /* all we need to save for IPC$ connection */
3460 ses->ipc_tid = smb_buffer_response->Tid;
3461 }
3462
3463 if (smb_buffer)
3464 cifs_buf_release(smb_buffer);
3465 return rc;
3466}
3467
3468int
3469cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3470{
3471 int rc = 0;
3472 int xid;
3473 struct cifsSesInfo *ses = NULL;
3474 struct task_struct *cifsd_task;
3475
3476 xid = GetXid();
3477
3478 if (cifs_sb->tcon) {
3479 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3480 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3481 if (rc == -EBUSY) {
3482 FreeXid(xid);
3483 return 0;
3484 }
3485 tconInfoFree(cifs_sb->tcon);
3486 if ((ses) && (ses->server)) {
3487 /* save off task so we do not refer to ses later */
3488 cifsd_task = ses->server->tsk;
3489 cFYI(1, ("About to do SMBLogoff "));
3490 rc = CIFSSMBLogoff(xid, ses);
3491 if (rc == -EBUSY) {
3492 FreeXid(xid);
3493 return 0;
3494 } else if (rc == -ESHUTDOWN) {
3495 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf1914012005-08-18 09:37:34 -07003496 if(cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 send_sig(SIGKILL,cifsd_task,1);
Steve Frenchf1914012005-08-18 09:37:34 -07003498 wait_for_completion(&cifsd_complete);
3499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 rc = 0;
3501 } /* else - we have an smb session
3502 left on this socket do not kill cifsd */
3503 } else
3504 cFYI(1, ("No session or bad tcon"));
3505 }
3506
3507 cifs_sb->tcon = NULL;
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003508 if (ses)
3509 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 if (ses)
3511 sesInfoFree(ses);
3512
3513 FreeXid(xid);
3514 return rc; /* BB check if we should always return zero here */
3515}
3516
3517int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3518 struct nls_table * nls_info)
3519{
3520 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003521 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003523 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524
3525 /* what if server changes its buffer size after dropping the session? */
3526 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3527 rc = CIFSSMBNegotiate(xid, pSesInfo);
3528 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3529 rc = CIFSSMBNegotiate(xid, pSesInfo);
3530 if(rc == -EAGAIN)
3531 rc = -EHOSTDOWN;
3532 }
3533 if(rc == 0) {
3534 spin_lock(&GlobalMid_Lock);
3535 if(pSesInfo->server->tcpStatus != CifsExiting)
3536 pSesInfo->server->tcpStatus = CifsGood;
3537 else
3538 rc = -EHOSTDOWN;
3539 spin_unlock(&GlobalMid_Lock);
3540
3541 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003542 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 }
3544 if (!rc) {
3545 pSesInfo->capabilities = pSesInfo->server->capabilities;
3546 if(linuxExtEnabled == 0)
3547 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003548 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3550 pSesInfo->server->secMode,
3551 pSesInfo->server->capabilities,
3552 pSesInfo->server->timeZone));
Steve French301dc3e2006-04-24 16:24:54 +00003553#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French60808232006-04-22 15:53:05 +00003554 if(experimEnabled > 1)
Steve French39798772006-05-31 22:40:51 +00003555 rc = CIFS_SessSetup(xid, pSesInfo,
3556 first_time, nls_info);
Steve French301dc3e2006-04-24 16:24:54 +00003557 else
3558#endif
3559 if (extended_security
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3561 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003562 cFYI(1, ("New style sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 rc = CIFSSpnegoSessSetup(xid, pSesInfo,
3564 NULL /* security blob */,
3565 0 /* blob length */,
3566 nls_info);
3567 } else if (extended_security
3568 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3569 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003570 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3572 pSesInfo,
3573 &ntlmv2_flag,
3574 nls_info);
3575 if (!rc) {
3576 if(ntlmv2_flag) {
3577 char * v2_response;
3578 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3579 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3580 nls_info)) {
3581 rc = -ENOMEM;
3582 goto ss_err_exit;
3583 } else
3584 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3585 if(v2_response) {
3586 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003587 /* if(first_time)
3588 cifs_calculate_ntlmv2_mac_key(
3589 pSesInfo->server->mac_signing_key,
3590 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 kfree(v2_response);
3592 /* BB Put dummy sig in SessSetup PDU? */
3593 } else {
3594 rc = -ENOMEM;
3595 goto ss_err_exit;
3596 }
3597
3598 } else {
3599 SMBNTencrypt(pSesInfo->password,
3600 pSesInfo->server->cryptKey,
3601 ntlm_session_key);
3602
Steve Frenchad009ac2005-04-28 22:41:05 -07003603 if(first_time)
3604 cifs_calculate_mac_key(
3605 pSesInfo->server->mac_signing_key,
3606 ntlm_session_key,
3607 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 }
3609 /* for better security the weaker lanman hash not sent
3610 in AuthSessSetup so we no longer calculate it */
3611
3612 rc = CIFSNTLMSSPAuthSessSetup(xid,
3613 pSesInfo,
3614 ntlm_session_key,
3615 ntlmv2_flag,
3616 nls_info);
3617 }
3618 } else { /* old style NTLM 0.12 session setup */
3619 SMBNTencrypt(pSesInfo->password,
3620 pSesInfo->server->cryptKey,
3621 ntlm_session_key);
3622
Steve Frenchad009ac2005-04-28 22:41:05 -07003623 if(first_time)
3624 cifs_calculate_mac_key(
3625 pSesInfo->server->mac_signing_key,
3626 ntlm_session_key, pSesInfo->password);
3627
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 rc = CIFSSessSetup(xid, pSesInfo,
3629 ntlm_session_key, nls_info);
3630 }
3631 if (rc) {
3632 cERROR(1,("Send error in SessSetup = %d",rc));
3633 } else {
3634 cFYI(1,("CIFS Session Established successfully"));
3635 pSesInfo->status = CifsGood;
3636 }
3637 }
3638ss_err_exit:
3639 return rc;
3640}
3641