blob: a36f4bd5a764c1c1ae968c94425f3bf4b6094f26 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve French366781c2008-01-25 10:12:41 +00004 * Copyright (C) International Business Machines Corp., 2002,2008
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
Steve Frenchfb8c4b12007-07-10 01:16:18 +000019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 */
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>
Igor Mammedovaaf737a2007-04-03 19:16:43 +000033#include <linux/kthread.h>
Steve French0ae0efa2005-10-10 10:57:19 -070034#include <linux/pagevec.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080035#include <linux/freezer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/uaccess.h>
37#include <asm/processor.h>
38#include "cifspdu.h"
39#include "cifsglob.h"
40#include "cifsproto.h"
41#include "cifs_unicode.h"
42#include "cifs_debug.h"
43#include "cifs_fs_sb.h"
44#include "ntlmssp.h"
45#include "nterr.h"
46#include "rfc1002pdu.h"
Steve Frencha2653eb2005-11-10 15:33:38 -080047#include "cn_cifs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#define CIFS_PORT 445
50#define RFC1001_PORT 139
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;
Steve French95b1cb92008-05-15 16:44:38 +000063 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 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;
Steve French4b18f2a2008-04-29 00:06:05 +000072 bool rw:1;
73 bool retry:1;
74 bool intr:1;
75 bool setuids:1;
76 bool override_uid:1;
77 bool override_gid:1;
Jeff Laytond0a9c072008-05-12 22:23:49 +000078 bool dynperm:1;
Steve French4b18f2a2008-04-29 00:06:05 +000079 bool noperm:1;
80 bool no_psx_acl:1; /* set if posix acl support should be disabled */
81 bool cifs_acl:1;
82 bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
83 bool server_ino:1; /* use inode numbers from server ie UniqueId */
84 bool direct_io:1;
Steve French95b1cb92008-05-15 16:44:38 +000085 bool remap:1; /* set to remap seven reserved chars in filenames */
86 bool posix_paths:1; /* unset to not ask for posix pathnames. */
Steve French4b18f2a2008-04-29 00:06:05 +000087 bool no_linux_ext:1;
88 bool sfu_emul:1;
Steve French95b1cb92008-05-15 16:44:38 +000089 bool nullauth:1; /* attempt to authenticate with null user */
90 bool nocase:1; /* request case insensitive filenames */
91 bool nobrl:1; /* disable sending byte range locks to srv */
92 bool seal:1; /* request transport encryption on share */
Steve French84210e92008-10-23 04:42:37 +000093 bool nodfs:1; /* Do not request DFS, even if available */
94 bool local_lease:1; /* check leases only on local system, not remote */
Steve Frenchedf1ae42008-10-29 00:47:57 +000095 bool noblocksnd:1;
96 bool noautotune:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 unsigned int rsize;
98 unsigned int wsize;
99 unsigned int sockopt;
100 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000101 char *prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102};
103
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500104static int ipv4_connect(struct TCP_Server_Info *server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000105static int ipv6_connect(struct sockaddr_in6 *psin_server,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000106 struct socket **csocket, bool noblocksnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
108
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000109 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 * cifs tcp session reconnection
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000111 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 * mark tcp session as reconnecting so temporarily locked
113 * mark all smb sessions as reconnecting for tcp session
114 * reconnect tcp session
115 * wake up waiters on reconnection? - (not needed currently)
116 */
117
Steve French2cd646a2006-09-28 19:43:08 +0000118static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119cifs_reconnect(struct TCP_Server_Info *server)
120{
121 int rc = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500122 struct list_head *tmp, *tmp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 struct cifsSesInfo *ses;
124 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000125 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000126
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000128 if (server->tcpStatus == CifsExiting) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000129 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 next time through the loop */
131 spin_unlock(&GlobalMid_Lock);
132 return rc;
133 } else
134 server->tcpStatus = CifsNeedReconnect;
135 spin_unlock(&GlobalMid_Lock);
136 server->maxBuf = 0;
137
Steve Frenche4eb2952005-04-28 22:41:09 -0700138 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140 /* before reconnecting the tcp session, mark the smb session (uid)
141 and the tid bad so they are not used until reconnected */
Jeff Layton14fbf502008-11-14 13:53:46 -0500142 read_lock(&cifs_tcp_ses_lock);
143 list_for_each(tmp, &server->smb_ses_list) {
144 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
145 ses->need_reconnect = true;
146 ses->ipc_tid = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500147 list_for_each(tmp2, &ses->tcon_list) {
148 tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list);
149 tcon->need_reconnect = true;
150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500152 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 /* do not want to be sending data on a socket we are freeing */
Jeff Layton72ca5452008-12-01 07:09:36 -0500154 mutex_lock(&server->srv_mutex);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000155 if (server->ssocket) {
Steve French467a8f82007-06-27 22:41:32 +0000156 cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 server->ssocket->flags));
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800158 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000159 cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000160 server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 server->ssocket->flags));
162 sock_release(server->ssocket);
163 server->ssocket = NULL;
164 }
165
166 spin_lock(&GlobalMid_Lock);
167 list_for_each(tmp, &server->pending_mid_q) {
168 mid_entry = list_entry(tmp, struct
169 mid_q_entry,
170 qhead);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000171 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 */
Steve Frenchad8b15f2008-08-08 21:10:16 +0000176 mid_entry->midState = MID_RETRY_NEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 }
178 }
179 spin_unlock(&GlobalMid_Lock);
Jeff Layton72ca5452008-12-01 07:09:36 -0500180 mutex_unlock(&server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Jeff Layton469ee612008-10-16 18:46:39 +0000182 while ((server->tcpStatus != CifsExiting) &&
183 (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000184 try_to_freeze();
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500185 if (server->addr.sockAddr6.sin6_family == AF_INET6)
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000186 rc = ipv6_connect(&server->addr.sockAddr6,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000187 &server->ssocket, server->noautotune);
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500188 else
189 rc = ipv4_connect(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000190 if (rc) {
191 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700192 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 } else {
194 atomic_inc(&tcpSesReconnectCount);
195 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000196 if (server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700198 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000199 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 /* atomic_set(&server->inFlight,0);*/
201 wake_up(&server->response_q);
202 }
203 }
204 return rc;
205}
206
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000207/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700208 return codes:
209 0 not a transact2, or all data present
210 >0 transact2 with that much data missing
211 -EINVAL = invalid transact2
212
213 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000214static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700215{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000216 struct smb_t2_rsp *pSMBt;
217 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700218 int data_in_this_rsp;
219 int remaining;
220
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000221 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700222 return 0;
223
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000224 /* check for plausible wct, bcc and t2 data and parm sizes */
225 /* check for parm and data offset going beyond end of smb */
226 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Steve French467a8f82007-06-27 22:41:32 +0000227 cFYI(1, ("invalid transact2 word count"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700228 return -EINVAL;
229 }
230
231 pSMBt = (struct smb_t2_rsp *)pSMB;
232
233 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
234 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
235
236 remaining = total_data_size - data_in_this_rsp;
237
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000238 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700239 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000240 else if (remaining < 0) {
Steve French467a8f82007-06-27 22:41:32 +0000241 cFYI(1, ("total data %d smaller than data in frame %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700242 total_data_size, data_in_this_rsp));
243 return -EINVAL;
244 } else {
Steve French467a8f82007-06-27 22:41:32 +0000245 cFYI(1, ("missing %d bytes from transact2, check next response",
Steve Frenche4eb2952005-04-28 22:41:09 -0700246 remaining));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000247 if (total_data_size > maxBufSize) {
248 cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
249 total_data_size, maxBufSize));
250 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700251 }
252 return remaining;
253 }
254}
255
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000256static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700257{
258 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
259 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
260 int total_data_size;
261 int total_in_buf;
262 int remaining;
263 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000264 char *data_area_of_target;
265 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700266 __u16 byte_count;
267
268 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
269
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000270 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Steve French63135e02007-07-17 17:34:02 +0000271 cFYI(1, ("total data size of primary and secondary t2 differ"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700272 }
273
274 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
275
276 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000277
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000278 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700279 return -EINVAL;
280
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000281 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700282 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000283
Steve Frenche4eb2952005-04-28 22:41:09 -0700284 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000285 if (remaining < total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000286 cFYI(1, ("transact2 2nd response contains too much data"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700287 }
288
289 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000290 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700291 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
292 /* validate target area */
293
294 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000295 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700296
297 data_area_of_target += total_in_buf;
298
299 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000300 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700301 total_in_buf += total_in_buf2;
302 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
303 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
304 byte_count += total_in_buf2;
305 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
306
Steve French70ca7342005-09-22 16:32:06 -0700307 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700308 byte_count += total_in_buf2;
309
310 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000311
Steve French70ca7342005-09-22 16:32:06 -0700312 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700313
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000314 if (remaining == total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000315 cFYI(1, ("found the last secondary response"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700316 return 0; /* we are done */
317 } else /* more responses to go */
318 return 1;
319
320}
321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322static int
323cifs_demultiplex_thread(struct TCP_Server_Info *server)
324{
325 int length;
326 unsigned int pdu_length, total_read;
327 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700328 struct smb_hdr *bigbuf = NULL;
329 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 struct msghdr smb_msg;
331 struct kvec iov;
332 struct socket *csocket = server->ssocket;
333 struct list_head *tmp;
334 struct cifsSesInfo *ses;
335 struct task_struct *task_to_wake = NULL;
336 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700337 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000338 bool isLargeBuf = false;
339 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700340 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 current->flags |= PF_MEMALLOC;
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700343 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400344
345 length = atomic_inc_return(&tcpSesAllocCount);
346 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000347 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
348 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700350 set_freezable();
Jeff Layton469ee612008-10-16 18:46:39 +0000351 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700352 if (try_to_freeze())
353 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700354 if (bigbuf == NULL) {
355 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000356 if (!bigbuf) {
357 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700358 msleep(3000);
359 /* retry will check if exiting */
360 continue;
361 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000362 } else if (isLargeBuf) {
363 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000364 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700366
367 if (smallbuf == NULL) {
368 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000369 if (!smallbuf) {
370 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700371 msleep(1000);
372 /* retry will check if exiting */
373 continue;
374 }
375 /* beginning of smb buffer is cleared in our buf_get */
376 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000377 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700378
Steve French4b18f2a2008-04-29 00:06:05 +0000379 isLargeBuf = false;
380 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700381 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 iov.iov_base = smb_buffer;
383 iov.iov_len = 4;
384 smb_msg.msg_control = NULL;
385 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000386 pdu_length = 4; /* enough to get RFC1001 header */
387incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 length =
389 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000390 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
Jeff Layton469ee612008-10-16 18:46:39 +0000392 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 break;
394 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000395 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000397 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 csocket = server->ssocket;
399 continue;
400 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700401 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 allowing socket to clear and app threads to set
403 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc527c8a2008-11-03 20:46:21 +0000404 if (pdu_length < 4) {
405 iov.iov_base = (4 - pdu_length) +
406 (char *)smb_buffer;
407 iov.iov_len = pdu_length;
408 smb_msg.msg_control = NULL;
409 smb_msg.msg_controllen = 0;
Steve Frenchc18c7322007-10-17 18:01:11 +0000410 goto incomplete_rcv;
Steve Frenchc527c8a2008-11-03 20:46:21 +0000411 } else
Steve Frenchc18c7322007-10-17 18:01:11 +0000412 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 } 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)) {
Steve French467a8f82007-06-27 22:41:32 +0000423 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 break;
425 }
Steve French467a8f82007-06-27 22:41:32 +0000426 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700427 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 cifs_reconnect(server);
429 csocket = server->ssocket;
430 wake_up(&server->response_q);
431 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000432 } else if (length < pdu_length) {
433 cFYI(1, ("requested %d bytes but only got %d bytes",
434 pdu_length, length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000435 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000436 msleep(1);
437 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 }
Steve French67010fb2005-04-28 22:41:09 -0700439
Steve French70ca7342005-09-22 16:32:06 -0700440 /* The right amount was read from socket - 4 bytes */
441 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700442
Steve French70ca7342005-09-22 16:32:06 -0700443 /* the first byte big endian of the length field,
444 is actually not part of the length but the type
445 with the most common, zero, as regular data */
446 temp = *((char *) smb_buffer);
447
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000448 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700449 but we convert it here so it is always manipulated
450 as host byte order */
Harvey Harrison5ca33c62008-07-23 17:45:58 -0700451 pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700452 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700453
Steve French467a8f82007-06-27 22:41:32 +0000454 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700455
456 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000457 continue;
Steve French70ca7342005-09-22 16:32:06 -0700458 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000459 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700460 continue;
Steve French70ca7342005-09-22 16:32:06 -0700461 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000462 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700463 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000464 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700465 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000466 if (server->tcpStatus == CifsNew) {
467 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700468 ret of smb negprot error) reconnecting
469 not going to help, ret error to mount */
470 break;
471 } else {
472 /* give server a second to
473 clean up before reconnect attempt */
474 msleep(1000);
475 /* always try 445 first on reconnect
476 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000477 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700478 since we do not begin with RFC1001
479 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000480 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700481 htons(CIFS_PORT);
482 cifs_reconnect(server);
483 csocket = server->ssocket;
484 wake_up(&server->response_q);
485 continue;
486 }
Steve French70ca7342005-09-22 16:32:06 -0700487 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000488 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700489 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
490 length);
Steve French46810cb2005-04-28 22:41:09 -0700491 cifs_reconnect(server);
492 csocket = server->ssocket;
493 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700494 }
495
496 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000497 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000498 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700499 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700500 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700501 cifs_reconnect(server);
502 csocket = server->ssocket;
503 wake_up(&server->response_q);
504 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000505 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700506
507 /* else length ok */
508 reconnect = 0;
509
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000510 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000511 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700512 memcpy(bigbuf, smallbuf, 4);
513 smb_buffer = bigbuf;
514 }
515 length = 0;
516 iov.iov_base = 4 + (char *)smb_buffer;
517 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000518 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700519 total_read += length) {
520 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
521 pdu_length - total_read, 0);
Jeff Layton469ee612008-10-16 18:46:39 +0000522 if ((server->tcpStatus == CifsExiting) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700523 (length == -EINTR)) {
524 /* then will exit */
525 reconnect = 2;
526 break;
527 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700528 cifs_reconnect(server);
529 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000530 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700531 /* Now we will reread sock */
532 reconnect = 1;
533 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000534 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700535 (length == -EAGAIN)) {
536 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000537 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700538 threads to set tcpStatus
539 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000540 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700541 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700542 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000543 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700544 pdu_length - total_read));
545 cifs_reconnect(server);
546 csocket = server->ssocket;
547 reconnect = 1;
548 break;
Steve French46810cb2005-04-28 22:41:09 -0700549 }
550 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000551 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700552 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000553 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700554 continue;
555
556 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000557
Steve Frenche4eb2952005-04-28 22:41:09 -0700558
559 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000560 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700561 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700562 continue;
563 }
564
565
566 task_to_wake = NULL;
567 spin_lock(&GlobalMid_Lock);
568 list_for_each(tmp, &server->pending_mid_q) {
569 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
570
Steve French50c2f752007-07-13 00:33:32 +0000571 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700572 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
573 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000574 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700575 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000576 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000577 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700578 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000579 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700580 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000581 mid_entry->multiRsp =
582 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700583 break;
584 } else {
585 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000586 mid_entry->multiEnd =
587 true;
Steve French50c2f752007-07-13 00:33:32 +0000588 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700589 }
590 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000591 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700592 cERROR(1,("1st trans2 resp needs bigbuf"));
593 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000594 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700595 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700596 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700597 mid_entry->resp_buf =
598 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000599 mid_entry->largeBuf =
600 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700601 bigbuf = NULL;
602 }
603 }
604 break;
Steve French50c2f752007-07-13 00:33:32 +0000605 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700606 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000607 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700608multi_t2_fnd:
609 task_to_wake = mid_entry->tsk;
610 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700611#ifdef CONFIG_CIFS_STATS2
612 mid_entry->when_received = jiffies;
613#endif
Steve French3a5ff612006-07-14 22:37:11 +0000614 /* so we do not time out requests to server
615 which is still responding (since server could
616 be busy but not dead) */
617 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700618 break;
619 }
620 }
621 spin_unlock(&GlobalMid_Lock);
622 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700623 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000624 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700625 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000626 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700627 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000628 else
Steve Frenchcd634992005-04-28 22:41:10 -0700629 smallbuf = NULL;
630 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700631 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000632 } else if (!is_valid_oplock_break(smb_buffer, server) &&
633 !isMultiRsp) {
Steve French50c2f752007-07-13 00:33:32 +0000634 cERROR(1, ("No task to wake, unknown frame received! "
635 "NumMids %d", midCount.counter));
636 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700637 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 */
Steve French50c2f752007-07-13 00:33:32 +0000642
Steve Frenche4eb2952005-04-28 22:41:09 -0700643 }
644 } /* end while !EXITING */
645
Jeff Laytone7ddee92008-11-14 13:44:38 -0500646 /* take it off the list, if it's not already */
647 write_lock(&cifs_tcp_ses_lock);
648 list_del_init(&server->tcp_ses_list);
649 write_unlock(&cifs_tcp_ses_lock);
650
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 spin_lock(&GlobalMid_Lock);
652 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000653 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000654 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000655
Steve French31ca3bc2005-04-28 22:41:11 -0700656 /* check if we have blocked requests that need to free */
657 /* Note that cifs_max_pending is normally 50, but
658 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000659 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000660 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700661 atomic_set(&server->inFlight, cifs_max_pending - 1);
662 /* We do not want to set the max_pending too low or we
663 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000665 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700667 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 to the same server - they now will see the session is in exit state
669 and get out of SendReceive. */
670 wake_up_all(&server->request_q);
671 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700672 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000673
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000674 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 sock_release(csocket);
676 server->ssocket = NULL;
677 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700678 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000679 cifs_buf_release(bigbuf);
680 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700681 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Jeff Layton14fbf502008-11-14 13:53:46 -0500683 /*
684 * BB: we shouldn't have to do any of this. It shouldn't be
685 * possible to exit from the thread with active SMB sessions
686 */
687 read_lock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700689 /* loop through server session structures attached to this and
690 mark them dead */
Jeff Layton14fbf502008-11-14 13:53:46 -0500691 list_for_each(tmp, &server->smb_ses_list) {
692 ses = list_entry(tmp, struct cifsSesInfo,
693 smb_ses_list);
694 ses->status = CifsExiting;
695 ses->server = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500697 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700699 /* although we can not zero the server struct pointer yet,
700 since there are active requests which may depnd on them,
701 mark the corresponding SMB sessions as exiting too */
Jeff Layton14fbf502008-11-14 13:53:46 -0500702 list_for_each(tmp, &server->smb_ses_list) {
Steve French31ca3bc2005-04-28 22:41:11 -0700703 ses = list_entry(tmp, struct cifsSesInfo,
Jeff Layton14fbf502008-11-14 13:53:46 -0500704 smb_ses_list);
705 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700706 }
707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 spin_lock(&GlobalMid_Lock);
709 list_for_each(tmp, &server->pending_mid_q) {
710 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
711 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000712 cFYI(1, ("Clearing Mid 0x%x - waking up ",
713 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000715 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 }
718 }
719 spin_unlock(&GlobalMid_Lock);
Jeff Layton14fbf502008-11-14 13:53:46 -0500720 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700722 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 }
724
Steve Frenchf1914012005-08-18 09:37:34 -0700725 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000726 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700728 /* due to delays on oplock break requests, we need
729 to wait at least 45 seconds before giving up
730 on a request getting a response and going ahead
731 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700733 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 /* if threads still have not exited they are probably never
735 coming home not much else we can do but free the memory */
736 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Steve French31ca3bc2005-04-28 22:41:11 -0700738 /* last chance to mark ses pointers invalid
739 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000740 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700741 kernel thread explicitly this might happen) */
Jeff Layton14fbf502008-11-14 13:53:46 -0500742 /* BB: This shouldn't be necessary, see above */
743 read_lock(&cifs_tcp_ses_lock);
744 list_for_each(tmp, &server->smb_ses_list) {
745 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
746 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700747 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500748 read_unlock(&cifs_tcp_ses_lock);
Steve French31ca3bc2005-04-28 22:41:11 -0700749
Jeff Laytonc359cf32007-11-16 22:22:06 +0000750 kfree(server->hostname);
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400751 task_to_wake = xchg(&server->tsk, NULL);
Steve French31ca3bc2005-04-28 22:41:11 -0700752 kfree(server);
Jeff Layton93d0ec82008-08-02 08:00:48 -0400753
754 length = atomic_dec_return(&tcpSesAllocCount);
Steve French26f57362007-08-30 22:09:15 +0000755 if (length > 0)
756 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
757 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000758
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400759 /* if server->tsk was NULL then wait for a signal before exiting */
760 if (!task_to_wake) {
761 set_current_state(TASK_INTERRUPTIBLE);
762 while (!signal_pending(current)) {
763 schedule();
764 set_current_state(TASK_INTERRUPTIBLE);
765 }
766 set_current_state(TASK_RUNNING);
767 }
768
Jeff Layton0468a2c2008-12-01 07:09:35 -0500769 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770}
771
Jeff Laytonc359cf32007-11-16 22:22:06 +0000772/* extract the host portion of the UNC string */
773static char *
774extract_hostname(const char *unc)
775{
776 const char *src;
777 char *dst, *delim;
778 unsigned int len;
779
780 /* skip double chars at beginning of string */
781 /* BB: check validity of these bytes? */
782 src = unc + 2;
783
784 /* delimiter between hostname and sharename is always '\\' now */
785 delim = strchr(src, '\\');
786 if (!delim)
787 return ERR_PTR(-EINVAL);
788
789 len = delim - src;
790 dst = kmalloc((len + 1), GFP_KERNEL);
791 if (dst == NULL)
792 return ERR_PTR(-ENOMEM);
793
794 memcpy(dst, src, len);
795 dst[len] = '\0';
796
797 return dst;
798}
799
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800static int
Steve French50c2f752007-07-13 00:33:32 +0000801cifs_parse_mount_options(char *options, const char *devname,
802 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803{
804 char *value;
805 char *data;
806 unsigned int temp_len, i, j;
807 char separator[2];
808
809 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000810 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Linus Torvalds12e36b22006-10-13 08:09:29 -0700812 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000813 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000814 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700815 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000816 int n = strnlen(nodename, 15);
817 memset(vol->source_rfc1001_name, 0x20, 15);
818 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000819 /* does not have to be perfect mapping since field is
820 informational, only used for servers that do not support
821 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700822 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 }
825 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700826 /* null target name indicates to use *SMBSERVR default called name
827 if we end up sending RFC1001 session initialize */
828 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 vol->linux_uid = current->uid; /* current->euid instead? */
830 vol->linux_gid = current->gid;
831 vol->dir_mode = S_IRWXUGO;
832 /* 2767 perms indicate mandatory locking support */
Steve French7505e052007-11-01 18:03:01 +0000833 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
835 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Steve French4b18f2a2008-04-29 00:06:05 +0000836 vol->rw = true;
Jeremy Allisonac670552005-06-22 17:26:35 -0700837 /* default is always to request posix paths. */
838 vol->posix_paths = 1;
839
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 if (!options)
841 return 1;
842
Steve French50c2f752007-07-13 00:33:32 +0000843 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000844 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 separator[0] = options[4];
846 options += 5;
847 } else {
Steve French467a8f82007-06-27 22:41:32 +0000848 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 }
850 }
Steve French50c2f752007-07-13 00:33:32 +0000851
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 while ((data = strsep(&options, separator)) != NULL) {
853 if (!*data)
854 continue;
855 if ((value = strchr(data, '=')) != NULL)
856 *value++ = '\0';
857
Steve French50c2f752007-07-13 00:33:32 +0000858 /* Have to parse this before we parse for "user" */
859 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000861 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 vol->no_xattr = 1;
863 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000864 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 printk(KERN_WARNING
866 "CIFS: invalid or missing username\n");
867 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000868 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000869 /* null user, ie anonymous, authentication */
870 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 }
872 if (strnlen(value, 200) < 200) {
873 vol->username = value;
874 } else {
875 printk(KERN_WARNING "CIFS: username too long\n");
876 return 1;
877 }
878 } else if (strnicmp(data, "pass", 4) == 0) {
879 if (!value) {
880 vol->password = NULL;
881 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000882 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 /* check if string begins with double comma
884 since that would mean the password really
885 does start with a comma, and would not
886 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000887 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 vol->password = NULL;
889 continue;
890 }
891 }
892 temp_len = strlen(value);
893 /* removed password length check, NTLM passwords
894 can be arbitrarily long */
895
Steve French50c2f752007-07-13 00:33:32 +0000896 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 prematurely null terminated. Commas in password are
898 specified across the cifs mount interface by a double
899 comma ie ,, and a comma used as in other cases ie ','
900 as a parameter delimiter/separator is single and due
901 to the strsep above is temporarily zeroed. */
902
903 /* NB: password legally can have multiple commas and
904 the only illegal character in a password is null */
905
Steve French50c2f752007-07-13 00:33:32 +0000906 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700907 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 /* reinsert comma */
909 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000910 temp_len += 2; /* move after second comma */
911 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000913 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700914 separator[0]) {
915 /* skip second comma */
916 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000917 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 /* single comma indicating start
919 of next parm */
920 break;
921 }
922 }
923 temp_len++;
924 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000925 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 options = NULL;
927 } else {
928 value[temp_len] = 0;
929 /* point option to start of next parm */
930 options = value + temp_len + 1;
931 }
Steve French50c2f752007-07-13 00:33:32 +0000932 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 double commas to singles. Note that this ends up
934 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700935 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000936 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000937 printk(KERN_WARNING "CIFS: no memory "
938 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700939 return 1;
940 }
Steve French50c2f752007-07-13 00:33:32 +0000941 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000943 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700944 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 /* skip second comma */
946 i++;
947 }
948 }
949 vol->password[j] = 0;
950 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700951 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000952 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000953 printk(KERN_WARNING "CIFS: no memory "
954 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700955 return 1;
956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 strcpy(vol->password, value);
958 }
959 } else if (strnicmp(data, "ip", 2) == 0) {
960 if (!value || !*value) {
961 vol->UNCip = NULL;
962 } else if (strnlen(value, 35) < 35) {
963 vol->UNCip = value;
964 } else {
Steve French50c2f752007-07-13 00:33:32 +0000965 printk(KERN_WARNING "CIFS: ip address "
966 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 return 1;
968 }
Steve French50c2f752007-07-13 00:33:32 +0000969 } else if (strnicmp(data, "sec", 3) == 0) {
970 if (!value || !*value) {
971 cERROR(1, ("no security value specified"));
972 continue;
973 } else if (strnicmp(value, "krb5i", 5) == 0) {
974 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000975 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800976 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000977 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
978 CIFSSEC_MAY_KRB5; */
979 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800980 return 1;
981 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000982 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800983 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000984 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000985 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800986 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000987 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800988 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000989 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000990 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800991 } else if (strnicmp(value, "ntlm", 4) == 0) {
992 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000993 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800994 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000995 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000996 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000997#ifdef CONFIG_CIFS_WEAK_PW_HASH
998 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000999 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +00001000#endif
Steve Frenchbf820672005-12-01 22:32:42 -08001001 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +00001002 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +00001003 } else {
1004 cERROR(1, ("bad security option: %s", value));
1005 return 1;
1006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 } else if ((strnicmp(data, "unc", 3) == 0)
1008 || (strnicmp(data, "target", 6) == 0)
1009 || (strnicmp(data, "path", 4) == 0)) {
1010 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001011 printk(KERN_WARNING "CIFS: invalid path to "
1012 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 return 1; /* needs_arg; */
1014 }
1015 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001016 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001017 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001019 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 if (strncmp(vol->UNC, "//", 2) == 0) {
1021 vol->UNC[0] = '\\';
1022 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001023 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001025 "CIFS: UNC Path does not begin "
1026 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 return 1;
1028 }
1029 } else {
1030 printk(KERN_WARNING "CIFS: UNC name too long\n");
1031 return 1;
1032 }
1033 } else if ((strnicmp(data, "domain", 3) == 0)
1034 || (strnicmp(data, "workgroup", 5) == 0)) {
1035 if (!value || !*value) {
1036 printk(KERN_WARNING "CIFS: invalid domain name\n");
1037 return 1; /* needs_arg; */
1038 }
1039 /* BB are there cases in which a comma can be valid in
1040 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001041 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 vol->domainname = value;
1043 cFYI(1, ("Domain name set"));
1044 } else {
Steve French50c2f752007-07-13 00:33:32 +00001045 printk(KERN_WARNING "CIFS: domain name too "
1046 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 return 1;
1048 }
Steve French50c2f752007-07-13 00:33:32 +00001049 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1050 if (!value || !*value) {
1051 printk(KERN_WARNING
1052 "CIFS: invalid path prefix\n");
1053 return 1; /* needs_argument */
1054 }
1055 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001056 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001057 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001058 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1059 if (vol->prepath == NULL)
1060 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001061 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001062 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001063 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001064 } else
Steve French50c2f752007-07-13 00:33:32 +00001065 strcpy(vol->prepath, value);
1066 cFYI(1, ("prefix path %s", vol->prepath));
1067 } else {
1068 printk(KERN_WARNING "CIFS: prefix too long\n");
1069 return 1;
1070 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 } else if (strnicmp(data, "iocharset", 9) == 0) {
1072 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001073 printk(KERN_WARNING "CIFS: invalid iocharset "
1074 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 return 1; /* needs_arg; */
1076 }
1077 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001078 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001080 /* if iocharset not set then load_nls_default
1081 is used by caller */
1082 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 } else {
Steve French63135e02007-07-17 17:34:02 +00001084 printk(KERN_WARNING "CIFS: iocharset name "
1085 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 return 1;
1087 }
1088 } else if (strnicmp(data, "uid", 3) == 0) {
1089 if (value && *value) {
1090 vol->linux_uid =
1091 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001092 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 }
1094 } else if (strnicmp(data, "gid", 3) == 0) {
1095 if (value && *value) {
1096 vol->linux_gid =
1097 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001098 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 }
1100 } else if (strnicmp(data, "file_mode", 4) == 0) {
1101 if (value && *value) {
1102 vol->file_mode =
1103 simple_strtoul(value, &value, 0);
1104 }
1105 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1106 if (value && *value) {
1107 vol->dir_mode =
1108 simple_strtoul(value, &value, 0);
1109 }
1110 } else if (strnicmp(data, "dirmode", 4) == 0) {
1111 if (value && *value) {
1112 vol->dir_mode =
1113 simple_strtoul(value, &value, 0);
1114 }
1115 } else if (strnicmp(data, "port", 4) == 0) {
1116 if (value && *value) {
1117 vol->port =
1118 simple_strtoul(value, &value, 0);
1119 }
1120 } else if (strnicmp(data, "rsize", 5) == 0) {
1121 if (value && *value) {
1122 vol->rsize =
1123 simple_strtoul(value, &value, 0);
1124 }
1125 } else if (strnicmp(data, "wsize", 5) == 0) {
1126 if (value && *value) {
1127 vol->wsize =
1128 simple_strtoul(value, &value, 0);
1129 }
1130 } else if (strnicmp(data, "sockopt", 5) == 0) {
1131 if (value && *value) {
1132 vol->sockopt =
1133 simple_strtoul(value, &value, 0);
1134 }
1135 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1136 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001137 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 } else {
Steve French50c2f752007-07-13 00:33:32 +00001139 memset(vol->source_rfc1001_name, 0x20, 15);
1140 for (i = 0; i < 15; i++) {
1141 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 valid in this workstation netbios name (and need
1143 special handling)? */
1144
1145 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001146 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 break;
Steve French50c2f752007-07-13 00:33:32 +00001148 else
1149 vol->source_rfc1001_name[i] =
1150 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 }
1152 /* The string has 16th byte zero still from
1153 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001154 if ((i == 15) && (value[i] != 0))
1155 printk(KERN_WARNING "CIFS: netbiosname"
1156 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001157 }
1158 } else if (strnicmp(data, "servern", 7) == 0) {
1159 /* servernetbiosname specified override *SMBSERVER */
1160 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001161 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001162 } else {
1163 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001164 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001165
Steve French50c2f752007-07-13 00:33:32 +00001166 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001167 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001168 valid in this workstation netbios name
1169 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001170
Steve French50c2f752007-07-13 00:33:32 +00001171 /* user or mount helper must uppercase
1172 the netbiosname */
1173 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001174 break;
1175 else
Steve French50c2f752007-07-13 00:33:32 +00001176 vol->target_rfc1001_name[i] =
1177 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001178 }
1179 /* The string has 16th byte zero still from
1180 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001181 if ((i == 15) && (value[i] != 0))
1182 printk(KERN_WARNING "CIFS: server net"
1183 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 }
1185 } else if (strnicmp(data, "credentials", 4) == 0) {
1186 /* ignore */
1187 } else if (strnicmp(data, "version", 3) == 0) {
1188 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001189 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 /* ignore */
1191 } else if (strnicmp(data, "rw", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001192 vol->rw = true;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001193 } else if (strnicmp(data, "noblocksend", 11) == 0) {
1194 vol->noblocksnd = 1;
1195 } else if (strnicmp(data, "noautotune", 10) == 0) {
1196 vol->noautotune = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 } else if ((strnicmp(data, "suid", 4) == 0) ||
1198 (strnicmp(data, "nosuid", 6) == 0) ||
1199 (strnicmp(data, "exec", 4) == 0) ||
1200 (strnicmp(data, "noexec", 6) == 0) ||
1201 (strnicmp(data, "nodev", 5) == 0) ||
1202 (strnicmp(data, "noauto", 6) == 0) ||
1203 (strnicmp(data, "dev", 3) == 0)) {
1204 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001205 uses these opts to set flags, and the flags are read
1206 by the kernel vfs layer before we get here (ie
1207 before read super) so there is no point trying to
1208 parse these options again and set anything and it
1209 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 continue;
1211 } else if (strnicmp(data, "ro", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001212 vol->rw = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 } else if (strnicmp(data, "hard", 4) == 0) {
1214 vol->retry = 1;
1215 } else if (strnicmp(data, "soft", 4) == 0) {
1216 vol->retry = 0;
1217 } else if (strnicmp(data, "perm", 4) == 0) {
1218 vol->noperm = 0;
1219 } else if (strnicmp(data, "noperm", 6) == 0) {
1220 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001221 } else if (strnicmp(data, "mapchars", 8) == 0) {
1222 vol->remap = 1;
1223 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1224 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001225 } else if (strnicmp(data, "sfu", 3) == 0) {
1226 vol->sfu_emul = 1;
1227 } else if (strnicmp(data, "nosfu", 5) == 0) {
1228 vol->sfu_emul = 0;
Steve French2c1b8612008-10-16 18:35:21 +00001229 } else if (strnicmp(data, "nodfs", 5) == 0) {
1230 vol->nodfs = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -07001231 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1232 vol->posix_paths = 1;
1233 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1234 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001235 } else if (strnicmp(data, "nounix", 6) == 0) {
1236 vol->no_linux_ext = 1;
1237 } else if (strnicmp(data, "nolinux", 7) == 0) {
1238 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001239 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001240 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001241 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001242 } else if (strnicmp(data, "brl", 3) == 0) {
1243 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001244 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001245 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001246 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001247 /* turn off mandatory locking in mode
1248 if remote locking is turned off since the
1249 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001250 if (vol->file_mode ==
1251 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001252 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 } else if (strnicmp(data, "setuids", 7) == 0) {
1254 vol->setuids = 1;
1255 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1256 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001257 } else if (strnicmp(data, "dynperm", 7) == 0) {
1258 vol->dynperm = true;
1259 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1260 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 } else if (strnicmp(data, "nohard", 6) == 0) {
1262 vol->retry = 0;
1263 } else if (strnicmp(data, "nosoft", 6) == 0) {
1264 vol->retry = 1;
1265 } else if (strnicmp(data, "nointr", 6) == 0) {
1266 vol->intr = 0;
1267 } else if (strnicmp(data, "intr", 4) == 0) {
1268 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001269 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001271 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001273 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001274 vol->cifs_acl = 1;
1275 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1276 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001277 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001279 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 vol->no_psx_acl = 1;
Steve French84210e92008-10-23 04:42:37 +00001281#ifdef CONFIG_CIFS_EXPERIMENTAL
1282 } else if (strnicmp(data, "locallease", 6) == 0) {
1283 vol->local_lease = 1;
1284#endif
Steve French50c2f752007-07-13 00:33:32 +00001285 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001286 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001287 } else if (strnicmp(data, "seal", 4) == 0) {
1288 /* we do not do the following in secFlags because seal
1289 is a per tree connection (mount) not a per socket
1290 or per-smb connection option in the protocol */
1291 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1292 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001293 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001295 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001297 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 if (!value || !*value) {
1299 vol->in6_addr = NULL;
1300 } else if (strnlen(value, 49) == 48) {
1301 vol->in6_addr = value;
1302 } else {
Steve French50c2f752007-07-13 00:33:32 +00001303 printk(KERN_WARNING "CIFS: ip v6 address not "
1304 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 return 1;
1306 }
1307 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001308 printk(KERN_WARNING "CIFS: Mount option noac not "
1309 "supported. Instead set "
1310 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 } else
Steve French50c2f752007-07-13 00:33:32 +00001312 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1313 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 }
1315 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001316 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001317 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1318 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 return 1;
1320 }
1321 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001322 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001323 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001325 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 if (strncmp(vol->UNC, "//", 2) == 0) {
1327 vol->UNC[0] = '\\';
1328 vol->UNC[1] = '\\';
1329 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001330 printk(KERN_WARNING "CIFS: UNC Path does not "
1331 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 return 1;
1333 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001334 value = strpbrk(vol->UNC+2, "/\\");
1335 if (value)
1336 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 } else {
1338 printk(KERN_WARNING "CIFS: UNC name too long\n");
1339 return 1;
1340 }
1341 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001342 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 vol->UNCip = &vol->UNC[2];
1344
1345 return 0;
1346}
1347
Jeff Laytone7ddee92008-11-14 13:44:38 -05001348static struct TCP_Server_Info *
1349cifs_find_tcp_session(struct sockaddr *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350{
1351 struct list_head *tmp;
Jeff Laytone7ddee92008-11-14 13:44:38 -05001352 struct TCP_Server_Info *server;
1353 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
1354 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
Jeff Laytone7ddee92008-11-14 13:44:38 -05001356 write_lock(&cifs_tcp_ses_lock);
1357 list_for_each(tmp, &cifs_tcp_ses_list) {
1358 server = list_entry(tmp, struct TCP_Server_Info,
1359 tcp_ses_list);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001360 /*
1361 * the demux thread can exit on its own while still in CifsNew
1362 * so don't accept any sockets in that state. Since the
1363 * tcpStatus never changes back to CifsNew it's safe to check
1364 * for this without a lock.
1365 */
1366 if (server->tcpStatus == CifsNew)
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001367 continue;
Steve French50c2f752007-07-13 00:33:32 +00001368
Jeff Laytone7ddee92008-11-14 13:44:38 -05001369 if (addr->sa_family == AF_INET &&
1370 (addr4->sin_addr.s_addr !=
1371 server->addr.sockAddr.sin_addr.s_addr))
1372 continue;
1373 else if (addr->sa_family == AF_INET6 &&
1374 memcmp(&server->addr.sockAddr6.sin6_addr,
1375 &addr6->sin6_addr, sizeof(addr6->sin6_addr)))
1376 continue;
Steve French50c2f752007-07-13 00:33:32 +00001377
Jeff Laytone7ddee92008-11-14 13:44:38 -05001378 ++server->srv_count;
1379 write_unlock(&cifs_tcp_ses_lock);
Steve Frenchd82c2df2008-11-15 00:07:26 +00001380 cFYI(1, ("Existing tcp session with server found"));
Jeff Laytone7ddee92008-11-14 13:44:38 -05001381 return server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 }
Jeff Laytone7ddee92008-11-14 13:44:38 -05001383 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 return NULL;
1385}
1386
Jeff Layton14fbf502008-11-14 13:53:46 -05001387static void
Jeff Laytone7ddee92008-11-14 13:44:38 -05001388cifs_put_tcp_session(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001390 struct task_struct *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
Jeff Laytone7ddee92008-11-14 13:44:38 -05001392 write_lock(&cifs_tcp_ses_lock);
1393 if (--server->srv_count > 0) {
1394 write_unlock(&cifs_tcp_ses_lock);
1395 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001397
Jeff Laytone7ddee92008-11-14 13:44:38 -05001398 list_del_init(&server->tcp_ses_list);
1399 write_unlock(&cifs_tcp_ses_lock);
1400
1401 spin_lock(&GlobalMid_Lock);
1402 server->tcpStatus = CifsExiting;
1403 spin_unlock(&GlobalMid_Lock);
1404
1405 task = xchg(&server->tsk, NULL);
1406 if (task)
1407 force_sig(SIGKILL, task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408}
1409
Jeff Layton63c038c2008-12-01 18:41:46 -05001410static struct TCP_Server_Info *
1411cifs_get_tcp_session(struct smb_vol *volume_info)
1412{
1413 struct TCP_Server_Info *tcp_ses = NULL;
1414 struct sockaddr addr;
1415 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
1416 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
1417 int rc;
1418
1419 memset(&addr, 0, sizeof(struct sockaddr));
1420
1421 if (volume_info->UNCip && volume_info->UNC) {
1422 rc = cifs_inet_pton(AF_INET, volume_info->UNCip,
1423 &sin_server->sin_addr.s_addr);
1424
1425 if (rc <= 0) {
1426 /* not ipv4 address, try ipv6 */
1427 rc = cifs_inet_pton(AF_INET6, volume_info->UNCip,
1428 &sin_server6->sin6_addr.in6_u);
1429 if (rc > 0)
1430 addr.sa_family = AF_INET6;
1431 } else {
1432 addr.sa_family = AF_INET;
1433 }
1434
1435 if (rc <= 0) {
1436 /* we failed translating address */
1437 rc = -EINVAL;
1438 goto out_err;
1439 }
1440
1441 cFYI(1, ("UNC: %s ip: %s", volume_info->UNC,
1442 volume_info->UNCip));
1443 } else if (volume_info->UNCip) {
1444 /* BB using ip addr as tcp_ses name to connect to the
1445 DFS root below */
1446 cERROR(1, ("Connecting to DFS root not implemented yet"));
1447 rc = -EINVAL;
1448 goto out_err;
1449 } else /* which tcp_sess DFS root would we conect to */ {
1450 cERROR(1,
1451 ("CIFS mount error: No UNC path (e.g. -o "
1452 "unc=//192.168.1.100/public) specified"));
1453 rc = -EINVAL;
1454 goto out_err;
1455 }
1456
1457 /* see if we already have a matching tcp_ses */
1458 tcp_ses = cifs_find_tcp_session(&addr);
1459 if (tcp_ses)
1460 return tcp_ses;
1461
1462 tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1463 if (!tcp_ses) {
1464 rc = -ENOMEM;
1465 goto out_err;
1466 }
1467
1468 tcp_ses->hostname = extract_hostname(volume_info->UNC);
1469 if (IS_ERR(tcp_ses->hostname)) {
1470 rc = PTR_ERR(tcp_ses->hostname);
1471 goto out_err;
1472 }
1473
1474 tcp_ses->noblocksnd = volume_info->noblocksnd;
1475 tcp_ses->noautotune = volume_info->noautotune;
1476 atomic_set(&tcp_ses->inFlight, 0);
1477 init_waitqueue_head(&tcp_ses->response_q);
1478 init_waitqueue_head(&tcp_ses->request_q);
1479 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
1480 mutex_init(&tcp_ses->srv_mutex);
1481 memcpy(tcp_ses->workstation_RFC1001_name,
1482 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1483 memcpy(tcp_ses->server_RFC1001_name,
1484 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1485 tcp_ses->sequence_number = 0;
1486 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
1487 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
1488
1489 /*
1490 * at this point we are the only ones with the pointer
1491 * to the struct since the kernel thread not created yet
1492 * no need to spinlock this init of tcpStatus or srv_count
1493 */
1494 tcp_ses->tcpStatus = CifsNew;
1495 ++tcp_ses->srv_count;
1496
1497 if (addr.sa_family == AF_INET6) {
1498 cFYI(1, ("attempting ipv6 connect"));
1499 /* BB should we allow ipv6 on port 139? */
1500 /* other OS never observed in Wild doing 139 with v6 */
1501 memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
1502 sizeof(struct sockaddr_in6));
1503 sin_server6->sin6_port = htons(volume_info->port);
1504 rc = ipv6_connect(sin_server6, &tcp_ses->ssocket,
1505 volume_info->noblocksnd);
1506 } else {
1507 memcpy(&tcp_ses->addr.sockAddr, sin_server,
1508 sizeof(struct sockaddr_in));
1509 sin_server->sin_port = htons(volume_info->port);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001510 rc = ipv4_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001511 }
1512 if (rc < 0) {
1513 cERROR(1, ("Error connecting to socket. Aborting operation"));
1514 goto out_err;
1515 }
1516
1517 /*
1518 * since we're in a cifs function already, we know that
1519 * this will succeed. No need for try_module_get().
1520 */
1521 __module_get(THIS_MODULE);
1522 tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
1523 tcp_ses, "cifsd");
1524 if (IS_ERR(tcp_ses->tsk)) {
1525 rc = PTR_ERR(tcp_ses->tsk);
1526 cERROR(1, ("error %d create cifsd thread", rc));
1527 module_put(THIS_MODULE);
1528 goto out_err;
1529 }
1530
1531 /* thread spawned, put it on the list */
1532 write_lock(&cifs_tcp_ses_lock);
1533 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
1534 write_unlock(&cifs_tcp_ses_lock);
1535
1536 return tcp_ses;
1537
1538out_err:
1539 if (tcp_ses) {
1540 kfree(tcp_ses->hostname);
1541 if (tcp_ses->ssocket)
1542 sock_release(tcp_ses->ssocket);
1543 kfree(tcp_ses);
1544 }
1545 return ERR_PTR(rc);
1546}
1547
Jeff Layton14fbf502008-11-14 13:53:46 -05001548static struct cifsSesInfo *
1549cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
1550{
1551 struct list_head *tmp;
1552 struct cifsSesInfo *ses;
1553
1554 write_lock(&cifs_tcp_ses_lock);
1555 list_for_each(tmp, &server->smb_ses_list) {
1556 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
1557 if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
1558 continue;
1559
1560 ++ses->ses_count;
1561 write_unlock(&cifs_tcp_ses_lock);
1562 return ses;
1563 }
1564 write_unlock(&cifs_tcp_ses_lock);
1565 return NULL;
1566}
1567
1568static void
1569cifs_put_smb_ses(struct cifsSesInfo *ses)
1570{
1571 int xid;
1572 struct TCP_Server_Info *server = ses->server;
1573
1574 write_lock(&cifs_tcp_ses_lock);
1575 if (--ses->ses_count > 0) {
1576 write_unlock(&cifs_tcp_ses_lock);
1577 return;
1578 }
1579
1580 list_del_init(&ses->smb_ses_list);
1581 write_unlock(&cifs_tcp_ses_lock);
1582
1583 if (ses->status == CifsGood) {
1584 xid = GetXid();
1585 CIFSSMBLogoff(xid, ses);
1586 _FreeXid(xid);
1587 }
1588 sesInfoFree(ses);
1589 cifs_put_tcp_session(server);
1590}
1591
Jeff Laytonf1987b42008-11-15 11:12:47 -05001592static struct cifsTconInfo *
1593cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
1594{
1595 struct list_head *tmp;
1596 struct cifsTconInfo *tcon;
1597
1598 write_lock(&cifs_tcp_ses_lock);
1599 list_for_each(tmp, &ses->tcon_list) {
1600 tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
1601 if (tcon->tidStatus == CifsExiting)
1602 continue;
1603 if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
1604 continue;
1605
1606 ++tcon->tc_count;
1607 write_unlock(&cifs_tcp_ses_lock);
1608 return tcon;
1609 }
1610 write_unlock(&cifs_tcp_ses_lock);
1611 return NULL;
1612}
1613
1614static void
1615cifs_put_tcon(struct cifsTconInfo *tcon)
1616{
1617 int xid;
1618 struct cifsSesInfo *ses = tcon->ses;
1619
1620 write_lock(&cifs_tcp_ses_lock);
1621 if (--tcon->tc_count > 0) {
1622 write_unlock(&cifs_tcp_ses_lock);
1623 return;
1624 }
1625
1626 list_del_init(&tcon->tcon_list);
1627 write_unlock(&cifs_tcp_ses_lock);
1628
1629 xid = GetXid();
1630 CIFSSMBTDis(xid, tcon);
1631 _FreeXid(xid);
1632
1633 DeleteTconOplockQEntries(tcon);
1634 tconInfoFree(tcon);
1635 cifs_put_smb_ses(ses);
1636}
1637
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638int
Steve French50c2f752007-07-13 00:33:32 +00001639get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1640 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001641 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642{
1643 char *temp_unc;
1644 int rc = 0;
1645
1646 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001647 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
1649 if (pSesInfo->ipc_tid == 0) {
1650 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001651 strnlen(pSesInfo->serverName,
1652 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 + 1 + 4 /* slash IPC$ */ + 2,
1654 GFP_KERNEL);
1655 if (temp_unc == NULL)
1656 return -ENOMEM;
1657 temp_unc[0] = '\\';
1658 temp_unc[1] = '\\';
1659 strcpy(temp_unc + 2, pSesInfo->serverName);
1660 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1661 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1662 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001663 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 kfree(temp_unc);
1665 }
1666 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00001667 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001668 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00001669 /* BB map targetUNCs to dfs_info3 structures, here or
1670 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
1672 return rc;
1673}
1674
Jeff Layton09e50d52008-07-23 10:11:19 -04001675#ifdef CONFIG_DEBUG_LOCK_ALLOC
1676static struct lock_class_key cifs_key[2];
1677static struct lock_class_key cifs_slock_key[2];
1678
1679static inline void
1680cifs_reclassify_socket4(struct socket *sock)
1681{
1682 struct sock *sk = sock->sk;
1683 BUG_ON(sock_owned_by_user(sk));
1684 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
1685 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
1686}
1687
1688static inline void
1689cifs_reclassify_socket6(struct socket *sock)
1690{
1691 struct sock *sk = sock->sk;
1692 BUG_ON(sock_owned_by_user(sk));
1693 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
1694 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
1695}
1696#else
1697static inline void
1698cifs_reclassify_socket4(struct socket *sock)
1699{
1700}
1701
1702static inline void
1703cifs_reclassify_socket6(struct socket *sock)
1704{
1705}
1706#endif
1707
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001709static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710{
Steve French50c2f752007-07-13 00:33:32 +00001711 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712
Steve French50c2f752007-07-13 00:33:32 +00001713 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 /* mask a nibble at a time and encode */
1715 target[j] = 'A' + (0x0F & (source[i] >> 4));
1716 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001717 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 }
1719
1720}
1721
1722
1723static int
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001724ipv4_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725{
1726 int rc = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001727 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 __be16 orig_port = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001729 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001731 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001732 rc = sock_create_kern(PF_INET, SOCK_STREAM,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001733 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001735 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001738
1739 /* BB other socket options to set KEEPALIVE, NODELAY? */
1740 cFYI(1, ("Socket created"));
1741 server->ssocket = socket;
1742 socket->sk->sk_allocation = GFP_NOFS;
1743 cifs_reclassify_socket4(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 }
1745
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001746 /* user overrode default port */
1747 if (server->addr.sockAddr.sin_port) {
1748 rc = socket->ops->connect(socket, (struct sockaddr *)
1749 &server->addr.sockAddr,
1750 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001752 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00001753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001755 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001756 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 later if fall back ports fail this time */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001758 orig_port = server->addr.sockAddr.sin_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
1760 /* do not retry on the same port we just failed on */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001761 if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) {
1762 server->addr.sockAddr.sin_port = htons(CIFS_PORT);
1763 rc = socket->ops->connect(socket,
1764 (struct sockaddr *)
1765 &server->addr.sockAddr,
1766 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001768 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 }
1770 }
1771 if (!connected) {
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001772 server->addr.sockAddr.sin_port = htons(RFC1001_PORT);
1773 rc = socket->ops->connect(socket, (struct sockaddr *)
1774 &server->addr.sockAddr,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001775 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001776 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001777 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 }
1779
1780 /* give up here - unless we want to retry on different
1781 protocol families some day */
1782 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001783 if (orig_port)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001784 server->addr.sockAddr.sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001785 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001786 sock_release(socket);
1787 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 return rc;
1789 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001790
1791
1792 /*
1793 * Eventually check for other socket options to change from
1794 * the default. sock_setsockopt not used because it expects
1795 * user space buffer
1796 */
1797 socket->sk->sk_rcvtimeo = 7 * HZ;
1798 socket->sk->sk_sndtimeo = 3 * HZ;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001799
Steve Frenchb387eae2005-10-10 14:21:15 -07001800 /* make the bufsizes depend on wsize/rsize and max requests */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001801 if (server->noautotune) {
1802 if (socket->sk->sk_sndbuf < (200 * 1024))
1803 socket->sk->sk_sndbuf = 200 * 1024;
1804 if (socket->sk->sk_rcvbuf < (140 * 1024))
1805 socket->sk->sk_rcvbuf = 140 * 1024;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001808 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1809 socket->sk->sk_sndbuf,
1810 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo));
1811
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 /* send RFC1001 sessinit */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001813 if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001815 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001817 struct rfc1002_session_packet *ses_init_buf;
1818 struct smb_hdr *smb_buf;
1819 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1820 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001821 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 ses_init_buf->trailer.session_req.called_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001823 if (server->server_RFC1001_name &&
1824 server->server_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05001825 rfc1002mangle(ses_init_buf->trailer.
1826 session_req.called_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001827 server->server_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05001828 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001829 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05001830 rfc1002mangle(ses_init_buf->trailer.
1831 session_req.called_name,
1832 DEFAULT_CIFS_CALLED_NAME,
1833 RFC1001_NAME_LEN_WITH_NULL);
Steve Frencha10faeb22005-08-22 21:38:31 -07001834
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 ses_init_buf->trailer.session_req.calling_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001836
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 /* calling name ends in null (byte 16) from old smb
1838 convention. */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001839 if (server->workstation_RFC1001_name &&
1840 server->workstation_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05001841 rfc1002mangle(ses_init_buf->trailer.
1842 session_req.calling_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001843 server->workstation_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05001844 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001845 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05001846 rfc1002mangle(ses_init_buf->trailer.
1847 session_req.calling_name,
1848 "LINUX_CIFS_CLNT",
1849 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001850
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 ses_init_buf->trailer.session_req.scope1 = 0;
1852 ses_init_buf->trailer.session_req.scope2 = 0;
1853 smb_buf = (struct smb_hdr *)ses_init_buf;
1854 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1855 smb_buf->smb_buf_length = 0x81000044;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001856 rc = smb_send(socket, smb_buf, 0x44,
1857 (struct sockaddr *) &server->addr.sockAddr,
1858 server->noblocksnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001860 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001861 requires very short break before negprot
1862 presumably because not expecting negprot
1863 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001864 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001865 complicating the code and causes no
1866 significant slowing down on mount
1867 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 }
Steve French50c2f752007-07-13 00:33:32 +00001869 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001871
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 }
Steve French50c2f752007-07-13 00:33:32 +00001873
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 return rc;
1875}
1876
1877static int
Steve Frenchedf1ae42008-10-29 00:47:57 +00001878ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket,
1879 bool noblocksnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880{
1881 int rc = 0;
1882 int connected = 0;
1883 __be16 orig_port = 0;
1884
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001885 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001886 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1887 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001889 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 *csocket = NULL;
1891 return rc;
1892 } else {
1893 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001894 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 (*csocket)->sk->sk_allocation = GFP_NOFS;
Jeff Layton09e50d52008-07-23 10:11:19 -04001896 cifs_reclassify_socket6(*csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 }
1898 }
1899
1900 psin_server->sin6_family = AF_INET6;
1901
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001902 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 rc = (*csocket)->ops->connect(*csocket,
1904 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001905 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 if (rc >= 0)
1907 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001908 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001910 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001911 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 later if fall back ports fail this time */
1913
1914 orig_port = psin_server->sin6_port;
1915 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001916 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 psin_server->sin6_port = htons(CIFS_PORT);
1918
1919 rc = (*csocket)->ops->connect(*csocket,
1920 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001921 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 if (rc >= 0)
1923 connected = 1;
1924 }
1925 }
1926 if (!connected) {
1927 psin_server->sin6_port = htons(RFC1001_PORT);
1928 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001929 psin_server, sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001930 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 connected = 1;
1932 }
1933
1934 /* give up here - unless we want to retry on different
1935 protocol families some day */
1936 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001937 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001939 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 sock_release(*csocket);
1941 *csocket = NULL;
1942 return rc;
1943 }
Steve French50c2f752007-07-13 00:33:32 +00001944 /* Eventually check for other socket options to change from
1945 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 user space buffer */
1947 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001948 if (!noblocksnd)
1949 (*csocket)->sk->sk_sndtimeo = 3 * HZ;
1950
Steve French50c2f752007-07-13 00:33:32 +00001951
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 return rc;
1953}
1954
Steve French50c2f752007-07-13 00:33:32 +00001955void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1956 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001957{
1958 /* if we are reconnecting then should we check to see if
1959 * any requested capabilities changed locally e.g. via
1960 * remount but we can not do much about it here
1961 * if they have (even if we could detect it by the following)
1962 * Perhaps we could add a backpointer to array of sb from tcon
1963 * or if we change to make all sb to same share the same
1964 * sb as NFS - then we only have one backpointer to sb.
1965 * What if we wanted to mount the server share twice once with
1966 * and once without posixacls or posix paths? */
1967 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001968
Steve Frenchc18c8422007-07-18 23:21:09 +00001969 if (vol_info && vol_info->no_linux_ext) {
1970 tcon->fsUnixInfo.Capability = 0;
1971 tcon->unix_ext = 0; /* Unix Extensions disabled */
1972 cFYI(1, ("Linux protocol extensions disabled"));
1973 return;
1974 } else if (vol_info)
1975 tcon->unix_ext = 1; /* Unix Extensions supported */
1976
1977 if (tcon->unix_ext == 0) {
1978 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1979 return;
1980 }
Steve French50c2f752007-07-13 00:33:32 +00001981
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001982 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001983 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001984
Steve French8af18972007-02-14 04:42:51 +00001985 /* check for reconnect case in which we do not
1986 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001987 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001988 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001989 originally at mount time */
1990 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1991 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001992 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1993 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
1994 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00001995 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001996 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1997 cERROR(1, ("possible reconnect error"));
1998 cERROR(1,
1999 ("server disabled POSIX path support"));
2000 }
Steve French8af18972007-02-14 04:42:51 +00002001 }
Steve French50c2f752007-07-13 00:33:32 +00002002
Steve French8af18972007-02-14 04:42:51 +00002003 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00002004 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00002005 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002006 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002007 cFYI(1, ("negotiated posix acl support"));
2008 if (sb)
Steve French8af18972007-02-14 04:42:51 +00002009 sb->s_flags |= MS_POSIXACL;
2010 }
2011
Steve French75865f8c2007-06-24 18:30:48 +00002012 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00002013 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002014 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002015 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00002016 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00002017 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00002018 CIFS_MOUNT_POSIX_PATHS;
2019 }
Steve French50c2f752007-07-13 00:33:32 +00002020
Steve French984acfe2007-04-26 16:42:50 +00002021 /* We might be setting the path sep back to a different
2022 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00002023 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00002024 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00002025 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00002026
2027 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
2028 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
2029 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00002030 cFYI(DBG2,
2031 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00002032 }
2033 }
Steve French50c2f752007-07-13 00:33:32 +00002034
2035
2036 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00002037#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00002038 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002039 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002040 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002041 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002042 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002043 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002044 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002045 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002046 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002047 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002048 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002049 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002050 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002051 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00002052#endif /* CIFS_DEBUG2 */
2053 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00002054 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00002055 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00002056 } else
Steve French5a44b312007-09-20 15:16:24 +00002057 cERROR(1, ("Negotiating Unix capabilities "
2058 "with the server failed. Consider "
2059 "mounting with the Unix Extensions\n"
2060 "disabled, if problems are found, "
2061 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00002062 "option."));
Steve French5a44b312007-09-20 15:16:24 +00002063
Steve French8af18972007-02-14 04:42:51 +00002064 }
2065 }
2066}
2067
Steve French03a143c2008-02-14 06:38:30 +00002068static void
2069convert_delimiter(char *path, char delim)
2070{
2071 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002072 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00002073
2074 if (path == NULL)
2075 return;
2076
Steve French582d21e2008-05-13 04:54:12 +00002077 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002078 old_delim = '\\';
2079 else
2080 old_delim = '/';
2081
Steve French03a143c2008-02-14 06:38:30 +00002082 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002083 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00002084 path[i] = delim;
2085 }
2086}
2087
Steve French3b795212008-11-13 19:45:32 +00002088static void setup_cifs_sb(struct smb_vol *pvolume_info,
2089 struct cifs_sb_info *cifs_sb)
2090{
2091 if (pvolume_info->rsize > CIFSMaxBufSize) {
2092 cERROR(1, ("rsize %d too large, using MaxBufSize",
2093 pvolume_info->rsize));
2094 cifs_sb->rsize = CIFSMaxBufSize;
2095 } else if ((pvolume_info->rsize) &&
2096 (pvolume_info->rsize <= CIFSMaxBufSize))
2097 cifs_sb->rsize = pvolume_info->rsize;
2098 else /* default */
2099 cifs_sb->rsize = CIFSMaxBufSize;
2100
2101 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
2102 cERROR(1, ("wsize %d too large, using 4096 instead",
2103 pvolume_info->wsize));
2104 cifs_sb->wsize = 4096;
2105 } else if (pvolume_info->wsize)
2106 cifs_sb->wsize = pvolume_info->wsize;
2107 else
2108 cifs_sb->wsize = min_t(const int,
2109 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2110 127*1024);
2111 /* old default of CIFSMaxBufSize was too small now
2112 that SMB Write2 can send multiple pages in kvec.
2113 RFC1001 does not describe what happens when frame
2114 bigger than 128K is sent so use that as max in
2115 conjunction with 52K kvec constraint on arch with 4K
2116 page size */
2117
2118 if (cifs_sb->rsize < 2048) {
2119 cifs_sb->rsize = 2048;
2120 /* Windows ME may prefer this */
2121 cFYI(1, ("readsize set to minimum: 2048"));
2122 }
2123 /* calculate prepath */
2124 cifs_sb->prepath = pvolume_info->prepath;
2125 if (cifs_sb->prepath) {
2126 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2127 /* we can not convert the / to \ in the path
2128 separators in the prefixpath yet because we do not
2129 know (until reset_cifs_unix_caps is called later)
2130 whether POSIX PATH CAP is available. We normalize
2131 the / to \ after reset_cifs_unix_caps is called */
2132 pvolume_info->prepath = NULL;
2133 } else
2134 cifs_sb->prepathlen = 0;
2135 cifs_sb->mnt_uid = pvolume_info->linux_uid;
2136 cifs_sb->mnt_gid = pvolume_info->linux_gid;
2137 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
2138 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
2139 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2140 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
2141
2142 if (pvolume_info->noperm)
2143 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
2144 if (pvolume_info->setuids)
2145 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
2146 if (pvolume_info->server_ino)
2147 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
2148 if (pvolume_info->remap)
2149 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
2150 if (pvolume_info->no_xattr)
2151 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
2152 if (pvolume_info->sfu_emul)
2153 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
2154 if (pvolume_info->nobrl)
2155 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
2156 if (pvolume_info->cifs_acl)
2157 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2158 if (pvolume_info->override_uid)
2159 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2160 if (pvolume_info->override_gid)
2161 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2162 if (pvolume_info->dynperm)
2163 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
2164 if (pvolume_info->direct_io) {
2165 cFYI(1, ("mounting share using direct i/o"));
2166 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2167 }
2168
2169 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
2170 cERROR(1, ("mount option dynperm ignored if cifsacl "
2171 "mount option supported"));
2172}
2173
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174int
2175cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2176 char *mount_data, const char *devname)
2177{
2178 int rc = 0;
2179 int xid;
Jeff Layton7586b762008-12-01 18:41:49 -05002180 struct smb_vol *volume_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 struct cifsSesInfo *pSesInfo = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 struct cifsTconInfo *tcon = NULL;
2183 struct TCP_Server_Info *srvTcp = NULL;
2184
2185 xid = GetXid();
2186
Jeff Layton7586b762008-12-01 18:41:49 -05002187 volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
2188 if (!volume_info) {
2189 rc = -ENOMEM;
2190 goto out;
2191 }
Steve French50c2f752007-07-13 00:33:32 +00002192
Jeff Layton7586b762008-12-01 18:41:49 -05002193 if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002194 rc = -EINVAL;
2195 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 }
2197
Jeff Layton7586b762008-12-01 18:41:49 -05002198 if (volume_info->nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002199 cFYI(1, ("null user"));
Jeff Layton7586b762008-12-01 18:41:49 -05002200 volume_info->username = "";
2201 } else if (volume_info->username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 /* BB fixme parse for domain name here */
Jeff Layton7586b762008-12-01 18:41:49 -05002203 cFYI(1, ("Username: %s", volume_info->username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08002205 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00002206 /* In userspace mount helper we can get user name from alternate
2207 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002208 rc = -EINVAL;
2209 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 }
2211
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
2213 /* this is needed for ASCII cp to Unicode converts */
Jeff Layton7586b762008-12-01 18:41:49 -05002214 if (volume_info->iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 cifs_sb->local_nls = load_nls_default();
2216 /* load_nls_default can not return null */
2217 } else {
Jeff Layton7586b762008-12-01 18:41:49 -05002218 cifs_sb->local_nls = load_nls(volume_info->iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002219 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002220 cERROR(1, ("CIFS mount error: iocharset %s not found",
Jeff Layton7586b762008-12-01 18:41:49 -05002221 volume_info->iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002222 rc = -ELIBACC;
2223 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 }
2225 }
2226
Jeff Layton63c038c2008-12-01 18:41:46 -05002227 /* get a reference to a tcp session */
Jeff Layton7586b762008-12-01 18:41:49 -05002228 srvTcp = cifs_get_tcp_session(volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05002229 if (IS_ERR(srvTcp)) {
2230 rc = PTR_ERR(srvTcp);
2231 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 }
2233
Jeff Layton7586b762008-12-01 18:41:49 -05002234 pSesInfo = cifs_find_smb_ses(srvTcp, volume_info->username);
Jeff Layton14fbf502008-11-14 13:53:46 -05002235 if (pSesInfo) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002236 cFYI(1, ("Existing smb sess found (status=%d)",
2237 pSesInfo->status));
Jeff Layton14fbf502008-11-14 13:53:46 -05002238 /*
2239 * The existing SMB session already has a reference to srvTcp,
2240 * so we can put back the extra one we got before
2241 */
2242 cifs_put_tcp_session(srvTcp);
2243
Steve French88e7d702008-01-03 17:37:09 +00002244 down(&pSesInfo->sesSem);
Steve French3b795212008-11-13 19:45:32 +00002245 if (pSesInfo->need_reconnect) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002246 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002247 rc = cifs_setup_session(xid, pSesInfo,
2248 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002249 }
Steve French88e7d702008-01-03 17:37:09 +00002250 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002252 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 pSesInfo = sesInfoAlloc();
Jeff Layton14fbf502008-11-14 13:53:46 -05002254 if (pSesInfo == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 rc = -ENOMEM;
Jeff Layton14fbf502008-11-14 13:53:46 -05002256 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 }
2258
Jeff Layton14fbf502008-11-14 13:53:46 -05002259 /* new SMB session uses our srvTcp ref */
2260 pSesInfo->server = srvTcp;
Jeff Layton63c038c2008-12-01 18:41:46 -05002261 if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6)
Jeff Layton8ecaf672008-12-01 15:23:50 -05002262 sprintf(pSesInfo->serverName, NIP6_FMT,
Jeff Layton63c038c2008-12-01 18:41:46 -05002263 NIP6(srvTcp->addr.sockAddr6.sin6_addr));
Jeff Layton8ecaf672008-12-01 15:23:50 -05002264 else
2265 sprintf(pSesInfo->serverName, NIPQUAD_FMT,
Jeff Layton63c038c2008-12-01 18:41:46 -05002266 NIPQUAD(srvTcp->addr.sockAddr.sin_addr.s_addr));
Jeff Layton14fbf502008-11-14 13:53:46 -05002267
2268 write_lock(&cifs_tcp_ses_lock);
2269 list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
2270 write_unlock(&cifs_tcp_ses_lock);
2271
Jeff Layton7586b762008-12-01 18:41:49 -05002272 /* volume_info->password freed at unmount */
2273 if (volume_info->password) {
2274 pSesInfo->password = volume_info->password;
Jeff Layton14fbf502008-11-14 13:53:46 -05002275 /* set to NULL to prevent freeing on exit */
Jeff Layton7586b762008-12-01 18:41:49 -05002276 volume_info->password = NULL;
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002277 }
Jeff Layton7586b762008-12-01 18:41:49 -05002278 if (volume_info->username)
2279 strncpy(pSesInfo->userName, volume_info->username,
Jeff Layton14fbf502008-11-14 13:53:46 -05002280 MAX_USERNAME_SIZE);
Jeff Layton7586b762008-12-01 18:41:49 -05002281 if (volume_info->domainname) {
2282 int len = strlen(volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002283 pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
2284 if (pSesInfo->domainName)
2285 strcpy(pSesInfo->domainName,
Jeff Layton7586b762008-12-01 18:41:49 -05002286 volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002287 }
Jeff Layton7586b762008-12-01 18:41:49 -05002288 pSesInfo->linux_uid = volume_info->linux_uid;
2289 pSesInfo->overrideSecFlg = volume_info->secFlg;
Jeff Layton14fbf502008-11-14 13:53:46 -05002290 down(&pSesInfo->sesSem);
2291
2292 /* BB FIXME need to pass vol->secFlgs BB */
2293 rc = cifs_setup_session(xid, pSesInfo,
2294 cifs_sb->local_nls);
2295 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 }
Steve French50c2f752007-07-13 00:33:32 +00002297
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 /* search for existing tcon to this server share */
2299 if (!rc) {
Jeff Layton7586b762008-12-01 18:41:49 -05002300 setup_cifs_sb(volume_info, cifs_sb);
Steve French27adb442008-05-23 19:43:29 +00002301
Jeff Layton7586b762008-12-01 18:41:49 -05002302 tcon = cifs_find_tcon(pSesInfo, volume_info->UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002304 cFYI(1, ("Found match on UNC path"));
Jeff Laytonf1987b42008-11-15 11:12:47 -05002305 /* existing tcon already has a reference */
2306 cifs_put_smb_ses(pSesInfo);
Jeff Layton7586b762008-12-01 18:41:49 -05002307 if (tcon->seal != volume_info->seal)
Steve Frenchab3f9922008-11-17 16:03:00 +00002308 cERROR(1, ("transport encryption setting "
2309 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 } else {
2311 tcon = tconInfoAlloc();
Steve French3b795212008-11-13 19:45:32 +00002312 if (tcon == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 rc = -ENOMEM;
Steve French3b795212008-11-13 19:45:32 +00002314 goto mount_fail_check;
2315 }
Steve Frenchab3f9922008-11-17 16:03:00 +00002316 tcon->ses = pSesInfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
Steve French3b795212008-11-13 19:45:32 +00002318 /* check for null share name ie connect to dfs root */
Jeff Layton7586b762008-12-01 18:41:49 -05002319 if ((strchr(volume_info->UNC + 3, '\\') == NULL)
2320 && (strchr(volume_info->UNC + 3, '/') == NULL)) {
Steve French3b795212008-11-13 19:45:32 +00002321 /* rc = connect_to_dfs_path(...) */
2322 cFYI(1, ("DFS root not supported"));
2323 rc = -ENODEV;
2324 goto mount_fail_check;
2325 } else {
2326 /* BB Do we need to wrap sesSem around
2327 * this TCon call and Unix SetFS as
2328 * we do on SessSetup and reconnect? */
Jeff Layton7586b762008-12-01 18:41:49 -05002329 rc = CIFSTCon(xid, pSesInfo, volume_info->UNC,
Steve French3b795212008-11-13 19:45:32 +00002330 tcon, cifs_sb->local_nls);
2331 cFYI(1, ("CIFS Tcon rc = %d", rc));
Jeff Layton7586b762008-12-01 18:41:49 -05002332 if (volume_info->nodfs) {
Steve French3b795212008-11-13 19:45:32 +00002333 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2334 cFYI(1, ("DFS disabled (%d)",
2335 tcon->Flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 }
2337 }
Jeff Layton14fbf502008-11-14 13:53:46 -05002338 if (rc)
Steve French3b795212008-11-13 19:45:32 +00002339 goto mount_fail_check;
Jeff Layton7586b762008-12-01 18:41:49 -05002340 tcon->seal = volume_info->seal;
Jeff Laytonf1987b42008-11-15 11:12:47 -05002341 write_lock(&cifs_tcp_ses_lock);
2342 list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
2343 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 }
Steve French3b795212008-11-13 19:45:32 +00002345
2346 /* we can have only one retry value for a connection
2347 to a share so for resources mounted more than once
2348 to the same server share the last value passed in
2349 for the retry flag is used */
Jeff Layton7586b762008-12-01 18:41:49 -05002350 tcon->retry = volume_info->retry;
2351 tcon->nocase = volume_info->nocase;
2352 tcon->local_lease = volume_info->local_lease;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 }
Steve French4523cc32007-04-30 20:13:06 +00002354 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2356 sb->s_maxbytes = (u64) 1 << 63;
2357 } else
2358 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2359 }
2360
Steve French8af18972007-02-14 04:42:51 +00002361 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 sb->s_time_gran = 100;
2363
Steve French3b795212008-11-13 19:45:32 +00002364mount_fail_check:
Jeff Layton14fbf502008-11-14 13:53:46 -05002365 /* on error free sesinfo and tcon struct if needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 if (rc) {
Jeff Laytone7ddee92008-11-14 13:44:38 -05002367 /* If find_unc succeeded then rc == 0 so we can not end */
2368 /* up accidently freeing someone elses tcon struct */
2369 if (tcon)
Jeff Laytonf1987b42008-11-15 11:12:47 -05002370 cifs_put_tcon(tcon);
2371 else if (pSesInfo)
Jeff Layton14fbf502008-11-14 13:53:46 -05002372 cifs_put_smb_ses(pSesInfo);
2373 else
2374 cifs_put_tcp_session(srvTcp);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002375 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 }
Steve Frenchd82c2df2008-11-15 00:07:26 +00002377 cifs_sb->tcon = tcon;
Steve Frenchd82c2df2008-11-15 00:07:26 +00002378
2379 /* do not care if following two calls succeed - informational */
2380 if (!tcon->ipc) {
2381 CIFSSMBQFSDeviceInfo(xid, tcon);
2382 CIFSSMBQFSAttributeInfo(xid, tcon);
2383 }
2384
2385 /* tell server which Unix caps we support */
2386 if (tcon->ses->capabilities & CAP_UNIX)
2387 /* reset of caps checks mount to see if unix extensions
2388 disabled for just this mount */
Jeff Layton7586b762008-12-01 18:41:49 -05002389 reset_cifs_unix_caps(xid, tcon, sb, volume_info);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002390 else
2391 tcon->unix_ext = 0; /* server does not support them */
2392
2393 /* convert forward to back slashes in prepath here if needed */
2394 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2395 convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
2396
2397 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
2398 cifs_sb->rsize = 1024 * 127;
2399 cFYI(DBG2, ("no very large read support, rsize now 127K"));
2400 }
2401 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2402 cifs_sb->wsize = min(cifs_sb->wsize,
2403 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2404 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2405 cifs_sb->rsize = min(cifs_sb->rsize,
2406 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
Jeff Layton7586b762008-12-01 18:41:49 -05002408 /* volume_info->password is freed above when existing session found
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 (in which case it is not needed anymore) but when new sesion is created
2410 the password ptr is put in the new session structure (in which case the
2411 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002412out:
2413 /* zero out password before freeing */
Jeff Layton7586b762008-12-01 18:41:49 -05002414 if (volume_info) {
2415 if (volume_info->password != NULL) {
2416 memset(volume_info->password, 0,
2417 strlen(volume_info->password));
2418 kfree(volume_info->password);
2419 }
2420 kfree(volume_info->UNC);
2421 kfree(volume_info->prepath);
2422 kfree(volume_info);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 FreeXid(xid);
2425 return rc;
2426}
2427
2428static int
2429CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002430 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 const struct nls_table *nls_codepage)
2432{
2433 struct smb_hdr *smb_buffer;
2434 struct smb_hdr *smb_buffer_response;
2435 SESSION_SETUP_ANDX *pSMB;
2436 SESSION_SETUP_ANDX *pSMBr;
2437 char *bcc_ptr;
2438 char *user;
2439 char *domain;
2440 int rc = 0;
2441 int remaining_words = 0;
2442 int bytes_returned = 0;
2443 int len;
2444 __u32 capabilities;
2445 __u16 count;
2446
Steve Frencheeac8042006-01-13 21:34:58 -08002447 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002448 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 return -EINVAL;
2450 user = ses->userName;
2451 domain = ses->domainName;
2452 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002453
2454 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002456
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 smb_buffer_response = smb_buffer;
2458 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2459
2460 /* send SMBsessionSetup here */
2461 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2462 NULL /* no tCon exists yet */ , 13 /* wct */ );
2463
Steve French1982c342005-08-17 12:38:22 -07002464 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 pSMB->req_no_secext.AndXCommand = 0xFF;
2466 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2467 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2468
Steve French50c2f752007-07-13 00:33:32 +00002469 if (ses->server->secMode &
2470 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2472
2473 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2474 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2475 if (ses->capabilities & CAP_UNICODE) {
2476 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2477 capabilities |= CAP_UNICODE;
2478 }
2479 if (ses->capabilities & CAP_STATUS32) {
2480 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2481 capabilities |= CAP_STATUS32;
2482 }
2483 if (ses->capabilities & CAP_DFS) {
2484 smb_buffer->Flags2 |= SMBFLG2_DFS;
2485 capabilities |= CAP_DFS;
2486 }
2487 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2488
Steve French50c2f752007-07-13 00:33:32 +00002489 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002490 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491
2492 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002493 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002495 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2496 bcc_ptr += CIFS_SESS_KEY_SIZE;
2497 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2498 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
2500 if (ses->capabilities & CAP_UNICODE) {
2501 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2502 *bcc_ptr = 0;
2503 bcc_ptr++;
2504 }
Steve French4523cc32007-04-30 20:13:06 +00002505 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002506 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002507 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002509 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 nls_codepage);
2511 /* convert number of 16 bit words to bytes */
2512 bcc_ptr += 2 * bytes_returned;
2513 bcc_ptr += 2; /* trailing null */
2514 if (domain == NULL)
2515 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002516 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 "CIFS_LINUX_DOM", 32, nls_codepage);
2518 else
2519 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002520 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 nls_codepage);
2522 bcc_ptr += 2 * bytes_returned;
2523 bcc_ptr += 2;
2524 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002525 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 32, nls_codepage);
2527 bcc_ptr += 2 * bytes_returned;
2528 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002529 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 32, nls_codepage);
2531 bcc_ptr += 2 * bytes_returned;
2532 bcc_ptr += 2;
2533 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002534 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 64, nls_codepage);
2536 bcc_ptr += 2 * bytes_returned;
2537 bcc_ptr += 2;
2538 } else {
Steve French50c2f752007-07-13 00:33:32 +00002539 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 strncpy(bcc_ptr, user, 200);
2541 bcc_ptr += strnlen(user, 200);
2542 }
2543 *bcc_ptr = 0;
2544 bcc_ptr++;
2545 if (domain == NULL) {
2546 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2547 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2548 } else {
2549 strncpy(bcc_ptr, domain, 64);
2550 bcc_ptr += strnlen(domain, 64);
2551 *bcc_ptr = 0;
2552 bcc_ptr++;
2553 }
2554 strcpy(bcc_ptr, "Linux version ");
2555 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002556 strcpy(bcc_ptr, utsname()->release);
2557 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2559 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2560 }
2561 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2562 smb_buffer->smb_buf_length += count;
2563 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2564
2565 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002566 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 if (rc) {
2568/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2569 } else if ((smb_buffer_response->WordCount == 3)
2570 || (smb_buffer_response->WordCount == 4)) {
2571 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2572 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2573 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002574 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2575 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2576 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002578 /* response can have either 3 or 4 word count - Samba sends 3 */
2579 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 if ((pSMBr->resp.hdr.WordCount == 3)
2581 || ((pSMBr->resp.hdr.WordCount == 4)
2582 && (blob_len < pSMBr->resp.ByteCount))) {
2583 if (pSMBr->resp.hdr.WordCount == 4)
2584 bcc_ptr += blob_len;
2585
2586 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2587 if ((long) (bcc_ptr) % 2) {
2588 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002589 (BCC(smb_buffer_response) - 1) / 2;
2590 /* Unicode strings must be word
2591 aligned */
2592 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 } else {
2594 remaining_words =
2595 BCC(smb_buffer_response) / 2;
2596 }
2597 len =
2598 UniStrnlen((wchar_t *) bcc_ptr,
2599 remaining_words - 1);
2600/* We look for obvious messed up bcc or strings in response so we do not go off
2601 the end since (at least) WIN2K and Windows XP have a major bug in not null
2602 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002603 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002604 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002605 ses->serverOS = kzalloc(2 * (len + 1),
2606 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002607 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002608 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002610 (__le16 *)bcc_ptr,
2611 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 bcc_ptr += 2 * (len + 1);
2613 remaining_words -= len + 1;
2614 ses->serverOS[2 * len] = 0;
2615 ses->serverOS[1 + (2 * len)] = 0;
2616 if (remaining_words > 0) {
2617 len = UniStrnlen((wchar_t *)bcc_ptr,
2618 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002619 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002620 ses->serverNOS = kzalloc(2 * (len + 1),
2621 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002622 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002623 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002625 (__le16 *)bcc_ptr,
2626 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 bcc_ptr += 2 * (len + 1);
2628 ses->serverNOS[2 * len] = 0;
2629 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002630 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002631 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002632 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 ses->flags |= CIFS_SES_NT4;
2634 }
2635 remaining_words -= len + 1;
2636 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002637 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002638 /* last string is not always null terminated
2639 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002640 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002641 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002643 kzalloc(2*(len+1),
2644 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002645 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002646 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002648 (__le16 *)bcc_ptr,
2649 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 bcc_ptr += 2 * (len + 1);
2651 ses->serverDomain[2*len] = 0;
2652 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002653 } else { /* else no more room so create
2654 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002655 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002656 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002657 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002658 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002659 }
Steve French50c2f752007-07-13 00:33:32 +00002660 } else { /* no room so create dummy domain
2661 and NOS string */
2662
Steve French433dc242005-04-28 22:41:08 -07002663 /* if these kcallocs fail not much we
2664 can do, but better to not fail the
2665 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002666 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002668 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002669 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002671 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 }
2673 } else { /* ASCII */
2674 len = strnlen(bcc_ptr, 1024);
2675 if (((long) bcc_ptr + len) - (long)
2676 pByteArea(smb_buffer_response)
2677 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002678 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002679 ses->serverOS = kzalloc(len + 1,
2680 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002681 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002682 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002683 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
2685 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002686 /* null terminate the string */
2687 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 bcc_ptr++;
2689
2690 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002691 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002692 ses->serverNOS = kzalloc(len + 1,
2693 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002694 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002695 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 strncpy(ses->serverNOS, bcc_ptr, len);
2697 bcc_ptr += len;
2698 bcc_ptr[0] = 0;
2699 bcc_ptr++;
2700
2701 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002702 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002703 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002704 ses->serverDomain = kzalloc(len + 1,
2705 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002706 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002707 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002708 strncpy(ses->serverDomain, bcc_ptr,
2709 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 bcc_ptr += len;
2711 bcc_ptr[0] = 0;
2712 bcc_ptr++;
2713 } else
2714 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002715 ("Variable field of length %d "
2716 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 len));
2718 }
2719 } else {
2720 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002721 (" Security Blob Length extends beyond "
2722 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 }
2724 } else {
2725 cERROR(1,
2726 (" Invalid Word count %d: ",
2727 smb_buffer_response->WordCount));
2728 rc = -EIO;
2729 }
Steve French433dc242005-04-28 22:41:08 -07002730sesssetup_nomem: /* do not return an error on nomem for the info strings,
2731 since that could make reconnection harder, and
2732 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002733 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734
2735 return rc;
2736}
2737
2738static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002740 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 const struct nls_table *nls_codepage)
2742{
2743 struct smb_hdr *smb_buffer;
2744 struct smb_hdr *smb_buffer_response;
2745 SESSION_SETUP_ANDX *pSMB;
2746 SESSION_SETUP_ANDX *pSMBr;
2747 char *bcc_ptr;
2748 char *domain;
2749 int rc = 0;
2750 int remaining_words = 0;
2751 int bytes_returned = 0;
2752 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002753 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 PNEGOTIATE_MESSAGE SecurityBlob;
2755 PCHALLENGE_MESSAGE SecurityBlob2;
2756 __u32 negotiate_flags, capabilities;
2757 __u16 count;
2758
Steve French12b3b8f2006-02-09 21:12:47 +00002759 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002760 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 return -EINVAL;
2762 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002763 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 smb_buffer = cifs_buf_get();
2765 if (smb_buffer == NULL) {
2766 return -ENOMEM;
2767 }
2768 smb_buffer_response = smb_buffer;
2769 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2770 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2771
2772 /* send SMBsessionSetup here */
2773 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2774 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002775
2776 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2778 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2779
2780 pSMB->req.AndXCommand = 0xFF;
2781 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2782 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2783
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002784 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2786
2787 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2788 CAP_EXTENDED_SECURITY;
2789 if (ses->capabilities & CAP_UNICODE) {
2790 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2791 capabilities |= CAP_UNICODE;
2792 }
2793 if (ses->capabilities & CAP_STATUS32) {
2794 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2795 capabilities |= CAP_STATUS32;
2796 }
2797 if (ses->capabilities & CAP_DFS) {
2798 smb_buffer->Flags2 |= SMBFLG2_DFS;
2799 capabilities |= CAP_DFS;
2800 }
2801 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2802
2803 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2804 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2805 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2806 SecurityBlob->MessageType = NtLmNegotiate;
2807 negotiate_flags =
2808 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002809 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2810 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002812 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002814/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002815 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 /* setup pointers to domain name and workstation name */
2817 bcc_ptr += SecurityBlobLength;
2818
2819 SecurityBlob->WorkstationName.Buffer = 0;
2820 SecurityBlob->WorkstationName.Length = 0;
2821 SecurityBlob->WorkstationName.MaximumLength = 0;
2822
Steve French12b3b8f2006-02-09 21:12:47 +00002823 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2824 along with username on auth request (ie the response to challenge) */
2825 SecurityBlob->DomainName.Buffer = 0;
2826 SecurityBlob->DomainName.Length = 0;
2827 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 if (ses->capabilities & CAP_UNICODE) {
2829 if ((long) bcc_ptr % 2) {
2830 *bcc_ptr = 0;
2831 bcc_ptr++;
2832 }
2833
2834 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002835 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 32, nls_codepage);
2837 bcc_ptr += 2 * bytes_returned;
2838 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002839 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 nls_codepage);
2841 bcc_ptr += 2 * bytes_returned;
2842 bcc_ptr += 2; /* null terminate Linux version */
2843 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002844 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 64, nls_codepage);
2846 bcc_ptr += 2 * bytes_returned;
2847 *(bcc_ptr + 1) = 0;
2848 *(bcc_ptr + 2) = 0;
2849 bcc_ptr += 2; /* null terminate network opsys string */
2850 *(bcc_ptr + 1) = 0;
2851 *(bcc_ptr + 2) = 0;
2852 bcc_ptr += 2; /* null domain */
2853 } else { /* ASCII */
2854 strcpy(bcc_ptr, "Linux version ");
2855 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002856 strcpy(bcc_ptr, utsname()->release);
2857 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2859 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2860 bcc_ptr++; /* empty domain field */
2861 *bcc_ptr = 0;
2862 }
2863 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2864 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2865 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2866 smb_buffer->smb_buf_length += count;
2867 pSMB->req.ByteCount = cpu_to_le16(count);
2868
2869 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002870 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871
2872 if (smb_buffer_response->Status.CifsError ==
2873 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2874 rc = 0;
2875
2876 if (rc) {
2877/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2878 } else if ((smb_buffer_response->WordCount == 3)
2879 || (smb_buffer_response->WordCount == 4)) {
2880 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2881 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2882
2883 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002884 cFYI(1, (" Guest login"));
2885 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886
Steve French50c2f752007-07-13 00:33:32 +00002887 bcc_ptr = pByteArea(smb_buffer_response);
2888 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889
2890 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2891 if (SecurityBlob2->MessageType != NtLmChallenge) {
2892 cFYI(1,
2893 ("Unexpected NTLMSSP message type received %d",
2894 SecurityBlob2->MessageType));
2895 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002896 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002897 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 if ((pSMBr->resp.hdr.WordCount == 3)
2899 || ((pSMBr->resp.hdr.WordCount == 4)
2900 && (blob_len <
2901 pSMBr->resp.ByteCount))) {
2902
2903 if (pSMBr->resp.hdr.WordCount == 4) {
2904 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002905 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 blob_len));
2907 }
2908
Steve French12b3b8f2006-02-09 21:12:47 +00002909 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910
2911 memcpy(ses->server->cryptKey,
2912 SecurityBlob2->Challenge,
2913 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002914 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002915 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002916 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917
Steve French50c2f752007-07-13 00:33:32 +00002918 if ((SecurityBlob2->NegotiateFlags &
2919 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002921 ses->server->secMode |=
2922 SECMODE_SIGN_REQUIRED;
2923 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002925 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 SECMODE_SIGN_ENABLED;
2927
2928 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2929 if ((long) (bcc_ptr) % 2) {
2930 remaining_words =
2931 (BCC(smb_buffer_response)
2932 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002933 /* Must word align unicode strings */
2934 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 } else {
2936 remaining_words =
2937 BCC
2938 (smb_buffer_response) / 2;
2939 }
2940 len =
2941 UniStrnlen((wchar_t *) bcc_ptr,
2942 remaining_words - 1);
2943/* We look for obvious messed up bcc or strings in response so we do not go off
2944 the end since (at least) WIN2K and Windows XP have a major bug in not null
2945 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002946 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002947 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002949 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002951 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 bcc_ptr, len,
2953 nls_codepage);
2954 bcc_ptr += 2 * (len + 1);
2955 remaining_words -= len + 1;
2956 ses->serverOS[2 * len] = 0;
2957 ses->serverOS[1 + (2 * len)] = 0;
2958 if (remaining_words > 0) {
2959 len = UniStrnlen((wchar_t *)
2960 bcc_ptr,
2961 remaining_words
2962 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002963 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002965 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 GFP_KERNEL);
2967 cifs_strfromUCS_le(ses->
2968 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002969 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 bcc_ptr,
2971 len,
2972 nls_codepage);
2973 bcc_ptr += 2 * (len + 1);
2974 ses->serverNOS[2 * len] = 0;
2975 ses->serverNOS[1 +
2976 (2 * len)] = 0;
2977 remaining_words -= len + 1;
2978 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002979 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2980 /* last string not always null terminated
2981 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002982 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002984 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 (len +
2986 1),
2987 GFP_KERNEL);
2988 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002989 (ses->serverDomain,
2990 (__le16 *)bcc_ptr,
2991 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 bcc_ptr +=
2993 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002994 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002996 ses->serverDomain
2997 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 = 0;
2999 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003000 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00003001 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003003 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003005 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00003007 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003009 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003010 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003012 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 }
3014 } else { /* ASCII */
3015 len = strnlen(bcc_ptr, 1024);
3016 if (((long) bcc_ptr + len) - (long)
3017 pByteArea(smb_buffer_response)
3018 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003019 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003020 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003022 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 GFP_KERNEL);
3024 strncpy(ses->serverOS,
3025 bcc_ptr, len);
3026
3027 bcc_ptr += len;
3028 bcc_ptr[0] = 0; /* null terminate string */
3029 bcc_ptr++;
3030
3031 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003032 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003034 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 GFP_KERNEL);
3036 strncpy(ses->serverNOS, bcc_ptr, len);
3037 bcc_ptr += len;
3038 bcc_ptr[0] = 0;
3039 bcc_ptr++;
3040
3041 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003042 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003044 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00003046 strncpy(ses->serverDomain,
3047 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 bcc_ptr += len;
3049 bcc_ptr[0] = 0;
3050 bcc_ptr++;
3051 } else
3052 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00003053 ("field of length %d "
3054 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 len));
3056 }
3057 } else {
Steve French50c2f752007-07-13 00:33:32 +00003058 cERROR(1, ("Security Blob Length extends beyond"
3059 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 }
3061 } else {
3062 cERROR(1, ("No session structure passed in."));
3063 }
3064 } else {
3065 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00003066 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 smb_buffer_response->WordCount));
3068 rc = -EIO;
3069 }
3070
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003071 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072
3073 return rc;
3074}
3075static int
3076CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00003077 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003078 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079{
3080 struct smb_hdr *smb_buffer;
3081 struct smb_hdr *smb_buffer_response;
3082 SESSION_SETUP_ANDX *pSMB;
3083 SESSION_SETUP_ANDX *pSMBr;
3084 char *bcc_ptr;
3085 char *user;
3086 char *domain;
3087 int rc = 0;
3088 int remaining_words = 0;
3089 int bytes_returned = 0;
3090 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003091 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 PAUTHENTICATE_MESSAGE SecurityBlob;
3093 __u32 negotiate_flags, capabilities;
3094 __u16 count;
3095
3096 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003097 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 return -EINVAL;
3099 user = ses->userName;
3100 domain = ses->domainName;
3101 smb_buffer = cifs_buf_get();
3102 if (smb_buffer == NULL) {
3103 return -ENOMEM;
3104 }
3105 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003106 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
3107 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108
3109 /* send SMBsessionSetup here */
3110 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
3111 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07003112
3113 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
3115 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
3116 pSMB->req.AndXCommand = 0xFF;
3117 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
3118 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
3119
3120 pSMB->req.hdr.Uid = ses->Suid;
3121
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003122 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3124
3125 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003126 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 if (ses->capabilities & CAP_UNICODE) {
3128 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3129 capabilities |= CAP_UNICODE;
3130 }
3131 if (ses->capabilities & CAP_STATUS32) {
3132 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3133 capabilities |= CAP_STATUS32;
3134 }
3135 if (ses->capabilities & CAP_DFS) {
3136 smb_buffer->Flags2 |= SMBFLG2_DFS;
3137 capabilities |= CAP_DFS;
3138 }
3139 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3140
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003141 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3142 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3144 SecurityBlob->MessageType = NtLmAuthenticate;
3145 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003146 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3147 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3148 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003149 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003151 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3153
3154/* setup pointers to domain name and workstation name */
3155
3156 SecurityBlob->WorkstationName.Buffer = 0;
3157 SecurityBlob->WorkstationName.Length = 0;
3158 SecurityBlob->WorkstationName.MaximumLength = 0;
3159 SecurityBlob->SessionKey.Length = 0;
3160 SecurityBlob->SessionKey.MaximumLength = 0;
3161 SecurityBlob->SessionKey.Buffer = 0;
3162
3163 SecurityBlob->LmChallengeResponse.Length = 0;
3164 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3165 SecurityBlob->LmChallengeResponse.Buffer = 0;
3166
3167 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003168 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003170 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3171 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 SecurityBlob->NtChallengeResponse.Buffer =
3173 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003174 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3175 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176
3177 if (ses->capabilities & CAP_UNICODE) {
3178 if (domain == NULL) {
3179 SecurityBlob->DomainName.Buffer = 0;
3180 SecurityBlob->DomainName.Length = 0;
3181 SecurityBlob->DomainName.MaximumLength = 0;
3182 } else {
Steve French77159b42007-08-31 01:10:17 +00003183 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003185 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003187 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 SecurityBlob->DomainName.Buffer =
3189 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003190 bcc_ptr += ln;
3191 SecurityBlobLength += ln;
3192 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 }
3194 if (user == NULL) {
3195 SecurityBlob->UserName.Buffer = 0;
3196 SecurityBlob->UserName.Length = 0;
3197 SecurityBlob->UserName.MaximumLength = 0;
3198 } else {
Steve French77159b42007-08-31 01:10:17 +00003199 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003201 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003203 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 SecurityBlob->UserName.Buffer =
3205 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003206 bcc_ptr += ln;
3207 SecurityBlobLength += ln;
3208 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 }
3210
Steve French63135e02007-07-17 17:34:02 +00003211 /* SecurityBlob->WorkstationName.Length =
3212 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003214 SecurityBlob->WorkstationName.MaximumLength =
3215 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3216 SecurityBlob->WorkstationName.Buffer =
3217 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 bcc_ptr += SecurityBlob->WorkstationName.Length;
3219 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003220 SecurityBlob->WorkstationName.Length =
3221 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222
3223 if ((long) bcc_ptr % 2) {
3224 *bcc_ptr = 0;
3225 bcc_ptr++;
3226 }
3227 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003228 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 32, nls_codepage);
3230 bcc_ptr += 2 * bytes_returned;
3231 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003232 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 nls_codepage);
3234 bcc_ptr += 2 * bytes_returned;
3235 bcc_ptr += 2; /* null term version string */
3236 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003237 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 64, nls_codepage);
3239 bcc_ptr += 2 * bytes_returned;
3240 *(bcc_ptr + 1) = 0;
3241 *(bcc_ptr + 2) = 0;
3242 bcc_ptr += 2; /* null terminate network opsys string */
3243 *(bcc_ptr + 1) = 0;
3244 *(bcc_ptr + 2) = 0;
3245 bcc_ptr += 2; /* null domain */
3246 } else { /* ASCII */
3247 if (domain == NULL) {
3248 SecurityBlob->DomainName.Buffer = 0;
3249 SecurityBlob->DomainName.Length = 0;
3250 SecurityBlob->DomainName.MaximumLength = 0;
3251 } else {
Steve French77159b42007-08-31 01:10:17 +00003252 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3254 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003255 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003257 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 SecurityBlob->DomainName.Buffer =
3259 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003260 bcc_ptr += ln;
3261 SecurityBlobLength += ln;
3262 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 }
3264 if (user == NULL) {
3265 SecurityBlob->UserName.Buffer = 0;
3266 SecurityBlob->UserName.Length = 0;
3267 SecurityBlob->UserName.MaximumLength = 0;
3268 } else {
Steve French77159b42007-08-31 01:10:17 +00003269 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003271 ln = strnlen(user, 64);
3272 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003274 cpu_to_le32(SecurityBlobLength);
3275 bcc_ptr += ln;
3276 SecurityBlobLength += ln;
3277 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 }
3279 /* BB fill in our workstation name if known BB */
3280
3281 strcpy(bcc_ptr, "Linux version ");
3282 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003283 strcpy(bcc_ptr, utsname()->release);
3284 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3286 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3287 bcc_ptr++; /* null domain */
3288 *bcc_ptr = 0;
3289 }
3290 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3291 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3292 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3293 smb_buffer->smb_buf_length += count;
3294 pSMB->req.ByteCount = cpu_to_le16(count);
3295
3296 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003297 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003299/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3300 } else if ((smb_buffer_response->WordCount == 3) ||
3301 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003303 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003305 cFYI(1, (" Guest login")); /* BB Should we set anything
3306 in SesInfo struct ? */
3307/* if (SecurityBlob2->MessageType != NtLm??) {
3308 cFYI("Unexpected message type on auth response is %d"));
3309 } */
3310
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 if (ses) {
3312 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003313 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003315 /* UID left in wire format */
3316 ses->Suid = smb_buffer_response->Uid;
3317 bcc_ptr = pByteArea(smb_buffer_response);
3318 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 if ((pSMBr->resp.hdr.WordCount == 3)
3320 || ((pSMBr->resp.hdr.WordCount == 4)
3321 && (blob_len <
3322 pSMBr->resp.ByteCount))) {
3323 if (pSMBr->resp.hdr.WordCount == 4) {
3324 bcc_ptr +=
3325 blob_len;
3326 cFYI(1,
3327 ("Security Blob Length %d ",
3328 blob_len));
3329 }
3330
3331 cFYI(1,
3332 ("NTLMSSP response to Authenticate "));
3333
3334 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3335 if ((long) (bcc_ptr) % 2) {
3336 remaining_words =
3337 (BCC(smb_buffer_response)
3338 - 1) / 2;
3339 bcc_ptr++; /* Unicode strings must be word aligned */
3340 } else {
3341 remaining_words = BCC(smb_buffer_response) / 2;
3342 }
Steve French77159b42007-08-31 01:10:17 +00003343 len = UniStrnlen((wchar_t *) bcc_ptr,
3344 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345/* We look for obvious messed up bcc or strings in response so we do not go off
3346 the end since (at least) WIN2K and Windows XP have a major bug in not null
3347 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003348 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003349 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003351 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003353 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 bcc_ptr, len,
3355 nls_codepage);
3356 bcc_ptr += 2 * (len + 1);
3357 remaining_words -= len + 1;
3358 ses->serverOS[2 * len] = 0;
3359 ses->serverOS[1 + (2 * len)] = 0;
3360 if (remaining_words > 0) {
3361 len = UniStrnlen((wchar_t *)
3362 bcc_ptr,
3363 remaining_words
3364 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003365 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003367 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 GFP_KERNEL);
3369 cifs_strfromUCS_le(ses->
3370 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003371 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 bcc_ptr,
3373 len,
3374 nls_codepage);
3375 bcc_ptr += 2 * (len + 1);
3376 ses->serverNOS[2 * len] = 0;
3377 ses->serverNOS[1+(2*len)] = 0;
3378 remaining_words -= len + 1;
3379 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003380 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003382 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003383 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003385 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 (len +
3387 1),
3388 GFP_KERNEL);
3389 cifs_strfromUCS_le
3390 (ses->
3391 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003392 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 bcc_ptr, len,
3394 nls_codepage);
3395 bcc_ptr +=
3396 2 * (len + 1);
3397 ses->
3398 serverDomain[2
3399 * len]
3400 = 0;
3401 ses->
3402 serverDomain[1
3403 +
3404 (2
3405 *
3406 len)]
3407 = 0;
3408 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003409 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003410 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003411 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003412 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003415 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003416 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003417 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003418 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003419 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 }
3421 } else { /* ASCII */
3422 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003423 if (((long) bcc_ptr + len) -
3424 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003425 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003426 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003427 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003428 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 strncpy(ses->serverOS,bcc_ptr, len);
3430
3431 bcc_ptr += len;
3432 bcc_ptr[0] = 0; /* null terminate the string */
3433 bcc_ptr++;
3434
3435 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003436 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003437 ses->serverNOS = kzalloc(len+1,
3438 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003439 strncpy(ses->serverNOS,
3440 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 bcc_ptr += len;
3442 bcc_ptr[0] = 0;
3443 bcc_ptr++;
3444
3445 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003446 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003447 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003448 ses->serverDomain =
3449 kzalloc(len+1,
3450 GFP_KERNEL);
3451 strncpy(ses->serverDomain,
3452 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 bcc_ptr += len;
3454 bcc_ptr[0] = 0;
3455 bcc_ptr++;
3456 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003457 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003458 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 len));
3460 }
3461 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003462 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003463 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 }
3465 } else {
3466 cERROR(1, ("No session structure passed in."));
3467 }
3468 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003469 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 smb_buffer_response->WordCount));
3471 rc = -EIO;
3472 }
3473
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003474 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475
3476 return rc;
3477}
3478
3479int
3480CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3481 const char *tree, struct cifsTconInfo *tcon,
3482 const struct nls_table *nls_codepage)
3483{
3484 struct smb_hdr *smb_buffer;
3485 struct smb_hdr *smb_buffer_response;
3486 TCONX_REQ *pSMB;
3487 TCONX_RSP *pSMBr;
3488 unsigned char *bcc_ptr;
3489 int rc = 0;
3490 int length;
3491 __u16 count;
3492
3493 if (ses == NULL)
3494 return -EIO;
3495
3496 smb_buffer = cifs_buf_get();
3497 if (smb_buffer == NULL) {
3498 return -ENOMEM;
3499 }
3500 smb_buffer_response = smb_buffer;
3501
3502 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3503 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003504
3505 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 smb_buffer->Uid = ses->Suid;
3507 pSMB = (TCONX_REQ *) smb_buffer;
3508 pSMBr = (TCONX_RSP *) smb_buffer_response;
3509
3510 pSMB->AndXCommand = 0xFF;
3511 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003513 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003514 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003515 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003516 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003517 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003518 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003519 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003520 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3521 specified as required (when that support is added to
3522 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003523 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003524 by Samba (not sure whether other servers allow
3525 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003526#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003527 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003528 (ses->server->secType == LANMAN))
3529 calc_lanman_hash(ses, bcc_ptr);
3530 else
3531#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003532 SMBNTencrypt(ses->password,
3533 ses->server->cryptKey,
3534 bcc_ptr);
3535
Steve French7c7b25b2006-06-01 19:20:10 +00003536 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003537 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003538 /* must align unicode strings */
3539 *bcc_ptr = 0; /* null byte password */
3540 bcc_ptr++;
3541 }
Steve Frencheeac8042006-01-13 21:34:58 -08003542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543
Steve French50c2f752007-07-13 00:33:32 +00003544 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003545 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3547
3548 if (ses->capabilities & CAP_STATUS32) {
3549 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3550 }
3551 if (ses->capabilities & CAP_DFS) {
3552 smb_buffer->Flags2 |= SMBFLG2_DFS;
3553 }
3554 if (ses->capabilities & CAP_UNICODE) {
3555 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3556 length =
Steve French50c2f752007-07-13 00:33:32 +00003557 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3558 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003559 (/* server len*/ + 256 /* share len */), nls_codepage);
3560 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561 bcc_ptr += 2; /* skip trailing null */
3562 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 strcpy(bcc_ptr, tree);
3564 bcc_ptr += strlen(tree) + 1;
3565 }
3566 strcpy(bcc_ptr, "?????");
3567 bcc_ptr += strlen("?????");
3568 bcc_ptr += 1;
3569 count = bcc_ptr - &pSMB->Password[0];
3570 pSMB->hdr.smb_buf_length += count;
3571 pSMB->ByteCount = cpu_to_le16(count);
3572
Steve French133672e2007-11-13 22:41:37 +00003573 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3574 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575
3576 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3577 /* above now done in SendReceive */
3578 if ((rc == 0) && (tcon != NULL)) {
3579 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003580 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 tcon->tid = smb_buffer_response->Tid;
3582 bcc_ptr = pByteArea(smb_buffer_response);
3583 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003584 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003585 if (length == 3) {
3586 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3587 (bcc_ptr[2] == 'C')) {
3588 cFYI(1, ("IPC connection"));
3589 tcon->ipc = 1;
3590 }
3591 } else if (length == 2) {
3592 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3593 /* the most common case */
3594 cFYI(1, ("disk share connection"));
3595 }
3596 }
Steve French50c2f752007-07-13 00:33:32 +00003597 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3599 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3600 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3601 if ((bcc_ptr + (2 * length)) -
3602 pByteArea(smb_buffer_response) <=
3603 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003604 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003606 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003607 if (tcon->nativeFileSystem)
3608 cifs_strfromUCS_le(
3609 tcon->nativeFileSystem,
3610 (__le16 *) bcc_ptr,
3611 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 bcc_ptr += 2 * length;
3613 bcc_ptr[0] = 0; /* null terminate the string */
3614 bcc_ptr[1] = 0;
3615 bcc_ptr += 2;
3616 }
Steve French50c2f752007-07-13 00:33:32 +00003617 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 } else {
3619 length = strnlen(bcc_ptr, 1024);
3620 if ((bcc_ptr + length) -
3621 pByteArea(smb_buffer_response) <=
3622 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003623 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003625 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003626 if (tcon->nativeFileSystem)
3627 strncpy(tcon->nativeFileSystem, bcc_ptr,
3628 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 }
Steve French50c2f752007-07-13 00:33:32 +00003630 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003632 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003633 (smb_buffer_response->WordCount == 7))
3634 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003635 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3636 else
3637 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3639 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003640 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 ses->ipc_tid = smb_buffer_response->Tid;
3642 }
3643
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003644 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 return rc;
3646}
3647
3648int
3649cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3650{
3651 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003652 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653
Jeff Laytonf1987b42008-11-15 11:12:47 -05003654 if (cifs_sb->tcon)
3655 cifs_put_tcon(cifs_sb->tcon);
Steve French50c2f752007-07-13 00:33:32 +00003656
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003658 tmp = cifs_sb->prepath;
3659 cifs_sb->prepathlen = 0;
3660 cifs_sb->prepath = NULL;
3661 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662
Steve French88e7d702008-01-03 17:37:09 +00003663 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003664}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665
3666int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003667 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668{
3669 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003670 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003671 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003672 int first_time = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003673 struct TCP_Server_Info *server = pSesInfo->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674
3675 /* what if server changes its buffer size after dropping the session? */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003676 if (server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 rc = CIFSSMBNegotiate(xid, pSesInfo);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003678 if (rc == -EAGAIN) {
3679 /* retry only once on 1st time connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003681 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 rc = -EHOSTDOWN;
3683 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003684 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 spin_lock(&GlobalMid_Lock);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003686 if (server->tcpStatus != CifsExiting)
3687 server->tcpStatus = CifsGood;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 else
3689 rc = -EHOSTDOWN;
3690 spin_unlock(&GlobalMid_Lock);
3691
3692 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003693 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 }
Steve French26b994f2008-08-06 05:11:33 +00003695
3696 if (rc)
3697 goto ss_err_exit;
3698
3699 pSesInfo->flags = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003700 pSesInfo->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003701 if (linuxExtEnabled == 0)
3702 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003703 /* pSesInfo->sequence_number = 0;*/
Steve French26b994f2008-08-06 05:11:33 +00003704 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003705 server->secMode, server->capabilities, server->timeAdj));
3706
Steve French26b994f2008-08-06 05:11:33 +00003707 if (experimEnabled < 2)
3708 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
3709 else if (extended_security
3710 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003711 && (server->secType == NTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003712 rc = -EOPNOTSUPP;
3713 } else if (extended_security
3714 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003715 && (server->secType == RawNTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003716 cFYI(1, ("NTLMSSP sesssetup"));
3717 rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
3718 nls_info);
3719 if (!rc) {
3720 if (ntlmv2_flag) {
3721 char *v2_response;
3722 cFYI(1, ("more secure NTLM ver2 hash"));
3723 if (CalcNTLMv2_partial_mac_key(pSesInfo,
3724 nls_info)) {
3725 rc = -ENOMEM;
3726 goto ss_err_exit;
3727 } else
3728 v2_response = kmalloc(16 + 64 /* blob*/,
3729 GFP_KERNEL);
3730 if (v2_response) {
3731 CalcNTLMv2_response(pSesInfo,
3732 v2_response);
3733 /* if (first_time)
3734 cifs_calculate_ntlmv2_mac_key */
3735 kfree(v2_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 /* BB Put dummy sig in SessSetup PDU? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 } else {
Steve French26b994f2008-08-06 05:11:33 +00003738 rc = -ENOMEM;
3739 goto ss_err_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 }
Steve French26b994f2008-08-06 05:11:33 +00003741
3742 } else {
3743 SMBNTencrypt(pSesInfo->password,
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003744 server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003745 ntlm_session_key);
3746
3747 if (first_time)
3748 cifs_calculate_mac_key(
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003749 &server->mac_signing_key,
Steve French26b994f2008-08-06 05:11:33 +00003750 ntlm_session_key,
3751 pSesInfo->password);
3752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 /* for better security the weaker lanman hash not sent
3754 in AuthSessSetup so we no longer calculate it */
3755
Steve French26b994f2008-08-06 05:11:33 +00003756 rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
3757 ntlm_session_key,
3758 ntlmv2_flag,
3759 nls_info);
3760 }
3761 } else { /* old style NTLM 0.12 session setup */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003762 SMBNTencrypt(pSesInfo->password, server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003763 ntlm_session_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764
Steve French26b994f2008-08-06 05:11:33 +00003765 if (first_time)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003766 cifs_calculate_mac_key(&server->mac_signing_key,
3767 ntlm_session_key,
3768 pSesInfo->password);
Steve Frenchad009ac2005-04-28 22:41:05 -07003769
Steve French26b994f2008-08-06 05:11:33 +00003770 rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 }
Steve French26b994f2008-08-06 05:11:33 +00003772 if (rc) {
3773 cERROR(1, ("Send error in SessSetup = %d", rc));
3774 } else {
3775 cFYI(1, ("CIFS Session Established successfully"));
Jeff Layton469ee612008-10-16 18:46:39 +00003776 spin_lock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003777 pSesInfo->status = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003778 pSesInfo->need_reconnect = false;
Jeff Layton469ee612008-10-16 18:46:39 +00003779 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003780 }
3781
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782ss_err_exit:
3783 return rc;
3784}
3785