blob: 01608bb4d673d9033ab10adac4bcfd9a38055aab [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;
92};
93
94static int ipv4_connect(struct sockaddr_in *psin_server,
95 struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -070096 char * netb_name,
97 char * server_netb_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static int ipv6_connect(struct sockaddr_in6 *psin_server,
99 struct socket **csocket);
100
101
102 /*
103 * cifs tcp session reconnection
104 *
105 * mark tcp session as reconnecting so temporarily locked
106 * mark all smb sessions as reconnecting for tcp session
107 * reconnect tcp session
108 * wake up waiters on reconnection? - (not needed currently)
109 */
110
111int
112cifs_reconnect(struct TCP_Server_Info *server)
113{
114 int rc = 0;
115 struct list_head *tmp;
116 struct cifsSesInfo *ses;
117 struct cifsTconInfo *tcon;
118 struct mid_q_entry * mid_entry;
119
120 spin_lock(&GlobalMid_Lock);
121 if(server->tcpStatus == CifsExiting) {
122 /* the demux thread will exit normally
123 next time through the loop */
124 spin_unlock(&GlobalMid_Lock);
125 return rc;
126 } else
127 server->tcpStatus = CifsNeedReconnect;
128 spin_unlock(&GlobalMid_Lock);
129 server->maxBuf = 0;
130
Steve Frenche4eb2952005-04-28 22:41:09 -0700131 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
133 /* before reconnecting the tcp session, mark the smb session (uid)
134 and the tid bad so they are not used until reconnected */
135 read_lock(&GlobalSMBSeslock);
136 list_for_each(tmp, &GlobalSMBSessionList) {
137 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
138 if (ses->server) {
139 if (ses->server == server) {
140 ses->status = CifsNeedReconnect;
141 ses->ipc_tid = 0;
142 }
143 }
144 /* else tcp and smb sessions need reconnection */
145 }
146 list_for_each(tmp, &GlobalTreeConnectionList) {
147 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
148 if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
149 tcon->tidStatus = CifsNeedReconnect;
150 }
151 }
152 read_unlock(&GlobalSMBSeslock);
153 /* do not want to be sending data on a socket we are freeing */
154 down(&server->tcpSem);
155 if(server->ssocket) {
156 cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
157 server->ssocket->flags));
158 server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
159 cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
160 server->ssocket->flags));
161 sock_release(server->ssocket);
162 server->ssocket = NULL;
163 }
164
165 spin_lock(&GlobalMid_Lock);
166 list_for_each(tmp, &server->pending_mid_q) {
167 mid_entry = list_entry(tmp, struct
168 mid_q_entry,
169 qhead);
170 if(mid_entry) {
171 if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700172 /* Mark other intransit requests as needing
173 retry so we do not immediately mark the
174 session bad again (ie after we reconnect
175 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 mid_entry->midState = MID_RETRY_NEEDED;
177 }
178 }
179 }
180 spin_unlock(&GlobalMid_Lock);
181 up(&server->tcpSem);
182
183 while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
184 {
185 if(server->protocolType == IPV6) {
186 rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
187 } else {
188 rc = ipv4_connect(&server->addr.sockAddr,
189 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700190 server->workstation_RFC1001_name,
191 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 }
193 if(rc) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700194 cFYI(1,("reconnect error %d",rc));
Steve French0cb766a2005-04-28 22:41:11 -0700195 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 } else {
197 atomic_inc(&tcpSesReconnectCount);
198 spin_lock(&GlobalMid_Lock);
199 if(server->tcpStatus != CifsExiting)
200 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700201 server->sequence_number = 0;
202 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 /* atomic_set(&server->inFlight,0);*/
204 wake_up(&server->response_q);
205 }
206 }
207 return rc;
208}
209
Steve Frenche4eb2952005-04-28 22:41:09 -0700210/*
211 return codes:
212 0 not a transact2, or all data present
213 >0 transact2 with that much data missing
214 -EINVAL = invalid transact2
215
216 */
217static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
218{
219 struct smb_t2_rsp * pSMBt;
220 int total_data_size;
221 int data_in_this_rsp;
222 int remaining;
223
224 if(pSMB->Command != SMB_COM_TRANSACTION2)
225 return 0;
226
227 /* check for plausible wct, bcc and t2 data and parm sizes */
228 /* check for parm and data offset going beyond end of smb */
229 if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
230 cFYI(1,("invalid transact2 word count"));
231 return -EINVAL;
232 }
233
234 pSMBt = (struct smb_t2_rsp *)pSMB;
235
236 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
237 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
238
239 remaining = total_data_size - data_in_this_rsp;
240
241 if(remaining == 0)
242 return 0;
243 else if(remaining < 0) {
244 cFYI(1,("total data %d smaller than data in frame %d",
245 total_data_size, data_in_this_rsp));
246 return -EINVAL;
247 } else {
248 cFYI(1,("missing %d bytes from transact2, check next response",
249 remaining));
250 if(total_data_size > maxBufSize) {
251 cERROR(1,("TotalDataSize %d is over maximum buffer %d",
252 total_data_size,maxBufSize));
253 return -EINVAL;
254 }
255 return remaining;
256 }
257}
258
259static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
260{
261 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
262 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
263 int total_data_size;
264 int total_in_buf;
265 int remaining;
266 int total_in_buf2;
267 char * data_area_of_target;
268 char * data_area_of_buf2;
269 __u16 byte_count;
270
271 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
272
273 if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
274 cFYI(1,("total data sizes of primary and secondary t2 differ"));
275 }
276
277 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
278
279 remaining = total_data_size - total_in_buf;
280
281 if(remaining < 0)
282 return -EINVAL;
283
284 if(remaining == 0) /* nothing to do, ignore */
285 return 0;
286
287 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
288 if(remaining < total_in_buf2) {
289 cFYI(1,("transact2 2nd response contains too much data"));
290 }
291
292 /* find end of first SMB data area */
293 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
294 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
295 /* validate target area */
296
297 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
298 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
299
300 data_area_of_target += total_in_buf;
301
302 /* copy second buffer into end of first buffer */
303 memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
304 total_in_buf += total_in_buf2;
305 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
306 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
307 byte_count += total_in_buf2;
308 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
309
Steve French70ca7342005-09-22 16:32:06 -0700310 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700311 byte_count += total_in_buf2;
312
313 /* BB also add check that we are not beyond maximum buffer size */
314
Steve French70ca7342005-09-22 16:32:06 -0700315 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700316
317 if(remaining == total_in_buf2) {
318 cFYI(1,("found the last secondary response"));
319 return 0; /* we are done */
320 } else /* more responses to go */
321 return 1;
322
323}
324
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325static int
326cifs_demultiplex_thread(struct TCP_Server_Info *server)
327{
328 int length;
329 unsigned int pdu_length, total_read;
330 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700331 struct smb_hdr *bigbuf = NULL;
332 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 struct msghdr smb_msg;
334 struct kvec iov;
335 struct socket *csocket = server->ssocket;
336 struct list_head *tmp;
337 struct cifsSesInfo *ses;
338 struct task_struct *task_to_wake = NULL;
339 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700340 char temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700341 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700342 int isMultiRsp;
343 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 daemonize("cifsd");
346 allow_signal(SIGKILL);
347 current->flags |= PF_MEMALLOC;
348 server->tsk = current; /* save process info to wake at shutdown */
349 cFYI(1, ("Demultiplex PID: %d", current->pid));
350 write_lock(&GlobalSMBSeslock);
351 atomic_inc(&tcpSesAllocCount);
352 length = tcpSesAllocCount.counter;
353 write_unlock(&GlobalSMBSeslock);
Steve Frenchf1914012005-08-18 09:37:34 -0700354 complete(&cifsd_complete);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 if(length > 1) {
356 mempool_resize(cifs_req_poolp,
357 length + cifs_min_rcv,
358 GFP_KERNEL);
359 }
360
361 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700362 if (try_to_freeze())
363 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700364 if (bigbuf == NULL) {
365 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000366 if (!bigbuf) {
367 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700368 msleep(3000);
369 /* retry will check if exiting */
370 continue;
371 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000372 } else if (isLargeBuf) {
373 /* we are reusing a dirty large buf, clear its start */
Steve Frenchb8643e12005-04-28 22:41:07 -0700374 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700376
377 if (smallbuf == NULL) {
378 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000379 if (!smallbuf) {
380 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700381 msleep(1000);
382 /* retry will check if exiting */
383 continue;
384 }
385 /* beginning of smb buffer is cleared in our buf_get */
386 } else /* if existing small buf clear beginning */
387 memset(smallbuf, 0, sizeof (struct smb_hdr));
388
389 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700390 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700391 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 iov.iov_base = smb_buffer;
393 iov.iov_len = 4;
394 smb_msg.msg_control = NULL;
395 smb_msg.msg_controllen = 0;
396 length =
397 kernel_recvmsg(csocket, &smb_msg,
398 &iov, 1, 4, 0 /* BB see socket.h flags */);
399
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000400 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 break;
402 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000403 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000405 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 csocket = server->ssocket;
407 continue;
408 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700409 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 allowing socket to clear and app threads to set
411 tcpStatus CifsNeedReconnect if server hung */
412 continue;
413 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000414 if (server->tcpStatus == CifsNew) {
415 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700416 /* some servers kill the TCP session rather than
417 returning an SMB negprot error, in which
418 case reconnecting here is not going to help,
419 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 break;
421 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000422 if (!try_to_freeze() && (length == -EINTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 cFYI(1,("cifsd thread killed"));
424 break;
425 }
Steve French57337e42005-04-28 22:41:10 -0700426 cFYI(1,("Reconnect after unexpected peek error %d",
427 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 cifs_reconnect(server);
429 csocket = server->ssocket;
430 wake_up(&server->response_q);
431 continue;
Steve French46810cb2005-04-28 22:41:09 -0700432 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700434 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 length));
436 cifs_reconnect(server);
437 csocket = server->ssocket;
438 wake_up(&server->response_q);
439 continue;
440 }
Steve French67010fb2005-04-28 22:41:09 -0700441
Steve French70ca7342005-09-22 16:32:06 -0700442 /* The right amount was read from socket - 4 bytes */
443 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700444
Steve French70ca7342005-09-22 16:32:06 -0700445 /* the first byte big endian of the length field,
446 is actually not part of the length but the type
447 with the most common, zero, as regular data */
448 temp = *((char *) smb_buffer);
449
450 /* Note that FC 1001 length is big endian on the wire,
451 but we convert it here so it is always manipulated
452 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700453 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700454 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700455
Steve French70ca7342005-09-22 16:32:06 -0700456 cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
457
458 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700459 continue;
Steve French70ca7342005-09-22 16:32:06 -0700460 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700461 cFYI(1,("Good RFC 1002 session rsp"));
462 continue;
Steve French70ca7342005-09-22 16:32:06 -0700463 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve French46810cb2005-04-28 22:41:09 -0700464 /* we get this from Windows 98 instead of
465 an error on SMB negprot response */
Steve Frenche4eb2952005-04-28 22:41:09 -0700466 cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700467 pdu_length));
Steve French46810cb2005-04-28 22:41:09 -0700468 if(server->tcpStatus == CifsNew) {
469 /* if nack on negprot (rather than
470 ret of smb negprot error) reconnecting
471 not going to help, ret error to mount */
472 break;
473 } else {
474 /* give server a second to
475 clean up before reconnect attempt */
476 msleep(1000);
477 /* always try 445 first on reconnect
478 since we get NACK on some if we ever
479 connected to port 139 (the NACK is
480 since we do not begin with RFC1001
481 session initialize frame) */
482 server->addr.sockAddr.sin_port =
483 htons(CIFS_PORT);
484 cifs_reconnect(server);
485 csocket = server->ssocket;
486 wake_up(&server->response_q);
487 continue;
488 }
Steve French70ca7342005-09-22 16:32:06 -0700489 } else if (temp != (char) 0) {
Steve French46810cb2005-04-28 22:41:09 -0700490 cERROR(1,("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700491 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
492 length);
Steve French46810cb2005-04-28 22:41:09 -0700493 cifs_reconnect(server);
494 csocket = server->ssocket;
495 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700496 }
497
498 /* else we have an SMB response */
499 if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700500 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700501 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700502 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700503 cifs_reconnect(server);
504 csocket = server->ssocket;
505 wake_up(&server->response_q);
506 continue;
507 }
508
509 /* else length ok */
510 reconnect = 0;
511
Steve Frenchec637e32005-12-12 20:53:18 -0800512 if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700513 isLargeBuf = TRUE;
514 memcpy(bigbuf, smallbuf, 4);
515 smb_buffer = bigbuf;
516 }
517 length = 0;
518 iov.iov_base = 4 + (char *)smb_buffer;
519 iov.iov_len = pdu_length;
520 for (total_read = 0; total_read < pdu_length;
521 total_read += length) {
522 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
523 pdu_length - total_read, 0);
524 if((server->tcpStatus == CifsExiting) ||
525 (length == -EINTR)) {
526 /* then will exit */
527 reconnect = 2;
528 break;
529 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700530 cifs_reconnect(server);
531 csocket = server->ssocket;
Steve Frenche4eb2952005-04-28 22:41:09 -0700532 /* Reconnect wakes up rspns q */
533 /* Now we will reread sock */
534 reconnect = 1;
535 break;
536 } else if ((length == -ERESTARTSYS) ||
537 (length == -EAGAIN)) {
538 msleep(1); /* minimum sleep to prevent looping,
539 allowing socket to clear and app
540 threads to set tcpStatus
541 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700542 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700543 } else if (length <= 0) {
544 cERROR(1,("Received no data, expecting %d",
545 pdu_length - total_read));
546 cifs_reconnect(server);
547 csocket = server->ssocket;
548 reconnect = 1;
549 break;
Steve French46810cb2005-04-28 22:41:09 -0700550 }
551 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700552 if(reconnect == 2)
553 break;
554 else if(reconnect == 1)
555 continue;
556
557 length += 4; /* account for rfc1002 hdr */
558
559
560 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000561 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700562 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700563 continue;
564 }
565
566
567 task_to_wake = NULL;
568 spin_lock(&GlobalMid_Lock);
569 list_for_each(tmp, &server->pending_mid_q) {
570 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
571
572 if ((mid_entry->mid == smb_buffer->Mid) &&
573 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
574 (mid_entry->command == smb_buffer->Command)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700575 if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
576 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700577 isMultiRsp = TRUE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700578 if(mid_entry->resp_buf) {
579 /* merge response - fix up 1st*/
580 if(coalesce_t2(smb_buffer,
581 mid_entry->resp_buf)) {
Steve French39798772006-05-31 22:40:51 +0000582 mid_entry->multiRsp = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700583 break;
584 } else {
585 /* all parts received */
Steve French39798772006-05-31 22:40:51 +0000586 mid_entry->multiEnd = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700587 goto multi_t2_fnd;
588 }
589 } else {
590 if(!isLargeBuf) {
591 cERROR(1,("1st trans2 resp needs bigbuf"));
592 /* BB maybe we can fix this up, switch
593 to already allocated large buffer? */
594 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700595 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700596 mid_entry->resp_buf =
597 smb_buffer;
598 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700599 bigbuf = NULL;
600 }
601 }
602 break;
603 }
604 mid_entry->resp_buf = smb_buffer;
605 if(isLargeBuf)
606 mid_entry->largeBuf = 1;
607 else
608 mid_entry->largeBuf = 0;
609multi_t2_fnd:
610 task_to_wake = mid_entry->tsk;
611 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700612#ifdef CONFIG_CIFS_STATS2
613 mid_entry->when_received = jiffies;
614#endif
Steve Frenche4eb2952005-04-28 22:41:09 -0700615 break;
616 }
617 }
618 spin_unlock(&GlobalMid_Lock);
619 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700620 /* Was previous buf put in mpx struct for multi-rsp? */
621 if(!isMultiRsp) {
622 /* smb buffer will be freed by user thread */
623 if(isLargeBuf) {
624 bigbuf = NULL;
625 } else
626 smallbuf = NULL;
627 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700628 wake_up_process(task_to_wake);
Steve Frenchd7c8c942006-03-03 10:43:49 +0000629 } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700630 && (isMultiRsp == FALSE)) {
Steve French39798772006-05-31 22:40:51 +0000631 cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
Steve French70ca7342005-09-22 16:32:06 -0700632 cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
633 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000634#ifdef CONFIG_CIFS_DEBUG2
635 cifs_dump_detail(smb_buffer);
636 cifs_dump_mids(server);
637#endif /* CIFS_DEBUG2 */
638
Steve Frenche4eb2952005-04-28 22:41:09 -0700639 }
640 } /* end while !EXITING */
641
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 spin_lock(&GlobalMid_Lock);
643 server->tcpStatus = CifsExiting;
644 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700645 /* check if we have blocked requests that need to free */
646 /* Note that cifs_max_pending is normally 50, but
647 can be set at module install time to as little as two */
648 if(atomic_read(&server->inFlight) >= cifs_max_pending)
649 atomic_set(&server->inFlight, cifs_max_pending - 1);
650 /* We do not want to set the max_pending too low or we
651 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 spin_unlock(&GlobalMid_Lock);
653 /* Although there should not be any requests blocked on
654 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700655 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 to the same server - they now will see the session is in exit state
657 and get out of SendReceive. */
658 wake_up_all(&server->request_q);
659 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700660 msleep(125);
661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 if(server->ssocket) {
663 sock_release(csocket);
664 server->ssocket = NULL;
665 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700666 /* buffer usuallly freed in free_mid - need to free it here on exit */
667 if (bigbuf != NULL)
668 cifs_buf_release(bigbuf);
669 if (smallbuf != NULL)
670 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672 read_lock(&GlobalSMBSeslock);
673 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700674 /* loop through server session structures attached to this and
675 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 list_for_each(tmp, &GlobalSMBSessionList) {
677 ses =
678 list_entry(tmp, struct cifsSesInfo,
679 cifsSessionList);
680 if (ses->server == server) {
681 ses->status = CifsExiting;
682 ses->server = NULL;
683 }
684 }
685 read_unlock(&GlobalSMBSeslock);
686 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700687 /* although we can not zero the server struct pointer yet,
688 since there are active requests which may depnd on them,
689 mark the corresponding SMB sessions as exiting too */
690 list_for_each(tmp, &GlobalSMBSessionList) {
691 ses = list_entry(tmp, struct cifsSesInfo,
692 cifsSessionList);
693 if (ses->server == server) {
694 ses->status = CifsExiting;
695 }
696 }
697
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 spin_lock(&GlobalMid_Lock);
699 list_for_each(tmp, &server->pending_mid_q) {
700 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
701 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
702 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700703 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 task_to_wake = mid_entry->tsk;
705 if(task_to_wake) {
706 wake_up_process(task_to_wake);
707 }
708 }
709 }
710 spin_unlock(&GlobalMid_Lock);
711 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700713 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 }
715
Steve Frenchf1914012005-08-18 09:37:34 -0700716 if (!list_empty(&server->pending_mid_q)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 /* mpx threads have not exited yet give them
718 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700719 /* due to delays on oplock break requests, we need
720 to wait at least 45 seconds before giving up
721 on a request getting a response and going ahead
722 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700724 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 /* if threads still have not exited they are probably never
726 coming home not much else we can do but free the memory */
727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
729 write_lock(&GlobalSMBSeslock);
730 atomic_dec(&tcpSesAllocCount);
731 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700732
733 /* last chance to mark ses pointers invalid
734 if there are any pointing to this (e.g
735 if a crazy root user tried to kill cifsd
736 kernel thread explicitly this might happen) */
737 list_for_each(tmp, &GlobalSMBSessionList) {
738 ses = list_entry(tmp, struct cifsSesInfo,
739 cifsSessionList);
740 if (ses->server == server) {
741 ses->server = NULL;
742 }
743 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700745
746 kfree(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 if(length > 0) {
748 mempool_resize(cifs_req_poolp,
749 length + cifs_min_rcv,
750 GFP_KERNEL);
751 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700752
Steve Frenchf1914012005-08-18 09:37:34 -0700753 complete_and_exit(&cifsd_complete, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 return 0;
755}
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757static int
758cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
759{
760 char *value;
761 char *data;
762 unsigned int temp_len, i, j;
763 char separator[2];
764
765 separator[0] = ',';
766 separator[1] = 0;
767
768 memset(vol->source_rfc1001_name,0x20,15);
769 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
770 /* does not have to be a perfect mapping since the field is
771 informational, only used for servers that do not support
772 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700773 vol->source_rfc1001_name[i] =
774 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
776 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700777 /* null target name indicates to use *SMBSERVR default called name
778 if we end up sending RFC1001 session initialize */
779 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 vol->linux_uid = current->uid; /* current->euid instead? */
781 vol->linux_gid = current->gid;
782 vol->dir_mode = S_IRWXUGO;
783 /* 2767 perms indicate mandatory locking support */
784 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
785
786 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
787 vol->rw = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700788 /* default is always to request posix paths. */
789 vol->posix_paths = 1;
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 if (!options)
792 return 1;
793
794 if(strncmp(options,"sep=",4) == 0) {
795 if(options[4] != 0) {
796 separator[0] = options[4];
797 options += 5;
798 } else {
799 cFYI(1,("Null separator not allowed"));
800 }
801 }
802
803 while ((data = strsep(&options, separator)) != NULL) {
804 if (!*data)
805 continue;
806 if ((value = strchr(data, '=')) != NULL)
807 *value++ = '\0';
808
809 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
810 vol->no_xattr = 0;
811 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
812 vol->no_xattr = 1;
813 } else if (strnicmp(data, "user", 4) == 0) {
814 if (!value || !*value) {
815 printk(KERN_WARNING
816 "CIFS: invalid or missing username\n");
817 return 1; /* needs_arg; */
818 }
819 if (strnlen(value, 200) < 200) {
820 vol->username = value;
821 } else {
822 printk(KERN_WARNING "CIFS: username too long\n");
823 return 1;
824 }
825 } else if (strnicmp(data, "pass", 4) == 0) {
826 if (!value) {
827 vol->password = NULL;
828 continue;
829 } else if(value[0] == 0) {
830 /* check if string begins with double comma
831 since that would mean the password really
832 does start with a comma, and would not
833 indicate an empty string */
834 if(value[1] != separator[0]) {
835 vol->password = NULL;
836 continue;
837 }
838 }
839 temp_len = strlen(value);
840 /* removed password length check, NTLM passwords
841 can be arbitrarily long */
842
843 /* if comma in password, the string will be
844 prematurely null terminated. Commas in password are
845 specified across the cifs mount interface by a double
846 comma ie ,, and a comma used as in other cases ie ','
847 as a parameter delimiter/separator is single and due
848 to the strsep above is temporarily zeroed. */
849
850 /* NB: password legally can have multiple commas and
851 the only illegal character in a password is null */
852
Steve French09d1db52005-04-28 22:41:08 -0700853 if ((value[temp_len] == 0) &&
854 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 /* reinsert comma */
856 value[temp_len] = separator[0];
857 temp_len+=2; /* move after the second comma */
858 while(value[temp_len] != 0) {
859 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700860 if (value[temp_len+1] ==
861 separator[0]) {
862 /* skip second comma */
863 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 } else {
865 /* single comma indicating start
866 of next parm */
867 break;
868 }
869 }
870 temp_len++;
871 }
872 if(value[temp_len] == 0) {
873 options = NULL;
874 } else {
875 value[temp_len] = 0;
876 /* point option to start of next parm */
877 options = value + temp_len + 1;
878 }
879 /* go from value to value + temp_len condensing
880 double commas to singles. Note that this ends up
881 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700882 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700883 if(vol->password == NULL) {
884 printk("CIFS: no memory for pass\n");
885 return 1;
886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 for(i=0,j=0;i<temp_len;i++,j++) {
888 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700889 if(value[i] == separator[0]
890 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 /* skip second comma */
892 i++;
893 }
894 }
895 vol->password[j] = 0;
896 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700897 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700898 if(vol->password == NULL) {
899 printk("CIFS: no memory for pass\n");
900 return 1;
901 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 strcpy(vol->password, value);
903 }
904 } else if (strnicmp(data, "ip", 2) == 0) {
905 if (!value || !*value) {
906 vol->UNCip = NULL;
907 } else if (strnlen(value, 35) < 35) {
908 vol->UNCip = value;
909 } else {
910 printk(KERN_WARNING "CIFS: ip address too long\n");
911 return 1;
912 }
Steve Frenchbf820672005-12-01 22:32:42 -0800913 } else if (strnicmp(data, "sec", 3) == 0) {
914 if (!value || !*value) {
915 cERROR(1,("no security value specified"));
916 continue;
917 } else if (strnicmp(value, "krb5i", 5) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000918 vol->secFlg = CIFSSEC_MAY_KRB5 |
919 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800920 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000921 /* vol->secFlg = CIFSSEC_MUST_SEAL |
922 CIFSSEC_MAY_KRB5; */
Steve Frenchbf820672005-12-01 22:32:42 -0800923 cERROR(1,("Krb5 cifs privacy not supported"));
924 return 1;
925 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000926 vol->secFlg = CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800927 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000928 vol->secFlg = CIFSSEC_MAY_NTLMV2 |
929 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800930 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000931 vol->secFlg = CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800932 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000933 vol->secFlg = CIFSSEC_MAY_NTLM |
934 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800935 } else if (strnicmp(value, "ntlm", 4) == 0) {
936 /* ntlm is default so can be turned off too */
Steve French189acaa2006-06-23 02:33:48 +0000937 vol->secFlg = CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800938 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000939 /* BB is there a better way to do this? */
940 vol->secFlg = CIFSSEC_MAY_NTLMV2;
941#ifdef CONFIG_CIFS_WEAK_PW_HASH
942 } else if (strnicmp(value, "lanman", 6) == 0) {
943 vol->secFlg = CIFSSEC_MAY_LANMAN;
944#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800945 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000946 vol->nullauth = 1;
Steve Frenchbf820672005-12-01 22:32:42 -0800947 } else {
948 cERROR(1,("bad security option: %s", value));
949 return 1;
950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 } else if ((strnicmp(data, "unc", 3) == 0)
952 || (strnicmp(data, "target", 6) == 0)
953 || (strnicmp(data, "path", 4) == 0)) {
954 if (!value || !*value) {
955 printk(KERN_WARNING
956 "CIFS: invalid path to network resource\n");
957 return 1; /* needs_arg; */
958 }
959 if ((temp_len = strnlen(value, 300)) < 300) {
960 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
961 if(vol->UNC == NULL)
962 return 1;
963 strcpy(vol->UNC,value);
964 if (strncmp(vol->UNC, "//", 2) == 0) {
965 vol->UNC[0] = '\\';
966 vol->UNC[1] = '\\';
967 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
968 printk(KERN_WARNING
969 "CIFS: UNC Path does not begin with // or \\\\ \n");
970 return 1;
971 }
972 } else {
973 printk(KERN_WARNING "CIFS: UNC name too long\n");
974 return 1;
975 }
976 } else if ((strnicmp(data, "domain", 3) == 0)
977 || (strnicmp(data, "workgroup", 5) == 0)) {
978 if (!value || !*value) {
979 printk(KERN_WARNING "CIFS: invalid domain name\n");
980 return 1; /* needs_arg; */
981 }
982 /* BB are there cases in which a comma can be valid in
983 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +0000984 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 vol->domainname = value;
986 cFYI(1, ("Domain name set"));
987 } else {
988 printk(KERN_WARNING "CIFS: domain name too long\n");
989 return 1;
990 }
991 } else if (strnicmp(data, "iocharset", 9) == 0) {
992 if (!value || !*value) {
993 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
994 return 1; /* needs_arg; */
995 }
996 if (strnlen(value, 65) < 65) {
997 if(strnicmp(value,"default",7))
998 vol->iocharset = value;
999 /* if iocharset not set load_nls_default used by caller */
1000 cFYI(1, ("iocharset set to %s",value));
1001 } else {
1002 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
1003 return 1;
1004 }
1005 } else if (strnicmp(data, "uid", 3) == 0) {
1006 if (value && *value) {
1007 vol->linux_uid =
1008 simple_strtoul(value, &value, 0);
1009 }
1010 } else if (strnicmp(data, "gid", 3) == 0) {
1011 if (value && *value) {
1012 vol->linux_gid =
1013 simple_strtoul(value, &value, 0);
1014 }
1015 } else if (strnicmp(data, "file_mode", 4) == 0) {
1016 if (value && *value) {
1017 vol->file_mode =
1018 simple_strtoul(value, &value, 0);
1019 }
1020 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1021 if (value && *value) {
1022 vol->dir_mode =
1023 simple_strtoul(value, &value, 0);
1024 }
1025 } else if (strnicmp(data, "dirmode", 4) == 0) {
1026 if (value && *value) {
1027 vol->dir_mode =
1028 simple_strtoul(value, &value, 0);
1029 }
1030 } else if (strnicmp(data, "port", 4) == 0) {
1031 if (value && *value) {
1032 vol->port =
1033 simple_strtoul(value, &value, 0);
1034 }
1035 } else if (strnicmp(data, "rsize", 5) == 0) {
1036 if (value && *value) {
1037 vol->rsize =
1038 simple_strtoul(value, &value, 0);
1039 }
1040 } else if (strnicmp(data, "wsize", 5) == 0) {
1041 if (value && *value) {
1042 vol->wsize =
1043 simple_strtoul(value, &value, 0);
1044 }
1045 } else if (strnicmp(data, "sockopt", 5) == 0) {
1046 if (value && *value) {
1047 vol->sockopt =
1048 simple_strtoul(value, &value, 0);
1049 }
1050 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1051 if (!value || !*value || (*value == ' ')) {
1052 cFYI(1,("invalid (empty) netbiosname specified"));
1053 } else {
1054 memset(vol->source_rfc1001_name,0x20,15);
1055 for(i=0;i<15;i++) {
1056 /* BB are there cases in which a comma can be
1057 valid in this workstation netbios name (and need
1058 special handling)? */
1059
1060 /* We do not uppercase netbiosname for user */
1061 if (value[i]==0)
1062 break;
1063 else
1064 vol->source_rfc1001_name[i] = value[i];
1065 }
1066 /* The string has 16th byte zero still from
1067 set at top of the function */
1068 if((i==15) && (value[i] != 0))
Steve Frencha10faeb22005-08-22 21:38:31 -07001069 printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
1070 }
1071 } else if (strnicmp(data, "servern", 7) == 0) {
1072 /* servernetbiosname specified override *SMBSERVER */
1073 if (!value || !*value || (*value == ' ')) {
1074 cFYI(1,("empty server netbiosname specified"));
1075 } else {
1076 /* last byte, type, is 0x20 for servr type */
1077 memset(vol->target_rfc1001_name,0x20,16);
1078
1079 for(i=0;i<15;i++) {
1080 /* BB are there cases in which a comma can be
1081 valid in this workstation netbios name (and need
1082 special handling)? */
1083
1084 /* user or mount helper must uppercase netbiosname */
1085 if (value[i]==0)
1086 break;
1087 else
1088 vol->target_rfc1001_name[i] = value[i];
1089 }
1090 /* The string has 16th byte zero still from
1091 set at top of the function */
1092 if((i==15) && (value[i] != 0))
1093 printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 }
1095 } else if (strnicmp(data, "credentials", 4) == 0) {
1096 /* ignore */
1097 } else if (strnicmp(data, "version", 3) == 0) {
1098 /* ignore */
1099 } else if (strnicmp(data, "guest",5) == 0) {
1100 /* ignore */
1101 } else if (strnicmp(data, "rw", 2) == 0) {
1102 vol->rw = TRUE;
1103 } else if ((strnicmp(data, "suid", 4) == 0) ||
1104 (strnicmp(data, "nosuid", 6) == 0) ||
1105 (strnicmp(data, "exec", 4) == 0) ||
1106 (strnicmp(data, "noexec", 6) == 0) ||
1107 (strnicmp(data, "nodev", 5) == 0) ||
1108 (strnicmp(data, "noauto", 6) == 0) ||
1109 (strnicmp(data, "dev", 3) == 0)) {
1110 /* The mount tool or mount.cifs helper (if present)
1111 uses these opts to set flags, and the flags are read
1112 by the kernel vfs layer before we get here (ie
1113 before read super) so there is no point trying to
1114 parse these options again and set anything and it
1115 is ok to just ignore them */
1116 continue;
1117 } else if (strnicmp(data, "ro", 2) == 0) {
1118 vol->rw = FALSE;
1119 } else if (strnicmp(data, "hard", 4) == 0) {
1120 vol->retry = 1;
1121 } else if (strnicmp(data, "soft", 4) == 0) {
1122 vol->retry = 0;
1123 } else if (strnicmp(data, "perm", 4) == 0) {
1124 vol->noperm = 0;
1125 } else if (strnicmp(data, "noperm", 6) == 0) {
1126 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001127 } else if (strnicmp(data, "mapchars", 8) == 0) {
1128 vol->remap = 1;
1129 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1130 vol->remap = 0;
Steve Frenchd7245c22005-07-14 18:25:12 -05001131 } else if (strnicmp(data, "sfu", 3) == 0) {
1132 vol->sfu_emul = 1;
1133 } else if (strnicmp(data, "nosfu", 5) == 0) {
1134 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001135 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1136 vol->posix_paths = 1;
1137 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1138 vol->posix_paths = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001139 } else if ((strnicmp(data, "nocase", 6) == 0) ||
1140 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001141 vol->nocase = 1;
1142 } else if (strnicmp(data, "brl", 3) == 0) {
1143 vol->nobrl = 0;
Steve Frenchcb8be642005-08-30 15:25:52 -07001144 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001145 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001146 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001147 /* turn off mandatory locking in mode
1148 if remote locking is turned off since the
1149 local vfs will do advisory */
1150 if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1151 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 } else if (strnicmp(data, "setuids", 7) == 0) {
1153 vol->setuids = 1;
1154 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1155 vol->setuids = 0;
1156 } else if (strnicmp(data, "nohard", 6) == 0) {
1157 vol->retry = 0;
1158 } else if (strnicmp(data, "nosoft", 6) == 0) {
1159 vol->retry = 1;
1160 } else if (strnicmp(data, "nointr", 6) == 0) {
1161 vol->intr = 0;
1162 } else if (strnicmp(data, "intr", 4) == 0) {
1163 vol->intr = 1;
1164 } else if (strnicmp(data, "serverino",7) == 0) {
1165 vol->server_ino = 1;
1166 } else if (strnicmp(data, "noserverino",9) == 0) {
1167 vol->server_ino = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08001168 } else if (strnicmp(data, "cifsacl",7) == 0) {
1169 vol->cifs_acl = 1;
1170 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1171 vol->cifs_acl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 } else if (strnicmp(data, "acl",3) == 0) {
1173 vol->no_psx_acl = 0;
1174 } else if (strnicmp(data, "noacl",5) == 0) {
1175 vol->no_psx_acl = 1;
1176 } else if (strnicmp(data, "direct",6) == 0) {
1177 vol->direct_io = 1;
1178 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1179 vol->direct_io = 1;
1180 } else if (strnicmp(data, "in6_addr",8) == 0) {
1181 if (!value || !*value) {
1182 vol->in6_addr = NULL;
1183 } else if (strnlen(value, 49) == 48) {
1184 vol->in6_addr = value;
1185 } else {
1186 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1187 return 1;
1188 }
1189 } else if (strnicmp(data, "noac", 4) == 0) {
1190 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1191 } else
1192 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1193 }
1194 if (vol->UNC == NULL) {
1195 if(devname == NULL) {
1196 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1197 return 1;
1198 }
1199 if ((temp_len = strnlen(devname, 300)) < 300) {
1200 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1201 if(vol->UNC == NULL)
1202 return 1;
1203 strcpy(vol->UNC,devname);
1204 if (strncmp(vol->UNC, "//", 2) == 0) {
1205 vol->UNC[0] = '\\';
1206 vol->UNC[1] = '\\';
1207 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1208 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1209 return 1;
1210 }
1211 } else {
1212 printk(KERN_WARNING "CIFS: UNC name too long\n");
1213 return 1;
1214 }
1215 }
1216 if(vol->UNCip == NULL)
1217 vol->UNCip = &vol->UNC[2];
1218
1219 return 0;
1220}
1221
1222static struct cifsSesInfo *
1223cifs_find_tcp_session(struct in_addr * target_ip_addr,
1224 struct in6_addr *target_ip6_addr,
1225 char *userName, struct TCP_Server_Info **psrvTcp)
1226{
1227 struct list_head *tmp;
1228 struct cifsSesInfo *ses;
1229 *psrvTcp = NULL;
1230 read_lock(&GlobalSMBSeslock);
1231
1232 list_for_each(tmp, &GlobalSMBSessionList) {
1233 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1234 if (ses->server) {
1235 if((target_ip_addr &&
1236 (ses->server->addr.sockAddr.sin_addr.s_addr
1237 == target_ip_addr->s_addr)) || (target_ip6_addr
1238 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1239 target_ip6_addr,sizeof(*target_ip6_addr)))){
1240 /* BB lock server and tcp session and increment use count here?? */
1241 *psrvTcp = ses->server; /* found a match on the TCP session */
1242 /* BB check if reconnection needed */
1243 if (strncmp
1244 (ses->userName, userName,
1245 MAX_USERNAME_SIZE) == 0){
1246 read_unlock(&GlobalSMBSeslock);
1247 return ses; /* found exact match on both tcp and SMB sessions */
1248 }
1249 }
1250 }
1251 /* else tcp and smb sessions need reconnection */
1252 }
1253 read_unlock(&GlobalSMBSeslock);
1254 return NULL;
1255}
1256
1257static struct cifsTconInfo *
1258find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1259{
1260 struct list_head *tmp;
1261 struct cifsTconInfo *tcon;
1262
1263 read_lock(&GlobalSMBSeslock);
1264 list_for_each(tmp, &GlobalTreeConnectionList) {
1265 cFYI(1, ("Next tcon - "));
1266 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1267 if (tcon->ses) {
1268 if (tcon->ses->server) {
1269 cFYI(1,
1270 (" old ip addr: %x == new ip %x ?",
1271 tcon->ses->server->addr.sockAddr.sin_addr.
1272 s_addr, new_target_ip_addr));
1273 if (tcon->ses->server->addr.sockAddr.sin_addr.
1274 s_addr == new_target_ip_addr) {
1275 /* BB lock tcon and server and tcp session and increment use count here? */
1276 /* found a match on the TCP session */
1277 /* BB check if reconnection needed */
1278 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1279 tcon->treeName, uncName));
1280 if (strncmp
1281 (tcon->treeName, uncName,
1282 MAX_TREE_SIZE) == 0) {
1283 cFYI(1,
1284 ("Matched UNC, old user: %s == new: %s ?",
1285 tcon->treeName, uncName));
1286 if (strncmp
1287 (tcon->ses->userName,
1288 userName,
1289 MAX_USERNAME_SIZE) == 0) {
1290 read_unlock(&GlobalSMBSeslock);
1291 return tcon;/* also matched user (smb session)*/
1292 }
1293 }
1294 }
1295 }
1296 }
1297 }
1298 read_unlock(&GlobalSMBSeslock);
1299 return NULL;
1300}
1301
1302int
1303connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001304 const char *old_path, const struct nls_table *nls_codepage,
1305 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306{
1307 unsigned char *referrals = NULL;
1308 unsigned int num_referrals;
1309 int rc = 0;
1310
1311 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001312 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313
1314 /* BB Add in code to: if valid refrl, if not ip address contact
1315 the helper that resolves tcp names, mount to it, try to
1316 tcon to it unmount it if fail */
1317
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001318 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
1320 return rc;
1321}
1322
1323int
1324get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1325 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001326 unsigned int *pnum_referrals,
1327 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328{
1329 char *temp_unc;
1330 int rc = 0;
1331
1332 *pnum_referrals = 0;
1333
1334 if (pSesInfo->ipc_tid == 0) {
1335 temp_unc = kmalloc(2 /* for slashes */ +
1336 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1337 + 1 + 4 /* slash IPC$ */ + 2,
1338 GFP_KERNEL);
1339 if (temp_unc == NULL)
1340 return -ENOMEM;
1341 temp_unc[0] = '\\';
1342 temp_unc[1] = '\\';
1343 strcpy(temp_unc + 2, pSesInfo->serverName);
1344 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1345 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1346 cFYI(1,
1347 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1348 kfree(temp_unc);
1349 }
1350 if (rc == 0)
1351 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001352 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
1354 return rc;
1355}
1356
1357/* See RFC1001 section 14 on representation of Netbios names */
1358static void rfc1002mangle(char * target,char * source, unsigned int length)
1359{
1360 unsigned int i,j;
1361
1362 for(i=0,j=0;i<(length);i++) {
1363 /* mask a nibble at a time and encode */
1364 target[j] = 'A' + (0x0F & (source[i] >> 4));
1365 target[j+1] = 'A' + (0x0F & source[i]);
1366 j+=2;
1367 }
1368
1369}
1370
1371
1372static int
1373ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001374 char * netbios_name, char * target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375{
1376 int rc = 0;
1377 int connected = 0;
1378 __be16 orig_port = 0;
1379
1380 if(*csocket == NULL) {
1381 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1382 if (rc < 0) {
1383 cERROR(1, ("Error %d creating socket",rc));
1384 *csocket = NULL;
1385 return rc;
1386 } else {
1387 /* BB other socket options to set KEEPALIVE, NODELAY? */
1388 cFYI(1,("Socket created"));
1389 (*csocket)->sk->sk_allocation = GFP_NOFS;
1390 }
1391 }
1392
1393 psin_server->sin_family = AF_INET;
1394 if(psin_server->sin_port) { /* user overrode default port */
1395 rc = (*csocket)->ops->connect(*csocket,
1396 (struct sockaddr *) psin_server,
1397 sizeof (struct sockaddr_in),0);
1398 if (rc >= 0)
1399 connected = 1;
1400 }
1401
1402 if(!connected) {
1403 /* save original port so we can retry user specified port
1404 later if fall back ports fail this time */
1405 orig_port = psin_server->sin_port;
1406
1407 /* do not retry on the same port we just failed on */
1408 if(psin_server->sin_port != htons(CIFS_PORT)) {
1409 psin_server->sin_port = htons(CIFS_PORT);
1410
1411 rc = (*csocket)->ops->connect(*csocket,
1412 (struct sockaddr *) psin_server,
1413 sizeof (struct sockaddr_in),0);
1414 if (rc >= 0)
1415 connected = 1;
1416 }
1417 }
1418 if (!connected) {
1419 psin_server->sin_port = htons(RFC1001_PORT);
1420 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1421 psin_server, sizeof (struct sockaddr_in),0);
1422 if (rc >= 0)
1423 connected = 1;
1424 }
1425
1426 /* give up here - unless we want to retry on different
1427 protocol families some day */
1428 if (!connected) {
1429 if(orig_port)
1430 psin_server->sin_port = orig_port;
1431 cFYI(1,("Error %d connecting to server via ipv4",rc));
1432 sock_release(*csocket);
1433 *csocket = NULL;
1434 return rc;
1435 }
1436 /* Eventually check for other socket options to change from
1437 the default. sock_setsockopt not used because it expects
1438 user space buffer */
Steve Frenchb387eae2005-10-10 14:21:15 -07001439 cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
1440 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001442 /* make the bufsizes depend on wsize/rsize and max requests */
1443 if((*csocket)->sk->sk_sndbuf < (200 * 1024))
1444 (*csocket)->sk->sk_sndbuf = 200 * 1024;
1445 if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
1446 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447
1448 /* send RFC1001 sessinit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1450 /* some servers require RFC1001 sessinit before sending
1451 negprot - BB check reconnection in case where second
1452 sessinit is sent but no second negprot */
1453 struct rfc1002_session_packet * ses_init_buf;
1454 struct smb_hdr * smb_buf;
Pekka Enberge915fc42005-09-06 15:18:35 -07001455 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 if(ses_init_buf) {
1457 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frencha10faeb22005-08-22 21:38:31 -07001458 if(target_name && (target_name[0] != 0)) {
1459 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1460 target_name, 16);
1461 } else {
1462 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1463 DEFAULT_CIFS_CALLED_NAME,16);
1464 }
1465
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 ses_init_buf->trailer.session_req.calling_len = 32;
1467 /* calling name ends in null (byte 16) from old smb
1468 convention. */
1469 if(netbios_name && (netbios_name[0] !=0)) {
1470 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1471 netbios_name,16);
1472 } else {
1473 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1474 "LINUX_CIFS_CLNT",16);
1475 }
1476 ses_init_buf->trailer.session_req.scope1 = 0;
1477 ses_init_buf->trailer.session_req.scope2 = 0;
1478 smb_buf = (struct smb_hdr *)ses_init_buf;
1479 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1480 smb_buf->smb_buf_length = 0x81000044;
1481 rc = smb_send(*csocket, smb_buf, 0x44,
1482 (struct sockaddr *)psin_server);
1483 kfree(ses_init_buf);
Steve French083d3a22006-03-03 09:53:36 +00001484 msleep(1); /* RFC1001 layer in at least one server
1485 requires very short break before negprot
1486 presumably because not expecting negprot
1487 to follow so fast. This is a simple
1488 solution that works without
1489 complicating the code and causes no
1490 significant slowing down on mount
1491 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 }
1493 /* else the negprot may still work without this
1494 even though malloc failed */
1495
1496 }
1497
1498 return rc;
1499}
1500
1501static int
1502ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1503{
1504 int rc = 0;
1505 int connected = 0;
1506 __be16 orig_port = 0;
1507
1508 if(*csocket == NULL) {
1509 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1510 if (rc < 0) {
1511 cERROR(1, ("Error %d creating ipv6 socket",rc));
1512 *csocket = NULL;
1513 return rc;
1514 } else {
1515 /* BB other socket options to set KEEPALIVE, NODELAY? */
1516 cFYI(1,("ipv6 Socket created"));
1517 (*csocket)->sk->sk_allocation = GFP_NOFS;
1518 }
1519 }
1520
1521 psin_server->sin6_family = AF_INET6;
1522
1523 if(psin_server->sin6_port) { /* user overrode default port */
1524 rc = (*csocket)->ops->connect(*csocket,
1525 (struct sockaddr *) psin_server,
1526 sizeof (struct sockaddr_in6),0);
1527 if (rc >= 0)
1528 connected = 1;
1529 }
1530
1531 if(!connected) {
1532 /* save original port so we can retry user specified port
1533 later if fall back ports fail this time */
1534
1535 orig_port = psin_server->sin6_port;
1536 /* do not retry on the same port we just failed on */
1537 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1538 psin_server->sin6_port = htons(CIFS_PORT);
1539
1540 rc = (*csocket)->ops->connect(*csocket,
1541 (struct sockaddr *) psin_server,
1542 sizeof (struct sockaddr_in6),0);
1543 if (rc >= 0)
1544 connected = 1;
1545 }
1546 }
1547 if (!connected) {
1548 psin_server->sin6_port = htons(RFC1001_PORT);
1549 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1550 psin_server, sizeof (struct sockaddr_in6),0);
1551 if (rc >= 0)
1552 connected = 1;
1553 }
1554
1555 /* give up here - unless we want to retry on different
1556 protocol families some day */
1557 if (!connected) {
1558 if(orig_port)
1559 psin_server->sin6_port = orig_port;
1560 cFYI(1,("Error %d connecting to server via ipv6",rc));
1561 sock_release(*csocket);
1562 *csocket = NULL;
1563 return rc;
1564 }
1565 /* Eventually check for other socket options to change from
1566 the default. sock_setsockopt not used because it expects
1567 user space buffer */
1568 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1569
1570 return rc;
1571}
1572
1573int
1574cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1575 char *mount_data, const char *devname)
1576{
1577 int rc = 0;
1578 int xid;
1579 int address_type = AF_INET;
1580 struct socket *csocket = NULL;
1581 struct sockaddr_in sin_server;
1582 struct sockaddr_in6 sin_server6;
1583 struct smb_vol volume_info;
1584 struct cifsSesInfo *pSesInfo = NULL;
1585 struct cifsSesInfo *existingCifsSes = NULL;
1586 struct cifsTconInfo *tcon = NULL;
1587 struct TCP_Server_Info *srvTcp = NULL;
1588
1589 xid = GetXid();
1590
1591/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1592
1593 memset(&volume_info,0,sizeof(struct smb_vol));
1594 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001595 kfree(volume_info.UNC);
1596 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 FreeXid(xid);
1598 return -EINVAL;
1599 }
1600
1601 if (volume_info.username) {
1602 /* BB fixme parse for domain name here */
1603 cFYI(1, ("Username: %s ", volume_info.username));
1604
1605 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001606 cifserror("No username specified");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 /* In userspace mount helper we can get user name from alternate
1608 locations such as env variables and files on disk */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001609 kfree(volume_info.UNC);
1610 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 FreeXid(xid);
1612 return -EINVAL;
1613 }
1614
1615 if (volume_info.UNCip && volume_info.UNC) {
1616 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1617
1618 if(rc <= 0) {
1619 /* not ipv4 address, try ipv6 */
1620 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1621 if(rc > 0)
1622 address_type = AF_INET6;
1623 } else {
1624 address_type = AF_INET;
1625 }
1626
1627 if(rc <= 0) {
1628 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001629 kfree(volume_info.UNC);
1630 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 FreeXid(xid);
1632 return -EINVAL;
1633 }
1634
1635 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1636 /* success */
1637 rc = 0;
1638 } else if (volume_info.UNCip){
1639 /* BB using ip addr as server name connect to the DFS root below */
1640 cERROR(1,("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001641 kfree(volume_info.UNC);
1642 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 FreeXid(xid);
1644 return -EINVAL;
1645 } else /* which servers DFS root would we conect to */ {
1646 cERROR(1,
Steve Frenchbf820672005-12-01 22:32:42 -08001647 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001648 kfree(volume_info.UNC);
1649 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 FreeXid(xid);
1651 return -EINVAL;
1652 }
1653
1654 /* this is needed for ASCII cp to Unicode converts */
1655 if(volume_info.iocharset == NULL) {
1656 cifs_sb->local_nls = load_nls_default();
1657 /* load_nls_default can not return null */
1658 } else {
1659 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1660 if(cifs_sb->local_nls == NULL) {
1661 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001662 kfree(volume_info.UNC);
1663 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 FreeXid(xid);
1665 return -ELIBACC;
1666 }
1667 }
1668
1669 if(address_type == AF_INET)
1670 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1671 NULL /* no ipv6 addr */,
1672 volume_info.username, &srvTcp);
1673 else if(address_type == AF_INET6)
1674 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1675 &sin_server6.sin6_addr,
1676 volume_info.username, &srvTcp);
1677 else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001678 kfree(volume_info.UNC);
1679 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 FreeXid(xid);
1681 return -EINVAL;
1682 }
1683
1684
1685 if (srvTcp) {
Steve Frenchbf820672005-12-01 22:32:42 -08001686 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 } else { /* create socket */
1688 if(volume_info.port)
1689 sin_server.sin_port = htons(volume_info.port);
1690 else
1691 sin_server.sin_port = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001692 rc = ipv4_connect(&sin_server,&csocket,
1693 volume_info.source_rfc1001_name,
1694 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 if (rc < 0) {
1696 cERROR(1,
1697 ("Error connecting to IPv4 socket. Aborting operation"));
1698 if(csocket != NULL)
1699 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001700 kfree(volume_info.UNC);
1701 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 FreeXid(xid);
1703 return rc;
1704 }
1705
1706 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1707 if (srvTcp == NULL) {
1708 rc = -ENOMEM;
1709 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001710 kfree(volume_info.UNC);
1711 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 FreeXid(xid);
1713 return rc;
1714 } else {
1715 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1716 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1717 atomic_set(&srvTcp->inFlight,0);
1718 /* BB Add code for ipv6 case too */
1719 srvTcp->ssocket = csocket;
1720 srvTcp->protocolType = IPV4;
1721 init_waitqueue_head(&srvTcp->response_q);
1722 init_waitqueue_head(&srvTcp->request_q);
1723 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1724 /* at this point we are the only ones with the pointer
1725 to the struct since the kernel thread not created yet
1726 so no need to spinlock this init of tcpStatus */
1727 srvTcp->tcpStatus = CifsNew;
1728 init_MUTEX(&srvTcp->tcpSem);
1729 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1730 CLONE_FS | CLONE_FILES | CLONE_VM);
1731 if(rc < 0) {
1732 rc = -ENOMEM;
1733 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001734 kfree(volume_info.UNC);
1735 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 FreeXid(xid);
1737 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001738 }
1739 wait_for_completion(&cifsd_complete);
1740 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001742 memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001743 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 }
1745 }
1746
1747 if (existingCifsSes) {
1748 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001749 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001750 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 /* volume_info.UNC freed at end of function */
1752 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001753 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 pSesInfo = sesInfoAlloc();
1755 if (pSesInfo == NULL)
1756 rc = -ENOMEM;
1757 else {
1758 pSesInfo->server = srvTcp;
1759 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1760 NIPQUAD(sin_server.sin_addr.s_addr));
1761 }
1762
1763 if (!rc){
1764 /* volume_info.password freed at unmount */
1765 if (volume_info.password)
1766 pSesInfo->password = volume_info.password;
1767 if (volume_info.username)
1768 strncpy(pSesInfo->userName,
1769 volume_info.username,MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001770 if (volume_info.domainname) {
1771 int len = strlen(volume_info.domainname);
1772 pSesInfo->domainName =
1773 kmalloc(len + 1, GFP_KERNEL);
1774 if(pSesInfo->domainName)
1775 strcpy(pSesInfo->domainName,
1776 volume_info.domainname);
1777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 pSesInfo->linux_uid = volume_info.linux_uid;
1779 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00001780 /* BB FIXME need to pass vol->secFlgs BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1782 up(&pSesInfo->sesSem);
1783 if(!rc)
1784 atomic_inc(&srvTcp->socketUseCount);
1785 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001786 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 }
1788
1789 /* search for existing tcon to this server share */
1790 if (!rc) {
Steve French0ae0efa2005-10-10 10:57:19 -07001791 if(volume_info.rsize > CIFSMaxBufSize) {
1792 cERROR(1,("rsize %d too large, using MaxBufSize",
1793 volume_info.rsize));
1794 cifs_sb->rsize = CIFSMaxBufSize;
1795 } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07001797 else /* default */
1798 cifs_sb->rsize = CIFSMaxBufSize;
1799
1800 if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
1801 cERROR(1,("wsize %d too large using 4096 instead",
1802 volume_info.wsize));
1803 cifs_sb->wsize = 4096;
1804 } else if(volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 cifs_sb->wsize = volume_info.wsize;
1806 else
Steve French17cbbaf2006-01-24 20:26:48 -08001807 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08001808 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
1809 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08001810 /* old default of CIFSMaxBufSize was too small now
1811 that SMB Write2 can send multiple pages in kvec.
1812 RFC1001 does not describe what happens when frame
1813 bigger than 128K is sent so use that as max in
1814 conjunction with 52K kvec constraint on arch with 4K
1815 page size */
1816
Steve French6cec2ae2006-02-22 17:31:52 -06001817 if(cifs_sb->rsize < 2048) {
1818 cifs_sb->rsize = 2048;
1819 /* Windows ME may prefer this */
1820 cFYI(1,("readsize set to minimum 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 }
1822 cifs_sb->mnt_uid = volume_info.linux_uid;
1823 cifs_sb->mnt_gid = volume_info.linux_gid;
1824 cifs_sb->mnt_file_mode = volume_info.file_mode;
1825 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve Frencheeac8042006-01-13 21:34:58 -08001826 cFYI(1,("file mode: 0x%x dir mode: 0x%x",
1827 cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828
1829 if(volume_info.noperm)
1830 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1831 if(volume_info.setuids)
1832 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1833 if(volume_info.server_ino)
1834 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001835 if(volume_info.remap)
1836 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 if(volume_info.no_xattr)
1838 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve Frenchd7245c22005-07-14 18:25:12 -05001839 if(volume_info.sfu_emul)
1840 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001841 if(volume_info.nobrl)
1842 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French0a4b92c2006-01-12 15:44:21 -08001843 if(volume_info.cifs_acl)
1844 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Jeremy Allisonac670552005-06-22 17:26:35 -07001845
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 if(volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001847 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1849 }
1850
1851 tcon =
1852 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1853 volume_info.username);
1854 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08001855 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 /* we can have only one retry value for a connection
1857 to a share so for resources mounted more than once
1858 to the same server share the last value passed in
1859 for the retry flag is used */
1860 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001861 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 } else {
1863 tcon = tconInfoAlloc();
1864 if (tcon == NULL)
1865 rc = -ENOMEM;
1866 else {
1867 /* check for null share name ie connect to dfs root */
1868
1869 /* BB check if this works for exactly length three strings */
1870 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1871 && (strchr(volume_info.UNC + 3, '/') ==
1872 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001873 rc = connect_to_dfs_path(xid, pSesInfo,
1874 "", cifs_sb->local_nls,
1875 cifs_sb->mnt_cifs_flags &
1876 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001877 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 FreeXid(xid);
1879 return -ENODEV;
1880 } else {
1881 rc = CIFSTCon(xid, pSesInfo,
1882 volume_info.UNC,
1883 tcon, cifs_sb->local_nls);
1884 cFYI(1, ("CIFS Tcon rc = %d", rc));
1885 }
1886 if (!rc) {
1887 atomic_inc(&pSesInfo->inUse);
1888 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001889 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 }
1891 }
1892 }
1893 }
1894 if(pSesInfo) {
1895 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1896 sb->s_maxbytes = (u64) 1 << 63;
1897 } else
1898 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1899 }
1900
1901 sb->s_time_gran = 100;
1902
1903/* on error free sesinfo and tcon struct if needed */
1904 if (rc) {
1905 /* if session setup failed, use count is zero but
1906 we still need to free cifsd thread */
1907 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1908 spin_lock(&GlobalMid_Lock);
1909 srvTcp->tcpStatus = CifsExiting;
1910 spin_unlock(&GlobalMid_Lock);
Steve Frenchf1914012005-08-18 09:37:34 -07001911 if(srvTcp->tsk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 send_sig(SIGKILL,srvTcp->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001913 wait_for_completion(&cifsd_complete);
1914 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 }
1916 /* If find_unc succeeded then rc == 0 so we can not end */
1917 if (tcon) /* up accidently freeing someone elses tcon struct */
1918 tconInfoFree(tcon);
1919 if (existingCifsSes == NULL) {
1920 if (pSesInfo) {
1921 if ((pSesInfo->server) &&
1922 (pSesInfo->status == CifsGood)) {
1923 int temp_rc;
1924 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1925 /* if the socketUseCount is now zero */
1926 if((temp_rc == -ESHUTDOWN) &&
Steve Frenchf1914012005-08-18 09:37:34 -07001927 (pSesInfo->server->tsk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 send_sig(SIGKILL,pSesInfo->server->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001929 wait_for_completion(&cifsd_complete);
1930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 } else
1932 cFYI(1, ("No session or bad tcon"));
1933 sesInfoFree(pSesInfo);
1934 /* pSesInfo = NULL; */
1935 }
1936 }
1937 } else {
1938 atomic_inc(&tcon->useCount);
1939 cifs_sb->tcon = tcon;
1940 tcon->ses = pSesInfo;
1941
Steve French82940a42006-03-02 03:24:57 +00001942 /* do not care if following two calls succeed - informational */
Steve French737b7582005-04-28 22:41:06 -07001943 CIFSSMBQFSDeviceInfo(xid, tcon);
1944 CIFSSMBQFSAttributeInfo(xid, tcon);
Steve French82940a42006-03-02 03:24:57 +00001945
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001947 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French82940a42006-03-02 03:24:57 +00001948 __u64 cap =
1949 le64_to_cpu(tcon->fsUnixInfo.Capability);
1950 cap &= CIFS_UNIX_CAP_MASK;
1951 if(volume_info.no_psx_acl)
1952 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1953 else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
1954 cFYI(1,("negotiated posix acl support"));
1955 sb->s_flags |= MS_POSIXACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 }
Jeremy Allisonac670552005-06-22 17:26:35 -07001957
Steve French82940a42006-03-02 03:24:57 +00001958 if(volume_info.posix_paths == 0)
1959 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
1960 else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
1961 cFYI(1,("negotiate posix pathnames"));
1962 cifs_sb->mnt_cifs_flags |=
1963 CIFS_MOUNT_POSIX_PATHS;
1964 }
1965
1966 cFYI(1,("Negotiate caps 0x%x",(int)cap));
1967
1968 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
1969 cFYI(1,("setting capabilities failed"));
Jeremy Allisonac670552005-06-22 17:26:35 -07001970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 }
1972 }
Steve French3e844692005-10-03 13:37:24 -07001973 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
1974 cifs_sb->wsize = min(cifs_sb->wsize,
1975 (tcon->ses->server->maxBuf -
1976 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07001977 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
1978 cifs_sb->rsize = min(cifs_sb->rsize,
1979 (tcon->ses->server->maxBuf -
1980 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 }
1982
1983 /* volume_info.password is freed above when existing session found
1984 (in which case it is not needed anymore) but when new sesion is created
1985 the password ptr is put in the new session structure (in which case the
1986 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001987 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 FreeXid(xid);
1989 return rc;
1990}
1991
1992static int
1993CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00001994 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 const struct nls_table *nls_codepage)
1996{
1997 struct smb_hdr *smb_buffer;
1998 struct smb_hdr *smb_buffer_response;
1999 SESSION_SETUP_ANDX *pSMB;
2000 SESSION_SETUP_ANDX *pSMBr;
2001 char *bcc_ptr;
2002 char *user;
2003 char *domain;
2004 int rc = 0;
2005 int remaining_words = 0;
2006 int bytes_returned = 0;
2007 int len;
2008 __u32 capabilities;
2009 __u16 count;
2010
Steve Frencheeac8042006-01-13 21:34:58 -08002011 cFYI(1, ("In sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 if(ses == NULL)
2013 return -EINVAL;
2014 user = ses->userName;
2015 domain = ses->domainName;
2016 smb_buffer = cifs_buf_get();
2017 if (smb_buffer == NULL) {
2018 return -ENOMEM;
2019 }
2020 smb_buffer_response = smb_buffer;
2021 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2022
2023 /* send SMBsessionSetup here */
2024 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2025 NULL /* no tCon exists yet */ , 13 /* wct */ );
2026
Steve French1982c342005-08-17 12:38:22 -07002027 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 pSMB->req_no_secext.AndXCommand = 0xFF;
2029 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2030 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2031
2032 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2033 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2034
2035 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2036 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2037 if (ses->capabilities & CAP_UNICODE) {
2038 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2039 capabilities |= CAP_UNICODE;
2040 }
2041 if (ses->capabilities & CAP_STATUS32) {
2042 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2043 capabilities |= CAP_STATUS32;
2044 }
2045 if (ses->capabilities & CAP_DFS) {
2046 smb_buffer->Flags2 |= SMBFLG2_DFS;
2047 capabilities |= CAP_DFS;
2048 }
2049 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2050
2051 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002052 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053
2054 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002055 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002057 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2058 bcc_ptr += CIFS_SESS_KEY_SIZE;
2059 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2060 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061
2062 if (ses->capabilities & CAP_UNICODE) {
2063 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2064 *bcc_ptr = 0;
2065 bcc_ptr++;
2066 }
2067 if(user == NULL)
Steve French39798772006-05-31 22:40:51 +00002068 bytes_returned = 0; /* skip null user */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 else
2070 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002071 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 nls_codepage);
2073 /* convert number of 16 bit words to bytes */
2074 bcc_ptr += 2 * bytes_returned;
2075 bcc_ptr += 2; /* trailing null */
2076 if (domain == NULL)
2077 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002078 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 "CIFS_LINUX_DOM", 32, nls_codepage);
2080 else
2081 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002082 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 nls_codepage);
2084 bcc_ptr += 2 * bytes_returned;
2085 bcc_ptr += 2;
2086 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002087 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 32, nls_codepage);
2089 bcc_ptr += 2 * bytes_returned;
2090 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002091 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 32, nls_codepage);
2093 bcc_ptr += 2 * bytes_returned;
2094 bcc_ptr += 2;
2095 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002096 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 64, nls_codepage);
2098 bcc_ptr += 2 * bytes_returned;
2099 bcc_ptr += 2;
2100 } else {
2101 if(user != NULL) {
2102 strncpy(bcc_ptr, user, 200);
2103 bcc_ptr += strnlen(user, 200);
2104 }
2105 *bcc_ptr = 0;
2106 bcc_ptr++;
2107 if (domain == NULL) {
2108 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2109 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2110 } else {
2111 strncpy(bcc_ptr, domain, 64);
2112 bcc_ptr += strnlen(domain, 64);
2113 *bcc_ptr = 0;
2114 bcc_ptr++;
2115 }
2116 strcpy(bcc_ptr, "Linux version ");
2117 bcc_ptr += strlen("Linux version ");
2118 strcpy(bcc_ptr, system_utsname.release);
2119 bcc_ptr += strlen(system_utsname.release) + 1;
2120 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2121 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2122 }
2123 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2124 smb_buffer->smb_buf_length += count;
2125 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2126
2127 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2128 &bytes_returned, 1);
2129 if (rc) {
2130/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2131 } else if ((smb_buffer_response->WordCount == 3)
2132 || (smb_buffer_response->WordCount == 4)) {
2133 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2134 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2135 if (action & GUEST_LOGIN)
2136 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2137 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2138 cFYI(1, ("UID = %d ", ses->Suid));
2139 /* response can have either 3 or 4 word count - Samba sends 3 */
2140 bcc_ptr = pByteArea(smb_buffer_response);
2141 if ((pSMBr->resp.hdr.WordCount == 3)
2142 || ((pSMBr->resp.hdr.WordCount == 4)
2143 && (blob_len < pSMBr->resp.ByteCount))) {
2144 if (pSMBr->resp.hdr.WordCount == 4)
2145 bcc_ptr += blob_len;
2146
2147 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2148 if ((long) (bcc_ptr) % 2) {
2149 remaining_words =
2150 (BCC(smb_buffer_response) - 1) /2;
2151 bcc_ptr++; /* Unicode strings must be word aligned */
2152 } else {
2153 remaining_words =
2154 BCC(smb_buffer_response) / 2;
2155 }
2156 len =
2157 UniStrnlen((wchar_t *) bcc_ptr,
2158 remaining_words - 1);
2159/* We look for obvious messed up bcc or strings in response so we do not go off
2160 the end since (at least) WIN2K and Windows XP have a major bug in not null
2161 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002162 if(ses->serverOS)
2163 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002164 ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002165 if(ses->serverOS == NULL)
2166 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002168 (__le16 *)bcc_ptr, len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 bcc_ptr += 2 * (len + 1);
2170 remaining_words -= len + 1;
2171 ses->serverOS[2 * len] = 0;
2172 ses->serverOS[1 + (2 * len)] = 0;
2173 if (remaining_words > 0) {
2174 len = UniStrnlen((wchar_t *)bcc_ptr,
2175 remaining_words-1);
Steve Frencha424f8b2006-05-30 18:06:04 +00002176 if(ses->serverNOS)
2177 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002178 ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002179 if(ses->serverNOS == NULL)
2180 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 cifs_strfromUCS_le(ses->serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002182 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 bcc_ptr += 2 * (len + 1);
2184 ses->serverNOS[2 * len] = 0;
2185 ses->serverNOS[1 + (2 * len)] = 0;
2186 if(strncmp(ses->serverNOS,
2187 "NT LAN Manager 4",16) == 0) {
2188 cFYI(1,("NT4 server"));
2189 ses->flags |= CIFS_SES_NT4;
2190 }
2191 remaining_words -= len + 1;
2192 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002193 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00002195 if(ses->serverDomain)
2196 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002198 kzalloc(2*(len+1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002199 if(ses->serverDomain == NULL)
2200 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 cifs_strfromUCS_le(ses->serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002202 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 bcc_ptr += 2 * (len + 1);
2204 ses->serverDomain[2*len] = 0;
2205 ses->serverDomain[1+(2*len)] = 0;
2206 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002207 else {
2208 if(ses->serverDomain)
2209 kfree(ses->serverDomain);
Steve French433dc242005-04-28 22:41:08 -07002210 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002211 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002214 /* if these kcallocs fail not much we
2215 can do, but better to not fail the
2216 sesssetup itself */
Steve Frencha424f8b2006-05-30 18:06:04 +00002217 if(ses->serverDomain)
2218 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002220 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002221 if(ses->serverNOS)
2222 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002224 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 }
2226 } else { /* ASCII */
2227 len = strnlen(bcc_ptr, 1024);
2228 if (((long) bcc_ptr + len) - (long)
2229 pByteArea(smb_buffer_response)
2230 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00002231 if(ses->serverOS)
2232 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002233 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002234 if(ses->serverOS == NULL)
2235 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 strncpy(ses->serverOS,bcc_ptr, len);
2237
2238 bcc_ptr += len;
2239 bcc_ptr[0] = 0; /* null terminate the string */
2240 bcc_ptr++;
2241
2242 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002243 if(ses->serverNOS)
2244 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002245 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002246 if(ses->serverNOS == NULL)
2247 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 strncpy(ses->serverNOS, bcc_ptr, len);
2249 bcc_ptr += len;
2250 bcc_ptr[0] = 0;
2251 bcc_ptr++;
2252
2253 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002254 if(ses->serverDomain)
2255 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07002256 ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002257 if(ses->serverDomain == NULL)
2258 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 strncpy(ses->serverDomain, bcc_ptr, len);
2260 bcc_ptr += len;
2261 bcc_ptr[0] = 0;
2262 bcc_ptr++;
2263 } else
2264 cFYI(1,
2265 ("Variable field of length %d extends beyond end of smb ",
2266 len));
2267 }
2268 } else {
2269 cERROR(1,
2270 (" Security Blob Length extends beyond end of SMB"));
2271 }
2272 } else {
2273 cERROR(1,
2274 (" Invalid Word count %d: ",
2275 smb_buffer_response->WordCount));
2276 rc = -EIO;
2277 }
Steve French433dc242005-04-28 22:41:08 -07002278sesssetup_nomem: /* do not return an error on nomem for the info strings,
2279 since that could make reconnection harder, and
2280 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 if (smb_buffer)
2282 cifs_buf_release(smb_buffer);
2283
2284 return rc;
2285}
2286
2287static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2289 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2290 const struct nls_table *nls_codepage)
2291{
2292 struct smb_hdr *smb_buffer;
2293 struct smb_hdr *smb_buffer_response;
2294 SESSION_SETUP_ANDX *pSMB;
2295 SESSION_SETUP_ANDX *pSMBr;
2296 char *bcc_ptr;
2297 char *domain;
2298 int rc = 0;
2299 int remaining_words = 0;
2300 int bytes_returned = 0;
2301 int len;
2302 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2303 PNEGOTIATE_MESSAGE SecurityBlob;
2304 PCHALLENGE_MESSAGE SecurityBlob2;
2305 __u32 negotiate_flags, capabilities;
2306 __u16 count;
2307
Steve French12b3b8f2006-02-09 21:12:47 +00002308 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 if(ses == NULL)
2310 return -EINVAL;
2311 domain = ses->domainName;
2312 *pNTLMv2_flag = FALSE;
2313 smb_buffer = cifs_buf_get();
2314 if (smb_buffer == NULL) {
2315 return -ENOMEM;
2316 }
2317 smb_buffer_response = smb_buffer;
2318 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2319 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2320
2321 /* send SMBsessionSetup here */
2322 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2323 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002324
2325 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2327 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2328
2329 pSMB->req.AndXCommand = 0xFF;
2330 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2331 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2332
2333 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2334 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2335
2336 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2337 CAP_EXTENDED_SECURITY;
2338 if (ses->capabilities & CAP_UNICODE) {
2339 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2340 capabilities |= CAP_UNICODE;
2341 }
2342 if (ses->capabilities & CAP_STATUS32) {
2343 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2344 capabilities |= CAP_STATUS32;
2345 }
2346 if (ses->capabilities & CAP_DFS) {
2347 smb_buffer->Flags2 |= SMBFLG2_DFS;
2348 capabilities |= CAP_DFS;
2349 }
2350 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2351
2352 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2353 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2354 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2355 SecurityBlob->MessageType = NtLmNegotiate;
2356 negotiate_flags =
2357 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002358 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2359 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2361 if(sign_CIFS_PDUs)
2362 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve French39798772006-05-31 22:40:51 +00002363/* if(ntlmv2_support)
2364 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 /* setup pointers to domain name and workstation name */
2366 bcc_ptr += SecurityBlobLength;
2367
2368 SecurityBlob->WorkstationName.Buffer = 0;
2369 SecurityBlob->WorkstationName.Length = 0;
2370 SecurityBlob->WorkstationName.MaximumLength = 0;
2371
Steve French12b3b8f2006-02-09 21:12:47 +00002372 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2373 along with username on auth request (ie the response to challenge) */
2374 SecurityBlob->DomainName.Buffer = 0;
2375 SecurityBlob->DomainName.Length = 0;
2376 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 if (ses->capabilities & CAP_UNICODE) {
2378 if ((long) bcc_ptr % 2) {
2379 *bcc_ptr = 0;
2380 bcc_ptr++;
2381 }
2382
2383 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002384 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 32, nls_codepage);
2386 bcc_ptr += 2 * bytes_returned;
2387 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002388 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 nls_codepage);
2390 bcc_ptr += 2 * bytes_returned;
2391 bcc_ptr += 2; /* null terminate Linux version */
2392 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002393 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 64, nls_codepage);
2395 bcc_ptr += 2 * bytes_returned;
2396 *(bcc_ptr + 1) = 0;
2397 *(bcc_ptr + 2) = 0;
2398 bcc_ptr += 2; /* null terminate network opsys string */
2399 *(bcc_ptr + 1) = 0;
2400 *(bcc_ptr + 2) = 0;
2401 bcc_ptr += 2; /* null domain */
2402 } else { /* ASCII */
2403 strcpy(bcc_ptr, "Linux version ");
2404 bcc_ptr += strlen("Linux version ");
2405 strcpy(bcc_ptr, system_utsname.release);
2406 bcc_ptr += strlen(system_utsname.release) + 1;
2407 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2408 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2409 bcc_ptr++; /* empty domain field */
2410 *bcc_ptr = 0;
2411 }
2412 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2413 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2414 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2415 smb_buffer->smb_buf_length += count;
2416 pSMB->req.ByteCount = cpu_to_le16(count);
2417
2418 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2419 &bytes_returned, 1);
2420
2421 if (smb_buffer_response->Status.CifsError ==
2422 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2423 rc = 0;
2424
2425 if (rc) {
2426/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2427 } else if ((smb_buffer_response->WordCount == 3)
2428 || (smb_buffer_response->WordCount == 4)) {
2429 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2430 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2431
2432 if (action & GUEST_LOGIN)
2433 cFYI(1, (" Guest login"));
2434 /* Do we want to set anything in SesInfo struct when guest login? */
2435
2436 bcc_ptr = pByteArea(smb_buffer_response);
2437 /* response can have either 3 or 4 word count - Samba sends 3 */
2438
2439 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2440 if (SecurityBlob2->MessageType != NtLmChallenge) {
2441 cFYI(1,
2442 ("Unexpected NTLMSSP message type received %d",
2443 SecurityBlob2->MessageType));
2444 } else if (ses) {
2445 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002446 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 if ((pSMBr->resp.hdr.WordCount == 3)
2448 || ((pSMBr->resp.hdr.WordCount == 4)
2449 && (blob_len <
2450 pSMBr->resp.ByteCount))) {
2451
2452 if (pSMBr->resp.hdr.WordCount == 4) {
2453 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002454 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 blob_len));
2456 }
2457
Steve French12b3b8f2006-02-09 21:12:47 +00002458 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459
2460 memcpy(ses->server->cryptKey,
2461 SecurityBlob2->Challenge,
2462 CIFS_CRYPTO_KEY_SIZE);
Steve French12b3b8f2006-02-09 21:12:47 +00002463 if(SecurityBlob2->NegotiateFlags &
2464 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 *pNTLMv2_flag = TRUE;
2466
2467 if((SecurityBlob2->NegotiateFlags &
2468 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2469 || (sign_CIFS_PDUs > 1))
2470 ses->server->secMode |=
2471 SECMODE_SIGN_REQUIRED;
2472 if ((SecurityBlob2->NegotiateFlags &
2473 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2474 ses->server->secMode |=
2475 SECMODE_SIGN_ENABLED;
2476
2477 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2478 if ((long) (bcc_ptr) % 2) {
2479 remaining_words =
2480 (BCC(smb_buffer_response)
2481 - 1) / 2;
2482 bcc_ptr++; /* Unicode strings must be word aligned */
2483 } else {
2484 remaining_words =
2485 BCC
2486 (smb_buffer_response) / 2;
2487 }
2488 len =
2489 UniStrnlen((wchar_t *) bcc_ptr,
2490 remaining_words - 1);
2491/* We look for obvious messed up bcc or strings in response so we do not go off
2492 the end since (at least) WIN2K and Windows XP have a major bug in not null
2493 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002494 if(ses->serverOS)
2495 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002497 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002499 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 bcc_ptr, len,
2501 nls_codepage);
2502 bcc_ptr += 2 * (len + 1);
2503 remaining_words -= len + 1;
2504 ses->serverOS[2 * len] = 0;
2505 ses->serverOS[1 + (2 * len)] = 0;
2506 if (remaining_words > 0) {
2507 len = UniStrnlen((wchar_t *)
2508 bcc_ptr,
2509 remaining_words
2510 - 1);
Steve Frencha424f8b2006-05-30 18:06:04 +00002511 if(ses->serverNOS)
2512 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002514 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 GFP_KERNEL);
2516 cifs_strfromUCS_le(ses->
2517 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002518 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 bcc_ptr,
2520 len,
2521 nls_codepage);
2522 bcc_ptr += 2 * (len + 1);
2523 ses->serverNOS[2 * len] = 0;
2524 ses->serverNOS[1 +
2525 (2 * len)] = 0;
2526 remaining_words -= len + 1;
2527 if (remaining_words > 0) {
2528 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2529 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00002530 if(ses->serverDomain)
2531 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002533 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 (len +
2535 1),
2536 GFP_KERNEL);
2537 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002538 (ses->serverDomain,
2539 (__le16 *)bcc_ptr,
2540 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 bcc_ptr +=
2542 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002543 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002545 ses->serverDomain
2546 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 = 0;
2548 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002549 else {
2550 if(ses->serverDomain)
2551 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002553 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 } else { /* no room so create dummy domain and NOS string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002557 if(ses->serverDomain);
2558 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002560 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002561 if(ses->serverNOS)
2562 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002564 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 }
2566 } else { /* ASCII */
2567 len = strnlen(bcc_ptr, 1024);
2568 if (((long) bcc_ptr + len) - (long)
2569 pByteArea(smb_buffer_response)
2570 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00002571 if(ses->serverOS)
2572 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002574 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 GFP_KERNEL);
2576 strncpy(ses->serverOS,
2577 bcc_ptr, len);
2578
2579 bcc_ptr += len;
2580 bcc_ptr[0] = 0; /* null terminate string */
2581 bcc_ptr++;
2582
2583 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002584 if(ses->serverNOS)
2585 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002587 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 GFP_KERNEL);
2589 strncpy(ses->serverNOS, bcc_ptr, len);
2590 bcc_ptr += len;
2591 bcc_ptr[0] = 0;
2592 bcc_ptr++;
2593
2594 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002595 if(ses->serverDomain)
2596 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002598 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 GFP_KERNEL);
2600 strncpy(ses->serverDomain, bcc_ptr, len);
2601 bcc_ptr += len;
2602 bcc_ptr[0] = 0;
2603 bcc_ptr++;
2604 } else
2605 cFYI(1,
Steve French12b3b8f2006-02-09 21:12:47 +00002606 ("Variable field of length %d extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 len));
2608 }
2609 } else {
2610 cERROR(1,
2611 (" Security Blob Length extends beyond end of SMB"));
2612 }
2613 } else {
2614 cERROR(1, ("No session structure passed in."));
2615 }
2616 } else {
2617 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002618 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 smb_buffer_response->WordCount));
2620 rc = -EIO;
2621 }
2622
2623 if (smb_buffer)
2624 cifs_buf_release(smb_buffer);
2625
2626 return rc;
2627}
2628static int
2629CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2630 char *ntlm_session_key, int ntlmv2_flag,
2631 const struct nls_table *nls_codepage)
2632{
2633 struct smb_hdr *smb_buffer;
2634 struct smb_hdr *smb_buffer_response;
2635 SESSION_SETUP_ANDX *pSMB;
2636 SESSION_SETUP_ANDX *pSMBr;
2637 char *bcc_ptr;
2638 char *user;
2639 char *domain;
2640 int rc = 0;
2641 int remaining_words = 0;
2642 int bytes_returned = 0;
2643 int len;
2644 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2645 PAUTHENTICATE_MESSAGE SecurityBlob;
2646 __u32 negotiate_flags, capabilities;
2647 __u16 count;
2648
2649 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2650 if(ses == NULL)
2651 return -EINVAL;
2652 user = ses->userName;
2653 domain = ses->domainName;
2654 smb_buffer = cifs_buf_get();
2655 if (smb_buffer == NULL) {
2656 return -ENOMEM;
2657 }
2658 smb_buffer_response = smb_buffer;
2659 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2660 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2661
2662 /* send SMBsessionSetup here */
2663 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2664 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002665
2666 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2668 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2669 pSMB->req.AndXCommand = 0xFF;
2670 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2671 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2672
2673 pSMB->req.hdr.Uid = ses->Suid;
2674
2675 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2676 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2677
2678 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2679 CAP_EXTENDED_SECURITY;
2680 if (ses->capabilities & CAP_UNICODE) {
2681 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2682 capabilities |= CAP_UNICODE;
2683 }
2684 if (ses->capabilities & CAP_STATUS32) {
2685 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2686 capabilities |= CAP_STATUS32;
2687 }
2688 if (ses->capabilities & CAP_DFS) {
2689 smb_buffer->Flags2 |= SMBFLG2_DFS;
2690 capabilities |= CAP_DFS;
2691 }
2692 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2693
2694 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2695 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2696 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2697 SecurityBlob->MessageType = NtLmAuthenticate;
2698 bcc_ptr += SecurityBlobLength;
2699 negotiate_flags =
2700 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2701 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2702 0x80000000 | NTLMSSP_NEGOTIATE_128;
2703 if(sign_CIFS_PDUs)
2704 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2705 if(ntlmv2_flag)
2706 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2707
2708/* setup pointers to domain name and workstation name */
2709
2710 SecurityBlob->WorkstationName.Buffer = 0;
2711 SecurityBlob->WorkstationName.Length = 0;
2712 SecurityBlob->WorkstationName.MaximumLength = 0;
2713 SecurityBlob->SessionKey.Length = 0;
2714 SecurityBlob->SessionKey.MaximumLength = 0;
2715 SecurityBlob->SessionKey.Buffer = 0;
2716
2717 SecurityBlob->LmChallengeResponse.Length = 0;
2718 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2719 SecurityBlob->LmChallengeResponse.Buffer = 0;
2720
2721 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002722 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002724 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2725 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 SecurityBlob->NtChallengeResponse.Buffer =
2727 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002728 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2729 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730
2731 if (ses->capabilities & CAP_UNICODE) {
2732 if (domain == NULL) {
2733 SecurityBlob->DomainName.Buffer = 0;
2734 SecurityBlob->DomainName.Length = 0;
2735 SecurityBlob->DomainName.MaximumLength = 0;
2736 } else {
2737 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002738 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 nls_codepage);
2740 len *= 2;
2741 SecurityBlob->DomainName.MaximumLength =
2742 cpu_to_le16(len);
2743 SecurityBlob->DomainName.Buffer =
2744 cpu_to_le32(SecurityBlobLength);
2745 bcc_ptr += len;
2746 SecurityBlobLength += len;
2747 SecurityBlob->DomainName.Length =
2748 cpu_to_le16(len);
2749 }
2750 if (user == NULL) {
2751 SecurityBlob->UserName.Buffer = 0;
2752 SecurityBlob->UserName.Length = 0;
2753 SecurityBlob->UserName.MaximumLength = 0;
2754 } else {
2755 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002756 cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 nls_codepage);
2758 len *= 2;
2759 SecurityBlob->UserName.MaximumLength =
2760 cpu_to_le16(len);
2761 SecurityBlob->UserName.Buffer =
2762 cpu_to_le32(SecurityBlobLength);
2763 bcc_ptr += len;
2764 SecurityBlobLength += len;
2765 SecurityBlob->UserName.Length =
2766 cpu_to_le16(len);
2767 }
2768
Steve Frenche89dc922005-11-11 15:18:19 -08002769 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 SecurityBlob->WorkstationName.Length *= 2;
2771 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2772 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2773 bcc_ptr += SecurityBlob->WorkstationName.Length;
2774 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2775 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2776
2777 if ((long) bcc_ptr % 2) {
2778 *bcc_ptr = 0;
2779 bcc_ptr++;
2780 }
2781 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002782 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 32, nls_codepage);
2784 bcc_ptr += 2 * bytes_returned;
2785 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002786 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 nls_codepage);
2788 bcc_ptr += 2 * bytes_returned;
2789 bcc_ptr += 2; /* null term version string */
2790 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002791 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 64, nls_codepage);
2793 bcc_ptr += 2 * bytes_returned;
2794 *(bcc_ptr + 1) = 0;
2795 *(bcc_ptr + 2) = 0;
2796 bcc_ptr += 2; /* null terminate network opsys string */
2797 *(bcc_ptr + 1) = 0;
2798 *(bcc_ptr + 2) = 0;
2799 bcc_ptr += 2; /* null domain */
2800 } else { /* ASCII */
2801 if (domain == NULL) {
2802 SecurityBlob->DomainName.Buffer = 0;
2803 SecurityBlob->DomainName.Length = 0;
2804 SecurityBlob->DomainName.MaximumLength = 0;
2805 } else {
2806 __u16 len;
2807 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2808 strncpy(bcc_ptr, domain, 63);
2809 len = strnlen(domain, 64);
2810 SecurityBlob->DomainName.MaximumLength =
2811 cpu_to_le16(len);
2812 SecurityBlob->DomainName.Buffer =
2813 cpu_to_le32(SecurityBlobLength);
2814 bcc_ptr += len;
2815 SecurityBlobLength += len;
2816 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2817 }
2818 if (user == NULL) {
2819 SecurityBlob->UserName.Buffer = 0;
2820 SecurityBlob->UserName.Length = 0;
2821 SecurityBlob->UserName.MaximumLength = 0;
2822 } else {
2823 __u16 len;
2824 strncpy(bcc_ptr, user, 63);
2825 len = strnlen(user, 64);
2826 SecurityBlob->UserName.MaximumLength =
2827 cpu_to_le16(len);
2828 SecurityBlob->UserName.Buffer =
2829 cpu_to_le32(SecurityBlobLength);
2830 bcc_ptr += len;
2831 SecurityBlobLength += len;
2832 SecurityBlob->UserName.Length = cpu_to_le16(len);
2833 }
2834 /* BB fill in our workstation name if known BB */
2835
2836 strcpy(bcc_ptr, "Linux version ");
2837 bcc_ptr += strlen("Linux version ");
2838 strcpy(bcc_ptr, system_utsname.release);
2839 bcc_ptr += strlen(system_utsname.release) + 1;
2840 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2841 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2842 bcc_ptr++; /* null domain */
2843 *bcc_ptr = 0;
2844 }
2845 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2846 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2847 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2848 smb_buffer->smb_buf_length += count;
2849 pSMB->req.ByteCount = cpu_to_le16(count);
2850
2851 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2852 &bytes_returned, 1);
2853 if (rc) {
2854/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2855 } else if ((smb_buffer_response->WordCount == 3)
2856 || (smb_buffer_response->WordCount == 4)) {
2857 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2858 __u16 blob_len =
2859 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2860 if (action & GUEST_LOGIN)
2861 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2862/* if(SecurityBlob2->MessageType != NtLm??){
2863 cFYI("Unexpected message type on auth response is %d "));
2864 } */
2865 if (ses) {
2866 cFYI(1,
2867 ("Does UID on challenge %d match auth response UID %d ",
2868 ses->Suid, smb_buffer_response->Uid));
2869 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2870 bcc_ptr = pByteArea(smb_buffer_response);
2871 /* response can have either 3 or 4 word count - Samba sends 3 */
2872 if ((pSMBr->resp.hdr.WordCount == 3)
2873 || ((pSMBr->resp.hdr.WordCount == 4)
2874 && (blob_len <
2875 pSMBr->resp.ByteCount))) {
2876 if (pSMBr->resp.hdr.WordCount == 4) {
2877 bcc_ptr +=
2878 blob_len;
2879 cFYI(1,
2880 ("Security Blob Length %d ",
2881 blob_len));
2882 }
2883
2884 cFYI(1,
2885 ("NTLMSSP response to Authenticate "));
2886
2887 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2888 if ((long) (bcc_ptr) % 2) {
2889 remaining_words =
2890 (BCC(smb_buffer_response)
2891 - 1) / 2;
2892 bcc_ptr++; /* Unicode strings must be word aligned */
2893 } else {
2894 remaining_words = BCC(smb_buffer_response) / 2;
2895 }
2896 len =
2897 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2898/* We look for obvious messed up bcc or strings in response so we do not go off
2899 the end since (at least) WIN2K and Windows XP have a major bug in not null
2900 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002901 if(ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00002902 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002904 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002906 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 bcc_ptr, len,
2908 nls_codepage);
2909 bcc_ptr += 2 * (len + 1);
2910 remaining_words -= len + 1;
2911 ses->serverOS[2 * len] = 0;
2912 ses->serverOS[1 + (2 * len)] = 0;
2913 if (remaining_words > 0) {
2914 len = UniStrnlen((wchar_t *)
2915 bcc_ptr,
2916 remaining_words
2917 - 1);
Steve Frencha424f8b2006-05-30 18:06:04 +00002918 if(ses->serverNOS)
2919 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002921 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 GFP_KERNEL);
2923 cifs_strfromUCS_le(ses->
2924 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002925 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 bcc_ptr,
2927 len,
2928 nls_codepage);
2929 bcc_ptr += 2 * (len + 1);
2930 ses->serverNOS[2 * len] = 0;
2931 ses->serverNOS[1+(2*len)] = 0;
2932 remaining_words -= len + 1;
2933 if (remaining_words > 0) {
2934 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2935 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00002936 if(ses->serverDomain)
2937 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002939 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 (len +
2941 1),
2942 GFP_KERNEL);
2943 cifs_strfromUCS_le
2944 (ses->
2945 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002946 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 bcc_ptr, len,
2948 nls_codepage);
2949 bcc_ptr +=
2950 2 * (len + 1);
2951 ses->
2952 serverDomain[2
2953 * len]
2954 = 0;
2955 ses->
2956 serverDomain[1
2957 +
2958 (2
2959 *
2960 len)]
2961 = 0;
2962 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002963 else {
2964 if(ses->serverDomain)
2965 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07002966 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 } else { /* no room so create dummy domain and NOS string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002969 if(ses->serverDomain)
2970 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07002971 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002972 if(ses->serverNOS)
2973 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002974 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 }
2976 } else { /* ASCII */
2977 len = strnlen(bcc_ptr, 1024);
2978 if (((long) bcc_ptr + len) -
2979 (long) pByteArea(smb_buffer_response)
2980 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00002981 if(ses->serverOS)
2982 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002983 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 strncpy(ses->serverOS,bcc_ptr, len);
2985
2986 bcc_ptr += len;
2987 bcc_ptr[0] = 0; /* null terminate the string */
2988 bcc_ptr++;
2989
2990 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002991 if(ses->serverNOS)
2992 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002993 ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 strncpy(ses->serverNOS, bcc_ptr, len);
2995 bcc_ptr += len;
2996 bcc_ptr[0] = 0;
2997 bcc_ptr++;
2998
2999 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00003000 if(ses->serverDomain)
3001 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003002 ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 strncpy(ses->serverDomain, bcc_ptr, len);
3004 bcc_ptr += len;
3005 bcc_ptr[0] = 0;
3006 bcc_ptr++;
3007 } else
3008 cFYI(1,
3009 ("Variable field of length %d extends beyond end of smb ",
3010 len));
3011 }
3012 } else {
3013 cERROR(1,
3014 (" Security Blob Length extends beyond end of SMB"));
3015 }
3016 } else {
3017 cERROR(1, ("No session structure passed in."));
3018 }
3019 } else {
3020 cERROR(1,
3021 (" Invalid Word count %d: ",
3022 smb_buffer_response->WordCount));
3023 rc = -EIO;
3024 }
3025
3026 if (smb_buffer)
3027 cifs_buf_release(smb_buffer);
3028
3029 return rc;
3030}
3031
3032int
3033CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3034 const char *tree, struct cifsTconInfo *tcon,
3035 const struct nls_table *nls_codepage)
3036{
3037 struct smb_hdr *smb_buffer;
3038 struct smb_hdr *smb_buffer_response;
3039 TCONX_REQ *pSMB;
3040 TCONX_RSP *pSMBr;
3041 unsigned char *bcc_ptr;
3042 int rc = 0;
3043 int length;
3044 __u16 count;
3045
3046 if (ses == NULL)
3047 return -EIO;
3048
3049 smb_buffer = cifs_buf_get();
3050 if (smb_buffer == NULL) {
3051 return -ENOMEM;
3052 }
3053 smb_buffer_response = smb_buffer;
3054
3055 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3056 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003057
3058 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 smb_buffer->Uid = ses->Suid;
3060 pSMB = (TCONX_REQ *) smb_buffer;
3061 pSMBr = (TCONX_RSP *) smb_buffer_response;
3062
3063 pSMB->AndXCommand = 0xFF;
3064 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 bcc_ptr = &pSMB->Password[0];
Steve Frencheeac8042006-01-13 21:34:58 -08003066 if((ses->server->secMode) & SECMODE_USER) {
3067 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003068 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003069 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003070 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003071 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003072 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003073 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3074 specified as required (when that support is added to
3075 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003076 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003077 by Samba (not sure whether other servers allow
3078 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003079#ifdef CONFIG_CIFS_WEAK_PW_HASH
3080 if((extended_security & CIFSSEC_MAY_LANMAN) &&
3081 (ses->server->secType == LANMAN))
3082 calc_lanman_hash(ses, bcc_ptr);
3083 else
3084#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003085 SMBNTencrypt(ses->password,
3086 ses->server->cryptKey,
3087 bcc_ptr);
3088
Steve French7c7b25b2006-06-01 19:20:10 +00003089 bcc_ptr += CIFS_SESS_KEY_SIZE;
3090 if(ses->capabilities & CAP_UNICODE) {
3091 /* must align unicode strings */
3092 *bcc_ptr = 0; /* null byte password */
3093 bcc_ptr++;
3094 }
Steve Frencheeac8042006-01-13 21:34:58 -08003095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
Steve Frencha878fb22006-05-30 18:04:19 +00003097 if(ses->server->secMode &
3098 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3100
3101 if (ses->capabilities & CAP_STATUS32) {
3102 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3103 }
3104 if (ses->capabilities & CAP_DFS) {
3105 smb_buffer->Flags2 |= SMBFLG2_DFS;
3106 }
3107 if (ses->capabilities & CAP_UNICODE) {
3108 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3109 length =
Steve Frencha878fb22006-05-30 18:04:19 +00003110 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3111 6 /* max utf8 char length in bytes */ *
3112 (/* server len*/ + 256 /* share len */), nls_codepage);
3113 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 bcc_ptr += 2; /* skip trailing null */
3115 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 strcpy(bcc_ptr, tree);
3117 bcc_ptr += strlen(tree) + 1;
3118 }
3119 strcpy(bcc_ptr, "?????");
3120 bcc_ptr += strlen("?????");
3121 bcc_ptr += 1;
3122 count = bcc_ptr - &pSMB->Password[0];
3123 pSMB->hdr.smb_buf_length += count;
3124 pSMB->ByteCount = cpu_to_le16(count);
3125
3126 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3127
3128 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3129 /* above now done in SendReceive */
3130 if ((rc == 0) && (tcon != NULL)) {
3131 tcon->tidStatus = CifsGood;
3132 tcon->tid = smb_buffer_response->Tid;
3133 bcc_ptr = pByteArea(smb_buffer_response);
3134 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3135 /* skip service field (NB: this field is always ASCII) */
3136 bcc_ptr += length + 1;
3137 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3138 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3139 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3140 if ((bcc_ptr + (2 * length)) -
3141 pByteArea(smb_buffer_response) <=
3142 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003143 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003145 kzalloc(length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 cifs_strfromUCS_le(tcon->nativeFileSystem,
Steve Frenche89dc922005-11-11 15:18:19 -08003147 (__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 length, nls_codepage);
3149 bcc_ptr += 2 * length;
3150 bcc_ptr[0] = 0; /* null terminate the string */
3151 bcc_ptr[1] = 0;
3152 bcc_ptr += 2;
3153 }
3154 /* else do not bother copying these informational fields */
3155 } else {
3156 length = strnlen(bcc_ptr, 1024);
3157 if ((bcc_ptr + length) -
3158 pByteArea(smb_buffer_response) <=
3159 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003160 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003162 kzalloc(length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 strncpy(tcon->nativeFileSystem, bcc_ptr,
3164 length);
3165 }
3166 /* else do not bother copying these informational fields */
3167 }
Steve French39798772006-05-31 22:40:51 +00003168 if(smb_buffer_response->WordCount == 3)
3169 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3170 else
3171 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3173 } else if ((rc == 0) && tcon == NULL) {
3174 /* all we need to save for IPC$ connection */
3175 ses->ipc_tid = smb_buffer_response->Tid;
3176 }
3177
3178 if (smb_buffer)
3179 cifs_buf_release(smb_buffer);
3180 return rc;
3181}
3182
3183int
3184cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3185{
3186 int rc = 0;
3187 int xid;
3188 struct cifsSesInfo *ses = NULL;
3189 struct task_struct *cifsd_task;
3190
3191 xid = GetXid();
3192
3193 if (cifs_sb->tcon) {
3194 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3195 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3196 if (rc == -EBUSY) {
3197 FreeXid(xid);
3198 return 0;
3199 }
3200 tconInfoFree(cifs_sb->tcon);
3201 if ((ses) && (ses->server)) {
3202 /* save off task so we do not refer to ses later */
3203 cifsd_task = ses->server->tsk;
3204 cFYI(1, ("About to do SMBLogoff "));
3205 rc = CIFSSMBLogoff(xid, ses);
3206 if (rc == -EBUSY) {
3207 FreeXid(xid);
3208 return 0;
3209 } else if (rc == -ESHUTDOWN) {
3210 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf1914012005-08-18 09:37:34 -07003211 if(cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 send_sig(SIGKILL,cifsd_task,1);
Steve Frenchf1914012005-08-18 09:37:34 -07003213 wait_for_completion(&cifsd_complete);
3214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 rc = 0;
3216 } /* else - we have an smb session
3217 left on this socket do not kill cifsd */
3218 } else
3219 cFYI(1, ("No session or bad tcon"));
3220 }
3221
3222 cifs_sb->tcon = NULL;
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003223 if (ses)
3224 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 if (ses)
3226 sesInfoFree(ses);
3227
3228 FreeXid(xid);
3229 return rc; /* BB check if we should always return zero here */
3230}
3231
3232int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3233 struct nls_table * nls_info)
3234{
3235 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003236 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003238 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239
3240 /* what if server changes its buffer size after dropping the session? */
3241 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3242 rc = CIFSSMBNegotiate(xid, pSesInfo);
3243 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3244 rc = CIFSSMBNegotiate(xid, pSesInfo);
3245 if(rc == -EAGAIN)
3246 rc = -EHOSTDOWN;
3247 }
3248 if(rc == 0) {
3249 spin_lock(&GlobalMid_Lock);
3250 if(pSesInfo->server->tcpStatus != CifsExiting)
3251 pSesInfo->server->tcpStatus = CifsGood;
3252 else
3253 rc = -EHOSTDOWN;
3254 spin_unlock(&GlobalMid_Lock);
3255
3256 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003257 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 }
3259 if (!rc) {
3260 pSesInfo->capabilities = pSesInfo->server->capabilities;
3261 if(linuxExtEnabled == 0)
3262 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003263 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3265 pSesInfo->server->secMode,
3266 pSesInfo->server->capabilities,
3267 pSesInfo->server->timeZone));
Steve French189acaa2006-06-23 02:33:48 +00003268 if(experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003269 rc = CIFS_SessSetup(xid, pSesInfo,
3270 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003271 else if (extended_security
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3273 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003274 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 } else if (extended_security
3276 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3277 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003278 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3280 pSesInfo,
3281 &ntlmv2_flag,
3282 nls_info);
3283 if (!rc) {
3284 if(ntlmv2_flag) {
3285 char * v2_response;
3286 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3287 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3288 nls_info)) {
3289 rc = -ENOMEM;
3290 goto ss_err_exit;
3291 } else
3292 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3293 if(v2_response) {
3294 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003295 /* if(first_time)
3296 cifs_calculate_ntlmv2_mac_key(
3297 pSesInfo->server->mac_signing_key,
3298 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 kfree(v2_response);
3300 /* BB Put dummy sig in SessSetup PDU? */
3301 } else {
3302 rc = -ENOMEM;
3303 goto ss_err_exit;
3304 }
3305
3306 } else {
3307 SMBNTencrypt(pSesInfo->password,
3308 pSesInfo->server->cryptKey,
3309 ntlm_session_key);
3310
Steve Frenchad009ac2005-04-28 22:41:05 -07003311 if(first_time)
3312 cifs_calculate_mac_key(
3313 pSesInfo->server->mac_signing_key,
3314 ntlm_session_key,
3315 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 }
3317 /* for better security the weaker lanman hash not sent
3318 in AuthSessSetup so we no longer calculate it */
3319
3320 rc = CIFSNTLMSSPAuthSessSetup(xid,
3321 pSesInfo,
3322 ntlm_session_key,
3323 ntlmv2_flag,
3324 nls_info);
3325 }
3326 } else { /* old style NTLM 0.12 session setup */
3327 SMBNTencrypt(pSesInfo->password,
3328 pSesInfo->server->cryptKey,
3329 ntlm_session_key);
3330
Steve Frenchad009ac2005-04-28 22:41:05 -07003331 if(first_time)
3332 cifs_calculate_mac_key(
3333 pSesInfo->server->mac_signing_key,
3334 ntlm_session_key, pSesInfo->password);
3335
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 rc = CIFSSessSetup(xid, pSesInfo,
3337 ntlm_session_key, nls_info);
3338 }
3339 if (rc) {
3340 cERROR(1,("Send error in SessSetup = %d",rc));
3341 } else {
3342 cFYI(1,("CIFS Session Established successfully"));
3343 pSesInfo->status = CifsGood;
3344 }
3345 }
3346ss_err_exit:
3347 return rc;
3348}
3349