blob: da0f4ffa06132f725570a79f7e0b5fb0b65d1eb6 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/pagemap.h>
27#include <linux/ctype.h>
28#include <linux/utsname.h>
29#include <linux/mempool.h>
Steve Frenchb8643e12005-04-28 22:41:07 -070030#include <linux/delay.h>
Steve Frenchf1914012005-08-18 09:37:34 -070031#include <linux/completion.h>
Igor Mammedovaaf737a2007-04-03 19:16:43 +000032#include <linux/kthread.h>
Steve French0ae0efa2005-10-10 10:57:19 -070033#include <linux/pagevec.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080034#include <linux/freezer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <asm/uaccess.h>
36#include <asm/processor.h>
Steve French0e2beda2009-01-30 21:24:41 +000037#include <net/ipv6.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#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 *
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001357cifs_find_tcp_session(struct sockaddr_storage *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 Laytona9ac49d2009-01-22 14:43:21 -05001377 if (addr->ss_family == AF_INET &&
Jeff Laytone7ddee92008-11-14 13:44:38 -05001378 (addr4->sin_addr.s_addr !=
1379 server->addr.sockAddr.sin_addr.s_addr))
1380 continue;
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001381 else if (addr->ss_family == AF_INET6 &&
Steve French0e2beda2009-01-30 21:24:41 +00001382 !ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
1383 &addr6->sin6_addr))
Jeff Laytone7ddee92008-11-14 13:44:38 -05001384 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;
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001422 struct sockaddr_storage addr;
Jeff Layton63c038c2008-12-01 18:41:46 -05001423 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
1424 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
1425 int rc;
1426
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001427 memset(&addr, 0, sizeof(struct sockaddr_storage));
Jeff Layton63c038c2008-12-01 18:41:46 -05001428
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)
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001438 addr.ss_family = AF_INET6;
Jeff Layton63c038c2008-12-01 18:41:46 -05001439 } else {
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001440 addr.ss_family = AF_INET;
Jeff Layton63c038c2008-12-01 18:41:46 -05001441 }
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
Jeff Laytona9ac49d2009-01-22 14:43:21 -05001505 if (addr.ss_family == AF_INET6) {
Jeff Layton63c038c2008-12-01 18:41:46 -05001506 cFYI(1, ("attempting ipv6 connect"));
1507 /* BB should we allow ipv6 on port 139? */
1508 /* other OS never observed in Wild doing 139 with v6 */
1509 memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
1510 sizeof(struct sockaddr_in6));
1511 sin_server6->sin6_port = htons(volume_info->port);
Jeff Laytond5c56052008-12-01 18:42:33 -05001512 rc = ipv6_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001513 } else {
1514 memcpy(&tcp_ses->addr.sockAddr, sin_server,
1515 sizeof(struct sockaddr_in));
1516 sin_server->sin_port = htons(volume_info->port);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001517 rc = ipv4_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001518 }
1519 if (rc < 0) {
1520 cERROR(1, ("Error connecting to socket. Aborting operation"));
1521 goto out_err;
1522 }
1523
1524 /*
1525 * since we're in a cifs function already, we know that
1526 * this will succeed. No need for try_module_get().
1527 */
1528 __module_get(THIS_MODULE);
1529 tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
1530 tcp_ses, "cifsd");
1531 if (IS_ERR(tcp_ses->tsk)) {
1532 rc = PTR_ERR(tcp_ses->tsk);
1533 cERROR(1, ("error %d create cifsd thread", rc));
1534 module_put(THIS_MODULE);
1535 goto out_err;
1536 }
1537
1538 /* thread spawned, put it on the list */
1539 write_lock(&cifs_tcp_ses_lock);
1540 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
1541 write_unlock(&cifs_tcp_ses_lock);
1542
1543 return tcp_ses;
1544
1545out_err:
1546 if (tcp_ses) {
1547 kfree(tcp_ses->hostname);
1548 if (tcp_ses->ssocket)
1549 sock_release(tcp_ses->ssocket);
1550 kfree(tcp_ses);
1551 }
1552 return ERR_PTR(rc);
1553}
1554
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555static struct cifsSesInfo *
Jeff Layton14fbf502008-11-14 13:53:46 -05001556cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557{
1558 struct list_head *tmp;
1559 struct cifsSesInfo *ses;
1560
Jeff Layton14fbf502008-11-14 13:53:46 -05001561 write_lock(&cifs_tcp_ses_lock);
1562 list_for_each(tmp, &server->smb_ses_list) {
1563 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
1564 if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 continue;
1566
Jeff Layton14fbf502008-11-14 13:53:46 -05001567 ++ses->ses_count;
1568 write_unlock(&cifs_tcp_ses_lock);
1569 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 }
Jeff Layton14fbf502008-11-14 13:53:46 -05001571 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 return NULL;
1573}
1574
Jeff Layton14fbf502008-11-14 13:53:46 -05001575static void
1576cifs_put_smb_ses(struct cifsSesInfo *ses)
1577{
1578 int xid;
1579 struct TCP_Server_Info *server = ses->server;
1580
1581 write_lock(&cifs_tcp_ses_lock);
1582 if (--ses->ses_count > 0) {
1583 write_unlock(&cifs_tcp_ses_lock);
1584 return;
1585 }
1586
1587 list_del_init(&ses->smb_ses_list);
1588 write_unlock(&cifs_tcp_ses_lock);
1589
1590 if (ses->status == CifsGood) {
1591 xid = GetXid();
1592 CIFSSMBLogoff(xid, ses);
1593 _FreeXid(xid);
1594 }
1595 sesInfoFree(ses);
1596 cifs_put_tcp_session(server);
1597}
1598
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599static struct cifsTconInfo *
Jeff Laytonf1987b42008-11-15 11:12:47 -05001600cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601{
1602 struct list_head *tmp;
1603 struct cifsTconInfo *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
Jeff Laytonf1987b42008-11-15 11:12:47 -05001605 write_lock(&cifs_tcp_ses_lock);
1606 list_for_each(tmp, &ses->tcon_list) {
1607 tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
1608 if (tcon->tidStatus == CifsExiting)
1609 continue;
1610 if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 continue;
1612
Jeff Laytonf1987b42008-11-15 11:12:47 -05001613 ++tcon->tc_count;
1614 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 return tcon;
1616 }
Jeff Laytonf1987b42008-11-15 11:12:47 -05001617 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 return NULL;
1619}
1620
Jeff Laytonf1987b42008-11-15 11:12:47 -05001621static void
1622cifs_put_tcon(struct cifsTconInfo *tcon)
1623{
1624 int xid;
1625 struct cifsSesInfo *ses = tcon->ses;
1626
1627 write_lock(&cifs_tcp_ses_lock);
1628 if (--tcon->tc_count > 0) {
1629 write_unlock(&cifs_tcp_ses_lock);
1630 return;
1631 }
1632
1633 list_del_init(&tcon->tcon_list);
1634 write_unlock(&cifs_tcp_ses_lock);
1635
1636 xid = GetXid();
1637 CIFSSMBTDis(xid, tcon);
1638 _FreeXid(xid);
1639
1640 DeleteTconOplockQEntries(tcon);
1641 tconInfoFree(tcon);
1642 cifs_put_smb_ses(ses);
1643}
1644
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645int
Steve French50c2f752007-07-13 00:33:32 +00001646get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1647 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001648 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649{
1650 char *temp_unc;
1651 int rc = 0;
1652
1653 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001654 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
1656 if (pSesInfo->ipc_tid == 0) {
1657 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001658 strnlen(pSesInfo->serverName,
1659 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 + 1 + 4 /* slash IPC$ */ + 2,
1661 GFP_KERNEL);
1662 if (temp_unc == NULL)
1663 return -ENOMEM;
1664 temp_unc[0] = '\\';
1665 temp_unc[1] = '\\';
1666 strcpy(temp_unc + 2, pSesInfo->serverName);
1667 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1668 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1669 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001670 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 kfree(temp_unc);
1672 }
1673 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00001674 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001675 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00001676 /* BB map targetUNCs to dfs_info3 structures, here or
1677 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
1679 return rc;
1680}
1681
Jeff Layton09e50d52008-07-23 10:11:19 -04001682#ifdef CONFIG_DEBUG_LOCK_ALLOC
1683static struct lock_class_key cifs_key[2];
1684static struct lock_class_key cifs_slock_key[2];
1685
1686static inline void
1687cifs_reclassify_socket4(struct socket *sock)
1688{
1689 struct sock *sk = sock->sk;
1690 BUG_ON(sock_owned_by_user(sk));
1691 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
1692 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
1693}
1694
1695static inline void
1696cifs_reclassify_socket6(struct socket *sock)
1697{
1698 struct sock *sk = sock->sk;
1699 BUG_ON(sock_owned_by_user(sk));
1700 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
1701 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
1702}
1703#else
1704static inline void
1705cifs_reclassify_socket4(struct socket *sock)
1706{
1707}
1708
1709static inline void
1710cifs_reclassify_socket6(struct socket *sock)
1711{
1712}
1713#endif
1714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001716static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717{
Steve French50c2f752007-07-13 00:33:32 +00001718 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719
Steve French50c2f752007-07-13 00:33:32 +00001720 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 /* mask a nibble at a time and encode */
1722 target[j] = 'A' + (0x0F & (source[i] >> 4));
1723 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001724 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 }
1726
1727}
1728
1729
1730static int
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001731ipv4_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732{
1733 int rc = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001734 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 __be16 orig_port = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001736 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001738 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001739 rc = sock_create_kern(PF_INET, SOCK_STREAM,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001740 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001742 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001745
1746 /* BB other socket options to set KEEPALIVE, NODELAY? */
1747 cFYI(1, ("Socket created"));
1748 server->ssocket = socket;
1749 socket->sk->sk_allocation = GFP_NOFS;
1750 cifs_reclassify_socket4(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
1752
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001753 /* user overrode default port */
1754 if (server->addr.sockAddr.sin_port) {
1755 rc = socket->ops->connect(socket, (struct sockaddr *)
1756 &server->addr.sockAddr,
1757 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001759 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00001760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001762 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001763 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 later if fall back ports fail this time */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001765 orig_port = server->addr.sockAddr.sin_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
1767 /* do not retry on the same port we just failed on */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001768 if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) {
1769 server->addr.sockAddr.sin_port = htons(CIFS_PORT);
1770 rc = socket->ops->connect(socket,
1771 (struct sockaddr *)
1772 &server->addr.sockAddr,
1773 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001775 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 }
1777 }
1778 if (!connected) {
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001779 server->addr.sockAddr.sin_port = htons(RFC1001_PORT);
1780 rc = socket->ops->connect(socket, (struct sockaddr *)
1781 &server->addr.sockAddr,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001782 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001783 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001784 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 }
1786
1787 /* give up here - unless we want to retry on different
1788 protocol families some day */
1789 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001790 if (orig_port)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001791 server->addr.sockAddr.sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001792 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001793 sock_release(socket);
1794 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 return rc;
1796 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001797
1798
1799 /*
1800 * Eventually check for other socket options to change from
1801 * the default. sock_setsockopt not used because it expects
1802 * user space buffer
1803 */
1804 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00001805 socket->sk->sk_sndtimeo = 5 * HZ;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001806
Steve Frenchb387eae2005-10-10 14:21:15 -07001807 /* make the bufsizes depend on wsize/rsize and max requests */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001808 if (server->noautotune) {
1809 if (socket->sk->sk_sndbuf < (200 * 1024))
1810 socket->sk->sk_sndbuf = 200 * 1024;
1811 if (socket->sk->sk_rcvbuf < (140 * 1024))
1812 socket->sk->sk_rcvbuf = 140 * 1024;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001815 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1816 socket->sk->sk_sndbuf,
1817 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo));
1818
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 /* send RFC1001 sessinit */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001820 if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001822 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001824 struct rfc1002_session_packet *ses_init_buf;
1825 struct smb_hdr *smb_buf;
1826 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1827 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001828 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 ses_init_buf->trailer.session_req.called_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001830 if (server->server_RFC1001_name &&
1831 server->server_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05001832 rfc1002mangle(ses_init_buf->trailer.
1833 session_req.called_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001834 server->server_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05001835 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001836 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05001837 rfc1002mangle(ses_init_buf->trailer.
1838 session_req.called_name,
1839 DEFAULT_CIFS_CALLED_NAME,
1840 RFC1001_NAME_LEN_WITH_NULL);
Steve Frencha10faeb22005-08-22 21:38:31 -07001841
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 ses_init_buf->trailer.session_req.calling_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001843
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 /* calling name ends in null (byte 16) from old smb
1845 convention. */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001846 if (server->workstation_RFC1001_name &&
1847 server->workstation_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05001848 rfc1002mangle(ses_init_buf->trailer.
1849 session_req.calling_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001850 server->workstation_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05001851 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001852 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05001853 rfc1002mangle(ses_init_buf->trailer.
1854 session_req.calling_name,
1855 "LINUX_CIFS_CLNT",
1856 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001857
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 ses_init_buf->trailer.session_req.scope1 = 0;
1859 ses_init_buf->trailer.session_req.scope2 = 0;
1860 smb_buf = (struct smb_hdr *)ses_init_buf;
1861 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1862 smb_buf->smb_buf_length = 0x81000044;
Jeff Layton0496e022008-12-30 12:39:16 -05001863 rc = smb_send(server, smb_buf, 0x44);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001865 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001866 requires very short break before negprot
1867 presumably because not expecting negprot
1868 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001869 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001870 complicating the code and causes no
1871 significant slowing down on mount
1872 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 }
Steve French50c2f752007-07-13 00:33:32 +00001874 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001876
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 }
Steve French50c2f752007-07-13 00:33:32 +00001878
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 return rc;
1880}
1881
1882static int
Jeff Laytond5c56052008-12-01 18:42:33 -05001883ipv6_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884{
1885 int rc = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05001886 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 __be16 orig_port = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05001888 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
Jeff Laytond5c56052008-12-01 18:42:33 -05001890 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001891 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
Jeff Laytond5c56052008-12-01 18:42:33 -05001892 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001894 cERROR(1, ("Error %d creating ipv6 socket", rc));
Jeff Laytond5c56052008-12-01 18:42:33 -05001895 socket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 }
Jeff Laytond5c56052008-12-01 18:42:33 -05001898
1899 /* BB other socket options to set KEEPALIVE, NODELAY? */
1900 cFYI(1, ("ipv6 Socket created"));
1901 server->ssocket = socket;
1902 socket->sk->sk_allocation = GFP_NOFS;
1903 cifs_reclassify_socket6(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 }
1905
Jeff Laytond5c56052008-12-01 18:42:33 -05001906 /* user overrode default port */
1907 if (server->addr.sockAddr6.sin6_port) {
1908 rc = socket->ops->connect(socket,
1909 (struct sockaddr *) &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001910 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001912 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00001913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001915 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001916 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 later if fall back ports fail this time */
1918
Jeff Laytond5c56052008-12-01 18:42:33 -05001919 orig_port = server->addr.sockAddr6.sin6_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 /* do not retry on the same port we just failed on */
Jeff Laytond5c56052008-12-01 18:42:33 -05001921 if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) {
1922 server->addr.sockAddr6.sin6_port = htons(CIFS_PORT);
1923 rc = socket->ops->connect(socket, (struct sockaddr *)
1924 &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001925 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001927 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 }
1929 }
1930 if (!connected) {
Jeff Laytond5c56052008-12-01 18:42:33 -05001931 server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT);
1932 rc = socket->ops->connect(socket, (struct sockaddr *)
1933 &server->addr.sockAddr6,
1934 sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001935 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001936 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 }
1938
1939 /* give up here - unless we want to retry on different
1940 protocol families some day */
1941 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001942 if (orig_port)
Jeff Laytond5c56052008-12-01 18:42:33 -05001943 server->addr.sockAddr6.sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001944 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Jeff Laytond5c56052008-12-01 18:42:33 -05001945 sock_release(socket);
1946 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 return rc;
1948 }
Steve Frenchedf1ae42008-10-29 00:47:57 +00001949
Jeff Laytond5c56052008-12-01 18:42:33 -05001950 /*
1951 * Eventually check for other socket options to change from
1952 * the default. sock_setsockopt not used because it expects
1953 * user space buffer
1954 */
1955 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00001956 socket->sk->sk_sndtimeo = 5 * HZ;
Jeff Laytond5c56052008-12-01 18:42:33 -05001957 server->ssocket = socket;
Steve French50c2f752007-07-13 00:33:32 +00001958
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 return rc;
1960}
1961
Steve French50c2f752007-07-13 00:33:32 +00001962void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1963 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001964{
1965 /* if we are reconnecting then should we check to see if
1966 * any requested capabilities changed locally e.g. via
1967 * remount but we can not do much about it here
1968 * if they have (even if we could detect it by the following)
1969 * Perhaps we could add a backpointer to array of sb from tcon
1970 * or if we change to make all sb to same share the same
1971 * sb as NFS - then we only have one backpointer to sb.
1972 * What if we wanted to mount the server share twice once with
1973 * and once without posixacls or posix paths? */
1974 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001975
Steve Frenchc18c8422007-07-18 23:21:09 +00001976 if (vol_info && vol_info->no_linux_ext) {
1977 tcon->fsUnixInfo.Capability = 0;
1978 tcon->unix_ext = 0; /* Unix Extensions disabled */
1979 cFYI(1, ("Linux protocol extensions disabled"));
1980 return;
1981 } else if (vol_info)
1982 tcon->unix_ext = 1; /* Unix Extensions supported */
1983
1984 if (tcon->unix_ext == 0) {
1985 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1986 return;
1987 }
Steve French50c2f752007-07-13 00:33:32 +00001988
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001989 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001990 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001991
Steve French8af18972007-02-14 04:42:51 +00001992 /* check for reconnect case in which we do not
1993 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001994 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001995 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001996 originally at mount time */
1997 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1998 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001999 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2000 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
2001 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00002002 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002003 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2004 cERROR(1, ("possible reconnect error"));
2005 cERROR(1,
2006 ("server disabled POSIX path support"));
2007 }
Steve French8af18972007-02-14 04:42:51 +00002008 }
Steve French50c2f752007-07-13 00:33:32 +00002009
Steve French8af18972007-02-14 04:42:51 +00002010 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00002011 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00002012 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002013 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002014 cFYI(1, ("negotiated posix acl support"));
2015 if (sb)
Steve French8af18972007-02-14 04:42:51 +00002016 sb->s_flags |= MS_POSIXACL;
2017 }
2018
Steve French75865f8c2007-06-24 18:30:48 +00002019 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00002020 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002021 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002022 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00002023 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00002024 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00002025 CIFS_MOUNT_POSIX_PATHS;
2026 }
Steve French50c2f752007-07-13 00:33:32 +00002027
Steve French984acfe2007-04-26 16:42:50 +00002028 /* We might be setting the path sep back to a different
2029 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00002030 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00002031 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00002032 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00002033
2034 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
2035 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
2036 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00002037 cFYI(DBG2,
2038 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00002039 }
2040 }
Steve French50c2f752007-07-13 00:33:32 +00002041
2042
2043 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00002044#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00002045 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002046 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002047 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002048 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002049 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002050 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002051 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002052 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002053 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002054 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002055 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002056 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002057 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002058 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00002059#endif /* CIFS_DEBUG2 */
2060 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00002061 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00002062 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00002063 } else
Steve French5a44b312007-09-20 15:16:24 +00002064 cERROR(1, ("Negotiating Unix capabilities "
2065 "with the server failed. Consider "
2066 "mounting with the Unix Extensions\n"
2067 "disabled, if problems are found, "
2068 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00002069 "option."));
Steve French5a44b312007-09-20 15:16:24 +00002070
Steve French8af18972007-02-14 04:42:51 +00002071 }
2072 }
2073}
2074
Steve French03a143c2008-02-14 06:38:30 +00002075static void
2076convert_delimiter(char *path, char delim)
2077{
2078 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002079 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00002080
2081 if (path == NULL)
2082 return;
2083
Steve French582d21e2008-05-13 04:54:12 +00002084 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002085 old_delim = '\\';
2086 else
2087 old_delim = '/';
2088
Steve French03a143c2008-02-14 06:38:30 +00002089 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002090 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00002091 path[i] = delim;
2092 }
2093}
2094
Steve French3b795212008-11-13 19:45:32 +00002095static void setup_cifs_sb(struct smb_vol *pvolume_info,
2096 struct cifs_sb_info *cifs_sb)
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002097{
Steve French3b795212008-11-13 19:45:32 +00002098 if (pvolume_info->rsize > CIFSMaxBufSize) {
2099 cERROR(1, ("rsize %d too large, using MaxBufSize",
2100 pvolume_info->rsize));
2101 cifs_sb->rsize = CIFSMaxBufSize;
2102 } else if ((pvolume_info->rsize) &&
2103 (pvolume_info->rsize <= CIFSMaxBufSize))
2104 cifs_sb->rsize = pvolume_info->rsize;
2105 else /* default */
2106 cifs_sb->rsize = CIFSMaxBufSize;
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002107
Steve French3b795212008-11-13 19:45:32 +00002108 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
2109 cERROR(1, ("wsize %d too large, using 4096 instead",
2110 pvolume_info->wsize));
2111 cifs_sb->wsize = 4096;
2112 } else if (pvolume_info->wsize)
2113 cifs_sb->wsize = pvolume_info->wsize;
2114 else
2115 cifs_sb->wsize = min_t(const int,
2116 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2117 127*1024);
2118 /* old default of CIFSMaxBufSize was too small now
2119 that SMB Write2 can send multiple pages in kvec.
2120 RFC1001 does not describe what happens when frame
2121 bigger than 128K is sent so use that as max in
2122 conjunction with 52K kvec constraint on arch with 4K
2123 page size */
2124
2125 if (cifs_sb->rsize < 2048) {
2126 cifs_sb->rsize = 2048;
2127 /* Windows ME may prefer this */
2128 cFYI(1, ("readsize set to minimum: 2048"));
2129 }
2130 /* calculate prepath */
2131 cifs_sb->prepath = pvolume_info->prepath;
2132 if (cifs_sb->prepath) {
2133 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2134 /* we can not convert the / to \ in the path
2135 separators in the prefixpath yet because we do not
2136 know (until reset_cifs_unix_caps is called later)
2137 whether POSIX PATH CAP is available. We normalize
2138 the / to \ after reset_cifs_unix_caps is called */
2139 pvolume_info->prepath = NULL;
2140 } else
2141 cifs_sb->prepathlen = 0;
2142 cifs_sb->mnt_uid = pvolume_info->linux_uid;
2143 cifs_sb->mnt_gid = pvolume_info->linux_gid;
2144 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
2145 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
2146 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2147 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
2148
2149 if (pvolume_info->noperm)
2150 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
2151 if (pvolume_info->setuids)
2152 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
2153 if (pvolume_info->server_ino)
2154 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
2155 if (pvolume_info->remap)
2156 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
2157 if (pvolume_info->no_xattr)
2158 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
2159 if (pvolume_info->sfu_emul)
2160 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
2161 if (pvolume_info->nobrl)
2162 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French13a6e422008-12-02 17:24:33 +00002163 if (pvolume_info->mand_lock)
2164 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
Steve French3b795212008-11-13 19:45:32 +00002165 if (pvolume_info->cifs_acl)
2166 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2167 if (pvolume_info->override_uid)
2168 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2169 if (pvolume_info->override_gid)
2170 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2171 if (pvolume_info->dynperm)
2172 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
2173 if (pvolume_info->direct_io) {
2174 cFYI(1, ("mounting share using direct i/o"));
2175 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2176 }
2177
2178 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
2179 cERROR(1, ("mount option dynperm ignored if cifsacl "
2180 "mount option supported"));
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002181}
2182
Igor Mammedove4cce942009-02-10 14:10:26 +03002183static int
2184is_path_accessible(int xid, struct cifsTconInfo *tcon,
2185 struct cifs_sb_info *cifs_sb, const char *full_path)
2186{
2187 int rc;
2188 __u64 inode_num;
2189 FILE_ALL_INFO *pfile_info;
2190
2191 rc = CIFSGetSrvInodeNumber(xid, tcon, full_path, &inode_num,
2192 cifs_sb->local_nls,
2193 cifs_sb->mnt_cifs_flags &
2194 CIFS_MOUNT_MAP_SPECIAL_CHR);
2195 if (rc != -EOPNOTSUPP)
2196 return rc;
2197
2198 pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
2199 if (pfile_info == NULL)
2200 return -ENOMEM;
2201
2202 rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
2203 0 /* not legacy */, cifs_sb->local_nls,
2204 cifs_sb->mnt_cifs_flags &
2205 CIFS_MOUNT_MAP_SPECIAL_CHR);
2206 kfree(pfile_info);
2207 return rc;
2208}
2209
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210int
2211cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2212 char *mount_data, const char *devname)
2213{
2214 int rc = 0;
2215 int xid;
Jeff Layton7586b762008-12-01 18:41:49 -05002216 struct smb_vol *volume_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 struct cifsSesInfo *pSesInfo = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 struct cifsTconInfo *tcon = NULL;
2219 struct TCP_Server_Info *srvTcp = NULL;
Igor Mammedove4cce942009-02-10 14:10:26 +03002220 char *full_path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
2222 xid = GetXid();
2223
Jeff Layton7586b762008-12-01 18:41:49 -05002224 volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
2225 if (!volume_info) {
2226 rc = -ENOMEM;
2227 goto out;
2228 }
Steve French50c2f752007-07-13 00:33:32 +00002229
Jeff Layton7586b762008-12-01 18:41:49 -05002230 if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002231 rc = -EINVAL;
2232 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 }
2234
Jeff Layton7586b762008-12-01 18:41:49 -05002235 if (volume_info->nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002236 cFYI(1, ("null user"));
Jeff Layton7586b762008-12-01 18:41:49 -05002237 volume_info->username = "";
2238 } else if (volume_info->username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 /* BB fixme parse for domain name here */
Jeff Layton7586b762008-12-01 18:41:49 -05002240 cFYI(1, ("Username: %s", volume_info->username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08002242 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00002243 /* In userspace mount helper we can get user name from alternate
2244 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002245 rc = -EINVAL;
2246 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 }
2248
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249
2250 /* this is needed for ASCII cp to Unicode converts */
Jeff Layton7586b762008-12-01 18:41:49 -05002251 if (volume_info->iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 cifs_sb->local_nls = load_nls_default();
2253 /* load_nls_default can not return null */
2254 } else {
Jeff Layton7586b762008-12-01 18:41:49 -05002255 cifs_sb->local_nls = load_nls(volume_info->iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002256 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002257 cERROR(1, ("CIFS mount error: iocharset %s not found",
Jeff Layton7586b762008-12-01 18:41:49 -05002258 volume_info->iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002259 rc = -ELIBACC;
2260 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 }
2262 }
2263
Jeff Layton63c038c2008-12-01 18:41:46 -05002264 /* get a reference to a tcp session */
Jeff Layton7586b762008-12-01 18:41:49 -05002265 srvTcp = cifs_get_tcp_session(volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05002266 if (IS_ERR(srvTcp)) {
2267 rc = PTR_ERR(srvTcp);
2268 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 }
2270
Jeff Layton7586b762008-12-01 18:41:49 -05002271 pSesInfo = cifs_find_smb_ses(srvTcp, volume_info->username);
Jeff Layton14fbf502008-11-14 13:53:46 -05002272 if (pSesInfo) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002273 cFYI(1, ("Existing smb sess found (status=%d)",
2274 pSesInfo->status));
Jeff Layton14fbf502008-11-14 13:53:46 -05002275 /*
2276 * The existing SMB session already has a reference to srvTcp,
2277 * so we can put back the extra one we got before
2278 */
2279 cifs_put_tcp_session(srvTcp);
2280
Steve French88e7d702008-01-03 17:37:09 +00002281 down(&pSesInfo->sesSem);
Steve French3b795212008-11-13 19:45:32 +00002282 if (pSesInfo->need_reconnect) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002283 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002284 rc = cifs_setup_session(xid, pSesInfo,
2285 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002286 }
Steve French88e7d702008-01-03 17:37:09 +00002287 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002289 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 pSesInfo = sesInfoAlloc();
Jeff Layton14fbf502008-11-14 13:53:46 -05002291 if (pSesInfo == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 rc = -ENOMEM;
Jeff Layton14fbf502008-11-14 13:53:46 -05002293 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 }
2295
Jeff Layton14fbf502008-11-14 13:53:46 -05002296 /* new SMB session uses our srvTcp ref */
2297 pSesInfo->server = srvTcp;
Jeff Layton63c038c2008-12-01 18:41:46 -05002298 if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6)
Linus Torvalds0191b622008-12-28 12:49:40 -08002299 sprintf(pSesInfo->serverName, "%pI6",
2300 &srvTcp->addr.sockAddr6.sin6_addr);
Jeff Layton8ecaf672008-12-01 15:23:50 -05002301 else
Linus Torvalds0191b622008-12-28 12:49:40 -08002302 sprintf(pSesInfo->serverName, "%pI4",
2303 &srvTcp->addr.sockAddr.sin_addr.s_addr);
Jeff Layton14fbf502008-11-14 13:53:46 -05002304
2305 write_lock(&cifs_tcp_ses_lock);
2306 list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
2307 write_unlock(&cifs_tcp_ses_lock);
2308
Jeff Layton7586b762008-12-01 18:41:49 -05002309 /* volume_info->password freed at unmount */
2310 if (volume_info->password) {
Jeff Layton00e485b2008-12-05 20:41:21 -05002311 pSesInfo->password = kstrdup(volume_info->password,
2312 GFP_KERNEL);
2313 if (!pSesInfo->password) {
2314 rc = -ENOMEM;
2315 goto mount_fail_check;
2316 }
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002317 }
Jeff Layton7586b762008-12-01 18:41:49 -05002318 if (volume_info->username)
2319 strncpy(pSesInfo->userName, volume_info->username,
Jeff Layton14fbf502008-11-14 13:53:46 -05002320 MAX_USERNAME_SIZE);
Jeff Layton7586b762008-12-01 18:41:49 -05002321 if (volume_info->domainname) {
2322 int len = strlen(volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002323 pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
2324 if (pSesInfo->domainName)
2325 strcpy(pSesInfo->domainName,
Jeff Layton7586b762008-12-01 18:41:49 -05002326 volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002327 }
Jeff Layton7586b762008-12-01 18:41:49 -05002328 pSesInfo->linux_uid = volume_info->linux_uid;
2329 pSesInfo->overrideSecFlg = volume_info->secFlg;
Jeff Layton14fbf502008-11-14 13:53:46 -05002330 down(&pSesInfo->sesSem);
2331
2332 /* BB FIXME need to pass vol->secFlgs BB */
2333 rc = cifs_setup_session(xid, pSesInfo,
2334 cifs_sb->local_nls);
2335 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 }
Steve French50c2f752007-07-13 00:33:32 +00002337
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 /* search for existing tcon to this server share */
2339 if (!rc) {
Jeff Layton7586b762008-12-01 18:41:49 -05002340 setup_cifs_sb(volume_info, cifs_sb);
Steve French0ae0efa2005-10-10 10:57:19 -07002341
Jeff Layton7586b762008-12-01 18:41:49 -05002342 tcon = cifs_find_tcon(pSesInfo, volume_info->UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002344 cFYI(1, ("Found match on UNC path"));
Jeff Laytonf1987b42008-11-15 11:12:47 -05002345 /* existing tcon already has a reference */
2346 cifs_put_smb_ses(pSesInfo);
Jeff Layton7586b762008-12-01 18:41:49 -05002347 if (tcon->seal != volume_info->seal)
Steve French95b1cb92008-05-15 16:44:38 +00002348 cERROR(1, ("transport encryption setting "
2349 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 } else {
2351 tcon = tconInfoAlloc();
Steve French3b795212008-11-13 19:45:32 +00002352 if (tcon == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 rc = -ENOMEM;
Steve French3b795212008-11-13 19:45:32 +00002354 goto mount_fail_check;
2355 }
Jeff Layton00e485b2008-12-05 20:41:21 -05002356
Steve Frenchab3f9922008-11-17 16:03:00 +00002357 tcon->ses = pSesInfo;
Jeff Layton00e485b2008-12-05 20:41:21 -05002358 if (volume_info->password) {
2359 tcon->password = kstrdup(volume_info->password,
2360 GFP_KERNEL);
2361 if (!tcon->password) {
2362 rc = -ENOMEM;
2363 goto mount_fail_check;
2364 }
2365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366
Steve French3b795212008-11-13 19:45:32 +00002367 /* check for null share name ie connect to dfs root */
Jeff Layton7586b762008-12-01 18:41:49 -05002368 if ((strchr(volume_info->UNC + 3, '\\') == NULL)
2369 && (strchr(volume_info->UNC + 3, '/') == NULL)) {
Steve French3b795212008-11-13 19:45:32 +00002370 /* rc = connect_to_dfs_path(...) */
2371 cFYI(1, ("DFS root not supported"));
2372 rc = -ENODEV;
2373 goto mount_fail_check;
2374 } else {
2375 /* BB Do we need to wrap sesSem around
2376 * this TCon call and Unix SetFS as
2377 * we do on SessSetup and reconnect? */
Jeff Layton7586b762008-12-01 18:41:49 -05002378 rc = CIFSTCon(xid, pSesInfo, volume_info->UNC,
Steve French3b795212008-11-13 19:45:32 +00002379 tcon, cifs_sb->local_nls);
2380 cFYI(1, ("CIFS Tcon rc = %d", rc));
Jeff Layton7586b762008-12-01 18:41:49 -05002381 if (volume_info->nodfs) {
Steve French3b795212008-11-13 19:45:32 +00002382 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2383 cFYI(1, ("DFS disabled (%d)",
2384 tcon->Flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 }
2386 }
Jeff Layton14fbf502008-11-14 13:53:46 -05002387 if (rc)
Steve French3b795212008-11-13 19:45:32 +00002388 goto mount_fail_check;
Jeff Layton7586b762008-12-01 18:41:49 -05002389 tcon->seal = volume_info->seal;
Jeff Laytonf1987b42008-11-15 11:12:47 -05002390 write_lock(&cifs_tcp_ses_lock);
2391 list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
2392 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 }
Steve French3b795212008-11-13 19:45:32 +00002394
2395 /* we can have only one retry value for a connection
2396 to a share so for resources mounted more than once
2397 to the same server share the last value passed in
2398 for the retry flag is used */
Jeff Layton7586b762008-12-01 18:41:49 -05002399 tcon->retry = volume_info->retry;
2400 tcon->nocase = volume_info->nocase;
2401 tcon->local_lease = volume_info->local_lease;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 }
Steve French4523cc32007-04-30 20:13:06 +00002403 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2405 sb->s_maxbytes = (u64) 1 << 63;
2406 } else
2407 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2408 }
2409
Steve French8af18972007-02-14 04:42:51 +00002410 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 sb->s_time_gran = 100;
2412
Steve French3b795212008-11-13 19:45:32 +00002413mount_fail_check:
Jeff Layton14fbf502008-11-14 13:53:46 -05002414 /* on error free sesinfo and tcon struct if needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 if (rc) {
Jeff Laytone7ddee92008-11-14 13:44:38 -05002416 /* If find_unc succeeded then rc == 0 so we can not end */
2417 /* up accidently freeing someone elses tcon struct */
2418 if (tcon)
Jeff Laytonf1987b42008-11-15 11:12:47 -05002419 cifs_put_tcon(tcon);
2420 else if (pSesInfo)
Jeff Layton14fbf502008-11-14 13:53:46 -05002421 cifs_put_smb_ses(pSesInfo);
Steve Frenchc18c8422007-07-18 23:21:09 +00002422 else
Jeff Layton14fbf502008-11-14 13:53:46 -05002423 cifs_put_tcp_session(srvTcp);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002424 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 }
Steve Frenchd82c2df2008-11-15 00:07:26 +00002426 cifs_sb->tcon = tcon;
Steve Frenchd82c2df2008-11-15 00:07:26 +00002427
2428 /* do not care if following two calls succeed - informational */
2429 if (!tcon->ipc) {
2430 CIFSSMBQFSDeviceInfo(xid, tcon);
2431 CIFSSMBQFSAttributeInfo(xid, tcon);
2432 }
2433
2434 /* tell server which Unix caps we support */
2435 if (tcon->ses->capabilities & CAP_UNIX)
2436 /* reset of caps checks mount to see if unix extensions
2437 disabled for just this mount */
Jeff Layton7586b762008-12-01 18:41:49 -05002438 reset_cifs_unix_caps(xid, tcon, sb, volume_info);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002439 else
2440 tcon->unix_ext = 0; /* server does not support them */
2441
2442 /* convert forward to back slashes in prepath here if needed */
2443 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2444 convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
2445
2446 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
2447 cifs_sb->rsize = 1024 * 127;
2448 cFYI(DBG2, ("no very large read support, rsize now 127K"));
2449 }
2450 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2451 cifs_sb->wsize = min(cifs_sb->wsize,
2452 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2453 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2454 cifs_sb->rsize = min(cifs_sb->rsize,
2455 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456
Igor Mammedove4cce942009-02-10 14:10:26 +03002457 if (!rc && cifs_sb->prepathlen) {
2458 /* build_path_to_root works only when we have a valid tcon */
2459 full_path = cifs_build_path_to_root(cifs_sb);
2460 if (full_path == NULL) {
2461 rc = -ENOMEM;
2462 goto mount_fail_check;
2463 }
2464 rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
2465 if (rc) {
2466 cERROR(1, ("Path %s in not accessible: %d",
2467 full_path, rc));
2468 kfree(full_path);
2469 goto mount_fail_check;
2470 }
2471 kfree(full_path);
2472 }
2473
Jeff Layton7586b762008-12-01 18:41:49 -05002474 /* volume_info->password is freed above when existing session found
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 (in which case it is not needed anymore) but when new sesion is created
2476 the password ptr is put in the new session structure (in which case the
2477 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002478out:
2479 /* zero out password before freeing */
Jeff Layton7586b762008-12-01 18:41:49 -05002480 if (volume_info) {
2481 if (volume_info->password != NULL) {
2482 memset(volume_info->password, 0,
2483 strlen(volume_info->password));
2484 kfree(volume_info->password);
2485 }
2486 kfree(volume_info->UNC);
2487 kfree(volume_info->prepath);
2488 kfree(volume_info);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 FreeXid(xid);
2491 return rc;
2492}
2493
2494static int
2495CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002496 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 const struct nls_table *nls_codepage)
2498{
2499 struct smb_hdr *smb_buffer;
2500 struct smb_hdr *smb_buffer_response;
2501 SESSION_SETUP_ANDX *pSMB;
2502 SESSION_SETUP_ANDX *pSMBr;
2503 char *bcc_ptr;
2504 char *user;
2505 char *domain;
2506 int rc = 0;
2507 int remaining_words = 0;
2508 int bytes_returned = 0;
2509 int len;
2510 __u32 capabilities;
2511 __u16 count;
2512
Steve Frencheeac8042006-01-13 21:34:58 -08002513 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002514 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 return -EINVAL;
2516 user = ses->userName;
2517 domain = ses->domainName;
2518 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002519
2520 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002522
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 smb_buffer_response = smb_buffer;
2524 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2525
2526 /* send SMBsessionSetup here */
2527 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2528 NULL /* no tCon exists yet */ , 13 /* wct */ );
2529
Steve French1982c342005-08-17 12:38:22 -07002530 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 pSMB->req_no_secext.AndXCommand = 0xFF;
2532 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2533 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2534
Steve French50c2f752007-07-13 00:33:32 +00002535 if (ses->server->secMode &
2536 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2538
2539 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2540 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2541 if (ses->capabilities & CAP_UNICODE) {
2542 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2543 capabilities |= CAP_UNICODE;
2544 }
2545 if (ses->capabilities & CAP_STATUS32) {
2546 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2547 capabilities |= CAP_STATUS32;
2548 }
2549 if (ses->capabilities & CAP_DFS) {
2550 smb_buffer->Flags2 |= SMBFLG2_DFS;
2551 capabilities |= CAP_DFS;
2552 }
2553 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2554
Steve French50c2f752007-07-13 00:33:32 +00002555 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002556 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557
2558 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002559 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002561 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2562 bcc_ptr += CIFS_SESS_KEY_SIZE;
2563 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2564 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565
2566 if (ses->capabilities & CAP_UNICODE) {
2567 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2568 *bcc_ptr = 0;
2569 bcc_ptr++;
2570 }
Steve French4523cc32007-04-30 20:13:06 +00002571 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002572 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002573 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002575 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 nls_codepage);
2577 /* convert number of 16 bit words to bytes */
2578 bcc_ptr += 2 * bytes_returned;
2579 bcc_ptr += 2; /* trailing null */
2580 if (domain == NULL)
2581 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002582 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 "CIFS_LINUX_DOM", 32, nls_codepage);
2584 else
2585 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002586 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 nls_codepage);
2588 bcc_ptr += 2 * bytes_returned;
2589 bcc_ptr += 2;
2590 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002591 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 32, nls_codepage);
2593 bcc_ptr += 2 * bytes_returned;
2594 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002595 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 32, nls_codepage);
2597 bcc_ptr += 2 * bytes_returned;
2598 bcc_ptr += 2;
2599 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002600 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 64, nls_codepage);
2602 bcc_ptr += 2 * bytes_returned;
2603 bcc_ptr += 2;
2604 } else {
Steve French50c2f752007-07-13 00:33:32 +00002605 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 strncpy(bcc_ptr, user, 200);
2607 bcc_ptr += strnlen(user, 200);
2608 }
2609 *bcc_ptr = 0;
2610 bcc_ptr++;
2611 if (domain == NULL) {
2612 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2613 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2614 } else {
2615 strncpy(bcc_ptr, domain, 64);
2616 bcc_ptr += strnlen(domain, 64);
2617 *bcc_ptr = 0;
2618 bcc_ptr++;
2619 }
2620 strcpy(bcc_ptr, "Linux version ");
2621 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002622 strcpy(bcc_ptr, utsname()->release);
2623 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2625 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2626 }
2627 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2628 smb_buffer->smb_buf_length += count;
2629 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2630
2631 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002632 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 if (rc) {
2634/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2635 } else if ((smb_buffer_response->WordCount == 3)
2636 || (smb_buffer_response->WordCount == 4)) {
2637 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2638 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2639 if (action & GUEST_LOGIN)
Steve French61e74802008-12-03 00:57:54 +00002640 cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */
Steve French50c2f752007-07-13 00:33:32 +00002641 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2642 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002644 /* response can have either 3 or 4 word count - Samba sends 3 */
2645 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 if ((pSMBr->resp.hdr.WordCount == 3)
2647 || ((pSMBr->resp.hdr.WordCount == 4)
2648 && (blob_len < pSMBr->resp.ByteCount))) {
2649 if (pSMBr->resp.hdr.WordCount == 4)
2650 bcc_ptr += blob_len;
2651
2652 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2653 if ((long) (bcc_ptr) % 2) {
2654 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002655 (BCC(smb_buffer_response) - 1) / 2;
2656 /* Unicode strings must be word
2657 aligned */
2658 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 } else {
2660 remaining_words =
2661 BCC(smb_buffer_response) / 2;
2662 }
2663 len =
2664 UniStrnlen((wchar_t *) bcc_ptr,
2665 remaining_words - 1);
2666/* We look for obvious messed up bcc or strings in response so we do not go off
2667 the end since (at least) WIN2K and Windows XP have a major bug in not null
2668 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002669 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002670 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002671 ses->serverOS = kzalloc(2 * (len + 1),
2672 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002673 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002674 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002676 (__le16 *)bcc_ptr,
2677 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 bcc_ptr += 2 * (len + 1);
2679 remaining_words -= len + 1;
2680 ses->serverOS[2 * len] = 0;
2681 ses->serverOS[1 + (2 * len)] = 0;
2682 if (remaining_words > 0) {
2683 len = UniStrnlen((wchar_t *)bcc_ptr,
2684 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002685 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002686 ses->serverNOS = kzalloc(2 * (len + 1),
2687 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002688 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002689 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002691 (__le16 *)bcc_ptr,
2692 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 bcc_ptr += 2 * (len + 1);
2694 ses->serverNOS[2 * len] = 0;
2695 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002696 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002697 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002698 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 ses->flags |= CIFS_SES_NT4;
2700 }
2701 remaining_words -= len + 1;
2702 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002703 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002704 /* last string is not always null terminated
2705 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002706 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002707 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002709 kzalloc(2*(len+1),
2710 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002711 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002712 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002714 (__le16 *)bcc_ptr,
2715 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 bcc_ptr += 2 * (len + 1);
2717 ses->serverDomain[2*len] = 0;
2718 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002719 } else { /* else no more room so create
2720 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002721 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002722 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002723 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002724 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002725 }
Steve French50c2f752007-07-13 00:33:32 +00002726 } else { /* no room so create dummy domain
2727 and NOS string */
2728
Steve French433dc242005-04-28 22:41:08 -07002729 /* if these kcallocs fail not much we
2730 can do, but better to not fail the
2731 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002732 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002734 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002735 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002737 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 }
2739 } else { /* ASCII */
2740 len = strnlen(bcc_ptr, 1024);
2741 if (((long) bcc_ptr + len) - (long)
2742 pByteArea(smb_buffer_response)
2743 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002744 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002745 ses->serverOS = kzalloc(len + 1,
2746 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002747 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002748 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002749 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
2751 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002752 /* null terminate the string */
2753 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 bcc_ptr++;
2755
2756 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002757 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002758 ses->serverNOS = kzalloc(len + 1,
2759 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002760 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002761 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 strncpy(ses->serverNOS, bcc_ptr, len);
2763 bcc_ptr += len;
2764 bcc_ptr[0] = 0;
2765 bcc_ptr++;
2766
2767 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002768 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002769 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002770 ses->serverDomain = kzalloc(len + 1,
2771 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002772 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002773 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002774 strncpy(ses->serverDomain, bcc_ptr,
2775 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 bcc_ptr += len;
2777 bcc_ptr[0] = 0;
2778 bcc_ptr++;
2779 } else
2780 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002781 ("Variable field of length %d "
2782 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 len));
2784 }
2785 } else {
Steve French61e74802008-12-03 00:57:54 +00002786 cERROR(1, ("Security Blob Length extends beyond "
Steve French50c2f752007-07-13 00:33:32 +00002787 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 }
2789 } else {
Steve French61e74802008-12-03 00:57:54 +00002790 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 smb_buffer_response->WordCount));
2792 rc = -EIO;
2793 }
Steve French433dc242005-04-28 22:41:08 -07002794sesssetup_nomem: /* do not return an error on nomem for the info strings,
2795 since that could make reconnection harder, and
2796 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002797 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798
2799 return rc;
2800}
2801
2802static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002804 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 const struct nls_table *nls_codepage)
2806{
2807 struct smb_hdr *smb_buffer;
2808 struct smb_hdr *smb_buffer_response;
2809 SESSION_SETUP_ANDX *pSMB;
2810 SESSION_SETUP_ANDX *pSMBr;
2811 char *bcc_ptr;
2812 char *domain;
2813 int rc = 0;
2814 int remaining_words = 0;
2815 int bytes_returned = 0;
2816 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002817 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 PNEGOTIATE_MESSAGE SecurityBlob;
2819 PCHALLENGE_MESSAGE SecurityBlob2;
2820 __u32 negotiate_flags, capabilities;
2821 __u16 count;
2822
Steve French12b3b8f2006-02-09 21:12:47 +00002823 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002824 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 return -EINVAL;
2826 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002827 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 smb_buffer = cifs_buf_get();
2829 if (smb_buffer == NULL) {
2830 return -ENOMEM;
2831 }
2832 smb_buffer_response = smb_buffer;
2833 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2834 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2835
2836 /* send SMBsessionSetup here */
2837 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2838 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002839
2840 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2842 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2843
2844 pSMB->req.AndXCommand = 0xFF;
2845 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2846 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2847
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002848 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2850
2851 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2852 CAP_EXTENDED_SECURITY;
2853 if (ses->capabilities & CAP_UNICODE) {
2854 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2855 capabilities |= CAP_UNICODE;
2856 }
2857 if (ses->capabilities & CAP_STATUS32) {
2858 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2859 capabilities |= CAP_STATUS32;
2860 }
2861 if (ses->capabilities & CAP_DFS) {
2862 smb_buffer->Flags2 |= SMBFLG2_DFS;
2863 capabilities |= CAP_DFS;
2864 }
2865 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2866
2867 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2868 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2869 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2870 SecurityBlob->MessageType = NtLmNegotiate;
2871 negotiate_flags =
2872 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002873 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2874 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002876 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002878/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002879 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 /* setup pointers to domain name and workstation name */
2881 bcc_ptr += SecurityBlobLength;
2882
2883 SecurityBlob->WorkstationName.Buffer = 0;
2884 SecurityBlob->WorkstationName.Length = 0;
2885 SecurityBlob->WorkstationName.MaximumLength = 0;
2886
Steve French12b3b8f2006-02-09 21:12:47 +00002887 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2888 along with username on auth request (ie the response to challenge) */
2889 SecurityBlob->DomainName.Buffer = 0;
2890 SecurityBlob->DomainName.Length = 0;
2891 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 if (ses->capabilities & CAP_UNICODE) {
2893 if ((long) bcc_ptr % 2) {
2894 *bcc_ptr = 0;
2895 bcc_ptr++;
2896 }
2897
2898 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002899 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 32, nls_codepage);
2901 bcc_ptr += 2 * bytes_returned;
2902 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002903 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 nls_codepage);
2905 bcc_ptr += 2 * bytes_returned;
2906 bcc_ptr += 2; /* null terminate Linux version */
2907 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002908 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 64, nls_codepage);
2910 bcc_ptr += 2 * bytes_returned;
2911 *(bcc_ptr + 1) = 0;
2912 *(bcc_ptr + 2) = 0;
2913 bcc_ptr += 2; /* null terminate network opsys string */
2914 *(bcc_ptr + 1) = 0;
2915 *(bcc_ptr + 2) = 0;
2916 bcc_ptr += 2; /* null domain */
2917 } else { /* ASCII */
2918 strcpy(bcc_ptr, "Linux version ");
2919 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002920 strcpy(bcc_ptr, utsname()->release);
2921 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2923 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2924 bcc_ptr++; /* empty domain field */
2925 *bcc_ptr = 0;
2926 }
2927 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2928 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2929 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2930 smb_buffer->smb_buf_length += count;
2931 pSMB->req.ByteCount = cpu_to_le16(count);
2932
2933 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002934 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
2936 if (smb_buffer_response->Status.CifsError ==
2937 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2938 rc = 0;
2939
2940 if (rc) {
2941/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2942 } else if ((smb_buffer_response->WordCount == 3)
2943 || (smb_buffer_response->WordCount == 4)) {
2944 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2945 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2946
2947 if (action & GUEST_LOGIN)
Steve French61e74802008-12-03 00:57:54 +00002948 cFYI(1, ("Guest login"));
Steve French50c2f752007-07-13 00:33:32 +00002949 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950
Steve French50c2f752007-07-13 00:33:32 +00002951 bcc_ptr = pByteArea(smb_buffer_response);
2952 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953
2954 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2955 if (SecurityBlob2->MessageType != NtLmChallenge) {
Steve French61e74802008-12-03 00:57:54 +00002956 cFYI(1, ("Unexpected NTLMSSP message type received %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 SecurityBlob2->MessageType));
2958 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002959 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002960 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 if ((pSMBr->resp.hdr.WordCount == 3)
2962 || ((pSMBr->resp.hdr.WordCount == 4)
2963 && (blob_len <
2964 pSMBr->resp.ByteCount))) {
2965
2966 if (pSMBr->resp.hdr.WordCount == 4) {
2967 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002968 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 blob_len));
2970 }
2971
Steve French12b3b8f2006-02-09 21:12:47 +00002972 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973
2974 memcpy(ses->server->cryptKey,
2975 SecurityBlob2->Challenge,
2976 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002977 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002978 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002979 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980
Steve French50c2f752007-07-13 00:33:32 +00002981 if ((SecurityBlob2->NegotiateFlags &
2982 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002984 ses->server->secMode |=
2985 SECMODE_SIGN_REQUIRED;
2986 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002988 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 SECMODE_SIGN_ENABLED;
2990
2991 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2992 if ((long) (bcc_ptr) % 2) {
2993 remaining_words =
2994 (BCC(smb_buffer_response)
2995 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002996 /* Must word align unicode strings */
2997 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 } else {
2999 remaining_words =
3000 BCC
3001 (smb_buffer_response) / 2;
3002 }
3003 len =
3004 UniStrnlen((wchar_t *) bcc_ptr,
3005 remaining_words - 1);
3006/* We look for obvious messed up bcc or strings in response so we do not go off
3007 the end since (at least) WIN2K and Windows XP have a major bug in not null
3008 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003009 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003010 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003012 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003014 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 bcc_ptr, len,
3016 nls_codepage);
3017 bcc_ptr += 2 * (len + 1);
3018 remaining_words -= len + 1;
3019 ses->serverOS[2 * len] = 0;
3020 ses->serverOS[1 + (2 * len)] = 0;
3021 if (remaining_words > 0) {
3022 len = UniStrnlen((wchar_t *)
3023 bcc_ptr,
3024 remaining_words
3025 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003026 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003028 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 GFP_KERNEL);
3030 cifs_strfromUCS_le(ses->
3031 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003032 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 bcc_ptr,
3034 len,
3035 nls_codepage);
3036 bcc_ptr += 2 * (len + 1);
3037 ses->serverNOS[2 * len] = 0;
3038 ses->serverNOS[1 +
3039 (2 * len)] = 0;
3040 remaining_words -= len + 1;
3041 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003042 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
3043 /* last string not always null terminated
3044 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00003045 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003047 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 (len +
3049 1),
3050 GFP_KERNEL);
3051 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08003052 (ses->serverDomain,
3053 (__le16 *)bcc_ptr,
3054 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 bcc_ptr +=
3056 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08003057 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08003059 ses->serverDomain
3060 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 = 0;
3062 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003063 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00003064 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003066 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00003070 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003072 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003073 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003075 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 }
3077 } else { /* ASCII */
3078 len = strnlen(bcc_ptr, 1024);
3079 if (((long) bcc_ptr + len) - (long)
3080 pByteArea(smb_buffer_response)
3081 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003082 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003083 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003085 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 GFP_KERNEL);
3087 strncpy(ses->serverOS,
3088 bcc_ptr, len);
3089
3090 bcc_ptr += len;
3091 bcc_ptr[0] = 0; /* null terminate string */
3092 bcc_ptr++;
3093
3094 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003095 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003097 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 GFP_KERNEL);
3099 strncpy(ses->serverNOS, bcc_ptr, len);
3100 bcc_ptr += len;
3101 bcc_ptr[0] = 0;
3102 bcc_ptr++;
3103
3104 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003105 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003107 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00003109 strncpy(ses->serverDomain,
3110 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 bcc_ptr += len;
3112 bcc_ptr[0] = 0;
3113 bcc_ptr++;
3114 } else
3115 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00003116 ("field of length %d "
3117 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 len));
3119 }
3120 } else {
Steve French50c2f752007-07-13 00:33:32 +00003121 cERROR(1, ("Security Blob Length extends beyond"
3122 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 }
3124 } else {
3125 cERROR(1, ("No session structure passed in."));
3126 }
3127 } else {
Steve French61e74802008-12-03 00:57:54 +00003128 cERROR(1, ("Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 smb_buffer_response->WordCount));
3130 rc = -EIO;
3131 }
3132
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003133 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134
3135 return rc;
3136}
3137static int
3138CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00003139 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003140 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141{
3142 struct smb_hdr *smb_buffer;
3143 struct smb_hdr *smb_buffer_response;
3144 SESSION_SETUP_ANDX *pSMB;
3145 SESSION_SETUP_ANDX *pSMBr;
3146 char *bcc_ptr;
3147 char *user;
3148 char *domain;
3149 int rc = 0;
3150 int remaining_words = 0;
3151 int bytes_returned = 0;
3152 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003153 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 PAUTHENTICATE_MESSAGE SecurityBlob;
3155 __u32 negotiate_flags, capabilities;
3156 __u16 count;
3157
3158 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003159 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 return -EINVAL;
3161 user = ses->userName;
3162 domain = ses->domainName;
3163 smb_buffer = cifs_buf_get();
3164 if (smb_buffer == NULL) {
3165 return -ENOMEM;
3166 }
3167 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003168 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
3169 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170
3171 /* send SMBsessionSetup here */
3172 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
3173 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07003174
3175 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
3177 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
3178 pSMB->req.AndXCommand = 0xFF;
3179 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
3180 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
3181
3182 pSMB->req.hdr.Uid = ses->Suid;
3183
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003184 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3186
3187 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003188 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 if (ses->capabilities & CAP_UNICODE) {
3190 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3191 capabilities |= CAP_UNICODE;
3192 }
3193 if (ses->capabilities & CAP_STATUS32) {
3194 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3195 capabilities |= CAP_STATUS32;
3196 }
3197 if (ses->capabilities & CAP_DFS) {
3198 smb_buffer->Flags2 |= SMBFLG2_DFS;
3199 capabilities |= CAP_DFS;
3200 }
3201 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3202
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003203 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3204 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3206 SecurityBlob->MessageType = NtLmAuthenticate;
3207 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003208 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3209 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3210 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003211 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003213 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3215
3216/* setup pointers to domain name and workstation name */
3217
3218 SecurityBlob->WorkstationName.Buffer = 0;
3219 SecurityBlob->WorkstationName.Length = 0;
3220 SecurityBlob->WorkstationName.MaximumLength = 0;
3221 SecurityBlob->SessionKey.Length = 0;
3222 SecurityBlob->SessionKey.MaximumLength = 0;
3223 SecurityBlob->SessionKey.Buffer = 0;
3224
3225 SecurityBlob->LmChallengeResponse.Length = 0;
3226 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3227 SecurityBlob->LmChallengeResponse.Buffer = 0;
3228
3229 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003230 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003232 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3233 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 SecurityBlob->NtChallengeResponse.Buffer =
3235 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003236 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3237 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238
3239 if (ses->capabilities & CAP_UNICODE) {
3240 if (domain == NULL) {
3241 SecurityBlob->DomainName.Buffer = 0;
3242 SecurityBlob->DomainName.Length = 0;
3243 SecurityBlob->DomainName.MaximumLength = 0;
3244 } else {
Steve French77159b42007-08-31 01:10:17 +00003245 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003247 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003249 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 SecurityBlob->DomainName.Buffer =
3251 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003252 bcc_ptr += ln;
3253 SecurityBlobLength += ln;
3254 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 }
3256 if (user == NULL) {
3257 SecurityBlob->UserName.Buffer = 0;
3258 SecurityBlob->UserName.Length = 0;
3259 SecurityBlob->UserName.MaximumLength = 0;
3260 } else {
Steve French77159b42007-08-31 01:10:17 +00003261 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003263 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003265 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 SecurityBlob->UserName.Buffer =
3267 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003268 bcc_ptr += ln;
3269 SecurityBlobLength += ln;
3270 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 }
3272
Steve French63135e02007-07-17 17:34:02 +00003273 /* SecurityBlob->WorkstationName.Length =
3274 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003276 SecurityBlob->WorkstationName.MaximumLength =
3277 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3278 SecurityBlob->WorkstationName.Buffer =
3279 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 bcc_ptr += SecurityBlob->WorkstationName.Length;
3281 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003282 SecurityBlob->WorkstationName.Length =
3283 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284
3285 if ((long) bcc_ptr % 2) {
3286 *bcc_ptr = 0;
3287 bcc_ptr++;
3288 }
3289 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003290 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 32, nls_codepage);
3292 bcc_ptr += 2 * bytes_returned;
3293 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003294 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 nls_codepage);
3296 bcc_ptr += 2 * bytes_returned;
3297 bcc_ptr += 2; /* null term version string */
3298 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003299 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 64, nls_codepage);
3301 bcc_ptr += 2 * bytes_returned;
3302 *(bcc_ptr + 1) = 0;
3303 *(bcc_ptr + 2) = 0;
3304 bcc_ptr += 2; /* null terminate network opsys string */
3305 *(bcc_ptr + 1) = 0;
3306 *(bcc_ptr + 2) = 0;
3307 bcc_ptr += 2; /* null domain */
3308 } else { /* ASCII */
3309 if (domain == NULL) {
3310 SecurityBlob->DomainName.Buffer = 0;
3311 SecurityBlob->DomainName.Length = 0;
3312 SecurityBlob->DomainName.MaximumLength = 0;
3313 } else {
Steve French77159b42007-08-31 01:10:17 +00003314 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3316 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003317 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003319 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 SecurityBlob->DomainName.Buffer =
3321 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003322 bcc_ptr += ln;
3323 SecurityBlobLength += ln;
3324 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 }
3326 if (user == NULL) {
3327 SecurityBlob->UserName.Buffer = 0;
3328 SecurityBlob->UserName.Length = 0;
3329 SecurityBlob->UserName.MaximumLength = 0;
3330 } else {
Steve French77159b42007-08-31 01:10:17 +00003331 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003333 ln = strnlen(user, 64);
3334 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003336 cpu_to_le32(SecurityBlobLength);
3337 bcc_ptr += ln;
3338 SecurityBlobLength += ln;
3339 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 }
3341 /* BB fill in our workstation name if known BB */
3342
3343 strcpy(bcc_ptr, "Linux version ");
3344 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003345 strcpy(bcc_ptr, utsname()->release);
3346 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3348 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3349 bcc_ptr++; /* null domain */
3350 *bcc_ptr = 0;
3351 }
3352 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3353 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3354 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3355 smb_buffer->smb_buf_length += count;
3356 pSMB->req.ByteCount = cpu_to_le16(count);
3357
3358 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003359 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003361/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3362 } else if ((smb_buffer_response->WordCount == 3) ||
3363 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003365 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 if (action & GUEST_LOGIN)
Steve French61e74802008-12-03 00:57:54 +00003367 cFYI(1, ("Guest login")); /* BB Should we set anything
Steve French50c2f752007-07-13 00:33:32 +00003368 in SesInfo struct ? */
3369/* if (SecurityBlob2->MessageType != NtLm??) {
3370 cFYI("Unexpected message type on auth response is %d"));
3371 } */
3372
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 if (ses) {
3374 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003375 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003377 /* UID left in wire format */
3378 ses->Suid = smb_buffer_response->Uid;
3379 bcc_ptr = pByteArea(smb_buffer_response);
3380 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 if ((pSMBr->resp.hdr.WordCount == 3)
3382 || ((pSMBr->resp.hdr.WordCount == 4)
3383 && (blob_len <
3384 pSMBr->resp.ByteCount))) {
3385 if (pSMBr->resp.hdr.WordCount == 4) {
3386 bcc_ptr +=
3387 blob_len;
3388 cFYI(1,
3389 ("Security Blob Length %d ",
3390 blob_len));
3391 }
3392
3393 cFYI(1,
3394 ("NTLMSSP response to Authenticate "));
3395
3396 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3397 if ((long) (bcc_ptr) % 2) {
3398 remaining_words =
3399 (BCC(smb_buffer_response)
3400 - 1) / 2;
3401 bcc_ptr++; /* Unicode strings must be word aligned */
3402 } else {
3403 remaining_words = BCC(smb_buffer_response) / 2;
3404 }
Steve French77159b42007-08-31 01:10:17 +00003405 len = UniStrnlen((wchar_t *) bcc_ptr,
3406 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407/* We look for obvious messed up bcc or strings in response so we do not go off
3408 the end since (at least) WIN2K and Windows XP have a major bug in not null
3409 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003410 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003411 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003413 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003415 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 bcc_ptr, len,
3417 nls_codepage);
3418 bcc_ptr += 2 * (len + 1);
3419 remaining_words -= len + 1;
3420 ses->serverOS[2 * len] = 0;
3421 ses->serverOS[1 + (2 * len)] = 0;
3422 if (remaining_words > 0) {
3423 len = UniStrnlen((wchar_t *)
3424 bcc_ptr,
3425 remaining_words
3426 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003427 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003429 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 GFP_KERNEL);
3431 cifs_strfromUCS_le(ses->
3432 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003433 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 bcc_ptr,
3435 len,
3436 nls_codepage);
3437 bcc_ptr += 2 * (len + 1);
3438 ses->serverNOS[2 * len] = 0;
3439 ses->serverNOS[1+(2*len)] = 0;
3440 remaining_words -= len + 1;
3441 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003442 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003444 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003445 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003447 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 (len +
3449 1),
3450 GFP_KERNEL);
3451 cifs_strfromUCS_le
3452 (ses->
3453 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003454 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 bcc_ptr, len,
3456 nls_codepage);
3457 bcc_ptr +=
3458 2 * (len + 1);
3459 ses->
3460 serverDomain[2
3461 * len]
3462 = 0;
3463 ses->
3464 serverDomain[1
3465 +
3466 (2
3467 *
3468 len)]
3469 = 0;
3470 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003471 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003472 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003473 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003474 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003477 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003478 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003479 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003480 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003481 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 }
3483 } else { /* ASCII */
3484 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003485 if (((long) bcc_ptr + len) -
3486 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003487 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003488 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003489 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003490 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 strncpy(ses->serverOS,bcc_ptr, len);
3492
3493 bcc_ptr += len;
3494 bcc_ptr[0] = 0; /* null terminate the string */
3495 bcc_ptr++;
3496
3497 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003498 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003499 ses->serverNOS = kzalloc(len+1,
3500 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003501 strncpy(ses->serverNOS,
3502 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 bcc_ptr += len;
3504 bcc_ptr[0] = 0;
3505 bcc_ptr++;
3506
3507 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003508 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003509 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003510 ses->serverDomain =
3511 kzalloc(len+1,
3512 GFP_KERNEL);
3513 strncpy(ses->serverDomain,
3514 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 bcc_ptr += len;
3516 bcc_ptr[0] = 0;
3517 bcc_ptr++;
3518 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003519 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003520 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 len));
3522 }
3523 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003524 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003525 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 }
3527 } else {
3528 cERROR(1, ("No session structure passed in."));
3529 }
3530 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003531 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 smb_buffer_response->WordCount));
3533 rc = -EIO;
3534 }
3535
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003536 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537
3538 return rc;
3539}
3540
3541int
3542CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3543 const char *tree, struct cifsTconInfo *tcon,
3544 const struct nls_table *nls_codepage)
3545{
3546 struct smb_hdr *smb_buffer;
3547 struct smb_hdr *smb_buffer_response;
3548 TCONX_REQ *pSMB;
3549 TCONX_RSP *pSMBr;
3550 unsigned char *bcc_ptr;
3551 int rc = 0;
3552 int length;
3553 __u16 count;
3554
3555 if (ses == NULL)
3556 return -EIO;
3557
3558 smb_buffer = cifs_buf_get();
3559 if (smb_buffer == NULL) {
3560 return -ENOMEM;
3561 }
3562 smb_buffer_response = smb_buffer;
3563
3564 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3565 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003566
3567 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 smb_buffer->Uid = ses->Suid;
3569 pSMB = (TCONX_REQ *) smb_buffer;
3570 pSMBr = (TCONX_RSP *) smb_buffer_response;
3571
3572 pSMB->AndXCommand = 0xFF;
3573 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003575 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003576 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003577 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003578 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003579 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003580 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003581 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003582 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3583 specified as required (when that support is added to
3584 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003585 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003586 by Samba (not sure whether other servers allow
3587 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003588#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003589 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Jeff Layton00e485b2008-12-05 20:41:21 -05003590 (ses->server->secType == LANMAN))
3591 calc_lanman_hash(tcon->password, ses->server->cryptKey,
Jeff Layton4e53a3f2008-12-05 20:41:21 -05003592 ses->server->secMode &
3593 SECMODE_PW_ENCRYPT ? true : false,
3594 bcc_ptr);
Steve French7c7b25b2006-06-01 19:20:10 +00003595 else
3596#endif /* CIFS_WEAK_PW_HASH */
Jeff Layton00e485b2008-12-05 20:41:21 -05003597 SMBNTencrypt(tcon->password, ses->server->cryptKey,
Steve Frencheeac8042006-01-13 21:34:58 -08003598 bcc_ptr);
3599
Steve French7c7b25b2006-06-01 19:20:10 +00003600 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003601 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003602 /* must align unicode strings */
3603 *bcc_ptr = 0; /* null byte password */
3604 bcc_ptr++;
3605 }
Steve Frencheeac8042006-01-13 21:34:58 -08003606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607
Steve French50c2f752007-07-13 00:33:32 +00003608 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003609 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3611
3612 if (ses->capabilities & CAP_STATUS32) {
3613 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3614 }
3615 if (ses->capabilities & CAP_DFS) {
3616 smb_buffer->Flags2 |= SMBFLG2_DFS;
3617 }
3618 if (ses->capabilities & CAP_UNICODE) {
3619 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3620 length =
Steve French50c2f752007-07-13 00:33:32 +00003621 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3622 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003623 (/* server len*/ + 256 /* share len */), nls_codepage);
3624 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 bcc_ptr += 2; /* skip trailing null */
3626 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 strcpy(bcc_ptr, tree);
3628 bcc_ptr += strlen(tree) + 1;
3629 }
3630 strcpy(bcc_ptr, "?????");
3631 bcc_ptr += strlen("?????");
3632 bcc_ptr += 1;
3633 count = bcc_ptr - &pSMB->Password[0];
3634 pSMB->hdr.smb_buf_length += count;
3635 pSMB->ByteCount = cpu_to_le16(count);
3636
Steve French133672e2007-11-13 22:41:37 +00003637 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3638 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639
3640 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3641 /* above now done in SendReceive */
3642 if ((rc == 0) && (tcon != NULL)) {
3643 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003644 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 tcon->tid = smb_buffer_response->Tid;
3646 bcc_ptr = pByteArea(smb_buffer_response);
3647 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003648 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003649 if (length == 3) {
3650 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3651 (bcc_ptr[2] == 'C')) {
3652 cFYI(1, ("IPC connection"));
3653 tcon->ipc = 1;
3654 }
3655 } else if (length == 2) {
3656 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3657 /* the most common case */
3658 cFYI(1, ("disk share connection"));
3659 }
3660 }
Steve French50c2f752007-07-13 00:33:32 +00003661 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3663 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3664 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3665 if ((bcc_ptr + (2 * length)) -
3666 pByteArea(smb_buffer_response) <=
3667 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003668 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003670 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003671 if (tcon->nativeFileSystem)
3672 cifs_strfromUCS_le(
3673 tcon->nativeFileSystem,
3674 (__le16 *) bcc_ptr,
3675 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 bcc_ptr += 2 * length;
3677 bcc_ptr[0] = 0; /* null terminate the string */
3678 bcc_ptr[1] = 0;
3679 bcc_ptr += 2;
3680 }
Steve French50c2f752007-07-13 00:33:32 +00003681 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 } else {
3683 length = strnlen(bcc_ptr, 1024);
3684 if ((bcc_ptr + length) -
3685 pByteArea(smb_buffer_response) <=
3686 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003687 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003689 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003690 if (tcon->nativeFileSystem)
3691 strncpy(tcon->nativeFileSystem, bcc_ptr,
3692 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 }
Steve French50c2f752007-07-13 00:33:32 +00003694 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003696 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003697 (smb_buffer_response->WordCount == 7))
3698 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003699 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3700 else
3701 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3703 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003704 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 ses->ipc_tid = smb_buffer_response->Tid;
3706 }
3707
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003708 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 return rc;
3710}
3711
3712int
3713cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3714{
3715 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003716 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717
Jeff Laytonf1987b42008-11-15 11:12:47 -05003718 if (cifs_sb->tcon)
3719 cifs_put_tcon(cifs_sb->tcon);
Steve French50c2f752007-07-13 00:33:32 +00003720
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003722 tmp = cifs_sb->prepath;
3723 cifs_sb->prepathlen = 0;
3724 cifs_sb->prepath = NULL;
3725 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726
Steve French88e7d702008-01-03 17:37:09 +00003727 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003728}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729
3730int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003731 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732{
3733 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003734 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003735 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003736 int first_time = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003737 struct TCP_Server_Info *server = pSesInfo->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738
3739 /* what if server changes its buffer size after dropping the session? */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003740 if (server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 rc = CIFSSMBNegotiate(xid, pSesInfo);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003742 if (rc == -EAGAIN) {
3743 /* retry only once on 1st time connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003745 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 rc = -EHOSTDOWN;
3747 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003748 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 spin_lock(&GlobalMid_Lock);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003750 if (server->tcpStatus != CifsExiting)
3751 server->tcpStatus = CifsGood;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 else
3753 rc = -EHOSTDOWN;
3754 spin_unlock(&GlobalMid_Lock);
3755
3756 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003757 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 }
Steve French26b994f2008-08-06 05:11:33 +00003759
3760 if (rc)
3761 goto ss_err_exit;
3762
3763 pSesInfo->flags = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003764 pSesInfo->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003765 if (linuxExtEnabled == 0)
3766 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003767 /* pSesInfo->sequence_number = 0;*/
Steve French26b994f2008-08-06 05:11:33 +00003768 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003769 server->secMode, server->capabilities, server->timeAdj));
3770
Steve French26b994f2008-08-06 05:11:33 +00003771 if (experimEnabled < 2)
3772 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
3773 else if (extended_security
3774 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003775 && (server->secType == NTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003776 rc = -EOPNOTSUPP;
3777 } else if (extended_security
3778 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003779 && (server->secType == RawNTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003780 cFYI(1, ("NTLMSSP sesssetup"));
3781 rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
3782 nls_info);
3783 if (!rc) {
3784 if (ntlmv2_flag) {
3785 char *v2_response;
3786 cFYI(1, ("more secure NTLM ver2 hash"));
3787 if (CalcNTLMv2_partial_mac_key(pSesInfo,
3788 nls_info)) {
3789 rc = -ENOMEM;
3790 goto ss_err_exit;
3791 } else
3792 v2_response = kmalloc(16 + 64 /* blob*/,
3793 GFP_KERNEL);
3794 if (v2_response) {
3795 CalcNTLMv2_response(pSesInfo,
3796 v2_response);
3797 /* if (first_time)
3798 cifs_calculate_ntlmv2_mac_key */
3799 kfree(v2_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 /* BB Put dummy sig in SessSetup PDU? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 } else {
Steve French26b994f2008-08-06 05:11:33 +00003802 rc = -ENOMEM;
3803 goto ss_err_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804 }
Steve French26b994f2008-08-06 05:11:33 +00003805
3806 } else {
3807 SMBNTencrypt(pSesInfo->password,
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003808 server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003809 ntlm_session_key);
3810
3811 if (first_time)
3812 cifs_calculate_mac_key(
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003813 &server->mac_signing_key,
Steve French26b994f2008-08-06 05:11:33 +00003814 ntlm_session_key,
3815 pSesInfo->password);
3816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 /* for better security the weaker lanman hash not sent
3818 in AuthSessSetup so we no longer calculate it */
3819
Steve French26b994f2008-08-06 05:11:33 +00003820 rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
3821 ntlm_session_key,
3822 ntlmv2_flag,
3823 nls_info);
3824 }
3825 } else { /* old style NTLM 0.12 session setup */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003826 SMBNTencrypt(pSesInfo->password, server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003827 ntlm_session_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828
Steve French26b994f2008-08-06 05:11:33 +00003829 if (first_time)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003830 cifs_calculate_mac_key(&server->mac_signing_key,
3831 ntlm_session_key,
3832 pSesInfo->password);
Steve Frenchad009ac2005-04-28 22:41:05 -07003833
Steve French26b994f2008-08-06 05:11:33 +00003834 rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 }
Steve French26b994f2008-08-06 05:11:33 +00003836 if (rc) {
3837 cERROR(1, ("Send error in SessSetup = %d", rc));
3838 } else {
3839 cFYI(1, ("CIFS Session Established successfully"));
Jeff Layton469ee612008-10-16 18:46:39 +00003840 spin_lock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003841 pSesInfo->status = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003842 pSesInfo->need_reconnect = false;
Jeff Layton469ee612008-10-16 18:46:39 +00003843 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003844 }
3845
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846ss_err_exit:
3847 return rc;
3848}
3849