blob: a3537a90a9d97f63ca87ffb69d74aec4199db337 [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 */
Steve French13a6e422008-12-02 17:24:33 +000092 bool mand_lock:1; /* send mandatory not posix byte range lock reqs */
Steve French95b1cb92008-05-15 16:44:38 +000093 bool seal:1; /* request transport encryption on share */
Steve French84210e92008-10-23 04:42:37 +000094 bool nodfs:1; /* Do not request DFS, even if available */
95 bool local_lease:1; /* check leases only on local system, not remote */
Steve Frenchedf1ae42008-10-29 00:47:57 +000096 bool noblocksnd:1;
97 bool noautotune:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 unsigned int rsize;
99 unsigned int wsize;
100 unsigned int sockopt;
101 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000102 char *prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103};
104
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500105static int ipv4_connect(struct TCP_Server_Info *server);
Jeff Laytond5c56052008-12-01 18:42:33 -0500106static int ipv6_connect(struct TCP_Server_Info *server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Jeff Laytond5c56052008-12-01 18:42:33 -0500108/*
109 * cifs tcp session reconnection
110 *
111 * mark tcp session as reconnecting so temporarily locked
112 * mark all smb sessions as reconnecting for tcp session
113 * reconnect tcp session
114 * wake up waiters on reconnection? - (not needed currently)
115 */
Steve French2cd646a2006-09-28 19:43:08 +0000116static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117cifs_reconnect(struct TCP_Server_Info *server)
118{
119 int rc = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500120 struct list_head *tmp, *tmp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 struct cifsSesInfo *ses;
122 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000123 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000126 if (server->tcpStatus == CifsExiting) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000127 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 next time through the loop */
129 spin_unlock(&GlobalMid_Lock);
130 return rc;
131 } else
132 server->tcpStatus = CifsNeedReconnect;
133 spin_unlock(&GlobalMid_Lock);
134 server->maxBuf = 0;
135
Steve Frenche4eb2952005-04-28 22:41:09 -0700136 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
138 /* before reconnecting the tcp session, mark the smb session (uid)
139 and the tid bad so they are not used until reconnected */
Jeff Layton14fbf502008-11-14 13:53:46 -0500140 read_lock(&cifs_tcp_ses_lock);
141 list_for_each(tmp, &server->smb_ses_list) {
142 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
143 ses->need_reconnect = true;
144 ses->ipc_tid = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500145 list_for_each(tmp2, &ses->tcon_list) {
146 tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list);
147 tcon->need_reconnect = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500150 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 /* do not want to be sending data on a socket we are freeing */
Jeff Layton72ca5452008-12-01 07:09:36 -0500152 mutex_lock(&server->srv_mutex);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000153 if (server->ssocket) {
Steve French467a8f82007-06-27 22:41:32 +0000154 cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 server->ssocket->flags));
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800156 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000157 cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000158 server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 server->ssocket->flags));
160 sock_release(server->ssocket);
161 server->ssocket = NULL;
162 }
163
164 spin_lock(&GlobalMid_Lock);
165 list_for_each(tmp, &server->pending_mid_q) {
166 mid_entry = list_entry(tmp, struct
167 mid_q_entry,
168 qhead);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000169 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700170 /* Mark other intransit requests as needing
171 retry so we do not immediately mark the
172 session bad again (ie after we reconnect
173 below) as they timeout too */
Steve Frenchad8b15f2008-08-08 21:10:16 +0000174 mid_entry->midState = MID_RETRY_NEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 }
176 }
177 spin_unlock(&GlobalMid_Lock);
Jeff Layton72ca5452008-12-01 07:09:36 -0500178 mutex_unlock(&server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Jeff Layton469ee612008-10-16 18:46:39 +0000180 while ((server->tcpStatus != CifsExiting) &&
181 (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000182 try_to_freeze();
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500183 if (server->addr.sockAddr6.sin6_family == AF_INET6)
Jeff Laytond5c56052008-12-01 18:42:33 -0500184 rc = ipv6_connect(server);
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500185 else
186 rc = ipv4_connect(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000187 if (rc) {
188 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700189 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 } else {
191 atomic_inc(&tcpSesReconnectCount);
192 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000193 if (server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700195 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000196 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 /* atomic_set(&server->inFlight,0);*/
198 wake_up(&server->response_q);
199 }
200 }
201 return rc;
202}
203
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000204/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700205 return codes:
206 0 not a transact2, or all data present
207 >0 transact2 with that much data missing
208 -EINVAL = invalid transact2
209
210 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000211static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700212{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000213 struct smb_t2_rsp *pSMBt;
214 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700215 int data_in_this_rsp;
216 int remaining;
217
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000218 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700219 return 0;
220
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000221 /* check for plausible wct, bcc and t2 data and parm sizes */
222 /* check for parm and data offset going beyond end of smb */
223 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Steve French467a8f82007-06-27 22:41:32 +0000224 cFYI(1, ("invalid transact2 word count"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700225 return -EINVAL;
226 }
227
228 pSMBt = (struct smb_t2_rsp *)pSMB;
229
230 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
231 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
232
233 remaining = total_data_size - data_in_this_rsp;
234
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000235 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700236 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000237 else if (remaining < 0) {
Steve French467a8f82007-06-27 22:41:32 +0000238 cFYI(1, ("total data %d smaller than data in frame %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700239 total_data_size, data_in_this_rsp));
240 return -EINVAL;
241 } else {
Steve French467a8f82007-06-27 22:41:32 +0000242 cFYI(1, ("missing %d bytes from transact2, check next response",
Steve Frenche4eb2952005-04-28 22:41:09 -0700243 remaining));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000244 if (total_data_size > maxBufSize) {
245 cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
246 total_data_size, maxBufSize));
247 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700248 }
249 return remaining;
250 }
251}
252
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000253static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700254{
255 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
256 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
257 int total_data_size;
258 int total_in_buf;
259 int remaining;
260 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000261 char *data_area_of_target;
262 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700263 __u16 byte_count;
264
265 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
266
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000267 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Steve French63135e02007-07-17 17:34:02 +0000268 cFYI(1, ("total data size of primary and secondary t2 differ"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700269 }
270
271 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
272
273 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000274
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000275 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700276 return -EINVAL;
277
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000278 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700279 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000280
Steve Frenche4eb2952005-04-28 22:41:09 -0700281 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000282 if (remaining < total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000283 cFYI(1, ("transact2 2nd response contains too much data"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700284 }
285
286 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000287 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700288 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
289 /* validate target area */
290
291 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000292 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700293
294 data_area_of_target += total_in_buf;
295
296 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000297 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700298 total_in_buf += total_in_buf2;
299 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
300 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
301 byte_count += total_in_buf2;
302 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
303
Steve French70ca7342005-09-22 16:32:06 -0700304 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700305 byte_count += total_in_buf2;
306
307 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000308
Steve French70ca7342005-09-22 16:32:06 -0700309 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700310
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000311 if (remaining == total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000312 cFYI(1, ("found the last secondary response"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700313 return 0; /* we are done */
314 } else /* more responses to go */
315 return 1;
316
317}
318
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319static int
320cifs_demultiplex_thread(struct TCP_Server_Info *server)
321{
322 int length;
323 unsigned int pdu_length, total_read;
324 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700325 struct smb_hdr *bigbuf = NULL;
326 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 struct msghdr smb_msg;
328 struct kvec iov;
329 struct socket *csocket = server->ssocket;
330 struct list_head *tmp;
331 struct cifsSesInfo *ses;
332 struct task_struct *task_to_wake = NULL;
333 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700334 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000335 bool isLargeBuf = false;
336 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700337 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 current->flags |= PF_MEMALLOC;
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700340 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400341
342 length = atomic_inc_return(&tcpSesAllocCount);
343 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000344 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
345 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700347 set_freezable();
Jeff Layton469ee612008-10-16 18:46:39 +0000348 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700349 if (try_to_freeze())
350 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700351 if (bigbuf == NULL) {
352 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000353 if (!bigbuf) {
354 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700355 msleep(3000);
356 /* retry will check if exiting */
357 continue;
358 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000359 } else if (isLargeBuf) {
360 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000361 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700363
364 if (smallbuf == NULL) {
365 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000366 if (!smallbuf) {
367 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700368 msleep(1000);
369 /* retry will check if exiting */
370 continue;
371 }
372 /* beginning of smb buffer is cleared in our buf_get */
373 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000374 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700375
Steve French4b18f2a2008-04-29 00:06:05 +0000376 isLargeBuf = false;
377 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700378 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 iov.iov_base = smb_buffer;
380 iov.iov_len = 4;
381 smb_msg.msg_control = NULL;
382 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000383 pdu_length = 4; /* enough to get RFC1001 header */
384incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 length =
386 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000387 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Jeff Layton469ee612008-10-16 18:46:39 +0000389 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 break;
391 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000392 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000394 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 csocket = server->ssocket;
396 continue;
397 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700398 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 allowing socket to clear and app threads to set
400 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc527c8a2008-11-03 20:46:21 +0000401 if (pdu_length < 4) {
402 iov.iov_base = (4 - pdu_length) +
403 (char *)smb_buffer;
404 iov.iov_len = pdu_length;
405 smb_msg.msg_control = NULL;
406 smb_msg.msg_controllen = 0;
Steve Frenchc18c7322007-10-17 18:01:11 +0000407 goto incomplete_rcv;
Steve Frenchc527c8a2008-11-03 20:46:21 +0000408 } else
Steve Frenchc18c7322007-10-17 18:01:11 +0000409 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000411 if (server->tcpStatus == CifsNew) {
412 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700413 /* some servers kill the TCP session rather than
414 returning an SMB negprot error, in which
415 case reconnecting here is not going to help,
416 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 break;
418 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000419 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000420 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 break;
422 }
Steve French467a8f82007-06-27 22:41:32 +0000423 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700424 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 cifs_reconnect(server);
426 csocket = server->ssocket;
427 wake_up(&server->response_q);
428 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000429 } else if (length < pdu_length) {
430 cFYI(1, ("requested %d bytes but only got %d bytes",
431 pdu_length, length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000432 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000433 msleep(1);
434 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 }
Steve French67010fb2005-04-28 22:41:09 -0700436
Steve French70ca7342005-09-22 16:32:06 -0700437 /* The right amount was read from socket - 4 bytes */
438 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700439
Steve French70ca7342005-09-22 16:32:06 -0700440 /* the first byte big endian of the length field,
441 is actually not part of the length but the type
442 with the most common, zero, as regular data */
443 temp = *((char *) smb_buffer);
444
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000445 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700446 but we convert it here so it is always manipulated
447 as host byte order */
Harvey Harrison5ca33c62008-07-23 17:45:58 -0700448 pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700449 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700450
Steve French467a8f82007-06-27 22:41:32 +0000451 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700452
453 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000454 continue;
Steve French70ca7342005-09-22 16:32:06 -0700455 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000456 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700457 continue;
Steve French70ca7342005-09-22 16:32:06 -0700458 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000459 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700460 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000461 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700462 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000463 if (server->tcpStatus == CifsNew) {
464 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700465 ret of smb negprot error) reconnecting
466 not going to help, ret error to mount */
467 break;
468 } else {
469 /* give server a second to
470 clean up before reconnect attempt */
471 msleep(1000);
472 /* always try 445 first on reconnect
473 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000474 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700475 since we do not begin with RFC1001
476 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000477 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700478 htons(CIFS_PORT);
479 cifs_reconnect(server);
480 csocket = server->ssocket;
481 wake_up(&server->response_q);
482 continue;
483 }
Steve French70ca7342005-09-22 16:32:06 -0700484 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000485 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700486 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
487 length);
Steve French46810cb2005-04-28 22:41:09 -0700488 cifs_reconnect(server);
489 csocket = server->ssocket;
490 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700491 }
492
493 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000494 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000495 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700496 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700497 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700498 cifs_reconnect(server);
499 csocket = server->ssocket;
500 wake_up(&server->response_q);
501 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000502 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700503
504 /* else length ok */
505 reconnect = 0;
506
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000507 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000508 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700509 memcpy(bigbuf, smallbuf, 4);
510 smb_buffer = bigbuf;
511 }
512 length = 0;
513 iov.iov_base = 4 + (char *)smb_buffer;
514 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000515 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700516 total_read += length) {
517 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
518 pdu_length - total_read, 0);
Jeff Layton469ee612008-10-16 18:46:39 +0000519 if ((server->tcpStatus == CifsExiting) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700520 (length == -EINTR)) {
521 /* then will exit */
522 reconnect = 2;
523 break;
524 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700525 cifs_reconnect(server);
526 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000527 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700528 /* Now we will reread sock */
529 reconnect = 1;
530 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000531 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700532 (length == -EAGAIN)) {
533 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000534 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700535 threads to set tcpStatus
536 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000537 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700538 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700539 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000540 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700541 pdu_length - total_read));
542 cifs_reconnect(server);
543 csocket = server->ssocket;
544 reconnect = 1;
545 break;
Steve French46810cb2005-04-28 22:41:09 -0700546 }
547 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000548 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700549 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000550 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700551 continue;
552
553 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000554
Steve Frenche4eb2952005-04-28 22:41:09 -0700555
556 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000557 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700558 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700559 continue;
560 }
561
562
563 task_to_wake = NULL;
564 spin_lock(&GlobalMid_Lock);
565 list_for_each(tmp, &server->pending_mid_q) {
566 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
567
Steve French50c2f752007-07-13 00:33:32 +0000568 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700569 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
570 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000571 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700572 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000573 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000574 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700575 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000576 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700577 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000578 mid_entry->multiRsp =
579 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700580 break;
581 } else {
582 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000583 mid_entry->multiEnd =
584 true;
Steve French50c2f752007-07-13 00:33:32 +0000585 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700586 }
587 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000588 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700589 cERROR(1,("1st trans2 resp needs bigbuf"));
590 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000591 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700592 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700593 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700594 mid_entry->resp_buf =
595 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000596 mid_entry->largeBuf =
597 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700598 bigbuf = NULL;
599 }
600 }
601 break;
Steve French50c2f752007-07-13 00:33:32 +0000602 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700603 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000604 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700605multi_t2_fnd:
606 task_to_wake = mid_entry->tsk;
607 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700608#ifdef CONFIG_CIFS_STATS2
609 mid_entry->when_received = jiffies;
610#endif
Steve French3a5ff612006-07-14 22:37:11 +0000611 /* so we do not time out requests to server
612 which is still responding (since server could
613 be busy but not dead) */
614 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700615 break;
616 }
617 }
618 spin_unlock(&GlobalMid_Lock);
619 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700620 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000621 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700622 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000623 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700624 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000625 else
Steve Frenchcd634992005-04-28 22:41:10 -0700626 smallbuf = NULL;
627 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700628 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000629 } else if (!is_valid_oplock_break(smb_buffer, server) &&
630 !isMultiRsp) {
Steve French50c2f752007-07-13 00:33:32 +0000631 cERROR(1, ("No task to wake, unknown frame received! "
632 "NumMids %d", midCount.counter));
633 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700634 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000635#ifdef CONFIG_CIFS_DEBUG2
636 cifs_dump_detail(smb_buffer);
637 cifs_dump_mids(server);
638#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000639
Steve Frenche4eb2952005-04-28 22:41:09 -0700640 }
641 } /* end while !EXITING */
642
Jeff Laytone7ddee92008-11-14 13:44:38 -0500643 /* take it off the list, if it's not already */
644 write_lock(&cifs_tcp_ses_lock);
645 list_del_init(&server->tcp_ses_list);
646 write_unlock(&cifs_tcp_ses_lock);
647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 spin_lock(&GlobalMid_Lock);
649 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000650 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000651 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000652
Steve French31ca3bc2005-04-28 22:41:11 -0700653 /* check if we have blocked requests that need to free */
654 /* Note that cifs_max_pending is normally 50, but
655 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000656 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000657 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700658 atomic_set(&server->inFlight, cifs_max_pending - 1);
659 /* We do not want to set the max_pending too low or we
660 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000662 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700664 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 to the same server - they now will see the session is in exit state
666 and get out of SendReceive. */
667 wake_up_all(&server->request_q);
668 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700669 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000670
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000671 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 sock_release(csocket);
673 server->ssocket = NULL;
674 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700675 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000676 cifs_buf_release(bigbuf);
677 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700678 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Jeff Layton14fbf502008-11-14 13:53:46 -0500680 /*
681 * BB: we shouldn't have to do any of this. It shouldn't be
682 * possible to exit from the thread with active SMB sessions
683 */
684 read_lock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700686 /* loop through server session structures attached to this and
687 mark them dead */
Jeff Layton14fbf502008-11-14 13:53:46 -0500688 list_for_each(tmp, &server->smb_ses_list) {
689 ses = list_entry(tmp, struct cifsSesInfo,
690 smb_ses_list);
691 ses->status = CifsExiting;
692 ses->server = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500694 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700696 /* although we can not zero the server struct pointer yet,
697 since there are active requests which may depnd on them,
698 mark the corresponding SMB sessions as exiting too */
Jeff Layton14fbf502008-11-14 13:53:46 -0500699 list_for_each(tmp, &server->smb_ses_list) {
Steve French31ca3bc2005-04-28 22:41:11 -0700700 ses = list_entry(tmp, struct cifsSesInfo,
Jeff Layton14fbf502008-11-14 13:53:46 -0500701 smb_ses_list);
702 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700703 }
704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 spin_lock(&GlobalMid_Lock);
706 list_for_each(tmp, &server->pending_mid_q) {
707 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
708 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000709 cFYI(1, ("Clearing Mid 0x%x - waking up ",
710 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000712 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 }
715 }
716 spin_unlock(&GlobalMid_Lock);
Jeff Layton14fbf502008-11-14 13:53:46 -0500717 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700719 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 }
721
Steve Frenchf1914012005-08-18 09:37:34 -0700722 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000723 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700725 /* due to delays on oplock break requests, we need
726 to wait at least 45 seconds before giving up
727 on a request getting a response and going ahead
728 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700730 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 /* if threads still have not exited they are probably never
732 coming home not much else we can do but free the memory */
733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Steve French31ca3bc2005-04-28 22:41:11 -0700735 /* last chance to mark ses pointers invalid
736 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000737 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700738 kernel thread explicitly this might happen) */
Jeff Layton14fbf502008-11-14 13:53:46 -0500739 /* BB: This shouldn't be necessary, see above */
740 read_lock(&cifs_tcp_ses_lock);
741 list_for_each(tmp, &server->smb_ses_list) {
742 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
743 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700744 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500745 read_unlock(&cifs_tcp_ses_lock);
Steve French31ca3bc2005-04-28 22:41:11 -0700746
Jeff Laytonc359cf32007-11-16 22:22:06 +0000747 kfree(server->hostname);
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400748 task_to_wake = xchg(&server->tsk, NULL);
Steve French31ca3bc2005-04-28 22:41:11 -0700749 kfree(server);
Jeff Layton93d0ec82008-08-02 08:00:48 -0400750
751 length = atomic_dec_return(&tcpSesAllocCount);
Steve French26f57362007-08-30 22:09:15 +0000752 if (length > 0)
753 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
754 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000755
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400756 /* if server->tsk was NULL then wait for a signal before exiting */
757 if (!task_to_wake) {
758 set_current_state(TASK_INTERRUPTIBLE);
759 while (!signal_pending(current)) {
760 schedule();
761 set_current_state(TASK_INTERRUPTIBLE);
762 }
763 set_current_state(TASK_RUNNING);
764 }
765
Jeff Layton0468a2c2008-12-01 07:09:35 -0500766 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767}
768
Jeff Laytonc359cf32007-11-16 22:22:06 +0000769/* extract the host portion of the UNC string */
770static char *
771extract_hostname(const char *unc)
772{
773 const char *src;
774 char *dst, *delim;
775 unsigned int len;
776
777 /* skip double chars at beginning of string */
778 /* BB: check validity of these bytes? */
779 src = unc + 2;
780
781 /* delimiter between hostname and sharename is always '\\' now */
782 delim = strchr(src, '\\');
783 if (!delim)
784 return ERR_PTR(-EINVAL);
785
786 len = delim - src;
787 dst = kmalloc((len + 1), GFP_KERNEL);
788 if (dst == NULL)
789 return ERR_PTR(-ENOMEM);
790
791 memcpy(dst, src, len);
792 dst[len] = '\0';
793
794 return dst;
795}
796
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797static int
Steve French50c2f752007-07-13 00:33:32 +0000798cifs_parse_mount_options(char *options, const char *devname,
799 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800{
801 char *value;
802 char *data;
803 unsigned int temp_len, i, j;
804 char separator[2];
805
806 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000807 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
Linus Torvalds12e36b22006-10-13 08:09:29 -0700809 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000810 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000811 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700812 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000813 int n = strnlen(nodename, 15);
814 memset(vol->source_rfc1001_name, 0x20, 15);
815 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000816 /* does not have to be perfect mapping since field is
817 informational, only used for servers that do not support
818 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700819 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 }
822 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700823 /* null target name indicates to use *SMBSERVR default called name
824 if we end up sending RFC1001 session initialize */
825 vol->target_rfc1001_name[0] = 0;
David Howellsa001e5b2008-11-14 10:38:47 +1100826 vol->linux_uid = current_uid(); /* use current_euid() instead? */
827 vol->linux_gid = current_gid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 vol->dir_mode = S_IRWXUGO;
829 /* 2767 perms indicate mandatory locking support */
Steve French7505e052007-11-01 18:03:01 +0000830 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
832 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Steve French4b18f2a2008-04-29 00:06:05 +0000833 vol->rw = true;
Jeremy Allisonac670552005-06-22 17:26:35 -0700834 /* default is always to request posix paths. */
835 vol->posix_paths = 1;
836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 if (!options)
838 return 1;
839
Steve French50c2f752007-07-13 00:33:32 +0000840 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000841 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 separator[0] = options[4];
843 options += 5;
844 } else {
Steve French467a8f82007-06-27 22:41:32 +0000845 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 }
847 }
Steve French50c2f752007-07-13 00:33:32 +0000848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 while ((data = strsep(&options, separator)) != NULL) {
850 if (!*data)
851 continue;
852 if ((value = strchr(data, '=')) != NULL)
853 *value++ = '\0';
854
Steve French50c2f752007-07-13 00:33:32 +0000855 /* Have to parse this before we parse for "user" */
856 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000858 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 vol->no_xattr = 1;
860 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000861 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 printk(KERN_WARNING
863 "CIFS: invalid or missing username\n");
864 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000865 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000866 /* null user, ie anonymous, authentication */
867 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 }
869 if (strnlen(value, 200) < 200) {
870 vol->username = value;
871 } else {
872 printk(KERN_WARNING "CIFS: username too long\n");
873 return 1;
874 }
875 } else if (strnicmp(data, "pass", 4) == 0) {
876 if (!value) {
877 vol->password = NULL;
878 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000879 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 /* check if string begins with double comma
881 since that would mean the password really
882 does start with a comma, and would not
883 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000884 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 vol->password = NULL;
886 continue;
887 }
888 }
889 temp_len = strlen(value);
890 /* removed password length check, NTLM passwords
891 can be arbitrarily long */
892
Steve French50c2f752007-07-13 00:33:32 +0000893 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 prematurely null terminated. Commas in password are
895 specified across the cifs mount interface by a double
896 comma ie ,, and a comma used as in other cases ie ','
897 as a parameter delimiter/separator is single and due
898 to the strsep above is temporarily zeroed. */
899
900 /* NB: password legally can have multiple commas and
901 the only illegal character in a password is null */
902
Steve French50c2f752007-07-13 00:33:32 +0000903 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700904 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 /* reinsert comma */
906 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000907 temp_len += 2; /* move after second comma */
908 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000910 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700911 separator[0]) {
912 /* skip second comma */
913 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000914 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 /* single comma indicating start
916 of next parm */
917 break;
918 }
919 }
920 temp_len++;
921 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000922 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 options = NULL;
924 } else {
925 value[temp_len] = 0;
926 /* point option to start of next parm */
927 options = value + temp_len + 1;
928 }
Steve French50c2f752007-07-13 00:33:32 +0000929 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 double commas to singles. Note that this ends up
931 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700932 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000933 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000934 printk(KERN_WARNING "CIFS: no memory "
935 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700936 return 1;
937 }
Steve French50c2f752007-07-13 00:33:32 +0000938 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000940 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700941 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 /* skip second comma */
943 i++;
944 }
945 }
946 vol->password[j] = 0;
947 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700948 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000949 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000950 printk(KERN_WARNING "CIFS: no memory "
951 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700952 return 1;
953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 strcpy(vol->password, value);
955 }
956 } else if (strnicmp(data, "ip", 2) == 0) {
957 if (!value || !*value) {
958 vol->UNCip = NULL;
959 } else if (strnlen(value, 35) < 35) {
960 vol->UNCip = value;
961 } else {
Steve French50c2f752007-07-13 00:33:32 +0000962 printk(KERN_WARNING "CIFS: ip address "
963 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return 1;
965 }
Steve French50c2f752007-07-13 00:33:32 +0000966 } else if (strnicmp(data, "sec", 3) == 0) {
967 if (!value || !*value) {
968 cERROR(1, ("no security value specified"));
969 continue;
970 } else if (strnicmp(value, "krb5i", 5) == 0) {
971 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000972 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800973 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000974 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
975 CIFSSEC_MAY_KRB5; */
976 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800977 return 1;
978 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000979 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800980 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000981 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000982 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800983 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000984 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800985 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000986 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000987 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800988 } else if (strnicmp(value, "ntlm", 4) == 0) {
989 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000990 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800991 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000992 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000993 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000994#ifdef CONFIG_CIFS_WEAK_PW_HASH
995 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000996 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000997#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800998 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000999 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +00001000 } else {
1001 cERROR(1, ("bad security option: %s", value));
1002 return 1;
1003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 } else if ((strnicmp(data, "unc", 3) == 0)
1005 || (strnicmp(data, "target", 6) == 0)
1006 || (strnicmp(data, "path", 4) == 0)) {
1007 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001008 printk(KERN_WARNING "CIFS: invalid path to "
1009 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 return 1; /* needs_arg; */
1011 }
1012 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001013 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001014 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001016 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (strncmp(vol->UNC, "//", 2) == 0) {
1018 vol->UNC[0] = '\\';
1019 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001020 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001022 "CIFS: UNC Path does not begin "
1023 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 return 1;
1025 }
1026 } else {
1027 printk(KERN_WARNING "CIFS: UNC name too long\n");
1028 return 1;
1029 }
1030 } else if ((strnicmp(data, "domain", 3) == 0)
1031 || (strnicmp(data, "workgroup", 5) == 0)) {
1032 if (!value || !*value) {
1033 printk(KERN_WARNING "CIFS: invalid domain name\n");
1034 return 1; /* needs_arg; */
1035 }
1036 /* BB are there cases in which a comma can be valid in
1037 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001038 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 vol->domainname = value;
1040 cFYI(1, ("Domain name set"));
1041 } else {
Steve French50c2f752007-07-13 00:33:32 +00001042 printk(KERN_WARNING "CIFS: domain name too "
1043 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 return 1;
1045 }
Steve French50c2f752007-07-13 00:33:32 +00001046 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1047 if (!value || !*value) {
1048 printk(KERN_WARNING
1049 "CIFS: invalid path prefix\n");
1050 return 1; /* needs_argument */
1051 }
1052 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001053 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001054 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001055 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1056 if (vol->prepath == NULL)
1057 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001058 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001059 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001060 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001061 } else
Steve French50c2f752007-07-13 00:33:32 +00001062 strcpy(vol->prepath, value);
1063 cFYI(1, ("prefix path %s", vol->prepath));
1064 } else {
1065 printk(KERN_WARNING "CIFS: prefix too long\n");
1066 return 1;
1067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 } else if (strnicmp(data, "iocharset", 9) == 0) {
1069 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001070 printk(KERN_WARNING "CIFS: invalid iocharset "
1071 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 return 1; /* needs_arg; */
1073 }
1074 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001075 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001077 /* if iocharset not set then load_nls_default
1078 is used by caller */
1079 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 } else {
Steve French63135e02007-07-17 17:34:02 +00001081 printk(KERN_WARNING "CIFS: iocharset name "
1082 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 return 1;
1084 }
1085 } else if (strnicmp(data, "uid", 3) == 0) {
1086 if (value && *value) {
1087 vol->linux_uid =
1088 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001089 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 }
1091 } else if (strnicmp(data, "gid", 3) == 0) {
1092 if (value && *value) {
1093 vol->linux_gid =
1094 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001095 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 }
1097 } else if (strnicmp(data, "file_mode", 4) == 0) {
1098 if (value && *value) {
1099 vol->file_mode =
1100 simple_strtoul(value, &value, 0);
1101 }
1102 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1103 if (value && *value) {
1104 vol->dir_mode =
1105 simple_strtoul(value, &value, 0);
1106 }
1107 } else if (strnicmp(data, "dirmode", 4) == 0) {
1108 if (value && *value) {
1109 vol->dir_mode =
1110 simple_strtoul(value, &value, 0);
1111 }
1112 } else if (strnicmp(data, "port", 4) == 0) {
1113 if (value && *value) {
1114 vol->port =
1115 simple_strtoul(value, &value, 0);
1116 }
1117 } else if (strnicmp(data, "rsize", 5) == 0) {
1118 if (value && *value) {
1119 vol->rsize =
1120 simple_strtoul(value, &value, 0);
1121 }
1122 } else if (strnicmp(data, "wsize", 5) == 0) {
1123 if (value && *value) {
1124 vol->wsize =
1125 simple_strtoul(value, &value, 0);
1126 }
1127 } else if (strnicmp(data, "sockopt", 5) == 0) {
1128 if (value && *value) {
1129 vol->sockopt =
1130 simple_strtoul(value, &value, 0);
1131 }
1132 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1133 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001134 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 } else {
Steve French50c2f752007-07-13 00:33:32 +00001136 memset(vol->source_rfc1001_name, 0x20, 15);
1137 for (i = 0; i < 15; i++) {
1138 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 valid in this workstation netbios name (and need
1140 special handling)? */
1141
1142 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001143 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 break;
Steve French50c2f752007-07-13 00:33:32 +00001145 else
1146 vol->source_rfc1001_name[i] =
1147 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
1149 /* The string has 16th byte zero still from
1150 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001151 if ((i == 15) && (value[i] != 0))
1152 printk(KERN_WARNING "CIFS: netbiosname"
1153 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001154 }
1155 } else if (strnicmp(data, "servern", 7) == 0) {
1156 /* servernetbiosname specified override *SMBSERVER */
1157 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001158 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001159 } else {
1160 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001161 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001162
Steve French50c2f752007-07-13 00:33:32 +00001163 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001164 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001165 valid in this workstation netbios name
1166 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001167
Steve French50c2f752007-07-13 00:33:32 +00001168 /* user or mount helper must uppercase
1169 the netbiosname */
1170 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001171 break;
1172 else
Steve French50c2f752007-07-13 00:33:32 +00001173 vol->target_rfc1001_name[i] =
1174 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001175 }
1176 /* The string has 16th byte zero still from
1177 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001178 if ((i == 15) && (value[i] != 0))
1179 printk(KERN_WARNING "CIFS: server net"
1180 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 }
1182 } else if (strnicmp(data, "credentials", 4) == 0) {
1183 /* ignore */
1184 } else if (strnicmp(data, "version", 3) == 0) {
1185 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001186 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 /* ignore */
1188 } else if (strnicmp(data, "rw", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001189 vol->rw = true;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001190 } else if (strnicmp(data, "noblocksend", 11) == 0) {
1191 vol->noblocksnd = 1;
1192 } else if (strnicmp(data, "noautotune", 10) == 0) {
1193 vol->noautotune = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 } else if ((strnicmp(data, "suid", 4) == 0) ||
1195 (strnicmp(data, "nosuid", 6) == 0) ||
1196 (strnicmp(data, "exec", 4) == 0) ||
1197 (strnicmp(data, "noexec", 6) == 0) ||
1198 (strnicmp(data, "nodev", 5) == 0) ||
1199 (strnicmp(data, "noauto", 6) == 0) ||
1200 (strnicmp(data, "dev", 3) == 0)) {
1201 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001202 uses these opts to set flags, and the flags are read
1203 by the kernel vfs layer before we get here (ie
1204 before read super) so there is no point trying to
1205 parse these options again and set anything and it
1206 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 continue;
1208 } else if (strnicmp(data, "ro", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001209 vol->rw = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 } else if (strnicmp(data, "hard", 4) == 0) {
1211 vol->retry = 1;
1212 } else if (strnicmp(data, "soft", 4) == 0) {
1213 vol->retry = 0;
1214 } else if (strnicmp(data, "perm", 4) == 0) {
1215 vol->noperm = 0;
1216 } else if (strnicmp(data, "noperm", 6) == 0) {
1217 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001218 } else if (strnicmp(data, "mapchars", 8) == 0) {
1219 vol->remap = 1;
1220 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1221 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001222 } else if (strnicmp(data, "sfu", 3) == 0) {
1223 vol->sfu_emul = 1;
1224 } else if (strnicmp(data, "nosfu", 5) == 0) {
1225 vol->sfu_emul = 0;
Steve French2c1b8612008-10-16 18:35:21 +00001226 } else if (strnicmp(data, "nodfs", 5) == 0) {
1227 vol->nodfs = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -07001228 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1229 vol->posix_paths = 1;
1230 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1231 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001232 } else if (strnicmp(data, "nounix", 6) == 0) {
1233 vol->no_linux_ext = 1;
1234 } else if (strnicmp(data, "nolinux", 7) == 0) {
1235 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001236 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001237 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001238 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001239 } else if (strnicmp(data, "brl", 3) == 0) {
1240 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001241 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001242 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001243 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001244 /* turn off mandatory locking in mode
1245 if remote locking is turned off since the
1246 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001247 if (vol->file_mode ==
1248 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001249 vol->file_mode = S_IALLUGO;
Steve French13a6e422008-12-02 17:24:33 +00001250 } else if (strnicmp(data, "forcemandatorylock", 9) == 0) {
1251 /* will take the shorter form "forcemand" as well */
1252 /* This mount option will force use of mandatory
1253 (DOS/Windows style) byte range locks, instead of
1254 using posix advisory byte range locks, even if the
1255 Unix extensions are available and posix locks would
1256 be supported otherwise. If Unix extensions are not
1257 negotiated this has no effect since mandatory locks
1258 would be used (mandatory locks is all that those
1259 those servers support) */
1260 vol->mand_lock = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 } else if (strnicmp(data, "setuids", 7) == 0) {
1262 vol->setuids = 1;
1263 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1264 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001265 } else if (strnicmp(data, "dynperm", 7) == 0) {
1266 vol->dynperm = true;
1267 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1268 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 } else if (strnicmp(data, "nohard", 6) == 0) {
1270 vol->retry = 0;
1271 } else if (strnicmp(data, "nosoft", 6) == 0) {
1272 vol->retry = 1;
1273 } else if (strnicmp(data, "nointr", 6) == 0) {
1274 vol->intr = 0;
1275 } else if (strnicmp(data, "intr", 4) == 0) {
1276 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001277 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001279 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001281 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001282 vol->cifs_acl = 1;
1283 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1284 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001285 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001287 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 vol->no_psx_acl = 1;
Steve French84210e92008-10-23 04:42:37 +00001289#ifdef CONFIG_CIFS_EXPERIMENTAL
1290 } else if (strnicmp(data, "locallease", 6) == 0) {
1291 vol->local_lease = 1;
1292#endif
Steve French50c2f752007-07-13 00:33:32 +00001293 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001294 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001295 } else if (strnicmp(data, "seal", 4) == 0) {
1296 /* we do not do the following in secFlags because seal
1297 is a per tree connection (mount) not a per socket
1298 or per-smb connection option in the protocol */
1299 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1300 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001301 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001303 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001305 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 if (!value || !*value) {
1307 vol->in6_addr = NULL;
1308 } else if (strnlen(value, 49) == 48) {
1309 vol->in6_addr = value;
1310 } else {
Steve French50c2f752007-07-13 00:33:32 +00001311 printk(KERN_WARNING "CIFS: ip v6 address not "
1312 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 return 1;
1314 }
1315 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001316 printk(KERN_WARNING "CIFS: Mount option noac not "
1317 "supported. Instead set "
1318 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 } else
Steve French50c2f752007-07-13 00:33:32 +00001320 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1321 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 }
1323 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001324 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001325 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1326 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 return 1;
1328 }
1329 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001330 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001331 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001333 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 if (strncmp(vol->UNC, "//", 2) == 0) {
1335 vol->UNC[0] = '\\';
1336 vol->UNC[1] = '\\';
1337 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001338 printk(KERN_WARNING "CIFS: UNC Path does not "
1339 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 return 1;
1341 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001342 value = strpbrk(vol->UNC+2, "/\\");
1343 if (value)
1344 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 } else {
1346 printk(KERN_WARNING "CIFS: UNC name too long\n");
1347 return 1;
1348 }
1349 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001350 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 vol->UNCip = &vol->UNC[2];
1352
1353 return 0;
1354}
1355
Jeff Laytone7ddee92008-11-14 13:44:38 -05001356static struct TCP_Server_Info *
1357cifs_find_tcp_session(struct sockaddr *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358{
1359 struct list_head *tmp;
Jeff Laytone7ddee92008-11-14 13:44:38 -05001360 struct TCP_Server_Info *server;
1361 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
1362 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Jeff Laytone7ddee92008-11-14 13:44:38 -05001364 write_lock(&cifs_tcp_ses_lock);
1365 list_for_each(tmp, &cifs_tcp_ses_list) {
1366 server = list_entry(tmp, struct TCP_Server_Info,
1367 tcp_ses_list);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001368 /*
1369 * the demux thread can exit on its own while still in CifsNew
1370 * so don't accept any sockets in that state. Since the
1371 * tcpStatus never changes back to CifsNew it's safe to check
1372 * for this without a lock.
1373 */
1374 if (server->tcpStatus == CifsNew)
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001375 continue;
Steve French50c2f752007-07-13 00:33:32 +00001376
Jeff Laytone7ddee92008-11-14 13:44:38 -05001377 if (addr->sa_family == AF_INET &&
1378 (addr4->sin_addr.s_addr !=
1379 server->addr.sockAddr.sin_addr.s_addr))
1380 continue;
1381 else if (addr->sa_family == AF_INET6 &&
1382 memcmp(&server->addr.sockAddr6.sin6_addr,
1383 &addr6->sin6_addr, sizeof(addr6->sin6_addr)))
1384 continue;
Steve French50c2f752007-07-13 00:33:32 +00001385
Jeff Laytone7ddee92008-11-14 13:44:38 -05001386 ++server->srv_count;
1387 write_unlock(&cifs_tcp_ses_lock);
Steve Frenchd82c2df2008-11-15 00:07:26 +00001388 cFYI(1, ("Existing tcp session with server found"));
Jeff Laytone7ddee92008-11-14 13:44:38 -05001389 return server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 }
Jeff Laytone7ddee92008-11-14 13:44:38 -05001391 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 return NULL;
1393}
1394
Jeff Layton14fbf502008-11-14 13:53:46 -05001395static void
Jeff Laytone7ddee92008-11-14 13:44:38 -05001396cifs_put_tcp_session(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001398 struct task_struct *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
Jeff Laytone7ddee92008-11-14 13:44:38 -05001400 write_lock(&cifs_tcp_ses_lock);
1401 if (--server->srv_count > 0) {
1402 write_unlock(&cifs_tcp_ses_lock);
1403 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001405
Jeff Laytone7ddee92008-11-14 13:44:38 -05001406 list_del_init(&server->tcp_ses_list);
1407 write_unlock(&cifs_tcp_ses_lock);
1408
1409 spin_lock(&GlobalMid_Lock);
1410 server->tcpStatus = CifsExiting;
1411 spin_unlock(&GlobalMid_Lock);
1412
1413 task = xchg(&server->tsk, NULL);
1414 if (task)
1415 force_sig(SIGKILL, task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416}
1417
Jeff Layton63c038c2008-12-01 18:41:46 -05001418static struct TCP_Server_Info *
1419cifs_get_tcp_session(struct smb_vol *volume_info)
1420{
1421 struct TCP_Server_Info *tcp_ses = NULL;
1422 struct sockaddr addr;
1423 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
1424 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
1425 int rc;
1426
1427 memset(&addr, 0, sizeof(struct sockaddr));
1428
1429 if (volume_info->UNCip && volume_info->UNC) {
1430 rc = cifs_inet_pton(AF_INET, volume_info->UNCip,
1431 &sin_server->sin_addr.s_addr);
1432
1433 if (rc <= 0) {
1434 /* not ipv4 address, try ipv6 */
1435 rc = cifs_inet_pton(AF_INET6, volume_info->UNCip,
1436 &sin_server6->sin6_addr.in6_u);
1437 if (rc > 0)
1438 addr.sa_family = AF_INET6;
1439 } else {
1440 addr.sa_family = AF_INET;
1441 }
1442
1443 if (rc <= 0) {
1444 /* we failed translating address */
1445 rc = -EINVAL;
1446 goto out_err;
1447 }
1448
1449 cFYI(1, ("UNC: %s ip: %s", volume_info->UNC,
1450 volume_info->UNCip));
1451 } else if (volume_info->UNCip) {
1452 /* BB using ip addr as tcp_ses name to connect to the
1453 DFS root below */
1454 cERROR(1, ("Connecting to DFS root not implemented yet"));
1455 rc = -EINVAL;
1456 goto out_err;
1457 } else /* which tcp_sess DFS root would we conect to */ {
1458 cERROR(1,
1459 ("CIFS mount error: No UNC path (e.g. -o "
1460 "unc=//192.168.1.100/public) specified"));
1461 rc = -EINVAL;
1462 goto out_err;
1463 }
1464
1465 /* see if we already have a matching tcp_ses */
1466 tcp_ses = cifs_find_tcp_session(&addr);
1467 if (tcp_ses)
1468 return tcp_ses;
1469
1470 tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1471 if (!tcp_ses) {
1472 rc = -ENOMEM;
1473 goto out_err;
1474 }
1475
1476 tcp_ses->hostname = extract_hostname(volume_info->UNC);
1477 if (IS_ERR(tcp_ses->hostname)) {
1478 rc = PTR_ERR(tcp_ses->hostname);
1479 goto out_err;
1480 }
1481
1482 tcp_ses->noblocksnd = volume_info->noblocksnd;
1483 tcp_ses->noautotune = volume_info->noautotune;
1484 atomic_set(&tcp_ses->inFlight, 0);
1485 init_waitqueue_head(&tcp_ses->response_q);
1486 init_waitqueue_head(&tcp_ses->request_q);
1487 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
1488 mutex_init(&tcp_ses->srv_mutex);
1489 memcpy(tcp_ses->workstation_RFC1001_name,
1490 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1491 memcpy(tcp_ses->server_RFC1001_name,
1492 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1493 tcp_ses->sequence_number = 0;
1494 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
1495 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
1496
1497 /*
1498 * at this point we are the only ones with the pointer
1499 * to the struct since the kernel thread not created yet
1500 * no need to spinlock this init of tcpStatus or srv_count
1501 */
1502 tcp_ses->tcpStatus = CifsNew;
1503 ++tcp_ses->srv_count;
1504
1505 if (addr.sa_family == AF_INET6) {
1506 cFYI(1, ("attempting ipv6 connect"));
1507 /* BB should we allow ipv6 on port 139? */
1508 /* other OS never observed in Wild doing 139 with v6 */
1509 memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
1510 sizeof(struct sockaddr_in6));
1511 sin_server6->sin6_port = htons(volume_info->port);
Jeff Laytond5c56052008-12-01 18:42:33 -05001512 rc = ipv6_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001513 } else {
1514 memcpy(&tcp_ses->addr.sockAddr, sin_server,
1515 sizeof(struct sockaddr_in));
1516 sin_server->sin_port = htons(volume_info->port);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001517 rc = ipv4_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001518 }
1519 if (rc < 0) {
1520 cERROR(1, ("Error connecting to socket. Aborting operation"));
1521 goto out_err;
1522 }
1523
1524 /*
1525 * since we're in a cifs function already, we know that
1526 * this will succeed. No need for try_module_get().
1527 */
1528 __module_get(THIS_MODULE);
1529 tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
1530 tcp_ses, "cifsd");
1531 if (IS_ERR(tcp_ses->tsk)) {
1532 rc = PTR_ERR(tcp_ses->tsk);
1533 cERROR(1, ("error %d create cifsd thread", rc));
1534 module_put(THIS_MODULE);
1535 goto out_err;
1536 }
1537
1538 /* thread spawned, put it on the list */
1539 write_lock(&cifs_tcp_ses_lock);
1540 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
1541 write_unlock(&cifs_tcp_ses_lock);
1542
1543 return tcp_ses;
1544
1545out_err:
1546 if (tcp_ses) {
1547 kfree(tcp_ses->hostname);
1548 if (tcp_ses->ssocket)
1549 sock_release(tcp_ses->ssocket);
1550 kfree(tcp_ses);
1551 }
1552 return ERR_PTR(rc);
1553}
1554
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555static struct cifsSesInfo *
Jeff Layton14fbf502008-11-14 13:53:46 -05001556cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557{
1558 struct list_head *tmp;
1559 struct cifsSesInfo *ses;
1560
Jeff Layton14fbf502008-11-14 13:53:46 -05001561 write_lock(&cifs_tcp_ses_lock);
1562 list_for_each(tmp, &server->smb_ses_list) {
1563 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
1564 if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 continue;
1566
Jeff Layton14fbf502008-11-14 13:53:46 -05001567 ++ses->ses_count;
1568 write_unlock(&cifs_tcp_ses_lock);
1569 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 }
Jeff Layton14fbf502008-11-14 13:53:46 -05001571 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 return NULL;
1573}
1574
Jeff Layton14fbf502008-11-14 13:53:46 -05001575static void
1576cifs_put_smb_ses(struct cifsSesInfo *ses)
1577{
1578 int xid;
1579 struct TCP_Server_Info *server = ses->server;
1580
1581 write_lock(&cifs_tcp_ses_lock);
1582 if (--ses->ses_count > 0) {
1583 write_unlock(&cifs_tcp_ses_lock);
1584 return;
1585 }
1586
1587 list_del_init(&ses->smb_ses_list);
1588 write_unlock(&cifs_tcp_ses_lock);
1589
1590 if (ses->status == CifsGood) {
1591 xid = GetXid();
1592 CIFSSMBLogoff(xid, ses);
1593 _FreeXid(xid);
1594 }
1595 sesInfoFree(ses);
1596 cifs_put_tcp_session(server);
1597}
1598
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599static struct cifsTconInfo *
Jeff Laytonf1987b42008-11-15 11:12:47 -05001600cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601{
1602 struct list_head *tmp;
1603 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
Jeff Laytonf1987b42008-11-15 11:12:47 -05001605 write_lock(&cifs_tcp_ses_lock);
1606 list_for_each(tmp, &ses->tcon_list) {
1607 tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
1608 if (tcon->tidStatus == CifsExiting)
1609 continue;
1610 if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 continue;
1612
Jeff Laytonf1987b42008-11-15 11:12:47 -05001613 ++tcon->tc_count;
1614 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 return tcon;
1616 }
Jeff Laytonf1987b42008-11-15 11:12:47 -05001617 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 return NULL;
1619}
1620
Jeff Laytonf1987b42008-11-15 11:12:47 -05001621static void
1622cifs_put_tcon(struct cifsTconInfo *tcon)
1623{
1624 int xid;
1625 struct cifsSesInfo *ses = tcon->ses;
1626
1627 write_lock(&cifs_tcp_ses_lock);
1628 if (--tcon->tc_count > 0) {
1629 write_unlock(&cifs_tcp_ses_lock);
1630 return;
1631 }
1632
1633 list_del_init(&tcon->tcon_list);
1634 write_unlock(&cifs_tcp_ses_lock);
1635
1636 xid = GetXid();
1637 CIFSSMBTDis(xid, tcon);
1638 _FreeXid(xid);
1639
1640 DeleteTconOplockQEntries(tcon);
1641 tconInfoFree(tcon);
1642 cifs_put_smb_ses(ses);
1643}
1644
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645int
Steve French50c2f752007-07-13 00:33:32 +00001646get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1647 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001648 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649{
1650 char *temp_unc;
1651 int rc = 0;
1652
1653 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001654 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
1656 if (pSesInfo->ipc_tid == 0) {
1657 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001658 strnlen(pSesInfo->serverName,
1659 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 + 1 + 4 /* slash IPC$ */ + 2,
1661 GFP_KERNEL);
1662 if (temp_unc == NULL)
1663 return -ENOMEM;
1664 temp_unc[0] = '\\';
1665 temp_unc[1] = '\\';
1666 strcpy(temp_unc + 2, pSesInfo->serverName);
1667 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1668 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1669 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001670 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 kfree(temp_unc);
1672 }
1673 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00001674 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001675 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00001676 /* BB map targetUNCs to dfs_info3 structures, here or
1677 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
1679 return rc;
1680}
1681
Jeff Layton09e50d52008-07-23 10:11:19 -04001682#ifdef CONFIG_DEBUG_LOCK_ALLOC
1683static struct lock_class_key cifs_key[2];
1684static struct lock_class_key cifs_slock_key[2];
1685
1686static inline void
1687cifs_reclassify_socket4(struct socket *sock)
1688{
1689 struct sock *sk = sock->sk;
1690 BUG_ON(sock_owned_by_user(sk));
1691 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
1692 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
1693}
1694
1695static inline void
1696cifs_reclassify_socket6(struct socket *sock)
1697{
1698 struct sock *sk = sock->sk;
1699 BUG_ON(sock_owned_by_user(sk));
1700 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
1701 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
1702}
1703#else
1704static inline void
1705cifs_reclassify_socket4(struct socket *sock)
1706{
1707}
1708
1709static inline void
1710cifs_reclassify_socket6(struct socket *sock)
1711{
1712}
1713#endif
1714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001716static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717{
Steve French50c2f752007-07-13 00:33:32 +00001718 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719
Steve French50c2f752007-07-13 00:33:32 +00001720 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 /* mask a nibble at a time and encode */
1722 target[j] = 'A' + (0x0F & (source[i] >> 4));
1723 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001724 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 }
1726
1727}
1728
1729
1730static int
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001731ipv4_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732{
1733 int rc = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001734 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 __be16 orig_port = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001736 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001738 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001739 rc = sock_create_kern(PF_INET, SOCK_STREAM,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001740 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001742 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001745
1746 /* BB other socket options to set KEEPALIVE, NODELAY? */
1747 cFYI(1, ("Socket created"));
1748 server->ssocket = socket;
1749 socket->sk->sk_allocation = GFP_NOFS;
1750 cifs_reclassify_socket4(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
1752
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001753 /* user overrode default port */
1754 if (server->addr.sockAddr.sin_port) {
1755 rc = socket->ops->connect(socket, (struct sockaddr *)
1756 &server->addr.sockAddr,
1757 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001759 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00001760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001762 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001763 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 later if fall back ports fail this time */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001765 orig_port = server->addr.sockAddr.sin_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
1767 /* do not retry on the same port we just failed on */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001768 if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) {
1769 server->addr.sockAddr.sin_port = htons(CIFS_PORT);
1770 rc = socket->ops->connect(socket,
1771 (struct sockaddr *)
1772 &server->addr.sockAddr,
1773 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001775 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 }
1777 }
1778 if (!connected) {
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001779 server->addr.sockAddr.sin_port = htons(RFC1001_PORT);
1780 rc = socket->ops->connect(socket, (struct sockaddr *)
1781 &server->addr.sockAddr,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001782 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001783 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001784 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 }
1786
1787 /* give up here - unless we want to retry on different
1788 protocol families some day */
1789 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001790 if (orig_port)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001791 server->addr.sockAddr.sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001792 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001793 sock_release(socket);
1794 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 return rc;
1796 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001797
1798
1799 /*
1800 * Eventually check for other socket options to change from
1801 * the default. sock_setsockopt not used because it expects
1802 * user space buffer
1803 */
1804 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00001805 socket->sk->sk_sndtimeo = 5 * HZ;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001806
Steve Frenchb387eae2005-10-10 14:21:15 -07001807 /* make the bufsizes depend on wsize/rsize and max requests */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001808 if (server->noautotune) {
1809 if (socket->sk->sk_sndbuf < (200 * 1024))
1810 socket->sk->sk_sndbuf = 200 * 1024;
1811 if (socket->sk->sk_rcvbuf < (140 * 1024))
1812 socket->sk->sk_rcvbuf = 140 * 1024;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001815 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1816 socket->sk->sk_sndbuf,
1817 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo));
1818
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 /* send RFC1001 sessinit */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001820 if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001822 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001824 struct rfc1002_session_packet *ses_init_buf;
1825 struct smb_hdr *smb_buf;
1826 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1827 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001828 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 ses_init_buf->trailer.session_req.called_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001830 if (server->server_RFC1001_name &&
1831 server->server_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05001832 rfc1002mangle(ses_init_buf->trailer.
1833 session_req.called_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001834 server->server_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05001835 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001836 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05001837 rfc1002mangle(ses_init_buf->trailer.
1838 session_req.called_name,
1839 DEFAULT_CIFS_CALLED_NAME,
1840 RFC1001_NAME_LEN_WITH_NULL);
Steve Frencha10faeb22005-08-22 21:38:31 -07001841
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 ses_init_buf->trailer.session_req.calling_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001843
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 /* calling name ends in null (byte 16) from old smb
1845 convention. */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001846 if (server->workstation_RFC1001_name &&
1847 server->workstation_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05001848 rfc1002mangle(ses_init_buf->trailer.
1849 session_req.calling_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001850 server->workstation_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05001851 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001852 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05001853 rfc1002mangle(ses_init_buf->trailer.
1854 session_req.calling_name,
1855 "LINUX_CIFS_CLNT",
1856 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001857
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 ses_init_buf->trailer.session_req.scope1 = 0;
1859 ses_init_buf->trailer.session_req.scope2 = 0;
1860 smb_buf = (struct smb_hdr *)ses_init_buf;
1861 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1862 smb_buf->smb_buf_length = 0x81000044;
Jeff Layton0496e022008-12-30 12:39:16 -05001863 rc = smb_send(server, smb_buf, 0x44);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001865 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001866 requires very short break before negprot
1867 presumably because not expecting negprot
1868 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001869 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001870 complicating the code and causes no
1871 significant slowing down on mount
1872 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 }
Steve French50c2f752007-07-13 00:33:32 +00001874 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001876
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 }
Steve French50c2f752007-07-13 00:33:32 +00001878
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 return rc;
1880}
1881
1882static int
Jeff Laytond5c56052008-12-01 18:42:33 -05001883ipv6_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884{
1885 int rc = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05001886 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 __be16 orig_port = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05001888 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
Jeff Laytond5c56052008-12-01 18:42:33 -05001890 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001891 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
Jeff Laytond5c56052008-12-01 18:42:33 -05001892 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001894 cERROR(1, ("Error %d creating ipv6 socket", rc));
Jeff Laytond5c56052008-12-01 18:42:33 -05001895 socket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 }
Jeff Laytond5c56052008-12-01 18:42:33 -05001898
1899 /* BB other socket options to set KEEPALIVE, NODELAY? */
1900 cFYI(1, ("ipv6 Socket created"));
1901 server->ssocket = socket;
1902 socket->sk->sk_allocation = GFP_NOFS;
1903 cifs_reclassify_socket6(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 }
1905
Jeff Laytond5c56052008-12-01 18:42:33 -05001906 /* user overrode default port */
1907 if (server->addr.sockAddr6.sin6_port) {
1908 rc = socket->ops->connect(socket,
1909 (struct sockaddr *) &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001910 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001912 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00001913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001915 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001916 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 later if fall back ports fail this time */
1918
Jeff Laytond5c56052008-12-01 18:42:33 -05001919 orig_port = server->addr.sockAddr6.sin6_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 /* do not retry on the same port we just failed on */
Jeff Laytond5c56052008-12-01 18:42:33 -05001921 if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) {
1922 server->addr.sockAddr6.sin6_port = htons(CIFS_PORT);
1923 rc = socket->ops->connect(socket, (struct sockaddr *)
1924 &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001925 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001927 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 }
1929 }
1930 if (!connected) {
Jeff Laytond5c56052008-12-01 18:42:33 -05001931 server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT);
1932 rc = socket->ops->connect(socket, (struct sockaddr *)
1933 &server->addr.sockAddr6,
1934 sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001935 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001936 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 }
1938
1939 /* give up here - unless we want to retry on different
1940 protocol families some day */
1941 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001942 if (orig_port)
Jeff Laytond5c56052008-12-01 18:42:33 -05001943 server->addr.sockAddr6.sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001944 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Jeff Laytond5c56052008-12-01 18:42:33 -05001945 sock_release(socket);
1946 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 return rc;
1948 }
Steve Frenchedf1ae42008-10-29 00:47:57 +00001949
Jeff Laytond5c56052008-12-01 18:42:33 -05001950 /*
1951 * Eventually check for other socket options to change from
1952 * the default. sock_setsockopt not used because it expects
1953 * user space buffer
1954 */
1955 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00001956 socket->sk->sk_sndtimeo = 5 * HZ;
Jeff Laytond5c56052008-12-01 18:42:33 -05001957 server->ssocket = socket;
Steve French50c2f752007-07-13 00:33:32 +00001958
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 return rc;
1960}
1961
Steve French50c2f752007-07-13 00:33:32 +00001962void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1963 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001964{
1965 /* if we are reconnecting then should we check to see if
1966 * any requested capabilities changed locally e.g. via
1967 * remount but we can not do much about it here
1968 * if they have (even if we could detect it by the following)
1969 * Perhaps we could add a backpointer to array of sb from tcon
1970 * or if we change to make all sb to same share the same
1971 * sb as NFS - then we only have one backpointer to sb.
1972 * What if we wanted to mount the server share twice once with
1973 * and once without posixacls or posix paths? */
1974 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001975
Steve Frenchc18c8422007-07-18 23:21:09 +00001976 if (vol_info && vol_info->no_linux_ext) {
1977 tcon->fsUnixInfo.Capability = 0;
1978 tcon->unix_ext = 0; /* Unix Extensions disabled */
1979 cFYI(1, ("Linux protocol extensions disabled"));
1980 return;
1981 } else if (vol_info)
1982 tcon->unix_ext = 1; /* Unix Extensions supported */
1983
1984 if (tcon->unix_ext == 0) {
1985 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1986 return;
1987 }
Steve French50c2f752007-07-13 00:33:32 +00001988
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001989 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001990 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001991
Steve French8af18972007-02-14 04:42:51 +00001992 /* check for reconnect case in which we do not
1993 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001994 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001995 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001996 originally at mount time */
1997 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1998 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001999 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2000 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
2001 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00002002 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002003 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2004 cERROR(1, ("possible reconnect error"));
2005 cERROR(1,
2006 ("server disabled POSIX path support"));
2007 }
Steve French8af18972007-02-14 04:42:51 +00002008 }
Steve French50c2f752007-07-13 00:33:32 +00002009
Steve French8af18972007-02-14 04:42:51 +00002010 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00002011 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00002012 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002013 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002014 cFYI(1, ("negotiated posix acl support"));
2015 if (sb)
Steve French8af18972007-02-14 04:42:51 +00002016 sb->s_flags |= MS_POSIXACL;
2017 }
2018
Steve French75865f8c2007-06-24 18:30:48 +00002019 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00002020 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002021 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002022 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00002023 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00002024 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00002025 CIFS_MOUNT_POSIX_PATHS;
2026 }
Steve French50c2f752007-07-13 00:33:32 +00002027
Steve French984acfe2007-04-26 16:42:50 +00002028 /* We might be setting the path sep back to a different
2029 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00002030 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00002031 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00002032 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00002033
2034 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
2035 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
2036 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00002037 cFYI(DBG2,
2038 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00002039 }
2040 }
Steve French50c2f752007-07-13 00:33:32 +00002041
2042
2043 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00002044#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00002045 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002046 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002047 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002048 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002049 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002050 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002051 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002052 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002053 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002054 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002055 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002056 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002057 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002058 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00002059#endif /* CIFS_DEBUG2 */
2060 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00002061 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00002062 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00002063 } else
Steve French5a44b312007-09-20 15:16:24 +00002064 cERROR(1, ("Negotiating Unix capabilities "
2065 "with the server failed. Consider "
2066 "mounting with the Unix Extensions\n"
2067 "disabled, if problems are found, "
2068 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00002069 "option."));
Steve French5a44b312007-09-20 15:16:24 +00002070
Steve French8af18972007-02-14 04:42:51 +00002071 }
2072 }
2073}
2074
Steve French03a143c2008-02-14 06:38:30 +00002075static void
2076convert_delimiter(char *path, char delim)
2077{
2078 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002079 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00002080
2081 if (path == NULL)
2082 return;
2083
Steve French582d21e2008-05-13 04:54:12 +00002084 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002085 old_delim = '\\';
2086 else
2087 old_delim = '/';
2088
Steve French03a143c2008-02-14 06:38:30 +00002089 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002090 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00002091 path[i] = delim;
2092 }
2093}
2094
Steve French3b795212008-11-13 19:45:32 +00002095static void setup_cifs_sb(struct smb_vol *pvolume_info,
2096 struct cifs_sb_info *cifs_sb)
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002097{
Steve French3b795212008-11-13 19:45:32 +00002098 if (pvolume_info->rsize > CIFSMaxBufSize) {
2099 cERROR(1, ("rsize %d too large, using MaxBufSize",
2100 pvolume_info->rsize));
2101 cifs_sb->rsize = CIFSMaxBufSize;
2102 } else if ((pvolume_info->rsize) &&
2103 (pvolume_info->rsize <= CIFSMaxBufSize))
2104 cifs_sb->rsize = pvolume_info->rsize;
2105 else /* default */
2106 cifs_sb->rsize = CIFSMaxBufSize;
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002107
Steve French3b795212008-11-13 19:45:32 +00002108 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
2109 cERROR(1, ("wsize %d too large, using 4096 instead",
2110 pvolume_info->wsize));
2111 cifs_sb->wsize = 4096;
2112 } else if (pvolume_info->wsize)
2113 cifs_sb->wsize = pvolume_info->wsize;
2114 else
2115 cifs_sb->wsize = min_t(const int,
2116 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2117 127*1024);
2118 /* old default of CIFSMaxBufSize was too small now
2119 that SMB Write2 can send multiple pages in kvec.
2120 RFC1001 does not describe what happens when frame
2121 bigger than 128K is sent so use that as max in
2122 conjunction with 52K kvec constraint on arch with 4K
2123 page size */
2124
2125 if (cifs_sb->rsize < 2048) {
2126 cifs_sb->rsize = 2048;
2127 /* Windows ME may prefer this */
2128 cFYI(1, ("readsize set to minimum: 2048"));
2129 }
2130 /* calculate prepath */
2131 cifs_sb->prepath = pvolume_info->prepath;
2132 if (cifs_sb->prepath) {
2133 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2134 /* we can not convert the / to \ in the path
2135 separators in the prefixpath yet because we do not
2136 know (until reset_cifs_unix_caps is called later)
2137 whether POSIX PATH CAP is available. We normalize
2138 the / to \ after reset_cifs_unix_caps is called */
2139 pvolume_info->prepath = NULL;
2140 } else
2141 cifs_sb->prepathlen = 0;
2142 cifs_sb->mnt_uid = pvolume_info->linux_uid;
2143 cifs_sb->mnt_gid = pvolume_info->linux_gid;
2144 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
2145 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
2146 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2147 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
2148
2149 if (pvolume_info->noperm)
2150 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
2151 if (pvolume_info->setuids)
2152 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
2153 if (pvolume_info->server_ino)
2154 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
2155 if (pvolume_info->remap)
2156 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
2157 if (pvolume_info->no_xattr)
2158 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
2159 if (pvolume_info->sfu_emul)
2160 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
2161 if (pvolume_info->nobrl)
2162 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French13a6e422008-12-02 17:24:33 +00002163 if (pvolume_info->mand_lock)
2164 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
Steve French3b795212008-11-13 19:45:32 +00002165 if (pvolume_info->cifs_acl)
2166 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2167 if (pvolume_info->override_uid)
2168 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2169 if (pvolume_info->override_gid)
2170 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2171 if (pvolume_info->dynperm)
2172 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
2173 if (pvolume_info->direct_io) {
2174 cFYI(1, ("mounting share using direct i/o"));
2175 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2176 }
2177
2178 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
2179 cERROR(1, ("mount option dynperm ignored if cifsacl "
2180 "mount option supported"));
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002181}
2182
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183int
2184cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2185 char *mount_data, const char *devname)
2186{
2187 int rc = 0;
2188 int xid;
Jeff Layton7586b762008-12-01 18:41:49 -05002189 struct smb_vol *volume_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 struct cifsSesInfo *pSesInfo = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 struct cifsTconInfo *tcon = NULL;
2192 struct TCP_Server_Info *srvTcp = NULL;
2193
2194 xid = GetXid();
2195
Jeff Layton7586b762008-12-01 18:41:49 -05002196 volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
2197 if (!volume_info) {
2198 rc = -ENOMEM;
2199 goto out;
2200 }
Steve French50c2f752007-07-13 00:33:32 +00002201
Jeff Layton7586b762008-12-01 18:41:49 -05002202 if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002203 rc = -EINVAL;
2204 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 }
2206
Jeff Layton7586b762008-12-01 18:41:49 -05002207 if (volume_info->nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002208 cFYI(1, ("null user"));
Jeff Layton7586b762008-12-01 18:41:49 -05002209 volume_info->username = "";
2210 } else if (volume_info->username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 /* BB fixme parse for domain name here */
Jeff Layton7586b762008-12-01 18:41:49 -05002212 cFYI(1, ("Username: %s", volume_info->username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08002214 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00002215 /* In userspace mount helper we can get user name from alternate
2216 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002217 rc = -EINVAL;
2218 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 }
2220
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
2222 /* this is needed for ASCII cp to Unicode converts */
Jeff Layton7586b762008-12-01 18:41:49 -05002223 if (volume_info->iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 cifs_sb->local_nls = load_nls_default();
2225 /* load_nls_default can not return null */
2226 } else {
Jeff Layton7586b762008-12-01 18:41:49 -05002227 cifs_sb->local_nls = load_nls(volume_info->iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002228 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002229 cERROR(1, ("CIFS mount error: iocharset %s not found",
Jeff Layton7586b762008-12-01 18:41:49 -05002230 volume_info->iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002231 rc = -ELIBACC;
2232 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 }
2234 }
2235
Jeff Layton63c038c2008-12-01 18:41:46 -05002236 /* get a reference to a tcp session */
Jeff Layton7586b762008-12-01 18:41:49 -05002237 srvTcp = cifs_get_tcp_session(volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05002238 if (IS_ERR(srvTcp)) {
2239 rc = PTR_ERR(srvTcp);
2240 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 }
2242
Jeff Layton7586b762008-12-01 18:41:49 -05002243 pSesInfo = cifs_find_smb_ses(srvTcp, volume_info->username);
Jeff Layton14fbf502008-11-14 13:53:46 -05002244 if (pSesInfo) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002245 cFYI(1, ("Existing smb sess found (status=%d)",
2246 pSesInfo->status));
Jeff Layton14fbf502008-11-14 13:53:46 -05002247 /*
2248 * The existing SMB session already has a reference to srvTcp,
2249 * so we can put back the extra one we got before
2250 */
2251 cifs_put_tcp_session(srvTcp);
2252
Steve French88e7d702008-01-03 17:37:09 +00002253 down(&pSesInfo->sesSem);
Steve French3b795212008-11-13 19:45:32 +00002254 if (pSesInfo->need_reconnect) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002255 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002256 rc = cifs_setup_session(xid, pSesInfo,
2257 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002258 }
Steve French88e7d702008-01-03 17:37:09 +00002259 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002261 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 pSesInfo = sesInfoAlloc();
Jeff Layton14fbf502008-11-14 13:53:46 -05002263 if (pSesInfo == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 rc = -ENOMEM;
Jeff Layton14fbf502008-11-14 13:53:46 -05002265 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 }
2267
Jeff Layton14fbf502008-11-14 13:53:46 -05002268 /* new SMB session uses our srvTcp ref */
2269 pSesInfo->server = srvTcp;
Jeff Layton63c038c2008-12-01 18:41:46 -05002270 if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6)
Linus Torvalds0191b622008-12-28 12:49:40 -08002271 sprintf(pSesInfo->serverName, "%pI6",
2272 &srvTcp->addr.sockAddr6.sin6_addr);
Jeff Layton8ecaf672008-12-01 15:23:50 -05002273 else
Linus Torvalds0191b622008-12-28 12:49:40 -08002274 sprintf(pSesInfo->serverName, "%pI4",
2275 &srvTcp->addr.sockAddr.sin_addr.s_addr);
Jeff Layton14fbf502008-11-14 13:53:46 -05002276
2277 write_lock(&cifs_tcp_ses_lock);
2278 list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
2279 write_unlock(&cifs_tcp_ses_lock);
2280
Jeff Layton7586b762008-12-01 18:41:49 -05002281 /* volume_info->password freed at unmount */
2282 if (volume_info->password) {
Jeff Layton00e485b2008-12-05 20:41:21 -05002283 pSesInfo->password = kstrdup(volume_info->password,
2284 GFP_KERNEL);
2285 if (!pSesInfo->password) {
2286 rc = -ENOMEM;
2287 goto mount_fail_check;
2288 }
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002289 }
Jeff Layton7586b762008-12-01 18:41:49 -05002290 if (volume_info->username)
2291 strncpy(pSesInfo->userName, volume_info->username,
Jeff Layton14fbf502008-11-14 13:53:46 -05002292 MAX_USERNAME_SIZE);
Jeff Layton7586b762008-12-01 18:41:49 -05002293 if (volume_info->domainname) {
2294 int len = strlen(volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002295 pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
2296 if (pSesInfo->domainName)
2297 strcpy(pSesInfo->domainName,
Jeff Layton7586b762008-12-01 18:41:49 -05002298 volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002299 }
Jeff Layton7586b762008-12-01 18:41:49 -05002300 pSesInfo->linux_uid = volume_info->linux_uid;
2301 pSesInfo->overrideSecFlg = volume_info->secFlg;
Jeff Layton14fbf502008-11-14 13:53:46 -05002302 down(&pSesInfo->sesSem);
2303
2304 /* BB FIXME need to pass vol->secFlgs BB */
2305 rc = cifs_setup_session(xid, pSesInfo,
2306 cifs_sb->local_nls);
2307 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 }
Steve French50c2f752007-07-13 00:33:32 +00002309
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 /* search for existing tcon to this server share */
2311 if (!rc) {
Jeff Layton7586b762008-12-01 18:41:49 -05002312 setup_cifs_sb(volume_info, cifs_sb);
Steve French0ae0efa2005-10-10 10:57:19 -07002313
Jeff Layton7586b762008-12-01 18:41:49 -05002314 tcon = cifs_find_tcon(pSesInfo, volume_info->UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002316 cFYI(1, ("Found match on UNC path"));
Jeff Laytonf1987b42008-11-15 11:12:47 -05002317 /* existing tcon already has a reference */
2318 cifs_put_smb_ses(pSesInfo);
Jeff Layton7586b762008-12-01 18:41:49 -05002319 if (tcon->seal != volume_info->seal)
Steve French95b1cb92008-05-15 16:44:38 +00002320 cERROR(1, ("transport encryption setting "
2321 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 } else {
2323 tcon = tconInfoAlloc();
Steve French3b795212008-11-13 19:45:32 +00002324 if (tcon == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 rc = -ENOMEM;
Steve French3b795212008-11-13 19:45:32 +00002326 goto mount_fail_check;
2327 }
Jeff Layton00e485b2008-12-05 20:41:21 -05002328
Steve Frenchab3f9922008-11-17 16:03:00 +00002329 tcon->ses = pSesInfo;
Jeff Layton00e485b2008-12-05 20:41:21 -05002330 if (volume_info->password) {
2331 tcon->password = kstrdup(volume_info->password,
2332 GFP_KERNEL);
2333 if (!tcon->password) {
2334 rc = -ENOMEM;
2335 goto mount_fail_check;
2336 }
2337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338
Steve French3b795212008-11-13 19:45:32 +00002339 /* check for null share name ie connect to dfs root */
Jeff Layton7586b762008-12-01 18:41:49 -05002340 if ((strchr(volume_info->UNC + 3, '\\') == NULL)
2341 && (strchr(volume_info->UNC + 3, '/') == NULL)) {
Steve French3b795212008-11-13 19:45:32 +00002342 /* rc = connect_to_dfs_path(...) */
2343 cFYI(1, ("DFS root not supported"));
2344 rc = -ENODEV;
2345 goto mount_fail_check;
2346 } else {
2347 /* BB Do we need to wrap sesSem around
2348 * this TCon call and Unix SetFS as
2349 * we do on SessSetup and reconnect? */
Jeff Layton7586b762008-12-01 18:41:49 -05002350 rc = CIFSTCon(xid, pSesInfo, volume_info->UNC,
Steve French3b795212008-11-13 19:45:32 +00002351 tcon, cifs_sb->local_nls);
2352 cFYI(1, ("CIFS Tcon rc = %d", rc));
Jeff Layton7586b762008-12-01 18:41:49 -05002353 if (volume_info->nodfs) {
Steve French3b795212008-11-13 19:45:32 +00002354 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2355 cFYI(1, ("DFS disabled (%d)",
2356 tcon->Flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 }
2358 }
Jeff Layton14fbf502008-11-14 13:53:46 -05002359 if (rc)
Steve French3b795212008-11-13 19:45:32 +00002360 goto mount_fail_check;
Jeff Layton7586b762008-12-01 18:41:49 -05002361 tcon->seal = volume_info->seal;
Jeff Laytonf1987b42008-11-15 11:12:47 -05002362 write_lock(&cifs_tcp_ses_lock);
2363 list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
2364 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 }
Steve French3b795212008-11-13 19:45:32 +00002366
2367 /* we can have only one retry value for a connection
2368 to a share so for resources mounted more than once
2369 to the same server share the last value passed in
2370 for the retry flag is used */
Jeff Layton7586b762008-12-01 18:41:49 -05002371 tcon->retry = volume_info->retry;
2372 tcon->nocase = volume_info->nocase;
2373 tcon->local_lease = volume_info->local_lease;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 }
Steve French4523cc32007-04-30 20:13:06 +00002375 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2377 sb->s_maxbytes = (u64) 1 << 63;
2378 } else
2379 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2380 }
2381
Steve French8af18972007-02-14 04:42:51 +00002382 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 sb->s_time_gran = 100;
2384
Steve French3b795212008-11-13 19:45:32 +00002385mount_fail_check:
Jeff Layton14fbf502008-11-14 13:53:46 -05002386 /* on error free sesinfo and tcon struct if needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 if (rc) {
Jeff Laytone7ddee92008-11-14 13:44:38 -05002388 /* If find_unc succeeded then rc == 0 so we can not end */
2389 /* up accidently freeing someone elses tcon struct */
2390 if (tcon)
Jeff Laytonf1987b42008-11-15 11:12:47 -05002391 cifs_put_tcon(tcon);
2392 else if (pSesInfo)
Jeff Layton14fbf502008-11-14 13:53:46 -05002393 cifs_put_smb_ses(pSesInfo);
Steve Frenchc18c8422007-07-18 23:21:09 +00002394 else
Jeff Layton14fbf502008-11-14 13:53:46 -05002395 cifs_put_tcp_session(srvTcp);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002396 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 }
Steve Frenchd82c2df2008-11-15 00:07:26 +00002398 cifs_sb->tcon = tcon;
Steve Frenchd82c2df2008-11-15 00:07:26 +00002399
2400 /* do not care if following two calls succeed - informational */
2401 if (!tcon->ipc) {
2402 CIFSSMBQFSDeviceInfo(xid, tcon);
2403 CIFSSMBQFSAttributeInfo(xid, tcon);
2404 }
2405
2406 /* tell server which Unix caps we support */
2407 if (tcon->ses->capabilities & CAP_UNIX)
2408 /* reset of caps checks mount to see if unix extensions
2409 disabled for just this mount */
Jeff Layton7586b762008-12-01 18:41:49 -05002410 reset_cifs_unix_caps(xid, tcon, sb, volume_info);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002411 else
2412 tcon->unix_ext = 0; /* server does not support them */
2413
2414 /* convert forward to back slashes in prepath here if needed */
2415 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2416 convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
2417
2418 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
2419 cifs_sb->rsize = 1024 * 127;
2420 cFYI(DBG2, ("no very large read support, rsize now 127K"));
2421 }
2422 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2423 cifs_sb->wsize = min(cifs_sb->wsize,
2424 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2425 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2426 cifs_sb->rsize = min(cifs_sb->rsize,
2427 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428
Jeff Layton7586b762008-12-01 18:41:49 -05002429 /* volume_info->password is freed above when existing session found
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 (in which case it is not needed anymore) but when new sesion is created
2431 the password ptr is put in the new session structure (in which case the
2432 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002433out:
2434 /* zero out password before freeing */
Jeff Layton7586b762008-12-01 18:41:49 -05002435 if (volume_info) {
2436 if (volume_info->password != NULL) {
2437 memset(volume_info->password, 0,
2438 strlen(volume_info->password));
2439 kfree(volume_info->password);
2440 }
2441 kfree(volume_info->UNC);
2442 kfree(volume_info->prepath);
2443 kfree(volume_info);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 FreeXid(xid);
2446 return rc;
2447}
2448
2449static int
2450CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002451 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 const struct nls_table *nls_codepage)
2453{
2454 struct smb_hdr *smb_buffer;
2455 struct smb_hdr *smb_buffer_response;
2456 SESSION_SETUP_ANDX *pSMB;
2457 SESSION_SETUP_ANDX *pSMBr;
2458 char *bcc_ptr;
2459 char *user;
2460 char *domain;
2461 int rc = 0;
2462 int remaining_words = 0;
2463 int bytes_returned = 0;
2464 int len;
2465 __u32 capabilities;
2466 __u16 count;
2467
Steve Frencheeac8042006-01-13 21:34:58 -08002468 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002469 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 return -EINVAL;
2471 user = ses->userName;
2472 domain = ses->domainName;
2473 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002474
2475 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002477
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 smb_buffer_response = smb_buffer;
2479 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2480
2481 /* send SMBsessionSetup here */
2482 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2483 NULL /* no tCon exists yet */ , 13 /* wct */ );
2484
Steve French1982c342005-08-17 12:38:22 -07002485 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 pSMB->req_no_secext.AndXCommand = 0xFF;
2487 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2488 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2489
Steve French50c2f752007-07-13 00:33:32 +00002490 if (ses->server->secMode &
2491 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2493
2494 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2495 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2496 if (ses->capabilities & CAP_UNICODE) {
2497 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2498 capabilities |= CAP_UNICODE;
2499 }
2500 if (ses->capabilities & CAP_STATUS32) {
2501 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2502 capabilities |= CAP_STATUS32;
2503 }
2504 if (ses->capabilities & CAP_DFS) {
2505 smb_buffer->Flags2 |= SMBFLG2_DFS;
2506 capabilities |= CAP_DFS;
2507 }
2508 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2509
Steve French50c2f752007-07-13 00:33:32 +00002510 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002511 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512
2513 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002514 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002516 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2517 bcc_ptr += CIFS_SESS_KEY_SIZE;
2518 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2519 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
2521 if (ses->capabilities & CAP_UNICODE) {
2522 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2523 *bcc_ptr = 0;
2524 bcc_ptr++;
2525 }
Steve French4523cc32007-04-30 20:13:06 +00002526 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002527 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002528 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002530 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 nls_codepage);
2532 /* convert number of 16 bit words to bytes */
2533 bcc_ptr += 2 * bytes_returned;
2534 bcc_ptr += 2; /* trailing null */
2535 if (domain == NULL)
2536 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002537 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 "CIFS_LINUX_DOM", 32, nls_codepage);
2539 else
2540 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002541 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 nls_codepage);
2543 bcc_ptr += 2 * bytes_returned;
2544 bcc_ptr += 2;
2545 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002546 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 32, nls_codepage);
2548 bcc_ptr += 2 * bytes_returned;
2549 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002550 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 32, nls_codepage);
2552 bcc_ptr += 2 * bytes_returned;
2553 bcc_ptr += 2;
2554 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002555 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 64, nls_codepage);
2557 bcc_ptr += 2 * bytes_returned;
2558 bcc_ptr += 2;
2559 } else {
Steve French50c2f752007-07-13 00:33:32 +00002560 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 strncpy(bcc_ptr, user, 200);
2562 bcc_ptr += strnlen(user, 200);
2563 }
2564 *bcc_ptr = 0;
2565 bcc_ptr++;
2566 if (domain == NULL) {
2567 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2568 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2569 } else {
2570 strncpy(bcc_ptr, domain, 64);
2571 bcc_ptr += strnlen(domain, 64);
2572 *bcc_ptr = 0;
2573 bcc_ptr++;
2574 }
2575 strcpy(bcc_ptr, "Linux version ");
2576 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002577 strcpy(bcc_ptr, utsname()->release);
2578 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2580 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2581 }
2582 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2583 smb_buffer->smb_buf_length += count;
2584 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2585
2586 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002587 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 if (rc) {
2589/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2590 } else if ((smb_buffer_response->WordCount == 3)
2591 || (smb_buffer_response->WordCount == 4)) {
2592 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2593 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2594 if (action & GUEST_LOGIN)
Steve French61e74802008-12-03 00:57:54 +00002595 cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */
Steve French50c2f752007-07-13 00:33:32 +00002596 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2597 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002599 /* response can have either 3 or 4 word count - Samba sends 3 */
2600 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 if ((pSMBr->resp.hdr.WordCount == 3)
2602 || ((pSMBr->resp.hdr.WordCount == 4)
2603 && (blob_len < pSMBr->resp.ByteCount))) {
2604 if (pSMBr->resp.hdr.WordCount == 4)
2605 bcc_ptr += blob_len;
2606
2607 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2608 if ((long) (bcc_ptr) % 2) {
2609 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002610 (BCC(smb_buffer_response) - 1) / 2;
2611 /* Unicode strings must be word
2612 aligned */
2613 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 } else {
2615 remaining_words =
2616 BCC(smb_buffer_response) / 2;
2617 }
2618 len =
2619 UniStrnlen((wchar_t *) bcc_ptr,
2620 remaining_words - 1);
2621/* We look for obvious messed up bcc or strings in response so we do not go off
2622 the end since (at least) WIN2K and Windows XP have a major bug in not null
2623 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002624 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002625 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002626 ses->serverOS = kzalloc(2 * (len + 1),
2627 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002628 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002629 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002631 (__le16 *)bcc_ptr,
2632 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 bcc_ptr += 2 * (len + 1);
2634 remaining_words -= len + 1;
2635 ses->serverOS[2 * len] = 0;
2636 ses->serverOS[1 + (2 * len)] = 0;
2637 if (remaining_words > 0) {
2638 len = UniStrnlen((wchar_t *)bcc_ptr,
2639 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002640 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002641 ses->serverNOS = kzalloc(2 * (len + 1),
2642 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002643 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002644 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002646 (__le16 *)bcc_ptr,
2647 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 bcc_ptr += 2 * (len + 1);
2649 ses->serverNOS[2 * len] = 0;
2650 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002651 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002652 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002653 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 ses->flags |= CIFS_SES_NT4;
2655 }
2656 remaining_words -= len + 1;
2657 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002658 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002659 /* last string is not always null terminated
2660 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002661 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002662 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002664 kzalloc(2*(len+1),
2665 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002666 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002667 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002669 (__le16 *)bcc_ptr,
2670 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 bcc_ptr += 2 * (len + 1);
2672 ses->serverDomain[2*len] = 0;
2673 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002674 } else { /* else no more room so create
2675 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002676 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002677 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002678 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002679 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002680 }
Steve French50c2f752007-07-13 00:33:32 +00002681 } else { /* no room so create dummy domain
2682 and NOS string */
2683
Steve French433dc242005-04-28 22:41:08 -07002684 /* if these kcallocs fail not much we
2685 can do, but better to not fail the
2686 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002687 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002689 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002690 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002692 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 }
2694 } else { /* ASCII */
2695 len = strnlen(bcc_ptr, 1024);
2696 if (((long) bcc_ptr + len) - (long)
2697 pByteArea(smb_buffer_response)
2698 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002699 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002700 ses->serverOS = kzalloc(len + 1,
2701 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002702 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002703 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002704 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705
2706 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002707 /* null terminate the string */
2708 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 bcc_ptr++;
2710
2711 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002712 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002713 ses->serverNOS = kzalloc(len + 1,
2714 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002715 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002716 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 strncpy(ses->serverNOS, bcc_ptr, len);
2718 bcc_ptr += len;
2719 bcc_ptr[0] = 0;
2720 bcc_ptr++;
2721
2722 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002723 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002724 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002725 ses->serverDomain = kzalloc(len + 1,
2726 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002727 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002728 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002729 strncpy(ses->serverDomain, bcc_ptr,
2730 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 bcc_ptr += len;
2732 bcc_ptr[0] = 0;
2733 bcc_ptr++;
2734 } else
2735 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002736 ("Variable field of length %d "
2737 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 len));
2739 }
2740 } else {
Steve French61e74802008-12-03 00:57:54 +00002741 cERROR(1, ("Security Blob Length extends beyond "
Steve French50c2f752007-07-13 00:33:32 +00002742 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 }
2744 } else {
Steve French61e74802008-12-03 00:57:54 +00002745 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 smb_buffer_response->WordCount));
2747 rc = -EIO;
2748 }
Steve French433dc242005-04-28 22:41:08 -07002749sesssetup_nomem: /* do not return an error on nomem for the info strings,
2750 since that could make reconnection harder, and
2751 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002752 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
2754 return rc;
2755}
2756
2757static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002759 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 const struct nls_table *nls_codepage)
2761{
2762 struct smb_hdr *smb_buffer;
2763 struct smb_hdr *smb_buffer_response;
2764 SESSION_SETUP_ANDX *pSMB;
2765 SESSION_SETUP_ANDX *pSMBr;
2766 char *bcc_ptr;
2767 char *domain;
2768 int rc = 0;
2769 int remaining_words = 0;
2770 int bytes_returned = 0;
2771 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002772 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 PNEGOTIATE_MESSAGE SecurityBlob;
2774 PCHALLENGE_MESSAGE SecurityBlob2;
2775 __u32 negotiate_flags, capabilities;
2776 __u16 count;
2777
Steve French12b3b8f2006-02-09 21:12:47 +00002778 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002779 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 return -EINVAL;
2781 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002782 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 smb_buffer = cifs_buf_get();
2784 if (smb_buffer == NULL) {
2785 return -ENOMEM;
2786 }
2787 smb_buffer_response = smb_buffer;
2788 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2789 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2790
2791 /* send SMBsessionSetup here */
2792 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2793 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002794
2795 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2797 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2798
2799 pSMB->req.AndXCommand = 0xFF;
2800 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2801 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2802
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002803 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2805
2806 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2807 CAP_EXTENDED_SECURITY;
2808 if (ses->capabilities & CAP_UNICODE) {
2809 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2810 capabilities |= CAP_UNICODE;
2811 }
2812 if (ses->capabilities & CAP_STATUS32) {
2813 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2814 capabilities |= CAP_STATUS32;
2815 }
2816 if (ses->capabilities & CAP_DFS) {
2817 smb_buffer->Flags2 |= SMBFLG2_DFS;
2818 capabilities |= CAP_DFS;
2819 }
2820 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2821
2822 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2823 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2824 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2825 SecurityBlob->MessageType = NtLmNegotiate;
2826 negotiate_flags =
2827 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002828 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2829 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002831 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002833/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002834 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 /* setup pointers to domain name and workstation name */
2836 bcc_ptr += SecurityBlobLength;
2837
2838 SecurityBlob->WorkstationName.Buffer = 0;
2839 SecurityBlob->WorkstationName.Length = 0;
2840 SecurityBlob->WorkstationName.MaximumLength = 0;
2841
Steve French12b3b8f2006-02-09 21:12:47 +00002842 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2843 along with username on auth request (ie the response to challenge) */
2844 SecurityBlob->DomainName.Buffer = 0;
2845 SecurityBlob->DomainName.Length = 0;
2846 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 if (ses->capabilities & CAP_UNICODE) {
2848 if ((long) bcc_ptr % 2) {
2849 *bcc_ptr = 0;
2850 bcc_ptr++;
2851 }
2852
2853 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002854 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 32, nls_codepage);
2856 bcc_ptr += 2 * bytes_returned;
2857 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002858 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 nls_codepage);
2860 bcc_ptr += 2 * bytes_returned;
2861 bcc_ptr += 2; /* null terminate Linux version */
2862 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002863 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 64, nls_codepage);
2865 bcc_ptr += 2 * bytes_returned;
2866 *(bcc_ptr + 1) = 0;
2867 *(bcc_ptr + 2) = 0;
2868 bcc_ptr += 2; /* null terminate network opsys string */
2869 *(bcc_ptr + 1) = 0;
2870 *(bcc_ptr + 2) = 0;
2871 bcc_ptr += 2; /* null domain */
2872 } else { /* ASCII */
2873 strcpy(bcc_ptr, "Linux version ");
2874 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002875 strcpy(bcc_ptr, utsname()->release);
2876 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2878 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2879 bcc_ptr++; /* empty domain field */
2880 *bcc_ptr = 0;
2881 }
2882 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2883 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2884 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2885 smb_buffer->smb_buf_length += count;
2886 pSMB->req.ByteCount = cpu_to_le16(count);
2887
2888 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002889 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890
2891 if (smb_buffer_response->Status.CifsError ==
2892 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2893 rc = 0;
2894
2895 if (rc) {
2896/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2897 } else if ((smb_buffer_response->WordCount == 3)
2898 || (smb_buffer_response->WordCount == 4)) {
2899 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2900 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2901
2902 if (action & GUEST_LOGIN)
Steve French61e74802008-12-03 00:57:54 +00002903 cFYI(1, ("Guest login"));
Steve French50c2f752007-07-13 00:33:32 +00002904 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905
Steve French50c2f752007-07-13 00:33:32 +00002906 bcc_ptr = pByteArea(smb_buffer_response);
2907 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
2909 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2910 if (SecurityBlob2->MessageType != NtLmChallenge) {
Steve French61e74802008-12-03 00:57:54 +00002911 cFYI(1, ("Unexpected NTLMSSP message type received %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 SecurityBlob2->MessageType));
2913 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002914 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002915 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 if ((pSMBr->resp.hdr.WordCount == 3)
2917 || ((pSMBr->resp.hdr.WordCount == 4)
2918 && (blob_len <
2919 pSMBr->resp.ByteCount))) {
2920
2921 if (pSMBr->resp.hdr.WordCount == 4) {
2922 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002923 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 blob_len));
2925 }
2926
Steve French12b3b8f2006-02-09 21:12:47 +00002927 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928
2929 memcpy(ses->server->cryptKey,
2930 SecurityBlob2->Challenge,
2931 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002932 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002933 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002934 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
Steve French50c2f752007-07-13 00:33:32 +00002936 if ((SecurityBlob2->NegotiateFlags &
2937 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002939 ses->server->secMode |=
2940 SECMODE_SIGN_REQUIRED;
2941 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002943 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 SECMODE_SIGN_ENABLED;
2945
2946 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2947 if ((long) (bcc_ptr) % 2) {
2948 remaining_words =
2949 (BCC(smb_buffer_response)
2950 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002951 /* Must word align unicode strings */
2952 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 } else {
2954 remaining_words =
2955 BCC
2956 (smb_buffer_response) / 2;
2957 }
2958 len =
2959 UniStrnlen((wchar_t *) bcc_ptr,
2960 remaining_words - 1);
2961/* We look for obvious messed up bcc or strings in response so we do not go off
2962 the end since (at least) WIN2K and Windows XP have a major bug in not null
2963 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002964 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002965 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002967 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002969 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 bcc_ptr, len,
2971 nls_codepage);
2972 bcc_ptr += 2 * (len + 1);
2973 remaining_words -= len + 1;
2974 ses->serverOS[2 * len] = 0;
2975 ses->serverOS[1 + (2 * len)] = 0;
2976 if (remaining_words > 0) {
2977 len = UniStrnlen((wchar_t *)
2978 bcc_ptr,
2979 remaining_words
2980 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002981 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002983 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 GFP_KERNEL);
2985 cifs_strfromUCS_le(ses->
2986 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002987 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 bcc_ptr,
2989 len,
2990 nls_codepage);
2991 bcc_ptr += 2 * (len + 1);
2992 ses->serverNOS[2 * len] = 0;
2993 ses->serverNOS[1 +
2994 (2 * len)] = 0;
2995 remaining_words -= len + 1;
2996 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002997 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2998 /* last string not always null terminated
2999 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00003000 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003002 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 (len +
3004 1),
3005 GFP_KERNEL);
3006 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08003007 (ses->serverDomain,
3008 (__le16 *)bcc_ptr,
3009 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 bcc_ptr +=
3011 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08003012 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08003014 ses->serverDomain
3015 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 = 0;
3017 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003018 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00003019 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003021 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00003025 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003027 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003028 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003030 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 }
3032 } else { /* ASCII */
3033 len = strnlen(bcc_ptr, 1024);
3034 if (((long) bcc_ptr + len) - (long)
3035 pByteArea(smb_buffer_response)
3036 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003037 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003038 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003040 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 GFP_KERNEL);
3042 strncpy(ses->serverOS,
3043 bcc_ptr, len);
3044
3045 bcc_ptr += len;
3046 bcc_ptr[0] = 0; /* null terminate string */
3047 bcc_ptr++;
3048
3049 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003050 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003052 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 GFP_KERNEL);
3054 strncpy(ses->serverNOS, bcc_ptr, len);
3055 bcc_ptr += len;
3056 bcc_ptr[0] = 0;
3057 bcc_ptr++;
3058
3059 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003060 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003062 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00003064 strncpy(ses->serverDomain,
3065 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 bcc_ptr += len;
3067 bcc_ptr[0] = 0;
3068 bcc_ptr++;
3069 } else
3070 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00003071 ("field of length %d "
3072 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 len));
3074 }
3075 } else {
Steve French50c2f752007-07-13 00:33:32 +00003076 cERROR(1, ("Security Blob Length extends beyond"
3077 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 }
3079 } else {
3080 cERROR(1, ("No session structure passed in."));
3081 }
3082 } else {
Steve French61e74802008-12-03 00:57:54 +00003083 cERROR(1, ("Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 smb_buffer_response->WordCount));
3085 rc = -EIO;
3086 }
3087
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003088 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089
3090 return rc;
3091}
3092static int
3093CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00003094 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003095 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096{
3097 struct smb_hdr *smb_buffer;
3098 struct smb_hdr *smb_buffer_response;
3099 SESSION_SETUP_ANDX *pSMB;
3100 SESSION_SETUP_ANDX *pSMBr;
3101 char *bcc_ptr;
3102 char *user;
3103 char *domain;
3104 int rc = 0;
3105 int remaining_words = 0;
3106 int bytes_returned = 0;
3107 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003108 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 PAUTHENTICATE_MESSAGE SecurityBlob;
3110 __u32 negotiate_flags, capabilities;
3111 __u16 count;
3112
3113 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003114 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 return -EINVAL;
3116 user = ses->userName;
3117 domain = ses->domainName;
3118 smb_buffer = cifs_buf_get();
3119 if (smb_buffer == NULL) {
3120 return -ENOMEM;
3121 }
3122 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003123 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
3124 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125
3126 /* send SMBsessionSetup here */
3127 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
3128 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07003129
3130 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
3132 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
3133 pSMB->req.AndXCommand = 0xFF;
3134 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
3135 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
3136
3137 pSMB->req.hdr.Uid = ses->Suid;
3138
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003139 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3141
3142 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003143 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 if (ses->capabilities & CAP_UNICODE) {
3145 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3146 capabilities |= CAP_UNICODE;
3147 }
3148 if (ses->capabilities & CAP_STATUS32) {
3149 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3150 capabilities |= CAP_STATUS32;
3151 }
3152 if (ses->capabilities & CAP_DFS) {
3153 smb_buffer->Flags2 |= SMBFLG2_DFS;
3154 capabilities |= CAP_DFS;
3155 }
3156 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3157
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003158 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3159 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3161 SecurityBlob->MessageType = NtLmAuthenticate;
3162 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003163 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3164 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3165 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003166 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003168 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3170
3171/* setup pointers to domain name and workstation name */
3172
3173 SecurityBlob->WorkstationName.Buffer = 0;
3174 SecurityBlob->WorkstationName.Length = 0;
3175 SecurityBlob->WorkstationName.MaximumLength = 0;
3176 SecurityBlob->SessionKey.Length = 0;
3177 SecurityBlob->SessionKey.MaximumLength = 0;
3178 SecurityBlob->SessionKey.Buffer = 0;
3179
3180 SecurityBlob->LmChallengeResponse.Length = 0;
3181 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3182 SecurityBlob->LmChallengeResponse.Buffer = 0;
3183
3184 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003185 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003187 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3188 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 SecurityBlob->NtChallengeResponse.Buffer =
3190 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003191 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3192 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193
3194 if (ses->capabilities & CAP_UNICODE) {
3195 if (domain == NULL) {
3196 SecurityBlob->DomainName.Buffer = 0;
3197 SecurityBlob->DomainName.Length = 0;
3198 SecurityBlob->DomainName.MaximumLength = 0;
3199 } else {
Steve French77159b42007-08-31 01:10:17 +00003200 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003202 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003204 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 SecurityBlob->DomainName.Buffer =
3206 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003207 bcc_ptr += ln;
3208 SecurityBlobLength += ln;
3209 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 }
3211 if (user == NULL) {
3212 SecurityBlob->UserName.Buffer = 0;
3213 SecurityBlob->UserName.Length = 0;
3214 SecurityBlob->UserName.MaximumLength = 0;
3215 } else {
Steve French77159b42007-08-31 01:10:17 +00003216 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003218 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003220 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 SecurityBlob->UserName.Buffer =
3222 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003223 bcc_ptr += ln;
3224 SecurityBlobLength += ln;
3225 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 }
3227
Steve French63135e02007-07-17 17:34:02 +00003228 /* SecurityBlob->WorkstationName.Length =
3229 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003231 SecurityBlob->WorkstationName.MaximumLength =
3232 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3233 SecurityBlob->WorkstationName.Buffer =
3234 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 bcc_ptr += SecurityBlob->WorkstationName.Length;
3236 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003237 SecurityBlob->WorkstationName.Length =
3238 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239
3240 if ((long) bcc_ptr % 2) {
3241 *bcc_ptr = 0;
3242 bcc_ptr++;
3243 }
3244 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003245 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 32, nls_codepage);
3247 bcc_ptr += 2 * bytes_returned;
3248 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003249 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 nls_codepage);
3251 bcc_ptr += 2 * bytes_returned;
3252 bcc_ptr += 2; /* null term version string */
3253 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003254 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 64, nls_codepage);
3256 bcc_ptr += 2 * bytes_returned;
3257 *(bcc_ptr + 1) = 0;
3258 *(bcc_ptr + 2) = 0;
3259 bcc_ptr += 2; /* null terminate network opsys string */
3260 *(bcc_ptr + 1) = 0;
3261 *(bcc_ptr + 2) = 0;
3262 bcc_ptr += 2; /* null domain */
3263 } else { /* ASCII */
3264 if (domain == NULL) {
3265 SecurityBlob->DomainName.Buffer = 0;
3266 SecurityBlob->DomainName.Length = 0;
3267 SecurityBlob->DomainName.MaximumLength = 0;
3268 } else {
Steve French77159b42007-08-31 01:10:17 +00003269 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3271 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003272 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003274 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 SecurityBlob->DomainName.Buffer =
3276 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003277 bcc_ptr += ln;
3278 SecurityBlobLength += ln;
3279 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 }
3281 if (user == NULL) {
3282 SecurityBlob->UserName.Buffer = 0;
3283 SecurityBlob->UserName.Length = 0;
3284 SecurityBlob->UserName.MaximumLength = 0;
3285 } else {
Steve French77159b42007-08-31 01:10:17 +00003286 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003288 ln = strnlen(user, 64);
3289 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003291 cpu_to_le32(SecurityBlobLength);
3292 bcc_ptr += ln;
3293 SecurityBlobLength += ln;
3294 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 }
3296 /* BB fill in our workstation name if known BB */
3297
3298 strcpy(bcc_ptr, "Linux version ");
3299 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003300 strcpy(bcc_ptr, utsname()->release);
3301 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3303 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3304 bcc_ptr++; /* null domain */
3305 *bcc_ptr = 0;
3306 }
3307 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3308 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3309 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3310 smb_buffer->smb_buf_length += count;
3311 pSMB->req.ByteCount = cpu_to_le16(count);
3312
3313 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003314 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003316/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3317 } else if ((smb_buffer_response->WordCount == 3) ||
3318 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003320 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 if (action & GUEST_LOGIN)
Steve French61e74802008-12-03 00:57:54 +00003322 cFYI(1, ("Guest login")); /* BB Should we set anything
Steve French50c2f752007-07-13 00:33:32 +00003323 in SesInfo struct ? */
3324/* if (SecurityBlob2->MessageType != NtLm??) {
3325 cFYI("Unexpected message type on auth response is %d"));
3326 } */
3327
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 if (ses) {
3329 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003330 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003332 /* UID left in wire format */
3333 ses->Suid = smb_buffer_response->Uid;
3334 bcc_ptr = pByteArea(smb_buffer_response);
3335 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 if ((pSMBr->resp.hdr.WordCount == 3)
3337 || ((pSMBr->resp.hdr.WordCount == 4)
3338 && (blob_len <
3339 pSMBr->resp.ByteCount))) {
3340 if (pSMBr->resp.hdr.WordCount == 4) {
3341 bcc_ptr +=
3342 blob_len;
3343 cFYI(1,
3344 ("Security Blob Length %d ",
3345 blob_len));
3346 }
3347
3348 cFYI(1,
3349 ("NTLMSSP response to Authenticate "));
3350
3351 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3352 if ((long) (bcc_ptr) % 2) {
3353 remaining_words =
3354 (BCC(smb_buffer_response)
3355 - 1) / 2;
3356 bcc_ptr++; /* Unicode strings must be word aligned */
3357 } else {
3358 remaining_words = BCC(smb_buffer_response) / 2;
3359 }
Steve French77159b42007-08-31 01:10:17 +00003360 len = UniStrnlen((wchar_t *) bcc_ptr,
3361 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362/* We look for obvious messed up bcc or strings in response so we do not go off
3363 the end since (at least) WIN2K and Windows XP have a major bug in not null
3364 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003365 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003366 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003368 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003370 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 bcc_ptr, len,
3372 nls_codepage);
3373 bcc_ptr += 2 * (len + 1);
3374 remaining_words -= len + 1;
3375 ses->serverOS[2 * len] = 0;
3376 ses->serverOS[1 + (2 * len)] = 0;
3377 if (remaining_words > 0) {
3378 len = UniStrnlen((wchar_t *)
3379 bcc_ptr,
3380 remaining_words
3381 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003382 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003384 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 GFP_KERNEL);
3386 cifs_strfromUCS_le(ses->
3387 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003388 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 bcc_ptr,
3390 len,
3391 nls_codepage);
3392 bcc_ptr += 2 * (len + 1);
3393 ses->serverNOS[2 * len] = 0;
3394 ses->serverNOS[1+(2*len)] = 0;
3395 remaining_words -= len + 1;
3396 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003397 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003399 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003400 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003402 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 (len +
3404 1),
3405 GFP_KERNEL);
3406 cifs_strfromUCS_le
3407 (ses->
3408 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003409 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 bcc_ptr, len,
3411 nls_codepage);
3412 bcc_ptr +=
3413 2 * (len + 1);
3414 ses->
3415 serverDomain[2
3416 * len]
3417 = 0;
3418 ses->
3419 serverDomain[1
3420 +
3421 (2
3422 *
3423 len)]
3424 = 0;
3425 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003426 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003427 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003428 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003429 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003430 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003432 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003433 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003434 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003435 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003436 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 }
3438 } else { /* ASCII */
3439 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003440 if (((long) bcc_ptr + len) -
3441 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003442 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003443 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003444 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003445 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 strncpy(ses->serverOS,bcc_ptr, len);
3447
3448 bcc_ptr += len;
3449 bcc_ptr[0] = 0; /* null terminate the string */
3450 bcc_ptr++;
3451
3452 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003453 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003454 ses->serverNOS = kzalloc(len+1,
3455 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003456 strncpy(ses->serverNOS,
3457 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 bcc_ptr += len;
3459 bcc_ptr[0] = 0;
3460 bcc_ptr++;
3461
3462 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003463 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003464 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003465 ses->serverDomain =
3466 kzalloc(len+1,
3467 GFP_KERNEL);
3468 strncpy(ses->serverDomain,
3469 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 bcc_ptr += len;
3471 bcc_ptr[0] = 0;
3472 bcc_ptr++;
3473 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003474 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003475 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 len));
3477 }
3478 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003479 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003480 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 }
3482 } else {
3483 cERROR(1, ("No session structure passed in."));
3484 }
3485 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003486 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 smb_buffer_response->WordCount));
3488 rc = -EIO;
3489 }
3490
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003491 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492
3493 return rc;
3494}
3495
3496int
3497CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3498 const char *tree, struct cifsTconInfo *tcon,
3499 const struct nls_table *nls_codepage)
3500{
3501 struct smb_hdr *smb_buffer;
3502 struct smb_hdr *smb_buffer_response;
3503 TCONX_REQ *pSMB;
3504 TCONX_RSP *pSMBr;
3505 unsigned char *bcc_ptr;
3506 int rc = 0;
3507 int length;
3508 __u16 count;
3509
3510 if (ses == NULL)
3511 return -EIO;
3512
3513 smb_buffer = cifs_buf_get();
3514 if (smb_buffer == NULL) {
3515 return -ENOMEM;
3516 }
3517 smb_buffer_response = smb_buffer;
3518
3519 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3520 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003521
3522 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 smb_buffer->Uid = ses->Suid;
3524 pSMB = (TCONX_REQ *) smb_buffer;
3525 pSMBr = (TCONX_RSP *) smb_buffer_response;
3526
3527 pSMB->AndXCommand = 0xFF;
3528 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003530 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003531 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003532 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003533 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003534 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003535 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003536 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003537 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3538 specified as required (when that support is added to
3539 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003540 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003541 by Samba (not sure whether other servers allow
3542 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003543#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003544 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Jeff Layton00e485b2008-12-05 20:41:21 -05003545 (ses->server->secType == LANMAN))
3546 calc_lanman_hash(tcon->password, ses->server->cryptKey,
Jeff Layton4e53a3f2008-12-05 20:41:21 -05003547 ses->server->secMode &
3548 SECMODE_PW_ENCRYPT ? true : false,
3549 bcc_ptr);
Steve French7c7b25b2006-06-01 19:20:10 +00003550 else
3551#endif /* CIFS_WEAK_PW_HASH */
Jeff Layton00e485b2008-12-05 20:41:21 -05003552 SMBNTencrypt(tcon->password, ses->server->cryptKey,
Steve Frencheeac8042006-01-13 21:34:58 -08003553 bcc_ptr);
3554
Steve French7c7b25b2006-06-01 19:20:10 +00003555 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003556 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003557 /* must align unicode strings */
3558 *bcc_ptr = 0; /* null byte password */
3559 bcc_ptr++;
3560 }
Steve Frencheeac8042006-01-13 21:34:58 -08003561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562
Steve French50c2f752007-07-13 00:33:32 +00003563 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003564 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3566
3567 if (ses->capabilities & CAP_STATUS32) {
3568 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3569 }
3570 if (ses->capabilities & CAP_DFS) {
3571 smb_buffer->Flags2 |= SMBFLG2_DFS;
3572 }
3573 if (ses->capabilities & CAP_UNICODE) {
3574 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3575 length =
Steve French50c2f752007-07-13 00:33:32 +00003576 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3577 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003578 (/* server len*/ + 256 /* share len */), nls_codepage);
3579 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 bcc_ptr += 2; /* skip trailing null */
3581 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 strcpy(bcc_ptr, tree);
3583 bcc_ptr += strlen(tree) + 1;
3584 }
3585 strcpy(bcc_ptr, "?????");
3586 bcc_ptr += strlen("?????");
3587 bcc_ptr += 1;
3588 count = bcc_ptr - &pSMB->Password[0];
3589 pSMB->hdr.smb_buf_length += count;
3590 pSMB->ByteCount = cpu_to_le16(count);
3591
Steve French133672e2007-11-13 22:41:37 +00003592 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3593 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594
3595 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3596 /* above now done in SendReceive */
3597 if ((rc == 0) && (tcon != NULL)) {
3598 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003599 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 tcon->tid = smb_buffer_response->Tid;
3601 bcc_ptr = pByteArea(smb_buffer_response);
3602 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003603 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003604 if (length == 3) {
3605 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3606 (bcc_ptr[2] == 'C')) {
3607 cFYI(1, ("IPC connection"));
3608 tcon->ipc = 1;
3609 }
3610 } else if (length == 2) {
3611 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3612 /* the most common case */
3613 cFYI(1, ("disk share connection"));
3614 }
3615 }
Steve French50c2f752007-07-13 00:33:32 +00003616 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3618 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3619 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3620 if ((bcc_ptr + (2 * 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 + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003626 if (tcon->nativeFileSystem)
3627 cifs_strfromUCS_le(
3628 tcon->nativeFileSystem,
3629 (__le16 *) bcc_ptr,
3630 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 bcc_ptr += 2 * length;
3632 bcc_ptr[0] = 0; /* null terminate the string */
3633 bcc_ptr[1] = 0;
3634 bcc_ptr += 2;
3635 }
Steve French50c2f752007-07-13 00:33:32 +00003636 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 } else {
3638 length = strnlen(bcc_ptr, 1024);
3639 if ((bcc_ptr + length) -
3640 pByteArea(smb_buffer_response) <=
3641 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003642 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003644 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003645 if (tcon->nativeFileSystem)
3646 strncpy(tcon->nativeFileSystem, bcc_ptr,
3647 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 }
Steve French50c2f752007-07-13 00:33:32 +00003649 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003651 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003652 (smb_buffer_response->WordCount == 7))
3653 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003654 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3655 else
3656 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3658 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003659 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 ses->ipc_tid = smb_buffer_response->Tid;
3661 }
3662
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003663 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 return rc;
3665}
3666
3667int
3668cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3669{
3670 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003671 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672
Jeff Laytonf1987b42008-11-15 11:12:47 -05003673 if (cifs_sb->tcon)
3674 cifs_put_tcon(cifs_sb->tcon);
Steve French50c2f752007-07-13 00:33:32 +00003675
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003677 tmp = cifs_sb->prepath;
3678 cifs_sb->prepathlen = 0;
3679 cifs_sb->prepath = NULL;
3680 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681
Steve French88e7d702008-01-03 17:37:09 +00003682 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003683}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684
3685int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003686 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687{
3688 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003689 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003690 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003691 int first_time = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003692 struct TCP_Server_Info *server = pSesInfo->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693
3694 /* what if server changes its buffer size after dropping the session? */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003695 if (server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 rc = CIFSSMBNegotiate(xid, pSesInfo);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003697 if (rc == -EAGAIN) {
3698 /* retry only once on 1st time connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003700 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 rc = -EHOSTDOWN;
3702 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003703 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 spin_lock(&GlobalMid_Lock);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003705 if (server->tcpStatus != CifsExiting)
3706 server->tcpStatus = CifsGood;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 else
3708 rc = -EHOSTDOWN;
3709 spin_unlock(&GlobalMid_Lock);
3710
3711 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003712 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 }
Steve French26b994f2008-08-06 05:11:33 +00003714
3715 if (rc)
3716 goto ss_err_exit;
3717
3718 pSesInfo->flags = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003719 pSesInfo->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003720 if (linuxExtEnabled == 0)
3721 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003722 /* pSesInfo->sequence_number = 0;*/
Steve French26b994f2008-08-06 05:11:33 +00003723 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003724 server->secMode, server->capabilities, server->timeAdj));
3725
Steve French26b994f2008-08-06 05:11:33 +00003726 if (experimEnabled < 2)
3727 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
3728 else if (extended_security
3729 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003730 && (server->secType == NTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003731 rc = -EOPNOTSUPP;
3732 } else if (extended_security
3733 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003734 && (server->secType == RawNTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003735 cFYI(1, ("NTLMSSP sesssetup"));
3736 rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
3737 nls_info);
3738 if (!rc) {
3739 if (ntlmv2_flag) {
3740 char *v2_response;
3741 cFYI(1, ("more secure NTLM ver2 hash"));
3742 if (CalcNTLMv2_partial_mac_key(pSesInfo,
3743 nls_info)) {
3744 rc = -ENOMEM;
3745 goto ss_err_exit;
3746 } else
3747 v2_response = kmalloc(16 + 64 /* blob*/,
3748 GFP_KERNEL);
3749 if (v2_response) {
3750 CalcNTLMv2_response(pSesInfo,
3751 v2_response);
3752 /* if (first_time)
3753 cifs_calculate_ntlmv2_mac_key */
3754 kfree(v2_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 /* BB Put dummy sig in SessSetup PDU? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 } else {
Steve French26b994f2008-08-06 05:11:33 +00003757 rc = -ENOMEM;
3758 goto ss_err_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 }
Steve French26b994f2008-08-06 05:11:33 +00003760
3761 } else {
3762 SMBNTencrypt(pSesInfo->password,
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003763 server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003764 ntlm_session_key);
3765
3766 if (first_time)
3767 cifs_calculate_mac_key(
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003768 &server->mac_signing_key,
Steve French26b994f2008-08-06 05:11:33 +00003769 ntlm_session_key,
3770 pSesInfo->password);
3771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 /* for better security the weaker lanman hash not sent
3773 in AuthSessSetup so we no longer calculate it */
3774
Steve French26b994f2008-08-06 05:11:33 +00003775 rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
3776 ntlm_session_key,
3777 ntlmv2_flag,
3778 nls_info);
3779 }
3780 } else { /* old style NTLM 0.12 session setup */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003781 SMBNTencrypt(pSesInfo->password, server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003782 ntlm_session_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783
Steve French26b994f2008-08-06 05:11:33 +00003784 if (first_time)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003785 cifs_calculate_mac_key(&server->mac_signing_key,
3786 ntlm_session_key,
3787 pSesInfo->password);
Steve Frenchad009ac2005-04-28 22:41:05 -07003788
Steve French26b994f2008-08-06 05:11:33 +00003789 rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 }
Steve French26b994f2008-08-06 05:11:33 +00003791 if (rc) {
3792 cERROR(1, ("Send error in SessSetup = %d", rc));
3793 } else {
3794 cFYI(1, ("CIFS Session Established successfully"));
Jeff Layton469ee612008-10-16 18:46:39 +00003795 spin_lock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003796 pSesInfo->status = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003797 pSesInfo->need_reconnect = false;
Jeff Layton469ee612008-10-16 18:46:39 +00003798 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003799 }
3800
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801ss_err_exit:
3802 return rc;
3803}
3804