blob: c4aedcf5c92415d85aa5e4f1cddb757a6e6a4ea5 [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 French3a5ff612006-07-14 22:37:11 +0000615 /* so we do not time out requests to server
616 which is still responding (since server could
617 be busy but not dead) */
618 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700619 break;
620 }
621 }
622 spin_unlock(&GlobalMid_Lock);
623 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700624 /* Was previous buf put in mpx struct for multi-rsp? */
625 if(!isMultiRsp) {
626 /* smb buffer will be freed by user thread */
627 if(isLargeBuf) {
628 bigbuf = NULL;
629 } else
630 smallbuf = NULL;
631 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700632 wake_up_process(task_to_wake);
Steve Frenchd7c8c942006-03-03 10:43:49 +0000633 } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
Steve Frenche4eb2952005-04-28 22:41:09 -0700634 && (isMultiRsp == FALSE)) {
Steve French39798772006-05-31 22:40:51 +0000635 cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
Steve French70ca7342005-09-22 16:32:06 -0700636 cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
637 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000638#ifdef CONFIG_CIFS_DEBUG2
639 cifs_dump_detail(smb_buffer);
640 cifs_dump_mids(server);
641#endif /* CIFS_DEBUG2 */
642
Steve Frenche4eb2952005-04-28 22:41:09 -0700643 }
644 } /* end while !EXITING */
645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 spin_lock(&GlobalMid_Lock);
647 server->tcpStatus = CifsExiting;
648 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700649 /* check if we have blocked requests that need to free */
650 /* Note that cifs_max_pending is normally 50, but
651 can be set at module install time to as little as two */
652 if(atomic_read(&server->inFlight) >= cifs_max_pending)
653 atomic_set(&server->inFlight, cifs_max_pending - 1);
654 /* We do not want to set the max_pending too low or we
655 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 spin_unlock(&GlobalMid_Lock);
657 /* Although there should not be any requests blocked on
658 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700659 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 to the same server - they now will see the session is in exit state
661 and get out of SendReceive. */
662 wake_up_all(&server->request_q);
663 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700664 msleep(125);
665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 if(server->ssocket) {
667 sock_release(csocket);
668 server->ssocket = NULL;
669 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700670 /* buffer usuallly freed in free_mid - need to free it here on exit */
671 if (bigbuf != NULL)
672 cifs_buf_release(bigbuf);
673 if (smallbuf != NULL)
674 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
676 read_lock(&GlobalSMBSeslock);
677 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700678 /* loop through server session structures attached to this and
679 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 list_for_each(tmp, &GlobalSMBSessionList) {
681 ses =
682 list_entry(tmp, struct cifsSesInfo,
683 cifsSessionList);
684 if (ses->server == server) {
685 ses->status = CifsExiting;
686 ses->server = NULL;
687 }
688 }
689 read_unlock(&GlobalSMBSeslock);
690 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700691 /* although we can not zero the server struct pointer yet,
692 since there are active requests which may depnd on them,
693 mark the corresponding SMB sessions as exiting too */
694 list_for_each(tmp, &GlobalSMBSessionList) {
695 ses = list_entry(tmp, struct cifsSesInfo,
696 cifsSessionList);
697 if (ses->server == server) {
698 ses->status = CifsExiting;
699 }
700 }
701
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 spin_lock(&GlobalMid_Lock);
703 list_for_each(tmp, &server->pending_mid_q) {
704 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
705 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
706 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700707 ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 task_to_wake = mid_entry->tsk;
709 if(task_to_wake) {
710 wake_up_process(task_to_wake);
711 }
712 }
713 }
714 spin_unlock(&GlobalMid_Lock);
715 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700717 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 }
719
Steve Frenchf1914012005-08-18 09:37:34 -0700720 if (!list_empty(&server->pending_mid_q)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 /* mpx threads have not exited yet give them
722 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700723 /* due to delays on oplock break requests, we need
724 to wait at least 45 seconds before giving up
725 on a request getting a response and going ahead
726 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700728 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 /* if threads still have not exited they are probably never
730 coming home not much else we can do but free the memory */
731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
733 write_lock(&GlobalSMBSeslock);
734 atomic_dec(&tcpSesAllocCount);
735 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700736
737 /* last chance to mark ses pointers invalid
738 if there are any pointing to this (e.g
739 if a crazy root user tried to kill cifsd
740 kernel thread explicitly this might happen) */
741 list_for_each(tmp, &GlobalSMBSessionList) {
742 ses = list_entry(tmp, struct cifsSesInfo,
743 cifsSessionList);
744 if (ses->server == server) {
745 ses->server = NULL;
746 }
747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700749
750 kfree(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if(length > 0) {
752 mempool_resize(cifs_req_poolp,
753 length + cifs_min_rcv,
754 GFP_KERNEL);
755 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700756
Steve Frenchf1914012005-08-18 09:37:34 -0700757 complete_and_exit(&cifsd_complete, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 return 0;
759}
760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761static int
762cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
763{
764 char *value;
765 char *data;
766 unsigned int temp_len, i, j;
767 char separator[2];
768
769 separator[0] = ',';
770 separator[1] = 0;
771
772 memset(vol->source_rfc1001_name,0x20,15);
773 for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
774 /* does not have to be a perfect mapping since the field is
775 informational, only used for servers that do not support
776 port 445 and it can be overridden at mount time */
Steve French09d1db52005-04-28 22:41:08 -0700777 vol->source_rfc1001_name[i] =
778 toupper(system_utsname.nodename[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
780 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700781 /* null target name indicates to use *SMBSERVR default called name
782 if we end up sending RFC1001 session initialize */
783 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 vol->linux_uid = current->uid; /* current->euid instead? */
785 vol->linux_gid = current->gid;
786 vol->dir_mode = S_IRWXUGO;
787 /* 2767 perms indicate mandatory locking support */
788 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
789
790 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
791 vol->rw = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700792 /* default is always to request posix paths. */
793 vol->posix_paths = 1;
794
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if (!options)
796 return 1;
797
798 if(strncmp(options,"sep=",4) == 0) {
799 if(options[4] != 0) {
800 separator[0] = options[4];
801 options += 5;
802 } else {
803 cFYI(1,("Null separator not allowed"));
804 }
805 }
806
807 while ((data = strsep(&options, separator)) != NULL) {
808 if (!*data)
809 continue;
810 if ((value = strchr(data, '=')) != NULL)
811 *value++ = '\0';
812
813 if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
814 vol->no_xattr = 0;
815 } else if (strnicmp(data, "nouser_xattr",12) == 0) {
816 vol->no_xattr = 1;
817 } else if (strnicmp(data, "user", 4) == 0) {
818 if (!value || !*value) {
819 printk(KERN_WARNING
820 "CIFS: invalid or missing username\n");
821 return 1; /* needs_arg; */
822 }
823 if (strnlen(value, 200) < 200) {
824 vol->username = value;
825 } else {
826 printk(KERN_WARNING "CIFS: username too long\n");
827 return 1;
828 }
829 } else if (strnicmp(data, "pass", 4) == 0) {
830 if (!value) {
831 vol->password = NULL;
832 continue;
833 } else if(value[0] == 0) {
834 /* check if string begins with double comma
835 since that would mean the password really
836 does start with a comma, and would not
837 indicate an empty string */
838 if(value[1] != separator[0]) {
839 vol->password = NULL;
840 continue;
841 }
842 }
843 temp_len = strlen(value);
844 /* removed password length check, NTLM passwords
845 can be arbitrarily long */
846
847 /* if comma in password, the string will be
848 prematurely null terminated. Commas in password are
849 specified across the cifs mount interface by a double
850 comma ie ,, and a comma used as in other cases ie ','
851 as a parameter delimiter/separator is single and due
852 to the strsep above is temporarily zeroed. */
853
854 /* NB: password legally can have multiple commas and
855 the only illegal character in a password is null */
856
Steve French09d1db52005-04-28 22:41:08 -0700857 if ((value[temp_len] == 0) &&
858 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 /* reinsert comma */
860 value[temp_len] = separator[0];
861 temp_len+=2; /* move after the second comma */
862 while(value[temp_len] != 0) {
863 if (value[temp_len] == separator[0]) {
Steve French09d1db52005-04-28 22:41:08 -0700864 if (value[temp_len+1] ==
865 separator[0]) {
866 /* skip second comma */
867 temp_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 } else {
869 /* single comma indicating start
870 of next parm */
871 break;
872 }
873 }
874 temp_len++;
875 }
876 if(value[temp_len] == 0) {
877 options = NULL;
878 } else {
879 value[temp_len] = 0;
880 /* point option to start of next parm */
881 options = value + temp_len + 1;
882 }
883 /* go from value to value + temp_len condensing
884 double commas to singles. Note that this ends up
885 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700886 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700887 if(vol->password == NULL) {
888 printk("CIFS: no memory for pass\n");
889 return 1;
890 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 for(i=0,j=0;i<temp_len;i++,j++) {
892 vol->password[j] = value[i];
Steve French09d1db52005-04-28 22:41:08 -0700893 if(value[i] == separator[0]
894 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 /* skip second comma */
896 i++;
897 }
898 }
899 vol->password[j] = 0;
900 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700901 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -0700902 if(vol->password == NULL) {
903 printk("CIFS: no memory for pass\n");
904 return 1;
905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 strcpy(vol->password, value);
907 }
908 } else if (strnicmp(data, "ip", 2) == 0) {
909 if (!value || !*value) {
910 vol->UNCip = NULL;
911 } else if (strnlen(value, 35) < 35) {
912 vol->UNCip = value;
913 } else {
914 printk(KERN_WARNING "CIFS: ip address too long\n");
915 return 1;
916 }
Steve Frenchbf820672005-12-01 22:32:42 -0800917 } else if (strnicmp(data, "sec", 3) == 0) {
918 if (!value || !*value) {
919 cERROR(1,("no security value specified"));
920 continue;
921 } else if (strnicmp(value, "krb5i", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000922 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000923 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800924 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000925 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
Steve French189acaa2006-06-23 02:33:48 +0000926 CIFSSEC_MAY_KRB5; */
Steve Frenchbf820672005-12-01 22:32:42 -0800927 cERROR(1,("Krb5 cifs privacy not supported"));
928 return 1;
929 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000930 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800931 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000932 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000933 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800934 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000935 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800936 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000937 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000938 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800939 } else if (strnicmp(value, "ntlm", 4) == 0) {
940 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000941 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800942 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000943 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000944 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000945#ifdef CONFIG_CIFS_WEAK_PW_HASH
946 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000947 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000948#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800949 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000950 vol->nullauth = 1;
Steve Frenchbf820672005-12-01 22:32:42 -0800951 } else {
952 cERROR(1,("bad security option: %s", value));
953 return 1;
954 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 } else if ((strnicmp(data, "unc", 3) == 0)
956 || (strnicmp(data, "target", 6) == 0)
957 || (strnicmp(data, "path", 4) == 0)) {
958 if (!value || !*value) {
959 printk(KERN_WARNING
960 "CIFS: invalid path to network resource\n");
961 return 1; /* needs_arg; */
962 }
963 if ((temp_len = strnlen(value, 300)) < 300) {
964 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
965 if(vol->UNC == NULL)
966 return 1;
967 strcpy(vol->UNC,value);
968 if (strncmp(vol->UNC, "//", 2) == 0) {
969 vol->UNC[0] = '\\';
970 vol->UNC[1] = '\\';
971 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
972 printk(KERN_WARNING
973 "CIFS: UNC Path does not begin with // or \\\\ \n");
974 return 1;
975 }
976 } else {
977 printk(KERN_WARNING "CIFS: UNC name too long\n");
978 return 1;
979 }
980 } else if ((strnicmp(data, "domain", 3) == 0)
981 || (strnicmp(data, "workgroup", 5) == 0)) {
982 if (!value || !*value) {
983 printk(KERN_WARNING "CIFS: invalid domain name\n");
984 return 1; /* needs_arg; */
985 }
986 /* BB are there cases in which a comma can be valid in
987 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +0000988 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 vol->domainname = value;
990 cFYI(1, ("Domain name set"));
991 } else {
992 printk(KERN_WARNING "CIFS: domain name too long\n");
993 return 1;
994 }
995 } else if (strnicmp(data, "iocharset", 9) == 0) {
996 if (!value || !*value) {
997 printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
998 return 1; /* needs_arg; */
999 }
1000 if (strnlen(value, 65) < 65) {
1001 if(strnicmp(value,"default",7))
1002 vol->iocharset = value;
1003 /* if iocharset not set load_nls_default used by caller */
1004 cFYI(1, ("iocharset set to %s",value));
1005 } else {
1006 printk(KERN_WARNING "CIFS: iocharset name too long.\n");
1007 return 1;
1008 }
1009 } else if (strnicmp(data, "uid", 3) == 0) {
1010 if (value && *value) {
1011 vol->linux_uid =
1012 simple_strtoul(value, &value, 0);
1013 }
1014 } else if (strnicmp(data, "gid", 3) == 0) {
1015 if (value && *value) {
1016 vol->linux_gid =
1017 simple_strtoul(value, &value, 0);
1018 }
1019 } else if (strnicmp(data, "file_mode", 4) == 0) {
1020 if (value && *value) {
1021 vol->file_mode =
1022 simple_strtoul(value, &value, 0);
1023 }
1024 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1025 if (value && *value) {
1026 vol->dir_mode =
1027 simple_strtoul(value, &value, 0);
1028 }
1029 } else if (strnicmp(data, "dirmode", 4) == 0) {
1030 if (value && *value) {
1031 vol->dir_mode =
1032 simple_strtoul(value, &value, 0);
1033 }
1034 } else if (strnicmp(data, "port", 4) == 0) {
1035 if (value && *value) {
1036 vol->port =
1037 simple_strtoul(value, &value, 0);
1038 }
1039 } else if (strnicmp(data, "rsize", 5) == 0) {
1040 if (value && *value) {
1041 vol->rsize =
1042 simple_strtoul(value, &value, 0);
1043 }
1044 } else if (strnicmp(data, "wsize", 5) == 0) {
1045 if (value && *value) {
1046 vol->wsize =
1047 simple_strtoul(value, &value, 0);
1048 }
1049 } else if (strnicmp(data, "sockopt", 5) == 0) {
1050 if (value && *value) {
1051 vol->sockopt =
1052 simple_strtoul(value, &value, 0);
1053 }
1054 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1055 if (!value || !*value || (*value == ' ')) {
1056 cFYI(1,("invalid (empty) netbiosname specified"));
1057 } else {
1058 memset(vol->source_rfc1001_name,0x20,15);
1059 for(i=0;i<15;i++) {
1060 /* BB are there cases in which a comma can be
1061 valid in this workstation netbios name (and need
1062 special handling)? */
1063
1064 /* We do not uppercase netbiosname for user */
1065 if (value[i]==0)
1066 break;
1067 else
1068 vol->source_rfc1001_name[i] = value[i];
1069 }
1070 /* The string has 16th byte zero still from
1071 set at top of the function */
1072 if((i==15) && (value[i] != 0))
Steve Frencha10faeb22005-08-22 21:38:31 -07001073 printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
1074 }
1075 } else if (strnicmp(data, "servern", 7) == 0) {
1076 /* servernetbiosname specified override *SMBSERVER */
1077 if (!value || !*value || (*value == ' ')) {
1078 cFYI(1,("empty server netbiosname specified"));
1079 } else {
1080 /* last byte, type, is 0x20 for servr type */
1081 memset(vol->target_rfc1001_name,0x20,16);
1082
1083 for(i=0;i<15;i++) {
1084 /* BB are there cases in which a comma can be
1085 valid in this workstation netbios name (and need
1086 special handling)? */
1087
1088 /* user or mount helper must uppercase netbiosname */
1089 if (value[i]==0)
1090 break;
1091 else
1092 vol->target_rfc1001_name[i] = value[i];
1093 }
1094 /* The string has 16th byte zero still from
1095 set at top of the function */
1096 if((i==15) && (value[i] != 0))
1097 printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 }
1099 } else if (strnicmp(data, "credentials", 4) == 0) {
1100 /* ignore */
1101 } else if (strnicmp(data, "version", 3) == 0) {
1102 /* ignore */
1103 } else if (strnicmp(data, "guest",5) == 0) {
1104 /* ignore */
1105 } else if (strnicmp(data, "rw", 2) == 0) {
1106 vol->rw = TRUE;
1107 } else if ((strnicmp(data, "suid", 4) == 0) ||
1108 (strnicmp(data, "nosuid", 6) == 0) ||
1109 (strnicmp(data, "exec", 4) == 0) ||
1110 (strnicmp(data, "noexec", 6) == 0) ||
1111 (strnicmp(data, "nodev", 5) == 0) ||
1112 (strnicmp(data, "noauto", 6) == 0) ||
1113 (strnicmp(data, "dev", 3) == 0)) {
1114 /* The mount tool or mount.cifs helper (if present)
1115 uses these opts to set flags, and the flags are read
1116 by the kernel vfs layer before we get here (ie
1117 before read super) so there is no point trying to
1118 parse these options again and set anything and it
1119 is ok to just ignore them */
1120 continue;
1121 } else if (strnicmp(data, "ro", 2) == 0) {
1122 vol->rw = FALSE;
1123 } else if (strnicmp(data, "hard", 4) == 0) {
1124 vol->retry = 1;
1125 } else if (strnicmp(data, "soft", 4) == 0) {
1126 vol->retry = 0;
1127 } else if (strnicmp(data, "perm", 4) == 0) {
1128 vol->noperm = 0;
1129 } else if (strnicmp(data, "noperm", 6) == 0) {
1130 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001131 } else if (strnicmp(data, "mapchars", 8) == 0) {
1132 vol->remap = 1;
1133 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1134 vol->remap = 0;
Steve Frenchd7245c22005-07-14 18:25:12 -05001135 } else if (strnicmp(data, "sfu", 3) == 0) {
1136 vol->sfu_emul = 1;
1137 } else if (strnicmp(data, "nosfu", 5) == 0) {
1138 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001139 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1140 vol->posix_paths = 1;
1141 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1142 vol->posix_paths = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001143 } else if ((strnicmp(data, "nocase", 6) == 0) ||
1144 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001145 vol->nocase = 1;
1146 } else if (strnicmp(data, "brl", 3) == 0) {
1147 vol->nobrl = 0;
Steve Frenchcb8be642005-08-30 15:25:52 -07001148 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001149 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001150 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001151 /* turn off mandatory locking in mode
1152 if remote locking is turned off since the
1153 local vfs will do advisory */
1154 if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1155 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 } else if (strnicmp(data, "setuids", 7) == 0) {
1157 vol->setuids = 1;
1158 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1159 vol->setuids = 0;
1160 } else if (strnicmp(data, "nohard", 6) == 0) {
1161 vol->retry = 0;
1162 } else if (strnicmp(data, "nosoft", 6) == 0) {
1163 vol->retry = 1;
1164 } else if (strnicmp(data, "nointr", 6) == 0) {
1165 vol->intr = 0;
1166 } else if (strnicmp(data, "intr", 4) == 0) {
1167 vol->intr = 1;
1168 } else if (strnicmp(data, "serverino",7) == 0) {
1169 vol->server_ino = 1;
1170 } else if (strnicmp(data, "noserverino",9) == 0) {
1171 vol->server_ino = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08001172 } else if (strnicmp(data, "cifsacl",7) == 0) {
1173 vol->cifs_acl = 1;
1174 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1175 vol->cifs_acl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 } else if (strnicmp(data, "acl",3) == 0) {
1177 vol->no_psx_acl = 0;
1178 } else if (strnicmp(data, "noacl",5) == 0) {
1179 vol->no_psx_acl = 1;
Steve French750d1152006-06-27 06:28:30 +00001180 } else if (strnicmp(data, "sign",4) == 0) {
1181 vol->secFlg |= CIFSSEC_MUST_SIGN;
1182/* } else if (strnicmp(data, "seal",4) == 0) {
1183 vol->secFlg |= CIFSSEC_MUST_SEAL; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 } else if (strnicmp(data, "direct",6) == 0) {
1185 vol->direct_io = 1;
1186 } else if (strnicmp(data, "forcedirectio",13) == 0) {
1187 vol->direct_io = 1;
1188 } else if (strnicmp(data, "in6_addr",8) == 0) {
1189 if (!value || !*value) {
1190 vol->in6_addr = NULL;
1191 } else if (strnlen(value, 49) == 48) {
1192 vol->in6_addr = value;
1193 } else {
1194 printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
1195 return 1;
1196 }
1197 } else if (strnicmp(data, "noac", 4) == 0) {
1198 printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
1199 } else
1200 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
1201 }
1202 if (vol->UNC == NULL) {
1203 if(devname == NULL) {
1204 printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
1205 return 1;
1206 }
1207 if ((temp_len = strnlen(devname, 300)) < 300) {
1208 vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
1209 if(vol->UNC == NULL)
1210 return 1;
1211 strcpy(vol->UNC,devname);
1212 if (strncmp(vol->UNC, "//", 2) == 0) {
1213 vol->UNC[0] = '\\';
1214 vol->UNC[1] = '\\';
1215 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
1216 printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
1217 return 1;
1218 }
1219 } else {
1220 printk(KERN_WARNING "CIFS: UNC name too long\n");
1221 return 1;
1222 }
1223 }
1224 if(vol->UNCip == NULL)
1225 vol->UNCip = &vol->UNC[2];
1226
1227 return 0;
1228}
1229
1230static struct cifsSesInfo *
1231cifs_find_tcp_session(struct in_addr * target_ip_addr,
1232 struct in6_addr *target_ip6_addr,
1233 char *userName, struct TCP_Server_Info **psrvTcp)
1234{
1235 struct list_head *tmp;
1236 struct cifsSesInfo *ses;
1237 *psrvTcp = NULL;
1238 read_lock(&GlobalSMBSeslock);
1239
1240 list_for_each(tmp, &GlobalSMBSessionList) {
1241 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1242 if (ses->server) {
1243 if((target_ip_addr &&
1244 (ses->server->addr.sockAddr.sin_addr.s_addr
1245 == target_ip_addr->s_addr)) || (target_ip6_addr
1246 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1247 target_ip6_addr,sizeof(*target_ip6_addr)))){
1248 /* BB lock server and tcp session and increment use count here?? */
1249 *psrvTcp = ses->server; /* found a match on the TCP session */
1250 /* BB check if reconnection needed */
1251 if (strncmp
1252 (ses->userName, userName,
1253 MAX_USERNAME_SIZE) == 0){
1254 read_unlock(&GlobalSMBSeslock);
1255 return ses; /* found exact match on both tcp and SMB sessions */
1256 }
1257 }
1258 }
1259 /* else tcp and smb sessions need reconnection */
1260 }
1261 read_unlock(&GlobalSMBSeslock);
1262 return NULL;
1263}
1264
1265static struct cifsTconInfo *
1266find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1267{
1268 struct list_head *tmp;
1269 struct cifsTconInfo *tcon;
1270
1271 read_lock(&GlobalSMBSeslock);
1272 list_for_each(tmp, &GlobalTreeConnectionList) {
1273 cFYI(1, ("Next tcon - "));
1274 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1275 if (tcon->ses) {
1276 if (tcon->ses->server) {
1277 cFYI(1,
1278 (" old ip addr: %x == new ip %x ?",
1279 tcon->ses->server->addr.sockAddr.sin_addr.
1280 s_addr, new_target_ip_addr));
1281 if (tcon->ses->server->addr.sockAddr.sin_addr.
1282 s_addr == new_target_ip_addr) {
1283 /* BB lock tcon and server and tcp session and increment use count here? */
1284 /* found a match on the TCP session */
1285 /* BB check if reconnection needed */
1286 cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
1287 tcon->treeName, uncName));
1288 if (strncmp
1289 (tcon->treeName, uncName,
1290 MAX_TREE_SIZE) == 0) {
1291 cFYI(1,
1292 ("Matched UNC, old user: %s == new: %s ?",
1293 tcon->treeName, uncName));
1294 if (strncmp
1295 (tcon->ses->userName,
1296 userName,
1297 MAX_USERNAME_SIZE) == 0) {
1298 read_unlock(&GlobalSMBSeslock);
1299 return tcon;/* also matched user (smb session)*/
1300 }
1301 }
1302 }
1303 }
1304 }
1305 }
1306 read_unlock(&GlobalSMBSeslock);
1307 return NULL;
1308}
1309
1310int
1311connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001312 const char *old_path, const struct nls_table *nls_codepage,
1313 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314{
1315 unsigned char *referrals = NULL;
1316 unsigned int num_referrals;
1317 int rc = 0;
1318
1319 rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001320 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
1322 /* BB Add in code to: if valid refrl, if not ip address contact
1323 the helper that resolves tcp names, mount to it, try to
1324 tcon to it unmount it if fail */
1325
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001326 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
1328 return rc;
1329}
1330
1331int
1332get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
1333 const char *old_path, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001334 unsigned int *pnum_referrals,
1335 unsigned char ** preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336{
1337 char *temp_unc;
1338 int rc = 0;
1339
1340 *pnum_referrals = 0;
1341
1342 if (pSesInfo->ipc_tid == 0) {
1343 temp_unc = kmalloc(2 /* for slashes */ +
1344 strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
1345 + 1 + 4 /* slash IPC$ */ + 2,
1346 GFP_KERNEL);
1347 if (temp_unc == NULL)
1348 return -ENOMEM;
1349 temp_unc[0] = '\\';
1350 temp_unc[1] = '\\';
1351 strcpy(temp_unc + 2, pSesInfo->serverName);
1352 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1353 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1354 cFYI(1,
1355 ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
1356 kfree(temp_unc);
1357 }
1358 if (rc == 0)
1359 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001360 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
1362 return rc;
1363}
1364
1365/* See RFC1001 section 14 on representation of Netbios names */
1366static void rfc1002mangle(char * target,char * source, unsigned int length)
1367{
1368 unsigned int i,j;
1369
1370 for(i=0,j=0;i<(length);i++) {
1371 /* mask a nibble at a time and encode */
1372 target[j] = 'A' + (0x0F & (source[i] >> 4));
1373 target[j+1] = 'A' + (0x0F & source[i]);
1374 j+=2;
1375 }
1376
1377}
1378
1379
1380static int
1381ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001382 char * netbios_name, char * target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383{
1384 int rc = 0;
1385 int connected = 0;
1386 __be16 orig_port = 0;
1387
1388 if(*csocket == NULL) {
1389 rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
1390 if (rc < 0) {
1391 cERROR(1, ("Error %d creating socket",rc));
1392 *csocket = NULL;
1393 return rc;
1394 } else {
1395 /* BB other socket options to set KEEPALIVE, NODELAY? */
1396 cFYI(1,("Socket created"));
1397 (*csocket)->sk->sk_allocation = GFP_NOFS;
1398 }
1399 }
1400
1401 psin_server->sin_family = AF_INET;
1402 if(psin_server->sin_port) { /* user overrode default port */
1403 rc = (*csocket)->ops->connect(*csocket,
1404 (struct sockaddr *) psin_server,
1405 sizeof (struct sockaddr_in),0);
1406 if (rc >= 0)
1407 connected = 1;
1408 }
1409
1410 if(!connected) {
1411 /* save original port so we can retry user specified port
1412 later if fall back ports fail this time */
1413 orig_port = psin_server->sin_port;
1414
1415 /* do not retry on the same port we just failed on */
1416 if(psin_server->sin_port != htons(CIFS_PORT)) {
1417 psin_server->sin_port = htons(CIFS_PORT);
1418
1419 rc = (*csocket)->ops->connect(*csocket,
1420 (struct sockaddr *) psin_server,
1421 sizeof (struct sockaddr_in),0);
1422 if (rc >= 0)
1423 connected = 1;
1424 }
1425 }
1426 if (!connected) {
1427 psin_server->sin_port = htons(RFC1001_PORT);
1428 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1429 psin_server, sizeof (struct sockaddr_in),0);
1430 if (rc >= 0)
1431 connected = 1;
1432 }
1433
1434 /* give up here - unless we want to retry on different
1435 protocol families some day */
1436 if (!connected) {
1437 if(orig_port)
1438 psin_server->sin_port = orig_port;
1439 cFYI(1,("Error %d connecting to server via ipv4",rc));
1440 sock_release(*csocket);
1441 *csocket = NULL;
1442 return rc;
1443 }
1444 /* Eventually check for other socket options to change from
1445 the default. sock_setsockopt not used because it expects
1446 user space buffer */
Steve Frenchb387eae2005-10-10 14:21:15 -07001447 cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
1448 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001450 /* make the bufsizes depend on wsize/rsize and max requests */
1451 if((*csocket)->sk->sk_sndbuf < (200 * 1024))
1452 (*csocket)->sk->sk_sndbuf = 200 * 1024;
1453 if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
1454 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455
1456 /* send RFC1001 sessinit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 if(psin_server->sin_port == htons(RFC1001_PORT)) {
1458 /* some servers require RFC1001 sessinit before sending
1459 negprot - BB check reconnection in case where second
1460 sessinit is sent but no second negprot */
1461 struct rfc1002_session_packet * ses_init_buf;
1462 struct smb_hdr * smb_buf;
Pekka Enberge915fc42005-09-06 15:18:35 -07001463 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 if(ses_init_buf) {
1465 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frencha10faeb22005-08-22 21:38:31 -07001466 if(target_name && (target_name[0] != 0)) {
1467 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1468 target_name, 16);
1469 } else {
1470 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1471 DEFAULT_CIFS_CALLED_NAME,16);
1472 }
1473
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 ses_init_buf->trailer.session_req.calling_len = 32;
1475 /* calling name ends in null (byte 16) from old smb
1476 convention. */
1477 if(netbios_name && (netbios_name[0] !=0)) {
1478 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1479 netbios_name,16);
1480 } else {
1481 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
1482 "LINUX_CIFS_CLNT",16);
1483 }
1484 ses_init_buf->trailer.session_req.scope1 = 0;
1485 ses_init_buf->trailer.session_req.scope2 = 0;
1486 smb_buf = (struct smb_hdr *)ses_init_buf;
1487 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1488 smb_buf->smb_buf_length = 0x81000044;
1489 rc = smb_send(*csocket, smb_buf, 0x44,
1490 (struct sockaddr *)psin_server);
1491 kfree(ses_init_buf);
Steve French083d3a22006-03-03 09:53:36 +00001492 msleep(1); /* RFC1001 layer in at least one server
1493 requires very short break before negprot
1494 presumably because not expecting negprot
1495 to follow so fast. This is a simple
1496 solution that works without
1497 complicating the code and causes no
1498 significant slowing down on mount
1499 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 }
1501 /* else the negprot may still work without this
1502 even though malloc failed */
1503
1504 }
1505
1506 return rc;
1507}
1508
1509static int
1510ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1511{
1512 int rc = 0;
1513 int connected = 0;
1514 __be16 orig_port = 0;
1515
1516 if(*csocket == NULL) {
1517 rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
1518 if (rc < 0) {
1519 cERROR(1, ("Error %d creating ipv6 socket",rc));
1520 *csocket = NULL;
1521 return rc;
1522 } else {
1523 /* BB other socket options to set KEEPALIVE, NODELAY? */
1524 cFYI(1,("ipv6 Socket created"));
1525 (*csocket)->sk->sk_allocation = GFP_NOFS;
1526 }
1527 }
1528
1529 psin_server->sin6_family = AF_INET6;
1530
1531 if(psin_server->sin6_port) { /* user overrode default port */
1532 rc = (*csocket)->ops->connect(*csocket,
1533 (struct sockaddr *) psin_server,
1534 sizeof (struct sockaddr_in6),0);
1535 if (rc >= 0)
1536 connected = 1;
1537 }
1538
1539 if(!connected) {
1540 /* save original port so we can retry user specified port
1541 later if fall back ports fail this time */
1542
1543 orig_port = psin_server->sin6_port;
1544 /* do not retry on the same port we just failed on */
1545 if(psin_server->sin6_port != htons(CIFS_PORT)) {
1546 psin_server->sin6_port = htons(CIFS_PORT);
1547
1548 rc = (*csocket)->ops->connect(*csocket,
1549 (struct sockaddr *) psin_server,
1550 sizeof (struct sockaddr_in6),0);
1551 if (rc >= 0)
1552 connected = 1;
1553 }
1554 }
1555 if (!connected) {
1556 psin_server->sin6_port = htons(RFC1001_PORT);
1557 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
1558 psin_server, sizeof (struct sockaddr_in6),0);
1559 if (rc >= 0)
1560 connected = 1;
1561 }
1562
1563 /* give up here - unless we want to retry on different
1564 protocol families some day */
1565 if (!connected) {
1566 if(orig_port)
1567 psin_server->sin6_port = orig_port;
1568 cFYI(1,("Error %d connecting to server via ipv6",rc));
1569 sock_release(*csocket);
1570 *csocket = NULL;
1571 return rc;
1572 }
1573 /* Eventually check for other socket options to change from
1574 the default. sock_setsockopt not used because it expects
1575 user space buffer */
1576 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1577
1578 return rc;
1579}
1580
1581int
1582cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1583 char *mount_data, const char *devname)
1584{
1585 int rc = 0;
1586 int xid;
1587 int address_type = AF_INET;
1588 struct socket *csocket = NULL;
1589 struct sockaddr_in sin_server;
1590 struct sockaddr_in6 sin_server6;
1591 struct smb_vol volume_info;
1592 struct cifsSesInfo *pSesInfo = NULL;
1593 struct cifsSesInfo *existingCifsSes = NULL;
1594 struct cifsTconInfo *tcon = NULL;
1595 struct TCP_Server_Info *srvTcp = NULL;
1596
1597 xid = GetXid();
1598
1599/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1600
1601 memset(&volume_info,0,sizeof(struct smb_vol));
1602 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001603 kfree(volume_info.UNC);
1604 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 FreeXid(xid);
1606 return -EINVAL;
1607 }
1608
1609 if (volume_info.username) {
1610 /* BB fixme parse for domain name here */
1611 cFYI(1, ("Username: %s ", volume_info.username));
1612
1613 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001614 cifserror("No username specified");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 /* In userspace mount helper we can get user name from alternate
1616 locations such as env variables and files on disk */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001617 kfree(volume_info.UNC);
1618 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 FreeXid(xid);
1620 return -EINVAL;
1621 }
1622
1623 if (volume_info.UNCip && volume_info.UNC) {
1624 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
1625
1626 if(rc <= 0) {
1627 /* not ipv4 address, try ipv6 */
1628 rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
1629 if(rc > 0)
1630 address_type = AF_INET6;
1631 } else {
1632 address_type = AF_INET;
1633 }
1634
1635 if(rc <= 0) {
1636 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001637 kfree(volume_info.UNC);
1638 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 FreeXid(xid);
1640 return -EINVAL;
1641 }
1642
1643 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1644 /* success */
1645 rc = 0;
1646 } else if (volume_info.UNCip){
1647 /* BB using ip addr as server name connect to the DFS root below */
1648 cERROR(1,("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001649 kfree(volume_info.UNC);
1650 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 FreeXid(xid);
1652 return -EINVAL;
1653 } else /* which servers DFS root would we conect to */ {
1654 cERROR(1,
Steve Frenchbf820672005-12-01 22:32:42 -08001655 ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001656 kfree(volume_info.UNC);
1657 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 FreeXid(xid);
1659 return -EINVAL;
1660 }
1661
1662 /* this is needed for ASCII cp to Unicode converts */
1663 if(volume_info.iocharset == NULL) {
1664 cifs_sb->local_nls = load_nls_default();
1665 /* load_nls_default can not return null */
1666 } else {
1667 cifs_sb->local_nls = load_nls(volume_info.iocharset);
1668 if(cifs_sb->local_nls == NULL) {
1669 cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001670 kfree(volume_info.UNC);
1671 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 FreeXid(xid);
1673 return -ELIBACC;
1674 }
1675 }
1676
1677 if(address_type == AF_INET)
1678 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1679 NULL /* no ipv6 addr */,
1680 volume_info.username, &srvTcp);
1681 else if(address_type == AF_INET6)
1682 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1683 &sin_server6.sin6_addr,
1684 volume_info.username, &srvTcp);
1685 else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001686 kfree(volume_info.UNC);
1687 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 FreeXid(xid);
1689 return -EINVAL;
1690 }
1691
1692
1693 if (srvTcp) {
Steve Frenchbf820672005-12-01 22:32:42 -08001694 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 } else { /* create socket */
1696 if(volume_info.port)
1697 sin_server.sin_port = htons(volume_info.port);
1698 else
1699 sin_server.sin_port = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -07001700 rc = ipv4_connect(&sin_server,&csocket,
1701 volume_info.source_rfc1001_name,
1702 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 if (rc < 0) {
1704 cERROR(1,
1705 ("Error connecting to IPv4 socket. Aborting operation"));
1706 if(csocket != NULL)
1707 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001708 kfree(volume_info.UNC);
1709 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 FreeXid(xid);
1711 return rc;
1712 }
1713
1714 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1715 if (srvTcp == NULL) {
1716 rc = -ENOMEM;
1717 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001718 kfree(volume_info.UNC);
1719 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 FreeXid(xid);
1721 return rc;
1722 } else {
1723 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
1724 memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
1725 atomic_set(&srvTcp->inFlight,0);
1726 /* BB Add code for ipv6 case too */
1727 srvTcp->ssocket = csocket;
1728 srvTcp->protocolType = IPV4;
1729 init_waitqueue_head(&srvTcp->response_q);
1730 init_waitqueue_head(&srvTcp->request_q);
1731 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1732 /* at this point we are the only ones with the pointer
1733 to the struct since the kernel thread not created yet
1734 so no need to spinlock this init of tcpStatus */
1735 srvTcp->tcpStatus = CifsNew;
1736 init_MUTEX(&srvTcp->tcpSem);
1737 rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
1738 CLONE_FS | CLONE_FILES | CLONE_VM);
1739 if(rc < 0) {
1740 rc = -ENOMEM;
1741 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001742 kfree(volume_info.UNC);
1743 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 FreeXid(xid);
1745 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001746 }
1747 wait_for_completion(&cifsd_complete);
1748 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001750 memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001751 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 }
1753 }
1754
1755 if (existingCifsSes) {
1756 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001757 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001758 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 /* volume_info.UNC freed at end of function */
1760 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001761 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 pSesInfo = sesInfoAlloc();
1763 if (pSesInfo == NULL)
1764 rc = -ENOMEM;
1765 else {
1766 pSesInfo->server = srvTcp;
1767 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1768 NIPQUAD(sin_server.sin_addr.s_addr));
1769 }
1770
1771 if (!rc){
1772 /* volume_info.password freed at unmount */
1773 if (volume_info.password)
1774 pSesInfo->password = volume_info.password;
1775 if (volume_info.username)
1776 strncpy(pSesInfo->userName,
1777 volume_info.username,MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001778 if (volume_info.domainname) {
1779 int len = strlen(volume_info.domainname);
1780 pSesInfo->domainName =
1781 kmalloc(len + 1, GFP_KERNEL);
1782 if(pSesInfo->domainName)
1783 strcpy(pSesInfo->domainName,
1784 volume_info.domainname);
1785 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00001787 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00001789 /* BB FIXME need to pass vol->secFlgs BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
1791 up(&pSesInfo->sesSem);
1792 if(!rc)
1793 atomic_inc(&srvTcp->socketUseCount);
1794 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001795 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 }
1797
1798 /* search for existing tcon to this server share */
1799 if (!rc) {
Steve French0ae0efa2005-10-10 10:57:19 -07001800 if(volume_info.rsize > CIFSMaxBufSize) {
1801 cERROR(1,("rsize %d too large, using MaxBufSize",
1802 volume_info.rsize));
1803 cifs_sb->rsize = CIFSMaxBufSize;
1804 } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07001806 else /* default */
1807 cifs_sb->rsize = CIFSMaxBufSize;
1808
1809 if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
1810 cERROR(1,("wsize %d too large using 4096 instead",
1811 volume_info.wsize));
1812 cifs_sb->wsize = 4096;
1813 } else if(volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 cifs_sb->wsize = volume_info.wsize;
1815 else
Steve French17cbbaf2006-01-24 20:26:48 -08001816 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08001817 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
1818 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08001819 /* old default of CIFSMaxBufSize was too small now
1820 that SMB Write2 can send multiple pages in kvec.
1821 RFC1001 does not describe what happens when frame
1822 bigger than 128K is sent so use that as max in
1823 conjunction with 52K kvec constraint on arch with 4K
1824 page size */
1825
Steve French6cec2ae2006-02-22 17:31:52 -06001826 if(cifs_sb->rsize < 2048) {
1827 cifs_sb->rsize = 2048;
1828 /* Windows ME may prefer this */
1829 cFYI(1,("readsize set to minimum 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 }
1831 cifs_sb->mnt_uid = volume_info.linux_uid;
1832 cifs_sb->mnt_gid = volume_info.linux_gid;
1833 cifs_sb->mnt_file_mode = volume_info.file_mode;
1834 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve Frencheeac8042006-01-13 21:34:58 -08001835 cFYI(1,("file mode: 0x%x dir mode: 0x%x",
1836 cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837
1838 if(volume_info.noperm)
1839 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1840 if(volume_info.setuids)
1841 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1842 if(volume_info.server_ino)
1843 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French6a0b4822005-04-28 22:41:05 -07001844 if(volume_info.remap)
1845 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 if(volume_info.no_xattr)
1847 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve Frenchd7245c22005-07-14 18:25:12 -05001848 if(volume_info.sfu_emul)
1849 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001850 if(volume_info.nobrl)
1851 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French0a4b92c2006-01-12 15:44:21 -08001852 if(volume_info.cifs_acl)
1853 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Jeremy Allisonac670552005-06-22 17:26:35 -07001854
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 if(volume_info.direct_io) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001856 cFYI(1,("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1858 }
1859
1860 tcon =
1861 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
1862 volume_info.username);
1863 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08001864 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 /* we can have only one retry value for a connection
1866 to a share so for resources mounted more than once
1867 to the same server share the last value passed in
1868 for the retry flag is used */
1869 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001870 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 } else {
1872 tcon = tconInfoAlloc();
1873 if (tcon == NULL)
1874 rc = -ENOMEM;
1875 else {
1876 /* check for null share name ie connect to dfs root */
1877
1878 /* BB check if this works for exactly length three strings */
1879 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
1880 && (strchr(volume_info.UNC + 3, '/') ==
1881 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07001882 rc = connect_to_dfs_path(xid, pSesInfo,
1883 "", cifs_sb->local_nls,
1884 cifs_sb->mnt_cifs_flags &
1885 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001886 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 FreeXid(xid);
1888 return -ENODEV;
1889 } else {
1890 rc = CIFSTCon(xid, pSesInfo,
1891 volume_info.UNC,
1892 tcon, cifs_sb->local_nls);
1893 cFYI(1, ("CIFS Tcon rc = %d", rc));
1894 }
1895 if (!rc) {
1896 atomic_inc(&pSesInfo->inUse);
1897 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07001898 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 }
1900 }
1901 }
1902 }
1903 if(pSesInfo) {
1904 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
1905 sb->s_maxbytes = (u64) 1 << 63;
1906 } else
1907 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
1908 }
1909
1910 sb->s_time_gran = 100;
1911
1912/* on error free sesinfo and tcon struct if needed */
1913 if (rc) {
1914 /* if session setup failed, use count is zero but
1915 we still need to free cifsd thread */
1916 if(atomic_read(&srvTcp->socketUseCount) == 0) {
1917 spin_lock(&GlobalMid_Lock);
1918 srvTcp->tcpStatus = CifsExiting;
1919 spin_unlock(&GlobalMid_Lock);
Steve Frenchf1914012005-08-18 09:37:34 -07001920 if(srvTcp->tsk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 send_sig(SIGKILL,srvTcp->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001922 wait_for_completion(&cifsd_complete);
1923 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 }
1925 /* If find_unc succeeded then rc == 0 so we can not end */
1926 if (tcon) /* up accidently freeing someone elses tcon struct */
1927 tconInfoFree(tcon);
1928 if (existingCifsSes == NULL) {
1929 if (pSesInfo) {
1930 if ((pSesInfo->server) &&
1931 (pSesInfo->status == CifsGood)) {
1932 int temp_rc;
1933 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
1934 /* if the socketUseCount is now zero */
1935 if((temp_rc == -ESHUTDOWN) &&
Steve Frenchf1914012005-08-18 09:37:34 -07001936 (pSesInfo->server->tsk)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 send_sig(SIGKILL,pSesInfo->server->tsk,1);
Steve Frenchf1914012005-08-18 09:37:34 -07001938 wait_for_completion(&cifsd_complete);
1939 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 } else
1941 cFYI(1, ("No session or bad tcon"));
1942 sesInfoFree(pSesInfo);
1943 /* pSesInfo = NULL; */
1944 }
1945 }
1946 } else {
1947 atomic_inc(&tcon->useCount);
1948 cifs_sb->tcon = tcon;
1949 tcon->ses = pSesInfo;
1950
Steve French82940a42006-03-02 03:24:57 +00001951 /* do not care if following two calls succeed - informational */
Steve French737b7582005-04-28 22:41:06 -07001952 CIFSSMBQFSDeviceInfo(xid, tcon);
1953 CIFSSMBQFSAttributeInfo(xid, tcon);
Steve French82940a42006-03-02 03:24:57 +00001954
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 if (tcon->ses->capabilities & CAP_UNIX) {
Steve French737b7582005-04-28 22:41:06 -07001956 if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French82940a42006-03-02 03:24:57 +00001957 __u64 cap =
1958 le64_to_cpu(tcon->fsUnixInfo.Capability);
1959 cap &= CIFS_UNIX_CAP_MASK;
1960 if(volume_info.no_psx_acl)
1961 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1962 else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
1963 cFYI(1,("negotiated posix acl support"));
1964 sb->s_flags |= MS_POSIXACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 }
Jeremy Allisonac670552005-06-22 17:26:35 -07001966
Steve French82940a42006-03-02 03:24:57 +00001967 if(volume_info.posix_paths == 0)
1968 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
1969 else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
1970 cFYI(1,("negotiate posix pathnames"));
1971 cifs_sb->mnt_cifs_flags |=
1972 CIFS_MOUNT_POSIX_PATHS;
1973 }
1974
1975 cFYI(1,("Negotiate caps 0x%x",(int)cap));
Steve French3a5ff612006-07-14 22:37:11 +00001976#ifdef CONFIG_CIFS_DEBUG2
1977 if(cap & CIFS_UNIX_FCNTL_CAP)
1978 cFYI(1,("FCNTL cap"));
1979 if(cap & CIFS_UNIX_EXTATTR_CAP)
1980 cFYI(1,("EXTATTR cap"));
1981 if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
1982 cFYI(1,("POSIX path cap"));
1983 if(cap & CIFS_UNIX_XATTR_CAP)
1984 cFYI(1,("XATTR cap"));
1985 if(cap & CIFS_UNIX_POSIX_ACL_CAP)
1986 cFYI(1,("POSIX ACL cap"));
1987#endif /* CIFS_DEBUG2 */
Steve French82940a42006-03-02 03:24:57 +00001988 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
1989 cFYI(1,("setting capabilities failed"));
Jeremy Allisonac670552005-06-22 17:26:35 -07001990 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 }
1992 }
Steve French3e844692005-10-03 13:37:24 -07001993 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
1994 cifs_sb->wsize = min(cifs_sb->wsize,
1995 (tcon->ses->server->maxBuf -
1996 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07001997 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
1998 cifs_sb->rsize = min(cifs_sb->rsize,
1999 (tcon->ses->server->maxBuf -
2000 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 }
2002
2003 /* volume_info.password is freed above when existing session found
2004 (in which case it is not needed anymore) but when new sesion is created
2005 the password ptr is put in the new session structure (in which case the
2006 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002007 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 FreeXid(xid);
2009 return rc;
2010}
2011
2012static int
2013CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002014 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 const struct nls_table *nls_codepage)
2016{
2017 struct smb_hdr *smb_buffer;
2018 struct smb_hdr *smb_buffer_response;
2019 SESSION_SETUP_ANDX *pSMB;
2020 SESSION_SETUP_ANDX *pSMBr;
2021 char *bcc_ptr;
2022 char *user;
2023 char *domain;
2024 int rc = 0;
2025 int remaining_words = 0;
2026 int bytes_returned = 0;
2027 int len;
2028 __u32 capabilities;
2029 __u16 count;
2030
Steve Frencheeac8042006-01-13 21:34:58 -08002031 cFYI(1, ("In sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 if(ses == NULL)
2033 return -EINVAL;
2034 user = ses->userName;
2035 domain = ses->domainName;
2036 smb_buffer = cifs_buf_get();
2037 if (smb_buffer == NULL) {
2038 return -ENOMEM;
2039 }
2040 smb_buffer_response = smb_buffer;
2041 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2042
2043 /* send SMBsessionSetup here */
2044 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2045 NULL /* no tCon exists yet */ , 13 /* wct */ );
2046
Steve French1982c342005-08-17 12:38:22 -07002047 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 pSMB->req_no_secext.AndXCommand = 0xFF;
2049 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2050 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2051
2052 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2053 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2054
2055 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2056 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2057 if (ses->capabilities & CAP_UNICODE) {
2058 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2059 capabilities |= CAP_UNICODE;
2060 }
2061 if (ses->capabilities & CAP_STATUS32) {
2062 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2063 capabilities |= CAP_STATUS32;
2064 }
2065 if (ses->capabilities & CAP_DFS) {
2066 smb_buffer->Flags2 |= SMBFLG2_DFS;
2067 capabilities |= CAP_DFS;
2068 }
2069 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2070
2071 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002072 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
2074 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002075 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002077 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2078 bcc_ptr += CIFS_SESS_KEY_SIZE;
2079 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2080 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
2082 if (ses->capabilities & CAP_UNICODE) {
2083 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2084 *bcc_ptr = 0;
2085 bcc_ptr++;
2086 }
2087 if(user == NULL)
Steve French39798772006-05-31 22:40:51 +00002088 bytes_returned = 0; /* skip null user */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 else
2090 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002091 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 nls_codepage);
2093 /* convert number of 16 bit words to bytes */
2094 bcc_ptr += 2 * bytes_returned;
2095 bcc_ptr += 2; /* trailing null */
2096 if (domain == NULL)
2097 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002098 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 "CIFS_LINUX_DOM", 32, nls_codepage);
2100 else
2101 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002102 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 nls_codepage);
2104 bcc_ptr += 2 * bytes_returned;
2105 bcc_ptr += 2;
2106 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002107 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 32, nls_codepage);
2109 bcc_ptr += 2 * bytes_returned;
2110 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002111 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 32, nls_codepage);
2113 bcc_ptr += 2 * bytes_returned;
2114 bcc_ptr += 2;
2115 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002116 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 64, nls_codepage);
2118 bcc_ptr += 2 * bytes_returned;
2119 bcc_ptr += 2;
2120 } else {
2121 if(user != NULL) {
2122 strncpy(bcc_ptr, user, 200);
2123 bcc_ptr += strnlen(user, 200);
2124 }
2125 *bcc_ptr = 0;
2126 bcc_ptr++;
2127 if (domain == NULL) {
2128 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2129 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2130 } else {
2131 strncpy(bcc_ptr, domain, 64);
2132 bcc_ptr += strnlen(domain, 64);
2133 *bcc_ptr = 0;
2134 bcc_ptr++;
2135 }
2136 strcpy(bcc_ptr, "Linux version ");
2137 bcc_ptr += strlen("Linux version ");
2138 strcpy(bcc_ptr, system_utsname.release);
2139 bcc_ptr += strlen(system_utsname.release) + 1;
2140 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2141 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2142 }
2143 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2144 smb_buffer->smb_buf_length += count;
2145 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2146
2147 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2148 &bytes_returned, 1);
2149 if (rc) {
2150/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2151 } else if ((smb_buffer_response->WordCount == 3)
2152 || (smb_buffer_response->WordCount == 4)) {
2153 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2154 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2155 if (action & GUEST_LOGIN)
2156 cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
2157 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
2158 cFYI(1, ("UID = %d ", ses->Suid));
2159 /* response can have either 3 or 4 word count - Samba sends 3 */
2160 bcc_ptr = pByteArea(smb_buffer_response);
2161 if ((pSMBr->resp.hdr.WordCount == 3)
2162 || ((pSMBr->resp.hdr.WordCount == 4)
2163 && (blob_len < pSMBr->resp.ByteCount))) {
2164 if (pSMBr->resp.hdr.WordCount == 4)
2165 bcc_ptr += blob_len;
2166
2167 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2168 if ((long) (bcc_ptr) % 2) {
2169 remaining_words =
2170 (BCC(smb_buffer_response) - 1) /2;
2171 bcc_ptr++; /* Unicode strings must be word aligned */
2172 } else {
2173 remaining_words =
2174 BCC(smb_buffer_response) / 2;
2175 }
2176 len =
2177 UniStrnlen((wchar_t *) bcc_ptr,
2178 remaining_words - 1);
2179/* We look for obvious messed up bcc or strings in response so we do not go off
2180 the end since (at least) WIN2K and Windows XP have a major bug in not null
2181 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002182 if(ses->serverOS)
2183 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002184 ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002185 if(ses->serverOS == NULL)
2186 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002188 (__le16 *)bcc_ptr, len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 bcc_ptr += 2 * (len + 1);
2190 remaining_words -= len + 1;
2191 ses->serverOS[2 * len] = 0;
2192 ses->serverOS[1 + (2 * len)] = 0;
2193 if (remaining_words > 0) {
2194 len = UniStrnlen((wchar_t *)bcc_ptr,
2195 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002196 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002197 ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002198 if(ses->serverNOS == NULL)
2199 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 cifs_strfromUCS_le(ses->serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002201 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 bcc_ptr += 2 * (len + 1);
2203 ses->serverNOS[2 * len] = 0;
2204 ses->serverNOS[1 + (2 * len)] = 0;
2205 if(strncmp(ses->serverNOS,
2206 "NT LAN Manager 4",16) == 0) {
2207 cFYI(1,("NT4 server"));
2208 ses->flags |= CIFS_SES_NT4;
2209 }
2210 remaining_words -= len + 1;
2211 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002212 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00002214 if(ses->serverDomain)
2215 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002217 kzalloc(2*(len+1),GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002218 if(ses->serverDomain == NULL)
2219 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 cifs_strfromUCS_le(ses->serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002221 (__le16 *)bcc_ptr,len,nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 bcc_ptr += 2 * (len + 1);
2223 ses->serverDomain[2*len] = 0;
2224 ses->serverDomain[1+(2*len)] = 0;
2225 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002226 else {
2227 if(ses->serverDomain)
2228 kfree(ses->serverDomain);
Steve French433dc242005-04-28 22:41:08 -07002229 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002230 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 } else { /* no room so create dummy domain and NOS string */
Steve French433dc242005-04-28 22:41:08 -07002233 /* if these kcallocs fail not much we
2234 can do, but better to not fail the
2235 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002236 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002238 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002239 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002241 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 }
2243 } else { /* ASCII */
2244 len = strnlen(bcc_ptr, 1024);
2245 if (((long) bcc_ptr + len) - (long)
2246 pByteArea(smb_buffer_response)
2247 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002248 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002249 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002250 if(ses->serverOS == NULL)
2251 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 strncpy(ses->serverOS,bcc_ptr, len);
2253
2254 bcc_ptr += len;
2255 bcc_ptr[0] = 0; /* null terminate the string */
2256 bcc_ptr++;
2257
2258 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002259 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002260 ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002261 if(ses->serverNOS == NULL)
2262 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 strncpy(ses->serverNOS, bcc_ptr, len);
2264 bcc_ptr += len;
2265 bcc_ptr[0] = 0;
2266 bcc_ptr++;
2267
2268 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00002269 if(ses->serverDomain)
2270 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07002271 ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
Steve French433dc242005-04-28 22:41:08 -07002272 if(ses->serverDomain == NULL)
2273 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 strncpy(ses->serverDomain, bcc_ptr, len);
2275 bcc_ptr += len;
2276 bcc_ptr[0] = 0;
2277 bcc_ptr++;
2278 } else
2279 cFYI(1,
2280 ("Variable field of length %d extends beyond end of smb ",
2281 len));
2282 }
2283 } else {
2284 cERROR(1,
2285 (" Security Blob Length extends beyond end of SMB"));
2286 }
2287 } else {
2288 cERROR(1,
2289 (" Invalid Word count %d: ",
2290 smb_buffer_response->WordCount));
2291 rc = -EIO;
2292 }
Steve French433dc242005-04-28 22:41:08 -07002293sesssetup_nomem: /* do not return an error on nomem for the info strings,
2294 since that could make reconnection harder, and
2295 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 if (smb_buffer)
2297 cifs_buf_release(smb_buffer);
2298
2299 return rc;
2300}
2301
2302static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
2304 struct cifsSesInfo *ses, int * pNTLMv2_flag,
2305 const struct nls_table *nls_codepage)
2306{
2307 struct smb_hdr *smb_buffer;
2308 struct smb_hdr *smb_buffer_response;
2309 SESSION_SETUP_ANDX *pSMB;
2310 SESSION_SETUP_ANDX *pSMBr;
2311 char *bcc_ptr;
2312 char *domain;
2313 int rc = 0;
2314 int remaining_words = 0;
2315 int bytes_returned = 0;
2316 int len;
2317 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2318 PNEGOTIATE_MESSAGE SecurityBlob;
2319 PCHALLENGE_MESSAGE SecurityBlob2;
2320 __u32 negotiate_flags, capabilities;
2321 __u16 count;
2322
Steve French12b3b8f2006-02-09 21:12:47 +00002323 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 if(ses == NULL)
2325 return -EINVAL;
2326 domain = ses->domainName;
2327 *pNTLMv2_flag = FALSE;
2328 smb_buffer = cifs_buf_get();
2329 if (smb_buffer == NULL) {
2330 return -ENOMEM;
2331 }
2332 smb_buffer_response = smb_buffer;
2333 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2334 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2335
2336 /* send SMBsessionSetup here */
2337 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2338 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002339
2340 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2342 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2343
2344 pSMB->req.AndXCommand = 0xFF;
2345 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2346 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2347
2348 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2349 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2350
2351 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2352 CAP_EXTENDED_SECURITY;
2353 if (ses->capabilities & CAP_UNICODE) {
2354 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2355 capabilities |= CAP_UNICODE;
2356 }
2357 if (ses->capabilities & CAP_STATUS32) {
2358 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2359 capabilities |= CAP_STATUS32;
2360 }
2361 if (ses->capabilities & CAP_DFS) {
2362 smb_buffer->Flags2 |= SMBFLG2_DFS;
2363 capabilities |= CAP_DFS;
2364 }
2365 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2366
2367 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2368 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2369 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2370 SecurityBlob->MessageType = NtLmNegotiate;
2371 negotiate_flags =
2372 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002373 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2374 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
2376 if(sign_CIFS_PDUs)
2377 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve French39798772006-05-31 22:40:51 +00002378/* if(ntlmv2_support)
2379 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 /* setup pointers to domain name and workstation name */
2381 bcc_ptr += SecurityBlobLength;
2382
2383 SecurityBlob->WorkstationName.Buffer = 0;
2384 SecurityBlob->WorkstationName.Length = 0;
2385 SecurityBlob->WorkstationName.MaximumLength = 0;
2386
Steve French12b3b8f2006-02-09 21:12:47 +00002387 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2388 along with username on auth request (ie the response to challenge) */
2389 SecurityBlob->DomainName.Buffer = 0;
2390 SecurityBlob->DomainName.Length = 0;
2391 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 if (ses->capabilities & CAP_UNICODE) {
2393 if ((long) bcc_ptr % 2) {
2394 *bcc_ptr = 0;
2395 bcc_ptr++;
2396 }
2397
2398 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002399 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 32, nls_codepage);
2401 bcc_ptr += 2 * bytes_returned;
2402 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002403 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 nls_codepage);
2405 bcc_ptr += 2 * bytes_returned;
2406 bcc_ptr += 2; /* null terminate Linux version */
2407 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002408 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 64, nls_codepage);
2410 bcc_ptr += 2 * bytes_returned;
2411 *(bcc_ptr + 1) = 0;
2412 *(bcc_ptr + 2) = 0;
2413 bcc_ptr += 2; /* null terminate network opsys string */
2414 *(bcc_ptr + 1) = 0;
2415 *(bcc_ptr + 2) = 0;
2416 bcc_ptr += 2; /* null domain */
2417 } else { /* ASCII */
2418 strcpy(bcc_ptr, "Linux version ");
2419 bcc_ptr += strlen("Linux version ");
2420 strcpy(bcc_ptr, system_utsname.release);
2421 bcc_ptr += strlen(system_utsname.release) + 1;
2422 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2423 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2424 bcc_ptr++; /* empty domain field */
2425 *bcc_ptr = 0;
2426 }
2427 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2428 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2429 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2430 smb_buffer->smb_buf_length += count;
2431 pSMB->req.ByteCount = cpu_to_le16(count);
2432
2433 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2434 &bytes_returned, 1);
2435
2436 if (smb_buffer_response->Status.CifsError ==
2437 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2438 rc = 0;
2439
2440 if (rc) {
2441/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2442 } else if ((smb_buffer_response->WordCount == 3)
2443 || (smb_buffer_response->WordCount == 4)) {
2444 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2445 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2446
2447 if (action & GUEST_LOGIN)
2448 cFYI(1, (" Guest login"));
2449 /* Do we want to set anything in SesInfo struct when guest login? */
2450
2451 bcc_ptr = pByteArea(smb_buffer_response);
2452 /* response can have either 3 or 4 word count - Samba sends 3 */
2453
2454 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2455 if (SecurityBlob2->MessageType != NtLmChallenge) {
2456 cFYI(1,
2457 ("Unexpected NTLMSSP message type received %d",
2458 SecurityBlob2->MessageType));
2459 } else if (ses) {
2460 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002461 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 if ((pSMBr->resp.hdr.WordCount == 3)
2463 || ((pSMBr->resp.hdr.WordCount == 4)
2464 && (blob_len <
2465 pSMBr->resp.ByteCount))) {
2466
2467 if (pSMBr->resp.hdr.WordCount == 4) {
2468 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002469 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 blob_len));
2471 }
2472
Steve French12b3b8f2006-02-09 21:12:47 +00002473 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474
2475 memcpy(ses->server->cryptKey,
2476 SecurityBlob2->Challenge,
2477 CIFS_CRYPTO_KEY_SIZE);
Steve French12b3b8f2006-02-09 21:12:47 +00002478 if(SecurityBlob2->NegotiateFlags &
2479 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 *pNTLMv2_flag = TRUE;
2481
2482 if((SecurityBlob2->NegotiateFlags &
2483 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
2484 || (sign_CIFS_PDUs > 1))
2485 ses->server->secMode |=
2486 SECMODE_SIGN_REQUIRED;
2487 if ((SecurityBlob2->NegotiateFlags &
2488 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
2489 ses->server->secMode |=
2490 SECMODE_SIGN_ENABLED;
2491
2492 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2493 if ((long) (bcc_ptr) % 2) {
2494 remaining_words =
2495 (BCC(smb_buffer_response)
2496 - 1) / 2;
2497 bcc_ptr++; /* Unicode strings must be word aligned */
2498 } else {
2499 remaining_words =
2500 BCC
2501 (smb_buffer_response) / 2;
2502 }
2503 len =
2504 UniStrnlen((wchar_t *) bcc_ptr,
2505 remaining_words - 1);
2506/* We look for obvious messed up bcc or strings in response so we do not go off
2507 the end since (at least) WIN2K and Windows XP have a major bug in not null
2508 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002509 if(ses->serverOS)
2510 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002512 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002514 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 bcc_ptr, len,
2516 nls_codepage);
2517 bcc_ptr += 2 * (len + 1);
2518 remaining_words -= len + 1;
2519 ses->serverOS[2 * len] = 0;
2520 ses->serverOS[1 + (2 * len)] = 0;
2521 if (remaining_words > 0) {
2522 len = UniStrnlen((wchar_t *)
2523 bcc_ptr,
2524 remaining_words
2525 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002526 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002528 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 GFP_KERNEL);
2530 cifs_strfromUCS_le(ses->
2531 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002532 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 bcc_ptr,
2534 len,
2535 nls_codepage);
2536 bcc_ptr += 2 * (len + 1);
2537 ses->serverNOS[2 * len] = 0;
2538 ses->serverNOS[1 +
2539 (2 * len)] = 0;
2540 remaining_words -= len + 1;
2541 if (remaining_words > 0) {
2542 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2543 /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002544 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002546 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 (len +
2548 1),
2549 GFP_KERNEL);
2550 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002551 (ses->serverDomain,
2552 (__le16 *)bcc_ptr,
2553 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 bcc_ptr +=
2555 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002556 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002558 ses->serverDomain
2559 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 = 0;
2561 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002562 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002563 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002565 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002569 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002571 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002572 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002574 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 }
2576 } else { /* ASCII */
2577 len = strnlen(bcc_ptr, 1024);
2578 if (((long) bcc_ptr + len) - (long)
2579 pByteArea(smb_buffer_response)
2580 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00002581 if(ses->serverOS)
2582 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002584 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 GFP_KERNEL);
2586 strncpy(ses->serverOS,
2587 bcc_ptr, len);
2588
2589 bcc_ptr += len;
2590 bcc_ptr[0] = 0; /* null terminate string */
2591 bcc_ptr++;
2592
2593 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002594 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002596 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 GFP_KERNEL);
2598 strncpy(ses->serverNOS, bcc_ptr, len);
2599 bcc_ptr += len;
2600 bcc_ptr[0] = 0;
2601 bcc_ptr++;
2602
2603 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002604 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002606 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 GFP_KERNEL);
2608 strncpy(ses->serverDomain, bcc_ptr, len);
2609 bcc_ptr += len;
2610 bcc_ptr[0] = 0;
2611 bcc_ptr++;
2612 } else
2613 cFYI(1,
Steve French12b3b8f2006-02-09 21:12:47 +00002614 ("Variable field of length %d extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 len));
2616 }
2617 } else {
2618 cERROR(1,
2619 (" Security Blob Length extends beyond end of SMB"));
2620 }
2621 } else {
2622 cERROR(1, ("No session structure passed in."));
2623 }
2624 } else {
2625 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002626 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 smb_buffer_response->WordCount));
2628 rc = -EIO;
2629 }
2630
2631 if (smb_buffer)
2632 cifs_buf_release(smb_buffer);
2633
2634 return rc;
2635}
2636static int
2637CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2638 char *ntlm_session_key, int ntlmv2_flag,
2639 const struct nls_table *nls_codepage)
2640{
2641 struct smb_hdr *smb_buffer;
2642 struct smb_hdr *smb_buffer_response;
2643 SESSION_SETUP_ANDX *pSMB;
2644 SESSION_SETUP_ANDX *pSMBr;
2645 char *bcc_ptr;
2646 char *user;
2647 char *domain;
2648 int rc = 0;
2649 int remaining_words = 0;
2650 int bytes_returned = 0;
2651 int len;
2652 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2653 PAUTHENTICATE_MESSAGE SecurityBlob;
2654 __u32 negotiate_flags, capabilities;
2655 __u16 count;
2656
2657 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
2658 if(ses == NULL)
2659 return -EINVAL;
2660 user = ses->userName;
2661 domain = ses->domainName;
2662 smb_buffer = cifs_buf_get();
2663 if (smb_buffer == NULL) {
2664 return -ENOMEM;
2665 }
2666 smb_buffer_response = smb_buffer;
2667 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2668 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2669
2670 /* send SMBsessionSetup here */
2671 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2672 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002673
2674 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2676 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2677 pSMB->req.AndXCommand = 0xFF;
2678 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2679 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2680
2681 pSMB->req.hdr.Uid = ses->Suid;
2682
2683 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
2684 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2685
2686 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2687 CAP_EXTENDED_SECURITY;
2688 if (ses->capabilities & CAP_UNICODE) {
2689 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2690 capabilities |= CAP_UNICODE;
2691 }
2692 if (ses->capabilities & CAP_STATUS32) {
2693 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2694 capabilities |= CAP_STATUS32;
2695 }
2696 if (ses->capabilities & CAP_DFS) {
2697 smb_buffer->Flags2 |= SMBFLG2_DFS;
2698 capabilities |= CAP_DFS;
2699 }
2700 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2701
2702 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2703 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2704 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2705 SecurityBlob->MessageType = NtLmAuthenticate;
2706 bcc_ptr += SecurityBlobLength;
2707 negotiate_flags =
2708 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2709 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2710 0x80000000 | NTLMSSP_NEGOTIATE_128;
2711 if(sign_CIFS_PDUs)
2712 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
2713 if(ntlmv2_flag)
2714 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2715
2716/* setup pointers to domain name and workstation name */
2717
2718 SecurityBlob->WorkstationName.Buffer = 0;
2719 SecurityBlob->WorkstationName.Length = 0;
2720 SecurityBlob->WorkstationName.MaximumLength = 0;
2721 SecurityBlob->SessionKey.Length = 0;
2722 SecurityBlob->SessionKey.MaximumLength = 0;
2723 SecurityBlob->SessionKey.Buffer = 0;
2724
2725 SecurityBlob->LmChallengeResponse.Length = 0;
2726 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2727 SecurityBlob->LmChallengeResponse.Buffer = 0;
2728
2729 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002730 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002732 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2733 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 SecurityBlob->NtChallengeResponse.Buffer =
2735 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002736 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2737 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738
2739 if (ses->capabilities & CAP_UNICODE) {
2740 if (domain == NULL) {
2741 SecurityBlob->DomainName.Buffer = 0;
2742 SecurityBlob->DomainName.Length = 0;
2743 SecurityBlob->DomainName.MaximumLength = 0;
2744 } else {
2745 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002746 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 nls_codepage);
2748 len *= 2;
2749 SecurityBlob->DomainName.MaximumLength =
2750 cpu_to_le16(len);
2751 SecurityBlob->DomainName.Buffer =
2752 cpu_to_le32(SecurityBlobLength);
2753 bcc_ptr += len;
2754 SecurityBlobLength += len;
2755 SecurityBlob->DomainName.Length =
2756 cpu_to_le16(len);
2757 }
2758 if (user == NULL) {
2759 SecurityBlob->UserName.Buffer = 0;
2760 SecurityBlob->UserName.Length = 0;
2761 SecurityBlob->UserName.MaximumLength = 0;
2762 } else {
2763 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002764 cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 nls_codepage);
2766 len *= 2;
2767 SecurityBlob->UserName.MaximumLength =
2768 cpu_to_le16(len);
2769 SecurityBlob->UserName.Buffer =
2770 cpu_to_le32(SecurityBlobLength);
2771 bcc_ptr += len;
2772 SecurityBlobLength += len;
2773 SecurityBlob->UserName.Length =
2774 cpu_to_le16(len);
2775 }
2776
Steve Frenche89dc922005-11-11 15:18:19 -08002777 /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 SecurityBlob->WorkstationName.Length *= 2;
2779 SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
2780 SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
2781 bcc_ptr += SecurityBlob->WorkstationName.Length;
2782 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
2783 SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
2784
2785 if ((long) bcc_ptr % 2) {
2786 *bcc_ptr = 0;
2787 bcc_ptr++;
2788 }
2789 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002790 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 32, nls_codepage);
2792 bcc_ptr += 2 * bytes_returned;
2793 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002794 cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 nls_codepage);
2796 bcc_ptr += 2 * bytes_returned;
2797 bcc_ptr += 2; /* null term version string */
2798 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002799 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 64, nls_codepage);
2801 bcc_ptr += 2 * bytes_returned;
2802 *(bcc_ptr + 1) = 0;
2803 *(bcc_ptr + 2) = 0;
2804 bcc_ptr += 2; /* null terminate network opsys string */
2805 *(bcc_ptr + 1) = 0;
2806 *(bcc_ptr + 2) = 0;
2807 bcc_ptr += 2; /* null domain */
2808 } else { /* ASCII */
2809 if (domain == NULL) {
2810 SecurityBlob->DomainName.Buffer = 0;
2811 SecurityBlob->DomainName.Length = 0;
2812 SecurityBlob->DomainName.MaximumLength = 0;
2813 } else {
2814 __u16 len;
2815 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
2816 strncpy(bcc_ptr, domain, 63);
2817 len = strnlen(domain, 64);
2818 SecurityBlob->DomainName.MaximumLength =
2819 cpu_to_le16(len);
2820 SecurityBlob->DomainName.Buffer =
2821 cpu_to_le32(SecurityBlobLength);
2822 bcc_ptr += len;
2823 SecurityBlobLength += len;
2824 SecurityBlob->DomainName.Length = cpu_to_le16(len);
2825 }
2826 if (user == NULL) {
2827 SecurityBlob->UserName.Buffer = 0;
2828 SecurityBlob->UserName.Length = 0;
2829 SecurityBlob->UserName.MaximumLength = 0;
2830 } else {
2831 __u16 len;
2832 strncpy(bcc_ptr, user, 63);
2833 len = strnlen(user, 64);
2834 SecurityBlob->UserName.MaximumLength =
2835 cpu_to_le16(len);
2836 SecurityBlob->UserName.Buffer =
2837 cpu_to_le32(SecurityBlobLength);
2838 bcc_ptr += len;
2839 SecurityBlobLength += len;
2840 SecurityBlob->UserName.Length = cpu_to_le16(len);
2841 }
2842 /* BB fill in our workstation name if known BB */
2843
2844 strcpy(bcc_ptr, "Linux version ");
2845 bcc_ptr += strlen("Linux version ");
2846 strcpy(bcc_ptr, system_utsname.release);
2847 bcc_ptr += strlen(system_utsname.release) + 1;
2848 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2849 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2850 bcc_ptr++; /* null domain */
2851 *bcc_ptr = 0;
2852 }
2853 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2854 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2855 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2856 smb_buffer->smb_buf_length += count;
2857 pSMB->req.ByteCount = cpu_to_le16(count);
2858
2859 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2860 &bytes_returned, 1);
2861 if (rc) {
2862/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2863 } else if ((smb_buffer_response->WordCount == 3)
2864 || (smb_buffer_response->WordCount == 4)) {
2865 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2866 __u16 blob_len =
2867 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2868 if (action & GUEST_LOGIN)
2869 cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
2870/* if(SecurityBlob2->MessageType != NtLm??){
2871 cFYI("Unexpected message type on auth response is %d "));
2872 } */
2873 if (ses) {
2874 cFYI(1,
2875 ("Does UID on challenge %d match auth response UID %d ",
2876 ses->Suid, smb_buffer_response->Uid));
2877 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
2878 bcc_ptr = pByteArea(smb_buffer_response);
2879 /* response can have either 3 or 4 word count - Samba sends 3 */
2880 if ((pSMBr->resp.hdr.WordCount == 3)
2881 || ((pSMBr->resp.hdr.WordCount == 4)
2882 && (blob_len <
2883 pSMBr->resp.ByteCount))) {
2884 if (pSMBr->resp.hdr.WordCount == 4) {
2885 bcc_ptr +=
2886 blob_len;
2887 cFYI(1,
2888 ("Security Blob Length %d ",
2889 blob_len));
2890 }
2891
2892 cFYI(1,
2893 ("NTLMSSP response to Authenticate "));
2894
2895 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2896 if ((long) (bcc_ptr) % 2) {
2897 remaining_words =
2898 (BCC(smb_buffer_response)
2899 - 1) / 2;
2900 bcc_ptr++; /* Unicode strings must be word aligned */
2901 } else {
2902 remaining_words = BCC(smb_buffer_response) / 2;
2903 }
2904 len =
2905 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
2906/* We look for obvious messed up bcc or strings in response so we do not go off
2907 the end since (at least) WIN2K and Windows XP have a major bug in not null
2908 terminating last Unicode string in response */
Steve Frencha424f8b2006-05-30 18:06:04 +00002909 if(ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00002910 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002912 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002914 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 bcc_ptr, len,
2916 nls_codepage);
2917 bcc_ptr += 2 * (len + 1);
2918 remaining_words -= len + 1;
2919 ses->serverOS[2 * len] = 0;
2920 ses->serverOS[1 + (2 * len)] = 0;
2921 if (remaining_words > 0) {
2922 len = UniStrnlen((wchar_t *)
2923 bcc_ptr,
2924 remaining_words
2925 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002926 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002928 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 GFP_KERNEL);
2930 cifs_strfromUCS_le(ses->
2931 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002932 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 bcc_ptr,
2934 len,
2935 nls_codepage);
2936 bcc_ptr += 2 * (len + 1);
2937 ses->serverNOS[2 * len] = 0;
2938 ses->serverNOS[1+(2*len)] = 0;
2939 remaining_words -= len + 1;
2940 if (remaining_words > 0) {
2941 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2942 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frencha424f8b2006-05-30 18:06:04 +00002943 if(ses->serverDomain)
2944 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002946 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 (len +
2948 1),
2949 GFP_KERNEL);
2950 cifs_strfromUCS_le
2951 (ses->
2952 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08002953 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 bcc_ptr, len,
2955 nls_codepage);
2956 bcc_ptr +=
2957 2 * (len + 1);
2958 ses->
2959 serverDomain[2
2960 * len]
2961 = 0;
2962 ses->
2963 serverDomain[1
2964 +
2965 (2
2966 *
2967 len)]
2968 = 0;
2969 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002970 else {
2971 if(ses->serverDomain)
2972 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07002973 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002974 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 } else { /* no room so create dummy domain and NOS string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002976 if(ses->serverDomain)
2977 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07002978 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002979 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002980 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 }
2982 } else { /* ASCII */
2983 len = strnlen(bcc_ptr, 1024);
2984 if (((long) bcc_ptr + len) -
2985 (long) pByteArea(smb_buffer_response)
2986 <= BCC(smb_buffer_response)) {
Steve Frencha424f8b2006-05-30 18:06:04 +00002987 if(ses->serverOS)
2988 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002989 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 strncpy(ses->serverOS,bcc_ptr, len);
2991
2992 bcc_ptr += len;
2993 bcc_ptr[0] = 0; /* null terminate the string */
2994 bcc_ptr++;
2995
2996 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002997 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07002998 ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 strncpy(ses->serverNOS, bcc_ptr, len);
3000 bcc_ptr += len;
3001 bcc_ptr[0] = 0;
3002 bcc_ptr++;
3003
3004 len = strnlen(bcc_ptr, 1024);
Steve Frencha424f8b2006-05-30 18:06:04 +00003005 if(ses->serverDomain)
3006 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003007 ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 strncpy(ses->serverDomain, bcc_ptr, len);
3009 bcc_ptr += len;
3010 bcc_ptr[0] = 0;
3011 bcc_ptr++;
3012 } else
3013 cFYI(1,
3014 ("Variable field of length %d extends beyond end of smb ",
3015 len));
3016 }
3017 } else {
3018 cERROR(1,
3019 (" Security Blob Length extends beyond end of SMB"));
3020 }
3021 } else {
3022 cERROR(1, ("No session structure passed in."));
3023 }
3024 } else {
3025 cERROR(1,
3026 (" Invalid Word count %d: ",
3027 smb_buffer_response->WordCount));
3028 rc = -EIO;
3029 }
3030
3031 if (smb_buffer)
3032 cifs_buf_release(smb_buffer);
3033
3034 return rc;
3035}
3036
3037int
3038CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3039 const char *tree, struct cifsTconInfo *tcon,
3040 const struct nls_table *nls_codepage)
3041{
3042 struct smb_hdr *smb_buffer;
3043 struct smb_hdr *smb_buffer_response;
3044 TCONX_REQ *pSMB;
3045 TCONX_RSP *pSMBr;
3046 unsigned char *bcc_ptr;
3047 int rc = 0;
3048 int length;
3049 __u16 count;
3050
3051 if (ses == NULL)
3052 return -EIO;
3053
3054 smb_buffer = cifs_buf_get();
3055 if (smb_buffer == NULL) {
3056 return -ENOMEM;
3057 }
3058 smb_buffer_response = smb_buffer;
3059
3060 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3061 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003062
3063 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 smb_buffer->Uid = ses->Suid;
3065 pSMB = (TCONX_REQ *) smb_buffer;
3066 pSMBr = (TCONX_RSP *) smb_buffer_response;
3067
3068 pSMB->AndXCommand = 0xFF;
3069 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 bcc_ptr = &pSMB->Password[0];
Steve Frencheeac8042006-01-13 21:34:58 -08003071 if((ses->server->secMode) & SECMODE_USER) {
3072 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003073 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003074 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003075 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003076 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003077 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003078 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3079 specified as required (when that support is added to
3080 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003081 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003082 by Samba (not sure whether other servers allow
3083 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003084#ifdef CONFIG_CIFS_WEAK_PW_HASH
3085 if((extended_security & CIFSSEC_MAY_LANMAN) &&
3086 (ses->server->secType == LANMAN))
3087 calc_lanman_hash(ses, bcc_ptr);
3088 else
3089#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003090 SMBNTencrypt(ses->password,
3091 ses->server->cryptKey,
3092 bcc_ptr);
3093
Steve French7c7b25b2006-06-01 19:20:10 +00003094 bcc_ptr += CIFS_SESS_KEY_SIZE;
3095 if(ses->capabilities & CAP_UNICODE) {
3096 /* must align unicode strings */
3097 *bcc_ptr = 0; /* null byte password */
3098 bcc_ptr++;
3099 }
Steve Frencheeac8042006-01-13 21:34:58 -08003100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101
Steve Frencha878fb22006-05-30 18:04:19 +00003102 if(ses->server->secMode &
3103 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3105
3106 if (ses->capabilities & CAP_STATUS32) {
3107 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3108 }
3109 if (ses->capabilities & CAP_DFS) {
3110 smb_buffer->Flags2 |= SMBFLG2_DFS;
3111 }
3112 if (ses->capabilities & CAP_UNICODE) {
3113 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3114 length =
Steve Frencha878fb22006-05-30 18:04:19 +00003115 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3116 6 /* max utf8 char length in bytes */ *
3117 (/* server len*/ + 256 /* share len */), nls_codepage);
3118 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 bcc_ptr += 2; /* skip trailing null */
3120 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 strcpy(bcc_ptr, tree);
3122 bcc_ptr += strlen(tree) + 1;
3123 }
3124 strcpy(bcc_ptr, "?????");
3125 bcc_ptr += strlen("?????");
3126 bcc_ptr += 1;
3127 count = bcc_ptr - &pSMB->Password[0];
3128 pSMB->hdr.smb_buf_length += count;
3129 pSMB->ByteCount = cpu_to_le16(count);
3130
3131 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3132
3133 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3134 /* above now done in SendReceive */
3135 if ((rc == 0) && (tcon != NULL)) {
3136 tcon->tidStatus = CifsGood;
3137 tcon->tid = smb_buffer_response->Tid;
3138 bcc_ptr = pByteArea(smb_buffer_response);
3139 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
3140 /* skip service field (NB: this field is always ASCII) */
3141 bcc_ptr += length + 1;
3142 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3143 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3144 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3145 if ((bcc_ptr + (2 * length)) -
3146 pByteArea(smb_buffer_response) <=
3147 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003148 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003150 kzalloc(length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 cifs_strfromUCS_le(tcon->nativeFileSystem,
Steve Frenche89dc922005-11-11 15:18:19 -08003152 (__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 length, nls_codepage);
3154 bcc_ptr += 2 * length;
3155 bcc_ptr[0] = 0; /* null terminate the string */
3156 bcc_ptr[1] = 0;
3157 bcc_ptr += 2;
3158 }
3159 /* else do not bother copying these informational fields */
3160 } else {
3161 length = strnlen(bcc_ptr, 1024);
3162 if ((bcc_ptr + length) -
3163 pByteArea(smb_buffer_response) <=
3164 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003165 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003167 kzalloc(length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 strncpy(tcon->nativeFileSystem, bcc_ptr,
3169 length);
3170 }
3171 /* else do not bother copying these informational fields */
3172 }
Steve French39798772006-05-31 22:40:51 +00003173 if(smb_buffer_response->WordCount == 3)
3174 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3175 else
3176 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3178 } else if ((rc == 0) && tcon == NULL) {
3179 /* all we need to save for IPC$ connection */
3180 ses->ipc_tid = smb_buffer_response->Tid;
3181 }
3182
3183 if (smb_buffer)
3184 cifs_buf_release(smb_buffer);
3185 return rc;
3186}
3187
3188int
3189cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3190{
3191 int rc = 0;
3192 int xid;
3193 struct cifsSesInfo *ses = NULL;
3194 struct task_struct *cifsd_task;
3195
3196 xid = GetXid();
3197
3198 if (cifs_sb->tcon) {
3199 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3200 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3201 if (rc == -EBUSY) {
3202 FreeXid(xid);
3203 return 0;
3204 }
3205 tconInfoFree(cifs_sb->tcon);
3206 if ((ses) && (ses->server)) {
3207 /* save off task so we do not refer to ses later */
3208 cifsd_task = ses->server->tsk;
3209 cFYI(1, ("About to do SMBLogoff "));
3210 rc = CIFSSMBLogoff(xid, ses);
3211 if (rc == -EBUSY) {
3212 FreeXid(xid);
3213 return 0;
3214 } else if (rc == -ESHUTDOWN) {
3215 cFYI(1,("Waking up socket by sending it signal"));
Steve Frenchf1914012005-08-18 09:37:34 -07003216 if(cifsd_task) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 send_sig(SIGKILL,cifsd_task,1);
Steve Frenchf1914012005-08-18 09:37:34 -07003218 wait_for_completion(&cifsd_complete);
3219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 rc = 0;
3221 } /* else - we have an smb session
3222 left on this socket do not kill cifsd */
3223 } else
3224 cFYI(1, ("No session or bad tcon"));
3225 }
3226
3227 cifs_sb->tcon = NULL;
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003228 if (ses)
3229 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 if (ses)
3231 sesInfoFree(ses);
3232
3233 FreeXid(xid);
3234 return rc; /* BB check if we should always return zero here */
3235}
3236
3237int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3238 struct nls_table * nls_info)
3239{
3240 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003241 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003243 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244
3245 /* what if server changes its buffer size after dropping the session? */
3246 if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
3247 rc = CIFSSMBNegotiate(xid, pSesInfo);
3248 if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
3249 rc = CIFSSMBNegotiate(xid, pSesInfo);
3250 if(rc == -EAGAIN)
3251 rc = -EHOSTDOWN;
3252 }
3253 if(rc == 0) {
3254 spin_lock(&GlobalMid_Lock);
3255 if(pSesInfo->server->tcpStatus != CifsExiting)
3256 pSesInfo->server->tcpStatus = CifsGood;
3257 else
3258 rc = -EHOSTDOWN;
3259 spin_unlock(&GlobalMid_Lock);
3260
3261 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003262 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 }
3264 if (!rc) {
3265 pSesInfo->capabilities = pSesInfo->server->capabilities;
3266 if(linuxExtEnabled == 0)
3267 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003268 /* pSesInfo->sequence_number = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
3270 pSesInfo->server->secMode,
3271 pSesInfo->server->capabilities,
3272 pSesInfo->server->timeZone));
Steve French189acaa2006-06-23 02:33:48 +00003273 if(experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003274 rc = CIFS_SessSetup(xid, pSesInfo,
3275 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003276 else if (extended_security
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3278 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003279 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 } else if (extended_security
3281 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3282 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003283 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3285 pSesInfo,
3286 &ntlmv2_flag,
3287 nls_info);
3288 if (!rc) {
3289 if(ntlmv2_flag) {
3290 char * v2_response;
3291 cFYI(1,("Can use more secure NTLM version 2 password hash"));
3292 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3293 nls_info)) {
3294 rc = -ENOMEM;
3295 goto ss_err_exit;
3296 } else
3297 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
3298 if(v2_response) {
3299 CalcNTLMv2_response(pSesInfo,v2_response);
Steve Frenchad009ac2005-04-28 22:41:05 -07003300 /* if(first_time)
3301 cifs_calculate_ntlmv2_mac_key(
3302 pSesInfo->server->mac_signing_key,
3303 response, ntlm_session_key, */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 kfree(v2_response);
3305 /* BB Put dummy sig in SessSetup PDU? */
3306 } else {
3307 rc = -ENOMEM;
3308 goto ss_err_exit;
3309 }
3310
3311 } else {
3312 SMBNTencrypt(pSesInfo->password,
3313 pSesInfo->server->cryptKey,
3314 ntlm_session_key);
3315
Steve Frenchad009ac2005-04-28 22:41:05 -07003316 if(first_time)
3317 cifs_calculate_mac_key(
3318 pSesInfo->server->mac_signing_key,
3319 ntlm_session_key,
3320 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 }
3322 /* for better security the weaker lanman hash not sent
3323 in AuthSessSetup so we no longer calculate it */
3324
3325 rc = CIFSNTLMSSPAuthSessSetup(xid,
3326 pSesInfo,
3327 ntlm_session_key,
3328 ntlmv2_flag,
3329 nls_info);
3330 }
3331 } else { /* old style NTLM 0.12 session setup */
3332 SMBNTencrypt(pSesInfo->password,
3333 pSesInfo->server->cryptKey,
3334 ntlm_session_key);
3335
Steve Frenchad009ac2005-04-28 22:41:05 -07003336 if(first_time)
3337 cifs_calculate_mac_key(
3338 pSesInfo->server->mac_signing_key,
3339 ntlm_session_key, pSesInfo->password);
3340
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 rc = CIFSSessSetup(xid, pSesInfo,
3342 ntlm_session_key, nls_info);
3343 }
3344 if (rc) {
3345 cERROR(1,("Send error in SessSetup = %d",rc));
3346 } else {
3347 cFYI(1,("CIFS Session Established successfully"));
3348 pSesInfo->status = CifsGood;
3349 }
3350 }
3351ss_err_exit:
3352 return rc;
3353}
3354