blob: 0e9ba0b9d71eb008138eab55841bffe5d73be196 [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;
Steve French189acaa2006-06-23 02:33:48 +000071 unsigned secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 unsigned rw:1;
73 unsigned retry:1;
74 unsigned intr:1;
75 unsigned setuids:1;
76 unsigned noperm:1;
77 unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
Steve French0a4b92c2006-01-12 15:44:21 -080078 unsigned cifs_acl:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
80 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
81 unsigned direct_io:1;
Steve French6a0b4822005-04-28 22:41:05 -070082 unsigned remap:1; /* set to remap seven reserved chars in filenames */
Jeremy Allisonac670552005-06-22 17:26:35 -070083 unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
Steve Frenchd7245c22005-07-14 18:25:12 -050084 unsigned sfu_emul:1;
Steve Frenchbf820672005-12-01 22:32:42 -080085 unsigned nullauth:1; /* attempt to authenticate with null user */
Steve Frenchc46fa8a2005-08-18 20:49:57 -070086 unsigned nocase; /* request case insensitive filenames */
87 unsigned nobrl; /* disable sending byte range locks to srv */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 unsigned int rsize;
89 unsigned int wsize;
90 unsigned int sockopt;
91 unsigned short int port;
Steve French2fe87f02006-09-21 07:02:52 +000092 char * prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093};
94
95static int ipv4_connect(struct sockaddr_in *psin_server,
96 struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -070097 char * netb_name,
98 char * server_netb_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099static int ipv6_connect(struct sockaddr_in6 *psin_server,
100 struct socket **csocket);
101
102
103 /*
104 * cifs tcp session reconnection
105 *
106 * mark tcp session as reconnecting so temporarily locked
107 * mark all smb sessions as reconnecting for tcp session
108 * reconnect tcp session
109 * wake up waiters on reconnection? - (not needed currently)
110 */
111
112int
113cifs_reconnect(struct TCP_Server_Info *server)
114{
115 int rc = 0;
116 struct list_head *tmp;
117 struct cifsSesInfo *ses;
118 struct cifsTconInfo *tcon;
119 struct mid_q_entry * mid_entry;
120
121 spin_lock(&GlobalMid_Lock);
122 if(server->tcpStatus == CifsExiting) {
123 /* the demux thread will exit normally
124 next time through the loop */
125 spin_unlock(&GlobalMid_Lock);
126 return rc;
127 } else
128 server->tcpStatus = CifsNeedReconnect;
129 spin_unlock(&GlobalMid_Lock);
130 server->maxBuf = 0;
131
Steve Frenche4eb2952005-04-28 22:41:09 -0700132 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
134 /* before reconnecting the tcp session, mark the smb session (uid)
135 and the tid bad so they are not used until reconnected */
136 read_lock(&GlobalSMBSeslock);
137 list_for_each(tmp, &GlobalSMBSessionList) {
138 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
139 if (ses->server) {
140 if (ses->server == server) {
141 ses->status = CifsNeedReconnect;
142 ses->ipc_tid = 0;
143 }
144 }
145 /* else tcp and smb sessions need reconnection */
146 }
147 list_for_each(tmp, &GlobalTreeConnectionList) {
148 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
149 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
150 tcon->tidStatus = CifsNeedReconnect;
151 }
152 }
153 read_unlock(&GlobalSMBSeslock);
154 /* do not want to be sending data on a socket we are freeing */
155 down(&server->tcpSem);
156 if(server->ssocket) {
157 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
158 server->ssocket->flags));
159 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
160 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
161 server->ssocket->flags));
162 sock_release(server->ssocket);
163 server->ssocket = NULL;
164 }
165
166 spin_lock(&GlobalMid_Lock);
167 list_for_each(tmp, &server->pending_mid_q) {
168 mid_entry = list_entry(tmp, struct
169 mid_q_entry,
170 qhead);
171 if(mid_entry) {
172 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700173 /* Mark other intransit requests as needing
174 retry so we do not immediately mark the
175 session bad again (ie after we reconnect
176 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 mid_entry->midState = MID_RETRY_NEEDED;
178 }
179 }
180 }
181 spin_unlock(&GlobalMid_Lock);
182 up(&server->tcpSem);
183
184 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
185 {
Steve French6c3d8902006-07-31 22:46:20 +0000186 try_to_freeze();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 if(server->protocolType == IPV6) {
188 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
189 } else {
190 rc = ipv4_connect(&server->addr.sockAddr,
191 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700192 server->workstation_RFC1001_name,
193 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 }
195 if(rc) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700196 cFYI(1,("reconnect error %d",rc));
Steve French0cb766a2005-04-28 22:41:11 -0700197 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 } else {
199 atomic_inc(&tcpSesReconnectCount);
200 spin_lock(&GlobalMid_Lock);
201 if(server->tcpStatus != CifsExiting)
202 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700203 server->sequence_number = 0;
204 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 /* atomic_set(&server->inFlight,0);*/
206 wake_up(&server->response_q);
207 }
208 }
209 return rc;
210}
211
Steve Frenche4eb2952005-04-28 22:41:09 -0700212/*
213 return codes:
214 0 not a transact2, or all data present
215 >0 transact2 with that much data missing
216 -EINVAL = invalid transact2
217
218 */
219static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
220{
221 struct smb_t2_rsp * pSMBt;
222 int total_data_size;
223 int data_in_this_rsp;
224 int remaining;
225
226 if(pSMB->Command != SMB_COM_TRANSACTION2)
227 return 0;
228
229 /* check for plausible wct, bcc and t2 data and parm sizes */
230 /* check for parm and data offset going beyond end of smb */
231 if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
232 cFYI(1,("invalid transact2 word count"));
233 return -EINVAL;
234 }
235
236 pSMBt = (struct smb_t2_rsp *)pSMB;
237
238 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
239 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
240
241 remaining = total_data_size - data_in_this_rsp;
242
243 if(remaining == 0)
244 return 0;
245 else if(remaining < 0) {
246 cFYI(1,("total data %d smaller than data in frame %d",
247 total_data_size, data_in_this_rsp));
248 return -EINVAL;
249 } else {
250 cFYI(1,("missing %d bytes from transact2, check next response",
251 remaining));
252 if(total_data_size > maxBufSize) {
253 cERROR(1,("TotalDataSize %d is over maximum buffer %d",
254 total_data_size,maxBufSize));
255 return -EINVAL;
256 }
257 return remaining;
258 }
259}
260
261static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
262{
263 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
264 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
265 int total_data_size;
266 int total_in_buf;
267 int remaining;
268 int total_in_buf2;
269 char * data_area_of_target;
270 char * data_area_of_buf2;
271 __u16 byte_count;
272
273 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
274
275 if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
276 cFYI(1,("total data sizes of primary and secondary t2 differ"));
277 }
278
279 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
280
281 remaining = total_data_size - total_in_buf;
282
283 if(remaining < 0)
284 return -EINVAL;
285
286 if(remaining == 0) /* nothing to do, ignore */
287 return 0;
288
289 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
290 if(remaining < total_in_buf2) {
291 cFYI(1,("transact2 2nd response contains too much data"));
292 }
293
294 /* find end of first SMB data area */
295 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
296 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
297 /* validate target area */
298
299 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
300 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
301
302 data_area_of_target += total_in_buf;
303
304 /* copy second buffer into end of first buffer */
305 memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
306 total_in_buf += total_in_buf2;
307 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
308 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
309 byte_count += total_in_buf2;
310 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
311
Steve French70ca7342005-09-22 16:32:06 -0700312 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700313 byte_count += total_in_buf2;
314
315 /* BB also add check that we are not beyond maximum buffer size */
316
Steve French70ca7342005-09-22 16:32:06 -0700317 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700318
319 if(remaining == total_in_buf2) {
320 cFYI(1,("found the last secondary response"));
321 return 0; /* we are done */
322 } else /* more responses to go */
323 return 1;
324
325}
326
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327static int
328cifs_demultiplex_thread(struct TCP_Server_Info *server)
329{
330 int length;
331 unsigned int pdu_length, total_read;
332 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700333 struct smb_hdr *bigbuf = NULL;
334 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 struct msghdr smb_msg;
336 struct kvec iov;
337 struct socket *csocket = server->ssocket;
338 struct list_head *tmp;
339 struct cifsSesInfo *ses;
340 struct task_struct *task_to_wake = NULL;
341 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700342 char temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700343 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700344 int isMultiRsp;
345 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347 daemonize("cifsd");
348 allow_signal(SIGKILL);
349 current->flags |= PF_MEMALLOC;
350 server->tsk = current; /* save process info to wake at shutdown */
351 cFYI(1, ("Demultiplex PID: %d", current->pid));
352 write_lock(&GlobalSMBSeslock);
353 atomic_inc(&tcpSesAllocCount);
354 length = tcpSesAllocCount.counter;
355 write_unlock(&GlobalSMBSeslock);
Steve Frenchf1914012005-08-18 09:37:34 -0700356 complete(&cifsd_complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 if(length > 1) {
358 mempool_resize(cifs_req_poolp,
359 length + cifs_min_rcv,
360 GFP_KERNEL);
361 }
362
363 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700364 if (try_to_freeze())
365 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700366 if (bigbuf == NULL) {
367 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000368 if (!bigbuf) {
369 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700370 msleep(3000);
371 /* retry will check if exiting */
372 continue;
373 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000374 } else if (isLargeBuf) {
375 /* we are reusing a dirty large buf, clear its start */
Steve Frenchb8643e12005-04-28 22:41:07 -0700376 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700378
379 if (smallbuf == NULL) {
380 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000381 if (!smallbuf) {
382 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700383 msleep(1000);
384 /* retry will check if exiting */
385 continue;
386 }
387 /* beginning of smb buffer is cleared in our buf_get */
388 } else /* if existing small buf clear beginning */
389 memset(smallbuf, 0, sizeof (struct smb_hdr));
390
391 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700392 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700393 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 iov.iov_base = smb_buffer;
395 iov.iov_len = 4;
396 smb_msg.msg_control = NULL;
397 smb_msg.msg_controllen = 0;
398 length =
399 kernel_recvmsg(csocket, &smb_msg,
400 &iov, 1, 4, 0 /* BB see socket.h flags */);
401
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000402 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 break;
404 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000405 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000407 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 csocket = server->ssocket;
409 continue;
410 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700411 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 allowing socket to clear and app threads to set
413 tcpStatus CifsNeedReconnect if server hung */
414 continue;
415 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000416 if (server->tcpStatus == CifsNew) {
417 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700418 /* some servers kill the TCP session rather than
419 returning an SMB negprot error, in which
420 case reconnecting here is not going to help,
421 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 break;
423 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000424 if (!try_to_freeze() && (length == -EINTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 cFYI(1,("cifsd thread killed"));
426 break;
427 }
Steve French57337e42005-04-28 22:41:10 -0700428 cFYI(1,("Reconnect after unexpected peek error %d",
429 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 cifs_reconnect(server);
431 csocket = server->ssocket;
432 wake_up(&server->response_q);
433 continue;
Steve French46810cb2005-04-28 22:41:09 -0700434 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700436 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 length));
438 cifs_reconnect(server);
439 csocket = server->ssocket;
440 wake_up(&server->response_q);
441 continue;
442 }
Steve French67010fb2005-04-28 22:41:09 -0700443
Steve French70ca7342005-09-22 16:32:06 -0700444 /* The right amount was read from socket - 4 bytes */
445 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700446
Steve French70ca7342005-09-22 16:32:06 -0700447 /* the first byte big endian of the length field,
448 is actually not part of the length but the type
449 with the most common, zero, as regular data */
450 temp = *((char *) smb_buffer);
451
452 /* Note that FC 1001 length is big endian on the wire,
453 but we convert it here so it is always manipulated
454 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700455 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700456 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700457
Steve French70ca7342005-09-22 16:32:06 -0700458 cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
459
460 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700461 continue;
Steve French70ca7342005-09-22 16:32:06 -0700462 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700463 cFYI(1,("Good RFC 1002 session rsp"));
464 continue;
Steve French70ca7342005-09-22 16:32:06 -0700465 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve French46810cb2005-04-28 22:41:09 -0700466 /* we get this from Windows 98 instead of
467 an error on SMB negprot response */
Steve Frenche4eb2952005-04-28 22:41:09 -0700468 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700469 pdu_length));
Steve French46810cb2005-04-28 22:41:09 -0700470 if(server->tcpStatus == CifsNew) {
471 /* if nack on negprot (rather than
472 ret of smb negprot error) reconnecting
473 not going to help, ret error to mount */
474 break;
475 } else {
476 /* give server a second to
477 clean up before reconnect attempt */
478 msleep(1000);
479 /* always try 445 first on reconnect
480 since we get NACK on some if we ever
481 connected to port 139 (the NACK is
482 since we do not begin with RFC1001
483 session initialize frame) */
484 server->addr.sockAddr.sin_port =
485 htons(CIFS_PORT);
486 cifs_reconnect(server);
487 csocket = server->ssocket;
488 wake_up(&server->response_q);
489 continue;
490 }
Steve French70ca7342005-09-22 16:32:06 -0700491 } else if (temp != (char) 0) {
Steve French46810cb2005-04-28 22:41:09 -0700492 cERROR(1,("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700493 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
494 length);
Steve French46810cb2005-04-28 22:41:09 -0700495 cifs_reconnect(server);
496 csocket = server->ssocket;
497 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700498 }
499
500 /* else we have an SMB response */
501 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700502 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700503 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700504 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700505 cifs_reconnect(server);
506 csocket = server->ssocket;
507 wake_up(&server->response_q);
508 continue;
509 }
510
511 /* else length ok */
512 reconnect = 0;
513
Steve Frenchec637e32005-12-12 20:53:18 -0800514 if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700515 isLargeBuf = TRUE;
516 memcpy(bigbuf, smallbuf, 4);
517 smb_buffer = bigbuf;
518 }
519 length = 0;
520 iov.iov_base = 4 + (char *)smb_buffer;
521 iov.iov_len = pdu_length;
522 for (total_read = 0; total_read < pdu_length;
523 total_read += length) {
524 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
525 pdu_length - total_read, 0);
526 if((server->tcpStatus == CifsExiting) ||
527 (length == -EINTR)) {
528 /* then will exit */
529 reconnect = 2;
530 break;
531 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700532 cifs_reconnect(server);
533 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700534 /* Reconnect wakes up rspns q */
535 /* Now we will reread sock */
536 reconnect = 1;
537 break;
538 } else if ((length == -ERESTARTSYS) ||
539 (length == -EAGAIN)) {
540 msleep(1); /* minimum sleep to prevent looping,
541 allowing socket to clear and app
542 threads to set tcpStatus
543 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700544 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700545 } else if (length <= 0) {
546 cERROR(1,("Received no data, expecting %d",
547 pdu_length - total_read));
548 cifs_reconnect(server);
549 csocket = server->ssocket;
550 reconnect = 1;
551 break;
Steve French46810cb2005-04-28 22:41:09 -0700552 }
553 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700554 if(reconnect == 2)
555 break;
556 else if(reconnect == 1)
557 continue;
558
559 length += 4; /* account for rfc1002 hdr */
560
561
562 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000563 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700564 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700565 continue;
566 }
567
568
569 task_to_wake = NULL;
570 spin_lock(&GlobalMid_Lock);
571 list_for_each(tmp, &server->pending_mid_q) {
572 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
573
574 if ((mid_entry->mid == smb_buffer->Mid) &&
575 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
576 (mid_entry->command == smb_buffer->Command)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700577 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
578 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700579 isMultiRsp = TRUE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700580 if(mid_entry->resp_buf) {
581 /* merge response - fix up 1st*/
582 if(coalesce_t2(smb_buffer,
583 mid_entry->resp_buf)) {
Steve French39798772006-05-31 22:40:51 +0000584 mid_entry->multiRsp = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700585 break;
586 } else {
587 /* all parts received */
Steve French39798772006-05-31 22:40:51 +0000588 mid_entry->multiEnd = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700589 goto multi_t2_fnd;
590 }
591 } else {
592 if(!isLargeBuf) {
593 cERROR(1,("1st trans2 resp needs bigbuf"));
594 /* BB maybe we can fix this up, switch
595 to already allocated large buffer? */
596 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700597 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700598 mid_entry->resp_buf =
599 smb_buffer;
600 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700601 bigbuf = NULL;
602 }
603 }
604 break;
605 }
606 mid_entry->resp_buf = smb_buffer;
607 if(isLargeBuf)
608 mid_entry->largeBuf = 1;
609 else
610 mid_entry->largeBuf = 0;
611multi_t2_fnd:
612 task_to_wake = mid_entry->tsk;
613 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700614#ifdef CONFIG_CIFS_STATS2
615 mid_entry->when_received = jiffies;
616#endif
Steve French3a5ff612006-07-14 22:37:11 +0000617 /* so we do not time out requests to server
618 which is still responding (since server could
619 be busy but not dead) */
620 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700621 break;
622 }
623 }
624 spin_unlock(&GlobalMid_Lock);
625 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700626 /* Was previous buf put in mpx struct for multi-rsp? */
627 if(!isMultiRsp) {
628 /* smb buffer will be freed by user thread */
629 if(isLargeBuf) {
630 bigbuf = NULL;
631 } else
632 smallbuf = NULL;
633 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700634 wake_up_process(task_to_wake);
Steve Frenchd7c8c942006-03-03 10:43:49 +0000635 } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700636 && (isMultiRsp == FALSE)) {
Steve French39798772006-05-31 22:40:51 +0000637 cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
Steve French70ca7342005-09-22 16:32:06 -0700638 cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
639 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000640#ifdef CONFIG_CIFS_DEBUG2
641 cifs_dump_detail(smb_buffer);
642 cifs_dump_mids(server);
643#endif /* CIFS_DEBUG2 */
644
Steve Frenche4eb2952005-04-28 22:41:09 -0700645 }
646 } /* end while !EXITING */
647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 spin_lock(&GlobalMid_Lock);
649 server->tcpStatus = CifsExiting;
650 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700651 /* check if we have blocked requests that need to free */
652 /* Note that cifs_max_pending is normally 50, but
653 can be set at module install time to as little as two */
654 if(atomic_read(&server->inFlight) >= cifs_max_pending)
655 atomic_set(&server->inFlight, cifs_max_pending - 1);
656 /* We do not want to set the max_pending too low or we
657 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 spin_unlock(&GlobalMid_Lock);
659 /* Although there should not be any requests blocked on
660 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700661 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 to the same server - they now will see the session is in exit state
663 and get out of SendReceive. */
664 wake_up_all(&server->request_q);
665 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700666 msleep(125);
667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 if(server->ssocket) {
669 sock_release(csocket);
670 server->ssocket = NULL;
671 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700672 /* buffer usuallly freed in free_mid - need to free it here on exit */
673 if (bigbuf != NULL)
674 cifs_buf_release(bigbuf);
675 if (smallbuf != NULL)
676 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
678 read_lock(&GlobalSMBSeslock);
679 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700680 /* loop through server session structures attached to this and
681 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 list_for_each(tmp, &GlobalSMBSessionList) {
683 ses =
684 list_entry(tmp, struct cifsSesInfo,
685 cifsSessionList);
686 if (ses->server == server) {
687 ses->status = CifsExiting;
688 ses->server = NULL;
689 }
690 }
691 read_unlock(&GlobalSMBSeslock);
692 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700693 /* although we can not zero the server struct pointer yet,
694 since there are active requests which may depnd on them,
695 mark the corresponding SMB sessions as exiting too */
696 list_for_each(tmp, &GlobalSMBSessionList) {
697 ses = list_entry(tmp, struct cifsSesInfo,
698 cifsSessionList);
699 if (ses->server == server) {
700 ses->status = CifsExiting;
701 }
702 }
703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 spin_lock(&GlobalMid_Lock);
705 list_for_each(tmp, &server->pending_mid_q) {
706 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
707 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
708 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700709 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 task_to_wake = mid_entry->tsk;
711 if(task_to_wake) {
712 wake_up_process(task_to_wake);
713 }
714 }
715 }
716 spin_unlock(&GlobalMid_Lock);
717 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700719 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 }
721
Steve Frenchf1914012005-08-18 09:37:34 -0700722 if (!list_empty(&server->pending_mid_q)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 /* mpx threads have not exited yet give them
724 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700725 /* due to delays on oplock break requests, we need
726 to wait at least 45 seconds before giving up
727 on a request getting a response and going ahead
728 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700730 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 /* if threads still have not exited they are probably never
732 coming home not much else we can do but free the memory */
733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735 write_lock(&GlobalSMBSeslock);
736 atomic_dec(&tcpSesAllocCount);
737 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700738
739 /* last chance to mark ses pointers invalid
740 if there are any pointing to this (e.g
741 if a crazy root user tried to kill cifsd
742 kernel thread explicitly this might happen) */
743 list_for_each(tmp, &GlobalSMBSessionList) {
744 ses = list_entry(tmp, struct cifsSesInfo,
745 cifsSessionList);
746 if (ses->server == server) {
747 ses->server = NULL;
748 }
749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700751
752 kfree(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 if(length > 0) {
754 mempool_resize(cifs_req_poolp,
755 length + cifs_min_rcv,
756 GFP_KERNEL);
757 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700758
Steve Frenchf1914012005-08-18 09:37:34 -0700759 complete_and_exit(&cifsd_complete, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return 0;
761}
762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763static int
764cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
765{
766 char *value;
767 char *data;
768 unsigned int temp_len, i, j;
769 char separator[2];
770
771 separator[0] = ',';
772 separator[1] = 0;
773
774 memset(vol->source_rfc1001_name,0x20,15);
775 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
776 /* does not have to be a perfect mapping since the field is
777 informational, only used for servers that do not support
778 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700779 vol->source_rfc1001_name[i] =
780 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 }
782 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700783 /* null target name indicates to use *SMBSERVR default called name
784 if we end up sending RFC1001 session initialize */
785 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 vol->linux_uid = current->uid; /* current->euid instead? */
787 vol->linux_gid = current->gid;
788 vol->dir_mode = S_IRWXUGO;
789 /* 2767 perms indicate mandatory locking support */
790 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
791
792 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
793 vol->rw = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700794 /* default is always to request posix paths. */
795 vol->posix_paths = 1;
796
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 if (!options)
798 return 1;
799
800 if(strncmp(options,"sep=",4) == 0) {
801 if(options[4] != 0) {
802 separator[0] = options[4];
803 options += 5;
804 } else {
805 cFYI(1,("Null separator not allowed"));
806 }
807 }
808
809 while ((data = strsep(&options, separator)) != NULL) {
810 if (!*data)
811 continue;
812 if ((value = strchr(data, '=')) != NULL)
813 *value++ = '\0';
814
815 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
816 vol->no_xattr = 0;
817 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
818 vol->no_xattr = 1;
819 } else if (strnicmp(data, "user", 4) == 0) {
820 if (!value || !*value) {
821 printk(KERN_WARNING
822 "CIFS: invalid or missing username\n");
823 return 1; /* needs_arg; */
824 }
825 if (strnlen(value, 200) < 200) {
826 vol->username = value;
827 } else {
828 printk(KERN_WARNING "CIFS: username too long\n");
829 return 1;
830 }
831 } else if (strnicmp(data, "pass", 4) == 0) {
832 if (!value) {
833 vol->password = NULL;
834 continue;
835 } else if(value[0] == 0) {
836 /* check if string begins with double comma
837 since that would mean the password really
838 does start with a comma, and would not
839 indicate an empty string */
840 if(value[1] != separator[0]) {
841 vol->password = NULL;
842 continue;
843 }
844 }
845 temp_len = strlen(value);
846 /* removed password length check, NTLM passwords
847 can be arbitrarily long */
848
849 /* if comma in password, the string will be
850 prematurely null terminated. Commas in password are
851 specified across the cifs mount interface by a double
852 comma ie ,, and a comma used as in other cases ie ','
853 as a parameter delimiter/separator is single and due
854 to the strsep above is temporarily zeroed. */
855
856 /* NB: password legally can have multiple commas and
857 the only illegal character in a password is null */
858
Steve French09d1db52005-04-28 22:41:08 -0700859 if ((value[temp_len] == 0) &&
860 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 /* reinsert comma */
862 value[temp_len] = separator[0];
863 temp_len+=2; /* move after the second comma */
864 while(value[temp_len] != 0) {
865 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700866 if (value[temp_len+1] ==
867 separator[0]) {
868 /* skip second comma */
869 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 } else {
871 /* single comma indicating start
872 of next parm */
873 break;
874 }
875 }
876 temp_len++;
877 }
878 if(value[temp_len] == 0) {
879 options = NULL;
880 } else {
881 value[temp_len] = 0;
882 /* point option to start of next parm */
883 options = value + temp_len + 1;
884 }
885 /* go from value to value + temp_len condensing
886 double commas to singles. Note that this ends up
887 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700888 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700889 if(vol->password == NULL) {
890 printk("CIFS: no memory for pass\n");
891 return 1;
892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 for(i=0,j=0;i<temp_len;i++,j++) {
894 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700895 if(value[i] == separator[0]
896 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 /* skip second comma */
898 i++;
899 }
900 }
901 vol->password[j] = 0;
902 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700903 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700904 if(vol->password == NULL) {
905 printk("CIFS: no memory for pass\n");
906 return 1;
907 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 strcpy(vol->password, value);
909 }
910 } else if (strnicmp(data, "ip", 2) == 0) {
911 if (!value || !*value) {
912 vol->UNCip = NULL;
913 } else if (strnlen(value, 35) < 35) {
914 vol->UNCip = value;
915 } else {
916 printk(KERN_WARNING "CIFS: ip address too long\n");
917 return 1;
918 }
Steve Frenchbf820672005-12-01 22:32:42 -0800919 } else if (strnicmp(data, "sec", 3) == 0) {
920 if (!value || !*value) {
921 cERROR(1,("no security value specified"));
922 continue;
923 } else if (strnicmp(value, "krb5i", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000924 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000925 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800926 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000927 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
Steve French189acaa2006-06-23 02:33:48 +0000928 CIFSSEC_MAY_KRB5; */
Steve Frenchbf820672005-12-01 22:32:42 -0800929 cERROR(1,("Krb5 cifs privacy not supported"));
930 return 1;
931 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000932 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800933 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000934 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000935 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800936 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000937 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800938 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000939 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000940 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800941 } else if (strnicmp(value, "ntlm", 4) == 0) {
942 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000943 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800944 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000945 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000946 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000947#ifdef CONFIG_CIFS_WEAK_PW_HASH
948 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000949 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000950#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800951 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000952 vol->nullauth = 1;
Steve Frenchbf820672005-12-01 22:32:42 -0800953 } else {
954 cERROR(1,("bad security option: %s", value));
955 return 1;
956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 } else if ((strnicmp(data, "unc", 3) == 0)
958 || (strnicmp(data, "target", 6) == 0)
959 || (strnicmp(data, "path", 4) == 0)) {
960 if (!value || !*value) {
961 printk(KERN_WARNING
962 "CIFS: invalid path to network resource\n");
963 return 1; /* needs_arg; */
964 }
965 if ((temp_len = strnlen(value, 300)) < 300) {
966 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
967 if(vol->UNC == NULL)
968 return 1;
969 strcpy(vol->UNC,value);
970 if (strncmp(vol->UNC, "//", 2) == 0) {
971 vol->UNC[0] = '\\';
972 vol->UNC[1] = '\\';
973 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
974 printk(KERN_WARNING
975 "CIFS: UNC Path does not begin with // or \\\\ \n");
976 return 1;
977 }
978 } else {
979 printk(KERN_WARNING "CIFS: UNC name too long\n");
980 return 1;
981 }
982 } else if ((strnicmp(data, "domain", 3) == 0)
983 || (strnicmp(data, "workgroup", 5) == 0)) {
984 if (!value || !*value) {
985 printk(KERN_WARNING "CIFS: invalid domain name\n");
986 return 1; /* needs_arg; */
987 }
988 /* BB are there cases in which a comma can be valid in
989 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +0000990 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 vol->domainname = value;
992 cFYI(1, ("Domain name set"));
993 } else {
994 printk(KERN_WARNING "CIFS: domain name too long\n");
995 return 1;
996 }
Steve French2fe87f02006-09-21 07:02:52 +0000997 } else if (strnicmp(data, "prefixpath", 10) == 0) {
998 if (!value || !*value) {
999 printk(KERN_WARNING
1000 "CIFS: invalid path prefix\n");
1001 return 1; /* needs_arg; */
1002 }
1003 if ((temp_len = strnlen(value, 1024)) < 1024) {
1004 if(value[0] != '/')
1005 temp_len++; /* missing leading slash */
1006 vol->prepath = kmalloc(temp_len+1,GFP_KERNEL);
1007 if(vol->prepath == NULL)
1008 return 1;
1009 if(value[0] != '/') {
1010 vol->prepath[0] = '/';
1011 strcpy(vol->prepath+1,value);
1012 } else
1013 strcpy(vol->prepath,value);
1014 cFYI(1,("prefix path %s",vol->prepath));
1015 } else {
1016 printk(KERN_WARNING "CIFS: prefix too long\n");
1017 return 1;
1018 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 } else if (strnicmp(data, "iocharset", 9) == 0) {
1020 if (!value || !*value) {
1021 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
1022 return 1; /* needs_arg; */
1023 }
1024 if (strnlen(value, 65) < 65) {
1025 if(strnicmp(value,"default",7))
1026 vol->iocharset = value;
1027 /* if iocharset not set load_nls_default used by caller */
1028 cFYI(1, ("iocharset set to %s",value));
1029 } else {
1030 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
1031 return 1;
1032 }
1033 } else if (strnicmp(data, "uid", 3) == 0) {
1034 if (value && *value) {
1035 vol->linux_uid =
1036 simple_strtoul(value, &value, 0);
1037 }
1038 } else if (strnicmp(data, "gid", 3) == 0) {
1039 if (value && *value) {
1040 vol->linux_gid =
1041 simple_strtoul(value, &value, 0);
1042 }
1043 } else if (strnicmp(data, "file_mode", 4) == 0) {
1044 if (value && *value) {
1045 vol->file_mode =
1046 simple_strtoul(value, &value, 0);
1047 }
1048 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1049 if (value && *value) {
1050 vol->dir_mode =
1051 simple_strtoul(value, &value, 0);
1052 }
1053 } else if (strnicmp(data, "dirmode", 4) == 0) {
1054 if (value && *value) {
1055 vol->dir_mode =
1056 simple_strtoul(value, &value, 0);
1057 }
1058 } else if (strnicmp(data, "port", 4) == 0) {
1059 if (value && *value) {
1060 vol->port =
1061 simple_strtoul(value, &value, 0);
1062 }
1063 } else if (strnicmp(data, "rsize", 5) == 0) {
1064 if (value && *value) {
1065 vol->rsize =
1066 simple_strtoul(value, &value, 0);
1067 }
1068 } else if (strnicmp(data, "wsize", 5) == 0) {
1069 if (value && *value) {
1070 vol->wsize =
1071 simple_strtoul(value, &value, 0);
1072 }
1073 } else if (strnicmp(data, "sockopt", 5) == 0) {
1074 if (value && *value) {
1075 vol->sockopt =
1076 simple_strtoul(value, &value, 0);
1077 }
1078 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1079 if (!value || !*value || (*value == ' ')) {
1080 cFYI(1,("invalid (empty) netbiosname specified"));
1081 } else {
1082 memset(vol->source_rfc1001_name,0x20,15);
1083 for(i=0;i<15;i++) {
1084 /* BB are there cases in which a comma can be
1085 valid in this workstation netbios name (and need
1086 special handling)? */
1087
1088 /* We do not uppercase netbiosname for user */
1089 if (value[i]==0)
1090 break;
1091 else
1092 vol->source_rfc1001_name[i] = value[i];
1093 }
1094 /* The string has 16th byte zero still from
1095 set at top of the function */
1096 if((i==15) && (value[i] != 0))
Steve Frencha10faeb22005-08-22 21:38:31 -07001097 printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
1098 }
1099 } else if (strnicmp(data, "servern", 7) == 0) {
1100 /* servernetbiosname specified override *SMBSERVER */
1101 if (!value || !*value || (*value == ' ')) {
1102 cFYI(1,("empty server netbiosname specified"));
1103 } else {
1104 /* last byte, type, is 0x20 for servr type */
1105 memset(vol->target_rfc1001_name,0x20,16);
1106
1107 for(i=0;i<15;i++) {
1108 /* BB are there cases in which a comma can be
1109 valid in this workstation netbios name (and need
1110 special handling)? */
1111
1112 /* user or mount helper must uppercase netbiosname */
1113 if (value[i]==0)
1114 break;
1115 else
1116 vol->target_rfc1001_name[i] = value[i];
1117 }
1118 /* The string has 16th byte zero still from
1119 set at top of the function */
1120 if((i==15) && (value[i] != 0))
1121 printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 }
1123 } else if (strnicmp(data, "credentials", 4) == 0) {
1124 /* ignore */
1125 } else if (strnicmp(data, "version", 3) == 0) {
1126 /* ignore */
1127 } else if (strnicmp(data, "guest",5) == 0) {
1128 /* ignore */
1129 } else if (strnicmp(data, "rw", 2) == 0) {
1130 vol->rw = TRUE;
1131 } else if ((strnicmp(data, "suid", 4) == 0) ||
1132 (strnicmp(data, "nosuid", 6) == 0) ||
1133 (strnicmp(data, "exec", 4) == 0) ||
1134 (strnicmp(data, "noexec", 6) == 0) ||
1135 (strnicmp(data, "nodev", 5) == 0) ||
1136 (strnicmp(data, "noauto", 6) == 0) ||
1137 (strnicmp(data, "dev", 3) == 0)) {
1138 /* The mount tool or mount.cifs helper (if present)
1139 uses these opts to set flags, and the flags are read
1140 by the kernel vfs layer before we get here (ie
1141 before read super) so there is no point trying to
1142 parse these options again and set anything and it
1143 is ok to just ignore them */
1144 continue;
1145 } else if (strnicmp(data, "ro", 2) == 0) {
1146 vol->rw = FALSE;
1147 } else if (strnicmp(data, "hard", 4) == 0) {
1148 vol->retry = 1;
1149 } else if (strnicmp(data, "soft", 4) == 0) {
1150 vol->retry = 0;
1151 } else if (strnicmp(data, "perm", 4) == 0) {
1152 vol->noperm = 0;
1153 } else if (strnicmp(data, "noperm", 6) == 0) {
1154 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001155 } else if (strnicmp(data, "mapchars", 8) == 0) {
1156 vol->remap = 1;
1157 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1158 vol->remap = 0;
Steve Frenchd7245c22005-07-14 18:25:12 -05001159 } else if (strnicmp(data, "sfu", 3) == 0) {
1160 vol->sfu_emul = 1;
1161 } else if (strnicmp(data, "nosfu", 5) == 0) {
1162 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001163 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1164 vol->posix_paths = 1;
1165 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1166 vol->posix_paths = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001167 } else if ((strnicmp(data, "nocase", 6) == 0) ||
1168 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001169 vol->nocase = 1;
1170 } else if (strnicmp(data, "brl", 3) == 0) {
1171 vol->nobrl = 0;
Steve Frenchcb8be642005-08-30 15:25:52 -07001172 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001173 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001174 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001175 /* turn off mandatory locking in mode
1176 if remote locking is turned off since the
1177 local vfs will do advisory */
1178 if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1179 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 } else if (strnicmp(data, "setuids", 7) == 0) {
1181 vol->setuids = 1;
1182 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1183 vol->setuids = 0;
1184 } else if (strnicmp(data, "nohard", 6) == 0) {
1185 vol->retry = 0;
1186 } else if (strnicmp(data, "nosoft", 6) == 0) {
1187 vol->retry = 1;
1188 } else if (strnicmp(data, "nointr", 6) == 0) {
1189 vol->intr = 0;
1190 } else if (strnicmp(data, "intr", 4) == 0) {
1191 vol->intr = 1;
1192 } else if (strnicmp(data, "serverino",7) == 0) {
1193 vol->server_ino = 1;
1194 } else if (strnicmp(data, "noserverino",9) == 0) {
1195 vol->server_ino = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08001196 } else if (strnicmp(data, "cifsacl",7) == 0) {
1197 vol->cifs_acl = 1;
1198 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1199 vol->cifs_acl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 } else if (strnicmp(data, "acl",3) == 0) {
1201 vol->no_psx_acl = 0;
1202 } else if (strnicmp(data, "noacl",5) == 0) {
1203 vol->no_psx_acl = 1;
Steve French750d1152006-06-27 06:28:30 +00001204 } else if (strnicmp(data, "sign",4) == 0) {
1205 vol->secFlg |= CIFSSEC_MUST_SIGN;
1206/* } else if (strnicmp(data, "seal",4) == 0) {
1207 vol->secFlg |= CIFSSEC_MUST_SEAL; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 } else if (strnicmp(data, "direct",6) == 0) {
1209 vol->direct_io = 1;
1210 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1211 vol->direct_io = 1;
1212 } else if (strnicmp(data, "in6_addr",8) == 0) {
1213 if (!value || !*value) {
1214 vol->in6_addr = NULL;
1215 } else if (strnlen(value, 49) == 48) {
1216 vol->in6_addr = value;
1217 } else {
1218 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1219 return 1;
1220 }
1221 } else if (strnicmp(data, "noac", 4) == 0) {
1222 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1223 } else
1224 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1225 }
1226 if (vol->UNC == NULL) {
1227 if(devname == NULL) {
1228 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1229 return 1;
1230 }
1231 if ((temp_len = strnlen(devname, 300)) < 300) {
1232 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1233 if(vol->UNC == NULL)
1234 return 1;
1235 strcpy(vol->UNC,devname);
1236 if (strncmp(vol->UNC, "//", 2) == 0) {
1237 vol->UNC[0] = '\\';
1238 vol->UNC[1] = '\\';
1239 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1240 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1241 return 1;
1242 }
1243 } else {
1244 printk(KERN_WARNING "CIFS: UNC name too long\n");
1245 return 1;
1246 }
1247 }
1248 if(vol->UNCip == NULL)
1249 vol->UNCip = &vol->UNC[2];
1250
1251 return 0;
1252}
1253
1254static struct cifsSesInfo *
1255cifs_find_tcp_session(struct in_addr * target_ip_addr,
1256 struct in6_addr *target_ip6_addr,
1257 char *userName, struct TCP_Server_Info **psrvTcp)
1258{
1259 struct list_head *tmp;
1260 struct cifsSesInfo *ses;
1261 *psrvTcp = NULL;
1262 read_lock(&GlobalSMBSeslock);
1263
1264 list_for_each(tmp, &GlobalSMBSessionList) {
1265 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1266 if (ses->server) {
1267 if((target_ip_addr &&
1268 (ses->server->addr.sockAddr.sin_addr.s_addr
1269 == target_ip_addr->s_addr)) || (target_ip6_addr
1270 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1271 target_ip6_addr,sizeof(*target_ip6_addr)))){
1272 /* BB lock server and tcp session and increment use count here?? */
1273 *psrvTcp = ses->server; /* found a match on the TCP session */
1274 /* BB check if reconnection needed */
1275 if (strncmp
1276 (ses->userName, userName,
1277 MAX_USERNAME_SIZE) == 0){
1278 read_unlock(&GlobalSMBSeslock);
1279 return ses; /* found exact match on both tcp and SMB sessions */
1280 }
1281 }
1282 }
1283 /* else tcp and smb sessions need reconnection */
1284 }
1285 read_unlock(&GlobalSMBSeslock);
1286 return NULL;
1287}
1288
1289static struct cifsTconInfo *
1290find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1291{
1292 struct list_head *tmp;
1293 struct cifsTconInfo *tcon;
1294
1295 read_lock(&GlobalSMBSeslock);
1296 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001297 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1299 if (tcon->ses) {
1300 if (tcon->ses->server) {
1301 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001302 ("old ip addr: %x == new ip %x ?",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 tcon->ses->server->addr.sockAddr.sin_addr.
1304 s_addr, new_target_ip_addr));
1305 if (tcon->ses->server->addr.sockAddr.sin_addr.
1306 s_addr == new_target_ip_addr) {
Steve Frenche466e482006-08-15 13:07:18 +00001307 /* BB lock tcon, server and tcp session and increment use count here? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 /* found a match on the TCP session */
1309 /* BB check if reconnection needed */
Steve Frenche466e482006-08-15 13:07:18 +00001310 cFYI(1,("IP match, old UNC: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 tcon->treeName, uncName));
1312 if (strncmp
1313 (tcon->treeName, uncName,
1314 MAX_TREE_SIZE) == 0) {
1315 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001316 ("and old usr: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 tcon->treeName, uncName));
1318 if (strncmp
1319 (tcon->ses->userName,
1320 userName,
1321 MAX_USERNAME_SIZE) == 0) {
1322 read_unlock(&GlobalSMBSeslock);
Steve Frenche466e482006-08-15 13:07:18 +00001323 /* matched smb session
1324 (user name */
1325 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 }
1327 }
1328 }
1329 }
1330 }
1331 }
1332 read_unlock(&GlobalSMBSeslock);
1333 return NULL;
1334}
1335
1336int
1337connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001338 const char *old_path, const struct nls_table *nls_codepage,
1339 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340{
1341 unsigned char *referrals = NULL;
1342 unsigned int num_referrals;
1343 int rc = 0;
1344
1345 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001346 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
1348 /* BB Add in code to: if valid refrl, if not ip address contact
1349 the helper that resolves tcp names, mount to it, try to
1350 tcon to it unmount it if fail */
1351
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001352 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
1354 return rc;
1355}
1356
1357int
1358get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1359 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001360 unsigned int *pnum_referrals,
1361 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362{
1363 char *temp_unc;
1364 int rc = 0;
1365
1366 *pnum_referrals = 0;
1367
1368 if (pSesInfo->ipc_tid == 0) {
1369 temp_unc = kmalloc(2 /* for slashes */ +
1370 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1371 + 1 + 4 /* slash IPC$ */ + 2,
1372 GFP_KERNEL);
1373 if (temp_unc == NULL)
1374 return -ENOMEM;
1375 temp_unc[0] = '\\';
1376 temp_unc[1] = '\\';
1377 strcpy(temp_unc + 2, pSesInfo->serverName);
1378 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1379 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1380 cFYI(1,
1381 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1382 kfree(temp_unc);
1383 }
1384 if (rc == 0)
1385 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001386 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
1388 return rc;
1389}
1390
1391/* See RFC1001 section 14 on representation of Netbios names */
1392static void rfc1002mangle(char * target,char * source, unsigned int length)
1393{
1394 unsigned int i,j;
1395
1396 for(i=0,j=0;i<(length);i++) {
1397 /* mask a nibble at a time and encode */
1398 target[j] = 'A' + (0x0F & (source[i] >> 4));
1399 target[j+1] = 'A' + (0x0F & source[i]);
1400 j+=2;
1401 }
1402
1403}
1404
1405
1406static int
1407ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001408 char * netbios_name, char * target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409{
1410 int rc = 0;
1411 int connected = 0;
1412 __be16 orig_port = 0;
1413
1414 if(*csocket == NULL) {
1415 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1416 if (rc < 0) {
1417 cERROR(1, ("Error %d creating socket",rc));
1418 *csocket = NULL;
1419 return rc;
1420 } else {
1421 /* BB other socket options to set KEEPALIVE, NODELAY? */
1422 cFYI(1,("Socket created"));
1423 (*csocket)->sk->sk_allocation = GFP_NOFS;
1424 }
1425 }
1426
1427 psin_server->sin_family = AF_INET;
1428 if(psin_server->sin_port) { /* user overrode default port */
1429 rc = (*csocket)->ops->connect(*csocket,
1430 (struct sockaddr *) psin_server,
1431 sizeof (struct sockaddr_in),0);
1432 if (rc >= 0)
1433 connected = 1;
1434 }
1435
1436 if(!connected) {
1437 /* save original port so we can retry user specified port
1438 later if fall back ports fail this time */
1439 orig_port = psin_server->sin_port;
1440
1441 /* do not retry on the same port we just failed on */
1442 if(psin_server->sin_port != htons(CIFS_PORT)) {
1443 psin_server->sin_port = htons(CIFS_PORT);
1444
1445 rc = (*csocket)->ops->connect(*csocket,
1446 (struct sockaddr *) psin_server,
1447 sizeof (struct sockaddr_in),0);
1448 if (rc >= 0)
1449 connected = 1;
1450 }
1451 }
1452 if (!connected) {
1453 psin_server->sin_port = htons(RFC1001_PORT);
1454 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1455 psin_server, sizeof (struct sockaddr_in),0);
1456 if (rc >= 0)
1457 connected = 1;
1458 }
1459
1460 /* give up here - unless we want to retry on different
1461 protocol families some day */
1462 if (!connected) {
1463 if(orig_port)
1464 psin_server->sin_port = orig_port;
1465 cFYI(1,("Error %d connecting to server via ipv4",rc));
1466 sock_release(*csocket);
1467 *csocket = NULL;
1468 return rc;
1469 }
1470 /* Eventually check for other socket options to change from
1471 the default. sock_setsockopt not used because it expects
1472 user space buffer */
Steve Frenchb387eae2005-10-10 14:21:15 -07001473 cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
1474 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001476 /* make the bufsizes depend on wsize/rsize and max requests */
1477 if((*csocket)->sk->sk_sndbuf < (200 * 1024))
1478 (*csocket)->sk->sk_sndbuf = 200 * 1024;
1479 if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
1480 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481
1482 /* send RFC1001 sessinit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1484 /* some servers require RFC1001 sessinit before sending
1485 negprot - BB check reconnection in case where second
1486 sessinit is sent but no second negprot */
1487 struct rfc1002_session_packet * ses_init_buf;
1488 struct smb_hdr * smb_buf;
Pekka Enberge915fc42005-09-06 15:18:35 -07001489 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 if(ses_init_buf) {
1491 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frencha10faeb22005-08-22 21:38:31 -07001492 if(target_name && (target_name[0] != 0)) {
1493 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1494 target_name, 16);
1495 } else {
1496 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1497 DEFAULT_CIFS_CALLED_NAME,16);
1498 }
1499
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 ses_init_buf->trailer.session_req.calling_len = 32;
1501 /* calling name ends in null (byte 16) from old smb
1502 convention. */
1503 if(netbios_name && (netbios_name[0] !=0)) {
1504 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1505 netbios_name,16);
1506 } else {
1507 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1508 "LINUX_CIFS_CLNT",16);
1509 }
1510 ses_init_buf->trailer.session_req.scope1 = 0;
1511 ses_init_buf->trailer.session_req.scope2 = 0;
1512 smb_buf = (struct smb_hdr *)ses_init_buf;
1513 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1514 smb_buf->smb_buf_length = 0x81000044;
1515 rc = smb_send(*csocket, smb_buf, 0x44,
1516 (struct sockaddr *)psin_server);
1517 kfree(ses_init_buf);
Steve French083d3a2c2006-03-03 09:53:36 +00001518 msleep(1); /* RFC1001 layer in at least one server
1519 requires very short break before negprot
1520 presumably because not expecting negprot
1521 to follow so fast. This is a simple
1522 solution that works without
1523 complicating the code and causes no
1524 significant slowing down on mount
1525 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 }
1527 /* else the negprot may still work without this
1528 even though malloc failed */
1529
1530 }
1531
1532 return rc;
1533}
1534
1535static int
1536ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1537{
1538 int rc = 0;
1539 int connected = 0;
1540 __be16 orig_port = 0;
1541
1542 if(*csocket == NULL) {
1543 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1544 if (rc < 0) {
1545 cERROR(1, ("Error %d creating ipv6 socket",rc));
1546 *csocket = NULL;
1547 return rc;
1548 } else {
1549 /* BB other socket options to set KEEPALIVE, NODELAY? */
1550 cFYI(1,("ipv6 Socket created"));
1551 (*csocket)->sk->sk_allocation = GFP_NOFS;
1552 }
1553 }
1554
1555 psin_server->sin6_family = AF_INET6;
1556
1557 if(psin_server->sin6_port) { /* user overrode default port */
1558 rc = (*csocket)->ops->connect(*csocket,
1559 (struct sockaddr *) psin_server,
1560 sizeof (struct sockaddr_in6),0);
1561 if (rc >= 0)
1562 connected = 1;
1563 }
1564
1565 if(!connected) {
1566 /* save original port so we can retry user specified port
1567 later if fall back ports fail this time */
1568
1569 orig_port = psin_server->sin6_port;
1570 /* do not retry on the same port we just failed on */
1571 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1572 psin_server->sin6_port = htons(CIFS_PORT);
1573
1574 rc = (*csocket)->ops->connect(*csocket,
1575 (struct sockaddr *) psin_server,
1576 sizeof (struct sockaddr_in6),0);
1577 if (rc >= 0)
1578 connected = 1;
1579 }
1580 }
1581 if (!connected) {
1582 psin_server->sin6_port = htons(RFC1001_PORT);
1583 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1584 psin_server, sizeof (struct sockaddr_in6),0);
1585 if (rc >= 0)
1586 connected = 1;
1587 }
1588
1589 /* give up here - unless we want to retry on different
1590 protocol families some day */
1591 if (!connected) {
1592 if(orig_port)
1593 psin_server->sin6_port = orig_port;
1594 cFYI(1,("Error %d connecting to server via ipv6",rc));
1595 sock_release(*csocket);
1596 *csocket = NULL;
1597 return rc;
1598 }
1599 /* Eventually check for other socket options to change from
1600 the default. sock_setsockopt not used because it expects
1601 user space buffer */
1602 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1603
1604 return rc;
1605}
1606
1607int
1608cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1609 char *mount_data, const char *devname)
1610{
1611 int rc = 0;
1612 int xid;
1613 int address_type = AF_INET;
1614 struct socket *csocket = NULL;
1615 struct sockaddr_in sin_server;
1616 struct sockaddr_in6 sin_server6;
1617 struct smb_vol volume_info;
1618 struct cifsSesInfo *pSesInfo = NULL;
1619 struct cifsSesInfo *existingCifsSes = NULL;
1620 struct cifsTconInfo *tcon = NULL;
1621 struct TCP_Server_Info *srvTcp = NULL;
1622
1623 xid = GetXid();
1624
1625/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1626
1627 memset(&volume_info,0,sizeof(struct smb_vol));
1628 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001629 kfree(volume_info.UNC);
1630 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001631 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 FreeXid(xid);
1633 return -EINVAL;
1634 }
1635
1636 if (volume_info.username) {
1637 /* BB fixme parse for domain name here */
1638 cFYI(1, ("Username: %s ", volume_info.username));
1639
1640 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001641 cifserror("No username specified");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 /* In userspace mount helper we can get user name from alternate
1643 locations such as env variables and files on disk */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001644 kfree(volume_info.UNC);
1645 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001646 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 FreeXid(xid);
1648 return -EINVAL;
1649 }
1650
1651 if (volume_info.UNCip && volume_info.UNC) {
1652 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1653
1654 if(rc <= 0) {
1655 /* not ipv4 address, try ipv6 */
1656 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1657 if(rc > 0)
1658 address_type = AF_INET6;
1659 } else {
1660 address_type = AF_INET;
1661 }
1662
1663 if(rc <= 0) {
1664 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001665 kfree(volume_info.UNC);
1666 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001667 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 FreeXid(xid);
1669 return -EINVAL;
1670 }
1671
1672 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1673 /* success */
1674 rc = 0;
1675 } else if (volume_info.UNCip){
1676 /* BB using ip addr as server name connect to the DFS root below */
1677 cERROR(1,("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001678 kfree(volume_info.UNC);
1679 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001680 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 FreeXid(xid);
1682 return -EINVAL;
1683 } else /* which servers DFS root would we conect to */ {
1684 cERROR(1,
Steve Frenchbf820672005-12-01 22:32:42 -08001685 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001686 kfree(volume_info.UNC);
1687 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001688 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 FreeXid(xid);
1690 return -EINVAL;
1691 }
1692
1693 /* this is needed for ASCII cp to Unicode converts */
1694 if(volume_info.iocharset == NULL) {
1695 cifs_sb->local_nls = load_nls_default();
1696 /* load_nls_default can not return null */
1697 } else {
1698 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1699 if(cifs_sb->local_nls == NULL) {
1700 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001701 kfree(volume_info.UNC);
1702 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001703 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 FreeXid(xid);
1705 return -ELIBACC;
1706 }
1707 }
1708
1709 if(address_type == AF_INET)
1710 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1711 NULL /* no ipv6 addr */,
1712 volume_info.username, &srvTcp);
1713 else if(address_type == AF_INET6)
1714 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1715 &sin_server6.sin6_addr,
1716 volume_info.username, &srvTcp);
1717 else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001718 kfree(volume_info.UNC);
1719 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001720 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 FreeXid(xid);
1722 return -EINVAL;
1723 }
1724
1725
1726 if (srvTcp) {
Steve Frenchbf820672005-12-01 22:32:42 -08001727 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 } else { /* create socket */
1729 if(volume_info.port)
1730 sin_server.sin_port = htons(volume_info.port);
1731 else
1732 sin_server.sin_port = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001733 rc = ipv4_connect(&sin_server,&csocket,
1734 volume_info.source_rfc1001_name,
1735 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 if (rc < 0) {
1737 cERROR(1,
1738 ("Error connecting to IPv4 socket. Aborting operation"));
1739 if(csocket != NULL)
1740 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001741 kfree(volume_info.UNC);
1742 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001743 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 FreeXid(xid);
1745 return rc;
1746 }
1747
1748 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1749 if (srvTcp == NULL) {
1750 rc = -ENOMEM;
1751 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001752 kfree(volume_info.UNC);
1753 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001754 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 FreeXid(xid);
1756 return rc;
1757 } else {
1758 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1759 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1760 atomic_set(&srvTcp->inFlight,0);
1761 /* BB Add code for ipv6 case too */
1762 srvTcp->ssocket = csocket;
1763 srvTcp->protocolType = IPV4;
1764 init_waitqueue_head(&srvTcp->response_q);
1765 init_waitqueue_head(&srvTcp->request_q);
1766 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1767 /* at this point we are the only ones with the pointer
1768 to the struct since the kernel thread not created yet
1769 so no need to spinlock this init of tcpStatus */
1770 srvTcp->tcpStatus = CifsNew;
1771 init_MUTEX(&srvTcp->tcpSem);
1772 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1773 CLONE_FS | CLONE_FILES | CLONE_VM);
1774 if(rc < 0) {
1775 rc = -ENOMEM;
1776 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001777 kfree(volume_info.UNC);
1778 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001779 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 FreeXid(xid);
1781 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001782 }
1783 wait_for_completion(&cifsd_complete);
1784 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001786 memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001787 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 }
1789 }
1790
1791 if (existingCifsSes) {
1792 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001793 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001794 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 /* volume_info.UNC freed at end of function */
1796 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001797 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 pSesInfo = sesInfoAlloc();
1799 if (pSesInfo == NULL)
1800 rc = -ENOMEM;
1801 else {
1802 pSesInfo->server = srvTcp;
1803 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1804 NIPQUAD(sin_server.sin_addr.s_addr));
1805 }
1806
1807 if (!rc){
1808 /* volume_info.password freed at unmount */
1809 if (volume_info.password)
1810 pSesInfo->password = volume_info.password;
1811 if (volume_info.username)
1812 strncpy(pSesInfo->userName,
1813 volume_info.username,MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001814 if (volume_info.domainname) {
1815 int len = strlen(volume_info.domainname);
1816 pSesInfo->domainName =
1817 kmalloc(len + 1, GFP_KERNEL);
1818 if(pSesInfo->domainName)
1819 strcpy(pSesInfo->domainName,
1820 volume_info.domainname);
1821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00001823 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00001825 /* BB FIXME need to pass vol->secFlgs BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1827 up(&pSesInfo->sesSem);
1828 if(!rc)
1829 atomic_inc(&srvTcp->socketUseCount);
1830 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001831 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 }
1833
1834 /* search for existing tcon to this server share */
1835 if (!rc) {
Steve French0ae0efa2005-10-10 10:57:19 -07001836 if(volume_info.rsize > CIFSMaxBufSize) {
1837 cERROR(1,("rsize %d too large, using MaxBufSize",
1838 volume_info.rsize));
1839 cifs_sb->rsize = CIFSMaxBufSize;
1840 } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07001842 else /* default */
1843 cifs_sb->rsize = CIFSMaxBufSize;
1844
1845 if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
1846 cERROR(1,("wsize %d too large using 4096 instead",
1847 volume_info.wsize));
1848 cifs_sb->wsize = 4096;
1849 } else if(volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 cifs_sb->wsize = volume_info.wsize;
1851 else
Steve French17cbbaf2006-01-24 20:26:48 -08001852 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08001853 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
1854 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08001855 /* old default of CIFSMaxBufSize was too small now
1856 that SMB Write2 can send multiple pages in kvec.
1857 RFC1001 does not describe what happens when frame
1858 bigger than 128K is sent so use that as max in
1859 conjunction with 52K kvec constraint on arch with 4K
1860 page size */
1861
Steve French6cec2ae2006-02-22 17:31:52 -06001862 if(cifs_sb->rsize < 2048) {
1863 cifs_sb->rsize = 2048;
1864 /* Windows ME may prefer this */
1865 cFYI(1,("readsize set to minimum 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 }
Steve French2fe87f02006-09-21 07:02:52 +00001867 /* calculate prepath */
1868 cifs_sb->prepath = volume_info.prepath;
1869 if(cifs_sb->prepath) {
1870 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
1871 cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
1872 volume_info.prepath = NULL;
1873 } else
1874 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 cifs_sb->mnt_uid = volume_info.linux_uid;
1876 cifs_sb->mnt_gid = volume_info.linux_gid;
1877 cifs_sb->mnt_file_mode = volume_info.file_mode;
1878 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve Frencheeac8042006-01-13 21:34:58 -08001879 cFYI(1,("file mode: 0x%x dir mode: 0x%x",
1880 cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
1882 if(volume_info.noperm)
1883 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1884 if(volume_info.setuids)
1885 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1886 if(volume_info.server_ino)
1887 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001888 if(volume_info.remap)
1889 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 if(volume_info.no_xattr)
1891 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve Frenchd7245c22005-07-14 18:25:12 -05001892 if(volume_info.sfu_emul)
1893 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001894 if(volume_info.nobrl)
1895 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French0a4b92c2006-01-12 15:44:21 -08001896 if(volume_info.cifs_acl)
1897 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Jeremy Allisonac670552005-06-22 17:26:35 -07001898
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 if(volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001900 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1902 }
1903
1904 tcon =
1905 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1906 volume_info.username);
1907 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08001908 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 /* we can have only one retry value for a connection
1910 to a share so for resources mounted more than once
1911 to the same server share the last value passed in
1912 for the retry flag is used */
1913 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001914 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 } else {
1916 tcon = tconInfoAlloc();
1917 if (tcon == NULL)
1918 rc = -ENOMEM;
1919 else {
1920 /* check for null share name ie connect to dfs root */
1921
1922 /* BB check if this works for exactly length three strings */
1923 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1924 && (strchr(volume_info.UNC + 3, '/') ==
1925 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001926 rc = connect_to_dfs_path(xid, pSesInfo,
1927 "", cifs_sb->local_nls,
1928 cifs_sb->mnt_cifs_flags &
1929 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001930 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 FreeXid(xid);
1932 return -ENODEV;
1933 } else {
1934 rc = CIFSTCon(xid, pSesInfo,
1935 volume_info.UNC,
1936 tcon, cifs_sb->local_nls);
1937 cFYI(1, ("CIFS Tcon rc = %d", rc));
1938 }
1939 if (!rc) {
1940 atomic_inc(&pSesInfo->inUse);
1941 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001942 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 }
1944 }
1945 }
1946 }
1947 if(pSesInfo) {
1948 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1949 sb->s_maxbytes = (u64) 1 << 63;
1950 } else
1951 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1952 }
1953
1954 sb->s_time_gran = 100;
1955
1956/* on error free sesinfo and tcon struct if needed */
1957 if (rc) {
1958 /* if session setup failed, use count is zero but
1959 we still need to free cifsd thread */
1960 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1961 spin_lock(&GlobalMid_Lock);
1962 srvTcp->tcpStatus = CifsExiting;
1963 spin_unlock(&GlobalMid_Lock);
Steve Frenchf1914012005-08-18 09:37:34 -07001964 if(srvTcp->tsk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 send_sig(SIGKILL,srvTcp->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001966 wait_for_completion(&cifsd_complete);
1967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 }
1969 /* If find_unc succeeded then rc == 0 so we can not end */
1970 if (tcon) /* up accidently freeing someone elses tcon struct */
1971 tconInfoFree(tcon);
1972 if (existingCifsSes == NULL) {
1973 if (pSesInfo) {
1974 if ((pSesInfo->server) &&
1975 (pSesInfo->status == CifsGood)) {
1976 int temp_rc;
1977 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1978 /* if the socketUseCount is now zero */
1979 if((temp_rc == -ESHUTDOWN) &&
Steve Frenchf1914012005-08-18 09:37:34 -07001980 (pSesInfo->server->tsk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 send_sig(SIGKILL,pSesInfo->server->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001982 wait_for_completion(&cifsd_complete);
1983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 } else
1985 cFYI(1, ("No session or bad tcon"));
1986 sesInfoFree(pSesInfo);
1987 /* pSesInfo = NULL; */
1988 }
1989 }
1990 } else {
1991 atomic_inc(&tcon->useCount);
1992 cifs_sb->tcon = tcon;
1993 tcon->ses = pSesInfo;
1994
Steve French82940a42006-03-02 03:24:57 +00001995 /* do not care if following two calls succeed - informational */
Steve French737b7582005-04-28 22:41:06 -07001996 CIFSSMBQFSDeviceInfo(xid, tcon);
1997 CIFSSMBQFSAttributeInfo(xid, tcon);
Steve French82940a42006-03-02 03:24:57 +00001998
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07002000 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French82940a42006-03-02 03:24:57 +00002001 __u64 cap =
2002 le64_to_cpu(tcon->fsUnixInfo.Capability);
2003 cap &= CIFS_UNIX_CAP_MASK;
2004 if(volume_info.no_psx_acl)
2005 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
2006 else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
2007 cFYI(1,("negotiated posix acl support"));
2008 sb->s_flags |= MS_POSIXACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 }
Jeremy Allisonac670552005-06-22 17:26:35 -07002010
Steve French82940a42006-03-02 03:24:57 +00002011 if(volume_info.posix_paths == 0)
2012 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
2013 else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
2014 cFYI(1,("negotiate posix pathnames"));
2015 cifs_sb->mnt_cifs_flags |=
2016 CIFS_MOUNT_POSIX_PATHS;
2017 }
2018
2019 cFYI(1,("Negotiate caps 0x%x",(int)cap));
Steve French3a5ff612006-07-14 22:37:11 +00002020#ifdef CONFIG_CIFS_DEBUG2
2021 if(cap & CIFS_UNIX_FCNTL_CAP)
2022 cFYI(1,("FCNTL cap"));
2023 if(cap & CIFS_UNIX_EXTATTR_CAP)
2024 cFYI(1,("EXTATTR cap"));
2025 if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
2026 cFYI(1,("POSIX path cap"));
2027 if(cap & CIFS_UNIX_XATTR_CAP)
2028 cFYI(1,("XATTR cap"));
2029 if(cap & CIFS_UNIX_POSIX_ACL_CAP)
2030 cFYI(1,("POSIX ACL cap"));
2031#endif /* CIFS_DEBUG2 */
Steve French82940a42006-03-02 03:24:57 +00002032 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
2033 cFYI(1,("setting capabilities failed"));
Jeremy Allisonac670552005-06-22 17:26:35 -07002034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 }
2036 }
Steve French3e844692005-10-03 13:37:24 -07002037 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2038 cifs_sb->wsize = min(cifs_sb->wsize,
2039 (tcon->ses->server->maxBuf -
2040 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002041 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2042 cifs_sb->rsize = min(cifs_sb->rsize,
2043 (tcon->ses->server->maxBuf -
2044 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 }
2046
2047 /* volume_info.password is freed above when existing session found
2048 (in which case it is not needed anymore) but when new sesion is created
2049 the password ptr is put in the new session structure (in which case the
2050 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002051 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002052 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 FreeXid(xid);
2054 return rc;
2055}
2056
2057static int
2058CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002059 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 const struct nls_table *nls_codepage)
2061{
2062 struct smb_hdr *smb_buffer;
2063 struct smb_hdr *smb_buffer_response;
2064 SESSION_SETUP_ANDX *pSMB;
2065 SESSION_SETUP_ANDX *pSMBr;
2066 char *bcc_ptr;
2067 char *user;
2068 char *domain;
2069 int rc = 0;
2070 int remaining_words = 0;
2071 int bytes_returned = 0;
2072 int len;
2073 __u32 capabilities;
2074 __u16 count;
2075
Steve Frencheeac8042006-01-13 21:34:58 -08002076 cFYI(1, ("In sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 if(ses == NULL)
2078 return -EINVAL;
2079 user = ses->userName;
2080 domain = ses->domainName;
2081 smb_buffer = cifs_buf_get();
2082 if (smb_buffer == NULL) {
2083 return -ENOMEM;
2084 }
2085 smb_buffer_response = smb_buffer;
2086 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2087
2088 /* send SMBsessionSetup here */
2089 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2090 NULL /* no tCon exists yet */ , 13 /* wct */ );
2091
Steve French1982c342005-08-17 12:38:22 -07002092 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 pSMB->req_no_secext.AndXCommand = 0xFF;
2094 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2095 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2096
2097 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2098 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2099
2100 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2101 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2102 if (ses->capabilities & CAP_UNICODE) {
2103 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2104 capabilities |= CAP_UNICODE;
2105 }
2106 if (ses->capabilities & CAP_STATUS32) {
2107 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2108 capabilities |= CAP_STATUS32;
2109 }
2110 if (ses->capabilities & CAP_DFS) {
2111 smb_buffer->Flags2 |= SMBFLG2_DFS;
2112 capabilities |= CAP_DFS;
2113 }
2114 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2115
2116 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002117 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118
2119 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002120 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002122 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2123 bcc_ptr += CIFS_SESS_KEY_SIZE;
2124 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2125 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126
2127 if (ses->capabilities & CAP_UNICODE) {
2128 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2129 *bcc_ptr = 0;
2130 bcc_ptr++;
2131 }
2132 if(user == NULL)
Steve French39798772006-05-31 22:40:51 +00002133 bytes_returned = 0; /* skip null user */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 else
2135 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002136 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 nls_codepage);
2138 /* convert number of 16 bit words to bytes */
2139 bcc_ptr += 2 * bytes_returned;
2140 bcc_ptr += 2; /* trailing null */
2141 if (domain == NULL)
2142 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002143 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 "CIFS_LINUX_DOM", 32, nls_codepage);
2145 else
2146 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002147 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 nls_codepage);
2149 bcc_ptr += 2 * bytes_returned;
2150 bcc_ptr += 2;
2151 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002152 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 32, nls_codepage);
2154 bcc_ptr += 2 * bytes_returned;
2155 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002156 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 32, nls_codepage);
2158 bcc_ptr += 2 * bytes_returned;
2159 bcc_ptr += 2;
2160 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002161 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 64, nls_codepage);
2163 bcc_ptr += 2 * bytes_returned;
2164 bcc_ptr += 2;
2165 } else {
2166 if(user != NULL) {
2167 strncpy(bcc_ptr, user, 200);
2168 bcc_ptr += strnlen(user, 200);
2169 }
2170 *bcc_ptr = 0;
2171 bcc_ptr++;
2172 if (domain == NULL) {
2173 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2174 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2175 } else {
2176 strncpy(bcc_ptr, domain, 64);
2177 bcc_ptr += strnlen(domain, 64);
2178 *bcc_ptr = 0;
2179 bcc_ptr++;
2180 }
2181 strcpy(bcc_ptr, "Linux version ");
2182 bcc_ptr += strlen("Linux version ");
2183 strcpy(bcc_ptr, system_utsname.release);
2184 bcc_ptr += strlen(system_utsname.release) + 1;
2185 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2186 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2187 }
2188 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2189 smb_buffer->smb_buf_length += count;
2190 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2191
2192 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2193 &bytes_returned, 1);
2194 if (rc) {
2195/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2196 } else if ((smb_buffer_response->WordCount == 3)
2197 || (smb_buffer_response->WordCount == 4)) {
2198 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2199 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2200 if (action & GUEST_LOGIN)
2201 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2202 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2203 cFYI(1, ("UID = %d ", ses->Suid));
2204 /* response can have either 3 or 4 word count - Samba sends 3 */
2205 bcc_ptr = pByteArea(smb_buffer_response);
2206 if ((pSMBr->resp.hdr.WordCount == 3)
2207 || ((pSMBr->resp.hdr.WordCount == 4)
2208 && (blob_len < pSMBr->resp.ByteCount))) {
2209 if (pSMBr->resp.hdr.WordCount == 4)
2210 bcc_ptr += blob_len;
2211
2212 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2213 if ((long) (bcc_ptr) % 2) {
2214 remaining_words =
2215 (BCC(smb_buffer_response) - 1) /2;
2216 bcc_ptr++; /* Unicode strings must be word aligned */
2217 } else {
2218 remaining_words =
2219 BCC(smb_buffer_response) / 2;
2220 }
2221 len =
2222 UniStrnlen((wchar_t *) bcc_ptr,
2223 remaining_words - 1);
2224/* We look for obvious messed up bcc or strings in response so we do not go off
2225 the end since (at least) WIN2K and Windows XP have a major bug in not null
2226 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002227 if(ses->serverOS)
2228 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002229 ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002230 if(ses->serverOS == NULL)
2231 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002233 (__le16 *)bcc_ptr, len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 bcc_ptr += 2 * (len + 1);
2235 remaining_words -= len + 1;
2236 ses->serverOS[2 * len] = 0;
2237 ses->serverOS[1 + (2 * len)] = 0;
2238 if (remaining_words > 0) {
2239 len = UniStrnlen((wchar_t *)bcc_ptr,
2240 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002241 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002242 ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002243 if(ses->serverNOS == NULL)
2244 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 cifs_strfromUCS_le(ses->serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002246 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 bcc_ptr += 2 * (len + 1);
2248 ses->serverNOS[2 * len] = 0;
2249 ses->serverNOS[1 + (2 * len)] = 0;
2250 if(strncmp(ses->serverNOS,
2251 "NT LAN Manager 4",16) == 0) {
2252 cFYI(1,("NT4 server"));
2253 ses->flags |= CIFS_SES_NT4;
2254 }
2255 remaining_words -= len + 1;
2256 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002257 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00002259 if(ses->serverDomain)
2260 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002262 kzalloc(2*(len+1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002263 if(ses->serverDomain == NULL)
2264 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 cifs_strfromUCS_le(ses->serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002266 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 bcc_ptr += 2 * (len + 1);
2268 ses->serverDomain[2*len] = 0;
2269 ses->serverDomain[1+(2*len)] = 0;
2270 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002271 else {
2272 if(ses->serverDomain)
2273 kfree(ses->serverDomain);
Steve French433dc242005-04-28 22:41:08 -07002274 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002275 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002278 /* if these kcallocs fail not much we
2279 can do, but better to not fail the
2280 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002281 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002283 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002284 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002286 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 }
2288 } else { /* ASCII */
2289 len = strnlen(bcc_ptr, 1024);
2290 if (((long) bcc_ptr + len) - (long)
2291 pByteArea(smb_buffer_response)
2292 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002293 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002294 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002295 if(ses->serverOS == NULL)
2296 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 strncpy(ses->serverOS,bcc_ptr, len);
2298
2299 bcc_ptr += len;
2300 bcc_ptr[0] = 0; /* null terminate the string */
2301 bcc_ptr++;
2302
2303 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002304 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002305 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002306 if(ses->serverNOS == NULL)
2307 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 strncpy(ses->serverNOS, bcc_ptr, len);
2309 bcc_ptr += len;
2310 bcc_ptr[0] = 0;
2311 bcc_ptr++;
2312
2313 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002314 if(ses->serverDomain)
2315 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07002316 ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002317 if(ses->serverDomain == NULL)
2318 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 strncpy(ses->serverDomain, bcc_ptr, len);
2320 bcc_ptr += len;
2321 bcc_ptr[0] = 0;
2322 bcc_ptr++;
2323 } else
2324 cFYI(1,
2325 ("Variable field of length %d extends beyond end of smb ",
2326 len));
2327 }
2328 } else {
2329 cERROR(1,
2330 (" Security Blob Length extends beyond end of SMB"));
2331 }
2332 } else {
2333 cERROR(1,
2334 (" Invalid Word count %d: ",
2335 smb_buffer_response->WordCount));
2336 rc = -EIO;
2337 }
Steve French433dc242005-04-28 22:41:08 -07002338sesssetup_nomem: /* do not return an error on nomem for the info strings,
2339 since that could make reconnection harder, and
2340 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 if (smb_buffer)
2342 cifs_buf_release(smb_buffer);
2343
2344 return rc;
2345}
2346
2347static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2349 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2350 const struct nls_table *nls_codepage)
2351{
2352 struct smb_hdr *smb_buffer;
2353 struct smb_hdr *smb_buffer_response;
2354 SESSION_SETUP_ANDX *pSMB;
2355 SESSION_SETUP_ANDX *pSMBr;
2356 char *bcc_ptr;
2357 char *domain;
2358 int rc = 0;
2359 int remaining_words = 0;
2360 int bytes_returned = 0;
2361 int len;
2362 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2363 PNEGOTIATE_MESSAGE SecurityBlob;
2364 PCHALLENGE_MESSAGE SecurityBlob2;
2365 __u32 negotiate_flags, capabilities;
2366 __u16 count;
2367
Steve French12b3b8f2006-02-09 21:12:47 +00002368 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 if(ses == NULL)
2370 return -EINVAL;
2371 domain = ses->domainName;
2372 *pNTLMv2_flag = FALSE;
2373 smb_buffer = cifs_buf_get();
2374 if (smb_buffer == NULL) {
2375 return -ENOMEM;
2376 }
2377 smb_buffer_response = smb_buffer;
2378 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2379 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2380
2381 /* send SMBsessionSetup here */
2382 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2383 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002384
2385 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2387 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2388
2389 pSMB->req.AndXCommand = 0xFF;
2390 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2391 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2392
2393 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2394 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2395
2396 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2397 CAP_EXTENDED_SECURITY;
2398 if (ses->capabilities & CAP_UNICODE) {
2399 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2400 capabilities |= CAP_UNICODE;
2401 }
2402 if (ses->capabilities & CAP_STATUS32) {
2403 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2404 capabilities |= CAP_STATUS32;
2405 }
2406 if (ses->capabilities & CAP_DFS) {
2407 smb_buffer->Flags2 |= SMBFLG2_DFS;
2408 capabilities |= CAP_DFS;
2409 }
2410 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2411
2412 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2413 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2414 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2415 SecurityBlob->MessageType = NtLmNegotiate;
2416 negotiate_flags =
2417 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002418 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2419 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2421 if(sign_CIFS_PDUs)
2422 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve French39798772006-05-31 22:40:51 +00002423/* if(ntlmv2_support)
2424 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 /* setup pointers to domain name and workstation name */
2426 bcc_ptr += SecurityBlobLength;
2427
2428 SecurityBlob->WorkstationName.Buffer = 0;
2429 SecurityBlob->WorkstationName.Length = 0;
2430 SecurityBlob->WorkstationName.MaximumLength = 0;
2431
Steve French12b3b8f2006-02-09 21:12:47 +00002432 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2433 along with username on auth request (ie the response to challenge) */
2434 SecurityBlob->DomainName.Buffer = 0;
2435 SecurityBlob->DomainName.Length = 0;
2436 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 if (ses->capabilities & CAP_UNICODE) {
2438 if ((long) bcc_ptr % 2) {
2439 *bcc_ptr = 0;
2440 bcc_ptr++;
2441 }
2442
2443 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002444 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 32, nls_codepage);
2446 bcc_ptr += 2 * bytes_returned;
2447 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002448 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 nls_codepage);
2450 bcc_ptr += 2 * bytes_returned;
2451 bcc_ptr += 2; /* null terminate Linux version */
2452 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002453 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 64, nls_codepage);
2455 bcc_ptr += 2 * bytes_returned;
2456 *(bcc_ptr + 1) = 0;
2457 *(bcc_ptr + 2) = 0;
2458 bcc_ptr += 2; /* null terminate network opsys string */
2459 *(bcc_ptr + 1) = 0;
2460 *(bcc_ptr + 2) = 0;
2461 bcc_ptr += 2; /* null domain */
2462 } else { /* ASCII */
2463 strcpy(bcc_ptr, "Linux version ");
2464 bcc_ptr += strlen("Linux version ");
2465 strcpy(bcc_ptr, system_utsname.release);
2466 bcc_ptr += strlen(system_utsname.release) + 1;
2467 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2468 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2469 bcc_ptr++; /* empty domain field */
2470 *bcc_ptr = 0;
2471 }
2472 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2473 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2474 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2475 smb_buffer->smb_buf_length += count;
2476 pSMB->req.ByteCount = cpu_to_le16(count);
2477
2478 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2479 &bytes_returned, 1);
2480
2481 if (smb_buffer_response->Status.CifsError ==
2482 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2483 rc = 0;
2484
2485 if (rc) {
2486/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2487 } else if ((smb_buffer_response->WordCount == 3)
2488 || (smb_buffer_response->WordCount == 4)) {
2489 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2490 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2491
2492 if (action & GUEST_LOGIN)
2493 cFYI(1, (" Guest login"));
2494 /* Do we want to set anything in SesInfo struct when guest login? */
2495
2496 bcc_ptr = pByteArea(smb_buffer_response);
2497 /* response can have either 3 or 4 word count - Samba sends 3 */
2498
2499 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2500 if (SecurityBlob2->MessageType != NtLmChallenge) {
2501 cFYI(1,
2502 ("Unexpected NTLMSSP message type received %d",
2503 SecurityBlob2->MessageType));
2504 } else if (ses) {
2505 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002506 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 if ((pSMBr->resp.hdr.WordCount == 3)
2508 || ((pSMBr->resp.hdr.WordCount == 4)
2509 && (blob_len <
2510 pSMBr->resp.ByteCount))) {
2511
2512 if (pSMBr->resp.hdr.WordCount == 4) {
2513 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002514 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 blob_len));
2516 }
2517
Steve French12b3b8f2006-02-09 21:12:47 +00002518 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519
2520 memcpy(ses->server->cryptKey,
2521 SecurityBlob2->Challenge,
2522 CIFS_CRYPTO_KEY_SIZE);
Steve French12b3b8f2006-02-09 21:12:47 +00002523 if(SecurityBlob2->NegotiateFlags &
2524 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 *pNTLMv2_flag = TRUE;
2526
2527 if((SecurityBlob2->NegotiateFlags &
2528 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2529 || (sign_CIFS_PDUs > 1))
2530 ses->server->secMode |=
2531 SECMODE_SIGN_REQUIRED;
2532 if ((SecurityBlob2->NegotiateFlags &
2533 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2534 ses->server->secMode |=
2535 SECMODE_SIGN_ENABLED;
2536
2537 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2538 if ((long) (bcc_ptr) % 2) {
2539 remaining_words =
2540 (BCC(smb_buffer_response)
2541 - 1) / 2;
2542 bcc_ptr++; /* Unicode strings must be word aligned */
2543 } else {
2544 remaining_words =
2545 BCC
2546 (smb_buffer_response) / 2;
2547 }
2548 len =
2549 UniStrnlen((wchar_t *) bcc_ptr,
2550 remaining_words - 1);
2551/* We look for obvious messed up bcc or strings in response so we do not go off
2552 the end since (at least) WIN2K and Windows XP have a major bug in not null
2553 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002554 if(ses->serverOS)
2555 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002557 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002559 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 bcc_ptr, len,
2561 nls_codepage);
2562 bcc_ptr += 2 * (len + 1);
2563 remaining_words -= len + 1;
2564 ses->serverOS[2 * len] = 0;
2565 ses->serverOS[1 + (2 * len)] = 0;
2566 if (remaining_words > 0) {
2567 len = UniStrnlen((wchar_t *)
2568 bcc_ptr,
2569 remaining_words
2570 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002571 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002573 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 GFP_KERNEL);
2575 cifs_strfromUCS_le(ses->
2576 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002577 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 bcc_ptr,
2579 len,
2580 nls_codepage);
2581 bcc_ptr += 2 * (len + 1);
2582 ses->serverNOS[2 * len] = 0;
2583 ses->serverNOS[1 +
2584 (2 * len)] = 0;
2585 remaining_words -= len + 1;
2586 if (remaining_words > 0) {
2587 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2588 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002589 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002591 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 (len +
2593 1),
2594 GFP_KERNEL);
2595 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002596 (ses->serverDomain,
2597 (__le16 *)bcc_ptr,
2598 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 bcc_ptr +=
2600 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002601 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002603 ses->serverDomain
2604 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 = 0;
2606 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002607 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002608 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002610 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002614 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002616 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002617 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002619 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 }
2621 } else { /* ASCII */
2622 len = strnlen(bcc_ptr, 1024);
2623 if (((long) bcc_ptr + len) - (long)
2624 pByteArea(smb_buffer_response)
2625 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00002626 if(ses->serverOS)
2627 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002629 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 GFP_KERNEL);
2631 strncpy(ses->serverOS,
2632 bcc_ptr, len);
2633
2634 bcc_ptr += len;
2635 bcc_ptr[0] = 0; /* null terminate string */
2636 bcc_ptr++;
2637
2638 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002639 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002641 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 GFP_KERNEL);
2643 strncpy(ses->serverNOS, bcc_ptr, len);
2644 bcc_ptr += len;
2645 bcc_ptr[0] = 0;
2646 bcc_ptr++;
2647
2648 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002649 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002651 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 GFP_KERNEL);
2653 strncpy(ses->serverDomain, bcc_ptr, len);
2654 bcc_ptr += len;
2655 bcc_ptr[0] = 0;
2656 bcc_ptr++;
2657 } else
2658 cFYI(1,
Steve French12b3b8f2006-02-09 21:12:47 +00002659 ("Variable field of length %d extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 len));
2661 }
2662 } else {
2663 cERROR(1,
2664 (" Security Blob Length extends beyond end of SMB"));
2665 }
2666 } else {
2667 cERROR(1, ("No session structure passed in."));
2668 }
2669 } else {
2670 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002671 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 smb_buffer_response->WordCount));
2673 rc = -EIO;
2674 }
2675
2676 if (smb_buffer)
2677 cifs_buf_release(smb_buffer);
2678
2679 return rc;
2680}
2681static int
2682CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2683 char *ntlm_session_key, int ntlmv2_flag,
2684 const struct nls_table *nls_codepage)
2685{
2686 struct smb_hdr *smb_buffer;
2687 struct smb_hdr *smb_buffer_response;
2688 SESSION_SETUP_ANDX *pSMB;
2689 SESSION_SETUP_ANDX *pSMBr;
2690 char *bcc_ptr;
2691 char *user;
2692 char *domain;
2693 int rc = 0;
2694 int remaining_words = 0;
2695 int bytes_returned = 0;
2696 int len;
2697 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2698 PAUTHENTICATE_MESSAGE SecurityBlob;
2699 __u32 negotiate_flags, capabilities;
2700 __u16 count;
2701
2702 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2703 if(ses == NULL)
2704 return -EINVAL;
2705 user = ses->userName;
2706 domain = ses->domainName;
2707 smb_buffer = cifs_buf_get();
2708 if (smb_buffer == NULL) {
2709 return -ENOMEM;
2710 }
2711 smb_buffer_response = smb_buffer;
2712 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2713 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2714
2715 /* send SMBsessionSetup here */
2716 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2717 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002718
2719 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2721 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2722 pSMB->req.AndXCommand = 0xFF;
2723 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2724 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2725
2726 pSMB->req.hdr.Uid = ses->Suid;
2727
2728 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2729 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2730
2731 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2732 CAP_EXTENDED_SECURITY;
2733 if (ses->capabilities & CAP_UNICODE) {
2734 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2735 capabilities |= CAP_UNICODE;
2736 }
2737 if (ses->capabilities & CAP_STATUS32) {
2738 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2739 capabilities |= CAP_STATUS32;
2740 }
2741 if (ses->capabilities & CAP_DFS) {
2742 smb_buffer->Flags2 |= SMBFLG2_DFS;
2743 capabilities |= CAP_DFS;
2744 }
2745 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2746
2747 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2748 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2749 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2750 SecurityBlob->MessageType = NtLmAuthenticate;
2751 bcc_ptr += SecurityBlobLength;
2752 negotiate_flags =
2753 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2754 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2755 0x80000000 | NTLMSSP_NEGOTIATE_128;
2756 if(sign_CIFS_PDUs)
2757 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2758 if(ntlmv2_flag)
2759 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2760
2761/* setup pointers to domain name and workstation name */
2762
2763 SecurityBlob->WorkstationName.Buffer = 0;
2764 SecurityBlob->WorkstationName.Length = 0;
2765 SecurityBlob->WorkstationName.MaximumLength = 0;
2766 SecurityBlob->SessionKey.Length = 0;
2767 SecurityBlob->SessionKey.MaximumLength = 0;
2768 SecurityBlob->SessionKey.Buffer = 0;
2769
2770 SecurityBlob->LmChallengeResponse.Length = 0;
2771 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2772 SecurityBlob->LmChallengeResponse.Buffer = 0;
2773
2774 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002775 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002777 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2778 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 SecurityBlob->NtChallengeResponse.Buffer =
2780 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002781 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2782 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
2784 if (ses->capabilities & CAP_UNICODE) {
2785 if (domain == NULL) {
2786 SecurityBlob->DomainName.Buffer = 0;
2787 SecurityBlob->DomainName.Length = 0;
2788 SecurityBlob->DomainName.MaximumLength = 0;
2789 } else {
2790 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002791 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 nls_codepage);
2793 len *= 2;
2794 SecurityBlob->DomainName.MaximumLength =
2795 cpu_to_le16(len);
2796 SecurityBlob->DomainName.Buffer =
2797 cpu_to_le32(SecurityBlobLength);
2798 bcc_ptr += len;
2799 SecurityBlobLength += len;
2800 SecurityBlob->DomainName.Length =
2801 cpu_to_le16(len);
2802 }
2803 if (user == NULL) {
2804 SecurityBlob->UserName.Buffer = 0;
2805 SecurityBlob->UserName.Length = 0;
2806 SecurityBlob->UserName.MaximumLength = 0;
2807 } else {
2808 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002809 cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 nls_codepage);
2811 len *= 2;
2812 SecurityBlob->UserName.MaximumLength =
2813 cpu_to_le16(len);
2814 SecurityBlob->UserName.Buffer =
2815 cpu_to_le32(SecurityBlobLength);
2816 bcc_ptr += len;
2817 SecurityBlobLength += len;
2818 SecurityBlob->UserName.Length =
2819 cpu_to_le16(len);
2820 }
2821
Steve Frenche89dc922005-11-11 15:18:19 -08002822 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 SecurityBlob->WorkstationName.Length *= 2;
2824 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2825 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2826 bcc_ptr += SecurityBlob->WorkstationName.Length;
2827 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2828 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2829
2830 if ((long) bcc_ptr % 2) {
2831 *bcc_ptr = 0;
2832 bcc_ptr++;
2833 }
2834 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002835 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 32, nls_codepage);
2837 bcc_ptr += 2 * bytes_returned;
2838 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002839 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 nls_codepage);
2841 bcc_ptr += 2 * bytes_returned;
2842 bcc_ptr += 2; /* null term version string */
2843 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002844 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 64, nls_codepage);
2846 bcc_ptr += 2 * bytes_returned;
2847 *(bcc_ptr + 1) = 0;
2848 *(bcc_ptr + 2) = 0;
2849 bcc_ptr += 2; /* null terminate network opsys string */
2850 *(bcc_ptr + 1) = 0;
2851 *(bcc_ptr + 2) = 0;
2852 bcc_ptr += 2; /* null domain */
2853 } else { /* ASCII */
2854 if (domain == NULL) {
2855 SecurityBlob->DomainName.Buffer = 0;
2856 SecurityBlob->DomainName.Length = 0;
2857 SecurityBlob->DomainName.MaximumLength = 0;
2858 } else {
2859 __u16 len;
2860 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2861 strncpy(bcc_ptr, domain, 63);
2862 len = strnlen(domain, 64);
2863 SecurityBlob->DomainName.MaximumLength =
2864 cpu_to_le16(len);
2865 SecurityBlob->DomainName.Buffer =
2866 cpu_to_le32(SecurityBlobLength);
2867 bcc_ptr += len;
2868 SecurityBlobLength += len;
2869 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2870 }
2871 if (user == NULL) {
2872 SecurityBlob->UserName.Buffer = 0;
2873 SecurityBlob->UserName.Length = 0;
2874 SecurityBlob->UserName.MaximumLength = 0;
2875 } else {
2876 __u16 len;
2877 strncpy(bcc_ptr, user, 63);
2878 len = strnlen(user, 64);
2879 SecurityBlob->UserName.MaximumLength =
2880 cpu_to_le16(len);
2881 SecurityBlob->UserName.Buffer =
2882 cpu_to_le32(SecurityBlobLength);
2883 bcc_ptr += len;
2884 SecurityBlobLength += len;
2885 SecurityBlob->UserName.Length = cpu_to_le16(len);
2886 }
2887 /* BB fill in our workstation name if known BB */
2888
2889 strcpy(bcc_ptr, "Linux version ");
2890 bcc_ptr += strlen("Linux version ");
2891 strcpy(bcc_ptr, system_utsname.release);
2892 bcc_ptr += strlen(system_utsname.release) + 1;
2893 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2894 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2895 bcc_ptr++; /* null domain */
2896 *bcc_ptr = 0;
2897 }
2898 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2899 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2900 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2901 smb_buffer->smb_buf_length += count;
2902 pSMB->req.ByteCount = cpu_to_le16(count);
2903
2904 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2905 &bytes_returned, 1);
2906 if (rc) {
2907/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2908 } else if ((smb_buffer_response->WordCount == 3)
2909 || (smb_buffer_response->WordCount == 4)) {
2910 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2911 __u16 blob_len =
2912 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2913 if (action & GUEST_LOGIN)
2914 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2915/* if(SecurityBlob2->MessageType != NtLm??){
2916 cFYI("Unexpected message type on auth response is %d "));
2917 } */
2918 if (ses) {
2919 cFYI(1,
2920 ("Does UID on challenge %d match auth response UID %d ",
2921 ses->Suid, smb_buffer_response->Uid));
2922 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2923 bcc_ptr = pByteArea(smb_buffer_response);
2924 /* response can have either 3 or 4 word count - Samba sends 3 */
2925 if ((pSMBr->resp.hdr.WordCount == 3)
2926 || ((pSMBr->resp.hdr.WordCount == 4)
2927 && (blob_len <
2928 pSMBr->resp.ByteCount))) {
2929 if (pSMBr->resp.hdr.WordCount == 4) {
2930 bcc_ptr +=
2931 blob_len;
2932 cFYI(1,
2933 ("Security Blob Length %d ",
2934 blob_len));
2935 }
2936
2937 cFYI(1,
2938 ("NTLMSSP response to Authenticate "));
2939
2940 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2941 if ((long) (bcc_ptr) % 2) {
2942 remaining_words =
2943 (BCC(smb_buffer_response)
2944 - 1) / 2;
2945 bcc_ptr++; /* Unicode strings must be word aligned */
2946 } else {
2947 remaining_words = BCC(smb_buffer_response) / 2;
2948 }
2949 len =
2950 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2951/* We look for obvious messed up bcc or strings in response so we do not go off
2952 the end since (at least) WIN2K and Windows XP have a major bug in not null
2953 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002954 if(ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00002955 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002957 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002959 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 bcc_ptr, len,
2961 nls_codepage);
2962 bcc_ptr += 2 * (len + 1);
2963 remaining_words -= len + 1;
2964 ses->serverOS[2 * len] = 0;
2965 ses->serverOS[1 + (2 * len)] = 0;
2966 if (remaining_words > 0) {
2967 len = UniStrnlen((wchar_t *)
2968 bcc_ptr,
2969 remaining_words
2970 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002971 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002973 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 GFP_KERNEL);
2975 cifs_strfromUCS_le(ses->
2976 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002977 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 bcc_ptr,
2979 len,
2980 nls_codepage);
2981 bcc_ptr += 2 * (len + 1);
2982 ses->serverNOS[2 * len] = 0;
2983 ses->serverNOS[1+(2*len)] = 0;
2984 remaining_words -= len + 1;
2985 if (remaining_words > 0) {
2986 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2987 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00002988 if(ses->serverDomain)
2989 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002991 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 (len +
2993 1),
2994 GFP_KERNEL);
2995 cifs_strfromUCS_le
2996 (ses->
2997 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002998 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 bcc_ptr, len,
3000 nls_codepage);
3001 bcc_ptr +=
3002 2 * (len + 1);
3003 ses->
3004 serverDomain[2
3005 * len]
3006 = 0;
3007 ses->
3008 serverDomain[1
3009 +
3010 (2
3011 *
3012 len)]
3013 = 0;
3014 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003015 else {
3016 if(ses->serverDomain)
3017 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003018 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003019 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 } else { /* no room so create dummy domain and NOS string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003021 if(ses->serverDomain)
3022 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003023 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003024 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003025 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 }
3027 } else { /* ASCII */
3028 len = strnlen(bcc_ptr, 1024);
3029 if (((long) bcc_ptr + len) -
3030 (long) pByteArea(smb_buffer_response)
3031 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00003032 if(ses->serverOS)
3033 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003034 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 strncpy(ses->serverOS,bcc_ptr, len);
3036
3037 bcc_ptr += len;
3038 bcc_ptr[0] = 0; /* null terminate the string */
3039 bcc_ptr++;
3040
3041 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003042 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003043 ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 strncpy(ses->serverNOS, bcc_ptr, len);
3045 bcc_ptr += len;
3046 bcc_ptr[0] = 0;
3047 bcc_ptr++;
3048
3049 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00003050 if(ses->serverDomain)
3051 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003052 ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 strncpy(ses->serverDomain, bcc_ptr, len);
3054 bcc_ptr += len;
3055 bcc_ptr[0] = 0;
3056 bcc_ptr++;
3057 } else
3058 cFYI(1,
3059 ("Variable field of length %d extends beyond end of smb ",
3060 len));
3061 }
3062 } else {
3063 cERROR(1,
3064 (" Security Blob Length extends beyond end of SMB"));
3065 }
3066 } else {
3067 cERROR(1, ("No session structure passed in."));
3068 }
3069 } else {
3070 cERROR(1,
3071 (" Invalid Word count %d: ",
3072 smb_buffer_response->WordCount));
3073 rc = -EIO;
3074 }
3075
3076 if (smb_buffer)
3077 cifs_buf_release(smb_buffer);
3078
3079 return rc;
3080}
3081
3082int
3083CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3084 const char *tree, struct cifsTconInfo *tcon,
3085 const struct nls_table *nls_codepage)
3086{
3087 struct smb_hdr *smb_buffer;
3088 struct smb_hdr *smb_buffer_response;
3089 TCONX_REQ *pSMB;
3090 TCONX_RSP *pSMBr;
3091 unsigned char *bcc_ptr;
3092 int rc = 0;
3093 int length;
3094 __u16 count;
3095
3096 if (ses == NULL)
3097 return -EIO;
3098
3099 smb_buffer = cifs_buf_get();
3100 if (smb_buffer == NULL) {
3101 return -ENOMEM;
3102 }
3103 smb_buffer_response = smb_buffer;
3104
3105 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3106 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003107
3108 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 smb_buffer->Uid = ses->Suid;
3110 pSMB = (TCONX_REQ *) smb_buffer;
3111 pSMBr = (TCONX_RSP *) smb_buffer_response;
3112
3113 pSMB->AndXCommand = 0xFF;
3114 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 bcc_ptr = &pSMB->Password[0];
Steve Frencheeac8042006-01-13 21:34:58 -08003116 if((ses->server->secMode) & SECMODE_USER) {
3117 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003118 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003119 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003120 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003121 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003122 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003123 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3124 specified as required (when that support is added to
3125 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003126 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003127 by Samba (not sure whether other servers allow
3128 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003129#ifdef CONFIG_CIFS_WEAK_PW_HASH
3130 if((extended_security & CIFSSEC_MAY_LANMAN) &&
3131 (ses->server->secType == LANMAN))
3132 calc_lanman_hash(ses, bcc_ptr);
3133 else
3134#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003135 SMBNTencrypt(ses->password,
3136 ses->server->cryptKey,
3137 bcc_ptr);
3138
Steve French7c7b25b2006-06-01 19:20:10 +00003139 bcc_ptr += CIFS_SESS_KEY_SIZE;
3140 if(ses->capabilities & CAP_UNICODE) {
3141 /* must align unicode strings */
3142 *bcc_ptr = 0; /* null byte password */
3143 bcc_ptr++;
3144 }
Steve Frencheeac8042006-01-13 21:34:58 -08003145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146
Steve Frencha878fb22006-05-30 18:04:19 +00003147 if(ses->server->secMode &
3148 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3150
3151 if (ses->capabilities & CAP_STATUS32) {
3152 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3153 }
3154 if (ses->capabilities & CAP_DFS) {
3155 smb_buffer->Flags2 |= SMBFLG2_DFS;
3156 }
3157 if (ses->capabilities & CAP_UNICODE) {
3158 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3159 length =
Steve Frencha878fb22006-05-30 18:04:19 +00003160 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3161 6 /* max utf8 char length in bytes */ *
3162 (/* server len*/ + 256 /* share len */), nls_codepage);
3163 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 bcc_ptr += 2; /* skip trailing null */
3165 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 strcpy(bcc_ptr, tree);
3167 bcc_ptr += strlen(tree) + 1;
3168 }
3169 strcpy(bcc_ptr, "?????");
3170 bcc_ptr += strlen("?????");
3171 bcc_ptr += 1;
3172 count = bcc_ptr - &pSMB->Password[0];
3173 pSMB->hdr.smb_buf_length += count;
3174 pSMB->ByteCount = cpu_to_le16(count);
3175
3176 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3177
3178 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3179 /* above now done in SendReceive */
3180 if ((rc == 0) && (tcon != NULL)) {
3181 tcon->tidStatus = CifsGood;
3182 tcon->tid = smb_buffer_response->Tid;
3183 bcc_ptr = pByteArea(smb_buffer_response);
3184 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3185 /* skip service field (NB: this field is always ASCII) */
3186 bcc_ptr += length + 1;
3187 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3188 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3189 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3190 if ((bcc_ptr + (2 * length)) -
3191 pByteArea(smb_buffer_response) <=
3192 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003193 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003195 kzalloc(length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 cifs_strfromUCS_le(tcon->nativeFileSystem,
Steve Frenche89dc922005-11-11 15:18:19 -08003197 (__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 length, nls_codepage);
3199 bcc_ptr += 2 * length;
3200 bcc_ptr[0] = 0; /* null terminate the string */
3201 bcc_ptr[1] = 0;
3202 bcc_ptr += 2;
3203 }
3204 /* else do not bother copying these informational fields */
3205 } else {
3206 length = strnlen(bcc_ptr, 1024);
3207 if ((bcc_ptr + length) -
3208 pByteArea(smb_buffer_response) <=
3209 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003210 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003212 kzalloc(length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 strncpy(tcon->nativeFileSystem, bcc_ptr,
3214 length);
3215 }
3216 /* else do not bother copying these informational fields */
3217 }
Steve French39798772006-05-31 22:40:51 +00003218 if(smb_buffer_response->WordCount == 3)
3219 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3220 else
3221 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3223 } else if ((rc == 0) && tcon == NULL) {
3224 /* all we need to save for IPC$ connection */
3225 ses->ipc_tid = smb_buffer_response->Tid;
3226 }
3227
3228 if (smb_buffer)
3229 cifs_buf_release(smb_buffer);
3230 return rc;
3231}
3232
3233int
3234cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3235{
3236 int rc = 0;
3237 int xid;
3238 struct cifsSesInfo *ses = NULL;
3239 struct task_struct *cifsd_task;
Steve French2fe87f02006-09-21 07:02:52 +00003240 char * tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
3242 xid = GetXid();
3243
3244 if (cifs_sb->tcon) {
3245 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3246 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3247 if (rc == -EBUSY) {
3248 FreeXid(xid);
3249 return 0;
3250 }
3251 tconInfoFree(cifs_sb->tcon);
3252 if ((ses) && (ses->server)) {
3253 /* save off task so we do not refer to ses later */
3254 cifsd_task = ses->server->tsk;
3255 cFYI(1, ("About to do SMBLogoff "));
3256 rc = CIFSSMBLogoff(xid, ses);
3257 if (rc == -EBUSY) {
3258 FreeXid(xid);
3259 return 0;
3260 } else if (rc == -ESHUTDOWN) {
3261 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf1914012005-08-18 09:37:34 -07003262 if(cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 send_sig(SIGKILL,cifsd_task,1);
Steve Frenchf1914012005-08-18 09:37:34 -07003264 wait_for_completion(&cifsd_complete);
3265 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 rc = 0;
3267 } /* else - we have an smb session
3268 left on this socket do not kill cifsd */
3269 } else
3270 cFYI(1, ("No session or bad tcon"));
3271 }
3272
3273 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003274 tmp = cifs_sb->prepath;
3275 cifs_sb->prepathlen = 0;
3276 cifs_sb->prepath = NULL;
3277 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003278 if (ses)
3279 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 if (ses)
3281 sesInfoFree(ses);
3282
3283 FreeXid(xid);
3284 return rc; /* BB check if we should always return zero here */
3285}
3286
3287int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3288 struct nls_table * nls_info)
3289{
3290 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003291 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003293 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294
3295 /* what if server changes its buffer size after dropping the session? */
3296 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3297 rc = CIFSSMBNegotiate(xid, pSesInfo);
3298 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3299 rc = CIFSSMBNegotiate(xid, pSesInfo);
3300 if(rc == -EAGAIN)
3301 rc = -EHOSTDOWN;
3302 }
3303 if(rc == 0) {
3304 spin_lock(&GlobalMid_Lock);
3305 if(pSesInfo->server->tcpStatus != CifsExiting)
3306 pSesInfo->server->tcpStatus = CifsGood;
3307 else
3308 rc = -EHOSTDOWN;
3309 spin_unlock(&GlobalMid_Lock);
3310
3311 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003312 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 }
3314 if (!rc) {
3315 pSesInfo->capabilities = pSesInfo->server->capabilities;
3316 if(linuxExtEnabled == 0)
3317 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003318 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3320 pSesInfo->server->secMode,
3321 pSesInfo->server->capabilities,
3322 pSesInfo->server->timeZone));
Steve French189acaa2006-06-23 02:33:48 +00003323 if(experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003324 rc = CIFS_SessSetup(xid, pSesInfo,
3325 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003326 else if (extended_security
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3328 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003329 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 } else if (extended_security
3331 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3332 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003333 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3335 pSesInfo,
3336 &ntlmv2_flag,
3337 nls_info);
3338 if (!rc) {
3339 if(ntlmv2_flag) {
3340 char * v2_response;
3341 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3342 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3343 nls_info)) {
3344 rc = -ENOMEM;
3345 goto ss_err_exit;
3346 } else
3347 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3348 if(v2_response) {
3349 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003350 /* if(first_time)
3351 cifs_calculate_ntlmv2_mac_key(
3352 pSesInfo->server->mac_signing_key,
3353 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 kfree(v2_response);
3355 /* BB Put dummy sig in SessSetup PDU? */
3356 } else {
3357 rc = -ENOMEM;
3358 goto ss_err_exit;
3359 }
3360
3361 } else {
3362 SMBNTencrypt(pSesInfo->password,
3363 pSesInfo->server->cryptKey,
3364 ntlm_session_key);
3365
Steve Frenchad009ac2005-04-28 22:41:05 -07003366 if(first_time)
3367 cifs_calculate_mac_key(
3368 pSesInfo->server->mac_signing_key,
3369 ntlm_session_key,
3370 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 }
3372 /* for better security the weaker lanman hash not sent
3373 in AuthSessSetup so we no longer calculate it */
3374
3375 rc = CIFSNTLMSSPAuthSessSetup(xid,
3376 pSesInfo,
3377 ntlm_session_key,
3378 ntlmv2_flag,
3379 nls_info);
3380 }
3381 } else { /* old style NTLM 0.12 session setup */
3382 SMBNTencrypt(pSesInfo->password,
3383 pSesInfo->server->cryptKey,
3384 ntlm_session_key);
3385
Steve Frenchad009ac2005-04-28 22:41:05 -07003386 if(first_time)
3387 cifs_calculate_mac_key(
3388 pSesInfo->server->mac_signing_key,
3389 ntlm_session_key, pSesInfo->password);
3390
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 rc = CIFSSessSetup(xid, pSesInfo,
3392 ntlm_session_key, nls_info);
3393 }
3394 if (rc) {
3395 cERROR(1,("Send error in SessSetup = %d",rc));
3396 } else {
3397 cFYI(1,("CIFS Session Established successfully"));
3398 pSesInfo->status = CifsGood;
3399 }
3400 }
3401ss_err_exit:
3402 return rc;
3403}
3404