blob: e9ea394ee075d0ef20ab7900d111c5bd6a6e20c6 [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;
1805 socket->sk->sk_sndtimeo = 3 * 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 Laytonbcf4b102008-12-01 18:42:15 -05001863 rc = smb_send(socket, smb_buf, 0x44,
1864 (struct sockaddr *) &server->addr.sockAddr,
1865 server->noblocksnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001867 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001868 requires very short break before negprot
1869 presumably because not expecting negprot
1870 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001871 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001872 complicating the code and causes no
1873 significant slowing down on mount
1874 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 }
Steve French50c2f752007-07-13 00:33:32 +00001876 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001878
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 }
Steve French50c2f752007-07-13 00:33:32 +00001880
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 return rc;
1882}
1883
1884static int
Jeff Laytond5c56052008-12-01 18:42:33 -05001885ipv6_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886{
1887 int rc = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05001888 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 __be16 orig_port = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05001890 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891
Jeff Laytond5c56052008-12-01 18:42:33 -05001892 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001893 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
Jeff Laytond5c56052008-12-01 18:42:33 -05001894 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001896 cERROR(1, ("Error %d creating ipv6 socket", rc));
Jeff Laytond5c56052008-12-01 18:42:33 -05001897 socket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 }
Jeff Laytond5c56052008-12-01 18:42:33 -05001900
1901 /* BB other socket options to set KEEPALIVE, NODELAY? */
1902 cFYI(1, ("ipv6 Socket created"));
1903 server->ssocket = socket;
1904 socket->sk->sk_allocation = GFP_NOFS;
1905 cifs_reclassify_socket6(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 }
1907
Jeff Laytond5c56052008-12-01 18:42:33 -05001908 /* user overrode default port */
1909 if (server->addr.sockAddr6.sin6_port) {
1910 rc = socket->ops->connect(socket,
1911 (struct sockaddr *) &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001912 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001914 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00001915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001917 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001918 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 later if fall back ports fail this time */
1920
Jeff Laytond5c56052008-12-01 18:42:33 -05001921 orig_port = server->addr.sockAddr6.sin6_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 /* do not retry on the same port we just failed on */
Jeff Laytond5c56052008-12-01 18:42:33 -05001923 if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) {
1924 server->addr.sockAddr6.sin6_port = htons(CIFS_PORT);
1925 rc = socket->ops->connect(socket, (struct sockaddr *)
1926 &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001927 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001929 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 }
1931 }
1932 if (!connected) {
Jeff Laytond5c56052008-12-01 18:42:33 -05001933 server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT);
1934 rc = socket->ops->connect(socket, (struct sockaddr *)
1935 &server->addr.sockAddr6,
1936 sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001937 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001938 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 }
1940
1941 /* give up here - unless we want to retry on different
1942 protocol families some day */
1943 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001944 if (orig_port)
Jeff Laytond5c56052008-12-01 18:42:33 -05001945 server->addr.sockAddr6.sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001946 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Jeff Laytond5c56052008-12-01 18:42:33 -05001947 sock_release(socket);
1948 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 return rc;
1950 }
Steve Frenchedf1ae42008-10-29 00:47:57 +00001951
Jeff Laytond5c56052008-12-01 18:42:33 -05001952 /*
1953 * Eventually check for other socket options to change from
1954 * the default. sock_setsockopt not used because it expects
1955 * user space buffer
1956 */
1957 socket->sk->sk_rcvtimeo = 7 * HZ;
1958 socket->sk->sk_sndtimeo = 3 * HZ;
1959 server->ssocket = socket;
Steve French50c2f752007-07-13 00:33:32 +00001960
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 return rc;
1962}
1963
Steve French50c2f752007-07-13 00:33:32 +00001964void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1965 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001966{
1967 /* if we are reconnecting then should we check to see if
1968 * any requested capabilities changed locally e.g. via
1969 * remount but we can not do much about it here
1970 * if they have (even if we could detect it by the following)
1971 * Perhaps we could add a backpointer to array of sb from tcon
1972 * or if we change to make all sb to same share the same
1973 * sb as NFS - then we only have one backpointer to sb.
1974 * What if we wanted to mount the server share twice once with
1975 * and once without posixacls or posix paths? */
1976 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001977
Steve Frenchc18c8422007-07-18 23:21:09 +00001978 if (vol_info && vol_info->no_linux_ext) {
1979 tcon->fsUnixInfo.Capability = 0;
1980 tcon->unix_ext = 0; /* Unix Extensions disabled */
1981 cFYI(1, ("Linux protocol extensions disabled"));
1982 return;
1983 } else if (vol_info)
1984 tcon->unix_ext = 1; /* Unix Extensions supported */
1985
1986 if (tcon->unix_ext == 0) {
1987 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1988 return;
1989 }
Steve French50c2f752007-07-13 00:33:32 +00001990
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001991 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001992 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001993
Steve French8af18972007-02-14 04:42:51 +00001994 /* check for reconnect case in which we do not
1995 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001996 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001997 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001998 originally at mount time */
1999 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
2000 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002001 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2002 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
2003 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00002004 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002005 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2006 cERROR(1, ("possible reconnect error"));
2007 cERROR(1,
2008 ("server disabled POSIX path support"));
2009 }
Steve French8af18972007-02-14 04:42:51 +00002010 }
Steve French50c2f752007-07-13 00:33:32 +00002011
Steve French8af18972007-02-14 04:42:51 +00002012 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00002013 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00002014 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002015 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002016 cFYI(1, ("negotiated posix acl support"));
2017 if (sb)
Steve French8af18972007-02-14 04:42:51 +00002018 sb->s_flags |= MS_POSIXACL;
2019 }
2020
Steve French75865f8c2007-06-24 18:30:48 +00002021 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00002022 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002023 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002024 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00002025 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00002026 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00002027 CIFS_MOUNT_POSIX_PATHS;
2028 }
Steve French50c2f752007-07-13 00:33:32 +00002029
Steve French984acfe2007-04-26 16:42:50 +00002030 /* We might be setting the path sep back to a different
2031 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00002032 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00002033 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00002034 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00002035
2036 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
2037 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
2038 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00002039 cFYI(DBG2,
2040 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00002041 }
2042 }
Steve French50c2f752007-07-13 00:33:32 +00002043
2044
2045 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00002046#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00002047 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002048 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002049 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002050 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002051 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002052 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002053 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002054 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002055 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002056 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002057 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002058 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002059 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002060 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00002061#endif /* CIFS_DEBUG2 */
2062 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00002063 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00002064 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00002065 } else
Steve French5a44b312007-09-20 15:16:24 +00002066 cERROR(1, ("Negotiating Unix capabilities "
2067 "with the server failed. Consider "
2068 "mounting with the Unix Extensions\n"
2069 "disabled, if problems are found, "
2070 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00002071 "option."));
Steve French5a44b312007-09-20 15:16:24 +00002072
Steve French8af18972007-02-14 04:42:51 +00002073 }
2074 }
2075}
2076
Steve French03a143c2008-02-14 06:38:30 +00002077static void
2078convert_delimiter(char *path, char delim)
2079{
2080 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002081 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00002082
2083 if (path == NULL)
2084 return;
2085
Steve French582d21e2008-05-13 04:54:12 +00002086 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002087 old_delim = '\\';
2088 else
2089 old_delim = '/';
2090
Steve French03a143c2008-02-14 06:38:30 +00002091 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002092 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00002093 path[i] = delim;
2094 }
2095}
2096
Steve French3b795212008-11-13 19:45:32 +00002097static void setup_cifs_sb(struct smb_vol *pvolume_info,
2098 struct cifs_sb_info *cifs_sb)
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002099{
Steve French3b795212008-11-13 19:45:32 +00002100 if (pvolume_info->rsize > CIFSMaxBufSize) {
2101 cERROR(1, ("rsize %d too large, using MaxBufSize",
2102 pvolume_info->rsize));
2103 cifs_sb->rsize = CIFSMaxBufSize;
2104 } else if ((pvolume_info->rsize) &&
2105 (pvolume_info->rsize <= CIFSMaxBufSize))
2106 cifs_sb->rsize = pvolume_info->rsize;
2107 else /* default */
2108 cifs_sb->rsize = CIFSMaxBufSize;
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002109
Steve French3b795212008-11-13 19:45:32 +00002110 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
2111 cERROR(1, ("wsize %d too large, using 4096 instead",
2112 pvolume_info->wsize));
2113 cifs_sb->wsize = 4096;
2114 } else if (pvolume_info->wsize)
2115 cifs_sb->wsize = pvolume_info->wsize;
2116 else
2117 cifs_sb->wsize = min_t(const int,
2118 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2119 127*1024);
2120 /* old default of CIFSMaxBufSize was too small now
2121 that SMB Write2 can send multiple pages in kvec.
2122 RFC1001 does not describe what happens when frame
2123 bigger than 128K is sent so use that as max in
2124 conjunction with 52K kvec constraint on arch with 4K
2125 page size */
2126
2127 if (cifs_sb->rsize < 2048) {
2128 cifs_sb->rsize = 2048;
2129 /* Windows ME may prefer this */
2130 cFYI(1, ("readsize set to minimum: 2048"));
2131 }
2132 /* calculate prepath */
2133 cifs_sb->prepath = pvolume_info->prepath;
2134 if (cifs_sb->prepath) {
2135 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2136 /* we can not convert the / to \ in the path
2137 separators in the prefixpath yet because we do not
2138 know (until reset_cifs_unix_caps is called later)
2139 whether POSIX PATH CAP is available. We normalize
2140 the / to \ after reset_cifs_unix_caps is called */
2141 pvolume_info->prepath = NULL;
2142 } else
2143 cifs_sb->prepathlen = 0;
2144 cifs_sb->mnt_uid = pvolume_info->linux_uid;
2145 cifs_sb->mnt_gid = pvolume_info->linux_gid;
2146 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
2147 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
2148 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2149 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
2150
2151 if (pvolume_info->noperm)
2152 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
2153 if (pvolume_info->setuids)
2154 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
2155 if (pvolume_info->server_ino)
2156 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
2157 if (pvolume_info->remap)
2158 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
2159 if (pvolume_info->no_xattr)
2160 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
2161 if (pvolume_info->sfu_emul)
2162 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
2163 if (pvolume_info->nobrl)
2164 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French13a6e422008-12-02 17:24:33 +00002165 if (pvolume_info->mand_lock)
2166 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
Steve French3b795212008-11-13 19:45:32 +00002167 if (pvolume_info->cifs_acl)
2168 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2169 if (pvolume_info->override_uid)
2170 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2171 if (pvolume_info->override_gid)
2172 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2173 if (pvolume_info->dynperm)
2174 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
2175 if (pvolume_info->direct_io) {
2176 cFYI(1, ("mounting share using direct i/o"));
2177 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2178 }
2179
2180 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
2181 cERROR(1, ("mount option dynperm ignored if cifsacl "
2182 "mount option supported"));
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002183}
2184
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185int
2186cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2187 char *mount_data, const char *devname)
2188{
2189 int rc = 0;
2190 int xid;
Jeff Layton7586b762008-12-01 18:41:49 -05002191 struct smb_vol *volume_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 struct cifsSesInfo *pSesInfo = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 struct cifsTconInfo *tcon = NULL;
2194 struct TCP_Server_Info *srvTcp = NULL;
2195
2196 xid = GetXid();
2197
Jeff Layton7586b762008-12-01 18:41:49 -05002198 volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
2199 if (!volume_info) {
2200 rc = -ENOMEM;
2201 goto out;
2202 }
Steve French50c2f752007-07-13 00:33:32 +00002203
Jeff Layton7586b762008-12-01 18:41:49 -05002204 if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002205 rc = -EINVAL;
2206 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 }
2208
Jeff Layton7586b762008-12-01 18:41:49 -05002209 if (volume_info->nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002210 cFYI(1, ("null user"));
Jeff Layton7586b762008-12-01 18:41:49 -05002211 volume_info->username = "";
2212 } else if (volume_info->username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 /* BB fixme parse for domain name here */
Jeff Layton7586b762008-12-01 18:41:49 -05002214 cFYI(1, ("Username: %s", volume_info->username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08002216 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00002217 /* In userspace mount helper we can get user name from alternate
2218 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002219 rc = -EINVAL;
2220 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 }
2222
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
2224 /* this is needed for ASCII cp to Unicode converts */
Jeff Layton7586b762008-12-01 18:41:49 -05002225 if (volume_info->iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 cifs_sb->local_nls = load_nls_default();
2227 /* load_nls_default can not return null */
2228 } else {
Jeff Layton7586b762008-12-01 18:41:49 -05002229 cifs_sb->local_nls = load_nls(volume_info->iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002230 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002231 cERROR(1, ("CIFS mount error: iocharset %s not found",
Jeff Layton7586b762008-12-01 18:41:49 -05002232 volume_info->iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002233 rc = -ELIBACC;
2234 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 }
2236 }
2237
Jeff Layton63c038c2008-12-01 18:41:46 -05002238 /* get a reference to a tcp session */
Jeff Layton7586b762008-12-01 18:41:49 -05002239 srvTcp = cifs_get_tcp_session(volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05002240 if (IS_ERR(srvTcp)) {
2241 rc = PTR_ERR(srvTcp);
2242 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 }
2244
Jeff Layton7586b762008-12-01 18:41:49 -05002245 pSesInfo = cifs_find_smb_ses(srvTcp, volume_info->username);
Jeff Layton14fbf502008-11-14 13:53:46 -05002246 if (pSesInfo) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002247 cFYI(1, ("Existing smb sess found (status=%d)",
2248 pSesInfo->status));
Jeff Layton14fbf502008-11-14 13:53:46 -05002249 /*
2250 * The existing SMB session already has a reference to srvTcp,
2251 * so we can put back the extra one we got before
2252 */
2253 cifs_put_tcp_session(srvTcp);
2254
Steve French88e7d702008-01-03 17:37:09 +00002255 down(&pSesInfo->sesSem);
Steve French3b795212008-11-13 19:45:32 +00002256 if (pSesInfo->need_reconnect) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002257 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002258 rc = cifs_setup_session(xid, pSesInfo,
2259 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002260 }
Steve French88e7d702008-01-03 17:37:09 +00002261 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002263 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 pSesInfo = sesInfoAlloc();
Jeff Layton14fbf502008-11-14 13:53:46 -05002265 if (pSesInfo == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 rc = -ENOMEM;
Jeff Layton14fbf502008-11-14 13:53:46 -05002267 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 }
2269
Jeff Layton14fbf502008-11-14 13:53:46 -05002270 /* new SMB session uses our srvTcp ref */
2271 pSesInfo->server = srvTcp;
Jeff Layton63c038c2008-12-01 18:41:46 -05002272 if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6)
Linus Torvalds0191b622008-12-28 12:49:40 -08002273 sprintf(pSesInfo->serverName, "%pI6",
2274 &srvTcp->addr.sockAddr6.sin6_addr);
Jeff Layton8ecaf672008-12-01 15:23:50 -05002275 else
Linus Torvalds0191b622008-12-28 12:49:40 -08002276 sprintf(pSesInfo->serverName, "%pI4",
2277 &srvTcp->addr.sockAddr.sin_addr.s_addr);
Jeff Layton14fbf502008-11-14 13:53:46 -05002278
2279 write_lock(&cifs_tcp_ses_lock);
2280 list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
2281 write_unlock(&cifs_tcp_ses_lock);
2282
Jeff Layton7586b762008-12-01 18:41:49 -05002283 /* volume_info->password freed at unmount */
2284 if (volume_info->password) {
Jeff Layton00e485b2008-12-05 20:41:21 -05002285 pSesInfo->password = kstrdup(volume_info->password,
2286 GFP_KERNEL);
2287 if (!pSesInfo->password) {
2288 rc = -ENOMEM;
2289 goto mount_fail_check;
2290 }
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002291 }
Jeff Layton7586b762008-12-01 18:41:49 -05002292 if (volume_info->username)
2293 strncpy(pSesInfo->userName, volume_info->username,
Jeff Layton14fbf502008-11-14 13:53:46 -05002294 MAX_USERNAME_SIZE);
Jeff Layton7586b762008-12-01 18:41:49 -05002295 if (volume_info->domainname) {
2296 int len = strlen(volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002297 pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
2298 if (pSesInfo->domainName)
2299 strcpy(pSesInfo->domainName,
Jeff Layton7586b762008-12-01 18:41:49 -05002300 volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002301 }
Jeff Layton7586b762008-12-01 18:41:49 -05002302 pSesInfo->linux_uid = volume_info->linux_uid;
2303 pSesInfo->overrideSecFlg = volume_info->secFlg;
Jeff Layton14fbf502008-11-14 13:53:46 -05002304 down(&pSesInfo->sesSem);
2305
2306 /* BB FIXME need to pass vol->secFlgs BB */
2307 rc = cifs_setup_session(xid, pSesInfo,
2308 cifs_sb->local_nls);
2309 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 }
Steve French50c2f752007-07-13 00:33:32 +00002311
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 /* search for existing tcon to this server share */
2313 if (!rc) {
Jeff Layton7586b762008-12-01 18:41:49 -05002314 setup_cifs_sb(volume_info, cifs_sb);
Steve French0ae0efa2005-10-10 10:57:19 -07002315
Jeff Layton7586b762008-12-01 18:41:49 -05002316 tcon = cifs_find_tcon(pSesInfo, volume_info->UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002318 cFYI(1, ("Found match on UNC path"));
Jeff Laytonf1987b42008-11-15 11:12:47 -05002319 /* existing tcon already has a reference */
2320 cifs_put_smb_ses(pSesInfo);
Jeff Layton7586b762008-12-01 18:41:49 -05002321 if (tcon->seal != volume_info->seal)
Steve French95b1cb92008-05-15 16:44:38 +00002322 cERROR(1, ("transport encryption setting "
2323 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 } else {
2325 tcon = tconInfoAlloc();
Steve French3b795212008-11-13 19:45:32 +00002326 if (tcon == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 rc = -ENOMEM;
Steve French3b795212008-11-13 19:45:32 +00002328 goto mount_fail_check;
2329 }
Jeff Layton00e485b2008-12-05 20:41:21 -05002330
Steve Frenchab3f9922008-11-17 16:03:00 +00002331 tcon->ses = pSesInfo;
Jeff Layton00e485b2008-12-05 20:41:21 -05002332 if (volume_info->password) {
2333 tcon->password = kstrdup(volume_info->password,
2334 GFP_KERNEL);
2335 if (!tcon->password) {
2336 rc = -ENOMEM;
2337 goto mount_fail_check;
2338 }
2339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340
Steve French3b795212008-11-13 19:45:32 +00002341 /* check for null share name ie connect to dfs root */
Jeff Layton7586b762008-12-01 18:41:49 -05002342 if ((strchr(volume_info->UNC + 3, '\\') == NULL)
2343 && (strchr(volume_info->UNC + 3, '/') == NULL)) {
Steve French3b795212008-11-13 19:45:32 +00002344 /* rc = connect_to_dfs_path(...) */
2345 cFYI(1, ("DFS root not supported"));
2346 rc = -ENODEV;
2347 goto mount_fail_check;
2348 } else {
2349 /* BB Do we need to wrap sesSem around
2350 * this TCon call and Unix SetFS as
2351 * we do on SessSetup and reconnect? */
Jeff Layton7586b762008-12-01 18:41:49 -05002352 rc = CIFSTCon(xid, pSesInfo, volume_info->UNC,
Steve French3b795212008-11-13 19:45:32 +00002353 tcon, cifs_sb->local_nls);
2354 cFYI(1, ("CIFS Tcon rc = %d", rc));
Jeff Layton7586b762008-12-01 18:41:49 -05002355 if (volume_info->nodfs) {
Steve French3b795212008-11-13 19:45:32 +00002356 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2357 cFYI(1, ("DFS disabled (%d)",
2358 tcon->Flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 }
2360 }
Jeff Layton14fbf502008-11-14 13:53:46 -05002361 if (rc)
Steve French3b795212008-11-13 19:45:32 +00002362 goto mount_fail_check;
Jeff Layton7586b762008-12-01 18:41:49 -05002363 tcon->seal = volume_info->seal;
Jeff Laytonf1987b42008-11-15 11:12:47 -05002364 write_lock(&cifs_tcp_ses_lock);
2365 list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
2366 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 }
Steve French3b795212008-11-13 19:45:32 +00002368
2369 /* we can have only one retry value for a connection
2370 to a share so for resources mounted more than once
2371 to the same server share the last value passed in
2372 for the retry flag is used */
Jeff Layton7586b762008-12-01 18:41:49 -05002373 tcon->retry = volume_info->retry;
2374 tcon->nocase = volume_info->nocase;
2375 tcon->local_lease = volume_info->local_lease;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 }
Steve French4523cc32007-04-30 20:13:06 +00002377 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2379 sb->s_maxbytes = (u64) 1 << 63;
2380 } else
2381 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2382 }
2383
Steve French8af18972007-02-14 04:42:51 +00002384 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 sb->s_time_gran = 100;
2386
Steve French3b795212008-11-13 19:45:32 +00002387mount_fail_check:
Jeff Layton14fbf502008-11-14 13:53:46 -05002388 /* on error free sesinfo and tcon struct if needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 if (rc) {
Jeff Laytone7ddee92008-11-14 13:44:38 -05002390 /* If find_unc succeeded then rc == 0 so we can not end */
2391 /* up accidently freeing someone elses tcon struct */
2392 if (tcon)
Jeff Laytonf1987b42008-11-15 11:12:47 -05002393 cifs_put_tcon(tcon);
2394 else if (pSesInfo)
Jeff Layton14fbf502008-11-14 13:53:46 -05002395 cifs_put_smb_ses(pSesInfo);
Steve Frenchc18c8422007-07-18 23:21:09 +00002396 else
Jeff Layton14fbf502008-11-14 13:53:46 -05002397 cifs_put_tcp_session(srvTcp);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002398 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 }
Steve Frenchd82c2df2008-11-15 00:07:26 +00002400 cifs_sb->tcon = tcon;
Steve Frenchd82c2df2008-11-15 00:07:26 +00002401
2402 /* do not care if following two calls succeed - informational */
2403 if (!tcon->ipc) {
2404 CIFSSMBQFSDeviceInfo(xid, tcon);
2405 CIFSSMBQFSAttributeInfo(xid, tcon);
2406 }
2407
2408 /* tell server which Unix caps we support */
2409 if (tcon->ses->capabilities & CAP_UNIX)
2410 /* reset of caps checks mount to see if unix extensions
2411 disabled for just this mount */
Jeff Layton7586b762008-12-01 18:41:49 -05002412 reset_cifs_unix_caps(xid, tcon, sb, volume_info);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002413 else
2414 tcon->unix_ext = 0; /* server does not support them */
2415
2416 /* convert forward to back slashes in prepath here if needed */
2417 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2418 convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
2419
2420 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
2421 cifs_sb->rsize = 1024 * 127;
2422 cFYI(DBG2, ("no very large read support, rsize now 127K"));
2423 }
2424 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2425 cifs_sb->wsize = min(cifs_sb->wsize,
2426 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2427 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2428 cifs_sb->rsize = min(cifs_sb->rsize,
2429 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
Jeff Layton7586b762008-12-01 18:41:49 -05002431 /* volume_info->password is freed above when existing session found
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 (in which case it is not needed anymore) but when new sesion is created
2433 the password ptr is put in the new session structure (in which case the
2434 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002435out:
2436 /* zero out password before freeing */
Jeff Layton7586b762008-12-01 18:41:49 -05002437 if (volume_info) {
2438 if (volume_info->password != NULL) {
2439 memset(volume_info->password, 0,
2440 strlen(volume_info->password));
2441 kfree(volume_info->password);
2442 }
2443 kfree(volume_info->UNC);
2444 kfree(volume_info->prepath);
2445 kfree(volume_info);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 FreeXid(xid);
2448 return rc;
2449}
2450
2451static int
2452CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002453 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 const struct nls_table *nls_codepage)
2455{
2456 struct smb_hdr *smb_buffer;
2457 struct smb_hdr *smb_buffer_response;
2458 SESSION_SETUP_ANDX *pSMB;
2459 SESSION_SETUP_ANDX *pSMBr;
2460 char *bcc_ptr;
2461 char *user;
2462 char *domain;
2463 int rc = 0;
2464 int remaining_words = 0;
2465 int bytes_returned = 0;
2466 int len;
2467 __u32 capabilities;
2468 __u16 count;
2469
Steve Frencheeac8042006-01-13 21:34:58 -08002470 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002471 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 return -EINVAL;
2473 user = ses->userName;
2474 domain = ses->domainName;
2475 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002476
2477 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002479
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 smb_buffer_response = smb_buffer;
2481 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2482
2483 /* send SMBsessionSetup here */
2484 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2485 NULL /* no tCon exists yet */ , 13 /* wct */ );
2486
Steve French1982c342005-08-17 12:38:22 -07002487 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 pSMB->req_no_secext.AndXCommand = 0xFF;
2489 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2490 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2491
Steve French50c2f752007-07-13 00:33:32 +00002492 if (ses->server->secMode &
2493 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2495
2496 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2497 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2498 if (ses->capabilities & CAP_UNICODE) {
2499 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2500 capabilities |= CAP_UNICODE;
2501 }
2502 if (ses->capabilities & CAP_STATUS32) {
2503 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2504 capabilities |= CAP_STATUS32;
2505 }
2506 if (ses->capabilities & CAP_DFS) {
2507 smb_buffer->Flags2 |= SMBFLG2_DFS;
2508 capabilities |= CAP_DFS;
2509 }
2510 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2511
Steve French50c2f752007-07-13 00:33:32 +00002512 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002513 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514
2515 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002516 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002518 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2519 bcc_ptr += CIFS_SESS_KEY_SIZE;
2520 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2521 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
2523 if (ses->capabilities & CAP_UNICODE) {
2524 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2525 *bcc_ptr = 0;
2526 bcc_ptr++;
2527 }
Steve French4523cc32007-04-30 20:13:06 +00002528 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002529 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002530 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002532 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 nls_codepage);
2534 /* convert number of 16 bit words to bytes */
2535 bcc_ptr += 2 * bytes_returned;
2536 bcc_ptr += 2; /* trailing null */
2537 if (domain == NULL)
2538 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002539 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 "CIFS_LINUX_DOM", 32, nls_codepage);
2541 else
2542 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002543 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 nls_codepage);
2545 bcc_ptr += 2 * bytes_returned;
2546 bcc_ptr += 2;
2547 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002548 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 32, nls_codepage);
2550 bcc_ptr += 2 * bytes_returned;
2551 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002552 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 32, nls_codepage);
2554 bcc_ptr += 2 * bytes_returned;
2555 bcc_ptr += 2;
2556 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002557 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 64, nls_codepage);
2559 bcc_ptr += 2 * bytes_returned;
2560 bcc_ptr += 2;
2561 } else {
Steve French50c2f752007-07-13 00:33:32 +00002562 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 strncpy(bcc_ptr, user, 200);
2564 bcc_ptr += strnlen(user, 200);
2565 }
2566 *bcc_ptr = 0;
2567 bcc_ptr++;
2568 if (domain == NULL) {
2569 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2570 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2571 } else {
2572 strncpy(bcc_ptr, domain, 64);
2573 bcc_ptr += strnlen(domain, 64);
2574 *bcc_ptr = 0;
2575 bcc_ptr++;
2576 }
2577 strcpy(bcc_ptr, "Linux version ");
2578 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002579 strcpy(bcc_ptr, utsname()->release);
2580 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2582 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2583 }
2584 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2585 smb_buffer->smb_buf_length += count;
2586 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2587
2588 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002589 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 if (rc) {
2591/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2592 } else if ((smb_buffer_response->WordCount == 3)
2593 || (smb_buffer_response->WordCount == 4)) {
2594 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2595 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2596 if (action & GUEST_LOGIN)
Steve French61e74802008-12-03 00:57:54 +00002597 cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */
Steve French50c2f752007-07-13 00:33:32 +00002598 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2599 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002601 /* response can have either 3 or 4 word count - Samba sends 3 */
2602 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 if ((pSMBr->resp.hdr.WordCount == 3)
2604 || ((pSMBr->resp.hdr.WordCount == 4)
2605 && (blob_len < pSMBr->resp.ByteCount))) {
2606 if (pSMBr->resp.hdr.WordCount == 4)
2607 bcc_ptr += blob_len;
2608
2609 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2610 if ((long) (bcc_ptr) % 2) {
2611 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002612 (BCC(smb_buffer_response) - 1) / 2;
2613 /* Unicode strings must be word
2614 aligned */
2615 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 } else {
2617 remaining_words =
2618 BCC(smb_buffer_response) / 2;
2619 }
2620 len =
2621 UniStrnlen((wchar_t *) bcc_ptr,
2622 remaining_words - 1);
2623/* We look for obvious messed up bcc or strings in response so we do not go off
2624 the end since (at least) WIN2K and Windows XP have a major bug in not null
2625 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002626 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002627 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002628 ses->serverOS = kzalloc(2 * (len + 1),
2629 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002630 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002631 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002633 (__le16 *)bcc_ptr,
2634 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 bcc_ptr += 2 * (len + 1);
2636 remaining_words -= len + 1;
2637 ses->serverOS[2 * len] = 0;
2638 ses->serverOS[1 + (2 * len)] = 0;
2639 if (remaining_words > 0) {
2640 len = UniStrnlen((wchar_t *)bcc_ptr,
2641 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002642 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002643 ses->serverNOS = kzalloc(2 * (len + 1),
2644 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002645 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002646 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002648 (__le16 *)bcc_ptr,
2649 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 bcc_ptr += 2 * (len + 1);
2651 ses->serverNOS[2 * len] = 0;
2652 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002653 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002654 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002655 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 ses->flags |= CIFS_SES_NT4;
2657 }
2658 remaining_words -= len + 1;
2659 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002660 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002661 /* last string is not always null terminated
2662 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002663 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002664 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002666 kzalloc(2*(len+1),
2667 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002668 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002669 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002671 (__le16 *)bcc_ptr,
2672 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 bcc_ptr += 2 * (len + 1);
2674 ses->serverDomain[2*len] = 0;
2675 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002676 } else { /* else no more room so create
2677 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002678 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002679 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002680 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002681 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002682 }
Steve French50c2f752007-07-13 00:33:32 +00002683 } else { /* no room so create dummy domain
2684 and NOS string */
2685
Steve French433dc242005-04-28 22:41:08 -07002686 /* if these kcallocs fail not much we
2687 can do, but better to not fail the
2688 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002689 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002691 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002692 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002694 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 }
2696 } else { /* ASCII */
2697 len = strnlen(bcc_ptr, 1024);
2698 if (((long) bcc_ptr + len) - (long)
2699 pByteArea(smb_buffer_response)
2700 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002701 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002702 ses->serverOS = kzalloc(len + 1,
2703 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002704 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002705 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002706 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707
2708 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002709 /* null terminate the string */
2710 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 bcc_ptr++;
2712
2713 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002714 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002715 ses->serverNOS = kzalloc(len + 1,
2716 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002717 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002718 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 strncpy(ses->serverNOS, bcc_ptr, len);
2720 bcc_ptr += len;
2721 bcc_ptr[0] = 0;
2722 bcc_ptr++;
2723
2724 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002725 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002726 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002727 ses->serverDomain = kzalloc(len + 1,
2728 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002729 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002730 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002731 strncpy(ses->serverDomain, bcc_ptr,
2732 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 bcc_ptr += len;
2734 bcc_ptr[0] = 0;
2735 bcc_ptr++;
2736 } else
2737 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002738 ("Variable field of length %d "
2739 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 len));
2741 }
2742 } else {
Steve French61e74802008-12-03 00:57:54 +00002743 cERROR(1, ("Security Blob Length extends beyond "
Steve French50c2f752007-07-13 00:33:32 +00002744 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 }
2746 } else {
Steve French61e74802008-12-03 00:57:54 +00002747 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 smb_buffer_response->WordCount));
2749 rc = -EIO;
2750 }
Steve French433dc242005-04-28 22:41:08 -07002751sesssetup_nomem: /* do not return an error on nomem for the info strings,
2752 since that could make reconnection harder, and
2753 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002754 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755
2756 return rc;
2757}
2758
2759static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002761 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 const struct nls_table *nls_codepage)
2763{
2764 struct smb_hdr *smb_buffer;
2765 struct smb_hdr *smb_buffer_response;
2766 SESSION_SETUP_ANDX *pSMB;
2767 SESSION_SETUP_ANDX *pSMBr;
2768 char *bcc_ptr;
2769 char *domain;
2770 int rc = 0;
2771 int remaining_words = 0;
2772 int bytes_returned = 0;
2773 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002774 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 PNEGOTIATE_MESSAGE SecurityBlob;
2776 PCHALLENGE_MESSAGE SecurityBlob2;
2777 __u32 negotiate_flags, capabilities;
2778 __u16 count;
2779
Steve French12b3b8f2006-02-09 21:12:47 +00002780 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002781 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 return -EINVAL;
2783 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002784 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 smb_buffer = cifs_buf_get();
2786 if (smb_buffer == NULL) {
2787 return -ENOMEM;
2788 }
2789 smb_buffer_response = smb_buffer;
2790 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2791 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2792
2793 /* send SMBsessionSetup here */
2794 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2795 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002796
2797 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2799 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2800
2801 pSMB->req.AndXCommand = 0xFF;
2802 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2803 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2804
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002805 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2807
2808 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2809 CAP_EXTENDED_SECURITY;
2810 if (ses->capabilities & CAP_UNICODE) {
2811 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2812 capabilities |= CAP_UNICODE;
2813 }
2814 if (ses->capabilities & CAP_STATUS32) {
2815 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2816 capabilities |= CAP_STATUS32;
2817 }
2818 if (ses->capabilities & CAP_DFS) {
2819 smb_buffer->Flags2 |= SMBFLG2_DFS;
2820 capabilities |= CAP_DFS;
2821 }
2822 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2823
2824 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2825 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2826 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2827 SecurityBlob->MessageType = NtLmNegotiate;
2828 negotiate_flags =
2829 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002830 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2831 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002833 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002835/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002836 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 /* setup pointers to domain name and workstation name */
2838 bcc_ptr += SecurityBlobLength;
2839
2840 SecurityBlob->WorkstationName.Buffer = 0;
2841 SecurityBlob->WorkstationName.Length = 0;
2842 SecurityBlob->WorkstationName.MaximumLength = 0;
2843
Steve French12b3b8f2006-02-09 21:12:47 +00002844 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2845 along with username on auth request (ie the response to challenge) */
2846 SecurityBlob->DomainName.Buffer = 0;
2847 SecurityBlob->DomainName.Length = 0;
2848 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 if (ses->capabilities & CAP_UNICODE) {
2850 if ((long) bcc_ptr % 2) {
2851 *bcc_ptr = 0;
2852 bcc_ptr++;
2853 }
2854
2855 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002856 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 32, nls_codepage);
2858 bcc_ptr += 2 * bytes_returned;
2859 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002860 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 nls_codepage);
2862 bcc_ptr += 2 * bytes_returned;
2863 bcc_ptr += 2; /* null terminate Linux version */
2864 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002865 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 64, nls_codepage);
2867 bcc_ptr += 2 * bytes_returned;
2868 *(bcc_ptr + 1) = 0;
2869 *(bcc_ptr + 2) = 0;
2870 bcc_ptr += 2; /* null terminate network opsys string */
2871 *(bcc_ptr + 1) = 0;
2872 *(bcc_ptr + 2) = 0;
2873 bcc_ptr += 2; /* null domain */
2874 } else { /* ASCII */
2875 strcpy(bcc_ptr, "Linux version ");
2876 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002877 strcpy(bcc_ptr, utsname()->release);
2878 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2880 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2881 bcc_ptr++; /* empty domain field */
2882 *bcc_ptr = 0;
2883 }
2884 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2885 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2886 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2887 smb_buffer->smb_buf_length += count;
2888 pSMB->req.ByteCount = cpu_to_le16(count);
2889
2890 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002891 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892
2893 if (smb_buffer_response->Status.CifsError ==
2894 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2895 rc = 0;
2896
2897 if (rc) {
2898/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2899 } else if ((smb_buffer_response->WordCount == 3)
2900 || (smb_buffer_response->WordCount == 4)) {
2901 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2902 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2903
2904 if (action & GUEST_LOGIN)
Steve French61e74802008-12-03 00:57:54 +00002905 cFYI(1, ("Guest login"));
Steve French50c2f752007-07-13 00:33:32 +00002906 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907
Steve French50c2f752007-07-13 00:33:32 +00002908 bcc_ptr = pByteArea(smb_buffer_response);
2909 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910
2911 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2912 if (SecurityBlob2->MessageType != NtLmChallenge) {
Steve French61e74802008-12-03 00:57:54 +00002913 cFYI(1, ("Unexpected NTLMSSP message type received %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 SecurityBlob2->MessageType));
2915 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002916 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002917 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 if ((pSMBr->resp.hdr.WordCount == 3)
2919 || ((pSMBr->resp.hdr.WordCount == 4)
2920 && (blob_len <
2921 pSMBr->resp.ByteCount))) {
2922
2923 if (pSMBr->resp.hdr.WordCount == 4) {
2924 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002925 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 blob_len));
2927 }
2928
Steve French12b3b8f2006-02-09 21:12:47 +00002929 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930
2931 memcpy(ses->server->cryptKey,
2932 SecurityBlob2->Challenge,
2933 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002934 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002935 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002936 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937
Steve French50c2f752007-07-13 00:33:32 +00002938 if ((SecurityBlob2->NegotiateFlags &
2939 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002941 ses->server->secMode |=
2942 SECMODE_SIGN_REQUIRED;
2943 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002945 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 SECMODE_SIGN_ENABLED;
2947
2948 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2949 if ((long) (bcc_ptr) % 2) {
2950 remaining_words =
2951 (BCC(smb_buffer_response)
2952 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002953 /* Must word align unicode strings */
2954 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 } else {
2956 remaining_words =
2957 BCC
2958 (smb_buffer_response) / 2;
2959 }
2960 len =
2961 UniStrnlen((wchar_t *) bcc_ptr,
2962 remaining_words - 1);
2963/* We look for obvious messed up bcc or strings in response so we do not go off
2964 the end since (at least) WIN2K and Windows XP have a major bug in not null
2965 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002966 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002967 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002969 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002971 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 bcc_ptr, len,
2973 nls_codepage);
2974 bcc_ptr += 2 * (len + 1);
2975 remaining_words -= len + 1;
2976 ses->serverOS[2 * len] = 0;
2977 ses->serverOS[1 + (2 * len)] = 0;
2978 if (remaining_words > 0) {
2979 len = UniStrnlen((wchar_t *)
2980 bcc_ptr,
2981 remaining_words
2982 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002983 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002985 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 GFP_KERNEL);
2987 cifs_strfromUCS_le(ses->
2988 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002989 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 bcc_ptr,
2991 len,
2992 nls_codepage);
2993 bcc_ptr += 2 * (len + 1);
2994 ses->serverNOS[2 * len] = 0;
2995 ses->serverNOS[1 +
2996 (2 * len)] = 0;
2997 remaining_words -= len + 1;
2998 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002999 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3000 /* last string not always null terminated
3001 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00003002 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003004 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 (len +
3006 1),
3007 GFP_KERNEL);
3008 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08003009 (ses->serverDomain,
3010 (__le16 *)bcc_ptr,
3011 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 bcc_ptr +=
3013 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08003014 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08003016 ses->serverDomain
3017 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 = 0;
3019 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003020 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00003021 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003023 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003025 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00003027 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003029 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003030 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003032 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 }
3034 } else { /* ASCII */
3035 len = strnlen(bcc_ptr, 1024);
3036 if (((long) bcc_ptr + len) - (long)
3037 pByteArea(smb_buffer_response)
3038 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003039 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003040 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003042 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 GFP_KERNEL);
3044 strncpy(ses->serverOS,
3045 bcc_ptr, len);
3046
3047 bcc_ptr += len;
3048 bcc_ptr[0] = 0; /* null terminate string */
3049 bcc_ptr++;
3050
3051 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003052 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003054 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 GFP_KERNEL);
3056 strncpy(ses->serverNOS, bcc_ptr, len);
3057 bcc_ptr += len;
3058 bcc_ptr[0] = 0;
3059 bcc_ptr++;
3060
3061 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003062 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003064 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00003066 strncpy(ses->serverDomain,
3067 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 bcc_ptr += len;
3069 bcc_ptr[0] = 0;
3070 bcc_ptr++;
3071 } else
3072 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00003073 ("field of length %d "
3074 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 len));
3076 }
3077 } else {
Steve French50c2f752007-07-13 00:33:32 +00003078 cERROR(1, ("Security Blob Length extends beyond"
3079 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 }
3081 } else {
3082 cERROR(1, ("No session structure passed in."));
3083 }
3084 } else {
Steve French61e74802008-12-03 00:57:54 +00003085 cERROR(1, ("Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 smb_buffer_response->WordCount));
3087 rc = -EIO;
3088 }
3089
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003090 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
3092 return rc;
3093}
3094static int
3095CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00003096 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003097 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098{
3099 struct smb_hdr *smb_buffer;
3100 struct smb_hdr *smb_buffer_response;
3101 SESSION_SETUP_ANDX *pSMB;
3102 SESSION_SETUP_ANDX *pSMBr;
3103 char *bcc_ptr;
3104 char *user;
3105 char *domain;
3106 int rc = 0;
3107 int remaining_words = 0;
3108 int bytes_returned = 0;
3109 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003110 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 PAUTHENTICATE_MESSAGE SecurityBlob;
3112 __u32 negotiate_flags, capabilities;
3113 __u16 count;
3114
3115 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003116 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 return -EINVAL;
3118 user = ses->userName;
3119 domain = ses->domainName;
3120 smb_buffer = cifs_buf_get();
3121 if (smb_buffer == NULL) {
3122 return -ENOMEM;
3123 }
3124 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003125 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
3126 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127
3128 /* send SMBsessionSetup here */
3129 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
3130 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07003131
3132 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
3134 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
3135 pSMB->req.AndXCommand = 0xFF;
3136 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
3137 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
3138
3139 pSMB->req.hdr.Uid = ses->Suid;
3140
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003141 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3143
3144 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003145 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 if (ses->capabilities & CAP_UNICODE) {
3147 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3148 capabilities |= CAP_UNICODE;
3149 }
3150 if (ses->capabilities & CAP_STATUS32) {
3151 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3152 capabilities |= CAP_STATUS32;
3153 }
3154 if (ses->capabilities & CAP_DFS) {
3155 smb_buffer->Flags2 |= SMBFLG2_DFS;
3156 capabilities |= CAP_DFS;
3157 }
3158 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3159
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003160 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3161 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3163 SecurityBlob->MessageType = NtLmAuthenticate;
3164 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003165 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3166 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3167 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003168 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003170 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3172
3173/* setup pointers to domain name and workstation name */
3174
3175 SecurityBlob->WorkstationName.Buffer = 0;
3176 SecurityBlob->WorkstationName.Length = 0;
3177 SecurityBlob->WorkstationName.MaximumLength = 0;
3178 SecurityBlob->SessionKey.Length = 0;
3179 SecurityBlob->SessionKey.MaximumLength = 0;
3180 SecurityBlob->SessionKey.Buffer = 0;
3181
3182 SecurityBlob->LmChallengeResponse.Length = 0;
3183 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3184 SecurityBlob->LmChallengeResponse.Buffer = 0;
3185
3186 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003187 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003189 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3190 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 SecurityBlob->NtChallengeResponse.Buffer =
3192 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003193 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3194 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195
3196 if (ses->capabilities & CAP_UNICODE) {
3197 if (domain == NULL) {
3198 SecurityBlob->DomainName.Buffer = 0;
3199 SecurityBlob->DomainName.Length = 0;
3200 SecurityBlob->DomainName.MaximumLength = 0;
3201 } else {
Steve French77159b42007-08-31 01:10:17 +00003202 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003204 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003206 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 SecurityBlob->DomainName.Buffer =
3208 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003209 bcc_ptr += ln;
3210 SecurityBlobLength += ln;
3211 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 }
3213 if (user == NULL) {
3214 SecurityBlob->UserName.Buffer = 0;
3215 SecurityBlob->UserName.Length = 0;
3216 SecurityBlob->UserName.MaximumLength = 0;
3217 } else {
Steve French77159b42007-08-31 01:10:17 +00003218 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003220 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003222 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 SecurityBlob->UserName.Buffer =
3224 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003225 bcc_ptr += ln;
3226 SecurityBlobLength += ln;
3227 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 }
3229
Steve French63135e02007-07-17 17:34:02 +00003230 /* SecurityBlob->WorkstationName.Length =
3231 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003233 SecurityBlob->WorkstationName.MaximumLength =
3234 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3235 SecurityBlob->WorkstationName.Buffer =
3236 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 bcc_ptr += SecurityBlob->WorkstationName.Length;
3238 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003239 SecurityBlob->WorkstationName.Length =
3240 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
3242 if ((long) bcc_ptr % 2) {
3243 *bcc_ptr = 0;
3244 bcc_ptr++;
3245 }
3246 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003247 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 32, nls_codepage);
3249 bcc_ptr += 2 * bytes_returned;
3250 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003251 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 nls_codepage);
3253 bcc_ptr += 2 * bytes_returned;
3254 bcc_ptr += 2; /* null term version string */
3255 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003256 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 64, nls_codepage);
3258 bcc_ptr += 2 * bytes_returned;
3259 *(bcc_ptr + 1) = 0;
3260 *(bcc_ptr + 2) = 0;
3261 bcc_ptr += 2; /* null terminate network opsys string */
3262 *(bcc_ptr + 1) = 0;
3263 *(bcc_ptr + 2) = 0;
3264 bcc_ptr += 2; /* null domain */
3265 } else { /* ASCII */
3266 if (domain == NULL) {
3267 SecurityBlob->DomainName.Buffer = 0;
3268 SecurityBlob->DomainName.Length = 0;
3269 SecurityBlob->DomainName.MaximumLength = 0;
3270 } else {
Steve French77159b42007-08-31 01:10:17 +00003271 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3273 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003274 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003276 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 SecurityBlob->DomainName.Buffer =
3278 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003279 bcc_ptr += ln;
3280 SecurityBlobLength += ln;
3281 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 }
3283 if (user == NULL) {
3284 SecurityBlob->UserName.Buffer = 0;
3285 SecurityBlob->UserName.Length = 0;
3286 SecurityBlob->UserName.MaximumLength = 0;
3287 } else {
Steve French77159b42007-08-31 01:10:17 +00003288 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003290 ln = strnlen(user, 64);
3291 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003293 cpu_to_le32(SecurityBlobLength);
3294 bcc_ptr += ln;
3295 SecurityBlobLength += ln;
3296 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 }
3298 /* BB fill in our workstation name if known BB */
3299
3300 strcpy(bcc_ptr, "Linux version ");
3301 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003302 strcpy(bcc_ptr, utsname()->release);
3303 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3305 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3306 bcc_ptr++; /* null domain */
3307 *bcc_ptr = 0;
3308 }
3309 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3310 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3311 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3312 smb_buffer->smb_buf_length += count;
3313 pSMB->req.ByteCount = cpu_to_le16(count);
3314
3315 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003316 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003318/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3319 } else if ((smb_buffer_response->WordCount == 3) ||
3320 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003322 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 if (action & GUEST_LOGIN)
Steve French61e74802008-12-03 00:57:54 +00003324 cFYI(1, ("Guest login")); /* BB Should we set anything
Steve French50c2f752007-07-13 00:33:32 +00003325 in SesInfo struct ? */
3326/* if (SecurityBlob2->MessageType != NtLm??) {
3327 cFYI("Unexpected message type on auth response is %d"));
3328 } */
3329
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 if (ses) {
3331 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003332 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003334 /* UID left in wire format */
3335 ses->Suid = smb_buffer_response->Uid;
3336 bcc_ptr = pByteArea(smb_buffer_response);
3337 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 if ((pSMBr->resp.hdr.WordCount == 3)
3339 || ((pSMBr->resp.hdr.WordCount == 4)
3340 && (blob_len <
3341 pSMBr->resp.ByteCount))) {
3342 if (pSMBr->resp.hdr.WordCount == 4) {
3343 bcc_ptr +=
3344 blob_len;
3345 cFYI(1,
3346 ("Security Blob Length %d ",
3347 blob_len));
3348 }
3349
3350 cFYI(1,
3351 ("NTLMSSP response to Authenticate "));
3352
3353 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3354 if ((long) (bcc_ptr) % 2) {
3355 remaining_words =
3356 (BCC(smb_buffer_response)
3357 - 1) / 2;
3358 bcc_ptr++; /* Unicode strings must be word aligned */
3359 } else {
3360 remaining_words = BCC(smb_buffer_response) / 2;
3361 }
Steve French77159b42007-08-31 01:10:17 +00003362 len = UniStrnlen((wchar_t *) bcc_ptr,
3363 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364/* We look for obvious messed up bcc or strings in response so we do not go off
3365 the end since (at least) WIN2K and Windows XP have a major bug in not null
3366 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003367 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003368 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003370 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003372 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 bcc_ptr, len,
3374 nls_codepage);
3375 bcc_ptr += 2 * (len + 1);
3376 remaining_words -= len + 1;
3377 ses->serverOS[2 * len] = 0;
3378 ses->serverOS[1 + (2 * len)] = 0;
3379 if (remaining_words > 0) {
3380 len = UniStrnlen((wchar_t *)
3381 bcc_ptr,
3382 remaining_words
3383 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003384 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003386 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 GFP_KERNEL);
3388 cifs_strfromUCS_le(ses->
3389 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003390 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 bcc_ptr,
3392 len,
3393 nls_codepage);
3394 bcc_ptr += 2 * (len + 1);
3395 ses->serverNOS[2 * len] = 0;
3396 ses->serverNOS[1+(2*len)] = 0;
3397 remaining_words -= len + 1;
3398 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003399 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003401 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003402 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003404 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 (len +
3406 1),
3407 GFP_KERNEL);
3408 cifs_strfromUCS_le
3409 (ses->
3410 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003411 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 bcc_ptr, len,
3413 nls_codepage);
3414 bcc_ptr +=
3415 2 * (len + 1);
3416 ses->
3417 serverDomain[2
3418 * len]
3419 = 0;
3420 ses->
3421 serverDomain[1
3422 +
3423 (2
3424 *
3425 len)]
3426 = 0;
3427 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003428 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003429 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003430 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003431 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003434 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003435 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003436 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003437 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003438 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 }
3440 } else { /* ASCII */
3441 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003442 if (((long) bcc_ptr + len) -
3443 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003444 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003445 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003446 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003447 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 strncpy(ses->serverOS,bcc_ptr, len);
3449
3450 bcc_ptr += len;
3451 bcc_ptr[0] = 0; /* null terminate the string */
3452 bcc_ptr++;
3453
3454 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003455 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003456 ses->serverNOS = kzalloc(len+1,
3457 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003458 strncpy(ses->serverNOS,
3459 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 bcc_ptr += len;
3461 bcc_ptr[0] = 0;
3462 bcc_ptr++;
3463
3464 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003465 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003466 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003467 ses->serverDomain =
3468 kzalloc(len+1,
3469 GFP_KERNEL);
3470 strncpy(ses->serverDomain,
3471 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 bcc_ptr += len;
3473 bcc_ptr[0] = 0;
3474 bcc_ptr++;
3475 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003476 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003477 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 len));
3479 }
3480 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003481 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003482 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 }
3484 } else {
3485 cERROR(1, ("No session structure passed in."));
3486 }
3487 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003488 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 smb_buffer_response->WordCount));
3490 rc = -EIO;
3491 }
3492
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003493 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494
3495 return rc;
3496}
3497
3498int
3499CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3500 const char *tree, struct cifsTconInfo *tcon,
3501 const struct nls_table *nls_codepage)
3502{
3503 struct smb_hdr *smb_buffer;
3504 struct smb_hdr *smb_buffer_response;
3505 TCONX_REQ *pSMB;
3506 TCONX_RSP *pSMBr;
3507 unsigned char *bcc_ptr;
3508 int rc = 0;
3509 int length;
3510 __u16 count;
3511
3512 if (ses == NULL)
3513 return -EIO;
3514
3515 smb_buffer = cifs_buf_get();
3516 if (smb_buffer == NULL) {
3517 return -ENOMEM;
3518 }
3519 smb_buffer_response = smb_buffer;
3520
3521 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3522 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003523
3524 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 smb_buffer->Uid = ses->Suid;
3526 pSMB = (TCONX_REQ *) smb_buffer;
3527 pSMBr = (TCONX_RSP *) smb_buffer_response;
3528
3529 pSMB->AndXCommand = 0xFF;
3530 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003532 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003533 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003534 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003535 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003536 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003537 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003538 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003539 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3540 specified as required (when that support is added to
3541 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003542 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003543 by Samba (not sure whether other servers allow
3544 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003545#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003546 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Jeff Layton00e485b2008-12-05 20:41:21 -05003547 (ses->server->secType == LANMAN))
3548 calc_lanman_hash(tcon->password, ses->server->cryptKey,
Jeff Layton4e53a3f2008-12-05 20:41:21 -05003549 ses->server->secMode &
3550 SECMODE_PW_ENCRYPT ? true : false,
3551 bcc_ptr);
Steve French7c7b25b2006-06-01 19:20:10 +00003552 else
3553#endif /* CIFS_WEAK_PW_HASH */
Jeff Layton00e485b2008-12-05 20:41:21 -05003554 SMBNTencrypt(tcon->password, ses->server->cryptKey,
Steve Frencheeac8042006-01-13 21:34:58 -08003555 bcc_ptr);
3556
Steve French7c7b25b2006-06-01 19:20:10 +00003557 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003558 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003559 /* must align unicode strings */
3560 *bcc_ptr = 0; /* null byte password */
3561 bcc_ptr++;
3562 }
Steve Frencheeac8042006-01-13 21:34:58 -08003563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564
Steve French50c2f752007-07-13 00:33:32 +00003565 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003566 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3568
3569 if (ses->capabilities & CAP_STATUS32) {
3570 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3571 }
3572 if (ses->capabilities & CAP_DFS) {
3573 smb_buffer->Flags2 |= SMBFLG2_DFS;
3574 }
3575 if (ses->capabilities & CAP_UNICODE) {
3576 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3577 length =
Steve French50c2f752007-07-13 00:33:32 +00003578 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3579 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003580 (/* server len*/ + 256 /* share len */), nls_codepage);
3581 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 bcc_ptr += 2; /* skip trailing null */
3583 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 strcpy(bcc_ptr, tree);
3585 bcc_ptr += strlen(tree) + 1;
3586 }
3587 strcpy(bcc_ptr, "?????");
3588 bcc_ptr += strlen("?????");
3589 bcc_ptr += 1;
3590 count = bcc_ptr - &pSMB->Password[0];
3591 pSMB->hdr.smb_buf_length += count;
3592 pSMB->ByteCount = cpu_to_le16(count);
3593
Steve French133672e2007-11-13 22:41:37 +00003594 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3595 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
3597 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3598 /* above now done in SendReceive */
3599 if ((rc == 0) && (tcon != NULL)) {
3600 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003601 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 tcon->tid = smb_buffer_response->Tid;
3603 bcc_ptr = pByteArea(smb_buffer_response);
3604 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003605 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003606 if (length == 3) {
3607 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3608 (bcc_ptr[2] == 'C')) {
3609 cFYI(1, ("IPC connection"));
3610 tcon->ipc = 1;
3611 }
3612 } else if (length == 2) {
3613 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3614 /* the most common case */
3615 cFYI(1, ("disk share connection"));
3616 }
3617 }
Steve French50c2f752007-07-13 00:33:32 +00003618 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3620 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3621 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3622 if ((bcc_ptr + (2 * length)) -
3623 pByteArea(smb_buffer_response) <=
3624 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003625 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003627 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003628 if (tcon->nativeFileSystem)
3629 cifs_strfromUCS_le(
3630 tcon->nativeFileSystem,
3631 (__le16 *) bcc_ptr,
3632 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 bcc_ptr += 2 * length;
3634 bcc_ptr[0] = 0; /* null terminate the string */
3635 bcc_ptr[1] = 0;
3636 bcc_ptr += 2;
3637 }
Steve French50c2f752007-07-13 00:33:32 +00003638 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 } else {
3640 length = strnlen(bcc_ptr, 1024);
3641 if ((bcc_ptr + length) -
3642 pByteArea(smb_buffer_response) <=
3643 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003644 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003646 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003647 if (tcon->nativeFileSystem)
3648 strncpy(tcon->nativeFileSystem, bcc_ptr,
3649 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 }
Steve French50c2f752007-07-13 00:33:32 +00003651 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003653 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003654 (smb_buffer_response->WordCount == 7))
3655 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003656 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3657 else
3658 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3660 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003661 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 ses->ipc_tid = smb_buffer_response->Tid;
3663 }
3664
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003665 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 return rc;
3667}
3668
3669int
3670cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3671{
3672 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003673 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674
Jeff Laytonf1987b42008-11-15 11:12:47 -05003675 if (cifs_sb->tcon)
3676 cifs_put_tcon(cifs_sb->tcon);
Steve French50c2f752007-07-13 00:33:32 +00003677
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003679 tmp = cifs_sb->prepath;
3680 cifs_sb->prepathlen = 0;
3681 cifs_sb->prepath = NULL;
3682 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683
Steve French88e7d702008-01-03 17:37:09 +00003684 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003685}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686
3687int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003688 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689{
3690 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003691 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003692 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003693 int first_time = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003694 struct TCP_Server_Info *server = pSesInfo->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695
3696 /* what if server changes its buffer size after dropping the session? */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003697 if (server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 rc = CIFSSMBNegotiate(xid, pSesInfo);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003699 if (rc == -EAGAIN) {
3700 /* retry only once on 1st time connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003702 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 rc = -EHOSTDOWN;
3704 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003705 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 spin_lock(&GlobalMid_Lock);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003707 if (server->tcpStatus != CifsExiting)
3708 server->tcpStatus = CifsGood;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 else
3710 rc = -EHOSTDOWN;
3711 spin_unlock(&GlobalMid_Lock);
3712
3713 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003714 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 }
Steve French26b994f2008-08-06 05:11:33 +00003716
3717 if (rc)
3718 goto ss_err_exit;
3719
3720 pSesInfo->flags = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003721 pSesInfo->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003722 if (linuxExtEnabled == 0)
3723 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003724 /* pSesInfo->sequence_number = 0;*/
Steve French26b994f2008-08-06 05:11:33 +00003725 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003726 server->secMode, server->capabilities, server->timeAdj));
3727
Steve French26b994f2008-08-06 05:11:33 +00003728 if (experimEnabled < 2)
3729 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
3730 else if (extended_security
3731 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003732 && (server->secType == NTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003733 rc = -EOPNOTSUPP;
3734 } else if (extended_security
3735 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003736 && (server->secType == RawNTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003737 cFYI(1, ("NTLMSSP sesssetup"));
3738 rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
3739 nls_info);
3740 if (!rc) {
3741 if (ntlmv2_flag) {
3742 char *v2_response;
3743 cFYI(1, ("more secure NTLM ver2 hash"));
3744 if (CalcNTLMv2_partial_mac_key(pSesInfo,
3745 nls_info)) {
3746 rc = -ENOMEM;
3747 goto ss_err_exit;
3748 } else
3749 v2_response = kmalloc(16 + 64 /* blob*/,
3750 GFP_KERNEL);
3751 if (v2_response) {
3752 CalcNTLMv2_response(pSesInfo,
3753 v2_response);
3754 /* if (first_time)
3755 cifs_calculate_ntlmv2_mac_key */
3756 kfree(v2_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 /* BB Put dummy sig in SessSetup PDU? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 } else {
Steve French26b994f2008-08-06 05:11:33 +00003759 rc = -ENOMEM;
3760 goto ss_err_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 }
Steve French26b994f2008-08-06 05:11:33 +00003762
3763 } else {
3764 SMBNTencrypt(pSesInfo->password,
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003765 server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003766 ntlm_session_key);
3767
3768 if (first_time)
3769 cifs_calculate_mac_key(
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003770 &server->mac_signing_key,
Steve French26b994f2008-08-06 05:11:33 +00003771 ntlm_session_key,
3772 pSesInfo->password);
3773 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 /* for better security the weaker lanman hash not sent
3775 in AuthSessSetup so we no longer calculate it */
3776
Steve French26b994f2008-08-06 05:11:33 +00003777 rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
3778 ntlm_session_key,
3779 ntlmv2_flag,
3780 nls_info);
3781 }
3782 } else { /* old style NTLM 0.12 session setup */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003783 SMBNTencrypt(pSesInfo->password, server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003784 ntlm_session_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785
Steve French26b994f2008-08-06 05:11:33 +00003786 if (first_time)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003787 cifs_calculate_mac_key(&server->mac_signing_key,
3788 ntlm_session_key,
3789 pSesInfo->password);
Steve Frenchad009ac2005-04-28 22:41:05 -07003790
Steve French26b994f2008-08-06 05:11:33 +00003791 rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 }
Steve French26b994f2008-08-06 05:11:33 +00003793 if (rc) {
3794 cERROR(1, ("Send error in SessSetup = %d", rc));
3795 } else {
3796 cFYI(1, ("CIFS Session Established successfully"));
Jeff Layton469ee612008-10-16 18:46:39 +00003797 spin_lock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003798 pSesInfo->status = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003799 pSesInfo->need_reconnect = false;
Jeff Layton469ee612008-10-16 18:46:39 +00003800 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003801 }
3802
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803ss_err_exit:
3804 return rc;
3805}
3806