Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * fs/cifs/connect.c | |
3 | * | |
1080ef75 | 4 | * Copyright (C) International Business Machines Corp., 2002,2011 |
1da177e4 LT |
5 | * 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 | |
fb8c4b14 | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
1da177e4 LT |
20 | */ |
21 | #include <linux/fs.h> | |
22 | #include <linux/net.h> | |
23 | #include <linux/string.h> | |
dc920277 | 24 | #include <linux/sched/mm.h> |
3f07c014 | 25 | #include <linux/sched/signal.h> |
1da177e4 LT |
26 | #include <linux/list.h> |
27 | #include <linux/wait.h> | |
5a0e3ad6 | 28 | #include <linux/slab.h> |
1da177e4 LT |
29 | #include <linux/pagemap.h> |
30 | #include <linux/ctype.h> | |
31 | #include <linux/utsname.h> | |
32 | #include <linux/mempool.h> | |
b8643e1b | 33 | #include <linux/delay.h> |
f191401f | 34 | #include <linux/completion.h> |
aaf737ad | 35 | #include <linux/kthread.h> |
0ae0efad | 36 | #include <linux/pagevec.h> |
7dfb7103 | 37 | #include <linux/freezer.h> |
5c2503a8 | 38 | #include <linux/namei.h> |
c6e970a0 | 39 | #include <linux/uuid.h> |
7c0f6ba6 | 40 | #include <linux/uaccess.h> |
1da177e4 | 41 | #include <asm/processor.h> |
50b64e3b | 42 | #include <linux/inet.h> |
143cb494 | 43 | #include <linux/module.h> |
8a8798a5 | 44 | #include <keys/user-type.h> |
0e2bedaa | 45 | #include <net/ipv6.h> |
8830d7e0 | 46 | #include <linux/parser.h> |
2f8b5444 | 47 | #include <linux/bvec.h> |
1da177e4 LT |
48 | #include "cifspdu.h" |
49 | #include "cifsglob.h" | |
50 | #include "cifsproto.h" | |
51 | #include "cifs_unicode.h" | |
52 | #include "cifs_debug.h" | |
53 | #include "cifs_fs_sb.h" | |
54 | #include "ntlmssp.h" | |
55 | #include "nterr.h" | |
56 | #include "rfc1002pdu.h" | |
488f1d2d | 57 | #include "fscache.h" |
53e0e11e | 58 | #include "smb2proto.h" |
2f894646 | 59 | #include "smbdirect.h" |
1c780228 PA |
60 | #include "dns_resolve.h" |
61 | #ifdef CONFIG_CIFS_DFS_UPCALL | |
62 | #include "dfs_cache.h" | |
63 | #endif | |
1da177e4 | 64 | |
1da177e4 | 65 | extern mempool_t *cifs_req_poolp; |
f92a720e | 66 | extern bool disable_legacy_dialects; |
1da177e4 | 67 | |
2de970ff | 68 | /* FIXME: should these be tunable? */ |
9d002df4 | 69 | #define TLINK_ERROR_EXPIRE (1 * HZ) |
2de970ff | 70 | #define TLINK_IDLE_EXPIRE (600 * HZ) |
9d002df4 | 71 | |
8830d7e0 | 72 | enum { |
8830d7e0 SP |
73 | /* Mount options that take no arguments */ |
74 | Opt_user_xattr, Opt_nouser_xattr, | |
75 | Opt_forceuid, Opt_noforceuid, | |
72bd481f | 76 | Opt_forcegid, Opt_noforcegid, |
3e7a02d4 | 77 | Opt_noblocksend, Opt_noautotune, Opt_nolease, |
82e9367c | 78 | Opt_hard, Opt_soft, Opt_perm, Opt_noperm, Opt_nodelete, |
2baa2682 | 79 | Opt_mapposix, Opt_nomapposix, |
8830d7e0 SP |
80 | Opt_mapchars, Opt_nomapchars, Opt_sfu, |
81 | Opt_nosfu, Opt_nodfs, Opt_posixpaths, | |
b326614e | 82 | Opt_noposixpaths, Opt_nounix, Opt_unix, |
8830d7e0 SP |
83 | Opt_nocase, |
84 | Opt_brl, Opt_nobrl, | |
3d4ef9a1 | 85 | Opt_handlecache, Opt_nohandlecache, |
95932655 | 86 | Opt_forcemandatorylock, Opt_setuidfromacl, Opt_setuids, |
8830d7e0 SP |
87 | Opt_nosetuids, Opt_dynperm, Opt_nodynperm, |
88 | Opt_nohard, Opt_nosoft, | |
89 | Opt_nointr, Opt_intr, | |
90 | Opt_nostrictsync, Opt_strictsync, | |
91 | Opt_serverino, Opt_noserverino, | |
92 | Opt_rwpidforward, Opt_cifsacl, Opt_nocifsacl, | |
93 | Opt_acl, Opt_noacl, Opt_locallease, | |
4f5c10f1 | 94 | Opt_sign, Opt_ignore_signature, Opt_seal, Opt_noac, |
8830d7e0 | 95 | Opt_fsc, Opt_mfsymlinks, |
a0b3df5c | 96 | Opt_multiuser, Opt_sloppy, Opt_nosharesock, |
b2a30774 | 97 | Opt_persistent, Opt_nopersistent, |
592fafe6 | 98 | Opt_resilient, Opt_noresilient, |
8eecd1c2 | 99 | Opt_domainauto, Opt_rdma, Opt_modesid, Opt_rootfs, |
bcc88801 | 100 | Opt_multichannel, Opt_nomultichannel, |
9fe5ff1c | 101 | Opt_compress, |
8830d7e0 SP |
102 | |
103 | /* Mount options which take numeric value */ | |
104 | Opt_backupuid, Opt_backupgid, Opt_uid, | |
105 | Opt_cruid, Opt_gid, Opt_file_mode, | |
106 | Opt_dirmode, Opt_port, | |
563317ec | 107 | Opt_min_enc_offload, |
e8506d25 | 108 | Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo, |
ca567eb2 | 109 | Opt_echo_interval, Opt_max_credits, Opt_handletimeout, |
bcc88801 | 110 | Opt_snapshot, Opt_max_channels, |
8830d7e0 SP |
111 | |
112 | /* Mount options which take string value */ | |
113 | Opt_user, Opt_pass, Opt_ip, | |
73a999fa | 114 | Opt_domain, Opt_srcaddr, Opt_iocharset, |
8830d7e0 | 115 | Opt_netbiosname, Opt_servern, |
23db65f5 | 116 | Opt_ver, Opt_vers, Opt_sec, Opt_cache, |
8830d7e0 SP |
117 | |
118 | /* Mount options to be ignored */ | |
119 | Opt_ignore, | |
120 | ||
121 | /* Options which could be blank */ | |
122 | Opt_blank_pass, | |
4fe9e963 SP |
123 | Opt_blank_user, |
124 | Opt_blank_ip, | |
8830d7e0 SP |
125 | |
126 | Opt_err | |
127 | }; | |
128 | ||
129 | static const match_table_t cifs_mount_option_tokens = { | |
130 | ||
131 | { Opt_user_xattr, "user_xattr" }, | |
132 | { Opt_nouser_xattr, "nouser_xattr" }, | |
133 | { Opt_forceuid, "forceuid" }, | |
134 | { Opt_noforceuid, "noforceuid" }, | |
72bd481f JL |
135 | { Opt_forcegid, "forcegid" }, |
136 | { Opt_noforcegid, "noforcegid" }, | |
8830d7e0 SP |
137 | { Opt_noblocksend, "noblocksend" }, |
138 | { Opt_noautotune, "noautotune" }, | |
3e7a02d4 | 139 | { Opt_nolease, "nolease" }, |
8830d7e0 SP |
140 | { Opt_hard, "hard" }, |
141 | { Opt_soft, "soft" }, | |
142 | { Opt_perm, "perm" }, | |
143 | { Opt_noperm, "noperm" }, | |
82e9367c | 144 | { Opt_nodelete, "nodelete" }, |
2baa2682 | 145 | { Opt_mapchars, "mapchars" }, /* SFU style */ |
8830d7e0 | 146 | { Opt_nomapchars, "nomapchars" }, |
2baa2682 SF |
147 | { Opt_mapposix, "mapposix" }, /* SFM style */ |
148 | { Opt_nomapposix, "nomapposix" }, | |
8830d7e0 SP |
149 | { Opt_sfu, "sfu" }, |
150 | { Opt_nosfu, "nosfu" }, | |
151 | { Opt_nodfs, "nodfs" }, | |
152 | { Opt_posixpaths, "posixpaths" }, | |
153 | { Opt_noposixpaths, "noposixpaths" }, | |
154 | { Opt_nounix, "nounix" }, | |
155 | { Opt_nounix, "nolinux" }, | |
b326614e SF |
156 | { Opt_nounix, "noposix" }, |
157 | { Opt_unix, "unix" }, | |
158 | { Opt_unix, "linux" }, | |
159 | { Opt_unix, "posix" }, | |
8830d7e0 SP |
160 | { Opt_nocase, "nocase" }, |
161 | { Opt_nocase, "ignorecase" }, | |
162 | { Opt_brl, "brl" }, | |
163 | { Opt_nobrl, "nobrl" }, | |
3d4ef9a1 SF |
164 | { Opt_handlecache, "handlecache" }, |
165 | { Opt_nohandlecache, "nohandlecache" }, | |
8830d7e0 SP |
166 | { Opt_nobrl, "nolock" }, |
167 | { Opt_forcemandatorylock, "forcemandatorylock" }, | |
5cfdddcf | 168 | { Opt_forcemandatorylock, "forcemand" }, |
8830d7e0 SP |
169 | { Opt_setuids, "setuids" }, |
170 | { Opt_nosetuids, "nosetuids" }, | |
95932655 | 171 | { Opt_setuidfromacl, "idsfromsid" }, |
8830d7e0 SP |
172 | { Opt_dynperm, "dynperm" }, |
173 | { Opt_nodynperm, "nodynperm" }, | |
174 | { Opt_nohard, "nohard" }, | |
175 | { Opt_nosoft, "nosoft" }, | |
176 | { Opt_nointr, "nointr" }, | |
177 | { Opt_intr, "intr" }, | |
178 | { Opt_nostrictsync, "nostrictsync" }, | |
179 | { Opt_strictsync, "strictsync" }, | |
180 | { Opt_serverino, "serverino" }, | |
181 | { Opt_noserverino, "noserverino" }, | |
182 | { Opt_rwpidforward, "rwpidforward" }, | |
412094a8 | 183 | { Opt_modesid, "modefromsid" }, |
8830d7e0 SP |
184 | { Opt_cifsacl, "cifsacl" }, |
185 | { Opt_nocifsacl, "nocifsacl" }, | |
186 | { Opt_acl, "acl" }, | |
187 | { Opt_noacl, "noacl" }, | |
188 | { Opt_locallease, "locallease" }, | |
189 | { Opt_sign, "sign" }, | |
4f5c10f1 | 190 | { Opt_ignore_signature, "signloosely" }, |
8830d7e0 | 191 | { Opt_seal, "seal" }, |
8830d7e0 SP |
192 | { Opt_noac, "noac" }, |
193 | { Opt_fsc, "fsc" }, | |
194 | { Opt_mfsymlinks, "mfsymlinks" }, | |
195 | { Opt_multiuser, "multiuser" }, | |
d8162558 | 196 | { Opt_sloppy, "sloppy" }, |
a0b3df5c | 197 | { Opt_nosharesock, "nosharesock" }, |
b2a30774 SF |
198 | { Opt_persistent, "persistenthandles"}, |
199 | { Opt_nopersistent, "nopersistenthandles"}, | |
592fafe6 SF |
200 | { Opt_resilient, "resilienthandles"}, |
201 | { Opt_noresilient, "noresilienthandles"}, | |
39566443 | 202 | { Opt_domainauto, "domainauto"}, |
8339dd32 | 203 | { Opt_rdma, "rdma"}, |
bcc88801 AA |
204 | { Opt_multichannel, "multichannel" }, |
205 | { Opt_nomultichannel, "nomultichannel" }, | |
8830d7e0 SP |
206 | |
207 | { Opt_backupuid, "backupuid=%s" }, | |
208 | { Opt_backupgid, "backupgid=%s" }, | |
209 | { Opt_uid, "uid=%s" }, | |
210 | { Opt_cruid, "cruid=%s" }, | |
211 | { Opt_gid, "gid=%s" }, | |
212 | { Opt_file_mode, "file_mode=%s" }, | |
213 | { Opt_dirmode, "dirmode=%s" }, | |
214 | { Opt_dirmode, "dir_mode=%s" }, | |
215 | { Opt_port, "port=%s" }, | |
563317ec | 216 | { Opt_min_enc_offload, "esize=%s" }, |
e8506d25 | 217 | { Opt_blocksize, "bsize=%s" }, |
8830d7e0 SP |
218 | { Opt_rsize, "rsize=%s" }, |
219 | { Opt_wsize, "wsize=%s" }, | |
220 | { Opt_actimeo, "actimeo=%s" }, | |
ca567eb2 | 221 | { Opt_handletimeout, "handletimeout=%s" }, |
adfeb3e0 | 222 | { Opt_echo_interval, "echo_interval=%s" }, |
141891f4 | 223 | { Opt_max_credits, "max_credits=%s" }, |
8b217fe7 | 224 | { Opt_snapshot, "snapshot=%s" }, |
bcc88801 | 225 | { Opt_max_channels, "max_channels=%s" }, |
9fe5ff1c | 226 | { Opt_compress, "compress=%s" }, |
8830d7e0 | 227 | |
4fe9e963 SP |
228 | { Opt_blank_user, "user=" }, |
229 | { Opt_blank_user, "username=" }, | |
8830d7e0 SP |
230 | { Opt_user, "user=%s" }, |
231 | { Opt_user, "username=%s" }, | |
232 | { Opt_blank_pass, "pass=" }, | |
3c15b4cf | 233 | { Opt_blank_pass, "password=" }, |
8830d7e0 SP |
234 | { Opt_pass, "pass=%s" }, |
235 | { Opt_pass, "password=%s" }, | |
4fe9e963 SP |
236 | { Opt_blank_ip, "ip=" }, |
237 | { Opt_blank_ip, "addr=" }, | |
8830d7e0 SP |
238 | { Opt_ip, "ip=%s" }, |
239 | { Opt_ip, "addr=%s" }, | |
73a999fa JL |
240 | { Opt_ignore, "unc=%s" }, |
241 | { Opt_ignore, "target=%s" }, | |
242 | { Opt_ignore, "path=%s" }, | |
8830d7e0 SP |
243 | { Opt_domain, "dom=%s" }, |
244 | { Opt_domain, "domain=%s" }, | |
245 | { Opt_domain, "workgroup=%s" }, | |
246 | { Opt_srcaddr, "srcaddr=%s" }, | |
73a999fa | 247 | { Opt_ignore, "prefixpath=%s" }, |
8830d7e0 | 248 | { Opt_iocharset, "iocharset=%s" }, |
8830d7e0 SP |
249 | { Opt_netbiosname, "netbiosname=%s" }, |
250 | { Opt_servern, "servern=%s" }, | |
251 | { Opt_ver, "ver=%s" }, | |
23db65f5 | 252 | { Opt_vers, "vers=%s" }, |
8830d7e0 | 253 | { Opt_sec, "sec=%s" }, |
15b6a473 | 254 | { Opt_cache, "cache=%s" }, |
8830d7e0 SP |
255 | |
256 | { Opt_ignore, "cred" }, | |
257 | { Opt_ignore, "credentials" }, | |
a557b976 JL |
258 | { Opt_ignore, "cred=%s" }, |
259 | { Opt_ignore, "credentials=%s" }, | |
8830d7e0 SP |
260 | { Opt_ignore, "guest" }, |
261 | { Opt_ignore, "rw" }, | |
262 | { Opt_ignore, "ro" }, | |
263 | { Opt_ignore, "suid" }, | |
264 | { Opt_ignore, "nosuid" }, | |
265 | { Opt_ignore, "exec" }, | |
266 | { Opt_ignore, "noexec" }, | |
267 | { Opt_ignore, "nodev" }, | |
268 | { Opt_ignore, "noauto" }, | |
269 | { Opt_ignore, "dev" }, | |
270 | { Opt_ignore, "mand" }, | |
271 | { Opt_ignore, "nomand" }, | |
9b9c5bea | 272 | { Opt_ignore, "relatime" }, |
8830d7e0 | 273 | { Opt_ignore, "_netdev" }, |
8eecd1c2 | 274 | { Opt_rootfs, "rootfs" }, |
8830d7e0 SP |
275 | |
276 | { Opt_err, NULL } | |
277 | }; | |
278 | ||
279 | enum { | |
280 | Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p, | |
281 | Opt_sec_ntlmsspi, Opt_sec_ntlmssp, | |
7659624f JL |
282 | Opt_ntlm, Opt_sec_ntlmi, Opt_sec_ntlmv2, |
283 | Opt_sec_ntlmv2i, Opt_sec_lanman, | |
8830d7e0 SP |
284 | Opt_sec_none, |
285 | ||
286 | Opt_sec_err | |
287 | }; | |
288 | ||
289 | static const match_table_t cifs_secflavor_tokens = { | |
290 | { Opt_sec_krb5, "krb5" }, | |
291 | { Opt_sec_krb5i, "krb5i" }, | |
292 | { Opt_sec_krb5p, "krb5p" }, | |
293 | { Opt_sec_ntlmsspi, "ntlmsspi" }, | |
294 | { Opt_sec_ntlmssp, "ntlmssp" }, | |
295 | { Opt_ntlm, "ntlm" }, | |
296 | { Opt_sec_ntlmi, "ntlmi" }, | |
7659624f JL |
297 | { Opt_sec_ntlmv2, "nontlm" }, |
298 | { Opt_sec_ntlmv2, "ntlmv2" }, | |
8830d7e0 | 299 | { Opt_sec_ntlmv2i, "ntlmv2i" }, |
8830d7e0 SP |
300 | { Opt_sec_lanman, "lanman" }, |
301 | { Opt_sec_none, "none" }, | |
302 | ||
303 | { Opt_sec_err, NULL } | |
304 | }; | |
305 | ||
15b6a473 JL |
306 | /* cache flavors */ |
307 | enum { | |
308 | Opt_cache_loose, | |
309 | Opt_cache_strict, | |
310 | Opt_cache_none, | |
83bbfa70 | 311 | Opt_cache_ro, |
41e033fe | 312 | Opt_cache_rw, |
15b6a473 JL |
313 | Opt_cache_err |
314 | }; | |
315 | ||
316 | static const match_table_t cifs_cacheflavor_tokens = { | |
317 | { Opt_cache_loose, "loose" }, | |
318 | { Opt_cache_strict, "strict" }, | |
319 | { Opt_cache_none, "none" }, | |
83bbfa70 | 320 | { Opt_cache_ro, "ro" }, |
41e033fe | 321 | { Opt_cache_rw, "singleclient" }, |
15b6a473 JL |
322 | { Opt_cache_err, NULL } |
323 | }; | |
324 | ||
23db65f5 JL |
325 | static const match_table_t cifs_smb_version_tokens = { |
326 | { Smb_1, SMB1_VERSION_STRING }, | |
dd446b16 | 327 | { Smb_20, SMB20_VERSION_STRING}, |
1080ef75 | 328 | { Smb_21, SMB21_VERSION_STRING }, |
e4aa25e7 | 329 | { Smb_30, SMB30_VERSION_STRING }, |
20b6d8b4 | 330 | { Smb_302, SMB302_VERSION_STRING }, |
4a3b38ae | 331 | { Smb_302, ALT_SMB302_VERSION_STRING }, |
5f7fbf73 | 332 | { Smb_311, SMB311_VERSION_STRING }, |
aab1893d | 333 | { Smb_311, ALT_SMB311_VERSION_STRING }, |
9764c02f SF |
334 | { Smb_3any, SMB3ANY_VERSION_STRING }, |
335 | { Smb_default, SMBDEFAULT_VERSION_STRING }, | |
5f7fbf73 | 336 | { Smb_version_err, NULL } |
23db65f5 JL |
337 | }; |
338 | ||
a9f1b85e PS |
339 | static int ip_connect(struct TCP_Server_Info *server); |
340 | static int generic_ip_connect(struct TCP_Server_Info *server); | |
b647c35f | 341 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); |
2de970ff | 342 | static void cifs_prune_tlinks(struct work_struct *work); |
93d5cb51 PA |
343 | static char *extract_hostname(const char *unc); |
344 | ||
28eb24ff PA |
345 | /* |
346 | * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may | |
347 | * get their ip addresses changed at some point. | |
348 | * | |
349 | * This should be called with server->srv_mutex held. | |
350 | */ | |
351 | #ifdef CONFIG_CIFS_DFS_UPCALL | |
352 | static int reconn_set_ipaddr(struct TCP_Server_Info *server) | |
353 | { | |
354 | int rc; | |
355 | int len; | |
356 | char *unc, *ipaddr = NULL; | |
357 | ||
358 | if (!server->hostname) | |
359 | return -EINVAL; | |
360 | ||
361 | len = strlen(server->hostname) + 3; | |
362 | ||
363 | unc = kmalloc(len, GFP_KERNEL); | |
364 | if (!unc) { | |
365 | cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__); | |
366 | return -ENOMEM; | |
367 | } | |
74ea5f98 | 368 | scnprintf(unc, len, "\\\\%s", server->hostname); |
28eb24ff PA |
369 | |
370 | rc = dns_resolve_server_name_to_ip(unc, &ipaddr); | |
371 | kfree(unc); | |
372 | ||
373 | if (rc < 0) { | |
374 | cifs_dbg(FYI, "%s: failed to resolve server part of %s to IP: %d\n", | |
375 | __func__, server->hostname, rc); | |
376 | return rc; | |
377 | } | |
378 | ||
fada37f6 | 379 | spin_lock(&cifs_tcp_ses_lock); |
28eb24ff PA |
380 | rc = cifs_convert_address((struct sockaddr *)&server->dstaddr, ipaddr, |
381 | strlen(ipaddr)); | |
fada37f6 | 382 | spin_unlock(&cifs_tcp_ses_lock); |
28eb24ff PA |
383 | kfree(ipaddr); |
384 | ||
385 | return !rc ? -1 : 0; | |
386 | } | |
387 | #else | |
388 | static inline int reconn_set_ipaddr(struct TCP_Server_Info *server) | |
389 | { | |
390 | return 0; | |
391 | } | |
392 | #endif | |
393 | ||
93d5cb51 | 394 | #ifdef CONFIG_CIFS_DFS_UPCALL |
93d5cb51 | 395 | /* These functions must be called with server->srv_mutex held */ |
93d5cb51 PA |
396 | static void reconn_inval_dfs_target(struct TCP_Server_Info *server, |
397 | struct cifs_sb_info *cifs_sb, | |
398 | struct dfs_cache_tgt_list *tgt_list, | |
399 | struct dfs_cache_tgt_iterator **tgt_it) | |
400 | { | |
401 | const char *name; | |
93d5cb51 PA |
402 | |
403 | if (!cifs_sb || !cifs_sb->origin_fullpath || !tgt_list || | |
404 | !server->nr_targets) | |
405 | return; | |
406 | ||
407 | if (!*tgt_it) { | |
408 | *tgt_it = dfs_cache_get_tgt_iterator(tgt_list); | |
409 | } else { | |
410 | *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it); | |
411 | if (!*tgt_it) | |
412 | *tgt_it = dfs_cache_get_tgt_iterator(tgt_list); | |
413 | } | |
414 | ||
415 | cifs_dbg(FYI, "%s: UNC: %s\n", __func__, cifs_sb->origin_fullpath); | |
416 | ||
417 | name = dfs_cache_get_tgt_name(*tgt_it); | |
418 | ||
419 | kfree(server->hostname); | |
420 | ||
421 | server->hostname = extract_hostname(name); | |
8428817d DC |
422 | if (IS_ERR(server->hostname)) { |
423 | cifs_dbg(FYI, | |
424 | "%s: failed to extract hostname from target: %ld\n", | |
425 | __func__, PTR_ERR(server->hostname)); | |
93d5cb51 PA |
426 | } |
427 | } | |
428 | ||
429 | static inline int reconn_setup_dfs_targets(struct cifs_sb_info *cifs_sb, | |
baf3f08e | 430 | struct dfs_cache_tgt_list *tl) |
93d5cb51 PA |
431 | { |
432 | if (!cifs_sb->origin_fullpath) | |
433 | return -EOPNOTSUPP; | |
434 | return dfs_cache_noreq_find(cifs_sb->origin_fullpath + 1, NULL, tl); | |
435 | } | |
436 | #endif | |
1da177e4 | 437 | |
d5c5605c JL |
438 | /* |
439 | * cifs tcp session reconnection | |
440 | * | |
441 | * mark tcp session as reconnecting so temporarily locked | |
442 | * mark all smb sessions as reconnecting for tcp session | |
443 | * reconnect tcp session | |
444 | * wake up waiters on reconnection? - (not needed currently) | |
445 | */ | |
28ea5290 | 446 | int |
1da177e4 LT |
447 | cifs_reconnect(struct TCP_Server_Info *server) |
448 | { | |
449 | int rc = 0; | |
f1987b44 | 450 | struct list_head *tmp, *tmp2; |
96daf2b0 SF |
451 | struct cifs_ses *ses; |
452 | struct cifs_tcon *tcon; | |
fb8c4b14 | 453 | struct mid_q_entry *mid_entry; |
3c1105df | 454 | struct list_head retry_list; |
93d5cb51 | 455 | #ifdef CONFIG_CIFS_DFS_UPCALL |
8354d88e | 456 | struct super_block *sb = NULL; |
23324407 PA |
457 | struct cifs_sb_info *cifs_sb = NULL; |
458 | struct dfs_cache_tgt_list tgt_list = {0}; | |
93d5cb51 PA |
459 | struct dfs_cache_tgt_iterator *tgt_it = NULL; |
460 | #endif | |
50c2f753 | 461 | |
1da177e4 | 462 | spin_lock(&GlobalMid_Lock); |
93d5cb51 PA |
463 | server->nr_targets = 1; |
464 | #ifdef CONFIG_CIFS_DFS_UPCALL | |
61cabc7b | 465 | spin_unlock(&GlobalMid_Lock); |
bacd704a | 466 | sb = cifs_get_tcp_super(server); |
8354d88e PAS |
467 | if (IS_ERR(sb)) { |
468 | rc = PTR_ERR(sb); | |
93d5cb51 PA |
469 | cifs_dbg(FYI, "%s: will not do DFS failover: rc = %d\n", |
470 | __func__, rc); | |
8354d88e | 471 | sb = NULL; |
93d5cb51 | 472 | } else { |
8354d88e PAS |
473 | cifs_sb = CIFS_SB(sb); |
474 | ||
baf3f08e | 475 | rc = reconn_setup_dfs_targets(cifs_sb, &tgt_list); |
55a7f006 | 476 | if (rc && (rc != -EOPNOTSUPP)) { |
afe6f653 | 477 | cifs_server_dbg(VFS, "%s: no target servers for DFS failover\n", |
93d5cb51 PA |
478 | __func__); |
479 | } else { | |
480 | server->nr_targets = dfs_cache_get_nr_tgts(&tgt_list); | |
481 | } | |
482 | } | |
483 | cifs_dbg(FYI, "%s: will retry %d target(s)\n", __func__, | |
484 | server->nr_targets); | |
61cabc7b | 485 | spin_lock(&GlobalMid_Lock); |
93d5cb51 | 486 | #endif |
469ee614 | 487 | if (server->tcpStatus == CifsExiting) { |
fb8c4b14 | 488 | /* the demux thread will exit normally |
1da177e4 LT |
489 | next time through the loop */ |
490 | spin_unlock(&GlobalMid_Lock); | |
8354d88e PAS |
491 | #ifdef CONFIG_CIFS_DFS_UPCALL |
492 | dfs_cache_free_tgts(&tgt_list); | |
bacd704a | 493 | cifs_put_tcp_super(sb); |
8354d88e | 494 | #endif |
e2e87519 | 495 | wake_up(&server->response_q); |
1da177e4 LT |
496 | return rc; |
497 | } else | |
498 | server->tcpStatus = CifsNeedReconnect; | |
499 | spin_unlock(&GlobalMid_Lock); | |
500 | server->maxBuf = 0; | |
aa24d1e9 | 501 | server->max_read = 0; |
1da177e4 | 502 | |
6e4d3bbe | 503 | cifs_dbg(FYI, "Mark tcp session as need reconnect\n"); |
bf1fdeb7 | 504 | trace_smb3_reconnect(server->CurrentMid, server->hostname); |
1da177e4 LT |
505 | |
506 | /* before reconnecting the tcp session, mark the smb session (uid) | |
507 | and the tid bad so they are not used until reconnected */ | |
f96637be JP |
508 | cifs_dbg(FYI, "%s: marking sessions and tcons for reconnect\n", |
509 | __func__); | |
3f9bcca7 | 510 | spin_lock(&cifs_tcp_ses_lock); |
14fbf50d | 511 | list_for_each(tmp, &server->smb_ses_list) { |
96daf2b0 | 512 | ses = list_entry(tmp, struct cifs_ses, smb_ses_list); |
14fbf50d | 513 | ses->need_reconnect = true; |
f1987b44 | 514 | list_for_each(tmp2, &ses->tcon_list) { |
96daf2b0 | 515 | tcon = list_entry(tmp2, struct cifs_tcon, tcon_list); |
3b795210 | 516 | tcon->need_reconnect = true; |
1da177e4 | 517 | } |
b327a717 AA |
518 | if (ses->tcon_ipc) |
519 | ses->tcon_ipc->need_reconnect = true; | |
1da177e4 | 520 | } |
3f9bcca7 | 521 | spin_unlock(&cifs_tcp_ses_lock); |
2b84a36c | 522 | |
1da177e4 | 523 | /* do not want to be sending data on a socket we are freeing */ |
f96637be | 524 | cifs_dbg(FYI, "%s: tearing down socket\n", __func__); |
72ca545b | 525 | mutex_lock(&server->srv_mutex); |
1d2a4f57 LL |
526 | if (server->ssocket) { |
527 | cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n", | |
528 | server->ssocket->state, server->ssocket->flags); | |
529 | kernel_sock_shutdown(server->ssocket, SHUT_WR); | |
530 | cifs_dbg(FYI, "Post shutdown state: 0x%x Flags: 0x%lx\n", | |
531 | server->ssocket->state, server->ssocket->flags); | |
532 | sock_release(server->ssocket); | |
533 | server->ssocket = NULL; | |
534 | } | |
535 | server->sequence_number = 0; | |
536 | server->session_estab = false; | |
537 | kfree(server->session_key.response); | |
538 | server->session_key.response = NULL; | |
539 | server->session_key.len = 0; | |
540 | server->lstrp = jiffies; | |
1da177e4 | 541 | |
2b84a36c | 542 | /* mark submitted MIDs for retry and issue callback */ |
3c1105df | 543 | INIT_LIST_HEAD(&retry_list); |
f96637be | 544 | cifs_dbg(FYI, "%s: moving mids to private list\n", __func__); |
1da177e4 | 545 | spin_lock(&GlobalMid_Lock); |
2b84a36c JL |
546 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { |
547 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | |
abe57073 | 548 | kref_get(&mid_entry->refcount); |
7c9421e1 PS |
549 | if (mid_entry->mid_state == MID_REQUEST_SUBMITTED) |
550 | mid_entry->mid_state = MID_RETRY_NEEDED; | |
3c1105df | 551 | list_move(&mid_entry->qhead, &retry_list); |
abe57073 | 552 | mid_entry->mid_flags |= MID_DELETED; |
3c1105df JL |
553 | } |
554 | spin_unlock(&GlobalMid_Lock); | |
1d2a4f57 | 555 | mutex_unlock(&server->srv_mutex); |
3c1105df | 556 | |
f96637be | 557 | cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__); |
3c1105df JL |
558 | list_for_each_safe(tmp, tmp2, &retry_list) { |
559 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | |
2b84a36c JL |
560 | list_del_init(&mid_entry->qhead); |
561 | mid_entry->callback(mid_entry); | |
abe57073 | 562 | cifs_mid_q_entry_release(mid_entry); |
1da177e4 | 563 | } |
1da177e4 | 564 | |
1d2a4f57 LL |
565 | if (cifs_rdma_enabled(server)) { |
566 | mutex_lock(&server->srv_mutex); | |
214bab44 | 567 | smbd_destroy(server); |
1d2a4f57 LL |
568 | mutex_unlock(&server->srv_mutex); |
569 | } | |
214bab44 | 570 | |
7fdbaa1b | 571 | do { |
6c3d8909 | 572 | try_to_freeze(); |
a9f1b85e | 573 | |
73e216a8 | 574 | mutex_lock(&server->srv_mutex); |
aaa3aef3 | 575 | #ifdef CONFIG_CIFS_DFS_UPCALL |
93d5cb51 PA |
576 | /* |
577 | * Set up next DFS target server (if any) for reconnect. If DFS | |
578 | * feature is disabled, then we will retry last server we | |
579 | * connected to before. | |
580 | */ | |
aaa3aef3 PA |
581 | reconn_inval_dfs_target(server, cifs_sb, &tgt_list, &tgt_it); |
582 | #endif | |
583 | rc = reconn_set_ipaddr(server); | |
584 | if (rc) { | |
585 | cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n", | |
586 | __func__, rc); | |
587 | } | |
588 | ||
781a8050 LL |
589 | if (cifs_rdma_enabled(server)) |
590 | rc = smbd_reconnect(server); | |
591 | else | |
592 | rc = generic_ip_connect(server); | |
fb8c4b14 | 593 | if (rc) { |
f96637be | 594 | cifs_dbg(FYI, "reconnect error %d\n", rc); |
4afe260b | 595 | mutex_unlock(&server->srv_mutex); |
0cb766ae | 596 | msleep(3000); |
1da177e4 LT |
597 | } else { |
598 | atomic_inc(&tcpSesReconnectCount); | |
335b7b62 | 599 | set_credits(server, 1); |
1da177e4 | 600 | spin_lock(&GlobalMid_Lock); |
469ee614 | 601 | if (server->tcpStatus != CifsExiting) |
fd88ce93 | 602 | server->tcpStatus = CifsNeedNegotiate; |
fb8c4b14 | 603 | spin_unlock(&GlobalMid_Lock); |
4afe260b | 604 | mutex_unlock(&server->srv_mutex); |
1da177e4 | 605 | } |
7fdbaa1b | 606 | } while (server->tcpStatus == CifsNeedReconnect); |
2b84a36c | 607 | |
93d5cb51 PA |
608 | #ifdef CONFIG_CIFS_DFS_UPCALL |
609 | if (tgt_it) { | |
610 | rc = dfs_cache_noreq_update_tgthint(cifs_sb->origin_fullpath + 1, | |
611 | tgt_it); | |
612 | if (rc) { | |
afe6f653 | 613 | cifs_server_dbg(VFS, "%s: failed to update DFS target hint: rc = %d\n", |
93d5cb51 PA |
614 | __func__, rc); |
615 | } | |
616 | rc = dfs_cache_update_vol(cifs_sb->origin_fullpath, server); | |
617 | if (rc) { | |
afe6f653 | 618 | cifs_server_dbg(VFS, "%s: failed to update vol info in DFS cache: rc = %d\n", |
93d5cb51 PA |
619 | __func__, rc); |
620 | } | |
23324407 | 621 | dfs_cache_free_tgts(&tgt_list); |
8354d88e | 622 | |
93d5cb51 | 623 | } |
8354d88e | 624 | |
bacd704a | 625 | cifs_put_tcp_super(sb); |
93d5cb51 | 626 | #endif |
b8c60012 SP |
627 | if (server->tcpStatus == CifsNeedNegotiate) |
628 | mod_delayed_work(cifsiod_wq, &server->echo, 0); | |
629 | ||
e2e87519 | 630 | wake_up(&server->response_q); |
1da177e4 LT |
631 | return rc; |
632 | } | |
633 | ||
c74093b6 JL |
634 | static void |
635 | cifs_echo_request(struct work_struct *work) | |
636 | { | |
637 | int rc; | |
638 | struct TCP_Server_Info *server = container_of(work, | |
639 | struct TCP_Server_Info, echo.work); | |
b8c60012 SP |
640 | unsigned long echo_interval; |
641 | ||
642 | /* | |
643 | * If we need to renegotiate, set echo interval to zero to | |
644 | * immediately call echo service where we can renegotiate. | |
645 | */ | |
646 | if (server->tcpStatus == CifsNeedNegotiate) | |
647 | echo_interval = 0; | |
648 | else | |
649 | echo_interval = server->echo_interval; | |
c74093b6 | 650 | |
247ec9b4 | 651 | /* |
b8c60012 SP |
652 | * We cannot send an echo if it is disabled. |
653 | * Also, no need to ping if we got a response recently. | |
247ec9b4 | 654 | */ |
4fcd1813 SF |
655 | |
656 | if (server->tcpStatus == CifsNeedReconnect || | |
b8c60012 SP |
657 | server->tcpStatus == CifsExiting || |
658 | server->tcpStatus == CifsNew || | |
f6d76178 | 659 | (server->ops->can_echo && !server->ops->can_echo(server)) || |
adfeb3e0 | 660 | time_before(jiffies, server->lstrp + echo_interval - HZ)) |
c74093b6 JL |
661 | goto requeue_echo; |
662 | ||
f6d76178 | 663 | rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS; |
c74093b6 | 664 | if (rc) |
f96637be JP |
665 | cifs_dbg(FYI, "Unable to send echo request to server: %s\n", |
666 | server->hostname); | |
c74093b6 JL |
667 | |
668 | requeue_echo: | |
b8c60012 | 669 | queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval); |
c74093b6 JL |
670 | } |
671 | ||
3d9c2472 | 672 | static bool |
2a37ef94 | 673 | allocate_buffers(struct TCP_Server_Info *server) |
3d9c2472 | 674 | { |
2a37ef94 JL |
675 | if (!server->bigbuf) { |
676 | server->bigbuf = (char *)cifs_buf_get(); | |
677 | if (!server->bigbuf) { | |
afe6f653 | 678 | cifs_server_dbg(VFS, "No memory for large SMB response\n"); |
3d9c2472 PS |
679 | msleep(3000); |
680 | /* retry will check if exiting */ | |
681 | return false; | |
682 | } | |
2a37ef94 | 683 | } else if (server->large_buf) { |
3d9c2472 | 684 | /* we are reusing a dirty large buf, clear its start */ |
1887f601 | 685 | memset(server->bigbuf, 0, HEADER_SIZE(server)); |
3d9c2472 PS |
686 | } |
687 | ||
2a37ef94 JL |
688 | if (!server->smallbuf) { |
689 | server->smallbuf = (char *)cifs_small_buf_get(); | |
690 | if (!server->smallbuf) { | |
afe6f653 | 691 | cifs_server_dbg(VFS, "No memory for SMB response\n"); |
3d9c2472 PS |
692 | msleep(1000); |
693 | /* retry will check if exiting */ | |
694 | return false; | |
695 | } | |
696 | /* beginning of smb buffer is cleared in our buf_get */ | |
697 | } else { | |
698 | /* if existing small buf clear beginning */ | |
1887f601 | 699 | memset(server->smallbuf, 0, HEADER_SIZE(server)); |
3d9c2472 PS |
700 | } |
701 | ||
3d9c2472 PS |
702 | return true; |
703 | } | |
704 | ||
ba749e6d JL |
705 | static bool |
706 | server_unresponsive(struct TCP_Server_Info *server) | |
707 | { | |
6dae51a5 | 708 | /* |
f2caf901 | 709 | * We need to wait 3 echo intervals to make sure we handle such |
6dae51a5 PS |
710 | * situations right: |
711 | * 1s client sends a normal SMB request | |
becc2ba2 | 712 | * 2s client gets a response |
6dae51a5 PS |
713 | * 30s echo workqueue job pops, and decides we got a response recently |
714 | * and don't need to send another | |
715 | * ... | |
716 | * 65s kernel_recvmsg times out, and we see that we haven't gotten | |
717 | * a response in >60s. | |
718 | */ | |
76e75270 SC |
719 | if ((server->tcpStatus == CifsGood || |
720 | server->tcpStatus == CifsNeedNegotiate) && | |
f2caf901 | 721 | time_after(jiffies, server->lstrp + 3 * server->echo_interval)) { |
afe6f653 RS |
722 | cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n", |
723 | (3 * server->echo_interval) / HZ); | |
ba749e6d | 724 | cifs_reconnect(server); |
ba749e6d JL |
725 | return true; |
726 | } | |
727 | ||
728 | return false; | |
729 | } | |
730 | ||
ef68e831 PS |
731 | static inline bool |
732 | zero_credits(struct TCP_Server_Info *server) | |
733 | { | |
734 | int val; | |
735 | ||
736 | spin_lock(&server->req_lock); | |
737 | val = server->credits + server->echo_credits + server->oplock_credits; | |
738 | if (server->in_flight == 0 && val == 0) { | |
739 | spin_unlock(&server->req_lock); | |
740 | return true; | |
741 | } | |
742 | spin_unlock(&server->req_lock); | |
743 | return false; | |
744 | } | |
745 | ||
71335664 AV |
746 | static int |
747 | cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg) | |
e7015fb1 | 748 | { |
a52c1eb7 JL |
749 | int length = 0; |
750 | int total_read; | |
e7015fb1 | 751 | |
71335664 AV |
752 | smb_msg->msg_control = NULL; |
753 | smb_msg->msg_controllen = 0; | |
e831e6cf | 754 | |
71335664 | 755 | for (total_read = 0; msg_data_left(smb_msg); total_read += length) { |
95edcff4 JL |
756 | try_to_freeze(); |
757 | ||
ef68e831 PS |
758 | /* reconnect if no credits and no requests in flight */ |
759 | if (zero_credits(server)) { | |
760 | cifs_reconnect(server); | |
761 | return -ECONNABORTED; | |
762 | } | |
763 | ||
71335664 AV |
764 | if (server_unresponsive(server)) |
765 | return -ECONNABORTED; | |
2fef137a LL |
766 | if (cifs_rdma_enabled(server) && server->smbd_conn) |
767 | length = smbd_recv(server->smbd_conn, smb_msg); | |
768 | else | |
769 | length = sock_recvmsg(server->ssocket, smb_msg, 0); | |
42c4dfc2 | 770 | |
71335664 AV |
771 | if (server->tcpStatus == CifsExiting) |
772 | return -ESHUTDOWN; | |
e7015fb1 | 773 | |
71335664 | 774 | if (server->tcpStatus == CifsNeedReconnect) { |
e7015fb1 | 775 | cifs_reconnect(server); |
71335664 AV |
776 | return -ECONNABORTED; |
777 | } | |
778 | ||
779 | if (length == -ERESTARTSYS || | |
780 | length == -EAGAIN || | |
781 | length == -EINTR) { | |
e7015fb1 PS |
782 | /* |
783 | * Minimum sleep to prevent looping, allowing socket | |
784 | * to clear and app threads to set tcpStatus | |
785 | * CifsNeedReconnect if server hung. | |
786 | */ | |
787 | usleep_range(1000, 2000); | |
788 | length = 0; | |
a52c1eb7 | 789 | continue; |
71335664 AV |
790 | } |
791 | ||
792 | if (length <= 0) { | |
09aab880 | 793 | cifs_dbg(FYI, "Received no data or error: %d\n", length); |
e7015fb1 | 794 | cifs_reconnect(server); |
71335664 | 795 | return -ECONNABORTED; |
e7015fb1 PS |
796 | } |
797 | } | |
a52c1eb7 | 798 | return total_read; |
e7015fb1 | 799 | } |
e7015fb1 | 800 | |
e28bc5b1 JL |
801 | int |
802 | cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, | |
803 | unsigned int to_read) | |
42c4dfc2 | 804 | { |
71335664 AV |
805 | struct msghdr smb_msg; |
806 | struct kvec iov = {.iov_base = buf, .iov_len = to_read}; | |
aa563d7b | 807 | iov_iter_kvec(&smb_msg.msg_iter, READ, &iov, 1, to_read); |
42c4dfc2 | 808 | |
71335664 AV |
809 | return cifs_readv_from_socket(server, &smb_msg); |
810 | } | |
42c4dfc2 | 811 | |
71335664 AV |
812 | int |
813 | cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page, | |
1dbe3466 | 814 | unsigned int page_offset, unsigned int to_read) |
71335664 AV |
815 | { |
816 | struct msghdr smb_msg; | |
1dbe3466 LL |
817 | struct bio_vec bv = { |
818 | .bv_page = page, .bv_len = to_read, .bv_offset = page_offset}; | |
aa563d7b | 819 | iov_iter_bvec(&smb_msg.msg_iter, READ, &bv, 1, to_read); |
71335664 | 820 | return cifs_readv_from_socket(server, &smb_msg); |
e7015fb1 PS |
821 | } |
822 | ||
98bac62c | 823 | static bool |
fe11e4cc | 824 | is_smb_response(struct TCP_Server_Info *server, unsigned char type) |
98bac62c | 825 | { |
98bac62c PS |
826 | /* |
827 | * The first byte big endian of the length field, | |
828 | * is actually not part of the length but the type | |
829 | * with the most common, zero, as regular data. | |
830 | */ | |
fe11e4cc JL |
831 | switch (type) { |
832 | case RFC1002_SESSION_MESSAGE: | |
833 | /* Regular SMB response */ | |
834 | return true; | |
835 | case RFC1002_SESSION_KEEP_ALIVE: | |
f96637be | 836 | cifs_dbg(FYI, "RFC 1002 session keep alive\n"); |
fe11e4cc JL |
837 | break; |
838 | case RFC1002_POSITIVE_SESSION_RESPONSE: | |
f96637be | 839 | cifs_dbg(FYI, "RFC 1002 positive session response\n"); |
fe11e4cc JL |
840 | break; |
841 | case RFC1002_NEGATIVE_SESSION_RESPONSE: | |
98bac62c PS |
842 | /* |
843 | * We get this from Windows 98 instead of an error on | |
844 | * SMB negprot response. | |
845 | */ | |
f96637be | 846 | cifs_dbg(FYI, "RFC 1002 negative session response\n"); |
98bac62c PS |
847 | /* give server a second to clean up */ |
848 | msleep(1000); | |
849 | /* | |
850 | * Always try 445 first on reconnect since we get NACK | |
851 | * on some if we ever connected to port 139 (the NACK | |
852 | * is since we do not begin with RFC1001 session | |
853 | * initialize frame). | |
854 | */ | |
fe11e4cc | 855 | cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT); |
98bac62c | 856 | cifs_reconnect(server); |
fe11e4cc JL |
857 | break; |
858 | default: | |
afe6f653 | 859 | cifs_server_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type); |
98bac62c | 860 | cifs_reconnect(server); |
98bac62c PS |
861 | } |
862 | ||
fe11e4cc | 863 | return false; |
98bac62c PS |
864 | } |
865 | ||
e28bc5b1 JL |
866 | void |
867 | dequeue_mid(struct mid_q_entry *mid, bool malformed) | |
ea1f4502 | 868 | { |
ad69bae1 | 869 | #ifdef CONFIG_CIFS_STATS2 |
ea1f4502 | 870 | mid->when_received = jiffies; |
ad69bae1 | 871 | #endif |
ea1f4502 JL |
872 | spin_lock(&GlobalMid_Lock); |
873 | if (!malformed) | |
7c9421e1 | 874 | mid->mid_state = MID_RESPONSE_RECEIVED; |
ea1f4502 | 875 | else |
7c9421e1 | 876 | mid->mid_state = MID_RESPONSE_MALFORMED; |
ddf83afb RS |
877 | /* |
878 | * Trying to handle/dequeue a mid after the send_recv() | |
879 | * function has finished processing it is a bug. | |
880 | */ | |
881 | if (mid->mid_flags & MID_DELETED) | |
a0a3036b | 882 | pr_warn_once("trying to dequeue a deleted mid\n"); |
abe57073 | 883 | else { |
ddf83afb | 884 | list_del_init(&mid->qhead); |
abe57073 PS |
885 | mid->mid_flags |= MID_DELETED; |
886 | } | |
ad69bae1 | 887 | spin_unlock(&GlobalMid_Lock); |
ea1f4502 | 888 | } |
ad69bae1 | 889 | |
86a7964b PS |
890 | static unsigned int |
891 | smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) | |
892 | { | |
893 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer; | |
894 | ||
895 | /* | |
896 | * SMB1 does not use credits. | |
897 | */ | |
898 | if (server->vals->header_preamble_size) | |
899 | return 0; | |
900 | ||
901 | return le16_to_cpu(shdr->CreditRequest); | |
902 | } | |
903 | ||
c8054ebd JL |
904 | static void |
905 | handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server, | |
d4e4854f | 906 | char *buf, int malformed) |
ea1f4502 | 907 | { |
316cf94a PS |
908 | if (server->ops->check_trans2 && |
909 | server->ops->check_trans2(mid, server, buf, malformed)) | |
c8054ebd | 910 | return; |
86a7964b | 911 | mid->credits_received = smb2_get_credits_from_hdr(buf, server); |
ea1f4502 | 912 | mid->resp_buf = buf; |
7c9421e1 | 913 | mid->large_buf = server->large_buf; |
2a37ef94 JL |
914 | /* Was previous buf put in mpx struct for multi-rsp? */ |
915 | if (!mid->multiRsp) { | |
916 | /* smb buffer will be freed by user thread */ | |
917 | if (server->large_buf) | |
918 | server->bigbuf = NULL; | |
919 | else | |
920 | server->smallbuf = NULL; | |
921 | } | |
ffc00e27 | 922 | dequeue_mid(mid, malformed); |
ad69bae1 PS |
923 | } |
924 | ||
762dfd10 PS |
925 | static void clean_demultiplex_info(struct TCP_Server_Info *server) |
926 | { | |
927 | int length; | |
928 | ||
929 | /* take it off the list, if it's not already */ | |
930 | spin_lock(&cifs_tcp_ses_lock); | |
931 | list_del_init(&server->tcp_ses_list); | |
932 | spin_unlock(&cifs_tcp_ses_lock); | |
933 | ||
934 | spin_lock(&GlobalMid_Lock); | |
935 | server->tcpStatus = CifsExiting; | |
936 | spin_unlock(&GlobalMid_Lock); | |
937 | wake_up_all(&server->response_q); | |
938 | ||
2d86dbc9 | 939 | /* check if we have blocked requests that need to free */ |
fc40f9cf | 940 | spin_lock(&server->req_lock); |
2d86dbc9 PS |
941 | if (server->credits <= 0) |
942 | server->credits = 1; | |
fc40f9cf | 943 | spin_unlock(&server->req_lock); |
762dfd10 PS |
944 | /* |
945 | * Although there should not be any requests blocked on this queue it | |
946 | * can not hurt to be paranoid and try to wake up requests that may | |
947 | * haven been blocked when more than 50 at time were on the wire to the | |
948 | * same server - they now will see the session is in exit state and get | |
949 | * out of SendReceive. | |
950 | */ | |
951 | wake_up_all(&server->request_q); | |
952 | /* give those requests time to exit */ | |
953 | msleep(125); | |
050b8c37 LL |
954 | if (cifs_rdma_enabled(server)) |
955 | smbd_destroy(server); | |
762dfd10 PS |
956 | if (server->ssocket) { |
957 | sock_release(server->ssocket); | |
958 | server->ssocket = NULL; | |
959 | } | |
960 | ||
961 | if (!list_empty(&server->pending_mid_q)) { | |
962 | struct list_head dispose_list; | |
963 | struct mid_q_entry *mid_entry; | |
964 | struct list_head *tmp, *tmp2; | |
965 | ||
966 | INIT_LIST_HEAD(&dispose_list); | |
967 | spin_lock(&GlobalMid_Lock); | |
968 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { | |
969 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | |
f96637be | 970 | cifs_dbg(FYI, "Clearing mid 0x%llx\n", mid_entry->mid); |
abe57073 | 971 | kref_get(&mid_entry->refcount); |
7c9421e1 | 972 | mid_entry->mid_state = MID_SHUTDOWN; |
762dfd10 | 973 | list_move(&mid_entry->qhead, &dispose_list); |
abe57073 | 974 | mid_entry->mid_flags |= MID_DELETED; |
762dfd10 PS |
975 | } |
976 | spin_unlock(&GlobalMid_Lock); | |
977 | ||
978 | /* now walk dispose list and issue callbacks */ | |
979 | list_for_each_safe(tmp, tmp2, &dispose_list) { | |
980 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | |
f96637be | 981 | cifs_dbg(FYI, "Callback mid 0x%llx\n", mid_entry->mid); |
762dfd10 PS |
982 | list_del_init(&mid_entry->qhead); |
983 | mid_entry->callback(mid_entry); | |
abe57073 | 984 | cifs_mid_q_entry_release(mid_entry); |
762dfd10 PS |
985 | } |
986 | /* 1/8th of sec is more than enough time for them to exit */ | |
987 | msleep(125); | |
988 | } | |
989 | ||
990 | if (!list_empty(&server->pending_mid_q)) { | |
991 | /* | |
992 | * mpx threads have not exited yet give them at least the smb | |
993 | * send timeout time for long ops. | |
994 | * | |
995 | * Due to delays on oplock break requests, we need to wait at | |
996 | * least 45 seconds before giving up on a request getting a | |
997 | * response and going ahead and killing cifsd. | |
998 | */ | |
f96637be | 999 | cifs_dbg(FYI, "Wait for exit from demultiplex thread\n"); |
762dfd10 PS |
1000 | msleep(46000); |
1001 | /* | |
1002 | * If threads still have not exited they are probably never | |
1003 | * coming home not much else we can do but free the memory. | |
1004 | */ | |
1005 | } | |
1006 | ||
1007 | kfree(server->hostname); | |
1008 | kfree(server); | |
1009 | ||
1010 | length = atomic_dec_return(&tcpSesAllocCount); | |
1011 | if (length > 0) | |
11d83360 | 1012 | mempool_resize(cifs_req_poolp, length + cifs_min_rcv); |
762dfd10 PS |
1013 | } |
1014 | ||
e9097ab4 JL |
1015 | static int |
1016 | standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |
1017 | { | |
1018 | int length; | |
1019 | char *buf = server->smallbuf; | |
2e96467d | 1020 | unsigned int pdu_length = server->pdu_size; |
e9097ab4 JL |
1021 | |
1022 | /* make sure this will fit in a large buffer */ | |
93012bf9 RS |
1023 | if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) - |
1024 | server->vals->header_preamble_size) { | |
afe6f653 | 1025 | cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length); |
e9097ab4 | 1026 | cifs_reconnect(server); |
3fabaa27 | 1027 | return -ECONNABORTED; |
e9097ab4 JL |
1028 | } |
1029 | ||
1030 | /* switch to large buffer if too big for a small one */ | |
1031 | if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) { | |
1032 | server->large_buf = true; | |
d4e4854f | 1033 | memcpy(server->bigbuf, buf, server->total_read); |
e9097ab4 | 1034 | buf = server->bigbuf; |
e9097ab4 JL |
1035 | } |
1036 | ||
1037 | /* now read the rest */ | |
1887f601 | 1038 | length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, |
93012bf9 RS |
1039 | pdu_length - HEADER_SIZE(server) + 1 |
1040 | + server->vals->header_preamble_size); | |
1041 | ||
e9097ab4 JL |
1042 | if (length < 0) |
1043 | return length; | |
1044 | server->total_read += length; | |
1045 | ||
d4e4854f | 1046 | dump_smb(buf, server->total_read); |
e9097ab4 | 1047 | |
4326ed2f PS |
1048 | return cifs_handle_standard(server, mid); |
1049 | } | |
1050 | ||
1051 | int | |
1052 | cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |
1053 | { | |
1054 | char *buf = server->large_buf ? server->bigbuf : server->smallbuf; | |
1055 | int length; | |
1056 | ||
e9097ab4 JL |
1057 | /* |
1058 | * We know that we received enough to get to the MID as we | |
1059 | * checked the pdu_length earlier. Now check to see | |
1060 | * if the rest of the header is OK. We borrow the length | |
1061 | * var for the rest of the loop to avoid a new stack var. | |
1062 | * | |
1063 | * 48 bytes is enough to display the header and a little bit | |
1064 | * into the payload for debugging purposes. | |
1065 | */ | |
373512ec | 1066 | length = server->ops->check_message(buf, server->total_read, server); |
e9097ab4 JL |
1067 | if (length != 0) |
1068 | cifs_dump_mem("Bad SMB: ", buf, | |
1069 | min_t(unsigned int, server->total_read, 48)); | |
1070 | ||
511c54a2 PS |
1071 | if (server->ops->is_session_expired && |
1072 | server->ops->is_session_expired(buf)) { | |
1073 | cifs_reconnect(server); | |
511c54a2 PS |
1074 | return -1; |
1075 | } | |
1076 | ||
2e44b288 | 1077 | if (server->ops->is_status_pending && |
66265f13 | 1078 | server->ops->is_status_pending(buf, server)) |
2e44b288 PS |
1079 | return -1; |
1080 | ||
ff4fa4a2 JL |
1081 | if (!mid) |
1082 | return length; | |
e9097ab4 | 1083 | |
d4e4854f | 1084 | handle_mid(mid, server, buf, length); |
ff4fa4a2 | 1085 | return 0; |
e9097ab4 JL |
1086 | } |
1087 | ||
eca00452 RS |
1088 | static void |
1089 | smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) | |
1090 | { | |
1091 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer; | |
1092 | ||
1093 | /* | |
1094 | * SMB1 does not use credits. | |
1095 | */ | |
1096 | if (server->vals->header_preamble_size) | |
1097 | return; | |
1098 | ||
1099 | if (shdr->CreditRequest) { | |
1100 | spin_lock(&server->req_lock); | |
1101 | server->credits += le16_to_cpu(shdr->CreditRequest); | |
1102 | spin_unlock(&server->req_lock); | |
1103 | wake_up(&server->request_q); | |
1104 | } | |
1105 | } | |
1106 | ||
1107 | ||
1da177e4 | 1108 | static int |
7c97c200 | 1109 | cifs_demultiplex_thread(void *p) |
1da177e4 | 1110 | { |
b24df3e3 | 1111 | int i, num_mids, length; |
7c97c200 | 1112 | struct TCP_Server_Info *server = p; |
2a37ef94 | 1113 | unsigned int pdu_length; |
8ce79ec3 | 1114 | unsigned int next_offset; |
2a37ef94 | 1115 | char *buf = NULL; |
a5c3e1c7 | 1116 | struct task_struct *task_to_wake = NULL; |
b24df3e3 RS |
1117 | struct mid_q_entry *mids[MAX_COMPOUND]; |
1118 | char *bufs[MAX_COMPOUND]; | |
dc920277 | 1119 | unsigned int noreclaim_flag; |
1da177e4 | 1120 | |
dc920277 | 1121 | noreclaim_flag = memalloc_noreclaim_save(); |
f96637be | 1122 | cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current)); |
93d0ec85 JL |
1123 | |
1124 | length = atomic_inc_return(&tcpSesAllocCount); | |
1125 | if (length > 1) | |
11d83360 | 1126 | mempool_resize(cifs_req_poolp, length + cifs_min_rcv); |
1da177e4 | 1127 | |
83144186 | 1128 | set_freezable(); |
33da8e7c | 1129 | allow_kernel_signal(SIGKILL); |
469ee614 | 1130 | while (server->tcpStatus != CifsExiting) { |
ede1327e SF |
1131 | if (try_to_freeze()) |
1132 | continue; | |
b8643e1b | 1133 | |
2a37ef94 | 1134 | if (!allocate_buffers(server)) |
3d9c2472 | 1135 | continue; |
b8643e1b | 1136 | |
2a37ef94 | 1137 | server->large_buf = false; |
2a37ef94 | 1138 | buf = server->smallbuf; |
f01d5e14 | 1139 | pdu_length = 4; /* enough to get RFC1001 header */ |
fda35943 | 1140 | |
e28bc5b1 | 1141 | length = cifs_read_from_socket(server, buf, pdu_length); |
a52c1eb7 | 1142 | if (length < 0) |
1da177e4 | 1143 | continue; |
977b6170 RS |
1144 | |
1145 | if (server->vals->header_preamble_size == 0) | |
1146 | server->total_read = 0; | |
1147 | else | |
1148 | server->total_read = length; | |
1da177e4 | 1149 | |
98bac62c PS |
1150 | /* |
1151 | * The right amount was read from socket - 4 bytes, | |
1152 | * so we can now interpret the length field. | |
1153 | */ | |
d4e4854f | 1154 | pdu_length = get_rfc1002_length(buf); |
70ca734a | 1155 | |
f96637be | 1156 | cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length); |
fe11e4cc | 1157 | if (!is_smb_response(server, buf[0])) |
fb8c4b14 | 1158 | continue; |
8ce79ec3 RS |
1159 | next_pdu: |
1160 | server->pdu_size = pdu_length; | |
e4eb295d | 1161 | |
89482a56 | 1162 | /* make sure we have enough to get to the MID */ |
8ce79ec3 | 1163 | if (server->pdu_size < HEADER_SIZE(server) - 1 - |
93012bf9 | 1164 | server->vals->header_preamble_size) { |
afe6f653 | 1165 | cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n", |
8ce79ec3 | 1166 | server->pdu_size); |
89482a56 | 1167 | cifs_reconnect(server); |
89482a56 | 1168 | continue; |
e4eb295d | 1169 | } |
e7015fb1 | 1170 | |
89482a56 | 1171 | /* read down to the MID */ |
93012bf9 RS |
1172 | length = cifs_read_from_socket(server, |
1173 | buf + server->vals->header_preamble_size, | |
1174 | HEADER_SIZE(server) - 1 | |
1175 | - server->vals->header_preamble_size); | |
89482a56 | 1176 | if (length < 0) |
e4eb295d | 1177 | continue; |
2a37ef94 | 1178 | server->total_read += length; |
1da177e4 | 1179 | |
8ce79ec3 RS |
1180 | if (server->ops->next_header) { |
1181 | next_offset = server->ops->next_header(buf); | |
1182 | if (next_offset) | |
1183 | server->pdu_size = next_offset; | |
1184 | } | |
1185 | ||
b24df3e3 RS |
1186 | memset(mids, 0, sizeof(mids)); |
1187 | memset(bufs, 0, sizeof(bufs)); | |
1188 | num_mids = 0; | |
1189 | ||
9bb17e09 PS |
1190 | if (server->ops->is_transform_hdr && |
1191 | server->ops->receive_transform && | |
1192 | server->ops->is_transform_hdr(buf)) { | |
1193 | length = server->ops->receive_transform(server, | |
b24df3e3 RS |
1194 | mids, |
1195 | bufs, | |
1196 | &num_mids); | |
9bb17e09 | 1197 | } else { |
b24df3e3 RS |
1198 | mids[0] = server->ops->find_mid(server, buf); |
1199 | bufs[0] = buf; | |
7af929d6 | 1200 | num_mids = 1; |
50c2f753 | 1201 | |
b24df3e3 RS |
1202 | if (!mids[0] || !mids[0]->receive) |
1203 | length = standard_receive3(server, mids[0]); | |
9bb17e09 | 1204 | else |
b24df3e3 | 1205 | length = mids[0]->receive(server, mids[0]); |
9bb17e09 | 1206 | } |
71823baf | 1207 | |
696e420b | 1208 | if (length < 0) { |
b24df3e3 RS |
1209 | for (i = 0; i < num_mids; i++) |
1210 | if (mids[i]) | |
1211 | cifs_mid_q_entry_release(mids[i]); | |
fe11e4cc | 1212 | continue; |
696e420b | 1213 | } |
1da177e4 | 1214 | |
fda35943 | 1215 | server->lstrp = jiffies; |
38bd4906 | 1216 | |
b24df3e3 RS |
1217 | for (i = 0; i < num_mids; i++) { |
1218 | if (mids[i] != NULL) { | |
1219 | mids[i]->resp_buf_size = server->pdu_size; | |
696e420b | 1220 | |
b24df3e3 RS |
1221 | if (!mids[i]->multiRsp || mids[i]->multiEnd) |
1222 | mids[i]->callback(mids[i]); | |
1223 | ||
1224 | cifs_mid_q_entry_release(mids[i]); | |
1225 | } else if (server->ops->is_oplock_break && | |
1226 | server->ops->is_oplock_break(bufs[i], | |
1227 | server)) { | |
eca00452 | 1228 | smb2_add_credits_from_hdr(bufs[i], server); |
b24df3e3 RS |
1229 | cifs_dbg(FYI, "Received oplock break\n"); |
1230 | } else { | |
a0a3036b JP |
1231 | cifs_server_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", |
1232 | atomic_read(&midCount)); | |
b24df3e3 RS |
1233 | cifs_dump_mem("Received Data is: ", bufs[i], |
1234 | HEADER_SIZE(server)); | |
3e272579 | 1235 | smb2_add_credits_from_hdr(bufs[i], server); |
3979877e | 1236 | #ifdef CONFIG_CIFS_DEBUG2 |
b24df3e3 RS |
1237 | if (server->ops->dump_detail) |
1238 | server->ops->dump_detail(bufs[i], | |
1239 | server); | |
1240 | cifs_dump_mids(server); | |
3979877e | 1241 | #endif /* CIFS_DEBUG2 */ |
b24df3e3 | 1242 | } |
8ce79ec3 | 1243 | } |
b24df3e3 | 1244 | |
8ce79ec3 RS |
1245 | if (pdu_length > server->pdu_size) { |
1246 | if (!allocate_buffers(server)) | |
1247 | continue; | |
1248 | pdu_length -= server->pdu_size; | |
1249 | server->total_read = 0; | |
1250 | server->large_buf = false; | |
1251 | buf = server->smallbuf; | |
1252 | goto next_pdu; | |
e4eb295d SF |
1253 | } |
1254 | } /* end while !EXITING */ | |
1255 | ||
fd62cb7e | 1256 | /* buffer usually freed in free_mid - need to free it here on exit */ |
2a37ef94 JL |
1257 | cifs_buf_release(server->bigbuf); |
1258 | if (server->smallbuf) /* no sense logging a debug message if NULL */ | |
1259 | cifs_small_buf_release(server->smallbuf); | |
1da177e4 | 1260 | |
a5c3e1c7 | 1261 | task_to_wake = xchg(&server->tsk, NULL); |
762dfd10 | 1262 | clean_demultiplex_info(server); |
a5c3e1c7 SF |
1263 | |
1264 | /* if server->tsk was NULL then wait for a signal before exiting */ | |
1265 | if (!task_to_wake) { | |
1266 | set_current_state(TASK_INTERRUPTIBLE); | |
1267 | while (!signal_pending(current)) { | |
1268 | schedule(); | |
1269 | set_current_state(TASK_INTERRUPTIBLE); | |
1270 | } | |
1271 | set_current_state(TASK_RUNNING); | |
1272 | } | |
1273 | ||
dc920277 | 1274 | memalloc_noreclaim_restore(noreclaim_flag); |
0468a2cf | 1275 | module_put_and_exit(0); |
1da177e4 LT |
1276 | } |
1277 | ||
c359cf3c JL |
1278 | /* extract the host portion of the UNC string */ |
1279 | static char * | |
1280 | extract_hostname(const char *unc) | |
1281 | { | |
1282 | const char *src; | |
1283 | char *dst, *delim; | |
1284 | unsigned int len; | |
1285 | ||
1286 | /* skip double chars at beginning of string */ | |
1287 | /* BB: check validity of these bytes? */ | |
c34fea5a PA |
1288 | if (strlen(unc) < 3) |
1289 | return ERR_PTR(-EINVAL); | |
1290 | for (src = unc; *src && *src == '\\'; src++) | |
1291 | ; | |
1292 | if (!*src) | |
1293 | return ERR_PTR(-EINVAL); | |
c359cf3c JL |
1294 | |
1295 | /* delimiter between hostname and sharename is always '\\' now */ | |
1296 | delim = strchr(src, '\\'); | |
1297 | if (!delim) | |
1298 | return ERR_PTR(-EINVAL); | |
1299 | ||
1300 | len = delim - src; | |
1301 | dst = kmalloc((len + 1), GFP_KERNEL); | |
1302 | if (dst == NULL) | |
1303 | return ERR_PTR(-ENOMEM); | |
1304 | ||
1305 | memcpy(dst, src, len); | |
1306 | dst[len] = '\0'; | |
1307 | ||
1308 | return dst; | |
1309 | } | |
1310 | ||
8830d7e0 SP |
1311 | static int get_option_ul(substring_t args[], unsigned long *option) |
1312 | { | |
1313 | int rc; | |
1314 | char *string; | |
1315 | ||
1316 | string = match_strdup(args); | |
1317 | if (string == NULL) | |
1318 | return -ENOMEM; | |
bfa890a3 | 1319 | rc = kstrtoul(string, 0, option); |
8830d7e0 SP |
1320 | kfree(string); |
1321 | ||
1322 | return rc; | |
1323 | } | |
1324 | ||
3da46565 EB |
1325 | static int get_option_uid(substring_t args[], kuid_t *result) |
1326 | { | |
1327 | unsigned long value; | |
1328 | kuid_t uid; | |
1329 | int rc; | |
1330 | ||
1331 | rc = get_option_ul(args, &value); | |
1332 | if (rc) | |
1333 | return rc; | |
1334 | ||
1335 | uid = make_kuid(current_user_ns(), value); | |
1336 | if (!uid_valid(uid)) | |
1337 | return -EINVAL; | |
1338 | ||
1339 | *result = uid; | |
1340 | return 0; | |
1341 | } | |
1342 | ||
1343 | static int get_option_gid(substring_t args[], kgid_t *result) | |
1344 | { | |
1345 | unsigned long value; | |
1346 | kgid_t gid; | |
1347 | int rc; | |
1348 | ||
1349 | rc = get_option_ul(args, &value); | |
1350 | if (rc) | |
1351 | return rc; | |
1352 | ||
1353 | gid = make_kgid(current_user_ns(), value); | |
1354 | if (!gid_valid(gid)) | |
1355 | return -EINVAL; | |
1356 | ||
1357 | *result = gid; | |
1358 | return 0; | |
1359 | } | |
8830d7e0 SP |
1360 | |
1361 | static int cifs_parse_security_flavors(char *value, | |
1362 | struct smb_vol *vol) | |
1363 | { | |
1364 | ||
1365 | substring_t args[MAX_OPT_ARGS]; | |
1366 | ||
1e3cc57e JL |
1367 | /* |
1368 | * With mount options, the last one should win. Reset any existing | |
1369 | * settings back to default. | |
1370 | */ | |
1371 | vol->sectype = Unspecified; | |
1372 | vol->sign = false; | |
1373 | ||
8830d7e0 | 1374 | switch (match_token(value, cifs_secflavor_tokens, args)) { |
3f618223 JL |
1375 | case Opt_sec_krb5p: |
1376 | cifs_dbg(VFS, "sec=krb5p is not supported!\n"); | |
1377 | return 1; | |
1378 | case Opt_sec_krb5i: | |
1379 | vol->sign = true; | |
1380 | /* Fallthrough */ | |
8830d7e0 | 1381 | case Opt_sec_krb5: |
1e3cc57e | 1382 | vol->sectype = Kerberos; |
8830d7e0 | 1383 | break; |
3f618223 | 1384 | case Opt_sec_ntlmsspi: |
1e3cc57e | 1385 | vol->sign = true; |
3f618223 | 1386 | /* Fallthrough */ |
8830d7e0 | 1387 | case Opt_sec_ntlmssp: |
1e3cc57e | 1388 | vol->sectype = RawNTLMSSP; |
8830d7e0 | 1389 | break; |
3f618223 | 1390 | case Opt_sec_ntlmi: |
1e3cc57e | 1391 | vol->sign = true; |
3f618223 | 1392 | /* Fallthrough */ |
8830d7e0 | 1393 | case Opt_ntlm: |
1e3cc57e | 1394 | vol->sectype = NTLM; |
8830d7e0 | 1395 | break; |
3f618223 | 1396 | case Opt_sec_ntlmv2i: |
1e3cc57e | 1397 | vol->sign = true; |
3f618223 | 1398 | /* Fallthrough */ |
7659624f | 1399 | case Opt_sec_ntlmv2: |
1e3cc57e | 1400 | vol->sectype = NTLMv2; |
8830d7e0 SP |
1401 | break; |
1402 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | |
1403 | case Opt_sec_lanman: | |
1e3cc57e | 1404 | vol->sectype = LANMAN; |
8830d7e0 SP |
1405 | break; |
1406 | #endif | |
1407 | case Opt_sec_none: | |
1408 | vol->nullauth = 1; | |
1409 | break; | |
1410 | default: | |
f96637be | 1411 | cifs_dbg(VFS, "bad security option: %s\n", value); |
8830d7e0 SP |
1412 | return 1; |
1413 | } | |
1414 | ||
1415 | return 0; | |
1416 | } | |
1417 | ||
15b6a473 JL |
1418 | static int |
1419 | cifs_parse_cache_flavor(char *value, struct smb_vol *vol) | |
1420 | { | |
1421 | substring_t args[MAX_OPT_ARGS]; | |
1422 | ||
1423 | switch (match_token(value, cifs_cacheflavor_tokens, args)) { | |
1424 | case Opt_cache_loose: | |
1425 | vol->direct_io = false; | |
1426 | vol->strict_io = false; | |
83bbfa70 | 1427 | vol->cache_ro = false; |
41e033fe | 1428 | vol->cache_rw = false; |
15b6a473 JL |
1429 | break; |
1430 | case Opt_cache_strict: | |
1431 | vol->direct_io = false; | |
1432 | vol->strict_io = true; | |
83bbfa70 | 1433 | vol->cache_ro = false; |
41e033fe | 1434 | vol->cache_rw = false; |
15b6a473 JL |
1435 | break; |
1436 | case Opt_cache_none: | |
1437 | vol->direct_io = true; | |
1438 | vol->strict_io = false; | |
83bbfa70 | 1439 | vol->cache_ro = false; |
41e033fe | 1440 | vol->cache_rw = false; |
83bbfa70 SF |
1441 | break; |
1442 | case Opt_cache_ro: | |
1443 | vol->direct_io = false; | |
1444 | vol->strict_io = false; | |
1445 | vol->cache_ro = true; | |
41e033fe SF |
1446 | vol->cache_rw = false; |
1447 | break; | |
1448 | case Opt_cache_rw: | |
1449 | vol->direct_io = false; | |
1450 | vol->strict_io = false; | |
1451 | vol->cache_ro = false; | |
1452 | vol->cache_rw = true; | |
15b6a473 JL |
1453 | break; |
1454 | default: | |
f96637be | 1455 | cifs_dbg(VFS, "bad cache= option: %s\n", value); |
15b6a473 JL |
1456 | return 1; |
1457 | } | |
1458 | return 0; | |
1459 | } | |
1460 | ||
23db65f5 | 1461 | static int |
c7c137b9 | 1462 | cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3) |
23db65f5 JL |
1463 | { |
1464 | substring_t args[MAX_OPT_ARGS]; | |
1465 | ||
1466 | switch (match_token(value, cifs_smb_version_tokens, args)) { | |
7420451f | 1467 | #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY |
23db65f5 | 1468 | case Smb_1: |
f92a720e SF |
1469 | if (disable_legacy_dialects) { |
1470 | cifs_dbg(VFS, "mount with legacy dialect disabled\n"); | |
1471 | return 1; | |
1472 | } | |
c7c137b9 SF |
1473 | if (is_smb3) { |
1474 | cifs_dbg(VFS, "vers=1.0 (cifs) not permitted when mounting with smb3\n"); | |
1475 | return 1; | |
1476 | } | |
a0a3036b | 1477 | cifs_dbg(VFS, "Use of the less secure dialect vers=1.0 is not recommended unless required for access to very old servers\n"); |
23db65f5 JL |
1478 | vol->ops = &smb1_operations; |
1479 | vol->vals = &smb1_values; | |
1480 | break; | |
dd446b16 | 1481 | case Smb_20: |
f92a720e SF |
1482 | if (disable_legacy_dialects) { |
1483 | cifs_dbg(VFS, "mount with legacy dialect disabled\n"); | |
1484 | return 1; | |
1485 | } | |
c7c137b9 SF |
1486 | if (is_smb3) { |
1487 | cifs_dbg(VFS, "vers=2.0 not permitted when mounting with smb3\n"); | |
1488 | return 1; | |
1489 | } | |
53ef1016 | 1490 | vol->ops = &smb20_operations; |
dd446b16 SF |
1491 | vol->vals = &smb20_values; |
1492 | break; | |
7420451f SF |
1493 | #else |
1494 | case Smb_1: | |
1495 | cifs_dbg(VFS, "vers=1.0 (cifs) mount not permitted when legacy dialects disabled\n"); | |
1496 | return 1; | |
1497 | case Smb_20: | |
1498 | cifs_dbg(VFS, "vers=2.0 mount not permitted when legacy dialects disabled\n"); | |
1499 | return 1; | |
1500 | #endif /* CIFS_ALLOW_INSECURE_LEGACY */ | |
1080ef75 SF |
1501 | case Smb_21: |
1502 | vol->ops = &smb21_operations; | |
1503 | vol->vals = &smb21_values; | |
1504 | break; | |
e4aa25e7 | 1505 | case Smb_30: |
38107d45 | 1506 | vol->ops = &smb30_operations; |
e4aa25e7 SF |
1507 | vol->vals = &smb30_values; |
1508 | break; | |
20b6d8b4 SF |
1509 | case Smb_302: |
1510 | vol->ops = &smb30_operations; /* currently identical with 3.0 */ | |
1511 | vol->vals = &smb302_values; | |
1512 | break; | |
5f7fbf73 | 1513 | case Smb_311: |
aab1893d | 1514 | vol->ops = &smb311_operations; |
5f7fbf73 SF |
1515 | vol->vals = &smb311_values; |
1516 | break; | |
9764c02f SF |
1517 | case Smb_3any: |
1518 | vol->ops = &smb30_operations; /* currently identical with 3.0 */ | |
1519 | vol->vals = &smb3any_values; | |
1520 | break; | |
1521 | case Smb_default: | |
1522 | vol->ops = &smb30_operations; /* currently identical with 3.0 */ | |
1523 | vol->vals = &smbdefault_values; | |
1524 | break; | |
23db65f5 | 1525 | default: |
f96637be | 1526 | cifs_dbg(VFS, "Unknown vers= option specified: %s\n", value); |
23db65f5 JL |
1527 | return 1; |
1528 | } | |
1529 | return 0; | |
1530 | } | |
1531 | ||
d387a5c5 JL |
1532 | /* |
1533 | * Parse a devname into substrings and populate the vol->UNC and vol->prepath | |
1534 | * fields with the result. Returns 0 on success and an error otherwise. | |
1535 | */ | |
1536 | static int | |
1537 | cifs_parse_devname(const char *devname, struct smb_vol *vol) | |
1538 | { | |
1539 | char *pos; | |
1540 | const char *delims = "/\\"; | |
1541 | size_t len; | |
1542 | ||
68e2672f | 1543 | if (unlikely(!devname || !*devname)) { |
a0a3036b | 1544 | cifs_dbg(VFS, "Device name not specified\n"); |
68e2672f YL |
1545 | return -EINVAL; |
1546 | } | |
1547 | ||
d387a5c5 JL |
1548 | /* make sure we have a valid UNC double delimiter prefix */ |
1549 | len = strspn(devname, delims); | |
1550 | if (len != 2) | |
1551 | return -EINVAL; | |
1552 | ||
1553 | /* find delimiter between host and sharename */ | |
1554 | pos = strpbrk(devname + 2, delims); | |
1555 | if (!pos) | |
1556 | return -EINVAL; | |
1557 | ||
1558 | /* skip past delimiter */ | |
1559 | ++pos; | |
1560 | ||
1561 | /* now go until next delimiter or end of string */ | |
1562 | len = strcspn(pos, delims); | |
1563 | ||
1564 | /* move "pos" up to delimiter or NULL */ | |
1565 | pos += len; | |
1566 | vol->UNC = kstrndup(devname, pos - devname, GFP_KERNEL); | |
1567 | if (!vol->UNC) | |
1568 | return -ENOMEM; | |
1569 | ||
1570 | convert_delimiter(vol->UNC, '\\'); | |
1571 | ||
11e31647 SP |
1572 | /* skip any delimiter */ |
1573 | if (*pos == '/' || *pos == '\\') | |
1574 | pos++; | |
1575 | ||
1576 | /* If pos is NULL then no prepath */ | |
1577 | if (!*pos) | |
d387a5c5 JL |
1578 | return 0; |
1579 | ||
1580 | vol->prepath = kstrdup(pos, GFP_KERNEL); | |
1581 | if (!vol->prepath) | |
1582 | return -ENOMEM; | |
1583 | ||
1584 | return 0; | |
1585 | } | |
1586 | ||
1da177e4 | 1587 | static int |
b946845a | 1588 | cifs_parse_mount_options(const char *mountdata, const char *devname, |
c7c137b9 | 1589 | struct smb_vol *vol, bool is_smb3) |
1da177e4 | 1590 | { |
8830d7e0 | 1591 | char *data, *end; |
957df453 | 1592 | char *mountdata_copy = NULL, *options; |
1da177e4 LT |
1593 | unsigned int temp_len, i, j; |
1594 | char separator[2]; | |
9b9d6b24 JL |
1595 | short int override_uid = -1; |
1596 | short int override_gid = -1; | |
1597 | bool uid_specified = false; | |
1598 | bool gid_specified = false; | |
d8162558 JL |
1599 | bool sloppy = false; |
1600 | char *invalid = NULL; | |
88463999 | 1601 | char *nodename = utsname()->nodename; |
8830d7e0 SP |
1602 | char *string = NULL; |
1603 | char *tmp_end, *value; | |
1604 | char delim; | |
b979aaa1 | 1605 | bool got_ip = false; |
7e682f76 | 1606 | bool got_version = false; |
b979aaa1 JL |
1607 | unsigned short port = 0; |
1608 | struct sockaddr *dstaddr = (struct sockaddr *)&vol->dstaddr; | |
1da177e4 LT |
1609 | |
1610 | separator[0] = ','; | |
50c2f753 | 1611 | separator[1] = 0; |
8830d7e0 | 1612 | delim = separator[0]; |
1da177e4 | 1613 | |
6ee9542a JL |
1614 | /* ensure we always start with zeroed-out smb_vol */ |
1615 | memset(vol, 0, sizeof(*vol)); | |
1616 | ||
88463999 JL |
1617 | /* |
1618 | * does not have to be perfect mapping since field is | |
1619 | * informational, only used for servers that do not support | |
1620 | * port 445 and it can be overridden at mount time | |
1621 | */ | |
1397f2ee JL |
1622 | memset(vol->source_rfc1001_name, 0x20, RFC1001_NAME_LEN); |
1623 | for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++) | |
88463999 JL |
1624 | vol->source_rfc1001_name[i] = toupper(nodename[i]); |
1625 | ||
1397f2ee | 1626 | vol->source_rfc1001_name[RFC1001_NAME_LEN] = 0; |
a10faeb2 SF |
1627 | /* null target name indicates to use *SMBSERVR default called name |
1628 | if we end up sending RFC1001 session initialize */ | |
1629 | vol->target_rfc1001_name[0] = 0; | |
3e4b3e1f JL |
1630 | vol->cred_uid = current_uid(); |
1631 | vol->linux_uid = current_uid(); | |
a001e5b5 | 1632 | vol->linux_gid = current_gid(); |
e8506d25 | 1633 | vol->bsize = 1024 * 1024; /* can improve cp performance significantly */ |
2baa2682 SF |
1634 | /* |
1635 | * default to SFM style remapping of seven reserved characters | |
1636 | * unless user overrides it or we negotiate CIFS POSIX where | |
1637 | * it is unnecessary. Can not simultaneously use more than one mapping | |
1638 | * since then readdir could list files that open could not open | |
1639 | */ | |
1640 | vol->remap = true; | |
1641 | ||
f55ed1a8 JL |
1642 | /* default to only allowing write access to owner of the mount */ |
1643 | vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR; | |
1da177e4 LT |
1644 | |
1645 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ | |
ac67055e JA |
1646 | /* default is always to request posix paths. */ |
1647 | vol->posix_paths = 1; | |
a0c9217f JL |
1648 | /* default to using server inode numbers where available */ |
1649 | vol->server_ino = 1; | |
ac67055e | 1650 | |
1b359204 JL |
1651 | /* default is to use strict cifs caching semantics */ |
1652 | vol->strict_io = true; | |
1653 | ||
6d20e840 SJ |
1654 | vol->actimeo = CIFS_DEF_ACTIMEO; |
1655 | ||
ca567eb2 SF |
1656 | /* Most clients set timeout to 0, allows server to use its default */ |
1657 | vol->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */ | |
1658 | ||
9764c02f SF |
1659 | /* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */ |
1660 | vol->ops = &smb30_operations; | |
1661 | vol->vals = &smbdefault_values; | |
23db65f5 | 1662 | |
b782fcc1 RV |
1663 | vol->echo_interval = SMB_ECHO_INTERVAL_DEFAULT; |
1664 | ||
bcc88801 AA |
1665 | /* default to no multichannel (single server connection) */ |
1666 | vol->multichannel = false; | |
1667 | vol->max_channels = 1; | |
1668 | ||
b946845a SF |
1669 | if (!mountdata) |
1670 | goto cifs_parse_mount_err; | |
1671 | ||
1672 | mountdata_copy = kstrndup(mountdata, PAGE_SIZE, GFP_KERNEL); | |
1673 | if (!mountdata_copy) | |
1674 | goto cifs_parse_mount_err; | |
1da177e4 | 1675 | |
b946845a | 1676 | options = mountdata_copy; |
4906e50b | 1677 | end = options + strlen(options); |
8830d7e0 | 1678 | |
50c2f753 | 1679 | if (strncmp(options, "sep=", 4) == 0) { |
fb8c4b14 | 1680 | if (options[4] != 0) { |
1da177e4 LT |
1681 | separator[0] = options[4]; |
1682 | options += 5; | |
1683 | } else { | |
f96637be | 1684 | cifs_dbg(FYI, "Null separator not allowed\n"); |
1da177e4 LT |
1685 | } |
1686 | } | |
3d3ea8e6 SP |
1687 | vol->backupuid_specified = false; /* no backup intent for a user */ |
1688 | vol->backupgid_specified = false; /* no backup intent for a group */ | |
50c2f753 | 1689 | |
37d4f99b JL |
1690 | switch (cifs_parse_devname(devname, vol)) { |
1691 | case 0: | |
1692 | break; | |
1693 | case -ENOMEM: | |
a0a3036b | 1694 | cifs_dbg(VFS, "Unable to allocate memory for devname\n"); |
37d4f99b JL |
1695 | goto cifs_parse_mount_err; |
1696 | case -EINVAL: | |
a0a3036b | 1697 | cifs_dbg(VFS, "Malformed UNC in devname\n"); |
37d4f99b JL |
1698 | goto cifs_parse_mount_err; |
1699 | default: | |
a0a3036b | 1700 | cifs_dbg(VFS, "Unknown error parsing devname\n"); |
37d4f99b | 1701 | goto cifs_parse_mount_err; |
d387a5c5 JL |
1702 | } |
1703 | ||
1da177e4 | 1704 | while ((data = strsep(&options, separator)) != NULL) { |
8830d7e0 SP |
1705 | substring_t args[MAX_OPT_ARGS]; |
1706 | unsigned long option; | |
1707 | int token; | |
1708 | ||
1da177e4 LT |
1709 | if (!*data) |
1710 | continue; | |
1da177e4 | 1711 | |
8830d7e0 SP |
1712 | token = match_token(data, cifs_mount_option_tokens, args); |
1713 | ||
1714 | switch (token) { | |
1715 | ||
1716 | /* Ingnore the following */ | |
1717 | case Opt_ignore: | |
1718 | break; | |
1719 | ||
1720 | /* Boolean values */ | |
1721 | case Opt_user_xattr: | |
1da177e4 | 1722 | vol->no_xattr = 0; |
8830d7e0 SP |
1723 | break; |
1724 | case Opt_nouser_xattr: | |
1da177e4 | 1725 | vol->no_xattr = 1; |
8830d7e0 SP |
1726 | break; |
1727 | case Opt_forceuid: | |
9b9d6b24 | 1728 | override_uid = 1; |
8830d7e0 SP |
1729 | break; |
1730 | case Opt_noforceuid: | |
9b9d6b24 | 1731 | override_uid = 0; |
8830d7e0 | 1732 | break; |
72bd481f JL |
1733 | case Opt_forcegid: |
1734 | override_gid = 1; | |
1735 | break; | |
1736 | case Opt_noforcegid: | |
1737 | override_gid = 0; | |
1738 | break; | |
8830d7e0 | 1739 | case Opt_noblocksend: |
edf1ae40 | 1740 | vol->noblocksnd = 1; |
8830d7e0 SP |
1741 | break; |
1742 | case Opt_noautotune: | |
edf1ae40 | 1743 | vol->noautotune = 1; |
8830d7e0 | 1744 | break; |
3e7a02d4 SF |
1745 | case Opt_nolease: |
1746 | vol->no_lease = 1; | |
1747 | break; | |
8830d7e0 | 1748 | case Opt_hard: |
1da177e4 | 1749 | vol->retry = 1; |
8830d7e0 SP |
1750 | break; |
1751 | case Opt_soft: | |
1da177e4 | 1752 | vol->retry = 0; |
8830d7e0 SP |
1753 | break; |
1754 | case Opt_perm: | |
1da177e4 | 1755 | vol->noperm = 0; |
8830d7e0 SP |
1756 | break; |
1757 | case Opt_noperm: | |
1da177e4 | 1758 | vol->noperm = 1; |
8830d7e0 | 1759 | break; |
82e9367c SF |
1760 | case Opt_nodelete: |
1761 | vol->nodelete = 1; | |
1762 | break; | |
8830d7e0 | 1763 | case Opt_mapchars: |
2baa2682 SF |
1764 | vol->sfu_remap = true; |
1765 | vol->remap = false; /* disable SFM mapping */ | |
8830d7e0 SP |
1766 | break; |
1767 | case Opt_nomapchars: | |
2baa2682 SF |
1768 | vol->sfu_remap = false; |
1769 | break; | |
1770 | case Opt_mapposix: | |
1771 | vol->remap = true; | |
1772 | vol->sfu_remap = false; /* disable SFU mapping */ | |
1773 | break; | |
1774 | case Opt_nomapposix: | |
1775 | vol->remap = false; | |
8830d7e0 SP |
1776 | break; |
1777 | case Opt_sfu: | |
50c2f753 | 1778 | vol->sfu_emul = 1; |
8830d7e0 SP |
1779 | break; |
1780 | case Opt_nosfu: | |
50c2f753 | 1781 | vol->sfu_emul = 0; |
8830d7e0 SP |
1782 | break; |
1783 | case Opt_nodfs: | |
2c1b8615 | 1784 | vol->nodfs = 1; |
8830d7e0 | 1785 | break; |
8eecd1c2 PAS |
1786 | case Opt_rootfs: |
1787 | #ifdef CONFIG_CIFS_ROOT | |
1788 | vol->rootfs = true; | |
1789 | #endif | |
1790 | break; | |
8830d7e0 | 1791 | case Opt_posixpaths: |
ac67055e | 1792 | vol->posix_paths = 1; |
8830d7e0 SP |
1793 | break; |
1794 | case Opt_noposixpaths: | |
ac67055e | 1795 | vol->posix_paths = 0; |
8830d7e0 SP |
1796 | break; |
1797 | case Opt_nounix: | |
b326614e SF |
1798 | if (vol->linux_ext) |
1799 | cifs_dbg(VFS, | |
1800 | "conflicting unix mount options\n"); | |
c18c842b | 1801 | vol->no_linux_ext = 1; |
8830d7e0 | 1802 | break; |
b326614e SF |
1803 | case Opt_unix: |
1804 | if (vol->no_linux_ext) | |
1805 | cifs_dbg(VFS, | |
1806 | "conflicting unix mount options\n"); | |
1807 | vol->linux_ext = 1; | |
1808 | break; | |
8830d7e0 | 1809 | case Opt_nocase: |
50c2f753 | 1810 | vol->nocase = 1; |
8830d7e0 SP |
1811 | break; |
1812 | case Opt_brl: | |
c46fa8ac | 1813 | vol->nobrl = 0; |
8830d7e0 SP |
1814 | break; |
1815 | case Opt_nobrl: | |
c46fa8ac | 1816 | vol->nobrl = 1; |
5cfdddcf PS |
1817 | /* |
1818 | * turn off mandatory locking in mode | |
8830d7e0 | 1819 | * if remote locking is turned off since the |
5cfdddcf PS |
1820 | * local vfs will do advisory |
1821 | */ | |
50c2f753 SF |
1822 | if (vol->file_mode == |
1823 | (S_IALLUGO & ~(S_ISUID | S_IXGRP))) | |
d3485d37 | 1824 | vol->file_mode = S_IALLUGO; |
8830d7e0 | 1825 | break; |
3d4ef9a1 SF |
1826 | case Opt_nohandlecache: |
1827 | vol->nohandlecache = 1; | |
1828 | break; | |
1829 | case Opt_handlecache: | |
1830 | vol->nohandlecache = 0; | |
1831 | break; | |
8830d7e0 | 1832 | case Opt_forcemandatorylock: |
13a6e42a | 1833 | vol->mand_lock = 1; |
8830d7e0 SP |
1834 | break; |
1835 | case Opt_setuids: | |
1da177e4 | 1836 | vol->setuids = 1; |
8830d7e0 SP |
1837 | break; |
1838 | case Opt_nosetuids: | |
1da177e4 | 1839 | vol->setuids = 0; |
8830d7e0 | 1840 | break; |
95932655 SF |
1841 | case Opt_setuidfromacl: |
1842 | vol->setuidfromacl = 1; | |
1843 | break; | |
8830d7e0 | 1844 | case Opt_dynperm: |
d0a9c078 | 1845 | vol->dynperm = true; |
8830d7e0 SP |
1846 | break; |
1847 | case Opt_nodynperm: | |
d0a9c078 | 1848 | vol->dynperm = false; |
8830d7e0 SP |
1849 | break; |
1850 | case Opt_nohard: | |
1da177e4 | 1851 | vol->retry = 0; |
8830d7e0 SP |
1852 | break; |
1853 | case Opt_nosoft: | |
1da177e4 | 1854 | vol->retry = 1; |
8830d7e0 SP |
1855 | break; |
1856 | case Opt_nointr: | |
1da177e4 | 1857 | vol->intr = 0; |
8830d7e0 SP |
1858 | break; |
1859 | case Opt_intr: | |
1da177e4 | 1860 | vol->intr = 1; |
8830d7e0 SP |
1861 | break; |
1862 | case Opt_nostrictsync: | |
be652445 | 1863 | vol->nostrictsync = 1; |
8830d7e0 SP |
1864 | break; |
1865 | case Opt_strictsync: | |
be652445 | 1866 | vol->nostrictsync = 0; |
8830d7e0 SP |
1867 | break; |
1868 | case Opt_serverino: | |
1da177e4 | 1869 | vol->server_ino = 1; |
8830d7e0 SP |
1870 | break; |
1871 | case Opt_noserverino: | |
1da177e4 | 1872 | vol->server_ino = 0; |
8830d7e0 SP |
1873 | break; |
1874 | case Opt_rwpidforward: | |
d4ffff1f | 1875 | vol->rwpidforward = 1; |
8830d7e0 | 1876 | break; |
412094a8 SF |
1877 | case Opt_modesid: |
1878 | vol->mode_ace = 1; | |
1879 | break; | |
8830d7e0 | 1880 | case Opt_cifsacl: |
0a4b92c0 | 1881 | vol->cifs_acl = 1; |
8830d7e0 SP |
1882 | break; |
1883 | case Opt_nocifsacl: | |
0a4b92c0 | 1884 | vol->cifs_acl = 0; |
8830d7e0 SP |
1885 | break; |
1886 | case Opt_acl: | |
1da177e4 | 1887 | vol->no_psx_acl = 0; |
8830d7e0 SP |
1888 | break; |
1889 | case Opt_noacl: | |
1da177e4 | 1890 | vol->no_psx_acl = 1; |
8830d7e0 SP |
1891 | break; |
1892 | case Opt_locallease: | |
84210e91 | 1893 | vol->local_lease = 1; |
8830d7e0 SP |
1894 | break; |
1895 | case Opt_sign: | |
1e3cc57e | 1896 | vol->sign = true; |
8830d7e0 | 1897 | break; |
4f5c10f1 SF |
1898 | case Opt_ignore_signature: |
1899 | vol->sign = true; | |
1900 | vol->ignore_signature = true; | |
1901 | break; | |
8830d7e0 | 1902 | case Opt_seal: |
95b1cb90 | 1903 | /* we do not do the following in secFlags because seal |
8830d7e0 SP |
1904 | * is a per tree connection (mount) not a per socket |
1905 | * or per-smb connection option in the protocol | |
1906 | * vol->secFlg |= CIFSSEC_MUST_SEAL; | |
1907 | */ | |
95b1cb90 | 1908 | vol->seal = 1; |
8830d7e0 | 1909 | break; |
8830d7e0 | 1910 | case Opt_noac: |
a0a3036b | 1911 | pr_warn("Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); |
8830d7e0 SP |
1912 | break; |
1913 | case Opt_fsc: | |
607a569d | 1914 | #ifndef CONFIG_CIFS_FSCACHE |
f96637be | 1915 | cifs_dbg(VFS, "FS-Cache support needs CONFIG_CIFS_FSCACHE kernel config option set\n"); |
b946845a | 1916 | goto cifs_parse_mount_err; |
607a569d | 1917 | #endif |
fa1df75d | 1918 | vol->fsc = true; |
8830d7e0 SP |
1919 | break; |
1920 | case Opt_mfsymlinks: | |
736a3320 | 1921 | vol->mfsymlinks = true; |
8830d7e0 SP |
1922 | break; |
1923 | case Opt_multiuser: | |
0eb8a132 | 1924 | vol->multiuser = true; |
8830d7e0 | 1925 | break; |
d8162558 JL |
1926 | case Opt_sloppy: |
1927 | sloppy = true; | |
1928 | break; | |
a0b3df5c JL |
1929 | case Opt_nosharesock: |
1930 | vol->nosharesock = true; | |
1931 | break; | |
b2a30774 SF |
1932 | case Opt_nopersistent: |
1933 | vol->nopersistent = true; | |
1934 | if (vol->persistent) { | |
1935 | cifs_dbg(VFS, | |
1936 | "persistenthandles mount options conflict\n"); | |
1937 | goto cifs_parse_mount_err; | |
1938 | } | |
1939 | break; | |
1940 | case Opt_persistent: | |
1941 | vol->persistent = true; | |
592fafe6 | 1942 | if ((vol->nopersistent) || (vol->resilient)) { |
b2a30774 SF |
1943 | cifs_dbg(VFS, |
1944 | "persistenthandles mount options conflict\n"); | |
1945 | goto cifs_parse_mount_err; | |
1946 | } | |
1947 | break; | |
592fafe6 SF |
1948 | case Opt_resilient: |
1949 | vol->resilient = true; | |
1950 | if (vol->persistent) { | |
1951 | cifs_dbg(VFS, | |
1952 | "persistenthandles mount options conflict\n"); | |
1953 | goto cifs_parse_mount_err; | |
1954 | } | |
1955 | break; | |
1956 | case Opt_noresilient: | |
1957 | vol->resilient = false; /* already the default */ | |
1958 | break; | |
39566443 GP |
1959 | case Opt_domainauto: |
1960 | vol->domainauto = true; | |
1961 | break; | |
8339dd32 LL |
1962 | case Opt_rdma: |
1963 | vol->rdma = true; | |
1964 | break; | |
bcc88801 AA |
1965 | case Opt_multichannel: |
1966 | vol->multichannel = true; | |
1ee0e6d4 SF |
1967 | /* if number of channels not specified, default to 2 */ |
1968 | if (vol->max_channels < 2) | |
1969 | vol->max_channels = 2; | |
bcc88801 AA |
1970 | break; |
1971 | case Opt_nomultichannel: | |
1972 | vol->multichannel = false; | |
1ee0e6d4 | 1973 | vol->max_channels = 1; |
bcc88801 | 1974 | break; |
9fe5ff1c SF |
1975 | case Opt_compress: |
1976 | vol->compression = UNKNOWN_TYPE; | |
1977 | cifs_dbg(VFS, | |
1978 | "SMB3 compression support is experimental\n"); | |
1979 | break; | |
8830d7e0 SP |
1980 | |
1981 | /* Numeric Values */ | |
1982 | case Opt_backupuid: | |
3da46565 | 1983 | if (get_option_uid(args, &vol->backupuid)) { |
f96637be JP |
1984 | cifs_dbg(VFS, "%s: Invalid backupuid value\n", |
1985 | __func__); | |
3d3ea8e6 SP |
1986 | goto cifs_parse_mount_err; |
1987 | } | |
1988 | vol->backupuid_specified = true; | |
8830d7e0 SP |
1989 | break; |
1990 | case Opt_backupgid: | |
3da46565 | 1991 | if (get_option_gid(args, &vol->backupgid)) { |
f96637be JP |
1992 | cifs_dbg(VFS, "%s: Invalid backupgid value\n", |
1993 | __func__); | |
3d3ea8e6 SP |
1994 | goto cifs_parse_mount_err; |
1995 | } | |
1996 | vol->backupgid_specified = true; | |
8830d7e0 SP |
1997 | break; |
1998 | case Opt_uid: | |
3da46565 | 1999 | if (get_option_uid(args, &vol->linux_uid)) { |
f96637be JP |
2000 | cifs_dbg(VFS, "%s: Invalid uid value\n", |
2001 | __func__); | |
8830d7e0 SP |
2002 | goto cifs_parse_mount_err; |
2003 | } | |
8830d7e0 SP |
2004 | uid_specified = true; |
2005 | break; | |
2006 | case Opt_cruid: | |
3da46565 | 2007 | if (get_option_uid(args, &vol->cred_uid)) { |
f96637be JP |
2008 | cifs_dbg(VFS, "%s: Invalid cruid value\n", |
2009 | __func__); | |
8830d7e0 SP |
2010 | goto cifs_parse_mount_err; |
2011 | } | |
8830d7e0 SP |
2012 | break; |
2013 | case Opt_gid: | |
3da46565 | 2014 | if (get_option_gid(args, &vol->linux_gid)) { |
f96637be JP |
2015 | cifs_dbg(VFS, "%s: Invalid gid value\n", |
2016 | __func__); | |
8830d7e0 SP |
2017 | goto cifs_parse_mount_err; |
2018 | } | |
8830d7e0 SP |
2019 | gid_specified = true; |
2020 | break; | |
2021 | case Opt_file_mode: | |
2022 | if (get_option_ul(args, &option)) { | |
f96637be JP |
2023 | cifs_dbg(VFS, "%s: Invalid file_mode value\n", |
2024 | __func__); | |
8830d7e0 SP |
2025 | goto cifs_parse_mount_err; |
2026 | } | |
2027 | vol->file_mode = option; | |
2028 | break; | |
2029 | case Opt_dirmode: | |
2030 | if (get_option_ul(args, &option)) { | |
f96637be JP |
2031 | cifs_dbg(VFS, "%s: Invalid dir_mode value\n", |
2032 | __func__); | |
8830d7e0 SP |
2033 | goto cifs_parse_mount_err; |
2034 | } | |
2035 | vol->dir_mode = option; | |
2036 | break; | |
2037 | case Opt_port: | |
b979aaa1 JL |
2038 | if (get_option_ul(args, &option) || |
2039 | option > USHRT_MAX) { | |
f96637be JP |
2040 | cifs_dbg(VFS, "%s: Invalid port value\n", |
2041 | __func__); | |
8830d7e0 SP |
2042 | goto cifs_parse_mount_err; |
2043 | } | |
b979aaa1 | 2044 | port = (unsigned short)option; |
8830d7e0 | 2045 | break; |
563317ec SF |
2046 | case Opt_min_enc_offload: |
2047 | if (get_option_ul(args, &option)) { | |
2048 | cifs_dbg(VFS, "Invalid minimum encrypted read offload size (esize)\n"); | |
2049 | goto cifs_parse_mount_err; | |
2050 | } | |
2051 | vol->min_offload = option; | |
2052 | break; | |
e8506d25 SF |
2053 | case Opt_blocksize: |
2054 | if (get_option_ul(args, &option)) { | |
2055 | cifs_dbg(VFS, "%s: Invalid blocksize value\n", | |
2056 | __func__); | |
2057 | goto cifs_parse_mount_err; | |
2058 | } | |
2059 | /* | |
2060 | * inode blocksize realistically should never need to be | |
2061 | * less than 16K or greater than 16M and default is 1MB. | |
2062 | * Note that small inode block sizes (e.g. 64K) can lead | |
2063 | * to very poor performance of common tools like cp and scp | |
2064 | */ | |
2065 | if ((option < CIFS_MAX_MSGSIZE) || | |
2066 | (option > (4 * SMB3_DEFAULT_IOSIZE))) { | |
2067 | cifs_dbg(VFS, "%s: Invalid blocksize\n", | |
2068 | __func__); | |
2069 | goto cifs_parse_mount_err; | |
2070 | } | |
2071 | vol->bsize = option; | |
2072 | break; | |
8830d7e0 SP |
2073 | case Opt_rsize: |
2074 | if (get_option_ul(args, &option)) { | |
f96637be JP |
2075 | cifs_dbg(VFS, "%s: Invalid rsize value\n", |
2076 | __func__); | |
b946845a | 2077 | goto cifs_parse_mount_err; |
8830d7e0 SP |
2078 | } |
2079 | vol->rsize = option; | |
2080 | break; | |
2081 | case Opt_wsize: | |
2082 | if (get_option_ul(args, &option)) { | |
f96637be JP |
2083 | cifs_dbg(VFS, "%s: Invalid wsize value\n", |
2084 | __func__); | |
8830d7e0 SP |
2085 | goto cifs_parse_mount_err; |
2086 | } | |
2087 | vol->wsize = option; | |
2088 | break; | |
2089 | case Opt_actimeo: | |
2090 | if (get_option_ul(args, &option)) { | |
f96637be JP |
2091 | cifs_dbg(VFS, "%s: Invalid actimeo value\n", |
2092 | __func__); | |
8830d7e0 SP |
2093 | goto cifs_parse_mount_err; |
2094 | } | |
2095 | vol->actimeo = HZ * option; | |
2096 | if (vol->actimeo > CIFS_MAX_ACTIMEO) { | |
f96637be | 2097 | cifs_dbg(VFS, "attribute cache timeout too large\n"); |
8830d7e0 SP |
2098 | goto cifs_parse_mount_err; |
2099 | } | |
2100 | break; | |
ca567eb2 SF |
2101 | case Opt_handletimeout: |
2102 | if (get_option_ul(args, &option)) { | |
2103 | cifs_dbg(VFS, "%s: Invalid handletimeout value\n", | |
2104 | __func__); | |
2105 | goto cifs_parse_mount_err; | |
2106 | } | |
2107 | vol->handle_timeout = option; | |
2108 | if (vol->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) { | |
2109 | cifs_dbg(VFS, "Invalid handle cache timeout, longer than 16 minutes\n"); | |
2110 | goto cifs_parse_mount_err; | |
2111 | } | |
2112 | break; | |
adfeb3e0 SF |
2113 | case Opt_echo_interval: |
2114 | if (get_option_ul(args, &option)) { | |
2115 | cifs_dbg(VFS, "%s: Invalid echo interval value\n", | |
2116 | __func__); | |
2117 | goto cifs_parse_mount_err; | |
2118 | } | |
2119 | vol->echo_interval = option; | |
2120 | break; | |
8b217fe7 SF |
2121 | case Opt_snapshot: |
2122 | if (get_option_ul(args, &option)) { | |
2123 | cifs_dbg(VFS, "%s: Invalid snapshot time\n", | |
2124 | __func__); | |
2125 | goto cifs_parse_mount_err; | |
2126 | } | |
2127 | vol->snapshot_time = option; | |
2128 | break; | |
141891f4 SF |
2129 | case Opt_max_credits: |
2130 | if (get_option_ul(args, &option) || (option < 20) || | |
2131 | (option > 60000)) { | |
2132 | cifs_dbg(VFS, "%s: Invalid max_credits value\n", | |
2133 | __func__); | |
2134 | goto cifs_parse_mount_err; | |
2135 | } | |
2136 | vol->max_credits = option; | |
2137 | break; | |
bcc88801 AA |
2138 | case Opt_max_channels: |
2139 | if (get_option_ul(args, &option) || option < 1 || | |
2140 | option > CIFS_MAX_CHANNELS) { | |
2141 | cifs_dbg(VFS, "%s: Invalid max_channels value, needs to be 1-%d\n", | |
2142 | __func__, CIFS_MAX_CHANNELS); | |
2143 | goto cifs_parse_mount_err; | |
2144 | } | |
2145 | vol->max_channels = option; | |
2146 | break; | |
8830d7e0 SP |
2147 | |
2148 | /* String Arguments */ | |
2149 | ||
4fe9e963 SP |
2150 | case Opt_blank_user: |
2151 | /* null user, ie. anonymous authentication */ | |
2152 | vol->nullauth = 1; | |
2153 | vol->username = NULL; | |
2154 | break; | |
8830d7e0 SP |
2155 | case Opt_user: |
2156 | string = match_strdup(args); | |
2157 | if (string == NULL) | |
2158 | goto out_nomem; | |
2159 | ||
8c3a2b4c SL |
2160 | if (strnlen(string, CIFS_MAX_USERNAME_LEN) > |
2161 | CIFS_MAX_USERNAME_LEN) { | |
a0a3036b | 2162 | pr_warn("username too long\n"); |
8830d7e0 SP |
2163 | goto cifs_parse_mount_err; |
2164 | } | |
2bd50fb3 TK |
2165 | |
2166 | kfree(vol->username); | |
8830d7e0 | 2167 | vol->username = kstrdup(string, GFP_KERNEL); |
f96637be | 2168 | if (!vol->username) |
8830d7e0 | 2169 | goto cifs_parse_mount_err; |
8830d7e0 SP |
2170 | break; |
2171 | case Opt_blank_pass: | |
8830d7e0 SP |
2172 | /* passwords have to be handled differently |
2173 | * to allow the character used for deliminator | |
2174 | * to be passed within them | |
2175 | */ | |
2176 | ||
c369c9a4 SP |
2177 | /* |
2178 | * Check if this is a case where the password | |
2179 | * starts with a delimiter | |
2180 | */ | |
2181 | tmp_end = strchr(data, '='); | |
2182 | tmp_end++; | |
2183 | if (!(tmp_end < end && tmp_end[1] == delim)) { | |
2184 | /* No it is not. Set the password to NULL */ | |
453431a5 | 2185 | kfree_sensitive(vol->password); |
c369c9a4 SP |
2186 | vol->password = NULL; |
2187 | break; | |
2188 | } | |
07fa6010 | 2189 | /* Fallthrough - to Opt_pass below.*/ |
c369c9a4 | 2190 | case Opt_pass: |
8830d7e0 SP |
2191 | /* Obtain the value string */ |
2192 | value = strchr(data, '='); | |
10238074 | 2193 | value++; |
8830d7e0 SP |
2194 | |
2195 | /* Set tmp_end to end of the string */ | |
2196 | tmp_end = (char *) value + strlen(value); | |
2197 | ||
2198 | /* Check if following character is the deliminator | |
2199 | * If yes, we have encountered a double deliminator | |
2200 | * reset the NULL character to the deliminator | |
2201 | */ | |
e73f843a | 2202 | if (tmp_end < end && tmp_end[1] == delim) { |
8830d7e0 SP |
2203 | tmp_end[0] = delim; |
2204 | ||
e73f843a SJ |
2205 | /* Keep iterating until we get to a single |
2206 | * deliminator OR the end | |
2207 | */ | |
2208 | while ((tmp_end = strchr(tmp_end, delim)) | |
2209 | != NULL && (tmp_end[1] == delim)) { | |
2210 | tmp_end = (char *) &tmp_end[2]; | |
2211 | } | |
2212 | ||
2213 | /* Reset var options to point to next element */ | |
2214 | if (tmp_end) { | |
2215 | tmp_end[0] = '\0'; | |
2216 | options = (char *) &tmp_end[1]; | |
2217 | } else | |
2218 | /* Reached the end of the mount option | |
2219 | * string */ | |
2220 | options = end; | |
8830d7e0 SP |
2221 | } |
2222 | ||
453431a5 | 2223 | kfree_sensitive(vol->password); |
8830d7e0 SP |
2224 | /* Now build new password string */ |
2225 | temp_len = strlen(value); | |
2226 | vol->password = kzalloc(temp_len+1, GFP_KERNEL); | |
2227 | if (vol->password == NULL) { | |
a0a3036b | 2228 | pr_warn("no memory for password\n"); |
8830d7e0 SP |
2229 | goto cifs_parse_mount_err; |
2230 | } | |
2231 | ||
2232 | for (i = 0, j = 0; i < temp_len; i++, j++) { | |
2233 | vol->password[j] = value[i]; | |
2234 | if ((value[i] == delim) && | |
2235 | value[i+1] == delim) | |
2236 | /* skip the second deliminator */ | |
2237 | i++; | |
2238 | } | |
2239 | vol->password[j] = '\0'; | |
2240 | break; | |
4fe9e963 | 2241 | case Opt_blank_ip: |
b979aaa1 JL |
2242 | /* FIXME: should this be an error instead? */ |
2243 | got_ip = false; | |
4fe9e963 | 2244 | break; |
8830d7e0 SP |
2245 | case Opt_ip: |
2246 | string = match_strdup(args); | |
2247 | if (string == NULL) | |
2248 | goto out_nomem; | |
2249 | ||
b979aaa1 JL |
2250 | if (!cifs_convert_address(dstaddr, string, |
2251 | strlen(string))) { | |
a0a3036b | 2252 | pr_err("bad ip= option (%s)\n", string); |
8830d7e0 SP |
2253 | goto cifs_parse_mount_err; |
2254 | } | |
b979aaa1 | 2255 | got_ip = true; |
8830d7e0 | 2256 | break; |
8830d7e0 SP |
2257 | case Opt_domain: |
2258 | string = match_strdup(args); | |
2259 | if (string == NULL) | |
2260 | goto out_nomem; | |
2261 | ||
057d6332 CG |
2262 | if (strnlen(string, CIFS_MAX_DOMAINNAME_LEN) |
2263 | == CIFS_MAX_DOMAINNAME_LEN) { | |
a0a3036b | 2264 | pr_warn("domain name too long\n"); |
8830d7e0 SP |
2265 | goto cifs_parse_mount_err; |
2266 | } | |
2267 | ||
2bd50fb3 | 2268 | kfree(vol->domainname); |
8830d7e0 SP |
2269 | vol->domainname = kstrdup(string, GFP_KERNEL); |
2270 | if (!vol->domainname) { | |
a0a3036b | 2271 | pr_warn("no memory for domainname\n"); |
8830d7e0 SP |
2272 | goto cifs_parse_mount_err; |
2273 | } | |
f96637be | 2274 | cifs_dbg(FYI, "Domain name set\n"); |
8830d7e0 SP |
2275 | break; |
2276 | case Opt_srcaddr: | |
2277 | string = match_strdup(args); | |
2278 | if (string == NULL) | |
2279 | goto out_nomem; | |
2280 | ||
4fe9e963 | 2281 | if (!cifs_convert_address( |
8830d7e0 SP |
2282 | (struct sockaddr *)&vol->srcaddr, |
2283 | string, strlen(string))) { | |
a0a3036b | 2284 | pr_warn("Could not parse srcaddr: %s\n", |
0b456f04 | 2285 | string); |
8830d7e0 SP |
2286 | goto cifs_parse_mount_err; |
2287 | } | |
2288 | break; | |
8830d7e0 SP |
2289 | case Opt_iocharset: |
2290 | string = match_strdup(args); | |
2291 | if (string == NULL) | |
2292 | goto out_nomem; | |
2293 | ||
4fe9e963 | 2294 | if (strnlen(string, 1024) >= 65) { |
a0a3036b | 2295 | pr_warn("iocharset name too long\n"); |
8830d7e0 SP |
2296 | goto cifs_parse_mount_err; |
2297 | } | |
2298 | ||
87e747cd | 2299 | if (strncasecmp(string, "default", 7) != 0) { |
2bd50fb3 | 2300 | kfree(vol->iocharset); |
8830d7e0 SP |
2301 | vol->iocharset = kstrdup(string, |
2302 | GFP_KERNEL); | |
2303 | if (!vol->iocharset) { | |
a0a3036b | 2304 | pr_warn("no memory for charset\n"); |
8830d7e0 SP |
2305 | goto cifs_parse_mount_err; |
2306 | } | |
2307 | } | |
2308 | /* if iocharset not set then load_nls_default | |
2309 | * is used by caller | |
2310 | */ | |
f96637be | 2311 | cifs_dbg(FYI, "iocharset set to %s\n", string); |
8830d7e0 | 2312 | break; |
8830d7e0 SP |
2313 | case Opt_netbiosname: |
2314 | string = match_strdup(args); | |
2315 | if (string == NULL) | |
2316 | goto out_nomem; | |
2317 | ||
8830d7e0 SP |
2318 | memset(vol->source_rfc1001_name, 0x20, |
2319 | RFC1001_NAME_LEN); | |
2320 | /* | |
2321 | * FIXME: are there cases in which a comma can | |
2322 | * be valid in workstation netbios name (and | |
2323 | * need special handling)? | |
2324 | */ | |
2325 | for (i = 0; i < RFC1001_NAME_LEN; i++) { | |
2326 | /* don't ucase netbiosname for user */ | |
2327 | if (string[i] == 0) | |
2328 | break; | |
2329 | vol->source_rfc1001_name[i] = string[i]; | |
2330 | } | |
2331 | /* The string has 16th byte zero still from | |
2332 | * set at top of the function | |
2333 | */ | |
2334 | if (i == RFC1001_NAME_LEN && string[i] != 0) | |
a0a3036b | 2335 | pr_warn("netbiosname longer than 15 truncated\n"); |
8830d7e0 SP |
2336 | break; |
2337 | case Opt_servern: | |
2338 | /* servernetbiosname specified override *SMBSERVER */ | |
2339 | string = match_strdup(args); | |
2340 | if (string == NULL) | |
2341 | goto out_nomem; | |
2342 | ||
8830d7e0 SP |
2343 | /* last byte, type, is 0x20 for servr type */ |
2344 | memset(vol->target_rfc1001_name, 0x20, | |
2345 | RFC1001_NAME_LEN_WITH_NULL); | |
2346 | ||
2347 | /* BB are there cases in which a comma can be | |
2348 | valid in this workstation netbios name | |
2349 | (and need special handling)? */ | |
2350 | ||
2351 | /* user or mount helper must uppercase the | |
2352 | netbios name */ | |
2353 | for (i = 0; i < 15; i++) { | |
2354 | if (string[i] == 0) | |
2355 | break; | |
2356 | vol->target_rfc1001_name[i] = string[i]; | |
2357 | } | |
2358 | /* The string has 16th byte zero still from | |
2359 | set at top of the function */ | |
2360 | if (i == RFC1001_NAME_LEN && string[i] != 0) | |
a0a3036b | 2361 | pr_warn("server netbiosname longer than 15 truncated\n"); |
8830d7e0 SP |
2362 | break; |
2363 | case Opt_ver: | |
7e682f76 | 2364 | /* version of mount userspace tools, not dialect */ |
8830d7e0 SP |
2365 | string = match_strdup(args); |
2366 | if (string == NULL) | |
2367 | goto out_nomem; | |
2368 | ||
7e682f76 | 2369 | /* If interface changes in mount.cifs bump to new ver */ |
87e747cd | 2370 | if (strncasecmp(string, "1", 1) == 0) { |
7e682f76 | 2371 | if (strlen(string) > 1) { |
a0a3036b JP |
2372 | pr_warn("Bad mount helper ver=%s. Did you want SMB1 (CIFS) dialect and mean to type vers=1.0 instead?\n", |
2373 | string); | |
7e682f76 SF |
2374 | goto cifs_parse_mount_err; |
2375 | } | |
8830d7e0 SP |
2376 | /* This is the default */ |
2377 | break; | |
2378 | } | |
2379 | /* For all other value, error */ | |
a0a3036b | 2380 | pr_warn("Invalid mount helper version specified\n"); |
b946845a | 2381 | goto cifs_parse_mount_err; |
23db65f5 | 2382 | case Opt_vers: |
7e682f76 | 2383 | /* protocol version (dialect) */ |
23db65f5 JL |
2384 | string = match_strdup(args); |
2385 | if (string == NULL) | |
2386 | goto out_nomem; | |
2387 | ||
c7c137b9 | 2388 | if (cifs_parse_smb_version(string, vol, is_smb3) != 0) |
23db65f5 | 2389 | goto cifs_parse_mount_err; |
7e682f76 | 2390 | got_version = true; |
23db65f5 | 2391 | break; |
8830d7e0 SP |
2392 | case Opt_sec: |
2393 | string = match_strdup(args); | |
2394 | if (string == NULL) | |
2395 | goto out_nomem; | |
2396 | ||
8830d7e0 SP |
2397 | if (cifs_parse_security_flavors(string, vol) != 0) |
2398 | goto cifs_parse_mount_err; | |
2399 | break; | |
15b6a473 JL |
2400 | case Opt_cache: |
2401 | string = match_strdup(args); | |
2402 | if (string == NULL) | |
2403 | goto out_nomem; | |
2404 | ||
2405 | if (cifs_parse_cache_flavor(string, vol) != 0) | |
2406 | goto cifs_parse_mount_err; | |
2407 | break; | |
8830d7e0 | 2408 | default: |
d8162558 JL |
2409 | /* |
2410 | * An option we don't recognize. Save it off for later | |
2411 | * if we haven't already found one | |
2412 | */ | |
2413 | if (!invalid) | |
2414 | invalid = data; | |
8830d7e0 | 2415 | break; |
1da177e4 | 2416 | } |
8830d7e0 SP |
2417 | /* Free up any allocated string */ |
2418 | kfree(string); | |
2419 | string = NULL; | |
1da177e4 | 2420 | } |
0eb8a132 | 2421 | |
d8162558 | 2422 | if (!sloppy && invalid) { |
a0a3036b | 2423 | pr_err("Unknown mount option \"%s\"\n", invalid); |
d8162558 JL |
2424 | goto cifs_parse_mount_err; |
2425 | } | |
2426 | ||
8339dd32 LL |
2427 | if (vol->rdma && vol->vals->protocol_id < SMB30_PROT_ID) { |
2428 | cifs_dbg(VFS, "SMB Direct requires Version >=3.0\n"); | |
2429 | goto cifs_parse_mount_err; | |
2430 | } | |
2431 | ||
8a8798a5 JL |
2432 | #ifndef CONFIG_KEYS |
2433 | /* Muliuser mounts require CONFIG_KEYS support */ | |
2434 | if (vol->multiuser) { | |
f96637be | 2435 | cifs_dbg(VFS, "Multiuser mounts require kernels with CONFIG_KEYS enabled\n"); |
b946845a | 2436 | goto cifs_parse_mount_err; |
0eb8a132 | 2437 | } |
8a8798a5 | 2438 | #endif |
e5e69abd | 2439 | if (!vol->UNC) { |
37d4f99b | 2440 | cifs_dbg(VFS, "CIFS mount error: No usable UNC path provided in device string!\n"); |
e5e69abd JL |
2441 | goto cifs_parse_mount_err; |
2442 | } | |
0eb8a132 | 2443 | |
62a1a439 JL |
2444 | /* make sure UNC has a share name */ |
2445 | if (!strchr(vol->UNC + 3, '\\')) { | |
f96637be | 2446 | cifs_dbg(VFS, "Malformed UNC. Unable to find share name.\n"); |
62a1a439 JL |
2447 | goto cifs_parse_mount_err; |
2448 | } | |
2449 | ||
b979aaa1 | 2450 | if (!got_ip) { |
29bb3158 DP |
2451 | int len; |
2452 | const char *slash; | |
2453 | ||
b979aaa1 | 2454 | /* No ip= option specified? Try to get it from UNC */ |
29bb3158 DP |
2455 | /* Use the address part of the UNC. */ |
2456 | slash = strchr(&vol->UNC[2], '\\'); | |
2457 | len = slash - &vol->UNC[2]; | |
2458 | if (!cifs_convert_address(dstaddr, &vol->UNC[2], len)) { | |
a0a3036b | 2459 | pr_err("Unable to determine destination address\n"); |
b979aaa1 JL |
2460 | goto cifs_parse_mount_err; |
2461 | } | |
2462 | } | |
2463 | ||
2464 | /* set the port that we got earlier */ | |
2465 | cifs_set_port(dstaddr, port); | |
1da177e4 | 2466 | |
9b9d6b24 JL |
2467 | if (uid_specified) |
2468 | vol->override_uid = override_uid; | |
2469 | else if (override_uid == 1) | |
a0a3036b | 2470 | pr_notice("ignoring forceuid mount option specified with no uid= option\n"); |
9b9d6b24 JL |
2471 | |
2472 | if (gid_specified) | |
2473 | vol->override_gid = override_gid; | |
2474 | else if (override_gid == 1) | |
a0a3036b | 2475 | pr_notice("ignoring forcegid mount option specified with no gid= option\n"); |
9b9d6b24 | 2476 | |
7e682f76 | 2477 | if (got_version == false) |
a0a3036b | 2478 | pr_warn_once("No dialect specified on mount. Default has changed to a more secure dialect, SMB2.1 or later (e.g. SMB3.1.1), from CIFS (SMB1). To use the less secure SMB1 dialect to access old servers which do not support SMB3.1.1 (or even SMB3 or SMB2.1) specify vers=1.0 on mount.\n"); |
7e682f76 | 2479 | |
b946845a | 2480 | kfree(mountdata_copy); |
1da177e4 | 2481 | return 0; |
b946845a | 2482 | |
8830d7e0 | 2483 | out_nomem: |
0b456f04 | 2484 | pr_warn("Could not allocate temporary buffer\n"); |
b946845a | 2485 | cifs_parse_mount_err: |
8830d7e0 | 2486 | kfree(string); |
b946845a SF |
2487 | kfree(mountdata_copy); |
2488 | return 1; | |
1da177e4 LT |
2489 | } |
2490 | ||
3eb9a889 BG |
2491 | /** Returns true if srcaddr isn't specified and rhs isn't |
2492 | * specified, or if srcaddr is specified and | |
2493 | * matches the IP address of the rhs argument. | |
2494 | */ | |
e4af35fa PA |
2495 | bool |
2496 | cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs) | |
3eb9a889 BG |
2497 | { |
2498 | switch (srcaddr->sa_family) { | |
2499 | case AF_UNSPEC: | |
2500 | return (rhs->sa_family == AF_UNSPEC); | |
2501 | case AF_INET: { | |
2502 | struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr; | |
2503 | struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs; | |
2504 | return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr); | |
2505 | } | |
2506 | case AF_INET6: { | |
2507 | struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr; | |
e3e2775c | 2508 | struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs; |
3eb9a889 BG |
2509 | return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr); |
2510 | } | |
2511 | default: | |
2512 | WARN_ON(1); | |
2513 | return false; /* don't expect to be here */ | |
2514 | } | |
2515 | } | |
2516 | ||
4b886136 PS |
2517 | /* |
2518 | * If no port is specified in addr structure, we try to match with 445 port | |
2519 | * and if it fails - with 139 ports. It should be called only if address | |
2520 | * families of server and addr are equal. | |
2521 | */ | |
2522 | static bool | |
2523 | match_port(struct TCP_Server_Info *server, struct sockaddr *addr) | |
2524 | { | |
6da97910 | 2525 | __be16 port, *sport; |
4b886136 | 2526 | |
3b249115 LL |
2527 | /* SMBDirect manages its own ports, don't match it here */ |
2528 | if (server->rdma) | |
2529 | return true; | |
2530 | ||
4b886136 PS |
2531 | switch (addr->sa_family) { |
2532 | case AF_INET: | |
2533 | sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port; | |
2534 | port = ((struct sockaddr_in *) addr)->sin_port; | |
2535 | break; | |
2536 | case AF_INET6: | |
2537 | sport = &((struct sockaddr_in6 *) &server->dstaddr)->sin6_port; | |
2538 | port = ((struct sockaddr_in6 *) addr)->sin6_port; | |
2539 | break; | |
2540 | default: | |
2541 | WARN_ON(1); | |
2542 | return false; | |
2543 | } | |
2544 | ||
2545 | if (!port) { | |
2546 | port = htons(CIFS_PORT); | |
2547 | if (port == *sport) | |
2548 | return true; | |
2549 | ||
2550 | port = htons(RFC1001_PORT); | |
2551 | } | |
2552 | ||
2553 | return port == *sport; | |
2554 | } | |
3eb9a889 | 2555 | |
4515148e | 2556 | static bool |
3eb9a889 BG |
2557 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr, |
2558 | struct sockaddr *srcaddr) | |
4515148e | 2559 | { |
4515148e | 2560 | switch (addr->sa_family) { |
a9f1b85e PS |
2561 | case AF_INET: { |
2562 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; | |
2563 | struct sockaddr_in *srv_addr4 = | |
2564 | (struct sockaddr_in *)&server->dstaddr; | |
2565 | ||
2566 | if (addr4->sin_addr.s_addr != srv_addr4->sin_addr.s_addr) | |
4515148e | 2567 | return false; |
4515148e | 2568 | break; |
a9f1b85e PS |
2569 | } |
2570 | case AF_INET6: { | |
2571 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; | |
2572 | struct sockaddr_in6 *srv_addr6 = | |
2573 | (struct sockaddr_in6 *)&server->dstaddr; | |
2574 | ||
4515148e | 2575 | if (!ipv6_addr_equal(&addr6->sin6_addr, |
a9f1b85e | 2576 | &srv_addr6->sin6_addr)) |
4515148e | 2577 | return false; |
a9f1b85e | 2578 | if (addr6->sin6_scope_id != srv_addr6->sin6_scope_id) |
4515148e | 2579 | return false; |
4515148e JL |
2580 | break; |
2581 | } | |
a9f1b85e PS |
2582 | default: |
2583 | WARN_ON(1); | |
2584 | return false; /* don't expect to be here */ | |
2585 | } | |
4515148e | 2586 | |
e4af35fa | 2587 | if (!cifs_match_ipaddr(srcaddr, (struct sockaddr *)&server->srcaddr)) |
3eb9a889 BG |
2588 | return false; |
2589 | ||
4515148e JL |
2590 | return true; |
2591 | } | |
2592 | ||
daf5b0b6 JL |
2593 | static bool |
2594 | match_security(struct TCP_Server_Info *server, struct smb_vol *vol) | |
2595 | { | |
3f618223 JL |
2596 | /* |
2597 | * The select_sectype function should either return the vol->sectype | |
2598 | * that was specified, or "Unspecified" if that sectype was not | |
2599 | * compatible with the given NEGOTIATE request. | |
2600 | */ | |
ef65aaed SP |
2601 | if (server->ops->select_sectype(server, vol->sectype) |
2602 | == Unspecified) | |
daf5b0b6 | 2603 | return false; |
daf5b0b6 | 2604 | |
3f618223 JL |
2605 | /* |
2606 | * Now check if signing mode is acceptable. No need to check | |
2607 | * global_secflags at this point since if MUST_SIGN is set then | |
2608 | * the server->sign had better be too. | |
2609 | */ | |
38d77c50 JL |
2610 | if (vol->sign && !server->sign) |
2611 | return false; | |
daf5b0b6 JL |
2612 | |
2613 | return true; | |
2614 | } | |
2615 | ||
9fa114f7 | 2616 | static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol) |
37bb04e5 | 2617 | { |
9fa114f7 JL |
2618 | struct sockaddr *addr = (struct sockaddr *)&vol->dstaddr; |
2619 | ||
a0b3df5c JL |
2620 | if (vol->nosharesock) |
2621 | return 0; | |
2622 | ||
43cdae88 SF |
2623 | /* If multidialect negotiation see if existing sessions match one */ |
2624 | if (strcmp(vol->vals->version_string, SMB3ANY_VERSION_STRING) == 0) { | |
2625 | if (server->vals->protocol_id < SMB30_PROT_ID) | |
2626 | return 0; | |
2627 | } else if (strcmp(vol->vals->version_string, | |
2628 | SMBDEFAULT_VERSION_STRING) == 0) { | |
2629 | if (server->vals->protocol_id < SMB21_PROT_ID) | |
2630 | return 0; | |
2631 | } else if ((server->vals != vol->vals) || (server->ops != vol->ops)) | |
23db65f5 JL |
2632 | return 0; |
2633 | ||
37bb04e5 PS |
2634 | if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns)) |
2635 | return 0; | |
2636 | ||
2637 | if (!match_address(server, addr, | |
2638 | (struct sockaddr *)&vol->srcaddr)) | |
2639 | return 0; | |
2640 | ||
2641 | if (!match_port(server, addr)) | |
2642 | return 0; | |
2643 | ||
2644 | if (!match_security(server, vol)) | |
2645 | return 0; | |
2646 | ||
b782fcc1 | 2647 | if (server->echo_interval != vol->echo_interval * HZ) |
adfeb3e0 SF |
2648 | return 0; |
2649 | ||
8339dd32 LL |
2650 | if (server->rdma != vol->rdma) |
2651 | return 0; | |
2652 | ||
4f5c10f1 SF |
2653 | if (server->ignore_signature != vol->ignore_signature) |
2654 | return 0; | |
2655 | ||
563317ec SF |
2656 | if (server->min_offload != vol->min_offload) |
2657 | return 0; | |
2658 | ||
37bb04e5 PS |
2659 | return 1; |
2660 | } | |
2661 | ||
54be1f6c | 2662 | struct TCP_Server_Info * |
9fa114f7 | 2663 | cifs_find_tcp_session(struct smb_vol *vol) |
1da177e4 | 2664 | { |
e7ddee90 | 2665 | struct TCP_Server_Info *server; |
e7ddee90 | 2666 | |
3f9bcca7 | 2667 | spin_lock(&cifs_tcp_ses_lock); |
4515148e | 2668 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { |
3345bb44 PAS |
2669 | /* |
2670 | * Skip ses channels since they're only handled in lower layers | |
2671 | * (e.g. cifs_send_recv). | |
2672 | */ | |
2673 | if (server->is_channel || !match_server(server, vol)) | |
daf5b0b6 JL |
2674 | continue; |
2675 | ||
e7ddee90 | 2676 | ++server->srv_count; |
3f9bcca7 | 2677 | spin_unlock(&cifs_tcp_ses_lock); |
f96637be | 2678 | cifs_dbg(FYI, "Existing tcp session with server found\n"); |
e7ddee90 | 2679 | return server; |
1da177e4 | 2680 | } |
3f9bcca7 | 2681 | spin_unlock(&cifs_tcp_ses_lock); |
1da177e4 LT |
2682 | return NULL; |
2683 | } | |
1b20d672 | 2684 | |
53e0e11e PS |
2685 | void |
2686 | cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) | |
1da177e4 | 2687 | { |
a5c3e1c7 SF |
2688 | struct task_struct *task; |
2689 | ||
3f9bcca7 | 2690 | spin_lock(&cifs_tcp_ses_lock); |
e7ddee90 | 2691 | if (--server->srv_count > 0) { |
3f9bcca7 | 2692 | spin_unlock(&cifs_tcp_ses_lock); |
e7ddee90 | 2693 | return; |
1da177e4 | 2694 | } |
1b20d672 | 2695 | |
f1d0c998 RL |
2696 | put_net(cifs_net_ns(server)); |
2697 | ||
e7ddee90 | 2698 | list_del_init(&server->tcp_ses_list); |
3f9bcca7 | 2699 | spin_unlock(&cifs_tcp_ses_lock); |
dea570e0 | 2700 | |
c74093b6 JL |
2701 | cancel_delayed_work_sync(&server->echo); |
2702 | ||
53e0e11e PS |
2703 | if (from_reconnect) |
2704 | /* | |
2705 | * Avoid deadlock here: reconnect work calls | |
2706 | * cifs_put_tcp_session() at its end. Need to be sure | |
2707 | * that reconnect work does nothing with server pointer after | |
2708 | * that step. | |
2709 | */ | |
2710 | cancel_delayed_work(&server->reconnect); | |
2711 | else | |
2712 | cancel_delayed_work_sync(&server->reconnect); | |
53e0e11e | 2713 | |
e7ddee90 JL |
2714 | spin_lock(&GlobalMid_Lock); |
2715 | server->tcpStatus = CifsExiting; | |
2716 | spin_unlock(&GlobalMid_Lock); | |
dea570e0 | 2717 | |
026e93dc | 2718 | cifs_crypto_secmech_release(server); |
488f1d2d SJ |
2719 | cifs_fscache_release_client_cookie(server); |
2720 | ||
21e73393 SP |
2721 | kfree(server->session_key.response); |
2722 | server->session_key.response = NULL; | |
2723 | server->session_key.len = 0; | |
a5c3e1c7 SF |
2724 | |
2725 | task = xchg(&server->tsk, NULL); | |
2726 | if (task) | |
72abe3bc | 2727 | send_sig(SIGKILL, task, 1); |
1da177e4 LT |
2728 | } |
2729 | ||
d70e9fa5 | 2730 | struct TCP_Server_Info * |
63c038c2 JL |
2731 | cifs_get_tcp_session(struct smb_vol *volume_info) |
2732 | { | |
2733 | struct TCP_Server_Info *tcp_ses = NULL; | |
63c038c2 JL |
2734 | int rc; |
2735 | ||
f96637be | 2736 | cifs_dbg(FYI, "UNC: %s\n", volume_info->UNC); |
63c038c2 JL |
2737 | |
2738 | /* see if we already have a matching tcp_ses */ | |
9fa114f7 | 2739 | tcp_ses = cifs_find_tcp_session(volume_info); |
63c038c2 JL |
2740 | if (tcp_ses) |
2741 | return tcp_ses; | |
2742 | ||
2743 | tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL); | |
2744 | if (!tcp_ses) { | |
2745 | rc = -ENOMEM; | |
2746 | goto out_err; | |
2747 | } | |
2748 | ||
23db65f5 JL |
2749 | tcp_ses->ops = volume_info->ops; |
2750 | tcp_ses->vals = volume_info->vals; | |
f1d0c998 | 2751 | cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns)); |
63c038c2 JL |
2752 | tcp_ses->hostname = extract_hostname(volume_info->UNC); |
2753 | if (IS_ERR(tcp_ses->hostname)) { | |
2754 | rc = PTR_ERR(tcp_ses->hostname); | |
f7c5445a | 2755 | goto out_err_crypto_release; |
63c038c2 JL |
2756 | } |
2757 | ||
8eecd1c2 PAS |
2758 | tcp_ses->noblockcnt = volume_info->rootfs; |
2759 | tcp_ses->noblocksnd = volume_info->noblocksnd || volume_info->rootfs; | |
63c038c2 | 2760 | tcp_ses->noautotune = volume_info->noautotune; |
6a5fa236 | 2761 | tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay; |
8339dd32 | 2762 | tcp_ses->rdma = volume_info->rdma; |
fc40f9cf | 2763 | tcp_ses->in_flight = 0; |
1b63f184 | 2764 | tcp_ses->max_in_flight = 0; |
2d86dbc9 | 2765 | tcp_ses->credits = 1; |
63c038c2 JL |
2766 | init_waitqueue_head(&tcp_ses->response_q); |
2767 | init_waitqueue_head(&tcp_ses->request_q); | |
2768 | INIT_LIST_HEAD(&tcp_ses->pending_mid_q); | |
2769 | mutex_init(&tcp_ses->srv_mutex); | |
2770 | memcpy(tcp_ses->workstation_RFC1001_name, | |
2771 | volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); | |
2772 | memcpy(tcp_ses->server_RFC1001_name, | |
2773 | volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); | |
5d0d2882 | 2774 | tcp_ses->session_estab = false; |
63c038c2 | 2775 | tcp_ses->sequence_number = 0; |
5b964852 | 2776 | tcp_ses->reconnect_instance = 1; |
fda35943 | 2777 | tcp_ses->lstrp = jiffies; |
9fe5ff1c | 2778 | tcp_ses->compress_algorithm = cpu_to_le16(volume_info->compression); |
58fa015f | 2779 | spin_lock_init(&tcp_ses->req_lock); |
63c038c2 JL |
2780 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); |
2781 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); | |
c74093b6 | 2782 | INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); |
53e0e11e PS |
2783 | INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server); |
2784 | mutex_init(&tcp_ses->reconnect_mutex); | |
9fa114f7 JL |
2785 | memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, |
2786 | sizeof(tcp_ses->srcaddr)); | |
2787 | memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr, | |
2788 | sizeof(tcp_ses->dstaddr)); | |
bcc88801 AA |
2789 | if (volume_info->use_client_guid) |
2790 | memcpy(tcp_ses->client_guid, volume_info->client_guid, | |
2791 | SMB2_CLIENT_GUID_SIZE); | |
2792 | else | |
2793 | generate_random_uuid(tcp_ses->client_guid); | |
63c038c2 JL |
2794 | /* |
2795 | * at this point we are the only ones with the pointer | |
2796 | * to the struct since the kernel thread not created yet | |
2797 | * no need to spinlock this init of tcpStatus or srv_count | |
2798 | */ | |
2799 | tcp_ses->tcpStatus = CifsNew; | |
2800 | ++tcp_ses->srv_count; | |
2801 | ||
adfeb3e0 SF |
2802 | if (volume_info->echo_interval >= SMB_ECHO_INTERVAL_MIN && |
2803 | volume_info->echo_interval <= SMB_ECHO_INTERVAL_MAX) | |
2804 | tcp_ses->echo_interval = volume_info->echo_interval * HZ; | |
2805 | else | |
2806 | tcp_ses->echo_interval = SMB_ECHO_INTERVAL_DEFAULT * HZ; | |
2f894646 LL |
2807 | if (tcp_ses->rdma) { |
2808 | #ifndef CONFIG_CIFS_SMB_DIRECT | |
2809 | cifs_dbg(VFS, "CONFIG_CIFS_SMB_DIRECT is not enabled\n"); | |
2810 | rc = -ENOENT; | |
2811 | goto out_err_crypto_release; | |
2812 | #endif | |
2813 | tcp_ses->smbd_conn = smbd_get_connection( | |
2814 | tcp_ses, (struct sockaddr *)&volume_info->dstaddr); | |
2815 | if (tcp_ses->smbd_conn) { | |
2816 | cifs_dbg(VFS, "RDMA transport established\n"); | |
2817 | rc = 0; | |
2818 | goto smbd_connected; | |
2819 | } else { | |
2820 | rc = -ENOENT; | |
2821 | goto out_err_crypto_release; | |
2822 | } | |
2823 | } | |
a9f1b85e | 2824 | rc = ip_connect(tcp_ses); |
63c038c2 | 2825 | if (rc < 0) { |
f96637be | 2826 | cifs_dbg(VFS, "Error connecting to socket. Aborting operation.\n"); |
f7c5445a | 2827 | goto out_err_crypto_release; |
63c038c2 | 2828 | } |
2f894646 | 2829 | smbd_connected: |
63c038c2 JL |
2830 | /* |
2831 | * since we're in a cifs function already, we know that | |
2832 | * this will succeed. No need for try_module_get(). | |
2833 | */ | |
2834 | __module_get(THIS_MODULE); | |
7c97c200 | 2835 | tcp_ses->tsk = kthread_run(cifs_demultiplex_thread, |
63c038c2 JL |
2836 | tcp_ses, "cifsd"); |
2837 | if (IS_ERR(tcp_ses->tsk)) { | |
2838 | rc = PTR_ERR(tcp_ses->tsk); | |
f96637be | 2839 | cifs_dbg(VFS, "error %d create cifsd thread\n", rc); |
63c038c2 | 2840 | module_put(THIS_MODULE); |
f7c5445a | 2841 | goto out_err_crypto_release; |
63c038c2 | 2842 | } |
563317ec | 2843 | tcp_ses->min_offload = volume_info->min_offload; |
fd88ce93 | 2844 | tcp_ses->tcpStatus = CifsNeedNegotiate; |
63c038c2 | 2845 | |
93d5cb51 | 2846 | tcp_ses->nr_targets = 1; |
4f5c10f1 | 2847 | tcp_ses->ignore_signature = volume_info->ignore_signature; |
63c038c2 | 2848 | /* thread spawned, put it on the list */ |
3f9bcca7 | 2849 | spin_lock(&cifs_tcp_ses_lock); |
63c038c2 | 2850 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); |
3f9bcca7 | 2851 | spin_unlock(&cifs_tcp_ses_lock); |
63c038c2 | 2852 | |
488f1d2d SJ |
2853 | cifs_fscache_get_client_cookie(tcp_ses); |
2854 | ||
c74093b6 | 2855 | /* queue echo request delayed work */ |
adfeb3e0 | 2856 | queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval); |
c74093b6 | 2857 | |
63c038c2 JL |
2858 | return tcp_ses; |
2859 | ||
f7c5445a | 2860 | out_err_crypto_release: |
026e93dc | 2861 | cifs_crypto_secmech_release(tcp_ses); |
d2b91521 | 2862 | |
f1d0c998 RL |
2863 | put_net(cifs_net_ns(tcp_ses)); |
2864 | ||
63c038c2 JL |
2865 | out_err: |
2866 | if (tcp_ses) { | |
8347a5cd SF |
2867 | if (!IS_ERR(tcp_ses->hostname)) |
2868 | kfree(tcp_ses->hostname); | |
63c038c2 JL |
2869 | if (tcp_ses->ssocket) |
2870 | sock_release(tcp_ses->ssocket); | |
2871 | kfree(tcp_ses); | |
2872 | } | |
2873 | return ERR_PTR(rc); | |
2874 | } | |
2875 | ||
96daf2b0 | 2876 | static int match_session(struct cifs_ses *ses, struct smb_vol *vol) |
37bb04e5 | 2877 | { |
3f618223 JL |
2878 | if (vol->sectype != Unspecified && |
2879 | vol->sectype != ses->sectype) | |
2880 | return 0; | |
2881 | ||
bcc88801 AA |
2882 | /* |
2883 | * If an existing session is limited to less channels than | |
2884 | * requested, it should not be reused | |
2885 | */ | |
2886 | if (ses->chan_max < vol->max_channels) | |
2887 | return 0; | |
2888 | ||
3f618223 | 2889 | switch (ses->sectype) { |
37bb04e5 | 2890 | case Kerberos: |
64ed39dd | 2891 | if (!uid_eq(vol->cred_uid, ses->cred_uid)) |
37bb04e5 PS |
2892 | return 0; |
2893 | break; | |
2894 | default: | |
04febabc JL |
2895 | /* NULL username means anonymous session */ |
2896 | if (ses->user_name == NULL) { | |
2897 | if (!vol->nullauth) | |
2898 | return 0; | |
2899 | break; | |
2900 | } | |
2901 | ||
37bb04e5 | 2902 | /* anything else takes username/password */ |
04febabc JL |
2903 | if (strncmp(ses->user_name, |
2904 | vol->username ? vol->username : "", | |
8c3a2b4c | 2905 | CIFS_MAX_USERNAME_LEN)) |
37bb04e5 | 2906 | return 0; |
08b37d51 | 2907 | if ((vol->username && strlen(vol->username) != 0) && |
37bb04e5 PS |
2908 | ses->password != NULL && |
2909 | strncmp(ses->password, | |
2910 | vol->password ? vol->password : "", | |
8c3a2b4c | 2911 | CIFS_MAX_PASSWORD_LEN)) |
37bb04e5 PS |
2912 | return 0; |
2913 | } | |
2914 | return 1; | |
2915 | } | |
2916 | ||
b327a717 AA |
2917 | /** |
2918 | * cifs_setup_ipc - helper to setup the IPC tcon for the session | |
2919 | * | |
2920 | * A new IPC connection is made and stored in the session | |
2921 | * tcon_ipc. The IPC tcon has the same lifetime as the session. | |
2922 | */ | |
2923 | static int | |
2924 | cifs_setup_ipc(struct cifs_ses *ses, struct smb_vol *volume_info) | |
2925 | { | |
2926 | int rc = 0, xid; | |
2927 | struct cifs_tcon *tcon; | |
2928 | struct nls_table *nls_codepage; | |
2929 | char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0}; | |
2930 | bool seal = false; | |
afe6f653 | 2931 | struct TCP_Server_Info *server = ses->server; |
b327a717 AA |
2932 | |
2933 | /* | |
2934 | * If the mount request that resulted in the creation of the | |
2935 | * session requires encryption, force IPC to be encrypted too. | |
2936 | */ | |
2937 | if (volume_info->seal) { | |
afe6f653 | 2938 | if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) |
b327a717 AA |
2939 | seal = true; |
2940 | else { | |
afe6f653 | 2941 | cifs_server_dbg(VFS, |
b327a717 AA |
2942 | "IPC: server doesn't support encryption\n"); |
2943 | return -EOPNOTSUPP; | |
2944 | } | |
2945 | } | |
2946 | ||
2947 | tcon = tconInfoAlloc(); | |
2948 | if (tcon == NULL) | |
2949 | return -ENOMEM; | |
2950 | ||
afe6f653 | 2951 | scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname); |
b327a717 AA |
2952 | |
2953 | /* cannot fail */ | |
2954 | nls_codepage = load_nls_default(); | |
2955 | ||
2956 | xid = get_xid(); | |
2957 | tcon->ses = ses; | |
2958 | tcon->ipc = true; | |
2959 | tcon->seal = seal; | |
afe6f653 | 2960 | rc = server->ops->tree_connect(xid, ses, unc, tcon, nls_codepage); |
b327a717 AA |
2961 | free_xid(xid); |
2962 | ||
2963 | if (rc) { | |
afe6f653 | 2964 | cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc); |
b327a717 AA |
2965 | tconInfoFree(tcon); |
2966 | goto out; | |
2967 | } | |
2968 | ||
2969 | cifs_dbg(FYI, "IPC tcon rc = %d ipc tid = %d\n", rc, tcon->tid); | |
2970 | ||
2971 | ses->tcon_ipc = tcon; | |
2972 | out: | |
2973 | unload_nls(nls_codepage); | |
2974 | return rc; | |
2975 | } | |
2976 | ||
2977 | /** | |
2978 | * cifs_free_ipc - helper to release the session IPC tcon | |
2979 | * | |
2980 | * Needs to be called everytime a session is destroyed | |
2981 | */ | |
2982 | static int | |
2983 | cifs_free_ipc(struct cifs_ses *ses) | |
2984 | { | |
2985 | int rc = 0, xid; | |
2986 | struct cifs_tcon *tcon = ses->tcon_ipc; | |
2987 | ||
2988 | if (tcon == NULL) | |
2989 | return 0; | |
2990 | ||
2991 | if (ses->server->ops->tree_disconnect) { | |
2992 | xid = get_xid(); | |
2993 | rc = ses->server->ops->tree_disconnect(xid, tcon); | |
2994 | free_xid(xid); | |
2995 | } | |
2996 | ||
2997 | if (rc) | |
2998 | cifs_dbg(FYI, "failed to disconnect IPC tcon (rc=%d)\n", rc); | |
2999 | ||
3000 | tconInfoFree(tcon); | |
3001 | ses->tcon_ipc = NULL; | |
3002 | return rc; | |
3003 | } | |
3004 | ||
96daf2b0 | 3005 | static struct cifs_ses * |
4ff67b72 | 3006 | cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) |
1da177e4 | 3007 | { |
96daf2b0 | 3008 | struct cifs_ses *ses; |
dea570e0 | 3009 | |
3f9bcca7 | 3010 | spin_lock(&cifs_tcp_ses_lock); |
4ff67b72 | 3011 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
7f48558e SP |
3012 | if (ses->status == CifsExiting) |
3013 | continue; | |
37bb04e5 PS |
3014 | if (!match_session(ses, vol)) |
3015 | continue; | |
14fbf50d | 3016 | ++ses->ses_count; |
3f9bcca7 | 3017 | spin_unlock(&cifs_tcp_ses_lock); |
14fbf50d JL |
3018 | return ses; |
3019 | } | |
3f9bcca7 | 3020 | spin_unlock(&cifs_tcp_ses_lock); |
14fbf50d JL |
3021 | return NULL; |
3022 | } | |
dea570e0 | 3023 | |
5072010c | 3024 | void cifs_put_smb_ses(struct cifs_ses *ses) |
14fbf50d | 3025 | { |
7f48558e | 3026 | unsigned int rc, xid; |
14fbf50d | 3027 | struct TCP_Server_Info *server = ses->server; |
dea570e0 | 3028 | |
f96637be | 3029 | cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count); |
7f48558e | 3030 | |
3f9bcca7 | 3031 | spin_lock(&cifs_tcp_ses_lock); |
7f48558e SP |
3032 | if (ses->status == CifsExiting) { |
3033 | spin_unlock(&cifs_tcp_ses_lock); | |
3034 | return; | |
3035 | } | |
14fbf50d | 3036 | if (--ses->ses_count > 0) { |
3f9bcca7 | 3037 | spin_unlock(&cifs_tcp_ses_lock); |
14fbf50d JL |
3038 | return; |
3039 | } | |
7f48558e SP |
3040 | if (ses->status == CifsGood) |
3041 | ses->status = CifsExiting; | |
3f9bcca7 | 3042 | spin_unlock(&cifs_tcp_ses_lock); |
dea570e0 | 3043 | |
b327a717 AA |
3044 | cifs_free_ipc(ses); |
3045 | ||
7f48558e | 3046 | if (ses->status == CifsExiting && server->ops->logoff) { |
6d5786a3 | 3047 | xid = get_xid(); |
7f48558e SP |
3048 | rc = server->ops->logoff(xid, ses); |
3049 | if (rc) | |
afe6f653 | 3050 | cifs_server_dbg(VFS, "%s: Session Logoff failure rc=%d\n", |
7f48558e | 3051 | __func__, rc); |
6d5786a3 | 3052 | _free_xid(xid); |
14fbf50d | 3053 | } |
7f48558e SP |
3054 | |
3055 | spin_lock(&cifs_tcp_ses_lock); | |
3056 | list_del_init(&ses->smb_ses_list); | |
3057 | spin_unlock(&cifs_tcp_ses_lock); | |
3058 | ||
d70e9fa5 AA |
3059 | /* close any extra channels */ |
3060 | if (ses->chan_count > 1) { | |
3061 | int i; | |
3062 | ||
3063 | for (i = 1; i < ses->chan_count; i++) | |
3064 | cifs_put_tcp_session(ses->chans[i].server, 0); | |
3065 | } | |
3066 | ||
14fbf50d | 3067 | sesInfoFree(ses); |
53e0e11e | 3068 | cifs_put_tcp_session(server, 0); |
14fbf50d | 3069 | } |
dea570e0 | 3070 | |
8a8798a5 JL |
3071 | #ifdef CONFIG_KEYS |
3072 | ||
057d6332 CG |
3073 | /* strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1 */ |
3074 | #define CIFSCREDS_DESC_SIZE (7 + CIFS_MAX_DOMAINNAME_LEN + 1) | |
8a8798a5 JL |
3075 | |
3076 | /* Populate username and pw fields from keyring if possible */ | |
3077 | static int | |
3078 | cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses) | |
3079 | { | |
3080 | int rc = 0; | |
f2aee329 | 3081 | int is_domain = 0; |
146aa8b1 DH |
3082 | const char *delim, *payload; |
3083 | char *desc; | |
8a8798a5 JL |
3084 | ssize_t len; |
3085 | struct key *key; | |
3086 | struct TCP_Server_Info *server = ses->server; | |
3087 | struct sockaddr_in *sa; | |
3088 | struct sockaddr_in6 *sa6; | |
146aa8b1 | 3089 | const struct user_key_payload *upayload; |
8a8798a5 JL |
3090 | |
3091 | desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL); | |
3092 | if (!desc) | |
3093 | return -ENOMEM; | |
3094 | ||
3095 | /* try to find an address key first */ | |
3096 | switch (server->dstaddr.ss_family) { | |
3097 | case AF_INET: | |
3098 | sa = (struct sockaddr_in *)&server->dstaddr; | |
3099 | sprintf(desc, "cifs:a:%pI4", &sa->sin_addr.s_addr); | |
3100 | break; | |
3101 | case AF_INET6: | |
3102 | sa6 = (struct sockaddr_in6 *)&server->dstaddr; | |
3103 | sprintf(desc, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr); | |
3104 | break; | |
3105 | default: | |
f96637be JP |
3106 | cifs_dbg(FYI, "Bad ss_family (%hu)\n", |
3107 | server->dstaddr.ss_family); | |
8a8798a5 JL |
3108 | rc = -EINVAL; |
3109 | goto out_err; | |
3110 | } | |
3111 | ||
f96637be | 3112 | cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc); |
028db3e2 | 3113 | key = request_key(&key_type_logon, desc, ""); |
8a8798a5 JL |
3114 | if (IS_ERR(key)) { |
3115 | if (!ses->domainName) { | |
f96637be | 3116 | cifs_dbg(FYI, "domainName is NULL\n"); |
8a8798a5 JL |
3117 | rc = PTR_ERR(key); |
3118 | goto out_err; | |
3119 | } | |
3120 | ||
3121 | /* didn't work, try to find a domain key */ | |
3122 | sprintf(desc, "cifs:d:%s", ses->domainName); | |
f96637be | 3123 | cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc); |
028db3e2 | 3124 | key = request_key(&key_type_logon, desc, ""); |
8a8798a5 JL |
3125 | if (IS_ERR(key)) { |
3126 | rc = PTR_ERR(key); | |
3127 | goto out_err; | |
3128 | } | |
f2aee329 | 3129 | is_domain = 1; |
8a8798a5 JL |
3130 | } |
3131 | ||
3132 | down_read(&key->sem); | |
0837e49a | 3133 | upayload = user_key_payload_locked(key); |
8a8798a5 | 3134 | if (IS_ERR_OR_NULL(upayload)) { |
4edc53c1 | 3135 | rc = upayload ? PTR_ERR(upayload) : -EINVAL; |
8a8798a5 JL |
3136 | goto out_key_put; |
3137 | } | |
3138 | ||
3139 | /* find first : in payload */ | |
146aa8b1 | 3140 | payload = upayload->data; |
8a8798a5 | 3141 | delim = strnchr(payload, upayload->datalen, ':'); |
f96637be | 3142 | cifs_dbg(FYI, "payload=%s\n", payload); |
8a8798a5 | 3143 | if (!delim) { |
f96637be JP |
3144 | cifs_dbg(FYI, "Unable to find ':' in payload (datalen=%d)\n", |
3145 | upayload->datalen); | |
8a8798a5 JL |
3146 | rc = -EINVAL; |
3147 | goto out_key_put; | |
3148 | } | |
3149 | ||
3150 | len = delim - payload; | |
8c3a2b4c | 3151 | if (len > CIFS_MAX_USERNAME_LEN || len <= 0) { |
f96637be JP |
3152 | cifs_dbg(FYI, "Bad value from username search (len=%zd)\n", |
3153 | len); | |
8a8798a5 JL |
3154 | rc = -EINVAL; |
3155 | goto out_key_put; | |
3156 | } | |
3157 | ||
3158 | vol->username = kstrndup(payload, len, GFP_KERNEL); | |
3159 | if (!vol->username) { | |
f96637be JP |
3160 | cifs_dbg(FYI, "Unable to allocate %zd bytes for username\n", |
3161 | len); | |
8a8798a5 JL |
3162 | rc = -ENOMEM; |
3163 | goto out_key_put; | |
3164 | } | |
f96637be | 3165 | cifs_dbg(FYI, "%s: username=%s\n", __func__, vol->username); |
8a8798a5 JL |
3166 | |
3167 | len = key->datalen - (len + 1); | |
8c3a2b4c | 3168 | if (len > CIFS_MAX_PASSWORD_LEN || len <= 0) { |
f96637be | 3169 | cifs_dbg(FYI, "Bad len for password search (len=%zd)\n", len); |
8a8798a5 JL |
3170 | rc = -EINVAL; |
3171 | kfree(vol->username); | |
3172 | vol->username = NULL; | |
3173 | goto out_key_put; | |
3174 | } | |
3175 | ||
3176 | ++delim; | |
3177 | vol->password = kstrndup(delim, len, GFP_KERNEL); | |
3178 | if (!vol->password) { | |
f96637be JP |
3179 | cifs_dbg(FYI, "Unable to allocate %zd bytes for password\n", |
3180 | len); | |
8a8798a5 JL |
3181 | rc = -ENOMEM; |
3182 | kfree(vol->username); | |
3183 | vol->username = NULL; | |
3184 | goto out_key_put; | |
3185 | } | |
3186 | ||
f2aee329 RS |
3187 | /* |
3188 | * If we have a domain key then we must set the domainName in the | |
3189 | * for the request. | |
3190 | */ | |
3191 | if (is_domain && ses->domainName) { | |
3192 | vol->domainname = kstrndup(ses->domainName, | |
3193 | strlen(ses->domainName), | |
3194 | GFP_KERNEL); | |
3195 | if (!vol->domainname) { | |
a0a3036b JP |
3196 | cifs_dbg(FYI, "Unable to allocate %zd bytes for domain\n", |
3197 | len); | |
f2aee329 RS |
3198 | rc = -ENOMEM; |
3199 | kfree(vol->username); | |
3200 | vol->username = NULL; | |
453431a5 | 3201 | kfree_sensitive(vol->password); |
f2aee329 RS |
3202 | vol->password = NULL; |
3203 | goto out_key_put; | |
3204 | } | |
3205 | } | |
3206 | ||
8a8798a5 JL |
3207 | out_key_put: |
3208 | up_read(&key->sem); | |
3209 | key_put(key); | |
3210 | out_err: | |
3211 | kfree(desc); | |
f96637be | 3212 | cifs_dbg(FYI, "%s: returning %d\n", __func__, rc); |
8a8798a5 JL |
3213 | return rc; |
3214 | } | |
3215 | #else /* ! CONFIG_KEYS */ | |
3216 | static inline int | |
3217 | cifs_set_cifscreds(struct smb_vol *vol __attribute__((unused)), | |
3218 | struct cifs_ses *ses __attribute__((unused))) | |
3219 | { | |
3220 | return -ENOSYS; | |
3221 | } | |
3222 | #endif /* CONFIG_KEYS */ | |
3223 | ||
4a1360d0 AA |
3224 | /** |
3225 | * cifs_get_smb_ses - get a session matching @volume_info data from @server | |
3226 | * | |
3227 | * This function assumes it is being called from cifs_mount() where we | |
3228 | * already got a server reference (server refcount +1). See | |
3229 | * cifs_get_tcon() for refcount explanations. | |
3230 | */ | |
5072010c | 3231 | struct cifs_ses * |
36988c76 JL |
3232 | cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) |
3233 | { | |
286170aa PS |
3234 | int rc = -ENOMEM; |
3235 | unsigned int xid; | |
96daf2b0 | 3236 | struct cifs_ses *ses; |
a9f1b85e PS |
3237 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; |
3238 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; | |
36988c76 | 3239 | |
6d5786a3 | 3240 | xid = get_xid(); |
36988c76 | 3241 | |
4ff67b72 | 3242 | ses = cifs_find_smb_ses(server, volume_info); |
36988c76 | 3243 | if (ses) { |
f96637be JP |
3244 | cifs_dbg(FYI, "Existing smb sess found (status=%d)\n", |
3245 | ses->status); | |
36988c76 | 3246 | |
36988c76 | 3247 | mutex_lock(&ses->session_mutex); |
198b5682 JL |
3248 | rc = cifs_negotiate_protocol(xid, ses); |
3249 | if (rc) { | |
3250 | mutex_unlock(&ses->session_mutex); | |
3251 | /* problem -- put our ses reference */ | |
3252 | cifs_put_smb_ses(ses); | |
6d5786a3 | 3253 | free_xid(xid); |
198b5682 JL |
3254 | return ERR_PTR(rc); |
3255 | } | |
36988c76 | 3256 | if (ses->need_reconnect) { |
f96637be | 3257 | cifs_dbg(FYI, "Session needs reconnect\n"); |
36988c76 JL |
3258 | rc = cifs_setup_session(xid, ses, |
3259 | volume_info->local_nls); | |
3260 | if (rc) { | |
3261 | mutex_unlock(&ses->session_mutex); | |
3262 | /* problem -- put our reference */ | |
3263 | cifs_put_smb_ses(ses); | |
6d5786a3 | 3264 | free_xid(xid); |
36988c76 JL |
3265 | return ERR_PTR(rc); |
3266 | } | |
3267 | } | |
3268 | mutex_unlock(&ses->session_mutex); | |
460cf341 JL |
3269 | |
3270 | /* existing SMB ses has a server reference already */ | |
53e0e11e | 3271 | cifs_put_tcp_session(server, 0); |
6d5786a3 | 3272 | free_xid(xid); |
36988c76 JL |
3273 | return ses; |
3274 | } | |
3275 | ||
f96637be | 3276 | cifs_dbg(FYI, "Existing smb sess not found\n"); |
36988c76 JL |
3277 | ses = sesInfoAlloc(); |
3278 | if (ses == NULL) | |
3279 | goto get_ses_fail; | |
3280 | ||
3281 | /* new SMB session uses our server ref */ | |
3282 | ses->server = server; | |
a9f1b85e PS |
3283 | if (server->dstaddr.ss_family == AF_INET6) |
3284 | sprintf(ses->serverName, "%pI6", &addr6->sin6_addr); | |
36988c76 | 3285 | else |
a9f1b85e | 3286 | sprintf(ses->serverName, "%pI4", &addr->sin_addr); |
36988c76 | 3287 | |
8727c8a8 SF |
3288 | if (volume_info->username) { |
3289 | ses->user_name = kstrdup(volume_info->username, GFP_KERNEL); | |
3290 | if (!ses->user_name) | |
3291 | goto get_ses_fail; | |
3292 | } | |
36988c76 JL |
3293 | |
3294 | /* volume_info->password freed at unmount */ | |
3295 | if (volume_info->password) { | |
3296 | ses->password = kstrdup(volume_info->password, GFP_KERNEL); | |
3297 | if (!ses->password) | |
3298 | goto get_ses_fail; | |
3299 | } | |
3300 | if (volume_info->domainname) { | |
d3686d54 SP |
3301 | ses->domainName = kstrdup(volume_info->domainname, GFP_KERNEL); |
3302 | if (!ses->domainName) | |
3303 | goto get_ses_fail; | |
36988c76 | 3304 | } |
39566443 GP |
3305 | if (volume_info->domainauto) |
3306 | ses->domainAuto = volume_info->domainauto; | |
3e4b3e1f | 3307 | ses->cred_uid = volume_info->cred_uid; |
36988c76 | 3308 | ses->linux_uid = volume_info->linux_uid; |
d9b94201 | 3309 | |
28e11bd8 JL |
3310 | ses->sectype = volume_info->sectype; |
3311 | ses->sign = volume_info->sign; | |
36988c76 | 3312 | mutex_lock(&ses->session_mutex); |
d70e9fa5 AA |
3313 | |
3314 | /* add server as first channel */ | |
3315 | ses->chans[0].server = server; | |
3316 | ses->chan_count = 1; | |
3317 | ses->chan_max = volume_info->multichannel ? volume_info->max_channels:1; | |
3318 | ||
198b5682 JL |
3319 | rc = cifs_negotiate_protocol(xid, ses); |
3320 | if (!rc) | |
3321 | rc = cifs_setup_session(xid, ses, volume_info->local_nls); | |
d70e9fa5 AA |
3322 | |
3323 | /* each channel uses a different signing key */ | |
3324 | memcpy(ses->chans[0].signkey, ses->smb3signingkey, | |
3325 | sizeof(ses->smb3signingkey)); | |
3326 | ||
36988c76 | 3327 | mutex_unlock(&ses->session_mutex); |
c8e56f1f | 3328 | if (rc) |
36988c76 JL |
3329 | goto get_ses_fail; |
3330 | ||
d70e9fa5 | 3331 | /* success, put it on the list and add it as first channel */ |
3f9bcca7 | 3332 | spin_lock(&cifs_tcp_ses_lock); |
36988c76 | 3333 | list_add(&ses->smb_ses_list, &server->smb_ses_list); |
3f9bcca7 | 3334 | spin_unlock(&cifs_tcp_ses_lock); |
36988c76 | 3335 | |
6d5786a3 | 3336 | free_xid(xid); |
b327a717 AA |
3337 | |
3338 | cifs_setup_ipc(ses, volume_info); | |
3339 | ||
36988c76 JL |
3340 | return ses; |
3341 | ||
3342 | get_ses_fail: | |
3343 | sesInfoFree(ses); | |
6d5786a3 | 3344 | free_xid(xid); |
36988c76 JL |
3345 | return ERR_PTR(rc); |
3346 | } | |
3347 | ||
ae6f8dd4 | 3348 | static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info) |
37bb04e5 PS |
3349 | { |
3350 | if (tcon->tidStatus == CifsExiting) | |
3351 | return 0; | |
ae6f8dd4 | 3352 | if (strncmp(tcon->treeName, volume_info->UNC, MAX_TREE_SIZE)) |
37bb04e5 | 3353 | return 0; |
ae6f8dd4 PS |
3354 | if (tcon->seal != volume_info->seal) |
3355 | return 0; | |
ae6f8dd4 PS |
3356 | if (tcon->snapshot_time != volume_info->snapshot_time) |
3357 | return 0; | |
ca567eb2 SF |
3358 | if (tcon->handle_timeout != volume_info->handle_timeout) |
3359 | return 0; | |
3e7a02d4 SF |
3360 | if (tcon->no_lease != volume_info->no_lease) |
3361 | return 0; | |
82e9367c SF |
3362 | if (tcon->nodelete != volume_info->nodelete) |
3363 | return 0; | |
37bb04e5 PS |
3364 | return 1; |
3365 | } | |
3366 | ||
96daf2b0 | 3367 | static struct cifs_tcon * |
8b217fe7 | 3368 | cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) |
f1987b44 JL |
3369 | { |
3370 | struct list_head *tmp; | |
96daf2b0 | 3371 | struct cifs_tcon *tcon; |
f1987b44 | 3372 | |
3f9bcca7 | 3373 | spin_lock(&cifs_tcp_ses_lock); |
f1987b44 | 3374 | list_for_each(tmp, &ses->tcon_list) { |
96daf2b0 | 3375 | tcon = list_entry(tmp, struct cifs_tcon, tcon_list); |
65303de8 PA |
3376 | #ifdef CONFIG_CIFS_DFS_UPCALL |
3377 | if (tcon->dfs_path) | |
3378 | continue; | |
3379 | #endif | |
ae6f8dd4 | 3380 | if (!match_tcon(tcon, volume_info)) |
f1987b44 | 3381 | continue; |
f1987b44 | 3382 | ++tcon->tc_count; |
3f9bcca7 | 3383 | spin_unlock(&cifs_tcp_ses_lock); |
dea570e0 | 3384 | return tcon; |
1da177e4 | 3385 | } |
3f9bcca7 | 3386 | spin_unlock(&cifs_tcp_ses_lock); |
1da177e4 LT |
3387 | return NULL; |
3388 | } | |
3389 | ||
53e0e11e | 3390 | void |
96daf2b0 | 3391 | cifs_put_tcon(struct cifs_tcon *tcon) |
f1987b44 | 3392 | { |
2e6e02ab | 3393 | unsigned int xid; |
b327a717 | 3394 | struct cifs_ses *ses; |
f1987b44 | 3395 | |
b327a717 AA |
3396 | /* |
3397 | * IPC tcon share the lifetime of their session and are | |
3398 | * destroyed in the session put function | |
3399 | */ | |
3400 | if (tcon == NULL || tcon->ipc) | |
3401 | return; | |
3402 | ||
3403 | ses = tcon->ses; | |
f96637be | 3404 | cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count); |
3f9bcca7 | 3405 | spin_lock(&cifs_tcp_ses_lock); |
f1987b44 | 3406 | if (--tcon->tc_count > 0) { |
3f9bcca7 | 3407 | spin_unlock(&cifs_tcp_ses_lock); |
f1987b44 JL |
3408 | return; |
3409 | } | |
3410 | ||
3411 | list_del_init(&tcon->tcon_list); | |
3f9bcca7 | 3412 | spin_unlock(&cifs_tcp_ses_lock); |
f1987b44 | 3413 | |
6d5786a3 | 3414 | xid = get_xid(); |
2e6e02ab PS |
3415 | if (ses->server->ops->tree_disconnect) |
3416 | ses->server->ops->tree_disconnect(xid, tcon); | |
6d5786a3 | 3417 | _free_xid(xid); |
f1987b44 | 3418 | |
d03382ce | 3419 | cifs_fscache_release_super_cookie(tcon); |
9f841593 | 3420 | tconInfoFree(tcon); |
f1987b44 JL |
3421 | cifs_put_smb_ses(ses); |
3422 | } | |
3423 | ||
4a1360d0 AA |
3424 | /** |
3425 | * cifs_get_tcon - get a tcon matching @volume_info data from @ses | |
3426 | * | |
3427 | * - tcon refcount is the number of mount points using the tcon. | |
3428 | * - ses refcount is the number of tcon using the session. | |
3429 | * | |
3430 | * 1. This function assumes it is being called from cifs_mount() where | |
3431 | * we already got a session reference (ses refcount +1). | |
3432 | * | |
3433 | * 2. Since we're in the context of adding a mount point, the end | |
3434 | * result should be either: | |
3435 | * | |
3436 | * a) a new tcon already allocated with refcount=1 (1 mount point) and | |
3437 | * its session refcount incremented (1 new tcon). This +1 was | |
3438 | * already done in (1). | |
3439 | * | |
3440 | * b) an existing tcon with refcount+1 (add a mount point to it) and | |
3441 | * identical ses refcount (no new tcon). Because of (1) we need to | |
3442 | * decrement the ses refcount. | |
3443 | */ | |
96daf2b0 SF |
3444 | static struct cifs_tcon * |
3445 | cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) | |
d00c28de JL |
3446 | { |
3447 | int rc, xid; | |
96daf2b0 | 3448 | struct cifs_tcon *tcon; |
d00c28de | 3449 | |
8b217fe7 | 3450 | tcon = cifs_find_tcon(ses, volume_info); |
d00c28de | 3451 | if (tcon) { |
4a1360d0 AA |
3452 | /* |
3453 | * tcon has refcount already incremented but we need to | |
3454 | * decrement extra ses reference gotten by caller (case b) | |
3455 | */ | |
f96637be | 3456 | cifs_dbg(FYI, "Found match on UNC path\n"); |
d00c28de | 3457 | cifs_put_smb_ses(ses); |
d00c28de JL |
3458 | return tcon; |
3459 | } | |
3460 | ||
2e6e02ab PS |
3461 | if (!ses->server->ops->tree_connect) { |
3462 | rc = -ENOSYS; | |
3463 | goto out_fail; | |
3464 | } | |
3465 | ||
d00c28de JL |
3466 | tcon = tconInfoAlloc(); |
3467 | if (tcon == NULL) { | |
3468 | rc = -ENOMEM; | |
3469 | goto out_fail; | |
3470 | } | |
3471 | ||
8b217fe7 | 3472 | if (volume_info->snapshot_time) { |
8b217fe7 SF |
3473 | if (ses->server->vals->protocol_id == 0) { |
3474 | cifs_dbg(VFS, | |
3475 | "Use SMB2 or later for snapshot mount option\n"); | |
3476 | rc = -EOPNOTSUPP; | |
3477 | goto out_fail; | |
3478 | } else | |
3479 | tcon->snapshot_time = volume_info->snapshot_time; | |
8b217fe7 SF |
3480 | } |
3481 | ||
ca567eb2 SF |
3482 | if (volume_info->handle_timeout) { |
3483 | if (ses->server->vals->protocol_id == 0) { | |
3484 | cifs_dbg(VFS, | |
3485 | "Use SMB2.1 or later for handle timeout option\n"); | |
3486 | rc = -EOPNOTSUPP; | |
3487 | goto out_fail; | |
3488 | } else | |
3489 | tcon->handle_timeout = volume_info->handle_timeout; | |
3490 | } | |
3491 | ||
d00c28de JL |
3492 | tcon->ses = ses; |
3493 | if (volume_info->password) { | |
3494 | tcon->password = kstrdup(volume_info->password, GFP_KERNEL); | |
3495 | if (!tcon->password) { | |
3496 | rc = -ENOMEM; | |
3497 | goto out_fail; | |
3498 | } | |
3499 | } | |
3500 | ||
23657ad7 SF |
3501 | if (volume_info->seal) { |
3502 | if (ses->server->vals->protocol_id == 0) { | |
3503 | cifs_dbg(VFS, | |
3504 | "SMB3 or later required for encryption\n"); | |
3505 | rc = -EOPNOTSUPP; | |
3506 | goto out_fail; | |
3507 | } else if (tcon->ses->server->capabilities & | |
3508 | SMB2_GLOBAL_CAP_ENCRYPTION) | |
3509 | tcon->seal = true; | |
3510 | else { | |
3511 | cifs_dbg(VFS, "Encryption is not supported on share\n"); | |
3512 | rc = -EOPNOTSUPP; | |
3513 | goto out_fail; | |
3514 | } | |
3515 | } | |
3516 | ||
8505c8bf SF |
3517 | if (volume_info->linux_ext) { |
3518 | if (ses->server->posix_ext_supported) { | |
b326614e | 3519 | tcon->posix_extensions = true; |
a0a3036b | 3520 | pr_warn_once("SMB3.11 POSIX Extensions are experimental\n"); |
8505c8bf | 3521 | } else { |
a0a3036b | 3522 | cifs_dbg(VFS, "Server does not support mounting with posix SMB3.11 extensions\n"); |
8505c8bf SF |
3523 | rc = -EOPNOTSUPP; |
3524 | goto out_fail; | |
2fbb5644 | 3525 | } |
b326614e | 3526 | } |
b326614e | 3527 | |
2e6e02ab PS |
3528 | /* |
3529 | * BB Do we need to wrap session_mutex around this TCon call and Unix | |
3530 | * SetFS as we do on SessSetup and reconnect? | |
3531 | */ | |
6d5786a3 | 3532 | xid = get_xid(); |
2e6e02ab PS |
3533 | rc = ses->server->ops->tree_connect(xid, ses, volume_info->UNC, tcon, |
3534 | volume_info->local_nls); | |
6d5786a3 | 3535 | free_xid(xid); |
f96637be | 3536 | cifs_dbg(FYI, "Tcon rc = %d\n", rc); |
d00c28de JL |
3537 | if (rc) |
3538 | goto out_fail; | |
3539 | ||
b618f001 SF |
3540 | tcon->use_persistent = false; |
3541 | /* check if SMB2 or later, CIFS does not support persistent handles */ | |
3542 | if (volume_info->persistent) { | |
3543 | if (ses->server->vals->protocol_id == 0) { | |
3544 | cifs_dbg(VFS, | |
3545 | "SMB3 or later required for persistent handles\n"); | |
3546 | rc = -EOPNOTSUPP; | |
3547 | goto out_fail; | |
3548 | } else if (ses->server->capabilities & | |
3549 | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES) | |
3550 | tcon->use_persistent = true; | |
3551 | else /* persistent handles requested but not supported */ { | |
3552 | cifs_dbg(VFS, | |
3553 | "Persistent handles not supported on share\n"); | |
3554 | rc = -EOPNOTSUPP; | |
3555 | goto out_fail; | |
3556 | } | |
3557 | } else if ((tcon->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY) | |
3558 | && (ses->server->capabilities & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES) | |
3559 | && (volume_info->nopersistent == false)) { | |
3560 | cifs_dbg(FYI, "enabling persistent handles\n"); | |
3561 | tcon->use_persistent = true; | |
592fafe6 SF |
3562 | } else if (volume_info->resilient) { |
3563 | if (ses->server->vals->protocol_id == 0) { | |
3564 | cifs_dbg(VFS, | |
3565 | "SMB2.1 or later required for resilient handles\n"); | |
3566 | rc = -EOPNOTSUPP; | |
3567 | goto out_fail; | |
3568 | } | |
3569 | tcon->use_resilient = true; | |
b618f001 SF |
3570 | } |
3571 | ||
cae53f70 SF |
3572 | /* If the user really knows what they are doing they can override */ |
3573 | if (tcon->share_flags & SMB2_SHAREFLAG_NO_CACHING) { | |
3574 | if (volume_info->cache_ro) | |
3575 | cifs_dbg(VFS, "cache=ro requested on mount but NO_CACHING flag set on share\n"); | |
3576 | else if (volume_info->cache_rw) | |
3577 | cifs_dbg(VFS, "cache=singleclient requested on mount but NO_CACHING flag set on share\n"); | |
3578 | } | |
3579 | ||
8fd6e1d6 K |
3580 | if (volume_info->no_lease) { |
3581 | if (ses->server->vals->protocol_id == 0) { | |
3582 | cifs_dbg(VFS, | |
3583 | "SMB2 or later required for nolease option\n"); | |
3584 | rc = -EOPNOTSUPP; | |
3585 | goto out_fail; | |
3586 | } else | |
3587 | tcon->no_lease = volume_info->no_lease; | |
3588 | } | |
3589 | ||
2e6e02ab PS |
3590 | /* |
3591 | * We can have only one retry value for a connection to a share so for | |
3592 | * resources mounted more than once to the same server share the last | |
3593 | * value passed in for the retry flag is used. | |
3594 | */ | |
d00c28de JL |
3595 | tcon->retry = volume_info->retry; |
3596 | tcon->nocase = volume_info->nocase; | |
3d4ef9a1 | 3597 | tcon->nohandlecache = volume_info->nohandlecache; |
82e9367c | 3598 | tcon->nodelete = volume_info->nodelete; |
d00c28de | 3599 | tcon->local_lease = volume_info->local_lease; |
233839b1 | 3600 | INIT_LIST_HEAD(&tcon->pending_opens); |
d00c28de | 3601 | |
3f9bcca7 | 3602 | spin_lock(&cifs_tcp_ses_lock); |
d00c28de | 3603 | list_add(&tcon->tcon_list, &ses->tcon_list); |
3f9bcca7 | 3604 | spin_unlock(&cifs_tcp_ses_lock); |
d00c28de | 3605 | |
d03382ce SJ |
3606 | cifs_fscache_get_super_cookie(tcon); |
3607 | ||
d00c28de JL |
3608 | return tcon; |
3609 | ||
3610 | out_fail: | |
3611 | tconInfoFree(tcon); | |
3612 | return ERR_PTR(rc); | |
3613 | } | |
3614 | ||
9d002df4 JL |
3615 | void |
3616 | cifs_put_tlink(struct tcon_link *tlink) | |
3617 | { | |
3618 | if (!tlink || IS_ERR(tlink)) | |
3619 | return; | |
3620 | ||
3621 | if (!atomic_dec_and_test(&tlink->tl_count) || | |
3622 | test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) { | |
3623 | tlink->tl_time = jiffies; | |
3624 | return; | |
3625 | } | |
3626 | ||
3627 | if (!IS_ERR(tlink_tcon(tlink))) | |
3628 | cifs_put_tcon(tlink_tcon(tlink)); | |
3629 | kfree(tlink); | |
3630 | return; | |
3631 | } | |
d00c28de | 3632 | |
25c7f41e PS |
3633 | static int |
3634 | compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) | |
3635 | { | |
3636 | struct cifs_sb_info *old = CIFS_SB(sb); | |
3637 | struct cifs_sb_info *new = mnt_data->cifs_sb; | |
29fbeb7a PAS |
3638 | unsigned int oldflags = old->mnt_cifs_flags & CIFS_MOUNT_MASK; |
3639 | unsigned int newflags = new->mnt_cifs_flags & CIFS_MOUNT_MASK; | |
25c7f41e PS |
3640 | |
3641 | if ((sb->s_flags & CIFS_MS_MASK) != (mnt_data->flags & CIFS_MS_MASK)) | |
3642 | return 0; | |
3643 | ||
29fbeb7a PAS |
3644 | if (old->mnt_cifs_serverino_autodisabled) |
3645 | newflags &= ~CIFS_MOUNT_SERVER_INUM; | |
3646 | ||
3647 | if (oldflags != newflags) | |
25c7f41e PS |
3648 | return 0; |
3649 | ||
25c7f41e | 3650 | /* |
5eba8ab3 JL |
3651 | * We want to share sb only if we don't specify an r/wsize or |
3652 | * specified r/wsize is greater than or equal to existing one. | |
25c7f41e PS |
3653 | */ |
3654 | if (new->wsize && new->wsize < old->wsize) | |
3655 | return 0; | |
3656 | ||
5eba8ab3 JL |
3657 | if (new->rsize && new->rsize < old->rsize) |
3658 | return 0; | |
3659 | ||
1f68233c | 3660 | if (!uid_eq(old->mnt_uid, new->mnt_uid) || !gid_eq(old->mnt_gid, new->mnt_gid)) |
25c7f41e PS |
3661 | return 0; |
3662 | ||
3663 | if (old->mnt_file_mode != new->mnt_file_mode || | |
3664 | old->mnt_dir_mode != new->mnt_dir_mode) | |
3665 | return 0; | |
3666 | ||
3667 | if (strcmp(old->local_nls->charset, new->local_nls->charset)) | |
3668 | return 0; | |
3669 | ||
3670 | if (old->actimeo != new->actimeo) | |
3671 | return 0; | |
3672 | ||
3673 | return 1; | |
3674 | } | |
3675 | ||
c1d8b24d SP |
3676 | static int |
3677 | match_prepath(struct super_block *sb, struct cifs_mnt_data *mnt_data) | |
3678 | { | |
3679 | struct cifs_sb_info *old = CIFS_SB(sb); | |
3680 | struct cifs_sb_info *new = mnt_data->cifs_sb; | |
fe129268 RS |
3681 | bool old_set = (old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) && |
3682 | old->prepath; | |
3683 | bool new_set = (new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) && | |
3684 | new->prepath; | |
c1d8b24d | 3685 | |
cd8c4296 | 3686 | if (old_set && new_set && !strcmp(new->prepath, old->prepath)) |
c1d8b24d | 3687 | return 1; |
cd8c4296 SP |
3688 | else if (!old_set && !new_set) |
3689 | return 1; | |
3690 | ||
c1d8b24d SP |
3691 | return 0; |
3692 | } | |
3693 | ||
25c7f41e PS |
3694 | int |
3695 | cifs_match_super(struct super_block *sb, void *data) | |
3696 | { | |
3697 | struct cifs_mnt_data *mnt_data = (struct cifs_mnt_data *)data; | |
3698 | struct smb_vol *volume_info; | |
3699 | struct cifs_sb_info *cifs_sb; | |
3700 | struct TCP_Server_Info *tcp_srv; | |
96daf2b0 SF |
3701 | struct cifs_ses *ses; |
3702 | struct cifs_tcon *tcon; | |
25c7f41e | 3703 | struct tcon_link *tlink; |
25c7f41e PS |
3704 | int rc = 0; |
3705 | ||
25c7f41e PS |
3706 | spin_lock(&cifs_tcp_ses_lock); |
3707 | cifs_sb = CIFS_SB(sb); | |
3708 | tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); | |
3709 | if (IS_ERR(tlink)) { | |
3710 | spin_unlock(&cifs_tcp_ses_lock); | |
3711 | return rc; | |
3712 | } | |
3713 | tcon = tlink_tcon(tlink); | |
3714 | ses = tcon->ses; | |
3715 | tcp_srv = ses->server; | |
3716 | ||
3717 | volume_info = mnt_data->vol; | |
3718 | ||
9fa114f7 | 3719 | if (!match_server(tcp_srv, volume_info) || |
25c7f41e | 3720 | !match_session(ses, volume_info) || |
ae6f8dd4 | 3721 | !match_tcon(tcon, volume_info) || |
c1d8b24d | 3722 | !match_prepath(sb, mnt_data)) { |
25c7f41e PS |
3723 | rc = 0; |
3724 | goto out; | |
3725 | } | |
3726 | ||
3727 | rc = compare_mount_options(sb, mnt_data); | |
3728 | out: | |
25c7f41e | 3729 | spin_unlock(&cifs_tcp_ses_lock); |
f484b5d0 | 3730 | cifs_put_tlink(tlink); |
25c7f41e PS |
3731 | return rc; |
3732 | } | |
3733 | ||
09e50d55 JL |
3734 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
3735 | static struct lock_class_key cifs_key[2]; | |
3736 | static struct lock_class_key cifs_slock_key[2]; | |
3737 | ||
3738 | static inline void | |
3739 | cifs_reclassify_socket4(struct socket *sock) | |
3740 | { | |
3741 | struct sock *sk = sock->sk; | |
fafc4e1e | 3742 | BUG_ON(!sock_allow_reclassification(sk)); |
09e50d55 JL |
3743 | sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS", |
3744 | &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]); | |
3745 | } | |
3746 | ||
3747 | static inline void | |
3748 | cifs_reclassify_socket6(struct socket *sock) | |
3749 | { | |
3750 | struct sock *sk = sock->sk; | |
fafc4e1e | 3751 | BUG_ON(!sock_allow_reclassification(sk)); |
09e50d55 JL |
3752 | sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS", |
3753 | &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]); | |
3754 | } | |
3755 | #else | |
3756 | static inline void | |
3757 | cifs_reclassify_socket4(struct socket *sock) | |
3758 | { | |
3759 | } | |
3760 | ||
3761 | static inline void | |
3762 | cifs_reclassify_socket6(struct socket *sock) | |
3763 | { | |
3764 | } | |
3765 | #endif | |
3766 | ||
1da177e4 | 3767 | /* See RFC1001 section 14 on representation of Netbios names */ |
50c2f753 | 3768 | static void rfc1002mangle(char *target, char *source, unsigned int length) |
1da177e4 | 3769 | { |
50c2f753 | 3770 | unsigned int i, j; |
1da177e4 | 3771 | |
50c2f753 | 3772 | for (i = 0, j = 0; i < (length); i++) { |
1da177e4 LT |
3773 | /* mask a nibble at a time and encode */ |
3774 | target[j] = 'A' + (0x0F & (source[i] >> 4)); | |
3775 | target[j+1] = 'A' + (0x0F & source[i]); | |
50c2f753 | 3776 | j += 2; |
1da177e4 LT |
3777 | } |
3778 | ||
3779 | } | |
3780 | ||
3eb9a889 BG |
3781 | static int |
3782 | bind_socket(struct TCP_Server_Info *server) | |
3783 | { | |
3784 | int rc = 0; | |
3785 | if (server->srcaddr.ss_family != AF_UNSPEC) { | |
3786 | /* Bind to the specified local IP address */ | |
3787 | struct socket *socket = server->ssocket; | |
3788 | rc = socket->ops->bind(socket, | |
3789 | (struct sockaddr *) &server->srcaddr, | |
3790 | sizeof(server->srcaddr)); | |
3791 | if (rc < 0) { | |
3792 | struct sockaddr_in *saddr4; | |
3793 | struct sockaddr_in6 *saddr6; | |
3794 | saddr4 = (struct sockaddr_in *)&server->srcaddr; | |
3795 | saddr6 = (struct sockaddr_in6 *)&server->srcaddr; | |
3796 | if (saddr6->sin6_family == AF_INET6) | |
afe6f653 | 3797 | cifs_server_dbg(VFS, "Failed to bind to: %pI6c, error: %d\n", |
f96637be | 3798 | &saddr6->sin6_addr, rc); |
3eb9a889 | 3799 | else |
afe6f653 | 3800 | cifs_server_dbg(VFS, "Failed to bind to: %pI4, error: %d\n", |
f96637be | 3801 | &saddr4->sin_addr.s_addr, rc); |
3eb9a889 BG |
3802 | } |
3803 | } | |
3804 | return rc; | |
3805 | } | |
1da177e4 LT |
3806 | |
3807 | static int | |
a9f1b85e | 3808 | ip_rfc1001_connect(struct TCP_Server_Info *server) |
1da177e4 LT |
3809 | { |
3810 | int rc = 0; | |
a9f1b85e PS |
3811 | /* |
3812 | * some servers require RFC1001 sessinit before sending | |
3813 | * negprot - BB check reconnection in case where second | |
3814 | * sessinit is sent but no second negprot | |
3815 | */ | |
3816 | struct rfc1002_session_packet *ses_init_buf; | |
3817 | struct smb_hdr *smb_buf; | |
3818 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), | |
3819 | GFP_KERNEL); | |
3820 | if (ses_init_buf) { | |
3821 | ses_init_buf->trailer.session_req.called_len = 32; | |
3822 | ||
997152f6 | 3823 | if (server->server_RFC1001_name[0] != 0) |
a9f1b85e PS |
3824 | rfc1002mangle(ses_init_buf->trailer. |
3825 | session_req.called_name, | |
3826 | server->server_RFC1001_name, | |
3827 | RFC1001_NAME_LEN_WITH_NULL); | |
3828 | else | |
3829 | rfc1002mangle(ses_init_buf->trailer. | |
3830 | session_req.called_name, | |
3831 | DEFAULT_CIFS_CALLED_NAME, | |
3832 | RFC1001_NAME_LEN_WITH_NULL); | |
3833 | ||
3834 | ses_init_buf->trailer.session_req.calling_len = 32; | |
3835 | ||
3836 | /* | |
3837 | * calling name ends in null (byte 16) from old smb | |
3838 | * convention. | |
3839 | */ | |
c85c35f8 | 3840 | if (server->workstation_RFC1001_name[0] != 0) |
a9f1b85e PS |
3841 | rfc1002mangle(ses_init_buf->trailer. |
3842 | session_req.calling_name, | |
3843 | server->workstation_RFC1001_name, | |
3844 | RFC1001_NAME_LEN_WITH_NULL); | |
3845 | else | |
3846 | rfc1002mangle(ses_init_buf->trailer. | |
3847 | session_req.calling_name, | |
3848 | "LINUX_CIFS_CLNT", | |
3849 | RFC1001_NAME_LEN_WITH_NULL); | |
3850 | ||
3851 | ses_init_buf->trailer.session_req.scope1 = 0; | |
3852 | ses_init_buf->trailer.session_req.scope2 = 0; | |
3853 | smb_buf = (struct smb_hdr *)ses_init_buf; | |
3854 | ||
3855 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ | |
be8e3b00 | 3856 | smb_buf->smb_buf_length = cpu_to_be32(0x81000044); |
a9f1b85e PS |
3857 | rc = smb_send(server, smb_buf, 0x44); |
3858 | kfree(ses_init_buf); | |
3859 | /* | |
3860 | * RFC1001 layer in at least one server | |
3861 | * requires very short break before negprot | |
3862 | * presumably because not expecting negprot | |
3863 | * to follow so fast. This is a simple | |
3864 | * solution that works without | |
3865 | * complicating the code and causes no | |
3866 | * significant slowing down on mount | |
3867 | * for everyone else | |
3868 | */ | |
3869 | usleep_range(1000, 2000); | |
3870 | } | |
3871 | /* | |
3872 | * else the negprot may still work without this | |
3873 | * even though malloc failed | |
3874 | */ | |
3875 | ||
3876 | return rc; | |
3877 | } | |
3878 | ||
3879 | static int | |
3880 | generic_ip_connect(struct TCP_Server_Info *server) | |
3881 | { | |
3882 | int rc = 0; | |
6da97910 | 3883 | __be16 sport; |
a9f1b85e | 3884 | int slen, sfamily; |
bcf4b106 | 3885 | struct socket *socket = server->ssocket; |
a9f1b85e PS |
3886 | struct sockaddr *saddr; |
3887 | ||
3888 | saddr = (struct sockaddr *) &server->dstaddr; | |
3889 | ||
3890 | if (server->dstaddr.ss_family == AF_INET6) { | |
3891 | sport = ((struct sockaddr_in6 *) saddr)->sin6_port; | |
3892 | slen = sizeof(struct sockaddr_in6); | |
3893 | sfamily = AF_INET6; | |
3894 | } else { | |
3895 | sport = ((struct sockaddr_in *) saddr)->sin_port; | |
3896 | slen = sizeof(struct sockaddr_in); | |
3897 | sfamily = AF_INET; | |
3898 | } | |
1da177e4 | 3899 | |
bcf4b106 | 3900 | if (socket == NULL) { |
f1d0c998 RL |
3901 | rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM, |
3902 | IPPROTO_TCP, &socket, 1); | |
1da177e4 | 3903 | if (rc < 0) { |
afe6f653 | 3904 | cifs_server_dbg(VFS, "Error %d creating socket\n", rc); |
a9f1b85e | 3905 | server->ssocket = NULL; |
1da177e4 | 3906 | return rc; |
1da177e4 | 3907 | } |
bcf4b106 JL |
3908 | |
3909 | /* BB other socket options to set KEEPALIVE, NODELAY? */ | |
f96637be | 3910 | cifs_dbg(FYI, "Socket created\n"); |
bcf4b106 JL |
3911 | server->ssocket = socket; |
3912 | socket->sk->sk_allocation = GFP_NOFS; | |
a9f1b85e PS |
3913 | if (sfamily == AF_INET6) |
3914 | cifs_reclassify_socket6(socket); | |
3915 | else | |
3916 | cifs_reclassify_socket4(socket); | |
1da177e4 LT |
3917 | } |
3918 | ||
3eb9a889 BG |
3919 | rc = bind_socket(server); |
3920 | if (rc < 0) | |
3921 | return rc; | |
3922 | ||
bcf4b106 JL |
3923 | /* |
3924 | * Eventually check for other socket options to change from | |
a9f1b85e PS |
3925 | * the default. sock_setsockopt not used because it expects |
3926 | * user space buffer | |
bcf4b106 JL |
3927 | */ |
3928 | socket->sk->sk_rcvtimeo = 7 * HZ; | |
da505c38 | 3929 | socket->sk->sk_sndtimeo = 5 * HZ; |
edf1ae40 | 3930 | |
b387eaeb | 3931 | /* make the bufsizes depend on wsize/rsize and max requests */ |
bcf4b106 JL |
3932 | if (server->noautotune) { |
3933 | if (socket->sk->sk_sndbuf < (200 * 1024)) | |
3934 | socket->sk->sk_sndbuf = 200 * 1024; | |
3935 | if (socket->sk->sk_rcvbuf < (140 * 1024)) | |
3936 | socket->sk->sk_rcvbuf = 140 * 1024; | |
edf1ae40 | 3937 | } |
1da177e4 | 3938 | |
12abc5ee CH |
3939 | if (server->tcp_nodelay) |
3940 | tcp_sock_set_nodelay(socket->sk); | |
6a5fa236 | 3941 | |
f96637be | 3942 | cifs_dbg(FYI, "sndbuf %d rcvbuf %d rcvtimeo 0x%lx\n", |
bcf4b106 | 3943 | socket->sk->sk_sndbuf, |
b6b38f70 | 3944 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo); |
bcf4b106 | 3945 | |
8eecd1c2 PAS |
3946 | rc = socket->ops->connect(socket, saddr, slen, |
3947 | server->noblockcnt ? O_NONBLOCK : 0); | |
d532cc7e PAS |
3948 | /* |
3949 | * When mounting SMB root file systems, we do not want to block in | |
3950 | * connect. Otherwise bail out and then let cifs_reconnect() perform | |
3951 | * reconnect failover - if possible. | |
3952 | */ | |
3953 | if (server->noblockcnt && rc == -EINPROGRESS) | |
8eecd1c2 | 3954 | rc = 0; |
ee1b3ea9 | 3955 | if (rc < 0) { |
f96637be | 3956 | cifs_dbg(FYI, "Error %d connecting to server\n", rc); |
ee1b3ea9 JL |
3957 | sock_release(socket); |
3958 | server->ssocket = NULL; | |
3959 | return rc; | |
3960 | } | |
3961 | ||
a9f1b85e PS |
3962 | if (sport == htons(RFC1001_PORT)) |
3963 | rc = ip_rfc1001_connect(server); | |
50c2f753 | 3964 | |
1da177e4 LT |
3965 | return rc; |
3966 | } | |
3967 | ||
3968 | static int | |
a9f1b85e | 3969 | ip_connect(struct TCP_Server_Info *server) |
1da177e4 | 3970 | { |
6da97910 | 3971 | __be16 *sport; |
a9f1b85e PS |
3972 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; |
3973 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; | |
1da177e4 | 3974 | |
a9f1b85e PS |
3975 | if (server->dstaddr.ss_family == AF_INET6) |
3976 | sport = &addr6->sin6_port; | |
3977 | else | |
3978 | sport = &addr->sin_port; | |
1da177e4 | 3979 | |
a9f1b85e PS |
3980 | if (*sport == 0) { |
3981 | int rc; | |
1da177e4 | 3982 | |
a9f1b85e PS |
3983 | /* try with 445 port at first */ |
3984 | *sport = htons(CIFS_PORT); | |
3eb9a889 | 3985 | |
a9f1b85e | 3986 | rc = generic_ip_connect(server); |
1da177e4 | 3987 | if (rc >= 0) |
a9f1b85e | 3988 | return rc; |
6a5fa236 | 3989 | |
a9f1b85e PS |
3990 | /* if it failed, try with 139 port */ |
3991 | *sport = htons(RFC1001_PORT); | |
6a5fa236 SF |
3992 | } |
3993 | ||
a9f1b85e | 3994 | return generic_ip_connect(server); |
1da177e4 LT |
3995 | } |
3996 | ||
6d5786a3 | 3997 | void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, |
2c6292ae | 3998 | struct cifs_sb_info *cifs_sb, struct smb_vol *vol_info) |
8af18971 SF |
3999 | { |
4000 | /* if we are reconnecting then should we check to see if | |
4001 | * any requested capabilities changed locally e.g. via | |
4002 | * remount but we can not do much about it here | |
4003 | * if they have (even if we could detect it by the following) | |
4004 | * Perhaps we could add a backpointer to array of sb from tcon | |
4005 | * or if we change to make all sb to same share the same | |
4006 | * sb as NFS - then we only have one backpointer to sb. | |
4007 | * What if we wanted to mount the server share twice once with | |
4008 | * and once without posixacls or posix paths? */ | |
4009 | __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); | |
50c2f753 | 4010 | |
c18c842b SF |
4011 | if (vol_info && vol_info->no_linux_ext) { |
4012 | tcon->fsUnixInfo.Capability = 0; | |
4013 | tcon->unix_ext = 0; /* Unix Extensions disabled */ | |
f96637be | 4014 | cifs_dbg(FYI, "Linux protocol extensions disabled\n"); |
c18c842b SF |
4015 | return; |
4016 | } else if (vol_info) | |
4017 | tcon->unix_ext = 1; /* Unix Extensions supported */ | |
4018 | ||
4019 | if (tcon->unix_ext == 0) { | |
f96637be | 4020 | cifs_dbg(FYI, "Unix extensions disabled so not set on reconnect\n"); |
c18c842b SF |
4021 | return; |
4022 | } | |
50c2f753 | 4023 | |
fb8c4b14 | 4024 | if (!CIFSSMBQFSUnixInfo(xid, tcon)) { |
8af18971 | 4025 | __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability); |
f96637be | 4026 | cifs_dbg(FYI, "unix caps which server supports %lld\n", cap); |
8af18971 SF |
4027 | /* check for reconnect case in which we do not |
4028 | want to change the mount behavior if we can avoid it */ | |
fb8c4b14 | 4029 | if (vol_info == NULL) { |
50c2f753 | 4030 | /* turn off POSIX ACL and PATHNAMES if not set |
8af18971 SF |
4031 | originally at mount time */ |
4032 | if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0) | |
4033 | cap &= ~CIFS_UNIX_POSIX_ACL_CAP; | |
11b6d645 IM |
4034 | if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) { |
4035 | if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) | |
f96637be | 4036 | cifs_dbg(VFS, "POSIXPATH support change\n"); |
8af18971 | 4037 | cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; |
11b6d645 | 4038 | } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) { |
f96637be JP |
4039 | cifs_dbg(VFS, "possible reconnect error\n"); |
4040 | cifs_dbg(VFS, "server disabled POSIX path support\n"); | |
11b6d645 | 4041 | } |
8af18971 | 4042 | } |
50c2f753 | 4043 | |
6848b733 | 4044 | if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) |
f96637be | 4045 | cifs_dbg(VFS, "per-share encryption not supported yet\n"); |
6848b733 | 4046 | |
8af18971 | 4047 | cap &= CIFS_UNIX_CAP_MASK; |
75865f8c | 4048 | if (vol_info && vol_info->no_psx_acl) |
8af18971 | 4049 | cap &= ~CIFS_UNIX_POSIX_ACL_CAP; |
75865f8c | 4050 | else if (CIFS_UNIX_POSIX_ACL_CAP & cap) { |
f96637be | 4051 | cifs_dbg(FYI, "negotiated posix acl support\n"); |
2c6292ae AV |
4052 | if (cifs_sb) |
4053 | cifs_sb->mnt_cifs_flags |= | |
4054 | CIFS_MOUNT_POSIXACL; | |
8af18971 SF |
4055 | } |
4056 | ||
75865f8c | 4057 | if (vol_info && vol_info->posix_paths == 0) |
8af18971 | 4058 | cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; |
75865f8c | 4059 | else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) { |
f96637be | 4060 | cifs_dbg(FYI, "negotiate posix pathnames\n"); |
2c6292ae AV |
4061 | if (cifs_sb) |
4062 | cifs_sb->mnt_cifs_flags |= | |
8af18971 SF |
4063 | CIFS_MOUNT_POSIX_PATHS; |
4064 | } | |
50c2f753 | 4065 | |
f96637be | 4066 | cifs_dbg(FYI, "Negotiate caps 0x%x\n", (int)cap); |
8af18971 | 4067 | #ifdef CONFIG_CIFS_DEBUG2 |
75865f8c | 4068 | if (cap & CIFS_UNIX_FCNTL_CAP) |
f96637be | 4069 | cifs_dbg(FYI, "FCNTL cap\n"); |
75865f8c | 4070 | if (cap & CIFS_UNIX_EXTATTR_CAP) |
f96637be | 4071 | cifs_dbg(FYI, "EXTATTR cap\n"); |
75865f8c | 4072 | if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) |
f96637be | 4073 | cifs_dbg(FYI, "POSIX path cap\n"); |
75865f8c | 4074 | if (cap & CIFS_UNIX_XATTR_CAP) |
f96637be | 4075 | cifs_dbg(FYI, "XATTR cap\n"); |
75865f8c | 4076 | if (cap & CIFS_UNIX_POSIX_ACL_CAP) |
f96637be | 4077 | cifs_dbg(FYI, "POSIX ACL cap\n"); |
75865f8c | 4078 | if (cap & CIFS_UNIX_LARGE_READ_CAP) |
f96637be | 4079 | cifs_dbg(FYI, "very large read cap\n"); |
75865f8c | 4080 | if (cap & CIFS_UNIX_LARGE_WRITE_CAP) |
f96637be | 4081 | cifs_dbg(FYI, "very large write cap\n"); |
6848b733 | 4082 | if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) |
f96637be | 4083 | cifs_dbg(FYI, "transport encryption cap\n"); |
6848b733 | 4084 | if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) |
f96637be | 4085 | cifs_dbg(FYI, "mandatory transport encryption cap\n"); |
8af18971 SF |
4086 | #endif /* CIFS_DEBUG2 */ |
4087 | if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { | |
442aa310 | 4088 | if (vol_info == NULL) { |
f96637be | 4089 | cifs_dbg(FYI, "resetting capabilities failed\n"); |
442aa310 | 4090 | } else |
f96637be | 4091 | cifs_dbg(VFS, "Negotiating Unix capabilities with the server failed. Consider mounting with the Unix Extensions disabled if problems are found by specifying the nounix mount option.\n"); |
5a44b319 | 4092 | |
8af18971 SF |
4093 | } |
4094 | } | |
4095 | } | |
4096 | ||
4214ebf4 | 4097 | int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, |
724d9f1c | 4098 | struct cifs_sb_info *cifs_sb) |
b1c8d2b4 | 4099 | { |
2de970ff JL |
4100 | INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks); |
4101 | ||
2ced6f69 AV |
4102 | spin_lock_init(&cifs_sb->tlink_tree_lock); |
4103 | cifs_sb->tlink_tree = RB_ROOT; | |
4104 | ||
e8506d25 | 4105 | cifs_sb->bsize = pvolume_info->bsize; |
25c7f41e | 4106 | /* |
5eba8ab3 JL |
4107 | * Temporarily set r/wsize for matching superblock. If we end up using |
4108 | * new sb then client will later negotiate it downward if needed. | |
25c7f41e | 4109 | */ |
5eba8ab3 | 4110 | cifs_sb->rsize = pvolume_info->rsize; |
25c7f41e PS |
4111 | cifs_sb->wsize = pvolume_info->wsize; |
4112 | ||
3b795210 SF |
4113 | cifs_sb->mnt_uid = pvolume_info->linux_uid; |
4114 | cifs_sb->mnt_gid = pvolume_info->linux_gid; | |
4115 | cifs_sb->mnt_file_mode = pvolume_info->file_mode; | |
4116 | cifs_sb->mnt_dir_mode = pvolume_info->dir_mode; | |
f52aa79d | 4117 | cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n", |
f96637be | 4118 | cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); |
3b795210 | 4119 | |
6d20e840 | 4120 | cifs_sb->actimeo = pvolume_info->actimeo; |
724d9f1c | 4121 | cifs_sb->local_nls = pvolume_info->local_nls; |
6d20e840 | 4122 | |
8393072b AA |
4123 | if (pvolume_info->nodfs) |
4124 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_DFS; | |
3b795210 SF |
4125 | if (pvolume_info->noperm) |
4126 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; | |
4127 | if (pvolume_info->setuids) | |
4128 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; | |
95932655 SF |
4129 | if (pvolume_info->setuidfromacl) |
4130 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UID_FROM_ACL; | |
3b795210 SF |
4131 | if (pvolume_info->server_ino) |
4132 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; | |
4133 | if (pvolume_info->remap) | |
2baa2682 SF |
4134 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR; |
4135 | if (pvolume_info->sfu_remap) | |
3b795210 SF |
4136 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; |
4137 | if (pvolume_info->no_xattr) | |
4138 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; | |
4139 | if (pvolume_info->sfu_emul) | |
4140 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; | |
4141 | if (pvolume_info->nobrl) | |
4142 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; | |
3d4ef9a1 SF |
4143 | if (pvolume_info->nohandlecache) |
4144 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_HANDLE_CACHE; | |
be652445 | 4145 | if (pvolume_info->nostrictsync) |
4717bed6 | 4146 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC; |
13a6e42a SF |
4147 | if (pvolume_info->mand_lock) |
4148 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL; | |
d4ffff1f PS |
4149 | if (pvolume_info->rwpidforward) |
4150 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD; | |
412094a8 SF |
4151 | if (pvolume_info->mode_ace) |
4152 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MODE_FROM_SID; | |
3b795210 SF |
4153 | if (pvolume_info->cifs_acl) |
4154 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; | |
3c7c87fd | 4155 | if (pvolume_info->backupuid_specified) { |
3d3ea8e6 | 4156 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID; |
3c7c87fd SP |
4157 | cifs_sb->mnt_backupuid = pvolume_info->backupuid; |
4158 | } | |
4159 | if (pvolume_info->backupgid_specified) { | |
3d3ea8e6 | 4160 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID; |
3c7c87fd SP |
4161 | cifs_sb->mnt_backupgid = pvolume_info->backupgid; |
4162 | } | |
3b795210 SF |
4163 | if (pvolume_info->override_uid) |
4164 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; | |
4165 | if (pvolume_info->override_gid) | |
4166 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; | |
4167 | if (pvolume_info->dynperm) | |
4168 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; | |
fa1df75d SJ |
4169 | if (pvolume_info->fsc) |
4170 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; | |
0eb8a132 JL |
4171 | if (pvolume_info->multiuser) |
4172 | cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER | | |
4173 | CIFS_MOUNT_NO_PERM); | |
d39454ff PS |
4174 | if (pvolume_info->strict_io) |
4175 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO; | |
3b795210 | 4176 | if (pvolume_info->direct_io) { |
f96637be | 4177 | cifs_dbg(FYI, "mounting share using direct i/o\n"); |
3b795210 SF |
4178 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; |
4179 | } | |
83bbfa70 SF |
4180 | if (pvolume_info->cache_ro) { |
4181 | cifs_dbg(VFS, "mounting share with read only caching. Ensure that the share will not be modified while in use.\n"); | |
4182 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RO_CACHE; | |
41e033fe SF |
4183 | } else if (pvolume_info->cache_rw) { |
4184 | cifs_dbg(VFS, "mounting share in single client RW caching mode. Ensure that no other systems will be accessing the share.\n"); | |
4185 | cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_RO_CACHE | | |
4186 | CIFS_MOUNT_RW_CACHE); | |
83bbfa70 | 4187 | } |
736a3320 SM |
4188 | if (pvolume_info->mfsymlinks) { |
4189 | if (pvolume_info->sfu_emul) { | |
db8b631d SF |
4190 | /* |
4191 | * Our SFU ("Services for Unix" emulation does not allow | |
4192 | * creating symlinks but does allow reading existing SFU | |
4193 | * symlinks (it does allow both creating and reading SFU | |
4194 | * style mknod and FIFOs though). When "mfsymlinks" and | |
4195 | * "sfu" are both enabled at the same time, it allows | |
4196 | * reading both types of symlinks, but will only create | |
4197 | * them with mfsymlinks format. This allows better | |
4198 | * Apple compatibility (probably better for Samba too) | |
4199 | * while still recognizing old Windows style symlinks. | |
4200 | */ | |
4201 | cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n"); | |
736a3320 | 4202 | } |
db8b631d | 4203 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS; |
736a3320 | 4204 | } |
3b795210 SF |
4205 | |
4206 | if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) | |
f96637be | 4207 | cifs_dbg(VFS, "mount option dynperm ignored if cifsacl mount option supported\n"); |
4214ebf4 SP |
4208 | |
4209 | if (pvolume_info->prepath) { | |
4210 | cifs_sb->prepath = kstrdup(pvolume_info->prepath, GFP_KERNEL); | |
4211 | if (cifs_sb->prepath == NULL) | |
4212 | return -ENOMEM; | |
4213 | } | |
4214 | ||
4215 | return 0; | |
b1c8d2b4 JL |
4216 | } |
4217 | ||
56c762eb PA |
4218 | void |
4219 | cifs_cleanup_volume_info_contents(struct smb_vol *volume_info) | |
1bfe73c2 | 4220 | { |
b946845a | 4221 | kfree(volume_info->username); |
453431a5 | 4222 | kfree_sensitive(volume_info->password); |
95c75454 | 4223 | kfree(volume_info->UNC); |
b946845a SF |
4224 | kfree(volume_info->domainname); |
4225 | kfree(volume_info->iocharset); | |
1bfe73c2 | 4226 | kfree(volume_info->prepath); |
b9bce2e9 JL |
4227 | } |
4228 | ||
4229 | void | |
4230 | cifs_cleanup_volume_info(struct smb_vol *volume_info) | |
4231 | { | |
4232 | if (!volume_info) | |
4233 | return; | |
56c762eb | 4234 | cifs_cleanup_volume_info_contents(volume_info); |
1bfe73c2 | 4235 | kfree(volume_info); |
1bfe73c2 IM |
4236 | } |
4237 | ||
56c762eb PA |
4238 | /* Release all succeed connections */ |
4239 | static inline void mount_put_conns(struct cifs_sb_info *cifs_sb, | |
4240 | unsigned int xid, | |
4241 | struct TCP_Server_Info *server, | |
4242 | struct cifs_ses *ses, struct cifs_tcon *tcon) | |
4243 | { | |
4244 | int rc = 0; | |
4245 | ||
4246 | if (tcon) | |
4247 | cifs_put_tcon(tcon); | |
4248 | else if (ses) | |
4249 | cifs_put_smb_ses(ses); | |
4250 | else if (server) | |
4251 | cifs_put_tcp_session(server, 0); | |
4252 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS; | |
4253 | free_xid(xid); | |
4254 | } | |
4255 | ||
4256 | /* Get connections for tcp, ses and tcon */ | |
4257 | static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, | |
4258 | unsigned int *xid, | |
4259 | struct TCP_Server_Info **nserver, | |
4260 | struct cifs_ses **nses, struct cifs_tcon **ntcon) | |
4261 | { | |
4262 | int rc = 0; | |
4263 | struct TCP_Server_Info *server; | |
4264 | struct cifs_ses *ses; | |
4265 | struct cifs_tcon *tcon; | |
4266 | ||
4267 | *nserver = NULL; | |
4268 | *nses = NULL; | |
4269 | *ntcon = NULL; | |
4270 | ||
4271 | *xid = get_xid(); | |
4272 | ||
4273 | /* get a reference to a tcp session */ | |
4274 | server = cifs_get_tcp_session(vol); | |
4275 | if (IS_ERR(server)) { | |
4276 | rc = PTR_ERR(server); | |
4277 | return rc; | |
4278 | } | |
4279 | ||
4280 | *nserver = server; | |
4281 | ||
4282 | if ((vol->max_credits < 20) || (vol->max_credits > 60000)) | |
4283 | server->max_credits = SMB2_MAX_CREDITS_AVAILABLE; | |
4284 | else | |
4285 | server->max_credits = vol->max_credits; | |
4286 | ||
4287 | /* get a reference to a SMB session */ | |
4288 | ses = cifs_get_smb_ses(server, vol); | |
4289 | if (IS_ERR(ses)) { | |
4290 | rc = PTR_ERR(ses); | |
4291 | return rc; | |
4292 | } | |
4293 | ||
4294 | *nses = ses; | |
4295 | ||
4296 | if ((vol->persistent == true) && (!(ses->server->capabilities & | |
4297 | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES))) { | |
afe6f653 | 4298 | cifs_server_dbg(VFS, "persistent handles not supported by server\n"); |
56c762eb PA |
4299 | return -EOPNOTSUPP; |
4300 | } | |
4301 | ||
4302 | /* search for existing tcon to this server share */ | |
4303 | tcon = cifs_get_tcon(ses, vol); | |
4304 | if (IS_ERR(tcon)) { | |
4305 | rc = PTR_ERR(tcon); | |
4306 | return rc; | |
4307 | } | |
4308 | ||
4309 | *ntcon = tcon; | |
4310 | ||
4311 | /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */ | |
4312 | if (tcon->posix_extensions) | |
4313 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; | |
4314 | ||
4315 | /* tell server which Unix caps we support */ | |
4316 | if (cap_unix(tcon->ses)) { | |
4317 | /* | |
4318 | * reset of caps checks mount to see if unix extensions disabled | |
4319 | * for just this mount. | |
4320 | */ | |
4321 | reset_cifs_unix_caps(*xid, tcon, cifs_sb, vol); | |
4322 | if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) && | |
4323 | (le64_to_cpu(tcon->fsUnixInfo.Capability) & | |
4324 | CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) | |
4325 | return -EACCES; | |
4326 | } else | |
4327 | tcon->unix_ext = 0; /* server does not support them */ | |
4328 | ||
4329 | /* do not care if a following call succeed - informational */ | |
1981ebaa | 4330 | if (!tcon->pipe && server->ops->qfs_tcon) { |
0f060936 | 4331 | server->ops->qfs_tcon(*xid, tcon, cifs_sb); |
1981ebaa SF |
4332 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE) { |
4333 | if (tcon->fsDevInfo.DeviceCharacteristics & | |
52870d50 | 4334 | cpu_to_le32(FILE_READ_ONLY_DEVICE)) |
1981ebaa | 4335 | cifs_dbg(VFS, "mounted to read only share\n"); |
41e033fe SF |
4336 | else if ((cifs_sb->mnt_cifs_flags & |
4337 | CIFS_MOUNT_RW_CACHE) == 0) | |
1981ebaa | 4338 | cifs_dbg(VFS, "read only mount of RW share\n"); |
41e033fe | 4339 | /* no need to log a RW mount of a typical RW share */ |
1981ebaa SF |
4340 | } |
4341 | } | |
56c762eb PA |
4342 | |
4343 | cifs_sb->wsize = server->ops->negotiate_wsize(tcon, vol); | |
4344 | cifs_sb->rsize = server->ops->negotiate_rsize(tcon, vol); | |
4345 | ||
4346 | return 0; | |
4347 | } | |
4348 | ||
4349 | static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, | |
4350 | struct cifs_tcon *tcon) | |
4351 | { | |
4352 | struct tcon_link *tlink; | |
4353 | ||
4354 | /* hang the tcon off of the superblock */ | |
4355 | tlink = kzalloc(sizeof(*tlink), GFP_KERNEL); | |
4356 | if (tlink == NULL) | |
4357 | return -ENOMEM; | |
4358 | ||
4359 | tlink->tl_uid = ses->linux_uid; | |
4360 | tlink->tl_tcon = tcon; | |
4361 | tlink->tl_time = jiffies; | |
4362 | set_bit(TCON_LINK_MASTER, &tlink->tl_flags); | |
4363 | set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); | |
4364 | ||
4365 | cifs_sb->master_tlink = tlink; | |
4366 | spin_lock(&cifs_sb->tlink_tree_lock); | |
4367 | tlink_rb_insert(&cifs_sb->tlink_tree, tlink); | |
4368 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
4369 | ||
4370 | queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks, | |
4371 | TLINK_IDLE_EXPIRE); | |
4372 | return 0; | |
4373 | } | |
b9bce2e9 | 4374 | |
2d6d589d | 4375 | #ifdef CONFIG_CIFS_DFS_UPCALL |
6d3ea7e4 SF |
4376 | /* |
4377 | * cifs_build_path_to_root returns full path to root when we do not have an | |
4378 | * exiting connection (tcon) | |
4379 | */ | |
1bfe73c2 | 4380 | static char * |
b2a0fa15 | 4381 | build_unc_path_to_root(const struct smb_vol *vol, |
4a367dc0 | 4382 | const struct cifs_sb_info *cifs_sb, bool useppath) |
1bfe73c2 | 4383 | { |
b2a0fa15 | 4384 | char *full_path, *pos; |
4a367dc0 PA |
4385 | unsigned int pplen = useppath && vol->prepath ? |
4386 | strlen(vol->prepath) + 1 : 0; | |
b2a0fa15 | 4387 | unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1); |
1bfe73c2 | 4388 | |
340625e6 RS |
4389 | if (unc_len > MAX_TREE_SIZE) |
4390 | return ERR_PTR(-EINVAL); | |
4391 | ||
b2a0fa15 | 4392 | full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL); |
1bfe73c2 IM |
4393 | if (full_path == NULL) |
4394 | return ERR_PTR(-ENOMEM); | |
4395 | ||
340625e6 | 4396 | memcpy(full_path, vol->UNC, unc_len); |
b2a0fa15 JL |
4397 | pos = full_path + unc_len; |
4398 | ||
4399 | if (pplen) { | |
1fc29bac | 4400 | *pos = CIFS_DIR_SEP(cifs_sb); |
340625e6 | 4401 | memcpy(pos + 1, vol->prepath, pplen); |
b2a0fa15 JL |
4402 | pos += pplen; |
4403 | } | |
4404 | ||
4405 | *pos = '\0'; /* add trailing null */ | |
f87d39d9 | 4406 | convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb)); |
f96637be | 4407 | cifs_dbg(FYI, "%s: full_path=%s\n", __func__, full_path); |
1bfe73c2 IM |
4408 | return full_path; |
4409 | } | |
dd613945 | 4410 | |
1c780228 PA |
4411 | /** |
4412 | * expand_dfs_referral - Perform a dfs referral query and update the cifs_sb | |
4413 | * | |
dd613945 | 4414 | * |
046462ab SF |
4415 | * If a referral is found, cifs_sb->mountdata will be (re-)allocated |
4416 | * to a string containing updated options for the submount. Otherwise it | |
4417 | * will be left untouched. | |
dd613945 SF |
4418 | * |
4419 | * Returns the rc from get_dfs_path to the caller, which can be used to | |
4420 | * determine whether there were referrals. | |
4421 | */ | |
4422 | static int | |
b669f33c | 4423 | expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, |
dd613945 | 4424 | struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb, |
046462ab | 4425 | int check_prefix) |
dd613945 SF |
4426 | { |
4427 | int rc; | |
1c780228 | 4428 | struct dfs_info3_param referral = {0}; |
dd613945 SF |
4429 | char *full_path = NULL, *ref_path = NULL, *mdata = NULL; |
4430 | ||
8393072b AA |
4431 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) |
4432 | return -EREMOTE; | |
4433 | ||
4a367dc0 | 4434 | full_path = build_unc_path_to_root(volume_info, cifs_sb, true); |
dd613945 SF |
4435 | if (IS_ERR(full_path)) |
4436 | return PTR_ERR(full_path); | |
4437 | ||
4438 | /* For DFS paths, skip the first '\' of the UNC */ | |
4439 | ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1; | |
4440 | ||
1c780228 PA |
4441 | rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), |
4442 | ref_path, &referral, NULL); | |
4443 | if (!rc) { | |
dd613945 SF |
4444 | char *fake_devname = NULL; |
4445 | ||
4446 | mdata = cifs_compose_mount_options(cifs_sb->mountdata, | |
1c780228 | 4447 | full_path + 1, &referral, |
dd613945 | 4448 | &fake_devname); |
1c780228 | 4449 | free_dfs_info_param(&referral); |
046462ab | 4450 | |
dd613945 SF |
4451 | if (IS_ERR(mdata)) { |
4452 | rc = PTR_ERR(mdata); | |
4453 | mdata = NULL; | |
b9bce2e9 | 4454 | } else { |
56c762eb | 4455 | cifs_cleanup_volume_info_contents(volume_info); |
b9bce2e9 | 4456 | rc = cifs_setup_volume_info(volume_info, mdata, |
1c780228 | 4457 | fake_devname, false); |
dd613945 | 4458 | } |
b9bce2e9 JL |
4459 | kfree(fake_devname); |
4460 | kfree(cifs_sb->mountdata); | |
046462ab | 4461 | cifs_sb->mountdata = mdata; |
dd613945 SF |
4462 | } |
4463 | kfree(full_path); | |
4464 | return rc; | |
4465 | } | |
4a367dc0 PA |
4466 | |
4467 | static inline int get_next_dfs_tgt(const char *path, | |
4468 | struct dfs_cache_tgt_list *tgt_list, | |
4469 | struct dfs_cache_tgt_iterator **tgt_it) | |
4470 | { | |
4471 | if (!*tgt_it) | |
4472 | *tgt_it = dfs_cache_get_tgt_iterator(tgt_list); | |
4473 | else | |
4474 | *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it); | |
4475 | return !*tgt_it ? -EHOSTDOWN : 0; | |
4476 | } | |
4477 | ||
4478 | static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it, | |
4479 | struct smb_vol *fake_vol, struct smb_vol *vol) | |
4480 | { | |
4481 | const char *tgt = dfs_cache_get_tgt_name(tgt_it); | |
4482 | int len = strlen(tgt) + 2; | |
4483 | char *new_unc; | |
4484 | ||
4485 | new_unc = kmalloc(len, GFP_KERNEL); | |
4486 | if (!new_unc) | |
4487 | return -ENOMEM; | |
74ea5f98 | 4488 | scnprintf(new_unc, len, "\\%s", tgt); |
4a367dc0 PA |
4489 | |
4490 | kfree(vol->UNC); | |
4491 | vol->UNC = new_unc; | |
4492 | ||
4493 | if (fake_vol->prepath) { | |
4494 | kfree(vol->prepath); | |
4495 | vol->prepath = fake_vol->prepath; | |
4496 | fake_vol->prepath = NULL; | |
4497 | } | |
4498 | memcpy(&vol->dstaddr, &fake_vol->dstaddr, sizeof(vol->dstaddr)); | |
4499 | ||
4500 | return 0; | |
4501 | } | |
4502 | ||
4503 | static int setup_dfs_tgt_conn(const char *path, | |
4504 | const struct dfs_cache_tgt_iterator *tgt_it, | |
4505 | struct cifs_sb_info *cifs_sb, | |
4506 | struct smb_vol *vol, | |
4507 | unsigned int *xid, | |
4508 | struct TCP_Server_Info **server, | |
4509 | struct cifs_ses **ses, | |
4510 | struct cifs_tcon **tcon) | |
4511 | { | |
4512 | int rc; | |
4513 | struct dfs_info3_param ref = {0}; | |
4514 | char *mdata = NULL, *fake_devname = NULL; | |
d0959b08 | 4515 | struct smb_vol fake_vol = {NULL}; |
4a367dc0 PA |
4516 | |
4517 | cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path); | |
4518 | ||
4519 | rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref); | |
4520 | if (rc) | |
4521 | return rc; | |
4522 | ||
4523 | mdata = cifs_compose_mount_options(cifs_sb->mountdata, path, &ref, | |
4524 | &fake_devname); | |
4525 | free_dfs_info_param(&ref); | |
4526 | ||
4527 | if (IS_ERR(mdata)) { | |
4528 | rc = PTR_ERR(mdata); | |
4529 | mdata = NULL; | |
4530 | } else { | |
4531 | cifs_dbg(FYI, "%s: fake_devname: %s\n", __func__, fake_devname); | |
4532 | rc = cifs_setup_volume_info(&fake_vol, mdata, fake_devname, | |
4533 | false); | |
4534 | } | |
4535 | kfree(mdata); | |
4536 | kfree(fake_devname); | |
4537 | ||
4538 | if (!rc) { | |
4539 | /* | |
4540 | * We use a 'fake_vol' here because we need pass it down to the | |
4541 | * mount_{get,put} functions to test connection against new DFS | |
4542 | * targets. | |
4543 | */ | |
4544 | mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon); | |
4545 | rc = mount_get_conns(&fake_vol, cifs_sb, xid, server, ses, | |
4546 | tcon); | |
4547 | if (!rc) { | |
4548 | /* | |
4549 | * We were able to connect to new target server. | |
4550 | * Update current volume info with new target server. | |
4551 | */ | |
4552 | rc = update_vol_info(tgt_it, &fake_vol, vol); | |
4553 | } | |
4554 | } | |
4555 | cifs_cleanup_volume_info_contents(&fake_vol); | |
4556 | return rc; | |
4557 | } | |
4558 | ||
4559 | static int mount_do_dfs_failover(const char *path, | |
4560 | struct cifs_sb_info *cifs_sb, | |
4561 | struct smb_vol *vol, | |
4562 | struct cifs_ses *root_ses, | |
4563 | unsigned int *xid, | |
4564 | struct TCP_Server_Info **server, | |
4565 | struct cifs_ses **ses, | |
4566 | struct cifs_tcon **tcon) | |
4567 | { | |
4568 | int rc; | |
4569 | struct dfs_cache_tgt_list tgt_list; | |
4570 | struct dfs_cache_tgt_iterator *tgt_it = NULL; | |
4571 | ||
4572 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) | |
4573 | return -EOPNOTSUPP; | |
4574 | ||
4575 | rc = dfs_cache_noreq_find(path, NULL, &tgt_list); | |
4576 | if (rc) | |
4577 | return rc; | |
4578 | ||
4579 | for (;;) { | |
4580 | /* Get next DFS target server - if any */ | |
4581 | rc = get_next_dfs_tgt(path, &tgt_list, &tgt_it); | |
4582 | if (rc) | |
4583 | break; | |
4584 | /* Connect to next DFS target */ | |
4585 | rc = setup_dfs_tgt_conn(path, tgt_it, cifs_sb, vol, xid, server, | |
4586 | ses, tcon); | |
4587 | if (!rc || rc == -EACCES || rc == -EOPNOTSUPP) | |
4588 | break; | |
4589 | } | |
4590 | if (!rc) { | |
4591 | /* | |
4592 | * Update DFS target hint in DFS referral cache with the target | |
4593 | * server we successfully reconnected to. | |
4594 | */ | |
4595 | rc = dfs_cache_update_tgthint(*xid, root_ses ? root_ses : *ses, | |
4596 | cifs_sb->local_nls, | |
4597 | cifs_remap(cifs_sb), path, | |
4598 | tgt_it); | |
4599 | } | |
4600 | dfs_cache_free_tgts(&tgt_list); | |
4601 | return rc; | |
4602 | } | |
2d6d589d | 4603 | #endif |
1bfe73c2 | 4604 | |
5072010c | 4605 | int |
04db79b0 | 4606 | cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, |
c7c137b9 | 4607 | const char *devname, bool is_smb3) |
1da177e4 | 4608 | { |
724d9f1c | 4609 | int rc = 0; |
1da177e4 | 4610 | |
c7c137b9 | 4611 | if (cifs_parse_mount_options(mount_data, devname, volume_info, is_smb3)) |
04db79b0 | 4612 | return -EINVAL; |
1da177e4 | 4613 | |
7586b765 | 4614 | if (volume_info->nullauth) { |
f96637be | 4615 | cifs_dbg(FYI, "Anonymous login\n"); |
04febabc JL |
4616 | kfree(volume_info->username); |
4617 | volume_info->username = NULL; | |
7586b765 | 4618 | } else if (volume_info->username) { |
1da177e4 | 4619 | /* BB fixme parse for domain name here */ |
f96637be | 4620 | cifs_dbg(FYI, "Username: %s\n", volume_info->username); |
1da177e4 | 4621 | } else { |
f96637be | 4622 | cifs_dbg(VFS, "No username specified\n"); |
50c2f753 SF |
4623 | /* In userspace mount helper we can get user name from alternate |
4624 | locations such as env variables and files on disk */ | |
04db79b0 | 4625 | return -EINVAL; |
1da177e4 LT |
4626 | } |
4627 | ||
1da177e4 | 4628 | /* this is needed for ASCII cp to Unicode converts */ |
7586b765 | 4629 | if (volume_info->iocharset == NULL) { |
a5fc4ce0 JL |
4630 | /* load_nls_default cannot return null */ |
4631 | volume_info->local_nls = load_nls_default(); | |
1da177e4 | 4632 | } else { |
a5fc4ce0 JL |
4633 | volume_info->local_nls = load_nls(volume_info->iocharset); |
4634 | if (volume_info->local_nls == NULL) { | |
f96637be | 4635 | cifs_dbg(VFS, "CIFS mount error: iocharset %s not found\n", |
b6b38f70 | 4636 | volume_info->iocharset); |
04db79b0 | 4637 | return -ELIBACC; |
1da177e4 LT |
4638 | } |
4639 | } | |
724d9f1c | 4640 | |
724d9f1c PS |
4641 | return rc; |
4642 | } | |
4643 | ||
04db79b0 | 4644 | struct smb_vol * |
c7c137b9 | 4645 | cifs_get_volume_info(char *mount_data, const char *devname, bool is_smb3) |
04db79b0 JL |
4646 | { |
4647 | int rc; | |
4648 | struct smb_vol *volume_info; | |
4649 | ||
6ee9542a | 4650 | volume_info = kmalloc(sizeof(struct smb_vol), GFP_KERNEL); |
04db79b0 JL |
4651 | if (!volume_info) |
4652 | return ERR_PTR(-ENOMEM); | |
4653 | ||
c7c137b9 | 4654 | rc = cifs_setup_volume_info(volume_info, mount_data, devname, is_smb3); |
04db79b0 JL |
4655 | if (rc) { |
4656 | cifs_cleanup_volume_info(volume_info); | |
4657 | volume_info = ERR_PTR(rc); | |
4658 | } | |
4659 | ||
4660 | return volume_info; | |
4661 | } | |
4662 | ||
a6b5058f AA |
4663 | static int |
4664 | cifs_are_all_path_components_accessible(struct TCP_Server_Info *server, | |
4665 | unsigned int xid, | |
4666 | struct cifs_tcon *tcon, | |
4667 | struct cifs_sb_info *cifs_sb, | |
ce465bf9 RS |
4668 | char *full_path, |
4669 | int added_treename) | |
a6b5058f AA |
4670 | { |
4671 | int rc; | |
4672 | char *s; | |
4673 | char sep, tmp; | |
ce465bf9 | 4674 | int skip = added_treename ? 1 : 0; |
a6b5058f AA |
4675 | |
4676 | sep = CIFS_DIR_SEP(cifs_sb); | |
4677 | s = full_path; | |
4678 | ||
4679 | rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, ""); | |
4680 | while (rc == 0) { | |
4681 | /* skip separators */ | |
4682 | while (*s == sep) | |
4683 | s++; | |
4684 | if (!*s) | |
4685 | break; | |
4686 | /* next separator */ | |
4687 | while (*s && *s != sep) | |
4688 | s++; | |
ce465bf9 RS |
4689 | /* |
4690 | * if the treename is added, we then have to skip the first | |
4691 | * part within the separators | |
4692 | */ | |
4693 | if (skip) { | |
4694 | skip = 0; | |
4695 | continue; | |
4696 | } | |
a6b5058f AA |
4697 | /* |
4698 | * temporarily null-terminate the path at the end of | |
4699 | * the current component | |
4700 | */ | |
4701 | tmp = *s; | |
4702 | *s = 0; | |
4703 | rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, | |
4704 | full_path); | |
4705 | *s = tmp; | |
4706 | } | |
4707 | return rc; | |
4708 | } | |
4709 | ||
56c762eb PA |
4710 | /* |
4711 | * Check if path is remote (e.g. a DFS share). Return -EREMOTE if it is, | |
4712 | * otherwise 0. | |
4713 | */ | |
4714 | static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb_vol *vol, | |
4715 | const unsigned int xid, | |
4716 | struct TCP_Server_Info *server, | |
4717 | struct cifs_tcon *tcon) | |
724d9f1c | 4718 | { |
1daaae8f | 4719 | int rc; |
56c762eb | 4720 | char *full_path; |
dd854466 | 4721 | |
56c762eb PA |
4722 | if (!server->ops->is_path_accessible) |
4723 | return -EOPNOTSUPP; | |
724d9f1c | 4724 | |
56c762eb PA |
4725 | /* |
4726 | * cifs_build_path_to_root works only when we have a valid tcon | |
4727 | */ | |
4728 | full_path = cifs_build_path_to_root(vol, cifs_sb, tcon, | |
4729 | tcon->Flags & SMB_SHARE_IS_IN_DFS); | |
4730 | if (full_path == NULL) | |
4731 | return -ENOMEM; | |
724d9f1c | 4732 | |
56c762eb | 4733 | cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path); |
1da177e4 | 4734 | |
56c762eb PA |
4735 | rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, |
4736 | full_path); | |
4737 | if (rc != 0 && rc != -EREMOTE) { | |
4738 | kfree(full_path); | |
4739 | return rc; | |
b618f001 | 4740 | } |
592fafe6 | 4741 | |
56c762eb PA |
4742 | if (rc != -EREMOTE) { |
4743 | rc = cifs_are_all_path_components_accessible(server, xid, tcon, | |
ce465bf9 | 4744 | cifs_sb, full_path, tcon->Flags & SMB_SHARE_IS_IN_DFS); |
56c762eb | 4745 | if (rc != 0) { |
a0a3036b | 4746 | cifs_server_dbg(VFS, "cannot query dirs between root and final path, enabling CIFS_MOUNT_USE_PREFIX_PATH\n"); |
56c762eb PA |
4747 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; |
4748 | rc = 0; | |
4749 | } | |
d00c28de | 4750 | } |
1bfe73c2 | 4751 | |
56c762eb PA |
4752 | kfree(full_path); |
4753 | return rc; | |
4754 | } | |
ce558b0e | 4755 | |
56c762eb | 4756 | #ifdef CONFIG_CIFS_DFS_UPCALL |
5bb30a4d PAS |
4757 | static inline void set_root_tcon(struct cifs_sb_info *cifs_sb, |
4758 | struct cifs_tcon *tcon, | |
4759 | struct cifs_tcon **root) | |
4760 | { | |
4761 | spin_lock(&cifs_tcp_ses_lock); | |
4762 | tcon->tc_count++; | |
4763 | tcon->remap = cifs_remap(cifs_sb); | |
4764 | spin_unlock(&cifs_tcp_ses_lock); | |
4765 | *root = tcon; | |
4766 | } | |
4767 | ||
56c762eb PA |
4768 | int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) |
4769 | { | |
4770 | int rc = 0; | |
4771 | unsigned int xid; | |
4772 | struct cifs_ses *ses; | |
4a367dc0 | 4773 | struct cifs_tcon *root_tcon = NULL; |
56c762eb PA |
4774 | struct cifs_tcon *tcon = NULL; |
4775 | struct TCP_Server_Info *server; | |
4a367dc0 | 4776 | char *root_path = NULL, *full_path = NULL; |
5072010c | 4777 | char *old_mountdata, *origin_mountdata = NULL; |
56c762eb | 4778 | int count; |
c18c842b | 4779 | |
56c762eb PA |
4780 | rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon); |
4781 | if (!rc && tcon) { | |
4a367dc0 PA |
4782 | /* If not a standalone DFS root, then check if path is remote */ |
4783 | rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, | |
4784 | cifs_remap(cifs_sb), vol->UNC + 1, NULL, | |
4785 | NULL); | |
4786 | if (rc) { | |
4787 | rc = is_path_remote(cifs_sb, vol, xid, server, tcon); | |
4788 | if (!rc) | |
4789 | goto out; | |
4790 | if (rc != -EREMOTE) | |
4791 | goto error; | |
4792 | } | |
56c762eb | 4793 | } |
4a367dc0 PA |
4794 | /* |
4795 | * If first DFS target server went offline and we failed to connect it, | |
4796 | * server and ses pointers are NULL at this point, though we still have | |
4797 | * chance to get a cached DFS referral in expand_dfs_referral() and | |
4798 | * retry next target available in it. | |
4799 | * | |
4800 | * If a NULL ses ptr is passed to dfs_cache_find(), a lookup will be | |
4801 | * performed against DFS path and *no* requests will be sent to server | |
4802 | * for any new DFS referrals. Hence it's safe to skip checking whether | |
4803 | * server or ses ptr is NULL. | |
4804 | */ | |
4805 | if (rc == -EACCES || rc == -EOPNOTSUPP) | |
56c762eb | 4806 | goto error; |
6848b733 | 4807 | |
4a367dc0 PA |
4808 | root_path = build_unc_path_to_root(vol, cifs_sb, false); |
4809 | if (IS_ERR(root_path)) { | |
4810 | rc = PTR_ERR(root_path); | |
4811 | root_path = NULL; | |
4812 | goto error; | |
4813 | } | |
f7910cbd | 4814 | |
93d5cb51 PA |
4815 | full_path = build_unc_path_to_root(vol, cifs_sb, true); |
4816 | if (IS_ERR(full_path)) { | |
4817 | rc = PTR_ERR(full_path); | |
4818 | full_path = NULL; | |
4819 | goto error; | |
4820 | } | |
c1508ca2 SF |
4821 | /* |
4822 | * Perform an unconditional check for whether there are DFS | |
4823 | * referrals for this path without prefix, to provide support | |
4824 | * for DFS referrals from w2k8 servers which don't seem to respond | |
4825 | * with PATH_NOT_COVERED to requests that include the prefix. | |
4826 | * Chase the referral if found, otherwise continue normally. | |
4827 | */ | |
56c762eb PA |
4828 | old_mountdata = cifs_sb->mountdata; |
4829 | (void)expand_dfs_referral(xid, ses, vol, cifs_sb, false); | |
4830 | ||
4831 | if (cifs_sb->mountdata == NULL) { | |
4832 | rc = -ENOENT; | |
4833 | goto error; | |
c1508ca2 | 4834 | } |
c1508ca2 | 4835 | |
5072010c PAS |
4836 | /* Save DFS root volume information for DFS refresh worker */ |
4837 | origin_mountdata = kstrndup(cifs_sb->mountdata, | |
4838 | strlen(cifs_sb->mountdata), GFP_KERNEL); | |
4839 | if (!origin_mountdata) { | |
4840 | rc = -ENOMEM; | |
4841 | goto error; | |
4842 | } | |
4843 | ||
56c762eb PA |
4844 | if (cifs_sb->mountdata != old_mountdata) { |
4845 | /* If we were redirected, reconnect to new target server */ | |
4846 | mount_put_conns(cifs_sb, xid, server, ses, tcon); | |
4847 | rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon); | |
4848 | } | |
4849 | if (rc) { | |
4850 | if (rc == -EACCES || rc == -EOPNOTSUPP) | |
4851 | goto error; | |
4a367dc0 PA |
4852 | /* Perform DFS failover to any other DFS targets */ |
4853 | rc = mount_do_dfs_failover(root_path + 1, cifs_sb, vol, NULL, | |
4854 | &xid, &server, &ses, &tcon); | |
4855 | if (rc) | |
4856 | goto error; | |
56c762eb PA |
4857 | } |
4858 | ||
4a367dc0 PA |
4859 | kfree(root_path); |
4860 | root_path = build_unc_path_to_root(vol, cifs_sb, false); | |
4861 | if (IS_ERR(root_path)) { | |
4862 | rc = PTR_ERR(root_path); | |
4863 | root_path = NULL; | |
4864 | goto error; | |
4865 | } | |
4866 | /* Cache out resolved root server */ | |
4867 | (void)dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), | |
4868 | root_path + 1, NULL, NULL); | |
5bb30a4d | 4869 | kfree(root_path); |
4a367dc0 | 4870 | root_path = NULL; |
4a367dc0 | 4871 | |
5bb30a4d | 4872 | set_root_tcon(cifs_sb, tcon, &root_tcon); |
4a367dc0 | 4873 | |
56c762eb PA |
4874 | for (count = 1; ;) { |
4875 | if (!rc && tcon) { | |
4876 | rc = is_path_remote(cifs_sb, vol, xid, server, tcon); | |
4877 | if (!rc || rc != -EREMOTE) | |
4878 | break; | |
68889f26 | 4879 | } |
6d3ea7e4 | 4880 | /* |
56c762eb PA |
4881 | * BB: when we implement proper loop detection, |
4882 | * we will remove this check. But now we need it | |
4883 | * to prevent an indefinite loop if 'DFS tree' is | |
4884 | * misconfigured (i.e. has loops). | |
6d3ea7e4 | 4885 | */ |
56c762eb | 4886 | if (count++ > MAX_NESTED_LINKS) { |
5c2503a8 | 4887 | rc = -ELOOP; |
56c762eb | 4888 | break; |
5c2503a8 | 4889 | } |
1bfe73c2 | 4890 | |
4a367dc0 PA |
4891 | kfree(full_path); |
4892 | full_path = build_unc_path_to_root(vol, cifs_sb, true); | |
4893 | if (IS_ERR(full_path)) { | |
4894 | rc = PTR_ERR(full_path); | |
4895 | full_path = NULL; | |
4896 | break; | |
4897 | } | |
4898 | ||
56c762eb | 4899 | old_mountdata = cifs_sb->mountdata; |
4a367dc0 | 4900 | rc = expand_dfs_referral(xid, root_tcon->ses, vol, cifs_sb, |
56c762eb PA |
4901 | true); |
4902 | if (rc) | |
4903 | break; | |
7b91e266 | 4904 | |
56c762eb PA |
4905 | if (cifs_sb->mountdata != old_mountdata) { |
4906 | mount_put_conns(cifs_sb, xid, server, ses, tcon); | |
4907 | rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, | |
4908 | &tcon); | |
5bb30a4d PAS |
4909 | /* |
4910 | * Ensure that DFS referrals go through new root server. | |
4911 | */ | |
4912 | if (!rc && tcon && | |
4913 | (tcon->share_flags & (SHI1005_FLAGS_DFS | | |
4914 | SHI1005_FLAGS_DFS_ROOT))) { | |
4915 | cifs_put_tcon(root_tcon); | |
4916 | set_root_tcon(cifs_sb, tcon, &root_tcon); | |
4917 | } | |
56c762eb PA |
4918 | } |
4919 | if (rc) { | |
4a367dc0 PA |
4920 | if (rc == -EACCES || rc == -EOPNOTSUPP) |
4921 | break; | |
4922 | /* Perform DFS failover to any other DFS targets */ | |
4923 | rc = mount_do_dfs_failover(full_path + 1, cifs_sb, vol, | |
4924 | root_tcon->ses, &xid, | |
4925 | &server, &ses, &tcon); | |
56c762eb PA |
4926 | if (rc == -EACCES || rc == -EOPNOTSUPP || !server || |
4927 | !ses) | |
4928 | goto error; | |
1bfe73c2 IM |
4929 | } |
4930 | } | |
4a367dc0 | 4931 | cifs_put_tcon(root_tcon); |
1bfe73c2 | 4932 | |
9d002df4 | 4933 | if (rc) |
56c762eb | 4934 | goto error; |
9d002df4 | 4935 | |
93d5cb51 PA |
4936 | spin_lock(&cifs_tcp_ses_lock); |
4937 | if (!tcon->dfs_path) { | |
4938 | /* Save full path in new tcon to do failover when reconnecting tcons */ | |
4939 | tcon->dfs_path = full_path; | |
4940 | full_path = NULL; | |
4941 | tcon->remap = cifs_remap(cifs_sb); | |
4942 | } | |
4943 | cifs_sb->origin_fullpath = kstrndup(tcon->dfs_path, | |
2f0a6174 Y |
4944 | strlen(tcon->dfs_path), |
4945 | GFP_ATOMIC); | |
93d5cb51 PA |
4946 | if (!cifs_sb->origin_fullpath) { |
4947 | spin_unlock(&cifs_tcp_ses_lock); | |
4948 | rc = -ENOMEM; | |
4949 | goto error; | |
4950 | } | |
4951 | spin_unlock(&cifs_tcp_ses_lock); | |
4952 | ||
5072010c | 4953 | rc = dfs_cache_add_vol(origin_mountdata, vol, cifs_sb->origin_fullpath); |
e511d317 PA |
4954 | if (rc) { |
4955 | kfree(cifs_sb->origin_fullpath); | |
4956 | goto error; | |
4957 | } | |
5fc7fcd0 AA |
4958 | /* |
4959 | * After reconnecting to a different server, unique ids won't | |
4960 | * match anymore, so we disable serverino. This prevents | |
4961 | * dentry revalidation to think the dentry are stale (ESTALE). | |
4962 | */ | |
4963 | cifs_autodisable_serverino(cifs_sb); | |
bacd704a PAS |
4964 | /* |
4965 | * Force the use of prefix path to support failover on DFS paths that | |
4966 | * resolve to targets that have different prefix paths. | |
4967 | */ | |
4968 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; | |
4969 | kfree(cifs_sb->prepath); | |
4970 | cifs_sb->prepath = vol->prepath; | |
4971 | vol->prepath = NULL; | |
4972 | ||
56c762eb PA |
4973 | out: |
4974 | free_xid(xid); | |
d70e9fa5 | 4975 | cifs_try_adding_channels(ses); |
56c762eb | 4976 | return mount_setup_tlink(cifs_sb, ses, tcon); |
9d002df4 | 4977 | |
56c762eb | 4978 | error: |
4a367dc0 PA |
4979 | kfree(full_path); |
4980 | kfree(root_path); | |
5072010c | 4981 | kfree(origin_mountdata); |
56c762eb PA |
4982 | mount_put_conns(cifs_sb, xid, server, ses, tcon); |
4983 | return rc; | |
4984 | } | |
4985 | #else | |
4986 | int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol) | |
4987 | { | |
4988 | int rc = 0; | |
4989 | unsigned int xid; | |
4990 | struct cifs_ses *ses; | |
4991 | struct cifs_tcon *tcon; | |
4992 | struct TCP_Server_Info *server; | |
413e661c | 4993 | |
56c762eb PA |
4994 | rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon); |
4995 | if (rc) | |
4996 | goto error; | |
2de970ff | 4997 | |
56c762eb PA |
4998 | if (tcon) { |
4999 | rc = is_path_remote(cifs_sb, vol, xid, server, tcon); | |
5000 | if (rc == -EREMOTE) | |
5001 | rc = -EOPNOTSUPP; | |
5002 | if (rc) | |
5003 | goto error; | |
1bfe73c2 IM |
5004 | } |
5005 | ||
6d5786a3 | 5006 | free_xid(xid); |
56c762eb PA |
5007 | |
5008 | return mount_setup_tlink(cifs_sb, ses, tcon); | |
5009 | ||
5010 | error: | |
5011 | mount_put_conns(cifs_sb, xid, server, ses, tcon); | |
1da177e4 LT |
5012 | return rc; |
5013 | } | |
56c762eb | 5014 | #endif |
1da177e4 | 5015 | |
8d1bca32 | 5016 | /* |
b327a717 | 5017 | * Issue a TREE_CONNECT request. |
8d1bca32 | 5018 | */ |
1da177e4 | 5019 | int |
2e6e02ab | 5020 | CIFSTCon(const unsigned int xid, struct cifs_ses *ses, |
96daf2b0 | 5021 | const char *tree, struct cifs_tcon *tcon, |
1da177e4 LT |
5022 | const struct nls_table *nls_codepage) |
5023 | { | |
5024 | struct smb_hdr *smb_buffer; | |
5025 | struct smb_hdr *smb_buffer_response; | |
5026 | TCONX_REQ *pSMB; | |
5027 | TCONX_RSP *pSMBr; | |
5028 | unsigned char *bcc_ptr; | |
5029 | int rc = 0; | |
690c522f JL |
5030 | int length; |
5031 | __u16 bytes_left, count; | |
1da177e4 LT |
5032 | |
5033 | if (ses == NULL) | |
5034 | return -EIO; | |
5035 | ||
5036 | smb_buffer = cifs_buf_get(); | |
ca43e3be | 5037 | if (smb_buffer == NULL) |
1da177e4 | 5038 | return -ENOMEM; |
ca43e3be | 5039 | |
1da177e4 LT |
5040 | smb_buffer_response = smb_buffer; |
5041 | ||
5042 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, | |
5043 | NULL /*no tid */ , 4 /*wct */ ); | |
1982c344 | 5044 | |
88257360 | 5045 | smb_buffer->Mid = get_next_mid(ses->server); |
1da177e4 LT |
5046 | smb_buffer->Uid = ses->Suid; |
5047 | pSMB = (TCONX_REQ *) smb_buffer; | |
5048 | pSMBr = (TCONX_RSP *) smb_buffer_response; | |
5049 | ||
5050 | pSMB->AndXCommand = 0xFF; | |
5051 | pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); | |
1da177e4 | 5052 | bcc_ptr = &pSMB->Password[0]; |
b327a717 | 5053 | if (tcon->pipe || (ses->server->sec_mode & SECMODE_USER)) { |
eeac8047 | 5054 | pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ |
7c7b25bc | 5055 | *bcc_ptr = 0; /* password is null byte */ |
eeac8047 | 5056 | bcc_ptr++; /* skip password */ |
7c7b25bc | 5057 | /* already aligned so no need to do it below */ |
eeac8047 | 5058 | } else { |
540b2e37 | 5059 | pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE); |
eeac8047 SF |
5060 | /* BB FIXME add code to fail this if NTLMv2 or Kerberos |
5061 | specified as required (when that support is added to | |
5062 | the vfs in the future) as only NTLM or the much | |
7c7b25bc | 5063 | weaker LANMAN (which we do not send by default) is accepted |
eeac8047 SF |
5064 | by Samba (not sure whether other servers allow |
5065 | NTLMv2 password here) */ | |
7c7b25bc | 5066 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
04912d6a | 5067 | if ((global_secflags & CIFSSEC_MAY_LANMAN) && |
3f618223 | 5068 | (ses->sectype == LANMAN)) |
d3ba50b1 | 5069 | calc_lanman_hash(tcon->password, ses->server->cryptkey, |
96daf2b0 | 5070 | ses->server->sec_mode & |
4e53a3fb JL |
5071 | SECMODE_PW_ENCRYPT ? true : false, |
5072 | bcc_ptr); | |
7c7b25bc SF |
5073 | else |
5074 | #endif /* CIFS_WEAK_PW_HASH */ | |
ee2c9258 | 5075 | rc = SMBNTencrypt(tcon->password, ses->server->cryptkey, |
9ef5992e | 5076 | bcc_ptr, nls_codepage); |
f3a31a2b SF |
5077 | if (rc) { |
5078 | cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n", | |
5079 | __func__, rc); | |
5080 | cifs_buf_release(smb_buffer); | |
5081 | return rc; | |
5082 | } | |
eeac8047 | 5083 | |
540b2e37 | 5084 | bcc_ptr += CIFS_AUTH_RESP_SIZE; |
fb8c4b14 | 5085 | if (ses->capabilities & CAP_UNICODE) { |
7c7b25bc SF |
5086 | /* must align unicode strings */ |
5087 | *bcc_ptr = 0; /* null byte password */ | |
5088 | bcc_ptr++; | |
5089 | } | |
eeac8047 | 5090 | } |
1da177e4 | 5091 | |
38d77c50 | 5092 | if (ses->server->sign) |
1da177e4 LT |
5093 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
5094 | ||
5095 | if (ses->capabilities & CAP_STATUS32) { | |
5096 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | |
5097 | } | |
5098 | if (ses->capabilities & CAP_DFS) { | |
5099 | smb_buffer->Flags2 |= SMBFLG2_DFS; | |
5100 | } | |
5101 | if (ses->capabilities & CAP_UNICODE) { | |
5102 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | |
5103 | length = | |
acbbb76a | 5104 | cifs_strtoUTF16((__le16 *) bcc_ptr, tree, |
50c2f753 | 5105 | 6 /* max utf8 char length in bytes */ * |
a878fb22 SF |
5106 | (/* server len*/ + 256 /* share len */), nls_codepage); |
5107 | bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */ | |
1da177e4 LT |
5108 | bcc_ptr += 2; /* skip trailing null */ |
5109 | } else { /* ASCII */ | |
1da177e4 LT |
5110 | strcpy(bcc_ptr, tree); |
5111 | bcc_ptr += strlen(tree) + 1; | |
5112 | } | |
5113 | strcpy(bcc_ptr, "?????"); | |
5114 | bcc_ptr += strlen("?????"); | |
5115 | bcc_ptr += 1; | |
5116 | count = bcc_ptr - &pSMB->Password[0]; | |
be8e3b00 SF |
5117 | pSMB->hdr.smb_buf_length = cpu_to_be32(be32_to_cpu( |
5118 | pSMB->hdr.smb_buf_length) + count); | |
1da177e4 LT |
5119 | pSMB->ByteCount = cpu_to_le16(count); |
5120 | ||
133672ef | 5121 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, |
7749981e | 5122 | 0); |
1da177e4 | 5123 | |
1da177e4 | 5124 | /* above now done in SendReceive */ |
b327a717 | 5125 | if (rc == 0) { |
0e0d2cf3 SF |
5126 | bool is_unicode; |
5127 | ||
1da177e4 | 5128 | tcon->tidStatus = CifsGood; |
3b795210 | 5129 | tcon->need_reconnect = false; |
1da177e4 LT |
5130 | tcon->tid = smb_buffer_response->Tid; |
5131 | bcc_ptr = pByteArea(smb_buffer_response); | |
690c522f | 5132 | bytes_left = get_bcc(smb_buffer_response); |
cc20c031 | 5133 | length = strnlen(bcc_ptr, bytes_left - 2); |
0e0d2cf3 SF |
5134 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) |
5135 | is_unicode = true; | |
5136 | else | |
5137 | is_unicode = false; | |
5138 | ||
cc20c031 | 5139 | |
50c2f753 | 5140 | /* skip service field (NB: this field is always ASCII) */ |
7f8ed420 SF |
5141 | if (length == 3) { |
5142 | if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && | |
5143 | (bcc_ptr[2] == 'C')) { | |
f96637be | 5144 | cifs_dbg(FYI, "IPC connection\n"); |
b327a717 AA |
5145 | tcon->ipc = true; |
5146 | tcon->pipe = true; | |
7f8ed420 SF |
5147 | } |
5148 | } else if (length == 2) { | |
5149 | if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) { | |
5150 | /* the most common case */ | |
f96637be | 5151 | cifs_dbg(FYI, "disk share connection\n"); |
7f8ed420 SF |
5152 | } |
5153 | } | |
50c2f753 | 5154 | bcc_ptr += length + 1; |
cc20c031 | 5155 | bytes_left -= (length + 1); |
46b51d08 | 5156 | strlcpy(tcon->treeName, tree, sizeof(tcon->treeName)); |
cc20c031 JL |
5157 | |
5158 | /* mostly informational -- no need to fail on error here */ | |
90a98b2f | 5159 | kfree(tcon->nativeFileSystem); |
acbbb76a | 5160 | tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr, |
0e0d2cf3 | 5161 | bytes_left, is_unicode, |
cc20c031 JL |
5162 | nls_codepage); |
5163 | ||
f96637be | 5164 | cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem); |
cc20c031 | 5165 | |
fb8c4b14 | 5166 | if ((smb_buffer_response->WordCount == 3) || |
1a4e15a0 SF |
5167 | (smb_buffer_response->WordCount == 7)) |
5168 | /* field is in same location */ | |
3979877e SF |
5169 | tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); |
5170 | else | |
5171 | tcon->Flags = 0; | |
f96637be | 5172 | cifs_dbg(FYI, "Tcon flags: 0x%x\n", tcon->Flags); |
1da177e4 LT |
5173 | } |
5174 | ||
a8a11d39 | 5175 | cifs_buf_release(smb_buffer); |
1da177e4 LT |
5176 | return rc; |
5177 | } | |
5178 | ||
2e32cf5e AV |
5179 | static void delayed_free(struct rcu_head *p) |
5180 | { | |
5181 | struct cifs_sb_info *sbi = container_of(p, struct cifs_sb_info, rcu); | |
5182 | unload_nls(sbi->local_nls); | |
5183 | kfree(sbi); | |
5184 | } | |
5185 | ||
2a9b9951 AV |
5186 | void |
5187 | cifs_umount(struct cifs_sb_info *cifs_sb) | |
1da177e4 | 5188 | { |
b647c35f JL |
5189 | struct rb_root *root = &cifs_sb->tlink_tree; |
5190 | struct rb_node *node; | |
5191 | struct tcon_link *tlink; | |
9d002df4 | 5192 | |
2de970ff JL |
5193 | cancel_delayed_work_sync(&cifs_sb->prune_tlinks); |
5194 | ||
b647c35f JL |
5195 | spin_lock(&cifs_sb->tlink_tree_lock); |
5196 | while ((node = rb_first(root))) { | |
5197 | tlink = rb_entry(node, struct tcon_link, tl_rbnode); | |
5198 | cifs_get_tlink(tlink); | |
5199 | clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); | |
5200 | rb_erase(node, root); | |
1da177e4 | 5201 | |
b647c35f JL |
5202 | spin_unlock(&cifs_sb->tlink_tree_lock); |
5203 | cifs_put_tlink(tlink); | |
5204 | spin_lock(&cifs_sb->tlink_tree_lock); | |
5205 | } | |
5206 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
50c2f753 | 5207 | |
d757d71b | 5208 | kfree(cifs_sb->mountdata); |
a6b5058f | 5209 | kfree(cifs_sb->prepath); |
93d5cb51 | 5210 | #ifdef CONFIG_CIFS_DFS_UPCALL |
e511d317 | 5211 | dfs_cache_del_vol(cifs_sb->origin_fullpath); |
93d5cb51 PA |
5212 | kfree(cifs_sb->origin_fullpath); |
5213 | #endif | |
2e32cf5e | 5214 | call_rcu(&cifs_sb->rcu, delayed_free); |
50c2f753 | 5215 | } |
1da177e4 | 5216 | |
286170aa PS |
5217 | int |
5218 | cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses) | |
1da177e4 LT |
5219 | { |
5220 | int rc = 0; | |
f6a6bf7c | 5221 | struct TCP_Server_Info *server = cifs_ses_server(ses); |
1da177e4 | 5222 | |
286170aa PS |
5223 | if (!server->ops->need_neg || !server->ops->negotiate) |
5224 | return -ENOSYS; | |
5225 | ||
198b5682 | 5226 | /* only send once per connect */ |
286170aa | 5227 | if (!server->ops->need_neg(server)) |
198b5682 JL |
5228 | return 0; |
5229 | ||
286170aa | 5230 | rc = server->ops->negotiate(xid, ses); |
198b5682 JL |
5231 | if (rc == 0) { |
5232 | spin_lock(&GlobalMid_Lock); | |
7fdbaa1b | 5233 | if (server->tcpStatus == CifsNeedNegotiate) |
198b5682 JL |
5234 | server->tcpStatus = CifsGood; |
5235 | else | |
5236 | rc = -EHOSTDOWN; | |
5237 | spin_unlock(&GlobalMid_Lock); | |
198b5682 JL |
5238 | } |
5239 | ||
5240 | return rc; | |
5241 | } | |
5242 | ||
58c45c58 PS |
5243 | int |
5244 | cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, | |
5245 | struct nls_table *nls_info) | |
198b5682 | 5246 | { |
58c45c58 | 5247 | int rc = -ENOSYS; |
f6a6bf7c | 5248 | struct TCP_Server_Info *server = cifs_ses_server(ses); |
26b994fa | 5249 | |
d70e9fa5 AA |
5250 | if (!ses->binding) { |
5251 | ses->capabilities = server->capabilities; | |
5252 | if (linuxExtEnabled == 0) | |
5253 | ses->capabilities &= (~server->vals->cap_unix); | |
5254 | ||
5255 | if (ses->auth_key.response) { | |
5256 | cifs_dbg(FYI, "Free previous auth_key.response = %p\n", | |
5257 | ses->auth_key.response); | |
5258 | kfree(ses->auth_key.response); | |
5259 | ses->auth_key.response = NULL; | |
5260 | ses->auth_key.len = 0; | |
5261 | } | |
5262 | } | |
20418acd | 5263 | |
f96637be | 5264 | cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n", |
96daf2b0 | 5265 | server->sec_mode, server->capabilities, server->timeAdj); |
cb7691b6 | 5266 | |
58c45c58 PS |
5267 | if (server->ops->sess_setup) |
5268 | rc = server->ops->sess_setup(xid, ses, nls_info); | |
5269 | ||
d4e63bd6 | 5270 | if (rc) |
afe6f653 | 5271 | cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc); |
21e73393 | 5272 | |
1da177e4 LT |
5273 | return rc; |
5274 | } | |
5275 | ||
8a8798a5 JL |
5276 | static int |
5277 | cifs_set_vol_auth(struct smb_vol *vol, struct cifs_ses *ses) | |
5278 | { | |
3f618223 JL |
5279 | vol->sectype = ses->sectype; |
5280 | ||
5281 | /* krb5 is special, since we don't need username or pw */ | |
5282 | if (vol->sectype == Kerberos) | |
8a8798a5 | 5283 | return 0; |
8a8798a5 JL |
5284 | |
5285 | return cifs_set_cifscreds(vol, ses); | |
5286 | } | |
5287 | ||
96daf2b0 | 5288 | static struct cifs_tcon * |
6d4a0832 | 5289 | cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) |
9d002df4 | 5290 | { |
8a8798a5 | 5291 | int rc; |
96daf2b0 SF |
5292 | struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb); |
5293 | struct cifs_ses *ses; | |
5294 | struct cifs_tcon *tcon = NULL; | |
9d002df4 | 5295 | struct smb_vol *vol_info; |
9d002df4 JL |
5296 | |
5297 | vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL); | |
803ab977 DC |
5298 | if (vol_info == NULL) |
5299 | return ERR_PTR(-ENOMEM); | |
9d002df4 | 5300 | |
9d002df4 JL |
5301 | vol_info->local_nls = cifs_sb->local_nls; |
5302 | vol_info->linux_uid = fsuid; | |
5303 | vol_info->cred_uid = fsuid; | |
5304 | vol_info->UNC = master_tcon->treeName; | |
5305 | vol_info->retry = master_tcon->retry; | |
5306 | vol_info->nocase = master_tcon->nocase; | |
3d4ef9a1 | 5307 | vol_info->nohandlecache = master_tcon->nohandlecache; |
9d002df4 | 5308 | vol_info->local_lease = master_tcon->local_lease; |
ad35f169 | 5309 | vol_info->no_lease = master_tcon->no_lease; |
00dfbc2f PA |
5310 | vol_info->resilient = master_tcon->use_resilient; |
5311 | vol_info->persistent = master_tcon->use_persistent; | |
6b356f6c | 5312 | vol_info->handle_timeout = master_tcon->handle_timeout; |
9d002df4 | 5313 | vol_info->no_linux_ext = !master_tcon->unix_ext; |
5391b8e1 | 5314 | vol_info->linux_ext = master_tcon->posix_extensions; |
28e11bd8 JL |
5315 | vol_info->sectype = master_tcon->ses->sectype; |
5316 | vol_info->sign = master_tcon->ses->sign; | |
cc15461c | 5317 | vol_info->seal = master_tcon->seal; |
9d002df4 | 5318 | |
8a8798a5 JL |
5319 | rc = cifs_set_vol_auth(vol_info, master_tcon->ses); |
5320 | if (rc) { | |
5321 | tcon = ERR_PTR(rc); | |
5322 | goto out; | |
5323 | } | |
9d002df4 JL |
5324 | |
5325 | /* get a reference for the same TCP session */ | |
3f9bcca7 | 5326 | spin_lock(&cifs_tcp_ses_lock); |
9d002df4 | 5327 | ++master_tcon->ses->server->srv_count; |
3f9bcca7 | 5328 | spin_unlock(&cifs_tcp_ses_lock); |
9d002df4 JL |
5329 | |
5330 | ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info); | |
5331 | if (IS_ERR(ses)) { | |
96daf2b0 | 5332 | tcon = (struct cifs_tcon *)ses; |
53e0e11e | 5333 | cifs_put_tcp_session(master_tcon->ses->server, 0); |
9d002df4 JL |
5334 | goto out; |
5335 | } | |
5336 | ||
5337 | tcon = cifs_get_tcon(ses, vol_info); | |
5338 | if (IS_ERR(tcon)) { | |
5339 | cifs_put_smb_ses(ses); | |
5340 | goto out; | |
5341 | } | |
5342 | ||
29e20f9c | 5343 | if (cap_unix(ses)) |
9d002df4 | 5344 | reset_cifs_unix_caps(0, tcon, NULL, vol_info); |
b326614e | 5345 | |
9d002df4 | 5346 | out: |
8a8798a5 | 5347 | kfree(vol_info->username); |
453431a5 | 5348 | kfree_sensitive(vol_info->password); |
9d002df4 JL |
5349 | kfree(vol_info); |
5350 | ||
5351 | return tcon; | |
5352 | } | |
5353 | ||
96daf2b0 | 5354 | struct cifs_tcon * |
9d002df4 JL |
5355 | cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb) |
5356 | { | |
5357 | return tlink_tcon(cifs_sb_master_tlink(cifs_sb)); | |
5358 | } | |
5359 | ||
b647c35f JL |
5360 | /* find and return a tlink with given uid */ |
5361 | static struct tcon_link * | |
6d4a0832 | 5362 | tlink_rb_search(struct rb_root *root, kuid_t uid) |
b647c35f JL |
5363 | { |
5364 | struct rb_node *node = root->rb_node; | |
5365 | struct tcon_link *tlink; | |
5366 | ||
5367 | while (node) { | |
5368 | tlink = rb_entry(node, struct tcon_link, tl_rbnode); | |
5369 | ||
6d4a0832 | 5370 | if (uid_gt(tlink->tl_uid, uid)) |
b647c35f | 5371 | node = node->rb_left; |
6d4a0832 | 5372 | else if (uid_lt(tlink->tl_uid, uid)) |
b647c35f JL |
5373 | node = node->rb_right; |
5374 | else | |
5375 | return tlink; | |
5376 | } | |
5377 | return NULL; | |
5378 | } | |
5379 | ||
5380 | /* insert a tcon_link into the tree */ | |
5381 | static void | |
5382 | tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink) | |
5383 | { | |
5384 | struct rb_node **new = &(root->rb_node), *parent = NULL; | |
5385 | struct tcon_link *tlink; | |
5386 | ||
5387 | while (*new) { | |
5388 | tlink = rb_entry(*new, struct tcon_link, tl_rbnode); | |
5389 | parent = *new; | |
5390 | ||
6d4a0832 | 5391 | if (uid_gt(tlink->tl_uid, new_tlink->tl_uid)) |
b647c35f JL |
5392 | new = &((*new)->rb_left); |
5393 | else | |
5394 | new = &((*new)->rb_right); | |
5395 | } | |
5396 | ||
5397 | rb_link_node(&new_tlink->tl_rbnode, parent, new); | |
5398 | rb_insert_color(&new_tlink->tl_rbnode, root); | |
5399 | } | |
5400 | ||
9d002df4 JL |
5401 | /* |
5402 | * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the | |
5403 | * current task. | |
5404 | * | |
5405 | * If the superblock doesn't refer to a multiuser mount, then just return | |
5406 | * the master tcon for the mount. | |
5407 | * | |
6ef933a3 | 5408 | * First, search the rbtree for an existing tcon for this fsuid. If one |
9d002df4 JL |
5409 | * exists, then check to see if it's pending construction. If it is then wait |
5410 | * for construction to complete. Once it's no longer pending, check to see if | |
5411 | * it failed and either return an error or retry construction, depending on | |
5412 | * the timeout. | |
5413 | * | |
5414 | * If one doesn't exist then insert a new tcon_link struct into the tree and | |
5415 | * try to construct a new one. | |
5416 | */ | |
5417 | struct tcon_link * | |
5418 | cifs_sb_tlink(struct cifs_sb_info *cifs_sb) | |
5419 | { | |
5420 | int ret; | |
6d4a0832 | 5421 | kuid_t fsuid = current_fsuid(); |
9d002df4 JL |
5422 | struct tcon_link *tlink, *newtlink; |
5423 | ||
5424 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) | |
5425 | return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); | |
5426 | ||
5427 | spin_lock(&cifs_sb->tlink_tree_lock); | |
b647c35f | 5428 | tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid); |
9d002df4 JL |
5429 | if (tlink) |
5430 | cifs_get_tlink(tlink); | |
5431 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
5432 | ||
5433 | if (tlink == NULL) { | |
5434 | newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL); | |
5435 | if (newtlink == NULL) | |
5436 | return ERR_PTR(-ENOMEM); | |
b647c35f | 5437 | newtlink->tl_uid = fsuid; |
9d002df4 JL |
5438 | newtlink->tl_tcon = ERR_PTR(-EACCES); |
5439 | set_bit(TCON_LINK_PENDING, &newtlink->tl_flags); | |
5440 | set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags); | |
5441 | cifs_get_tlink(newtlink); | |
5442 | ||
9d002df4 JL |
5443 | spin_lock(&cifs_sb->tlink_tree_lock); |
5444 | /* was one inserted after previous search? */ | |
b647c35f | 5445 | tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid); |
9d002df4 JL |
5446 | if (tlink) { |
5447 | cifs_get_tlink(tlink); | |
5448 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
9d002df4 JL |
5449 | kfree(newtlink); |
5450 | goto wait_for_construction; | |
5451 | } | |
9d002df4 | 5452 | tlink = newtlink; |
b647c35f JL |
5453 | tlink_rb_insert(&cifs_sb->tlink_tree, tlink); |
5454 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
9d002df4 JL |
5455 | } else { |
5456 | wait_for_construction: | |
5457 | ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING, | |
9d002df4 JL |
5458 | TASK_INTERRUPTIBLE); |
5459 | if (ret) { | |
5460 | cifs_put_tlink(tlink); | |
74316201 | 5461 | return ERR_PTR(-ERESTARTSYS); |
9d002df4 JL |
5462 | } |
5463 | ||
5464 | /* if it's good, return it */ | |
5465 | if (!IS_ERR(tlink->tl_tcon)) | |
5466 | return tlink; | |
5467 | ||
5468 | /* return error if we tried this already recently */ | |
5469 | if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) { | |
5470 | cifs_put_tlink(tlink); | |
5471 | return ERR_PTR(-EACCES); | |
5472 | } | |
5473 | ||
5474 | if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags)) | |
5475 | goto wait_for_construction; | |
5476 | } | |
5477 | ||
5478 | tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid); | |
5479 | clear_bit(TCON_LINK_PENDING, &tlink->tl_flags); | |
5480 | wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING); | |
5481 | ||
5482 | if (IS_ERR(tlink->tl_tcon)) { | |
5483 | cifs_put_tlink(tlink); | |
5484 | return ERR_PTR(-EACCES); | |
5485 | } | |
5486 | ||
5487 | return tlink; | |
5488 | } | |
2de970ff JL |
5489 | |
5490 | /* | |
5491 | * periodic workqueue job that scans tcon_tree for a superblock and closes | |
5492 | * out tcons. | |
5493 | */ | |
5494 | static void | |
5495 | cifs_prune_tlinks(struct work_struct *work) | |
5496 | { | |
5497 | struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info, | |
5498 | prune_tlinks.work); | |
b647c35f | 5499 | struct rb_root *root = &cifs_sb->tlink_tree; |
37e12f55 | 5500 | struct rb_node *node; |
b647c35f JL |
5501 | struct rb_node *tmp; |
5502 | struct tcon_link *tlink; | |
2de970ff | 5503 | |
b647c35f JL |
5504 | /* |
5505 | * Because we drop the spinlock in the loop in order to put the tlink | |
5506 | * it's not guarded against removal of links from the tree. The only | |
5507 | * places that remove entries from the tree are this function and | |
5508 | * umounts. Because this function is non-reentrant and is canceled | |
5509 | * before umount can proceed, this is safe. | |
5510 | */ | |
5511 | spin_lock(&cifs_sb->tlink_tree_lock); | |
5512 | node = rb_first(root); | |
5513 | while (node != NULL) { | |
5514 | tmp = node; | |
5515 | node = rb_next(tmp); | |
5516 | tlink = rb_entry(tmp, struct tcon_link, tl_rbnode); | |
5517 | ||
5518 | if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) || | |
5519 | atomic_read(&tlink->tl_count) != 0 || | |
5520 | time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies)) | |
5521 | continue; | |
2de970ff | 5522 | |
b647c35f JL |
5523 | cifs_get_tlink(tlink); |
5524 | clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); | |
5525 | rb_erase(tmp, root); | |
5526 | ||
5527 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
5528 | cifs_put_tlink(tlink); | |
5529 | spin_lock(&cifs_sb->tlink_tree_lock); | |
5530 | } | |
5531 | spin_unlock(&cifs_sb->tlink_tree_lock); | |
2de970ff | 5532 | |
da472fc8 | 5533 | queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks, |
2de970ff JL |
5534 | TLINK_IDLE_EXPIRE); |
5535 | } |