blob: d1c3086d7ddd0137dcc98394b917de4aecb349fa [file] [log] [blame]
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001/*
2 * fs/cifs/connect.c
3 *
4 * Copyright (C) International Business Machines Corp., 2002,2011
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
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <linux/fs.h>
22#include <linux/net.h>
23#include <linux/string.h>
Olivier Deprez157378f2022-04-04 15:47:50 +020024#include <linux/sched/mm.h>
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000025#include <linux/sched/signal.h>
26#include <linux/list.h>
27#include <linux/wait.h>
28#include <linux/slab.h>
29#include <linux/pagemap.h>
30#include <linux/ctype.h>
31#include <linux/utsname.h>
32#include <linux/mempool.h>
33#include <linux/delay.h>
34#include <linux/completion.h>
35#include <linux/kthread.h>
36#include <linux/pagevec.h>
37#include <linux/freezer.h>
38#include <linux/namei.h>
39#include <linux/uuid.h>
40#include <linux/uaccess.h>
41#include <asm/processor.h>
42#include <linux/inet.h>
43#include <linux/module.h>
44#include <keys/user-type.h>
45#include <net/ipv6.h>
46#include <linux/parser.h>
47#include <linux/bvec.h>
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"
57#include "fscache.h"
58#include "smb2proto.h"
59#include "smbdirect.h"
David Brazdil0f672f62019-12-10 10:32:29 +000060#include "dns_resolve.h"
David Brazdil0f672f62019-12-10 10:32:29 +000061#ifdef CONFIG_CIFS_DFS_UPCALL
62#include "dfs_cache.h"
63#endif
Olivier Deprez157378f2022-04-04 15:47:50 +020064#include "fs_context.h"
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000065
66extern mempool_t *cifs_req_poolp;
67extern bool disable_legacy_dialects;
68
69/* FIXME: should these be tunable? */
70#define TLINK_ERROR_EXPIRE (1 * HZ)
71#define TLINK_IDLE_EXPIRE (600 * HZ)
72
Olivier Deprez157378f2022-04-04 15:47:50 +020073/* Drop the connection to not overload the server */
74#define NUM_STATUS_IO_TIMEOUT 5
75
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000076enum {
77 /* Mount options that take no arguments */
78 Opt_user_xattr, Opt_nouser_xattr,
79 Opt_forceuid, Opt_noforceuid,
80 Opt_forcegid, Opt_noforcegid,
David Brazdil0f672f62019-12-10 10:32:29 +000081 Opt_noblocksend, Opt_noautotune, Opt_nolease,
Olivier Deprez157378f2022-04-04 15:47:50 +020082 Opt_hard, Opt_soft, Opt_perm, Opt_noperm, Opt_nodelete,
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000083 Opt_mapposix, Opt_nomapposix,
84 Opt_mapchars, Opt_nomapchars, Opt_sfu,
85 Opt_nosfu, Opt_nodfs, Opt_posixpaths,
86 Opt_noposixpaths, Opt_nounix, Opt_unix,
87 Opt_nocase,
88 Opt_brl, Opt_nobrl,
89 Opt_handlecache, Opt_nohandlecache,
90 Opt_forcemandatorylock, Opt_setuidfromacl, Opt_setuids,
91 Opt_nosetuids, Opt_dynperm, Opt_nodynperm,
92 Opt_nohard, Opt_nosoft,
93 Opt_nointr, Opt_intr,
94 Opt_nostrictsync, Opt_strictsync,
95 Opt_serverino, Opt_noserverino,
96 Opt_rwpidforward, Opt_cifsacl, Opt_nocifsacl,
97 Opt_acl, Opt_noacl, Opt_locallease,
David Brazdil0f672f62019-12-10 10:32:29 +000098 Opt_sign, Opt_ignore_signature, Opt_seal, Opt_noac,
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000099 Opt_fsc, Opt_mfsymlinks,
100 Opt_multiuser, Opt_sloppy, Opt_nosharesock,
101 Opt_persistent, Opt_nopersistent,
102 Opt_resilient, Opt_noresilient,
David Brazdil0f672f62019-12-10 10:32:29 +0000103 Opt_domainauto, Opt_rdma, Opt_modesid, Opt_rootfs,
Olivier Deprez157378f2022-04-04 15:47:50 +0200104 Opt_multichannel, Opt_nomultichannel,
David Brazdil0f672f62019-12-10 10:32:29 +0000105 Opt_compress,
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000106
107 /* Mount options which take numeric value */
108 Opt_backupuid, Opt_backupgid, Opt_uid,
109 Opt_cruid, Opt_gid, Opt_file_mode,
110 Opt_dirmode, Opt_port,
David Brazdil0f672f62019-12-10 10:32:29 +0000111 Opt_min_enc_offload,
112 Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo,
113 Opt_echo_interval, Opt_max_credits, Opt_handletimeout,
Olivier Deprez157378f2022-04-04 15:47:50 +0200114 Opt_snapshot, Opt_max_channels,
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000115
116 /* Mount options which take string value */
117 Opt_user, Opt_pass, Opt_ip,
118 Opt_domain, Opt_srcaddr, Opt_iocharset,
119 Opt_netbiosname, Opt_servern,
120 Opt_ver, Opt_vers, Opt_sec, Opt_cache,
121
122 /* Mount options to be ignored */
123 Opt_ignore,
124
125 /* Options which could be blank */
126 Opt_blank_pass,
127 Opt_blank_user,
128 Opt_blank_ip,
129
130 Opt_err
131};
132
133static const match_table_t cifs_mount_option_tokens = {
134
135 { Opt_user_xattr, "user_xattr" },
136 { Opt_nouser_xattr, "nouser_xattr" },
137 { Opt_forceuid, "forceuid" },
138 { Opt_noforceuid, "noforceuid" },
139 { Opt_forcegid, "forcegid" },
140 { Opt_noforcegid, "noforcegid" },
141 { Opt_noblocksend, "noblocksend" },
142 { Opt_noautotune, "noautotune" },
David Brazdil0f672f62019-12-10 10:32:29 +0000143 { Opt_nolease, "nolease" },
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000144 { Opt_hard, "hard" },
145 { Opt_soft, "soft" },
146 { Opt_perm, "perm" },
147 { Opt_noperm, "noperm" },
Olivier Deprez157378f2022-04-04 15:47:50 +0200148 { Opt_nodelete, "nodelete" },
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000149 { Opt_mapchars, "mapchars" }, /* SFU style */
150 { Opt_nomapchars, "nomapchars" },
151 { Opt_mapposix, "mapposix" }, /* SFM style */
152 { Opt_nomapposix, "nomapposix" },
153 { Opt_sfu, "sfu" },
154 { Opt_nosfu, "nosfu" },
155 { Opt_nodfs, "nodfs" },
156 { Opt_posixpaths, "posixpaths" },
157 { Opt_noposixpaths, "noposixpaths" },
158 { Opt_nounix, "nounix" },
159 { Opt_nounix, "nolinux" },
160 { Opt_nounix, "noposix" },
161 { Opt_unix, "unix" },
162 { Opt_unix, "linux" },
163 { Opt_unix, "posix" },
164 { Opt_nocase, "nocase" },
165 { Opt_nocase, "ignorecase" },
166 { Opt_brl, "brl" },
167 { Opt_nobrl, "nobrl" },
168 { Opt_handlecache, "handlecache" },
169 { Opt_nohandlecache, "nohandlecache" },
170 { Opt_nobrl, "nolock" },
171 { Opt_forcemandatorylock, "forcemandatorylock" },
172 { Opt_forcemandatorylock, "forcemand" },
173 { Opt_setuids, "setuids" },
174 { Opt_nosetuids, "nosetuids" },
175 { Opt_setuidfromacl, "idsfromsid" },
176 { Opt_dynperm, "dynperm" },
177 { Opt_nodynperm, "nodynperm" },
178 { Opt_nohard, "nohard" },
179 { Opt_nosoft, "nosoft" },
180 { Opt_nointr, "nointr" },
181 { Opt_intr, "intr" },
182 { Opt_nostrictsync, "nostrictsync" },
183 { Opt_strictsync, "strictsync" },
184 { Opt_serverino, "serverino" },
185 { Opt_noserverino, "noserverino" },
186 { Opt_rwpidforward, "rwpidforward" },
David Brazdil0f672f62019-12-10 10:32:29 +0000187 { Opt_modesid, "modefromsid" },
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000188 { Opt_cifsacl, "cifsacl" },
189 { Opt_nocifsacl, "nocifsacl" },
190 { Opt_acl, "acl" },
191 { Opt_noacl, "noacl" },
192 { Opt_locallease, "locallease" },
193 { Opt_sign, "sign" },
David Brazdil0f672f62019-12-10 10:32:29 +0000194 { Opt_ignore_signature, "signloosely" },
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000195 { Opt_seal, "seal" },
196 { Opt_noac, "noac" },
197 { Opt_fsc, "fsc" },
198 { Opt_mfsymlinks, "mfsymlinks" },
199 { Opt_multiuser, "multiuser" },
200 { Opt_sloppy, "sloppy" },
201 { Opt_nosharesock, "nosharesock" },
202 { Opt_persistent, "persistenthandles"},
203 { Opt_nopersistent, "nopersistenthandles"},
204 { Opt_resilient, "resilienthandles"},
205 { Opt_noresilient, "noresilienthandles"},
206 { Opt_domainauto, "domainauto"},
207 { Opt_rdma, "rdma"},
Olivier Deprez157378f2022-04-04 15:47:50 +0200208 { Opt_multichannel, "multichannel" },
209 { Opt_nomultichannel, "nomultichannel" },
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000210
211 { Opt_backupuid, "backupuid=%s" },
212 { Opt_backupgid, "backupgid=%s" },
213 { Opt_uid, "uid=%s" },
214 { Opt_cruid, "cruid=%s" },
215 { Opt_gid, "gid=%s" },
216 { Opt_file_mode, "file_mode=%s" },
217 { Opt_dirmode, "dirmode=%s" },
218 { Opt_dirmode, "dir_mode=%s" },
219 { Opt_port, "port=%s" },
David Brazdil0f672f62019-12-10 10:32:29 +0000220 { Opt_min_enc_offload, "esize=%s" },
221 { Opt_blocksize, "bsize=%s" },
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000222 { Opt_rsize, "rsize=%s" },
223 { Opt_wsize, "wsize=%s" },
224 { Opt_actimeo, "actimeo=%s" },
David Brazdil0f672f62019-12-10 10:32:29 +0000225 { Opt_handletimeout, "handletimeout=%s" },
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000226 { Opt_echo_interval, "echo_interval=%s" },
227 { Opt_max_credits, "max_credits=%s" },
228 { Opt_snapshot, "snapshot=%s" },
Olivier Deprez157378f2022-04-04 15:47:50 +0200229 { Opt_max_channels, "max_channels=%s" },
David Brazdil0f672f62019-12-10 10:32:29 +0000230 { Opt_compress, "compress=%s" },
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000231
232 { Opt_blank_user, "user=" },
233 { Opt_blank_user, "username=" },
234 { Opt_user, "user=%s" },
235 { Opt_user, "username=%s" },
236 { Opt_blank_pass, "pass=" },
237 { Opt_blank_pass, "password=" },
238 { Opt_pass, "pass=%s" },
239 { Opt_pass, "password=%s" },
240 { Opt_blank_ip, "ip=" },
241 { Opt_blank_ip, "addr=" },
242 { Opt_ip, "ip=%s" },
243 { Opt_ip, "addr=%s" },
244 { Opt_ignore, "unc=%s" },
245 { Opt_ignore, "target=%s" },
246 { Opt_ignore, "path=%s" },
247 { Opt_domain, "dom=%s" },
248 { Opt_domain, "domain=%s" },
249 { Opt_domain, "workgroup=%s" },
250 { Opt_srcaddr, "srcaddr=%s" },
251 { Opt_ignore, "prefixpath=%s" },
252 { Opt_iocharset, "iocharset=%s" },
253 { Opt_netbiosname, "netbiosname=%s" },
254 { Opt_servern, "servern=%s" },
255 { Opt_ver, "ver=%s" },
256 { Opt_vers, "vers=%s" },
257 { Opt_sec, "sec=%s" },
258 { Opt_cache, "cache=%s" },
259
260 { Opt_ignore, "cred" },
261 { Opt_ignore, "credentials" },
262 { Opt_ignore, "cred=%s" },
263 { Opt_ignore, "credentials=%s" },
264 { Opt_ignore, "guest" },
265 { Opt_ignore, "rw" },
266 { Opt_ignore, "ro" },
267 { Opt_ignore, "suid" },
268 { Opt_ignore, "nosuid" },
269 { Opt_ignore, "exec" },
270 { Opt_ignore, "noexec" },
271 { Opt_ignore, "nodev" },
272 { Opt_ignore, "noauto" },
273 { Opt_ignore, "dev" },
274 { Opt_ignore, "mand" },
275 { Opt_ignore, "nomand" },
David Brazdil0f672f62019-12-10 10:32:29 +0000276 { Opt_ignore, "relatime" },
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000277 { Opt_ignore, "_netdev" },
David Brazdil0f672f62019-12-10 10:32:29 +0000278 { Opt_rootfs, "rootfs" },
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000279
280 { Opt_err, NULL }
281};
282
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000283static int ip_connect(struct TCP_Server_Info *server);
284static int generic_ip_connect(struct TCP_Server_Info *server);
285static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
286static void cifs_prune_tlinks(struct work_struct *work);
David Brazdil0f672f62019-12-10 10:32:29 +0000287static char *extract_hostname(const char *unc);
288
289/*
290 * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may
291 * get their ip addresses changed at some point.
292 *
293 * This should be called with server->srv_mutex held.
294 */
295#ifdef CONFIG_CIFS_DFS_UPCALL
296static int reconn_set_ipaddr(struct TCP_Server_Info *server)
297{
298 int rc;
299 int len;
300 char *unc, *ipaddr = NULL;
301
302 if (!server->hostname)
303 return -EINVAL;
304
305 len = strlen(server->hostname) + 3;
306
307 unc = kmalloc(len, GFP_KERNEL);
308 if (!unc) {
309 cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__);
310 return -ENOMEM;
311 }
312 scnprintf(unc, len, "\\\\%s", server->hostname);
313
314 rc = dns_resolve_server_name_to_ip(unc, &ipaddr);
315 kfree(unc);
316
317 if (rc < 0) {
318 cifs_dbg(FYI, "%s: failed to resolve server part of %s to IP: %d\n",
319 __func__, server->hostname, rc);
320 return rc;
321 }
322
Olivier Deprez0e641232021-09-23 10:07:05 +0200323 spin_lock(&cifs_tcp_ses_lock);
David Brazdil0f672f62019-12-10 10:32:29 +0000324 rc = cifs_convert_address((struct sockaddr *)&server->dstaddr, ipaddr,
325 strlen(ipaddr));
Olivier Deprez0e641232021-09-23 10:07:05 +0200326 spin_unlock(&cifs_tcp_ses_lock);
David Brazdil0f672f62019-12-10 10:32:29 +0000327 kfree(ipaddr);
328
329 return !rc ? -1 : 0;
330}
331#else
332static inline int reconn_set_ipaddr(struct TCP_Server_Info *server)
333{
334 return 0;
335}
336#endif
337
338#ifdef CONFIG_CIFS_DFS_UPCALL
David Brazdil0f672f62019-12-10 10:32:29 +0000339/* These functions must be called with server->srv_mutex held */
Olivier Deprez157378f2022-04-04 15:47:50 +0200340static void reconn_set_next_dfs_target(struct TCP_Server_Info *server,
341 struct cifs_sb_info *cifs_sb,
342 struct dfs_cache_tgt_list *tgt_list,
343 struct dfs_cache_tgt_iterator **tgt_it)
David Brazdil0f672f62019-12-10 10:32:29 +0000344{
345 const char *name;
346
Olivier Deprez157378f2022-04-04 15:47:50 +0200347 if (!cifs_sb || !cifs_sb->origin_fullpath)
David Brazdil0f672f62019-12-10 10:32:29 +0000348 return;
349
350 if (!*tgt_it) {
351 *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
352 } else {
353 *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it);
354 if (!*tgt_it)
355 *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
356 }
357
358 cifs_dbg(FYI, "%s: UNC: %s\n", __func__, cifs_sb->origin_fullpath);
359
360 name = dfs_cache_get_tgt_name(*tgt_it);
361
362 kfree(server->hostname);
363
364 server->hostname = extract_hostname(name);
365 if (IS_ERR(server->hostname)) {
366 cifs_dbg(FYI,
367 "%s: failed to extract hostname from target: %ld\n",
368 __func__, PTR_ERR(server->hostname));
369 }
370}
371
372static inline int reconn_setup_dfs_targets(struct cifs_sb_info *cifs_sb,
Olivier Deprez157378f2022-04-04 15:47:50 +0200373 struct dfs_cache_tgt_list *tl)
David Brazdil0f672f62019-12-10 10:32:29 +0000374{
375 if (!cifs_sb->origin_fullpath)
376 return -EOPNOTSUPP;
377 return dfs_cache_noreq_find(cifs_sb->origin_fullpath + 1, NULL, tl);
378}
379#endif
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000380
381/*
382 * cifs tcp session reconnection
383 *
384 * mark tcp session as reconnecting so temporarily locked
385 * mark all smb sessions as reconnecting for tcp session
386 * reconnect tcp session
387 * wake up waiters on reconnection? - (not needed currently)
388 */
389int
390cifs_reconnect(struct TCP_Server_Info *server)
391{
392 int rc = 0;
393 struct list_head *tmp, *tmp2;
394 struct cifs_ses *ses;
395 struct cifs_tcon *tcon;
396 struct mid_q_entry *mid_entry;
397 struct list_head retry_list;
David Brazdil0f672f62019-12-10 10:32:29 +0000398#ifdef CONFIG_CIFS_DFS_UPCALL
Olivier Deprez0e641232021-09-23 10:07:05 +0200399 struct super_block *sb = NULL;
David Brazdil0f672f62019-12-10 10:32:29 +0000400 struct cifs_sb_info *cifs_sb = NULL;
401 struct dfs_cache_tgt_list tgt_list = {0};
402 struct dfs_cache_tgt_iterator *tgt_it = NULL;
403#endif
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000404
405 spin_lock(&GlobalMid_Lock);
David Brazdil0f672f62019-12-10 10:32:29 +0000406 server->nr_targets = 1;
407#ifdef CONFIG_CIFS_DFS_UPCALL
408 spin_unlock(&GlobalMid_Lock);
Olivier Deprez157378f2022-04-04 15:47:50 +0200409 sb = cifs_get_tcp_super(server);
Olivier Deprez0e641232021-09-23 10:07:05 +0200410 if (IS_ERR(sb)) {
411 rc = PTR_ERR(sb);
David Brazdil0f672f62019-12-10 10:32:29 +0000412 cifs_dbg(FYI, "%s: will not do DFS failover: rc = %d\n",
413 __func__, rc);
Olivier Deprez0e641232021-09-23 10:07:05 +0200414 sb = NULL;
David Brazdil0f672f62019-12-10 10:32:29 +0000415 } else {
Olivier Deprez0e641232021-09-23 10:07:05 +0200416 cifs_sb = CIFS_SB(sb);
Olivier Deprez157378f2022-04-04 15:47:50 +0200417 rc = reconn_setup_dfs_targets(cifs_sb, &tgt_list);
418 if (rc) {
419 cifs_sb = NULL;
420 if (rc != -EOPNOTSUPP) {
421 cifs_server_dbg(VFS, "%s: no target servers for DFS failover\n",
422 __func__);
423 }
David Brazdil0f672f62019-12-10 10:32:29 +0000424 } else {
425 server->nr_targets = dfs_cache_get_nr_tgts(&tgt_list);
426 }
427 }
428 cifs_dbg(FYI, "%s: will retry %d target(s)\n", __func__,
429 server->nr_targets);
430 spin_lock(&GlobalMid_Lock);
431#endif
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000432 if (server->tcpStatus == CifsExiting) {
433 /* the demux thread will exit normally
434 next time through the loop */
435 spin_unlock(&GlobalMid_Lock);
Olivier Deprez0e641232021-09-23 10:07:05 +0200436#ifdef CONFIG_CIFS_DFS_UPCALL
437 dfs_cache_free_tgts(&tgt_list);
Olivier Deprez157378f2022-04-04 15:47:50 +0200438 cifs_put_tcp_super(sb);
Olivier Deprez0e641232021-09-23 10:07:05 +0200439#endif
Olivier Deprez157378f2022-04-04 15:47:50 +0200440 wake_up(&server->response_q);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000441 return rc;
442 } else
443 server->tcpStatus = CifsNeedReconnect;
444 spin_unlock(&GlobalMid_Lock);
445 server->maxBuf = 0;
446 server->max_read = 0;
447
David Brazdil0f672f62019-12-10 10:32:29 +0000448 cifs_dbg(FYI, "Mark tcp session as need reconnect\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000449 trace_smb3_reconnect(server->CurrentMid, server->hostname);
450
451 /* before reconnecting the tcp session, mark the smb session (uid)
452 and the tid bad so they are not used until reconnected */
453 cifs_dbg(FYI, "%s: marking sessions and tcons for reconnect\n",
454 __func__);
455 spin_lock(&cifs_tcp_ses_lock);
456 list_for_each(tmp, &server->smb_ses_list) {
457 ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
458 ses->need_reconnect = true;
459 list_for_each(tmp2, &ses->tcon_list) {
460 tcon = list_entry(tmp2, struct cifs_tcon, tcon_list);
461 tcon->need_reconnect = true;
462 }
463 if (ses->tcon_ipc)
464 ses->tcon_ipc->need_reconnect = true;
465 }
466 spin_unlock(&cifs_tcp_ses_lock);
467
468 /* do not want to be sending data on a socket we are freeing */
469 cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
470 mutex_lock(&server->srv_mutex);
471 if (server->ssocket) {
472 cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n",
473 server->ssocket->state, server->ssocket->flags);
474 kernel_sock_shutdown(server->ssocket, SHUT_WR);
475 cifs_dbg(FYI, "Post shutdown state: 0x%x Flags: 0x%lx\n",
476 server->ssocket->state, server->ssocket->flags);
477 sock_release(server->ssocket);
478 server->ssocket = NULL;
479 }
480 server->sequence_number = 0;
481 server->session_estab = false;
482 kfree(server->session_key.response);
483 server->session_key.response = NULL;
484 server->session_key.len = 0;
485 server->lstrp = jiffies;
486
487 /* mark submitted MIDs for retry and issue callback */
488 INIT_LIST_HEAD(&retry_list);
489 cifs_dbg(FYI, "%s: moving mids to private list\n", __func__);
490 spin_lock(&GlobalMid_Lock);
491 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
492 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
David Brazdil0f672f62019-12-10 10:32:29 +0000493 kref_get(&mid_entry->refcount);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000494 if (mid_entry->mid_state == MID_REQUEST_SUBMITTED)
495 mid_entry->mid_state = MID_RETRY_NEEDED;
496 list_move(&mid_entry->qhead, &retry_list);
David Brazdil0f672f62019-12-10 10:32:29 +0000497 mid_entry->mid_flags |= MID_DELETED;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000498 }
499 spin_unlock(&GlobalMid_Lock);
500 mutex_unlock(&server->srv_mutex);
501
502 cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
503 list_for_each_safe(tmp, tmp2, &retry_list) {
504 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
505 list_del_init(&mid_entry->qhead);
506 mid_entry->callback(mid_entry);
David Brazdil0f672f62019-12-10 10:32:29 +0000507 cifs_mid_q_entry_release(mid_entry);
508 }
509
510 if (cifs_rdma_enabled(server)) {
511 mutex_lock(&server->srv_mutex);
512 smbd_destroy(server);
513 mutex_unlock(&server->srv_mutex);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000514 }
515
516 do {
517 try_to_freeze();
518
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000519 mutex_lock(&server->srv_mutex);
Olivier Deprez0e641232021-09-23 10:07:05 +0200520#ifdef CONFIG_CIFS_DFS_UPCALL
David Brazdil0f672f62019-12-10 10:32:29 +0000521 /*
522 * Set up next DFS target server (if any) for reconnect. If DFS
523 * feature is disabled, then we will retry last server we
524 * connected to before.
525 */
Olivier Deprez157378f2022-04-04 15:47:50 +0200526 reconn_set_next_dfs_target(server, cifs_sb, &tgt_list, &tgt_it);
Olivier Deprez0e641232021-09-23 10:07:05 +0200527#endif
528 rc = reconn_set_ipaddr(server);
529 if (rc) {
530 cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n",
531 __func__, rc);
532 }
533
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000534 if (cifs_rdma_enabled(server))
535 rc = smbd_reconnect(server);
536 else
537 rc = generic_ip_connect(server);
538 if (rc) {
539 cifs_dbg(FYI, "reconnect error %d\n", rc);
540 mutex_unlock(&server->srv_mutex);
541 msleep(3000);
542 } else {
543 atomic_inc(&tcpSesReconnectCount);
David Brazdil0f672f62019-12-10 10:32:29 +0000544 set_credits(server, 1);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000545 spin_lock(&GlobalMid_Lock);
546 if (server->tcpStatus != CifsExiting)
547 server->tcpStatus = CifsNeedNegotiate;
548 spin_unlock(&GlobalMid_Lock);
549 mutex_unlock(&server->srv_mutex);
550 }
551 } while (server->tcpStatus == CifsNeedReconnect);
552
David Brazdil0f672f62019-12-10 10:32:29 +0000553#ifdef CONFIG_CIFS_DFS_UPCALL
554 if (tgt_it) {
555 rc = dfs_cache_noreq_update_tgthint(cifs_sb->origin_fullpath + 1,
556 tgt_it);
557 if (rc) {
558 cifs_server_dbg(VFS, "%s: failed to update DFS target hint: rc = %d\n",
559 __func__, rc);
560 }
561 rc = dfs_cache_update_vol(cifs_sb->origin_fullpath, server);
562 if (rc) {
563 cifs_server_dbg(VFS, "%s: failed to update vol info in DFS cache: rc = %d\n",
564 __func__, rc);
565 }
566 dfs_cache_free_tgts(&tgt_list);
Olivier Deprez0e641232021-09-23 10:07:05 +0200567
David Brazdil0f672f62019-12-10 10:32:29 +0000568 }
Olivier Deprez0e641232021-09-23 10:07:05 +0200569
Olivier Deprez157378f2022-04-04 15:47:50 +0200570 cifs_put_tcp_super(sb);
David Brazdil0f672f62019-12-10 10:32:29 +0000571#endif
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000572 if (server->tcpStatus == CifsNeedNegotiate)
573 mod_delayed_work(cifsiod_wq, &server->echo, 0);
574
Olivier Deprez157378f2022-04-04 15:47:50 +0200575 wake_up(&server->response_q);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000576 return rc;
577}
578
579static void
580cifs_echo_request(struct work_struct *work)
581{
582 int rc;
583 struct TCP_Server_Info *server = container_of(work,
584 struct TCP_Server_Info, echo.work);
585 unsigned long echo_interval;
586
587 /*
588 * If we need to renegotiate, set echo interval to zero to
589 * immediately call echo service where we can renegotiate.
590 */
591 if (server->tcpStatus == CifsNeedNegotiate)
592 echo_interval = 0;
593 else
594 echo_interval = server->echo_interval;
595
596 /*
597 * We cannot send an echo if it is disabled.
598 * Also, no need to ping if we got a response recently.
599 */
600
601 if (server->tcpStatus == CifsNeedReconnect ||
602 server->tcpStatus == CifsExiting ||
603 server->tcpStatus == CifsNew ||
604 (server->ops->can_echo && !server->ops->can_echo(server)) ||
605 time_before(jiffies, server->lstrp + echo_interval - HZ))
606 goto requeue_echo;
607
608 rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
609 if (rc)
610 cifs_dbg(FYI, "Unable to send echo request to server: %s\n",
611 server->hostname);
612
613requeue_echo:
614 queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval);
615}
616
617static bool
618allocate_buffers(struct TCP_Server_Info *server)
619{
620 if (!server->bigbuf) {
621 server->bigbuf = (char *)cifs_buf_get();
622 if (!server->bigbuf) {
David Brazdil0f672f62019-12-10 10:32:29 +0000623 cifs_server_dbg(VFS, "No memory for large SMB response\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000624 msleep(3000);
625 /* retry will check if exiting */
626 return false;
627 }
628 } else if (server->large_buf) {
629 /* we are reusing a dirty large buf, clear its start */
630 memset(server->bigbuf, 0, HEADER_SIZE(server));
631 }
632
633 if (!server->smallbuf) {
634 server->smallbuf = (char *)cifs_small_buf_get();
635 if (!server->smallbuf) {
David Brazdil0f672f62019-12-10 10:32:29 +0000636 cifs_server_dbg(VFS, "No memory for SMB response\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000637 msleep(1000);
638 /* retry will check if exiting */
639 return false;
640 }
641 /* beginning of smb buffer is cleared in our buf_get */
642 } else {
643 /* if existing small buf clear beginning */
644 memset(server->smallbuf, 0, HEADER_SIZE(server));
645 }
646
647 return true;
648}
649
650static bool
651server_unresponsive(struct TCP_Server_Info *server)
652{
653 /*
David Brazdil0f672f62019-12-10 10:32:29 +0000654 * We need to wait 3 echo intervals to make sure we handle such
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000655 * situations right:
656 * 1s client sends a normal SMB request
657 * 2s client gets a response
658 * 30s echo workqueue job pops, and decides we got a response recently
659 * and don't need to send another
660 * ...
661 * 65s kernel_recvmsg times out, and we see that we haven't gotten
662 * a response in >60s.
663 */
664 if ((server->tcpStatus == CifsGood ||
665 server->tcpStatus == CifsNeedNegotiate) &&
Olivier Deprez157378f2022-04-04 15:47:50 +0200666 (!server->ops->can_echo || server->ops->can_echo(server)) &&
David Brazdil0f672f62019-12-10 10:32:29 +0000667 time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
668 cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n",
669 (3 * server->echo_interval) / HZ);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000670 cifs_reconnect(server);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000671 return true;
672 }
673
674 return false;
675}
676
David Brazdil0f672f62019-12-10 10:32:29 +0000677static inline bool
678zero_credits(struct TCP_Server_Info *server)
679{
680 int val;
681
682 spin_lock(&server->req_lock);
683 val = server->credits + server->echo_credits + server->oplock_credits;
684 if (server->in_flight == 0 && val == 0) {
685 spin_unlock(&server->req_lock);
686 return true;
687 }
688 spin_unlock(&server->req_lock);
689 return false;
690}
691
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000692static int
693cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
694{
695 int length = 0;
696 int total_read;
697
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000698 for (total_read = 0; msg_data_left(smb_msg); total_read += length) {
699 try_to_freeze();
700
David Brazdil0f672f62019-12-10 10:32:29 +0000701 /* reconnect if no credits and no requests in flight */
702 if (zero_credits(server)) {
703 cifs_reconnect(server);
704 return -ECONNABORTED;
705 }
706
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000707 if (server_unresponsive(server))
708 return -ECONNABORTED;
709 if (cifs_rdma_enabled(server) && server->smbd_conn)
710 length = smbd_recv(server->smbd_conn, smb_msg);
711 else
712 length = sock_recvmsg(server->ssocket, smb_msg, 0);
713
714 if (server->tcpStatus == CifsExiting)
715 return -ESHUTDOWN;
716
717 if (server->tcpStatus == CifsNeedReconnect) {
718 cifs_reconnect(server);
719 return -ECONNABORTED;
720 }
721
722 if (length == -ERESTARTSYS ||
723 length == -EAGAIN ||
724 length == -EINTR) {
725 /*
726 * Minimum sleep to prevent looping, allowing socket
727 * to clear and app threads to set tcpStatus
728 * CifsNeedReconnect if server hung.
729 */
730 usleep_range(1000, 2000);
731 length = 0;
732 continue;
733 }
734
735 if (length <= 0) {
736 cifs_dbg(FYI, "Received no data or error: %d\n", length);
737 cifs_reconnect(server);
738 return -ECONNABORTED;
739 }
740 }
741 return total_read;
742}
743
744int
745cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
746 unsigned int to_read)
747{
Olivier Deprez92d4c212022-12-06 15:05:30 +0100748 struct msghdr smb_msg = {};
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000749 struct kvec iov = {.iov_base = buf, .iov_len = to_read};
David Brazdil0f672f62019-12-10 10:32:29 +0000750 iov_iter_kvec(&smb_msg.msg_iter, READ, &iov, 1, to_read);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000751
752 return cifs_readv_from_socket(server, &smb_msg);
753}
754
Olivier Deprez92d4c212022-12-06 15:05:30 +0100755ssize_t
756cifs_discard_from_socket(struct TCP_Server_Info *server, size_t to_read)
757{
758 struct msghdr smb_msg = {};
759
760 /*
761 * iov_iter_discard already sets smb_msg.type and count and iov_offset
762 * and cifs_readv_from_socket sets msg_control and msg_controllen
763 * so little to initialize in struct msghdr
764 */
765 iov_iter_discard(&smb_msg.msg_iter, READ, to_read);
766
767 return cifs_readv_from_socket(server, &smb_msg);
768}
769
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000770int
771cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page,
772 unsigned int page_offset, unsigned int to_read)
773{
Olivier Deprez92d4c212022-12-06 15:05:30 +0100774 struct msghdr smb_msg = {};
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000775 struct bio_vec bv = {
776 .bv_page = page, .bv_len = to_read, .bv_offset = page_offset};
David Brazdil0f672f62019-12-10 10:32:29 +0000777 iov_iter_bvec(&smb_msg.msg_iter, READ, &bv, 1, to_read);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000778 return cifs_readv_from_socket(server, &smb_msg);
779}
780
781static bool
782is_smb_response(struct TCP_Server_Info *server, unsigned char type)
783{
784 /*
785 * The first byte big endian of the length field,
786 * is actually not part of the length but the type
787 * with the most common, zero, as regular data.
788 */
789 switch (type) {
790 case RFC1002_SESSION_MESSAGE:
791 /* Regular SMB response */
792 return true;
793 case RFC1002_SESSION_KEEP_ALIVE:
794 cifs_dbg(FYI, "RFC 1002 session keep alive\n");
795 break;
796 case RFC1002_POSITIVE_SESSION_RESPONSE:
797 cifs_dbg(FYI, "RFC 1002 positive session response\n");
798 break;
799 case RFC1002_NEGATIVE_SESSION_RESPONSE:
800 /*
801 * We get this from Windows 98 instead of an error on
802 * SMB negprot response.
803 */
804 cifs_dbg(FYI, "RFC 1002 negative session response\n");
805 /* give server a second to clean up */
806 msleep(1000);
807 /*
808 * Always try 445 first on reconnect since we get NACK
809 * on some if we ever connected to port 139 (the NACK
810 * is since we do not begin with RFC1001 session
811 * initialize frame).
812 */
813 cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT);
814 cifs_reconnect(server);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000815 break;
816 default:
David Brazdil0f672f62019-12-10 10:32:29 +0000817 cifs_server_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000818 cifs_reconnect(server);
819 }
820
821 return false;
822}
823
824void
825dequeue_mid(struct mid_q_entry *mid, bool malformed)
826{
827#ifdef CONFIG_CIFS_STATS2
828 mid->when_received = jiffies;
829#endif
830 spin_lock(&GlobalMid_Lock);
831 if (!malformed)
832 mid->mid_state = MID_RESPONSE_RECEIVED;
833 else
834 mid->mid_state = MID_RESPONSE_MALFORMED;
835 /*
836 * Trying to handle/dequeue a mid after the send_recv()
837 * function has finished processing it is a bug.
838 */
839 if (mid->mid_flags & MID_DELETED)
Olivier Deprez157378f2022-04-04 15:47:50 +0200840 pr_warn_once("trying to dequeue a deleted mid\n");
David Brazdil0f672f62019-12-10 10:32:29 +0000841 else {
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000842 list_del_init(&mid->qhead);
David Brazdil0f672f62019-12-10 10:32:29 +0000843 mid->mid_flags |= MID_DELETED;
844 }
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000845 spin_unlock(&GlobalMid_Lock);
846}
847
Olivier Deprez0e641232021-09-23 10:07:05 +0200848static unsigned int
849smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
850{
851 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer;
852
853 /*
854 * SMB1 does not use credits.
855 */
856 if (server->vals->header_preamble_size)
857 return 0;
858
859 return le16_to_cpu(shdr->CreditRequest);
860}
861
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000862static void
863handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
864 char *buf, int malformed)
865{
866 if (server->ops->check_trans2 &&
867 server->ops->check_trans2(mid, server, buf, malformed))
868 return;
Olivier Deprez0e641232021-09-23 10:07:05 +0200869 mid->credits_received = smb2_get_credits_from_hdr(buf, server);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000870 mid->resp_buf = buf;
871 mid->large_buf = server->large_buf;
872 /* Was previous buf put in mpx struct for multi-rsp? */
873 if (!mid->multiRsp) {
874 /* smb buffer will be freed by user thread */
875 if (server->large_buf)
876 server->bigbuf = NULL;
877 else
878 server->smallbuf = NULL;
879 }
880 dequeue_mid(mid, malformed);
881}
882
883static void clean_demultiplex_info(struct TCP_Server_Info *server)
884{
885 int length;
886
887 /* take it off the list, if it's not already */
888 spin_lock(&cifs_tcp_ses_lock);
889 list_del_init(&server->tcp_ses_list);
890 spin_unlock(&cifs_tcp_ses_lock);
891
Olivier Deprez0e641232021-09-23 10:07:05 +0200892 cancel_delayed_work_sync(&server->echo);
893
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000894 spin_lock(&GlobalMid_Lock);
895 server->tcpStatus = CifsExiting;
896 spin_unlock(&GlobalMid_Lock);
897 wake_up_all(&server->response_q);
898
899 /* check if we have blocked requests that need to free */
900 spin_lock(&server->req_lock);
901 if (server->credits <= 0)
902 server->credits = 1;
903 spin_unlock(&server->req_lock);
904 /*
905 * Although there should not be any requests blocked on this queue it
906 * can not hurt to be paranoid and try to wake up requests that may
907 * haven been blocked when more than 50 at time were on the wire to the
908 * same server - they now will see the session is in exit state and get
909 * out of SendReceive.
910 */
911 wake_up_all(&server->request_q);
912 /* give those requests time to exit */
913 msleep(125);
David Brazdil0f672f62019-12-10 10:32:29 +0000914 if (cifs_rdma_enabled(server))
915 smbd_destroy(server);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000916 if (server->ssocket) {
917 sock_release(server->ssocket);
918 server->ssocket = NULL;
919 }
920
921 if (!list_empty(&server->pending_mid_q)) {
922 struct list_head dispose_list;
923 struct mid_q_entry *mid_entry;
924 struct list_head *tmp, *tmp2;
925
926 INIT_LIST_HEAD(&dispose_list);
927 spin_lock(&GlobalMid_Lock);
928 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
929 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
930 cifs_dbg(FYI, "Clearing mid 0x%llx\n", mid_entry->mid);
David Brazdil0f672f62019-12-10 10:32:29 +0000931 kref_get(&mid_entry->refcount);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000932 mid_entry->mid_state = MID_SHUTDOWN;
933 list_move(&mid_entry->qhead, &dispose_list);
David Brazdil0f672f62019-12-10 10:32:29 +0000934 mid_entry->mid_flags |= MID_DELETED;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000935 }
936 spin_unlock(&GlobalMid_Lock);
937
938 /* now walk dispose list and issue callbacks */
939 list_for_each_safe(tmp, tmp2, &dispose_list) {
940 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
941 cifs_dbg(FYI, "Callback mid 0x%llx\n", mid_entry->mid);
942 list_del_init(&mid_entry->qhead);
943 mid_entry->callback(mid_entry);
David Brazdil0f672f62019-12-10 10:32:29 +0000944 cifs_mid_q_entry_release(mid_entry);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000945 }
946 /* 1/8th of sec is more than enough time for them to exit */
947 msleep(125);
948 }
949
950 if (!list_empty(&server->pending_mid_q)) {
951 /*
952 * mpx threads have not exited yet give them at least the smb
953 * send timeout time for long ops.
954 *
955 * Due to delays on oplock break requests, we need to wait at
956 * least 45 seconds before giving up on a request getting a
957 * response and going ahead and killing cifsd.
958 */
959 cifs_dbg(FYI, "Wait for exit from demultiplex thread\n");
960 msleep(46000);
961 /*
962 * If threads still have not exited they are probably never
963 * coming home not much else we can do but free the memory.
964 */
965 }
966
967 kfree(server->hostname);
968 kfree(server);
969
970 length = atomic_dec_return(&tcpSesAllocCount);
971 if (length > 0)
972 mempool_resize(cifs_req_poolp, length + cifs_min_rcv);
973}
974
975static int
976standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
977{
978 int length;
979 char *buf = server->smallbuf;
980 unsigned int pdu_length = server->pdu_size;
981
982 /* make sure this will fit in a large buffer */
983 if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
984 server->vals->header_preamble_size) {
David Brazdil0f672f62019-12-10 10:32:29 +0000985 cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000986 cifs_reconnect(server);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000987 return -ECONNABORTED;
988 }
989
990 /* switch to large buffer if too big for a small one */
991 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
992 server->large_buf = true;
993 memcpy(server->bigbuf, buf, server->total_read);
994 buf = server->bigbuf;
995 }
996
997 /* now read the rest */
998 length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
999 pdu_length - HEADER_SIZE(server) + 1
1000 + server->vals->header_preamble_size);
1001
1002 if (length < 0)
1003 return length;
1004 server->total_read += length;
1005
1006 dump_smb(buf, server->total_read);
1007
1008 return cifs_handle_standard(server, mid);
1009}
1010
1011int
1012cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1013{
1014 char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
1015 int length;
1016
1017 /*
1018 * We know that we received enough to get to the MID as we
1019 * checked the pdu_length earlier. Now check to see
1020 * if the rest of the header is OK. We borrow the length
1021 * var for the rest of the loop to avoid a new stack var.
1022 *
1023 * 48 bytes is enough to display the header and a little bit
1024 * into the payload for debugging purposes.
1025 */
1026 length = server->ops->check_message(buf, server->total_read, server);
1027 if (length != 0)
1028 cifs_dump_mem("Bad SMB: ", buf,
1029 min_t(unsigned int, server->total_read, 48));
1030
1031 if (server->ops->is_session_expired &&
1032 server->ops->is_session_expired(buf)) {
1033 cifs_reconnect(server);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001034 return -1;
1035 }
1036
1037 if (server->ops->is_status_pending &&
David Brazdil0f672f62019-12-10 10:32:29 +00001038 server->ops->is_status_pending(buf, server))
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001039 return -1;
1040
1041 if (!mid)
1042 return length;
1043
1044 handle_mid(mid, server, buf, length);
1045 return 0;
1046}
1047
David Brazdil0f672f62019-12-10 10:32:29 +00001048static void
1049smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
1050{
1051 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer;
1052
1053 /*
1054 * SMB1 does not use credits.
1055 */
1056 if (server->vals->header_preamble_size)
1057 return;
1058
1059 if (shdr->CreditRequest) {
1060 spin_lock(&server->req_lock);
1061 server->credits += le16_to_cpu(shdr->CreditRequest);
1062 spin_unlock(&server->req_lock);
1063 wake_up(&server->request_q);
1064 }
1065}
1066
1067
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001068static int
1069cifs_demultiplex_thread(void *p)
1070{
1071 int i, num_mids, length;
1072 struct TCP_Server_Info *server = p;
1073 unsigned int pdu_length;
1074 unsigned int next_offset;
1075 char *buf = NULL;
1076 struct task_struct *task_to_wake = NULL;
1077 struct mid_q_entry *mids[MAX_COMPOUND];
1078 char *bufs[MAX_COMPOUND];
Olivier Deprez157378f2022-04-04 15:47:50 +02001079 unsigned int noreclaim_flag, num_io_timeout = 0;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001080
Olivier Deprez157378f2022-04-04 15:47:50 +02001081 noreclaim_flag = memalloc_noreclaim_save();
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001082 cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current));
1083
1084 length = atomic_inc_return(&tcpSesAllocCount);
1085 if (length > 1)
1086 mempool_resize(cifs_req_poolp, length + cifs_min_rcv);
1087
1088 set_freezable();
David Brazdil0f672f62019-12-10 10:32:29 +00001089 allow_kernel_signal(SIGKILL);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001090 while (server->tcpStatus != CifsExiting) {
1091 if (try_to_freeze())
1092 continue;
1093
1094 if (!allocate_buffers(server))
1095 continue;
1096
1097 server->large_buf = false;
1098 buf = server->smallbuf;
1099 pdu_length = 4; /* enough to get RFC1001 header */
1100
1101 length = cifs_read_from_socket(server, buf, pdu_length);
1102 if (length < 0)
1103 continue;
1104
1105 if (server->vals->header_preamble_size == 0)
1106 server->total_read = 0;
1107 else
1108 server->total_read = length;
1109
1110 /*
1111 * The right amount was read from socket - 4 bytes,
1112 * so we can now interpret the length field.
1113 */
1114 pdu_length = get_rfc1002_length(buf);
1115
1116 cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
1117 if (!is_smb_response(server, buf[0]))
1118 continue;
1119next_pdu:
1120 server->pdu_size = pdu_length;
1121
1122 /* make sure we have enough to get to the MID */
1123 if (server->pdu_size < HEADER_SIZE(server) - 1 -
1124 server->vals->header_preamble_size) {
David Brazdil0f672f62019-12-10 10:32:29 +00001125 cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n",
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001126 server->pdu_size);
1127 cifs_reconnect(server);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001128 continue;
1129 }
1130
1131 /* read down to the MID */
1132 length = cifs_read_from_socket(server,
1133 buf + server->vals->header_preamble_size,
1134 HEADER_SIZE(server) - 1
1135 - server->vals->header_preamble_size);
1136 if (length < 0)
1137 continue;
1138 server->total_read += length;
1139
1140 if (server->ops->next_header) {
1141 next_offset = server->ops->next_header(buf);
1142 if (next_offset)
1143 server->pdu_size = next_offset;
1144 }
1145
1146 memset(mids, 0, sizeof(mids));
1147 memset(bufs, 0, sizeof(bufs));
1148 num_mids = 0;
1149
1150 if (server->ops->is_transform_hdr &&
1151 server->ops->receive_transform &&
1152 server->ops->is_transform_hdr(buf)) {
1153 length = server->ops->receive_transform(server,
1154 mids,
1155 bufs,
1156 &num_mids);
1157 } else {
1158 mids[0] = server->ops->find_mid(server, buf);
1159 bufs[0] = buf;
1160 num_mids = 1;
1161
1162 if (!mids[0] || !mids[0]->receive)
1163 length = standard_receive3(server, mids[0]);
1164 else
1165 length = mids[0]->receive(server, mids[0]);
1166 }
1167
1168 if (length < 0) {
1169 for (i = 0; i < num_mids; i++)
1170 if (mids[i])
1171 cifs_mid_q_entry_release(mids[i]);
1172 continue;
1173 }
1174
Olivier Deprez157378f2022-04-04 15:47:50 +02001175 if (server->ops->is_status_io_timeout &&
1176 server->ops->is_status_io_timeout(buf)) {
1177 num_io_timeout++;
1178 if (num_io_timeout > NUM_STATUS_IO_TIMEOUT) {
1179 cifs_reconnect(server);
1180 num_io_timeout = 0;
1181 continue;
1182 }
1183 }
1184
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001185 server->lstrp = jiffies;
1186
1187 for (i = 0; i < num_mids; i++) {
1188 if (mids[i] != NULL) {
1189 mids[i]->resp_buf_size = server->pdu_size;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001190
1191 if (!mids[i]->multiRsp || mids[i]->multiEnd)
1192 mids[i]->callback(mids[i]);
1193
1194 cifs_mid_q_entry_release(mids[i]);
1195 } else if (server->ops->is_oplock_break &&
1196 server->ops->is_oplock_break(bufs[i],
1197 server)) {
David Brazdil0f672f62019-12-10 10:32:29 +00001198 smb2_add_credits_from_hdr(bufs[i], server);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001199 cifs_dbg(FYI, "Received oplock break\n");
1200 } else {
Olivier Deprez157378f2022-04-04 15:47:50 +02001201 cifs_server_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n",
1202 atomic_read(&midCount));
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001203 cifs_dump_mem("Received Data is: ", bufs[i],
1204 HEADER_SIZE(server));
David Brazdil0f672f62019-12-10 10:32:29 +00001205 smb2_add_credits_from_hdr(bufs[i], server);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001206#ifdef CONFIG_CIFS_DEBUG2
1207 if (server->ops->dump_detail)
1208 server->ops->dump_detail(bufs[i],
1209 server);
1210 cifs_dump_mids(server);
1211#endif /* CIFS_DEBUG2 */
1212 }
1213 }
1214
1215 if (pdu_length > server->pdu_size) {
1216 if (!allocate_buffers(server))
1217 continue;
1218 pdu_length -= server->pdu_size;
1219 server->total_read = 0;
1220 server->large_buf = false;
1221 buf = server->smallbuf;
1222 goto next_pdu;
1223 }
1224 } /* end while !EXITING */
1225
1226 /* buffer usually freed in free_mid - need to free it here on exit */
1227 cifs_buf_release(server->bigbuf);
1228 if (server->smallbuf) /* no sense logging a debug message if NULL */
1229 cifs_small_buf_release(server->smallbuf);
1230
1231 task_to_wake = xchg(&server->tsk, NULL);
1232 clean_demultiplex_info(server);
1233
1234 /* if server->tsk was NULL then wait for a signal before exiting */
1235 if (!task_to_wake) {
1236 set_current_state(TASK_INTERRUPTIBLE);
1237 while (!signal_pending(current)) {
1238 schedule();
1239 set_current_state(TASK_INTERRUPTIBLE);
1240 }
1241 set_current_state(TASK_RUNNING);
1242 }
1243
Olivier Deprez157378f2022-04-04 15:47:50 +02001244 memalloc_noreclaim_restore(noreclaim_flag);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001245 module_put_and_exit(0);
1246}
1247
1248/* extract the host portion of the UNC string */
1249static char *
1250extract_hostname(const char *unc)
1251{
1252 const char *src;
1253 char *dst, *delim;
1254 unsigned int len;
1255
1256 /* skip double chars at beginning of string */
1257 /* BB: check validity of these bytes? */
David Brazdil0f672f62019-12-10 10:32:29 +00001258 if (strlen(unc) < 3)
1259 return ERR_PTR(-EINVAL);
1260 for (src = unc; *src && *src == '\\'; src++)
1261 ;
1262 if (!*src)
1263 return ERR_PTR(-EINVAL);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001264
1265 /* delimiter between hostname and sharename is always '\\' now */
1266 delim = strchr(src, '\\');
1267 if (!delim)
1268 return ERR_PTR(-EINVAL);
1269
1270 len = delim - src;
1271 dst = kmalloc((len + 1), GFP_KERNEL);
1272 if (dst == NULL)
1273 return ERR_PTR(-ENOMEM);
1274
1275 memcpy(dst, src, len);
1276 dst[len] = '\0';
1277
1278 return dst;
1279}
1280
1281static int get_option_ul(substring_t args[], unsigned long *option)
1282{
1283 int rc;
1284 char *string;
1285
1286 string = match_strdup(args);
1287 if (string == NULL)
1288 return -ENOMEM;
1289 rc = kstrtoul(string, 0, option);
1290 kfree(string);
1291
1292 return rc;
1293}
1294
1295static int get_option_uid(substring_t args[], kuid_t *result)
1296{
1297 unsigned long value;
1298 kuid_t uid;
1299 int rc;
1300
1301 rc = get_option_ul(args, &value);
1302 if (rc)
1303 return rc;
1304
1305 uid = make_kuid(current_user_ns(), value);
1306 if (!uid_valid(uid))
1307 return -EINVAL;
1308
1309 *result = uid;
1310 return 0;
1311}
1312
1313static int get_option_gid(substring_t args[], kgid_t *result)
1314{
1315 unsigned long value;
1316 kgid_t gid;
1317 int rc;
1318
1319 rc = get_option_ul(args, &value);
1320 if (rc)
1321 return rc;
1322
1323 gid = make_kgid(current_user_ns(), value);
1324 if (!gid_valid(gid))
1325 return -EINVAL;
1326
1327 *result = gid;
1328 return 0;
1329}
1330
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001331/*
1332 * Parse a devname into substrings and populate the vol->UNC and vol->prepath
1333 * fields with the result. Returns 0 on success and an error otherwise.
1334 */
1335static int
1336cifs_parse_devname(const char *devname, struct smb_vol *vol)
1337{
1338 char *pos;
1339 const char *delims = "/\\";
1340 size_t len;
1341
David Brazdil0f672f62019-12-10 10:32:29 +00001342 if (unlikely(!devname || !*devname)) {
Olivier Deprez157378f2022-04-04 15:47:50 +02001343 cifs_dbg(VFS, "Device name not specified\n");
David Brazdil0f672f62019-12-10 10:32:29 +00001344 return -EINVAL;
1345 }
1346
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001347 /* make sure we have a valid UNC double delimiter prefix */
1348 len = strspn(devname, delims);
1349 if (len != 2)
1350 return -EINVAL;
1351
1352 /* find delimiter between host and sharename */
1353 pos = strpbrk(devname + 2, delims);
1354 if (!pos)
1355 return -EINVAL;
1356
1357 /* skip past delimiter */
1358 ++pos;
1359
1360 /* now go until next delimiter or end of string */
1361 len = strcspn(pos, delims);
1362
1363 /* move "pos" up to delimiter or NULL */
1364 pos += len;
1365 vol->UNC = kstrndup(devname, pos - devname, GFP_KERNEL);
1366 if (!vol->UNC)
1367 return -ENOMEM;
1368
1369 convert_delimiter(vol->UNC, '\\');
1370
1371 /* skip any delimiter */
1372 if (*pos == '/' || *pos == '\\')
1373 pos++;
1374
1375 /* If pos is NULL then no prepath */
1376 if (!*pos)
1377 return 0;
1378
1379 vol->prepath = kstrdup(pos, GFP_KERNEL);
1380 if (!vol->prepath)
1381 return -ENOMEM;
1382
1383 return 0;
1384}
1385
1386static int
1387cifs_parse_mount_options(const char *mountdata, const char *devname,
1388 struct smb_vol *vol, bool is_smb3)
1389{
1390 char *data, *end;
1391 char *mountdata_copy = NULL, *options;
1392 unsigned int temp_len, i, j;
1393 char separator[2];
1394 short int override_uid = -1;
1395 short int override_gid = -1;
1396 bool uid_specified = false;
1397 bool gid_specified = false;
1398 bool sloppy = false;
1399 char *invalid = NULL;
1400 char *nodename = utsname()->nodename;
1401 char *string = NULL;
1402 char *tmp_end, *value;
1403 char delim;
1404 bool got_ip = false;
1405 bool got_version = false;
1406 unsigned short port = 0;
1407 struct sockaddr *dstaddr = (struct sockaddr *)&vol->dstaddr;
1408
1409 separator[0] = ',';
1410 separator[1] = 0;
1411 delim = separator[0];
1412
1413 /* ensure we always start with zeroed-out smb_vol */
1414 memset(vol, 0, sizeof(*vol));
1415
1416 /*
1417 * does not have to be perfect mapping since field is
1418 * informational, only used for servers that do not support
1419 * port 445 and it can be overridden at mount time
1420 */
1421 memset(vol->source_rfc1001_name, 0x20, RFC1001_NAME_LEN);
1422 for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++)
1423 vol->source_rfc1001_name[i] = toupper(nodename[i]);
1424
1425 vol->source_rfc1001_name[RFC1001_NAME_LEN] = 0;
1426 /* null target name indicates to use *SMBSERVR default called name
1427 if we end up sending RFC1001 session initialize */
1428 vol->target_rfc1001_name[0] = 0;
1429 vol->cred_uid = current_uid();
1430 vol->linux_uid = current_uid();
1431 vol->linux_gid = current_gid();
David Brazdil0f672f62019-12-10 10:32:29 +00001432 vol->bsize = 1024 * 1024; /* can improve cp performance significantly */
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001433 /*
1434 * default to SFM style remapping of seven reserved characters
1435 * unless user overrides it or we negotiate CIFS POSIX where
1436 * it is unnecessary. Can not simultaneously use more than one mapping
1437 * since then readdir could list files that open could not open
1438 */
1439 vol->remap = true;
1440
1441 /* default to only allowing write access to owner of the mount */
1442 vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
1443
1444 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
1445 /* default is always to request posix paths. */
1446 vol->posix_paths = 1;
1447 /* default to using server inode numbers where available */
1448 vol->server_ino = 1;
1449
1450 /* default is to use strict cifs caching semantics */
1451 vol->strict_io = true;
1452
1453 vol->actimeo = CIFS_DEF_ACTIMEO;
1454
David Brazdil0f672f62019-12-10 10:32:29 +00001455 /* Most clients set timeout to 0, allows server to use its default */
1456 vol->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */
1457
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001458 /* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */
1459 vol->ops = &smb30_operations;
1460 vol->vals = &smbdefault_values;
1461
1462 vol->echo_interval = SMB_ECHO_INTERVAL_DEFAULT;
1463
Olivier Deprez157378f2022-04-04 15:47:50 +02001464 /* default to no multichannel (single server connection) */
1465 vol->multichannel = false;
1466 vol->max_channels = 1;
1467
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001468 if (!mountdata)
1469 goto cifs_parse_mount_err;
1470
1471 mountdata_copy = kstrndup(mountdata, PAGE_SIZE, GFP_KERNEL);
1472 if (!mountdata_copy)
1473 goto cifs_parse_mount_err;
1474
1475 options = mountdata_copy;
1476 end = options + strlen(options);
1477
1478 if (strncmp(options, "sep=", 4) == 0) {
1479 if (options[4] != 0) {
1480 separator[0] = options[4];
1481 options += 5;
1482 } else {
1483 cifs_dbg(FYI, "Null separator not allowed\n");
1484 }
1485 }
1486 vol->backupuid_specified = false; /* no backup intent for a user */
1487 vol->backupgid_specified = false; /* no backup intent for a group */
1488
1489 switch (cifs_parse_devname(devname, vol)) {
1490 case 0:
1491 break;
1492 case -ENOMEM:
Olivier Deprez157378f2022-04-04 15:47:50 +02001493 cifs_dbg(VFS, "Unable to allocate memory for devname\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001494 goto cifs_parse_mount_err;
1495 case -EINVAL:
Olivier Deprez157378f2022-04-04 15:47:50 +02001496 cifs_dbg(VFS, "Malformed UNC in devname\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001497 goto cifs_parse_mount_err;
1498 default:
Olivier Deprez157378f2022-04-04 15:47:50 +02001499 cifs_dbg(VFS, "Unknown error parsing devname\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001500 goto cifs_parse_mount_err;
1501 }
1502
1503 while ((data = strsep(&options, separator)) != NULL) {
1504 substring_t args[MAX_OPT_ARGS];
1505 unsigned long option;
1506 int token;
1507
1508 if (!*data)
1509 continue;
1510
1511 token = match_token(data, cifs_mount_option_tokens, args);
1512
1513 switch (token) {
1514
1515 /* Ingnore the following */
1516 case Opt_ignore:
1517 break;
1518
1519 /* Boolean values */
1520 case Opt_user_xattr:
1521 vol->no_xattr = 0;
1522 break;
1523 case Opt_nouser_xattr:
1524 vol->no_xattr = 1;
1525 break;
1526 case Opt_forceuid:
1527 override_uid = 1;
1528 break;
1529 case Opt_noforceuid:
1530 override_uid = 0;
1531 break;
1532 case Opt_forcegid:
1533 override_gid = 1;
1534 break;
1535 case Opt_noforcegid:
1536 override_gid = 0;
1537 break;
1538 case Opt_noblocksend:
1539 vol->noblocksnd = 1;
1540 break;
1541 case Opt_noautotune:
1542 vol->noautotune = 1;
1543 break;
David Brazdil0f672f62019-12-10 10:32:29 +00001544 case Opt_nolease:
1545 vol->no_lease = 1;
1546 break;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001547 case Opt_hard:
1548 vol->retry = 1;
1549 break;
1550 case Opt_soft:
1551 vol->retry = 0;
1552 break;
1553 case Opt_perm:
1554 vol->noperm = 0;
1555 break;
1556 case Opt_noperm:
1557 vol->noperm = 1;
1558 break;
Olivier Deprez157378f2022-04-04 15:47:50 +02001559 case Opt_nodelete:
1560 vol->nodelete = 1;
1561 break;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001562 case Opt_mapchars:
1563 vol->sfu_remap = true;
1564 vol->remap = false; /* disable SFM mapping */
1565 break;
1566 case Opt_nomapchars:
1567 vol->sfu_remap = false;
1568 break;
1569 case Opt_mapposix:
1570 vol->remap = true;
1571 vol->sfu_remap = false; /* disable SFU mapping */
1572 break;
1573 case Opt_nomapposix:
1574 vol->remap = false;
1575 break;
1576 case Opt_sfu:
1577 vol->sfu_emul = 1;
1578 break;
1579 case Opt_nosfu:
1580 vol->sfu_emul = 0;
1581 break;
1582 case Opt_nodfs:
1583 vol->nodfs = 1;
1584 break;
David Brazdil0f672f62019-12-10 10:32:29 +00001585 case Opt_rootfs:
1586#ifdef CONFIG_CIFS_ROOT
1587 vol->rootfs = true;
1588#endif
1589 break;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001590 case Opt_posixpaths:
1591 vol->posix_paths = 1;
1592 break;
1593 case Opt_noposixpaths:
1594 vol->posix_paths = 0;
1595 break;
1596 case Opt_nounix:
1597 if (vol->linux_ext)
1598 cifs_dbg(VFS,
1599 "conflicting unix mount options\n");
1600 vol->no_linux_ext = 1;
1601 break;
1602 case Opt_unix:
1603 if (vol->no_linux_ext)
1604 cifs_dbg(VFS,
1605 "conflicting unix mount options\n");
1606 vol->linux_ext = 1;
1607 break;
1608 case Opt_nocase:
1609 vol->nocase = 1;
1610 break;
1611 case Opt_brl:
1612 vol->nobrl = 0;
1613 break;
1614 case Opt_nobrl:
1615 vol->nobrl = 1;
1616 /*
1617 * turn off mandatory locking in mode
1618 * if remote locking is turned off since the
1619 * local vfs will do advisory
1620 */
1621 if (vol->file_mode ==
1622 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
1623 vol->file_mode = S_IALLUGO;
1624 break;
1625 case Opt_nohandlecache:
1626 vol->nohandlecache = 1;
1627 break;
1628 case Opt_handlecache:
1629 vol->nohandlecache = 0;
1630 break;
1631 case Opt_forcemandatorylock:
1632 vol->mand_lock = 1;
1633 break;
1634 case Opt_setuids:
1635 vol->setuids = 1;
1636 break;
1637 case Opt_nosetuids:
1638 vol->setuids = 0;
1639 break;
1640 case Opt_setuidfromacl:
1641 vol->setuidfromacl = 1;
1642 break;
1643 case Opt_dynperm:
1644 vol->dynperm = true;
1645 break;
1646 case Opt_nodynperm:
1647 vol->dynperm = false;
1648 break;
1649 case Opt_nohard:
1650 vol->retry = 0;
1651 break;
1652 case Opt_nosoft:
1653 vol->retry = 1;
1654 break;
1655 case Opt_nointr:
1656 vol->intr = 0;
1657 break;
1658 case Opt_intr:
1659 vol->intr = 1;
1660 break;
1661 case Opt_nostrictsync:
1662 vol->nostrictsync = 1;
1663 break;
1664 case Opt_strictsync:
1665 vol->nostrictsync = 0;
1666 break;
1667 case Opt_serverino:
1668 vol->server_ino = 1;
1669 break;
1670 case Opt_noserverino:
1671 vol->server_ino = 0;
1672 break;
1673 case Opt_rwpidforward:
1674 vol->rwpidforward = 1;
1675 break;
David Brazdil0f672f62019-12-10 10:32:29 +00001676 case Opt_modesid:
1677 vol->mode_ace = 1;
1678 break;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001679 case Opt_cifsacl:
1680 vol->cifs_acl = 1;
1681 break;
1682 case Opt_nocifsacl:
1683 vol->cifs_acl = 0;
1684 break;
1685 case Opt_acl:
1686 vol->no_psx_acl = 0;
1687 break;
1688 case Opt_noacl:
1689 vol->no_psx_acl = 1;
1690 break;
1691 case Opt_locallease:
1692 vol->local_lease = 1;
1693 break;
1694 case Opt_sign:
1695 vol->sign = true;
1696 break;
David Brazdil0f672f62019-12-10 10:32:29 +00001697 case Opt_ignore_signature:
1698 vol->sign = true;
1699 vol->ignore_signature = true;
1700 break;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001701 case Opt_seal:
1702 /* we do not do the following in secFlags because seal
1703 * is a per tree connection (mount) not a per socket
1704 * or per-smb connection option in the protocol
1705 * vol->secFlg |= CIFSSEC_MUST_SEAL;
1706 */
1707 vol->seal = 1;
1708 break;
1709 case Opt_noac:
Olivier Deprez157378f2022-04-04 15:47:50 +02001710 pr_warn("Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001711 break;
1712 case Opt_fsc:
1713#ifndef CONFIG_CIFS_FSCACHE
1714 cifs_dbg(VFS, "FS-Cache support needs CONFIG_CIFS_FSCACHE kernel config option set\n");
1715 goto cifs_parse_mount_err;
1716#endif
1717 vol->fsc = true;
1718 break;
1719 case Opt_mfsymlinks:
1720 vol->mfsymlinks = true;
1721 break;
1722 case Opt_multiuser:
1723 vol->multiuser = true;
1724 break;
1725 case Opt_sloppy:
1726 sloppy = true;
1727 break;
1728 case Opt_nosharesock:
1729 vol->nosharesock = true;
1730 break;
1731 case Opt_nopersistent:
1732 vol->nopersistent = true;
1733 if (vol->persistent) {
1734 cifs_dbg(VFS,
1735 "persistenthandles mount options conflict\n");
1736 goto cifs_parse_mount_err;
1737 }
1738 break;
1739 case Opt_persistent:
1740 vol->persistent = true;
1741 if ((vol->nopersistent) || (vol->resilient)) {
1742 cifs_dbg(VFS,
1743 "persistenthandles mount options conflict\n");
1744 goto cifs_parse_mount_err;
1745 }
1746 break;
1747 case Opt_resilient:
1748 vol->resilient = true;
1749 if (vol->persistent) {
1750 cifs_dbg(VFS,
1751 "persistenthandles mount options conflict\n");
1752 goto cifs_parse_mount_err;
1753 }
1754 break;
1755 case Opt_noresilient:
1756 vol->resilient = false; /* already the default */
1757 break;
1758 case Opt_domainauto:
1759 vol->domainauto = true;
1760 break;
1761 case Opt_rdma:
1762 vol->rdma = true;
1763 break;
Olivier Deprez157378f2022-04-04 15:47:50 +02001764 case Opt_multichannel:
1765 vol->multichannel = true;
1766 /* if number of channels not specified, default to 2 */
1767 if (vol->max_channels < 2)
1768 vol->max_channels = 2;
1769 break;
1770 case Opt_nomultichannel:
1771 vol->multichannel = false;
1772 vol->max_channels = 1;
1773 break;
David Brazdil0f672f62019-12-10 10:32:29 +00001774 case Opt_compress:
1775 vol->compression = UNKNOWN_TYPE;
1776 cifs_dbg(VFS,
1777 "SMB3 compression support is experimental\n");
1778 break;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001779
1780 /* Numeric Values */
1781 case Opt_backupuid:
1782 if (get_option_uid(args, &vol->backupuid)) {
1783 cifs_dbg(VFS, "%s: Invalid backupuid value\n",
1784 __func__);
1785 goto cifs_parse_mount_err;
1786 }
1787 vol->backupuid_specified = true;
1788 break;
1789 case Opt_backupgid:
1790 if (get_option_gid(args, &vol->backupgid)) {
1791 cifs_dbg(VFS, "%s: Invalid backupgid value\n",
1792 __func__);
1793 goto cifs_parse_mount_err;
1794 }
1795 vol->backupgid_specified = true;
1796 break;
1797 case Opt_uid:
1798 if (get_option_uid(args, &vol->linux_uid)) {
1799 cifs_dbg(VFS, "%s: Invalid uid value\n",
1800 __func__);
1801 goto cifs_parse_mount_err;
1802 }
1803 uid_specified = true;
1804 break;
1805 case Opt_cruid:
1806 if (get_option_uid(args, &vol->cred_uid)) {
1807 cifs_dbg(VFS, "%s: Invalid cruid value\n",
1808 __func__);
1809 goto cifs_parse_mount_err;
1810 }
1811 break;
1812 case Opt_gid:
1813 if (get_option_gid(args, &vol->linux_gid)) {
1814 cifs_dbg(VFS, "%s: Invalid gid value\n",
1815 __func__);
1816 goto cifs_parse_mount_err;
1817 }
1818 gid_specified = true;
1819 break;
1820 case Opt_file_mode:
1821 if (get_option_ul(args, &option)) {
1822 cifs_dbg(VFS, "%s: Invalid file_mode value\n",
1823 __func__);
1824 goto cifs_parse_mount_err;
1825 }
1826 vol->file_mode = option;
1827 break;
1828 case Opt_dirmode:
1829 if (get_option_ul(args, &option)) {
1830 cifs_dbg(VFS, "%s: Invalid dir_mode value\n",
1831 __func__);
1832 goto cifs_parse_mount_err;
1833 }
1834 vol->dir_mode = option;
1835 break;
1836 case Opt_port:
1837 if (get_option_ul(args, &option) ||
1838 option > USHRT_MAX) {
1839 cifs_dbg(VFS, "%s: Invalid port value\n",
1840 __func__);
1841 goto cifs_parse_mount_err;
1842 }
1843 port = (unsigned short)option;
1844 break;
David Brazdil0f672f62019-12-10 10:32:29 +00001845 case Opt_min_enc_offload:
1846 if (get_option_ul(args, &option)) {
1847 cifs_dbg(VFS, "Invalid minimum encrypted read offload size (esize)\n");
1848 goto cifs_parse_mount_err;
1849 }
1850 vol->min_offload = option;
1851 break;
1852 case Opt_blocksize:
1853 if (get_option_ul(args, &option)) {
1854 cifs_dbg(VFS, "%s: Invalid blocksize value\n",
1855 __func__);
1856 goto cifs_parse_mount_err;
1857 }
1858 /*
1859 * inode blocksize realistically should never need to be
1860 * less than 16K or greater than 16M and default is 1MB.
1861 * Note that small inode block sizes (e.g. 64K) can lead
1862 * to very poor performance of common tools like cp and scp
1863 */
1864 if ((option < CIFS_MAX_MSGSIZE) ||
1865 (option > (4 * SMB3_DEFAULT_IOSIZE))) {
1866 cifs_dbg(VFS, "%s: Invalid blocksize\n",
1867 __func__);
1868 goto cifs_parse_mount_err;
1869 }
1870 vol->bsize = option;
1871 break;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001872 case Opt_rsize:
1873 if (get_option_ul(args, &option)) {
1874 cifs_dbg(VFS, "%s: Invalid rsize value\n",
1875 __func__);
1876 goto cifs_parse_mount_err;
1877 }
1878 vol->rsize = option;
1879 break;
1880 case Opt_wsize:
1881 if (get_option_ul(args, &option)) {
1882 cifs_dbg(VFS, "%s: Invalid wsize value\n",
1883 __func__);
1884 goto cifs_parse_mount_err;
1885 }
1886 vol->wsize = option;
1887 break;
1888 case Opt_actimeo:
1889 if (get_option_ul(args, &option)) {
1890 cifs_dbg(VFS, "%s: Invalid actimeo value\n",
1891 __func__);
1892 goto cifs_parse_mount_err;
1893 }
1894 vol->actimeo = HZ * option;
1895 if (vol->actimeo > CIFS_MAX_ACTIMEO) {
1896 cifs_dbg(VFS, "attribute cache timeout too large\n");
1897 goto cifs_parse_mount_err;
1898 }
1899 break;
David Brazdil0f672f62019-12-10 10:32:29 +00001900 case Opt_handletimeout:
1901 if (get_option_ul(args, &option)) {
1902 cifs_dbg(VFS, "%s: Invalid handletimeout value\n",
1903 __func__);
1904 goto cifs_parse_mount_err;
1905 }
1906 vol->handle_timeout = option;
1907 if (vol->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) {
1908 cifs_dbg(VFS, "Invalid handle cache timeout, longer than 16 minutes\n");
1909 goto cifs_parse_mount_err;
1910 }
1911 break;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001912 case Opt_echo_interval:
1913 if (get_option_ul(args, &option)) {
1914 cifs_dbg(VFS, "%s: Invalid echo interval value\n",
1915 __func__);
1916 goto cifs_parse_mount_err;
1917 }
1918 vol->echo_interval = option;
1919 break;
1920 case Opt_snapshot:
1921 if (get_option_ul(args, &option)) {
1922 cifs_dbg(VFS, "%s: Invalid snapshot time\n",
1923 __func__);
1924 goto cifs_parse_mount_err;
1925 }
1926 vol->snapshot_time = option;
1927 break;
1928 case Opt_max_credits:
1929 if (get_option_ul(args, &option) || (option < 20) ||
1930 (option > 60000)) {
1931 cifs_dbg(VFS, "%s: Invalid max_credits value\n",
1932 __func__);
1933 goto cifs_parse_mount_err;
1934 }
1935 vol->max_credits = option;
1936 break;
Olivier Deprez157378f2022-04-04 15:47:50 +02001937 case Opt_max_channels:
1938 if (get_option_ul(args, &option) || option < 1 ||
1939 option > CIFS_MAX_CHANNELS) {
1940 cifs_dbg(VFS, "%s: Invalid max_channels value, needs to be 1-%d\n",
1941 __func__, CIFS_MAX_CHANNELS);
1942 goto cifs_parse_mount_err;
1943 }
1944 vol->max_channels = option;
1945 break;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001946
1947 /* String Arguments */
1948
1949 case Opt_blank_user:
1950 /* null user, ie. anonymous authentication */
1951 vol->nullauth = 1;
1952 vol->username = NULL;
1953 break;
1954 case Opt_user:
1955 string = match_strdup(args);
1956 if (string == NULL)
1957 goto out_nomem;
1958
1959 if (strnlen(string, CIFS_MAX_USERNAME_LEN) >
1960 CIFS_MAX_USERNAME_LEN) {
Olivier Deprez157378f2022-04-04 15:47:50 +02001961 pr_warn("username too long\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001962 goto cifs_parse_mount_err;
1963 }
1964
1965 kfree(vol->username);
1966 vol->username = kstrdup(string, GFP_KERNEL);
1967 if (!vol->username)
1968 goto cifs_parse_mount_err;
1969 break;
1970 case Opt_blank_pass:
1971 /* passwords have to be handled differently
1972 * to allow the character used for deliminator
1973 * to be passed within them
1974 */
1975
1976 /*
1977 * Check if this is a case where the password
1978 * starts with a delimiter
1979 */
1980 tmp_end = strchr(data, '=');
1981 tmp_end++;
1982 if (!(tmp_end < end && tmp_end[1] == delim)) {
1983 /* No it is not. Set the password to NULL */
Olivier Deprez157378f2022-04-04 15:47:50 +02001984 kfree_sensitive(vol->password);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001985 vol->password = NULL;
1986 break;
1987 }
Olivier Deprez157378f2022-04-04 15:47:50 +02001988 fallthrough; /* to Opt_pass below */
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001989 case Opt_pass:
1990 /* Obtain the value string */
1991 value = strchr(data, '=');
1992 value++;
1993
1994 /* Set tmp_end to end of the string */
1995 tmp_end = (char *) value + strlen(value);
1996
1997 /* Check if following character is the deliminator
1998 * If yes, we have encountered a double deliminator
1999 * reset the NULL character to the deliminator
2000 */
2001 if (tmp_end < end && tmp_end[1] == delim) {
2002 tmp_end[0] = delim;
2003
2004 /* Keep iterating until we get to a single
2005 * deliminator OR the end
2006 */
2007 while ((tmp_end = strchr(tmp_end, delim))
2008 != NULL && (tmp_end[1] == delim)) {
2009 tmp_end = (char *) &tmp_end[2];
2010 }
2011
2012 /* Reset var options to point to next element */
2013 if (tmp_end) {
2014 tmp_end[0] = '\0';
2015 options = (char *) &tmp_end[1];
2016 } else
2017 /* Reached the end of the mount option
2018 * string */
2019 options = end;
2020 }
2021
Olivier Deprez157378f2022-04-04 15:47:50 +02002022 kfree_sensitive(vol->password);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002023 /* Now build new password string */
2024 temp_len = strlen(value);
2025 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
2026 if (vol->password == NULL) {
Olivier Deprez157378f2022-04-04 15:47:50 +02002027 pr_warn("no memory for password\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002028 goto cifs_parse_mount_err;
2029 }
2030
2031 for (i = 0, j = 0; i < temp_len; i++, j++) {
2032 vol->password[j] = value[i];
2033 if ((value[i] == delim) &&
2034 value[i+1] == delim)
2035 /* skip the second deliminator */
2036 i++;
2037 }
2038 vol->password[j] = '\0';
2039 break;
2040 case Opt_blank_ip:
2041 /* FIXME: should this be an error instead? */
2042 got_ip = false;
2043 break;
2044 case Opt_ip:
2045 string = match_strdup(args);
2046 if (string == NULL)
2047 goto out_nomem;
2048
2049 if (!cifs_convert_address(dstaddr, string,
2050 strlen(string))) {
Olivier Deprez157378f2022-04-04 15:47:50 +02002051 pr_err("bad ip= option (%s)\n", string);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002052 goto cifs_parse_mount_err;
2053 }
2054 got_ip = true;
2055 break;
2056 case Opt_domain:
2057 string = match_strdup(args);
2058 if (string == NULL)
2059 goto out_nomem;
2060
2061 if (strnlen(string, CIFS_MAX_DOMAINNAME_LEN)
2062 == CIFS_MAX_DOMAINNAME_LEN) {
Olivier Deprez157378f2022-04-04 15:47:50 +02002063 pr_warn("domain name too long\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002064 goto cifs_parse_mount_err;
2065 }
2066
2067 kfree(vol->domainname);
2068 vol->domainname = kstrdup(string, GFP_KERNEL);
2069 if (!vol->domainname) {
Olivier Deprez157378f2022-04-04 15:47:50 +02002070 pr_warn("no memory for domainname\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002071 goto cifs_parse_mount_err;
2072 }
2073 cifs_dbg(FYI, "Domain name set\n");
2074 break;
2075 case Opt_srcaddr:
2076 string = match_strdup(args);
2077 if (string == NULL)
2078 goto out_nomem;
2079
2080 if (!cifs_convert_address(
2081 (struct sockaddr *)&vol->srcaddr,
2082 string, strlen(string))) {
Olivier Deprez157378f2022-04-04 15:47:50 +02002083 pr_warn("Could not parse srcaddr: %s\n",
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002084 string);
2085 goto cifs_parse_mount_err;
2086 }
2087 break;
2088 case Opt_iocharset:
2089 string = match_strdup(args);
2090 if (string == NULL)
2091 goto out_nomem;
2092
2093 if (strnlen(string, 1024) >= 65) {
Olivier Deprez157378f2022-04-04 15:47:50 +02002094 pr_warn("iocharset name too long\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002095 goto cifs_parse_mount_err;
2096 }
2097
2098 if (strncasecmp(string, "default", 7) != 0) {
2099 kfree(vol->iocharset);
2100 vol->iocharset = kstrdup(string,
2101 GFP_KERNEL);
2102 if (!vol->iocharset) {
Olivier Deprez157378f2022-04-04 15:47:50 +02002103 pr_warn("no memory for charset\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002104 goto cifs_parse_mount_err;
2105 }
2106 }
2107 /* if iocharset not set then load_nls_default
2108 * is used by caller
2109 */
2110 cifs_dbg(FYI, "iocharset set to %s\n", string);
2111 break;
2112 case Opt_netbiosname:
2113 string = match_strdup(args);
2114 if (string == NULL)
2115 goto out_nomem;
2116
2117 memset(vol->source_rfc1001_name, 0x20,
2118 RFC1001_NAME_LEN);
2119 /*
2120 * FIXME: are there cases in which a comma can
2121 * be valid in workstation netbios name (and
2122 * need special handling)?
2123 */
2124 for (i = 0; i < RFC1001_NAME_LEN; i++) {
2125 /* don't ucase netbiosname for user */
2126 if (string[i] == 0)
2127 break;
2128 vol->source_rfc1001_name[i] = string[i];
2129 }
2130 /* The string has 16th byte zero still from
2131 * set at top of the function
2132 */
2133 if (i == RFC1001_NAME_LEN && string[i] != 0)
Olivier Deprez157378f2022-04-04 15:47:50 +02002134 pr_warn("netbiosname longer than 15 truncated\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002135 break;
2136 case Opt_servern:
2137 /* servernetbiosname specified override *SMBSERVER */
2138 string = match_strdup(args);
2139 if (string == NULL)
2140 goto out_nomem;
2141
2142 /* last byte, type, is 0x20 for servr type */
2143 memset(vol->target_rfc1001_name, 0x20,
2144 RFC1001_NAME_LEN_WITH_NULL);
2145
2146 /* BB are there cases in which a comma can be
2147 valid in this workstation netbios name
2148 (and need special handling)? */
2149
2150 /* user or mount helper must uppercase the
2151 netbios name */
2152 for (i = 0; i < 15; i++) {
2153 if (string[i] == 0)
2154 break;
2155 vol->target_rfc1001_name[i] = string[i];
2156 }
2157 /* The string has 16th byte zero still from
2158 set at top of the function */
2159 if (i == RFC1001_NAME_LEN && string[i] != 0)
Olivier Deprez157378f2022-04-04 15:47:50 +02002160 pr_warn("server netbiosname longer than 15 truncated\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002161 break;
2162 case Opt_ver:
2163 /* version of mount userspace tools, not dialect */
2164 string = match_strdup(args);
2165 if (string == NULL)
2166 goto out_nomem;
2167
2168 /* If interface changes in mount.cifs bump to new ver */
2169 if (strncasecmp(string, "1", 1) == 0) {
2170 if (strlen(string) > 1) {
Olivier Deprez157378f2022-04-04 15:47:50 +02002171 pr_warn("Bad mount helper ver=%s. Did you want SMB1 (CIFS) dialect and mean to type vers=1.0 instead?\n",
2172 string);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002173 goto cifs_parse_mount_err;
2174 }
2175 /* This is the default */
2176 break;
2177 }
2178 /* For all other value, error */
Olivier Deprez157378f2022-04-04 15:47:50 +02002179 pr_warn("Invalid mount helper version specified\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002180 goto cifs_parse_mount_err;
2181 case Opt_vers:
2182 /* protocol version (dialect) */
2183 string = match_strdup(args);
2184 if (string == NULL)
2185 goto out_nomem;
2186
2187 if (cifs_parse_smb_version(string, vol, is_smb3) != 0)
2188 goto cifs_parse_mount_err;
2189 got_version = true;
2190 break;
2191 case Opt_sec:
2192 string = match_strdup(args);
2193 if (string == NULL)
2194 goto out_nomem;
2195
2196 if (cifs_parse_security_flavors(string, vol) != 0)
2197 goto cifs_parse_mount_err;
2198 break;
2199 case Opt_cache:
2200 string = match_strdup(args);
2201 if (string == NULL)
2202 goto out_nomem;
2203
2204 if (cifs_parse_cache_flavor(string, vol) != 0)
2205 goto cifs_parse_mount_err;
2206 break;
2207 default:
2208 /*
2209 * An option we don't recognize. Save it off for later
2210 * if we haven't already found one
2211 */
2212 if (!invalid)
2213 invalid = data;
2214 break;
2215 }
2216 /* Free up any allocated string */
2217 kfree(string);
2218 string = NULL;
2219 }
2220
2221 if (!sloppy && invalid) {
Olivier Deprez157378f2022-04-04 15:47:50 +02002222 pr_err("Unknown mount option \"%s\"\n", invalid);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002223 goto cifs_parse_mount_err;
2224 }
2225
2226 if (vol->rdma && vol->vals->protocol_id < SMB30_PROT_ID) {
2227 cifs_dbg(VFS, "SMB Direct requires Version >=3.0\n");
2228 goto cifs_parse_mount_err;
2229 }
2230
2231#ifndef CONFIG_KEYS
2232 /* Muliuser mounts require CONFIG_KEYS support */
2233 if (vol->multiuser) {
2234 cifs_dbg(VFS, "Multiuser mounts require kernels with CONFIG_KEYS enabled\n");
2235 goto cifs_parse_mount_err;
2236 }
2237#endif
2238 if (!vol->UNC) {
2239 cifs_dbg(VFS, "CIFS mount error: No usable UNC path provided in device string!\n");
2240 goto cifs_parse_mount_err;
2241 }
2242
2243 /* make sure UNC has a share name */
2244 if (!strchr(vol->UNC + 3, '\\')) {
2245 cifs_dbg(VFS, "Malformed UNC. Unable to find share name.\n");
2246 goto cifs_parse_mount_err;
2247 }
2248
2249 if (!got_ip) {
2250 int len;
2251 const char *slash;
2252
2253 /* No ip= option specified? Try to get it from UNC */
2254 /* Use the address part of the UNC. */
2255 slash = strchr(&vol->UNC[2], '\\');
2256 len = slash - &vol->UNC[2];
2257 if (!cifs_convert_address(dstaddr, &vol->UNC[2], len)) {
Olivier Deprez157378f2022-04-04 15:47:50 +02002258 pr_err("Unable to determine destination address\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002259 goto cifs_parse_mount_err;
2260 }
2261 }
2262
2263 /* set the port that we got earlier */
2264 cifs_set_port(dstaddr, port);
2265
2266 if (uid_specified)
2267 vol->override_uid = override_uid;
2268 else if (override_uid == 1)
Olivier Deprez157378f2022-04-04 15:47:50 +02002269 pr_notice("ignoring forceuid mount option specified with no uid= option\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002270
2271 if (gid_specified)
2272 vol->override_gid = override_gid;
2273 else if (override_gid == 1)
Olivier Deprez157378f2022-04-04 15:47:50 +02002274 pr_notice("ignoring forcegid mount option specified with no gid= option\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002275
2276 if (got_version == false)
Olivier Deprez157378f2022-04-04 15:47:50 +02002277 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");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002278
2279 kfree(mountdata_copy);
2280 return 0;
2281
2282out_nomem:
2283 pr_warn("Could not allocate temporary buffer\n");
2284cifs_parse_mount_err:
2285 kfree(string);
2286 kfree(mountdata_copy);
2287 return 1;
2288}
2289
2290/** Returns true if srcaddr isn't specified and rhs isn't
2291 * specified, or if srcaddr is specified and
2292 * matches the IP address of the rhs argument.
2293 */
Olivier Deprez157378f2022-04-04 15:47:50 +02002294bool
2295cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002296{
2297 switch (srcaddr->sa_family) {
2298 case AF_UNSPEC:
2299 return (rhs->sa_family == AF_UNSPEC);
2300 case AF_INET: {
2301 struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
2302 struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
2303 return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr);
2304 }
2305 case AF_INET6: {
2306 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
2307 struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs;
2308 return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr);
2309 }
2310 default:
2311 WARN_ON(1);
2312 return false; /* don't expect to be here */
2313 }
2314}
2315
2316/*
2317 * If no port is specified in addr structure, we try to match with 445 port
2318 * and if it fails - with 139 ports. It should be called only if address
2319 * families of server and addr are equal.
2320 */
2321static bool
2322match_port(struct TCP_Server_Info *server, struct sockaddr *addr)
2323{
2324 __be16 port, *sport;
2325
David Brazdil0f672f62019-12-10 10:32:29 +00002326 /* SMBDirect manages its own ports, don't match it here */
2327 if (server->rdma)
2328 return true;
2329
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002330 switch (addr->sa_family) {
2331 case AF_INET:
2332 sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port;
2333 port = ((struct sockaddr_in *) addr)->sin_port;
2334 break;
2335 case AF_INET6:
2336 sport = &((struct sockaddr_in6 *) &server->dstaddr)->sin6_port;
2337 port = ((struct sockaddr_in6 *) addr)->sin6_port;
2338 break;
2339 default:
2340 WARN_ON(1);
2341 return false;
2342 }
2343
2344 if (!port) {
2345 port = htons(CIFS_PORT);
2346 if (port == *sport)
2347 return true;
2348
2349 port = htons(RFC1001_PORT);
2350 }
2351
2352 return port == *sport;
2353}
2354
2355static bool
2356match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
2357 struct sockaddr *srcaddr)
2358{
2359 switch (addr->sa_family) {
2360 case AF_INET: {
2361 struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
2362 struct sockaddr_in *srv_addr4 =
2363 (struct sockaddr_in *)&server->dstaddr;
2364
2365 if (addr4->sin_addr.s_addr != srv_addr4->sin_addr.s_addr)
2366 return false;
2367 break;
2368 }
2369 case AF_INET6: {
2370 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
2371 struct sockaddr_in6 *srv_addr6 =
2372 (struct sockaddr_in6 *)&server->dstaddr;
2373
2374 if (!ipv6_addr_equal(&addr6->sin6_addr,
2375 &srv_addr6->sin6_addr))
2376 return false;
2377 if (addr6->sin6_scope_id != srv_addr6->sin6_scope_id)
2378 return false;
2379 break;
2380 }
2381 default:
2382 WARN_ON(1);
2383 return false; /* don't expect to be here */
2384 }
2385
Olivier Deprez157378f2022-04-04 15:47:50 +02002386 if (!cifs_match_ipaddr(srcaddr, (struct sockaddr *)&server->srcaddr))
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002387 return false;
2388
2389 return true;
2390}
2391
2392static bool
2393match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
2394{
2395 /*
2396 * The select_sectype function should either return the vol->sectype
2397 * that was specified, or "Unspecified" if that sectype was not
2398 * compatible with the given NEGOTIATE request.
2399 */
2400 if (server->ops->select_sectype(server, vol->sectype)
2401 == Unspecified)
2402 return false;
2403
2404 /*
2405 * Now check if signing mode is acceptable. No need to check
2406 * global_secflags at this point since if MUST_SIGN is set then
2407 * the server->sign had better be too.
2408 */
2409 if (vol->sign && !server->sign)
2410 return false;
2411
2412 return true;
2413}
2414
2415static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol)
2416{
2417 struct sockaddr *addr = (struct sockaddr *)&vol->dstaddr;
2418
2419 if (vol->nosharesock)
2420 return 0;
2421
David Brazdil0f672f62019-12-10 10:32:29 +00002422 /* If multidialect negotiation see if existing sessions match one */
2423 if (strcmp(vol->vals->version_string, SMB3ANY_VERSION_STRING) == 0) {
2424 if (server->vals->protocol_id < SMB30_PROT_ID)
2425 return 0;
2426 } else if (strcmp(vol->vals->version_string,
2427 SMBDEFAULT_VERSION_STRING) == 0) {
2428 if (server->vals->protocol_id < SMB21_PROT_ID)
2429 return 0;
2430 } else if ((server->vals != vol->vals) || (server->ops != vol->ops))
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002431 return 0;
2432
2433 if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
2434 return 0;
2435
2436 if (!match_address(server, addr,
2437 (struct sockaddr *)&vol->srcaddr))
2438 return 0;
2439
2440 if (!match_port(server, addr))
2441 return 0;
2442
2443 if (!match_security(server, vol))
2444 return 0;
2445
2446 if (server->echo_interval != vol->echo_interval * HZ)
2447 return 0;
2448
2449 if (server->rdma != vol->rdma)
2450 return 0;
2451
David Brazdil0f672f62019-12-10 10:32:29 +00002452 if (server->ignore_signature != vol->ignore_signature)
2453 return 0;
2454
2455 if (server->min_offload != vol->min_offload)
2456 return 0;
2457
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002458 return 1;
2459}
2460
David Brazdil0f672f62019-12-10 10:32:29 +00002461struct TCP_Server_Info *
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002462cifs_find_tcp_session(struct smb_vol *vol)
2463{
2464 struct TCP_Server_Info *server;
2465
2466 spin_lock(&cifs_tcp_ses_lock);
2467 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
Olivier Deprez157378f2022-04-04 15:47:50 +02002468 /*
2469 * Skip ses channels since they're only handled in lower layers
2470 * (e.g. cifs_send_recv).
2471 */
2472 if (server->is_channel || !match_server(server, vol))
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002473 continue;
2474
2475 ++server->srv_count;
2476 spin_unlock(&cifs_tcp_ses_lock);
2477 cifs_dbg(FYI, "Existing tcp session with server found\n");
2478 return server;
2479 }
2480 spin_unlock(&cifs_tcp_ses_lock);
2481 return NULL;
2482}
2483
2484void
2485cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
2486{
2487 struct task_struct *task;
2488
2489 spin_lock(&cifs_tcp_ses_lock);
2490 if (--server->srv_count > 0) {
2491 spin_unlock(&cifs_tcp_ses_lock);
2492 return;
2493 }
2494
2495 put_net(cifs_net_ns(server));
2496
2497 list_del_init(&server->tcp_ses_list);
2498 spin_unlock(&cifs_tcp_ses_lock);
2499
2500 cancel_delayed_work_sync(&server->echo);
2501
2502 if (from_reconnect)
2503 /*
2504 * Avoid deadlock here: reconnect work calls
2505 * cifs_put_tcp_session() at its end. Need to be sure
2506 * that reconnect work does nothing with server pointer after
2507 * that step.
2508 */
2509 cancel_delayed_work(&server->reconnect);
2510 else
2511 cancel_delayed_work_sync(&server->reconnect);
2512
2513 spin_lock(&GlobalMid_Lock);
2514 server->tcpStatus = CifsExiting;
2515 spin_unlock(&GlobalMid_Lock);
2516
2517 cifs_crypto_secmech_release(server);
2518 cifs_fscache_release_client_cookie(server);
2519
2520 kfree(server->session_key.response);
2521 server->session_key.response = NULL;
2522 server->session_key.len = 0;
2523
2524 task = xchg(&server->tsk, NULL);
2525 if (task)
David Brazdil0f672f62019-12-10 10:32:29 +00002526 send_sig(SIGKILL, task, 1);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002527}
2528
Olivier Deprez157378f2022-04-04 15:47:50 +02002529struct TCP_Server_Info *
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002530cifs_get_tcp_session(struct smb_vol *volume_info)
2531{
2532 struct TCP_Server_Info *tcp_ses = NULL;
2533 int rc;
2534
2535 cifs_dbg(FYI, "UNC: %s\n", volume_info->UNC);
2536
2537 /* see if we already have a matching tcp_ses */
2538 tcp_ses = cifs_find_tcp_session(volume_info);
2539 if (tcp_ses)
2540 return tcp_ses;
2541
2542 tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
2543 if (!tcp_ses) {
2544 rc = -ENOMEM;
2545 goto out_err;
2546 }
2547
2548 tcp_ses->ops = volume_info->ops;
2549 tcp_ses->vals = volume_info->vals;
2550 cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
2551 tcp_ses->hostname = extract_hostname(volume_info->UNC);
2552 if (IS_ERR(tcp_ses->hostname)) {
2553 rc = PTR_ERR(tcp_ses->hostname);
2554 goto out_err_crypto_release;
2555 }
2556
David Brazdil0f672f62019-12-10 10:32:29 +00002557 tcp_ses->noblockcnt = volume_info->rootfs;
2558 tcp_ses->noblocksnd = volume_info->noblocksnd || volume_info->rootfs;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002559 tcp_ses->noautotune = volume_info->noautotune;
2560 tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
2561 tcp_ses->rdma = volume_info->rdma;
2562 tcp_ses->in_flight = 0;
David Brazdil0f672f62019-12-10 10:32:29 +00002563 tcp_ses->max_in_flight = 0;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002564 tcp_ses->credits = 1;
2565 init_waitqueue_head(&tcp_ses->response_q);
2566 init_waitqueue_head(&tcp_ses->request_q);
2567 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
2568 mutex_init(&tcp_ses->srv_mutex);
2569 memcpy(tcp_ses->workstation_RFC1001_name,
2570 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
2571 memcpy(tcp_ses->server_RFC1001_name,
2572 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
2573 tcp_ses->session_estab = false;
2574 tcp_ses->sequence_number = 0;
David Brazdil0f672f62019-12-10 10:32:29 +00002575 tcp_ses->reconnect_instance = 1;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002576 tcp_ses->lstrp = jiffies;
David Brazdil0f672f62019-12-10 10:32:29 +00002577 tcp_ses->compress_algorithm = cpu_to_le16(volume_info->compression);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002578 spin_lock_init(&tcp_ses->req_lock);
2579 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
2580 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
2581 INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
2582 INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server);
2583 mutex_init(&tcp_ses->reconnect_mutex);
2584 memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
2585 sizeof(tcp_ses->srcaddr));
2586 memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr,
2587 sizeof(tcp_ses->dstaddr));
Olivier Deprez157378f2022-04-04 15:47:50 +02002588 if (volume_info->use_client_guid)
2589 memcpy(tcp_ses->client_guid, volume_info->client_guid,
2590 SMB2_CLIENT_GUID_SIZE);
2591 else
2592 generate_random_uuid(tcp_ses->client_guid);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002593 /*
2594 * at this point we are the only ones with the pointer
2595 * to the struct since the kernel thread not created yet
2596 * no need to spinlock this init of tcpStatus or srv_count
2597 */
2598 tcp_ses->tcpStatus = CifsNew;
2599 ++tcp_ses->srv_count;
2600
2601 if (volume_info->echo_interval >= SMB_ECHO_INTERVAL_MIN &&
2602 volume_info->echo_interval <= SMB_ECHO_INTERVAL_MAX)
2603 tcp_ses->echo_interval = volume_info->echo_interval * HZ;
2604 else
2605 tcp_ses->echo_interval = SMB_ECHO_INTERVAL_DEFAULT * HZ;
2606 if (tcp_ses->rdma) {
2607#ifndef CONFIG_CIFS_SMB_DIRECT
2608 cifs_dbg(VFS, "CONFIG_CIFS_SMB_DIRECT is not enabled\n");
2609 rc = -ENOENT;
2610 goto out_err_crypto_release;
2611#endif
2612 tcp_ses->smbd_conn = smbd_get_connection(
2613 tcp_ses, (struct sockaddr *)&volume_info->dstaddr);
2614 if (tcp_ses->smbd_conn) {
2615 cifs_dbg(VFS, "RDMA transport established\n");
2616 rc = 0;
2617 goto smbd_connected;
2618 } else {
2619 rc = -ENOENT;
2620 goto out_err_crypto_release;
2621 }
2622 }
2623 rc = ip_connect(tcp_ses);
2624 if (rc < 0) {
2625 cifs_dbg(VFS, "Error connecting to socket. Aborting operation.\n");
2626 goto out_err_crypto_release;
2627 }
2628smbd_connected:
2629 /*
2630 * since we're in a cifs function already, we know that
2631 * this will succeed. No need for try_module_get().
2632 */
2633 __module_get(THIS_MODULE);
2634 tcp_ses->tsk = kthread_run(cifs_demultiplex_thread,
2635 tcp_ses, "cifsd");
2636 if (IS_ERR(tcp_ses->tsk)) {
2637 rc = PTR_ERR(tcp_ses->tsk);
2638 cifs_dbg(VFS, "error %d create cifsd thread\n", rc);
2639 module_put(THIS_MODULE);
2640 goto out_err_crypto_release;
2641 }
David Brazdil0f672f62019-12-10 10:32:29 +00002642 tcp_ses->min_offload = volume_info->min_offload;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002643 tcp_ses->tcpStatus = CifsNeedNegotiate;
2644
Olivier Deprez157378f2022-04-04 15:47:50 +02002645 if ((volume_info->max_credits < 20) || (volume_info->max_credits > 60000))
2646 tcp_ses->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
2647 else
2648 tcp_ses->max_credits = volume_info->max_credits;
2649
David Brazdil0f672f62019-12-10 10:32:29 +00002650 tcp_ses->nr_targets = 1;
2651 tcp_ses->ignore_signature = volume_info->ignore_signature;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002652 /* thread spawned, put it on the list */
2653 spin_lock(&cifs_tcp_ses_lock);
2654 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
2655 spin_unlock(&cifs_tcp_ses_lock);
2656
2657 cifs_fscache_get_client_cookie(tcp_ses);
2658
2659 /* queue echo request delayed work */
2660 queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval);
2661
2662 return tcp_ses;
2663
2664out_err_crypto_release:
2665 cifs_crypto_secmech_release(tcp_ses);
2666
2667 put_net(cifs_net_ns(tcp_ses));
2668
2669out_err:
2670 if (tcp_ses) {
2671 if (!IS_ERR(tcp_ses->hostname))
2672 kfree(tcp_ses->hostname);
2673 if (tcp_ses->ssocket)
2674 sock_release(tcp_ses->ssocket);
2675 kfree(tcp_ses);
2676 }
2677 return ERR_PTR(rc);
2678}
2679
2680static int match_session(struct cifs_ses *ses, struct smb_vol *vol)
2681{
2682 if (vol->sectype != Unspecified &&
2683 vol->sectype != ses->sectype)
2684 return 0;
2685
Olivier Deprez157378f2022-04-04 15:47:50 +02002686 /*
2687 * If an existing session is limited to less channels than
2688 * requested, it should not be reused
2689 */
2690 if (ses->chan_max < vol->max_channels)
2691 return 0;
2692
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002693 switch (ses->sectype) {
2694 case Kerberos:
2695 if (!uid_eq(vol->cred_uid, ses->cred_uid))
2696 return 0;
2697 break;
2698 default:
2699 /* NULL username means anonymous session */
2700 if (ses->user_name == NULL) {
2701 if (!vol->nullauth)
2702 return 0;
2703 break;
2704 }
2705
2706 /* anything else takes username/password */
2707 if (strncmp(ses->user_name,
2708 vol->username ? vol->username : "",
2709 CIFS_MAX_USERNAME_LEN))
2710 return 0;
2711 if ((vol->username && strlen(vol->username) != 0) &&
2712 ses->password != NULL &&
2713 strncmp(ses->password,
2714 vol->password ? vol->password : "",
2715 CIFS_MAX_PASSWORD_LEN))
2716 return 0;
2717 }
2718 return 1;
2719}
2720
2721/**
2722 * cifs_setup_ipc - helper to setup the IPC tcon for the session
2723 *
2724 * A new IPC connection is made and stored in the session
2725 * tcon_ipc. The IPC tcon has the same lifetime as the session.
2726 */
2727static int
2728cifs_setup_ipc(struct cifs_ses *ses, struct smb_vol *volume_info)
2729{
2730 int rc = 0, xid;
2731 struct cifs_tcon *tcon;
2732 struct nls_table *nls_codepage;
2733 char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0};
2734 bool seal = false;
David Brazdil0f672f62019-12-10 10:32:29 +00002735 struct TCP_Server_Info *server = ses->server;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002736
2737 /*
2738 * If the mount request that resulted in the creation of the
2739 * session requires encryption, force IPC to be encrypted too.
2740 */
2741 if (volume_info->seal) {
David Brazdil0f672f62019-12-10 10:32:29 +00002742 if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002743 seal = true;
2744 else {
David Brazdil0f672f62019-12-10 10:32:29 +00002745 cifs_server_dbg(VFS,
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002746 "IPC: server doesn't support encryption\n");
2747 return -EOPNOTSUPP;
2748 }
2749 }
2750
2751 tcon = tconInfoAlloc();
2752 if (tcon == NULL)
2753 return -ENOMEM;
2754
David Brazdil0f672f62019-12-10 10:32:29 +00002755 scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002756
2757 /* cannot fail */
2758 nls_codepage = load_nls_default();
2759
2760 xid = get_xid();
2761 tcon->ses = ses;
2762 tcon->ipc = true;
2763 tcon->seal = seal;
David Brazdil0f672f62019-12-10 10:32:29 +00002764 rc = server->ops->tree_connect(xid, ses, unc, tcon, nls_codepage);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002765 free_xid(xid);
2766
2767 if (rc) {
David Brazdil0f672f62019-12-10 10:32:29 +00002768 cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002769 tconInfoFree(tcon);
2770 goto out;
2771 }
2772
2773 cifs_dbg(FYI, "IPC tcon rc = %d ipc tid = %d\n", rc, tcon->tid);
2774
2775 ses->tcon_ipc = tcon;
2776out:
2777 unload_nls(nls_codepage);
2778 return rc;
2779}
2780
2781/**
2782 * cifs_free_ipc - helper to release the session IPC tcon
2783 *
2784 * Needs to be called everytime a session is destroyed
2785 */
2786static int
2787cifs_free_ipc(struct cifs_ses *ses)
2788{
2789 int rc = 0, xid;
2790 struct cifs_tcon *tcon = ses->tcon_ipc;
2791
2792 if (tcon == NULL)
2793 return 0;
2794
2795 if (ses->server->ops->tree_disconnect) {
2796 xid = get_xid();
2797 rc = ses->server->ops->tree_disconnect(xid, tcon);
2798 free_xid(xid);
2799 }
2800
2801 if (rc)
2802 cifs_dbg(FYI, "failed to disconnect IPC tcon (rc=%d)\n", rc);
2803
2804 tconInfoFree(tcon);
2805 ses->tcon_ipc = NULL;
2806 return rc;
2807}
2808
2809static struct cifs_ses *
2810cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
2811{
2812 struct cifs_ses *ses;
2813
2814 spin_lock(&cifs_tcp_ses_lock);
2815 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
2816 if (ses->status == CifsExiting)
2817 continue;
2818 if (!match_session(ses, vol))
2819 continue;
2820 ++ses->ses_count;
2821 spin_unlock(&cifs_tcp_ses_lock);
2822 return ses;
2823 }
2824 spin_unlock(&cifs_tcp_ses_lock);
2825 return NULL;
2826}
2827
David Brazdil0f672f62019-12-10 10:32:29 +00002828void cifs_put_smb_ses(struct cifs_ses *ses)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002829{
2830 unsigned int rc, xid;
2831 struct TCP_Server_Info *server = ses->server;
2832
2833 cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
2834
2835 spin_lock(&cifs_tcp_ses_lock);
2836 if (ses->status == CifsExiting) {
2837 spin_unlock(&cifs_tcp_ses_lock);
2838 return;
2839 }
2840 if (--ses->ses_count > 0) {
2841 spin_unlock(&cifs_tcp_ses_lock);
2842 return;
2843 }
Olivier Deprez0e641232021-09-23 10:07:05 +02002844 spin_unlock(&cifs_tcp_ses_lock);
2845
2846 spin_lock(&GlobalMid_Lock);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002847 if (ses->status == CifsGood)
2848 ses->status = CifsExiting;
Olivier Deprez0e641232021-09-23 10:07:05 +02002849 spin_unlock(&GlobalMid_Lock);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002850
2851 cifs_free_ipc(ses);
2852
2853 if (ses->status == CifsExiting && server->ops->logoff) {
2854 xid = get_xid();
2855 rc = server->ops->logoff(xid, ses);
2856 if (rc)
David Brazdil0f672f62019-12-10 10:32:29 +00002857 cifs_server_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002858 __func__, rc);
2859 _free_xid(xid);
2860 }
2861
2862 spin_lock(&cifs_tcp_ses_lock);
2863 list_del_init(&ses->smb_ses_list);
2864 spin_unlock(&cifs_tcp_ses_lock);
2865
Olivier Deprez157378f2022-04-04 15:47:50 +02002866 /* close any extra channels */
2867 if (ses->chan_count > 1) {
2868 int i;
2869
2870 for (i = 1; i < ses->chan_count; i++)
2871 cifs_put_tcp_session(ses->chans[i].server, 0);
2872 }
2873
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002874 sesInfoFree(ses);
2875 cifs_put_tcp_session(server, 0);
2876}
2877
2878#ifdef CONFIG_KEYS
2879
2880/* strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1 */
2881#define CIFSCREDS_DESC_SIZE (7 + CIFS_MAX_DOMAINNAME_LEN + 1)
2882
2883/* Populate username and pw fields from keyring if possible */
2884static int
2885cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
2886{
2887 int rc = 0;
David Brazdil0f672f62019-12-10 10:32:29 +00002888 int is_domain = 0;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002889 const char *delim, *payload;
2890 char *desc;
2891 ssize_t len;
2892 struct key *key;
2893 struct TCP_Server_Info *server = ses->server;
2894 struct sockaddr_in *sa;
2895 struct sockaddr_in6 *sa6;
2896 const struct user_key_payload *upayload;
2897
2898 desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
2899 if (!desc)
2900 return -ENOMEM;
2901
2902 /* try to find an address key first */
2903 switch (server->dstaddr.ss_family) {
2904 case AF_INET:
2905 sa = (struct sockaddr_in *)&server->dstaddr;
2906 sprintf(desc, "cifs:a:%pI4", &sa->sin_addr.s_addr);
2907 break;
2908 case AF_INET6:
2909 sa6 = (struct sockaddr_in6 *)&server->dstaddr;
2910 sprintf(desc, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr);
2911 break;
2912 default:
2913 cifs_dbg(FYI, "Bad ss_family (%hu)\n",
2914 server->dstaddr.ss_family);
2915 rc = -EINVAL;
2916 goto out_err;
2917 }
2918
2919 cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc);
2920 key = request_key(&key_type_logon, desc, "");
2921 if (IS_ERR(key)) {
2922 if (!ses->domainName) {
2923 cifs_dbg(FYI, "domainName is NULL\n");
2924 rc = PTR_ERR(key);
2925 goto out_err;
2926 }
2927
2928 /* didn't work, try to find a domain key */
2929 sprintf(desc, "cifs:d:%s", ses->domainName);
2930 cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc);
2931 key = request_key(&key_type_logon, desc, "");
2932 if (IS_ERR(key)) {
2933 rc = PTR_ERR(key);
2934 goto out_err;
2935 }
David Brazdil0f672f62019-12-10 10:32:29 +00002936 is_domain = 1;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002937 }
2938
2939 down_read(&key->sem);
2940 upayload = user_key_payload_locked(key);
2941 if (IS_ERR_OR_NULL(upayload)) {
2942 rc = upayload ? PTR_ERR(upayload) : -EINVAL;
2943 goto out_key_put;
2944 }
2945
2946 /* find first : in payload */
2947 payload = upayload->data;
2948 delim = strnchr(payload, upayload->datalen, ':');
2949 cifs_dbg(FYI, "payload=%s\n", payload);
2950 if (!delim) {
2951 cifs_dbg(FYI, "Unable to find ':' in payload (datalen=%d)\n",
2952 upayload->datalen);
2953 rc = -EINVAL;
2954 goto out_key_put;
2955 }
2956
2957 len = delim - payload;
2958 if (len > CIFS_MAX_USERNAME_LEN || len <= 0) {
2959 cifs_dbg(FYI, "Bad value from username search (len=%zd)\n",
2960 len);
2961 rc = -EINVAL;
2962 goto out_key_put;
2963 }
2964
2965 vol->username = kstrndup(payload, len, GFP_KERNEL);
2966 if (!vol->username) {
2967 cifs_dbg(FYI, "Unable to allocate %zd bytes for username\n",
2968 len);
2969 rc = -ENOMEM;
2970 goto out_key_put;
2971 }
2972 cifs_dbg(FYI, "%s: username=%s\n", __func__, vol->username);
2973
2974 len = key->datalen - (len + 1);
2975 if (len > CIFS_MAX_PASSWORD_LEN || len <= 0) {
2976 cifs_dbg(FYI, "Bad len for password search (len=%zd)\n", len);
2977 rc = -EINVAL;
2978 kfree(vol->username);
2979 vol->username = NULL;
2980 goto out_key_put;
2981 }
2982
2983 ++delim;
2984 vol->password = kstrndup(delim, len, GFP_KERNEL);
2985 if (!vol->password) {
2986 cifs_dbg(FYI, "Unable to allocate %zd bytes for password\n",
2987 len);
2988 rc = -ENOMEM;
2989 kfree(vol->username);
2990 vol->username = NULL;
2991 goto out_key_put;
2992 }
2993
David Brazdil0f672f62019-12-10 10:32:29 +00002994 /*
2995 * If we have a domain key then we must set the domainName in the
2996 * for the request.
2997 */
2998 if (is_domain && ses->domainName) {
2999 vol->domainname = kstrndup(ses->domainName,
3000 strlen(ses->domainName),
3001 GFP_KERNEL);
3002 if (!vol->domainname) {
Olivier Deprez157378f2022-04-04 15:47:50 +02003003 cifs_dbg(FYI, "Unable to allocate %zd bytes for domain\n",
3004 len);
David Brazdil0f672f62019-12-10 10:32:29 +00003005 rc = -ENOMEM;
3006 kfree(vol->username);
3007 vol->username = NULL;
Olivier Deprez157378f2022-04-04 15:47:50 +02003008 kfree_sensitive(vol->password);
David Brazdil0f672f62019-12-10 10:32:29 +00003009 vol->password = NULL;
3010 goto out_key_put;
3011 }
3012 }
3013
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003014out_key_put:
3015 up_read(&key->sem);
3016 key_put(key);
3017out_err:
3018 kfree(desc);
3019 cifs_dbg(FYI, "%s: returning %d\n", __func__, rc);
3020 return rc;
3021}
3022#else /* ! CONFIG_KEYS */
3023static inline int
3024cifs_set_cifscreds(struct smb_vol *vol __attribute__((unused)),
3025 struct cifs_ses *ses __attribute__((unused)))
3026{
3027 return -ENOSYS;
3028}
3029#endif /* CONFIG_KEYS */
3030
3031/**
3032 * cifs_get_smb_ses - get a session matching @volume_info data from @server
3033 *
3034 * This function assumes it is being called from cifs_mount() where we
3035 * already got a server reference (server refcount +1). See
3036 * cifs_get_tcon() for refcount explanations.
3037 */
David Brazdil0f672f62019-12-10 10:32:29 +00003038struct cifs_ses *
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003039cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
3040{
3041 int rc = -ENOMEM;
3042 unsigned int xid;
3043 struct cifs_ses *ses;
3044 struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
3045 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
3046
3047 xid = get_xid();
3048
3049 ses = cifs_find_smb_ses(server, volume_info);
3050 if (ses) {
3051 cifs_dbg(FYI, "Existing smb sess found (status=%d)\n",
3052 ses->status);
3053
3054 mutex_lock(&ses->session_mutex);
3055 rc = cifs_negotiate_protocol(xid, ses);
3056 if (rc) {
3057 mutex_unlock(&ses->session_mutex);
3058 /* problem -- put our ses reference */
3059 cifs_put_smb_ses(ses);
3060 free_xid(xid);
3061 return ERR_PTR(rc);
3062 }
3063 if (ses->need_reconnect) {
3064 cifs_dbg(FYI, "Session needs reconnect\n");
3065 rc = cifs_setup_session(xid, ses,
3066 volume_info->local_nls);
3067 if (rc) {
3068 mutex_unlock(&ses->session_mutex);
3069 /* problem -- put our reference */
3070 cifs_put_smb_ses(ses);
3071 free_xid(xid);
3072 return ERR_PTR(rc);
3073 }
3074 }
3075 mutex_unlock(&ses->session_mutex);
3076
3077 /* existing SMB ses has a server reference already */
3078 cifs_put_tcp_session(server, 0);
3079 free_xid(xid);
3080 return ses;
3081 }
3082
3083 cifs_dbg(FYI, "Existing smb sess not found\n");
3084 ses = sesInfoAlloc();
3085 if (ses == NULL)
3086 goto get_ses_fail;
3087
3088 /* new SMB session uses our server ref */
3089 ses->server = server;
3090 if (server->dstaddr.ss_family == AF_INET6)
3091 sprintf(ses->serverName, "%pI6", &addr6->sin6_addr);
3092 else
3093 sprintf(ses->serverName, "%pI4", &addr->sin_addr);
3094
3095 if (volume_info->username) {
3096 ses->user_name = kstrdup(volume_info->username, GFP_KERNEL);
3097 if (!ses->user_name)
3098 goto get_ses_fail;
3099 }
3100
3101 /* volume_info->password freed at unmount */
3102 if (volume_info->password) {
3103 ses->password = kstrdup(volume_info->password, GFP_KERNEL);
3104 if (!ses->password)
3105 goto get_ses_fail;
3106 }
3107 if (volume_info->domainname) {
3108 ses->domainName = kstrdup(volume_info->domainname, GFP_KERNEL);
3109 if (!ses->domainName)
3110 goto get_ses_fail;
3111 }
3112 if (volume_info->domainauto)
3113 ses->domainAuto = volume_info->domainauto;
3114 ses->cred_uid = volume_info->cred_uid;
3115 ses->linux_uid = volume_info->linux_uid;
3116
3117 ses->sectype = volume_info->sectype;
3118 ses->sign = volume_info->sign;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003119 mutex_lock(&ses->session_mutex);
Olivier Deprez157378f2022-04-04 15:47:50 +02003120
3121 /* add server as first channel */
3122 ses->chans[0].server = server;
3123 ses->chan_count = 1;
3124 ses->chan_max = volume_info->multichannel ? volume_info->max_channels:1;
3125
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003126 rc = cifs_negotiate_protocol(xid, ses);
3127 if (!rc)
3128 rc = cifs_setup_session(xid, ses, volume_info->local_nls);
Olivier Deprez157378f2022-04-04 15:47:50 +02003129
3130 /* each channel uses a different signing key */
3131 memcpy(ses->chans[0].signkey, ses->smb3signingkey,
3132 sizeof(ses->smb3signingkey));
3133
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003134 mutex_unlock(&ses->session_mutex);
3135 if (rc)
3136 goto get_ses_fail;
3137
Olivier Deprez157378f2022-04-04 15:47:50 +02003138 /* success, put it on the list and add it as first channel */
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003139 spin_lock(&cifs_tcp_ses_lock);
3140 list_add(&ses->smb_ses_list, &server->smb_ses_list);
3141 spin_unlock(&cifs_tcp_ses_lock);
3142
3143 free_xid(xid);
3144
3145 cifs_setup_ipc(ses, volume_info);
3146
3147 return ses;
3148
3149get_ses_fail:
3150 sesInfoFree(ses);
3151 free_xid(xid);
3152 return ERR_PTR(rc);
3153}
3154
3155static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info)
3156{
3157 if (tcon->tidStatus == CifsExiting)
3158 return 0;
3159 if (strncmp(tcon->treeName, volume_info->UNC, MAX_TREE_SIZE))
3160 return 0;
3161 if (tcon->seal != volume_info->seal)
3162 return 0;
3163 if (tcon->snapshot_time != volume_info->snapshot_time)
3164 return 0;
David Brazdil0f672f62019-12-10 10:32:29 +00003165 if (tcon->handle_timeout != volume_info->handle_timeout)
3166 return 0;
3167 if (tcon->no_lease != volume_info->no_lease)
3168 return 0;
Olivier Deprez157378f2022-04-04 15:47:50 +02003169 if (tcon->nodelete != volume_info->nodelete)
3170 return 0;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003171 return 1;
3172}
3173
3174static struct cifs_tcon *
3175cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
3176{
3177 struct list_head *tmp;
3178 struct cifs_tcon *tcon;
3179
3180 spin_lock(&cifs_tcp_ses_lock);
3181 list_for_each(tmp, &ses->tcon_list) {
3182 tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
Olivier Deprez0e641232021-09-23 10:07:05 +02003183#ifdef CONFIG_CIFS_DFS_UPCALL
3184 if (tcon->dfs_path)
3185 continue;
3186#endif
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003187 if (!match_tcon(tcon, volume_info))
3188 continue;
3189 ++tcon->tc_count;
3190 spin_unlock(&cifs_tcp_ses_lock);
3191 return tcon;
3192 }
3193 spin_unlock(&cifs_tcp_ses_lock);
3194 return NULL;
3195}
3196
3197void
3198cifs_put_tcon(struct cifs_tcon *tcon)
3199{
3200 unsigned int xid;
3201 struct cifs_ses *ses;
3202
3203 /*
3204 * IPC tcon share the lifetime of their session and are
3205 * destroyed in the session put function
3206 */
3207 if (tcon == NULL || tcon->ipc)
3208 return;
3209
3210 ses = tcon->ses;
3211 cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count);
3212 spin_lock(&cifs_tcp_ses_lock);
3213 if (--tcon->tc_count > 0) {
3214 spin_unlock(&cifs_tcp_ses_lock);
3215 return;
3216 }
3217
3218 list_del_init(&tcon->tcon_list);
3219 spin_unlock(&cifs_tcp_ses_lock);
3220
3221 xid = get_xid();
3222 if (ses->server->ops->tree_disconnect)
3223 ses->server->ops->tree_disconnect(xid, tcon);
3224 _free_xid(xid);
3225
3226 cifs_fscache_release_super_cookie(tcon);
3227 tconInfoFree(tcon);
3228 cifs_put_smb_ses(ses);
3229}
3230
3231/**
3232 * cifs_get_tcon - get a tcon matching @volume_info data from @ses
3233 *
3234 * - tcon refcount is the number of mount points using the tcon.
3235 * - ses refcount is the number of tcon using the session.
3236 *
3237 * 1. This function assumes it is being called from cifs_mount() where
3238 * we already got a session reference (ses refcount +1).
3239 *
3240 * 2. Since we're in the context of adding a mount point, the end
3241 * result should be either:
3242 *
3243 * a) a new tcon already allocated with refcount=1 (1 mount point) and
3244 * its session refcount incremented (1 new tcon). This +1 was
3245 * already done in (1).
3246 *
3247 * b) an existing tcon with refcount+1 (add a mount point to it) and
3248 * identical ses refcount (no new tcon). Because of (1) we need to
3249 * decrement the ses refcount.
3250 */
3251static struct cifs_tcon *
3252cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
3253{
3254 int rc, xid;
3255 struct cifs_tcon *tcon;
3256
3257 tcon = cifs_find_tcon(ses, volume_info);
3258 if (tcon) {
3259 /*
3260 * tcon has refcount already incremented but we need to
3261 * decrement extra ses reference gotten by caller (case b)
3262 */
3263 cifs_dbg(FYI, "Found match on UNC path\n");
3264 cifs_put_smb_ses(ses);
3265 return tcon;
3266 }
3267
3268 if (!ses->server->ops->tree_connect) {
3269 rc = -ENOSYS;
3270 goto out_fail;
3271 }
3272
3273 tcon = tconInfoAlloc();
3274 if (tcon == NULL) {
3275 rc = -ENOMEM;
3276 goto out_fail;
3277 }
3278
3279 if (volume_info->snapshot_time) {
3280 if (ses->server->vals->protocol_id == 0) {
3281 cifs_dbg(VFS,
3282 "Use SMB2 or later for snapshot mount option\n");
3283 rc = -EOPNOTSUPP;
3284 goto out_fail;
3285 } else
3286 tcon->snapshot_time = volume_info->snapshot_time;
3287 }
3288
David Brazdil0f672f62019-12-10 10:32:29 +00003289 if (volume_info->handle_timeout) {
3290 if (ses->server->vals->protocol_id == 0) {
3291 cifs_dbg(VFS,
3292 "Use SMB2.1 or later for handle timeout option\n");
3293 rc = -EOPNOTSUPP;
3294 goto out_fail;
3295 } else
3296 tcon->handle_timeout = volume_info->handle_timeout;
3297 }
3298
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003299 tcon->ses = ses;
3300 if (volume_info->password) {
3301 tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
3302 if (!tcon->password) {
3303 rc = -ENOMEM;
3304 goto out_fail;
3305 }
3306 }
3307
3308 if (volume_info->seal) {
3309 if (ses->server->vals->protocol_id == 0) {
3310 cifs_dbg(VFS,
3311 "SMB3 or later required for encryption\n");
3312 rc = -EOPNOTSUPP;
3313 goto out_fail;
3314 } else if (tcon->ses->server->capabilities &
3315 SMB2_GLOBAL_CAP_ENCRYPTION)
3316 tcon->seal = true;
3317 else {
3318 cifs_dbg(VFS, "Encryption is not supported on share\n");
3319 rc = -EOPNOTSUPP;
3320 goto out_fail;
3321 }
3322 }
3323
3324 if (volume_info->linux_ext) {
3325 if (ses->server->posix_ext_supported) {
3326 tcon->posix_extensions = true;
Olivier Deprez157378f2022-04-04 15:47:50 +02003327 pr_warn_once("SMB3.11 POSIX Extensions are experimental\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003328 } else {
Olivier Deprez157378f2022-04-04 15:47:50 +02003329 cifs_dbg(VFS, "Server does not support mounting with posix SMB3.11 extensions\n");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003330 rc = -EOPNOTSUPP;
3331 goto out_fail;
3332 }
3333 }
3334
3335 /*
3336 * BB Do we need to wrap session_mutex around this TCon call and Unix
3337 * SetFS as we do on SessSetup and reconnect?
3338 */
3339 xid = get_xid();
3340 rc = ses->server->ops->tree_connect(xid, ses, volume_info->UNC, tcon,
3341 volume_info->local_nls);
3342 free_xid(xid);
3343 cifs_dbg(FYI, "Tcon rc = %d\n", rc);
3344 if (rc)
3345 goto out_fail;
3346
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003347 tcon->use_persistent = false;
3348 /* check if SMB2 or later, CIFS does not support persistent handles */
3349 if (volume_info->persistent) {
3350 if (ses->server->vals->protocol_id == 0) {
3351 cifs_dbg(VFS,
3352 "SMB3 or later required for persistent handles\n");
3353 rc = -EOPNOTSUPP;
3354 goto out_fail;
3355 } else if (ses->server->capabilities &
3356 SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)
3357 tcon->use_persistent = true;
3358 else /* persistent handles requested but not supported */ {
3359 cifs_dbg(VFS,
3360 "Persistent handles not supported on share\n");
3361 rc = -EOPNOTSUPP;
3362 goto out_fail;
3363 }
3364 } else if ((tcon->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY)
3365 && (ses->server->capabilities & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)
3366 && (volume_info->nopersistent == false)) {
3367 cifs_dbg(FYI, "enabling persistent handles\n");
3368 tcon->use_persistent = true;
3369 } else if (volume_info->resilient) {
3370 if (ses->server->vals->protocol_id == 0) {
3371 cifs_dbg(VFS,
3372 "SMB2.1 or later required for resilient handles\n");
3373 rc = -EOPNOTSUPP;
3374 goto out_fail;
3375 }
3376 tcon->use_resilient = true;
3377 }
3378
David Brazdil0f672f62019-12-10 10:32:29 +00003379 /* If the user really knows what they are doing they can override */
3380 if (tcon->share_flags & SMB2_SHAREFLAG_NO_CACHING) {
3381 if (volume_info->cache_ro)
3382 cifs_dbg(VFS, "cache=ro requested on mount but NO_CACHING flag set on share\n");
3383 else if (volume_info->cache_rw)
3384 cifs_dbg(VFS, "cache=singleclient requested on mount but NO_CACHING flag set on share\n");
3385 }
3386
Olivier Deprez157378f2022-04-04 15:47:50 +02003387 if (volume_info->no_lease) {
3388 if (ses->server->vals->protocol_id == 0) {
3389 cifs_dbg(VFS,
3390 "SMB2 or later required for nolease option\n");
3391 rc = -EOPNOTSUPP;
3392 goto out_fail;
3393 } else
3394 tcon->no_lease = volume_info->no_lease;
3395 }
3396
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003397 /*
3398 * We can have only one retry value for a connection to a share so for
3399 * resources mounted more than once to the same server share the last
3400 * value passed in for the retry flag is used.
3401 */
3402 tcon->retry = volume_info->retry;
3403 tcon->nocase = volume_info->nocase;
Olivier Deprez157378f2022-04-04 15:47:50 +02003404 if (ses->server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING)
3405 tcon->nohandlecache = volume_info->nohandlecache;
3406 else
3407 tcon->nohandlecache = 1;
3408 tcon->nodelete = volume_info->nodelete;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003409 tcon->local_lease = volume_info->local_lease;
3410 INIT_LIST_HEAD(&tcon->pending_opens);
3411
3412 spin_lock(&cifs_tcp_ses_lock);
3413 list_add(&tcon->tcon_list, &ses->tcon_list);
3414 spin_unlock(&cifs_tcp_ses_lock);
3415
3416 cifs_fscache_get_super_cookie(tcon);
3417
3418 return tcon;
3419
3420out_fail:
3421 tconInfoFree(tcon);
3422 return ERR_PTR(rc);
3423}
3424
3425void
3426cifs_put_tlink(struct tcon_link *tlink)
3427{
3428 if (!tlink || IS_ERR(tlink))
3429 return;
3430
3431 if (!atomic_dec_and_test(&tlink->tl_count) ||
3432 test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) {
3433 tlink->tl_time = jiffies;
3434 return;
3435 }
3436
3437 if (!IS_ERR(tlink_tcon(tlink)))
3438 cifs_put_tcon(tlink_tcon(tlink));
3439 kfree(tlink);
3440 return;
3441}
3442
3443static int
3444compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
3445{
3446 struct cifs_sb_info *old = CIFS_SB(sb);
3447 struct cifs_sb_info *new = mnt_data->cifs_sb;
David Brazdil0f672f62019-12-10 10:32:29 +00003448 unsigned int oldflags = old->mnt_cifs_flags & CIFS_MOUNT_MASK;
3449 unsigned int newflags = new->mnt_cifs_flags & CIFS_MOUNT_MASK;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003450
3451 if ((sb->s_flags & CIFS_MS_MASK) != (mnt_data->flags & CIFS_MS_MASK))
3452 return 0;
3453
David Brazdil0f672f62019-12-10 10:32:29 +00003454 if (old->mnt_cifs_serverino_autodisabled)
3455 newflags &= ~CIFS_MOUNT_SERVER_INUM;
3456
3457 if (oldflags != newflags)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003458 return 0;
3459
3460 /*
3461 * We want to share sb only if we don't specify an r/wsize or
3462 * specified r/wsize is greater than or equal to existing one.
3463 */
3464 if (new->wsize && new->wsize < old->wsize)
3465 return 0;
3466
3467 if (new->rsize && new->rsize < old->rsize)
3468 return 0;
3469
3470 if (!uid_eq(old->mnt_uid, new->mnt_uid) || !gid_eq(old->mnt_gid, new->mnt_gid))
3471 return 0;
3472
3473 if (old->mnt_file_mode != new->mnt_file_mode ||
3474 old->mnt_dir_mode != new->mnt_dir_mode)
3475 return 0;
3476
3477 if (strcmp(old->local_nls->charset, new->local_nls->charset))
3478 return 0;
3479
3480 if (old->actimeo != new->actimeo)
3481 return 0;
3482
3483 return 1;
3484}
3485
3486static int
3487match_prepath(struct super_block *sb, struct cifs_mnt_data *mnt_data)
3488{
3489 struct cifs_sb_info *old = CIFS_SB(sb);
3490 struct cifs_sb_info *new = mnt_data->cifs_sb;
Olivier Deprez0e641232021-09-23 10:07:05 +02003491 bool old_set = (old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
3492 old->prepath;
3493 bool new_set = (new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
3494 new->prepath;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003495
3496 if (old_set && new_set && !strcmp(new->prepath, old->prepath))
3497 return 1;
3498 else if (!old_set && !new_set)
3499 return 1;
3500
3501 return 0;
3502}
3503
3504int
3505cifs_match_super(struct super_block *sb, void *data)
3506{
3507 struct cifs_mnt_data *mnt_data = (struct cifs_mnt_data *)data;
3508 struct smb_vol *volume_info;
3509 struct cifs_sb_info *cifs_sb;
3510 struct TCP_Server_Info *tcp_srv;
3511 struct cifs_ses *ses;
3512 struct cifs_tcon *tcon;
3513 struct tcon_link *tlink;
3514 int rc = 0;
3515
3516 spin_lock(&cifs_tcp_ses_lock);
3517 cifs_sb = CIFS_SB(sb);
3518 tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
Olivier Deprez157378f2022-04-04 15:47:50 +02003519 if (tlink == NULL) {
3520 /* can not match superblock if tlink were ever null */
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003521 spin_unlock(&cifs_tcp_ses_lock);
Olivier Deprez157378f2022-04-04 15:47:50 +02003522 return 0;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003523 }
3524 tcon = tlink_tcon(tlink);
3525 ses = tcon->ses;
3526 tcp_srv = ses->server;
3527
3528 volume_info = mnt_data->vol;
3529
3530 if (!match_server(tcp_srv, volume_info) ||
3531 !match_session(ses, volume_info) ||
3532 !match_tcon(tcon, volume_info) ||
3533 !match_prepath(sb, mnt_data)) {
3534 rc = 0;
3535 goto out;
3536 }
3537
3538 rc = compare_mount_options(sb, mnt_data);
3539out:
3540 spin_unlock(&cifs_tcp_ses_lock);
3541 cifs_put_tlink(tlink);
3542 return rc;
3543}
3544
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003545#ifdef CONFIG_DEBUG_LOCK_ALLOC
3546static struct lock_class_key cifs_key[2];
3547static struct lock_class_key cifs_slock_key[2];
3548
3549static inline void
3550cifs_reclassify_socket4(struct socket *sock)
3551{
3552 struct sock *sk = sock->sk;
3553 BUG_ON(!sock_allow_reclassification(sk));
3554 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
3555 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
3556}
3557
3558static inline void
3559cifs_reclassify_socket6(struct socket *sock)
3560{
3561 struct sock *sk = sock->sk;
3562 BUG_ON(!sock_allow_reclassification(sk));
3563 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
3564 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
3565}
3566#else
3567static inline void
3568cifs_reclassify_socket4(struct socket *sock)
3569{
3570}
3571
3572static inline void
3573cifs_reclassify_socket6(struct socket *sock)
3574{
3575}
3576#endif
3577
3578/* See RFC1001 section 14 on representation of Netbios names */
3579static void rfc1002mangle(char *target, char *source, unsigned int length)
3580{
3581 unsigned int i, j;
3582
3583 for (i = 0, j = 0; i < (length); i++) {
3584 /* mask a nibble at a time and encode */
3585 target[j] = 'A' + (0x0F & (source[i] >> 4));
3586 target[j+1] = 'A' + (0x0F & source[i]);
3587 j += 2;
3588 }
3589
3590}
3591
3592static int
3593bind_socket(struct TCP_Server_Info *server)
3594{
3595 int rc = 0;
3596 if (server->srcaddr.ss_family != AF_UNSPEC) {
3597 /* Bind to the specified local IP address */
3598 struct socket *socket = server->ssocket;
3599 rc = socket->ops->bind(socket,
3600 (struct sockaddr *) &server->srcaddr,
3601 sizeof(server->srcaddr));
3602 if (rc < 0) {
3603 struct sockaddr_in *saddr4;
3604 struct sockaddr_in6 *saddr6;
3605 saddr4 = (struct sockaddr_in *)&server->srcaddr;
3606 saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
3607 if (saddr6->sin6_family == AF_INET6)
David Brazdil0f672f62019-12-10 10:32:29 +00003608 cifs_server_dbg(VFS, "Failed to bind to: %pI6c, error: %d\n",
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003609 &saddr6->sin6_addr, rc);
3610 else
David Brazdil0f672f62019-12-10 10:32:29 +00003611 cifs_server_dbg(VFS, "Failed to bind to: %pI4, error: %d\n",
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003612 &saddr4->sin_addr.s_addr, rc);
3613 }
3614 }
3615 return rc;
3616}
3617
3618static int
3619ip_rfc1001_connect(struct TCP_Server_Info *server)
3620{
3621 int rc = 0;
3622 /*
3623 * some servers require RFC1001 sessinit before sending
3624 * negprot - BB check reconnection in case where second
3625 * sessinit is sent but no second negprot
3626 */
3627 struct rfc1002_session_packet *ses_init_buf;
3628 struct smb_hdr *smb_buf;
3629 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
3630 GFP_KERNEL);
3631 if (ses_init_buf) {
3632 ses_init_buf->trailer.session_req.called_len = 32;
3633
3634 if (server->server_RFC1001_name[0] != 0)
3635 rfc1002mangle(ses_init_buf->trailer.
3636 session_req.called_name,
3637 server->server_RFC1001_name,
3638 RFC1001_NAME_LEN_WITH_NULL);
3639 else
3640 rfc1002mangle(ses_init_buf->trailer.
3641 session_req.called_name,
3642 DEFAULT_CIFS_CALLED_NAME,
3643 RFC1001_NAME_LEN_WITH_NULL);
3644
3645 ses_init_buf->trailer.session_req.calling_len = 32;
3646
3647 /*
3648 * calling name ends in null (byte 16) from old smb
3649 * convention.
3650 */
3651 if (server->workstation_RFC1001_name[0] != 0)
3652 rfc1002mangle(ses_init_buf->trailer.
3653 session_req.calling_name,
3654 server->workstation_RFC1001_name,
3655 RFC1001_NAME_LEN_WITH_NULL);
3656 else
3657 rfc1002mangle(ses_init_buf->trailer.
3658 session_req.calling_name,
3659 "LINUX_CIFS_CLNT",
3660 RFC1001_NAME_LEN_WITH_NULL);
3661
3662 ses_init_buf->trailer.session_req.scope1 = 0;
3663 ses_init_buf->trailer.session_req.scope2 = 0;
3664 smb_buf = (struct smb_hdr *)ses_init_buf;
3665
3666 /* sizeof RFC1002_SESSION_REQUEST with no scope */
3667 smb_buf->smb_buf_length = cpu_to_be32(0x81000044);
3668 rc = smb_send(server, smb_buf, 0x44);
3669 kfree(ses_init_buf);
3670 /*
3671 * RFC1001 layer in at least one server
3672 * requires very short break before negprot
3673 * presumably because not expecting negprot
3674 * to follow so fast. This is a simple
3675 * solution that works without
3676 * complicating the code and causes no
3677 * significant slowing down on mount
3678 * for everyone else
3679 */
3680 usleep_range(1000, 2000);
3681 }
3682 /*
3683 * else the negprot may still work without this
3684 * even though malloc failed
3685 */
3686
3687 return rc;
3688}
3689
3690static int
3691generic_ip_connect(struct TCP_Server_Info *server)
3692{
3693 int rc = 0;
3694 __be16 sport;
3695 int slen, sfamily;
3696 struct socket *socket = server->ssocket;
3697 struct sockaddr *saddr;
3698
3699 saddr = (struct sockaddr *) &server->dstaddr;
3700
3701 if (server->dstaddr.ss_family == AF_INET6) {
Olivier Deprez157378f2022-04-04 15:47:50 +02003702 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&server->dstaddr;
3703
3704 sport = ipv6->sin6_port;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003705 slen = sizeof(struct sockaddr_in6);
3706 sfamily = AF_INET6;
Olivier Deprez157378f2022-04-04 15:47:50 +02003707 cifs_dbg(FYI, "%s: connecting to [%pI6]:%d\n", __func__, &ipv6->sin6_addr,
3708 ntohs(sport));
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003709 } else {
Olivier Deprez157378f2022-04-04 15:47:50 +02003710 struct sockaddr_in *ipv4 = (struct sockaddr_in *)&server->dstaddr;
3711
3712 sport = ipv4->sin_port;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003713 slen = sizeof(struct sockaddr_in);
3714 sfamily = AF_INET;
Olivier Deprez157378f2022-04-04 15:47:50 +02003715 cifs_dbg(FYI, "%s: connecting to %pI4:%d\n", __func__, &ipv4->sin_addr,
3716 ntohs(sport));
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003717 }
3718
3719 if (socket == NULL) {
3720 rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM,
3721 IPPROTO_TCP, &socket, 1);
3722 if (rc < 0) {
David Brazdil0f672f62019-12-10 10:32:29 +00003723 cifs_server_dbg(VFS, "Error %d creating socket\n", rc);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003724 server->ssocket = NULL;
3725 return rc;
3726 }
3727
3728 /* BB other socket options to set KEEPALIVE, NODELAY? */
3729 cifs_dbg(FYI, "Socket created\n");
3730 server->ssocket = socket;
3731 socket->sk->sk_allocation = GFP_NOFS;
3732 if (sfamily == AF_INET6)
3733 cifs_reclassify_socket6(socket);
3734 else
3735 cifs_reclassify_socket4(socket);
3736 }
3737
3738 rc = bind_socket(server);
3739 if (rc < 0)
3740 return rc;
3741
3742 /*
3743 * Eventually check for other socket options to change from
3744 * the default. sock_setsockopt not used because it expects
3745 * user space buffer
3746 */
3747 socket->sk->sk_rcvtimeo = 7 * HZ;
3748 socket->sk->sk_sndtimeo = 5 * HZ;
3749
3750 /* make the bufsizes depend on wsize/rsize and max requests */
3751 if (server->noautotune) {
3752 if (socket->sk->sk_sndbuf < (200 * 1024))
3753 socket->sk->sk_sndbuf = 200 * 1024;
3754 if (socket->sk->sk_rcvbuf < (140 * 1024))
3755 socket->sk->sk_rcvbuf = 140 * 1024;
3756 }
3757
Olivier Deprez157378f2022-04-04 15:47:50 +02003758 if (server->tcp_nodelay)
3759 tcp_sock_set_nodelay(socket->sk);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003760
3761 cifs_dbg(FYI, "sndbuf %d rcvbuf %d rcvtimeo 0x%lx\n",
3762 socket->sk->sk_sndbuf,
3763 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
3764
David Brazdil0f672f62019-12-10 10:32:29 +00003765 rc = socket->ops->connect(socket, saddr, slen,
3766 server->noblockcnt ? O_NONBLOCK : 0);
3767 /*
3768 * When mounting SMB root file systems, we do not want to block in
3769 * connect. Otherwise bail out and then let cifs_reconnect() perform
3770 * reconnect failover - if possible.
3771 */
3772 if (server->noblockcnt && rc == -EINPROGRESS)
3773 rc = 0;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003774 if (rc < 0) {
3775 cifs_dbg(FYI, "Error %d connecting to server\n", rc);
3776 sock_release(socket);
3777 server->ssocket = NULL;
3778 return rc;
3779 }
3780
3781 if (sport == htons(RFC1001_PORT))
3782 rc = ip_rfc1001_connect(server);
3783
3784 return rc;
3785}
3786
3787static int
3788ip_connect(struct TCP_Server_Info *server)
3789{
3790 __be16 *sport;
3791 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
3792 struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
3793
3794 if (server->dstaddr.ss_family == AF_INET6)
3795 sport = &addr6->sin6_port;
3796 else
3797 sport = &addr->sin_port;
3798
3799 if (*sport == 0) {
3800 int rc;
3801
3802 /* try with 445 port at first */
3803 *sport = htons(CIFS_PORT);
3804
3805 rc = generic_ip_connect(server);
3806 if (rc >= 0)
3807 return rc;
3808
3809 /* if it failed, try with 139 port */
3810 *sport = htons(RFC1001_PORT);
3811 }
3812
3813 return generic_ip_connect(server);
3814}
3815
3816void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
3817 struct cifs_sb_info *cifs_sb, struct smb_vol *vol_info)
3818{
3819 /* if we are reconnecting then should we check to see if
3820 * any requested capabilities changed locally e.g. via
3821 * remount but we can not do much about it here
3822 * if they have (even if we could detect it by the following)
3823 * Perhaps we could add a backpointer to array of sb from tcon
3824 * or if we change to make all sb to same share the same
3825 * sb as NFS - then we only have one backpointer to sb.
3826 * What if we wanted to mount the server share twice once with
3827 * and once without posixacls or posix paths? */
3828 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
3829
3830 if (vol_info && vol_info->no_linux_ext) {
3831 tcon->fsUnixInfo.Capability = 0;
3832 tcon->unix_ext = 0; /* Unix Extensions disabled */
3833 cifs_dbg(FYI, "Linux protocol extensions disabled\n");
3834 return;
3835 } else if (vol_info)
3836 tcon->unix_ext = 1; /* Unix Extensions supported */
3837
3838 if (tcon->unix_ext == 0) {
3839 cifs_dbg(FYI, "Unix extensions disabled so not set on reconnect\n");
3840 return;
3841 }
3842
3843 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
3844 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
3845 cifs_dbg(FYI, "unix caps which server supports %lld\n", cap);
3846 /* check for reconnect case in which we do not
3847 want to change the mount behavior if we can avoid it */
3848 if (vol_info == NULL) {
3849 /* turn off POSIX ACL and PATHNAMES if not set
3850 originally at mount time */
3851 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
3852 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
3853 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
3854 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
3855 cifs_dbg(VFS, "POSIXPATH support change\n");
3856 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
3857 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
3858 cifs_dbg(VFS, "possible reconnect error\n");
3859 cifs_dbg(VFS, "server disabled POSIX path support\n");
3860 }
3861 }
3862
3863 if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
3864 cifs_dbg(VFS, "per-share encryption not supported yet\n");
3865
3866 cap &= CIFS_UNIX_CAP_MASK;
3867 if (vol_info && vol_info->no_psx_acl)
3868 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
3869 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
3870 cifs_dbg(FYI, "negotiated posix acl support\n");
3871 if (cifs_sb)
3872 cifs_sb->mnt_cifs_flags |=
3873 CIFS_MOUNT_POSIXACL;
3874 }
3875
3876 if (vol_info && vol_info->posix_paths == 0)
3877 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
3878 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3879 cifs_dbg(FYI, "negotiate posix pathnames\n");
3880 if (cifs_sb)
3881 cifs_sb->mnt_cifs_flags |=
3882 CIFS_MOUNT_POSIX_PATHS;
3883 }
3884
3885 cifs_dbg(FYI, "Negotiate caps 0x%x\n", (int)cap);
3886#ifdef CONFIG_CIFS_DEBUG2
3887 if (cap & CIFS_UNIX_FCNTL_CAP)
3888 cifs_dbg(FYI, "FCNTL cap\n");
3889 if (cap & CIFS_UNIX_EXTATTR_CAP)
3890 cifs_dbg(FYI, "EXTATTR cap\n");
3891 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
3892 cifs_dbg(FYI, "POSIX path cap\n");
3893 if (cap & CIFS_UNIX_XATTR_CAP)
3894 cifs_dbg(FYI, "XATTR cap\n");
3895 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
3896 cifs_dbg(FYI, "POSIX ACL cap\n");
3897 if (cap & CIFS_UNIX_LARGE_READ_CAP)
3898 cifs_dbg(FYI, "very large read cap\n");
3899 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
3900 cifs_dbg(FYI, "very large write cap\n");
3901 if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)
3902 cifs_dbg(FYI, "transport encryption cap\n");
3903 if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
3904 cifs_dbg(FYI, "mandatory transport encryption cap\n");
3905#endif /* CIFS_DEBUG2 */
3906 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
3907 if (vol_info == NULL) {
3908 cifs_dbg(FYI, "resetting capabilities failed\n");
3909 } else
3910 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");
3911
3912 }
3913 }
3914}
3915
3916int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
3917 struct cifs_sb_info *cifs_sb)
3918{
3919 INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
3920
3921 spin_lock_init(&cifs_sb->tlink_tree_lock);
3922 cifs_sb->tlink_tree = RB_ROOT;
3923
David Brazdil0f672f62019-12-10 10:32:29 +00003924 cifs_sb->bsize = pvolume_info->bsize;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003925 /*
3926 * Temporarily set r/wsize for matching superblock. If we end up using
3927 * new sb then client will later negotiate it downward if needed.
3928 */
3929 cifs_sb->rsize = pvolume_info->rsize;
3930 cifs_sb->wsize = pvolume_info->wsize;
3931
3932 cifs_sb->mnt_uid = pvolume_info->linux_uid;
3933 cifs_sb->mnt_gid = pvolume_info->linux_gid;
3934 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
3935 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
Olivier Deprez0e641232021-09-23 10:07:05 +02003936 cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n",
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003937 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode);
3938
3939 cifs_sb->actimeo = pvolume_info->actimeo;
3940 cifs_sb->local_nls = pvolume_info->local_nls;
3941
David Brazdil0f672f62019-12-10 10:32:29 +00003942 if (pvolume_info->nodfs)
3943 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_DFS;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003944 if (pvolume_info->noperm)
3945 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
3946 if (pvolume_info->setuids)
3947 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
3948 if (pvolume_info->setuidfromacl)
3949 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UID_FROM_ACL;
3950 if (pvolume_info->server_ino)
3951 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
3952 if (pvolume_info->remap)
3953 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR;
3954 if (pvolume_info->sfu_remap)
3955 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
3956 if (pvolume_info->no_xattr)
3957 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
3958 if (pvolume_info->sfu_emul)
3959 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
3960 if (pvolume_info->nobrl)
3961 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
3962 if (pvolume_info->nohandlecache)
3963 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_HANDLE_CACHE;
3964 if (pvolume_info->nostrictsync)
3965 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
3966 if (pvolume_info->mand_lock)
3967 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
3968 if (pvolume_info->rwpidforward)
3969 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD;
David Brazdil0f672f62019-12-10 10:32:29 +00003970 if (pvolume_info->mode_ace)
3971 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MODE_FROM_SID;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00003972 if (pvolume_info->cifs_acl)
3973 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
3974 if (pvolume_info->backupuid_specified) {
3975 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID;
3976 cifs_sb->mnt_backupuid = pvolume_info->backupuid;
3977 }
3978 if (pvolume_info->backupgid_specified) {
3979 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID;
3980 cifs_sb->mnt_backupgid = pvolume_info->backupgid;
3981 }
3982 if (pvolume_info->override_uid)
3983 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
3984 if (pvolume_info->override_gid)
3985 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
3986 if (pvolume_info->dynperm)
3987 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
3988 if (pvolume_info->fsc)
3989 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE;
3990 if (pvolume_info->multiuser)
3991 cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER |
3992 CIFS_MOUNT_NO_PERM);
3993 if (pvolume_info->strict_io)
3994 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO;
3995 if (pvolume_info->direct_io) {
3996 cifs_dbg(FYI, "mounting share using direct i/o\n");
3997 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
3998 }
David Brazdil0f672f62019-12-10 10:32:29 +00003999 if (pvolume_info->cache_ro) {
4000 cifs_dbg(VFS, "mounting share with read only caching. Ensure that the share will not be modified while in use.\n");
4001 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RO_CACHE;
4002 } else if (pvolume_info->cache_rw) {
4003 cifs_dbg(VFS, "mounting share in single client RW caching mode. Ensure that no other systems will be accessing the share.\n");
4004 cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_RO_CACHE |
4005 CIFS_MOUNT_RW_CACHE);
4006 }
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004007 if (pvolume_info->mfsymlinks) {
4008 if (pvolume_info->sfu_emul) {
4009 /*
4010 * Our SFU ("Services for Unix" emulation does not allow
4011 * creating symlinks but does allow reading existing SFU
4012 * symlinks (it does allow both creating and reading SFU
4013 * style mknod and FIFOs though). When "mfsymlinks" and
4014 * "sfu" are both enabled at the same time, it allows
4015 * reading both types of symlinks, but will only create
4016 * them with mfsymlinks format. This allows better
4017 * Apple compatibility (probably better for Samba too)
4018 * while still recognizing old Windows style symlinks.
4019 */
4020 cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
4021 }
4022 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
4023 }
4024
4025 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
4026 cifs_dbg(VFS, "mount option dynperm ignored if cifsacl mount option supported\n");
4027
4028 if (pvolume_info->prepath) {
4029 cifs_sb->prepath = kstrdup(pvolume_info->prepath, GFP_KERNEL);
4030 if (cifs_sb->prepath == NULL)
4031 return -ENOMEM;
Olivier Deprez157378f2022-04-04 15:47:50 +02004032 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004033 }
4034
4035 return 0;
4036}
4037
David Brazdil0f672f62019-12-10 10:32:29 +00004038void
4039cifs_cleanup_volume_info_contents(struct smb_vol *volume_info)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004040{
4041 kfree(volume_info->username);
Olivier Deprez157378f2022-04-04 15:47:50 +02004042 kfree_sensitive(volume_info->password);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004043 kfree(volume_info->UNC);
4044 kfree(volume_info->domainname);
4045 kfree(volume_info->iocharset);
4046 kfree(volume_info->prepath);
4047}
4048
4049void
4050cifs_cleanup_volume_info(struct smb_vol *volume_info)
4051{
4052 if (!volume_info)
4053 return;
David Brazdil0f672f62019-12-10 10:32:29 +00004054 cifs_cleanup_volume_info_contents(volume_info);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004055 kfree(volume_info);
4056}
4057
David Brazdil0f672f62019-12-10 10:32:29 +00004058/* Release all succeed connections */
4059static inline void mount_put_conns(struct cifs_sb_info *cifs_sb,
4060 unsigned int xid,
4061 struct TCP_Server_Info *server,
4062 struct cifs_ses *ses, struct cifs_tcon *tcon)
4063{
4064 int rc = 0;
4065
4066 if (tcon)
4067 cifs_put_tcon(tcon);
4068 else if (ses)
4069 cifs_put_smb_ses(ses);
4070 else if (server)
4071 cifs_put_tcp_session(server, 0);
4072 cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS;
4073 free_xid(xid);
4074}
4075
4076/* Get connections for tcp, ses and tcon */
4077static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
4078 unsigned int *xid,
4079 struct TCP_Server_Info **nserver,
4080 struct cifs_ses **nses, struct cifs_tcon **ntcon)
4081{
4082 int rc = 0;
4083 struct TCP_Server_Info *server;
4084 struct cifs_ses *ses;
4085 struct cifs_tcon *tcon;
4086
4087 *nserver = NULL;
4088 *nses = NULL;
4089 *ntcon = NULL;
4090
4091 *xid = get_xid();
4092
4093 /* get a reference to a tcp session */
4094 server = cifs_get_tcp_session(vol);
4095 if (IS_ERR(server)) {
4096 rc = PTR_ERR(server);
4097 return rc;
4098 }
4099
4100 *nserver = server;
4101
David Brazdil0f672f62019-12-10 10:32:29 +00004102 /* get a reference to a SMB session */
4103 ses = cifs_get_smb_ses(server, vol);
4104 if (IS_ERR(ses)) {
4105 rc = PTR_ERR(ses);
4106 return rc;
4107 }
4108
4109 *nses = ses;
4110
4111 if ((vol->persistent == true) && (!(ses->server->capabilities &
4112 SMB2_GLOBAL_CAP_PERSISTENT_HANDLES))) {
4113 cifs_server_dbg(VFS, "persistent handles not supported by server\n");
4114 return -EOPNOTSUPP;
4115 }
4116
4117 /* search for existing tcon to this server share */
4118 tcon = cifs_get_tcon(ses, vol);
4119 if (IS_ERR(tcon)) {
4120 rc = PTR_ERR(tcon);
4121 return rc;
4122 }
4123
4124 *ntcon = tcon;
4125
4126 /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
4127 if (tcon->posix_extensions)
4128 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
4129
4130 /* tell server which Unix caps we support */
4131 if (cap_unix(tcon->ses)) {
4132 /*
4133 * reset of caps checks mount to see if unix extensions disabled
4134 * for just this mount.
4135 */
4136 reset_cifs_unix_caps(*xid, tcon, cifs_sb, vol);
4137 if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) &&
4138 (le64_to_cpu(tcon->fsUnixInfo.Capability) &
4139 CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP))
4140 return -EACCES;
4141 } else
4142 tcon->unix_ext = 0; /* server does not support them */
4143
4144 /* do not care if a following call succeed - informational */
4145 if (!tcon->pipe && server->ops->qfs_tcon) {
Olivier Deprez157378f2022-04-04 15:47:50 +02004146 server->ops->qfs_tcon(*xid, tcon, cifs_sb);
David Brazdil0f672f62019-12-10 10:32:29 +00004147 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE) {
4148 if (tcon->fsDevInfo.DeviceCharacteristics &
4149 cpu_to_le32(FILE_READ_ONLY_DEVICE))
4150 cifs_dbg(VFS, "mounted to read only share\n");
4151 else if ((cifs_sb->mnt_cifs_flags &
4152 CIFS_MOUNT_RW_CACHE) == 0)
4153 cifs_dbg(VFS, "read only mount of RW share\n");
4154 /* no need to log a RW mount of a typical RW share */
4155 }
4156 }
4157
4158 cifs_sb->wsize = server->ops->negotiate_wsize(tcon, vol);
4159 cifs_sb->rsize = server->ops->negotiate_rsize(tcon, vol);
4160
4161 return 0;
4162}
4163
4164static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
4165 struct cifs_tcon *tcon)
4166{
4167 struct tcon_link *tlink;
4168
4169 /* hang the tcon off of the superblock */
4170 tlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
4171 if (tlink == NULL)
4172 return -ENOMEM;
4173
4174 tlink->tl_uid = ses->linux_uid;
4175 tlink->tl_tcon = tcon;
4176 tlink->tl_time = jiffies;
4177 set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
4178 set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
4179
4180 cifs_sb->master_tlink = tlink;
4181 spin_lock(&cifs_sb->tlink_tree_lock);
4182 tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
4183 spin_unlock(&cifs_sb->tlink_tree_lock);
4184
4185 queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
4186 TLINK_IDLE_EXPIRE);
4187 return 0;
4188}
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004189
4190#ifdef CONFIG_CIFS_DFS_UPCALL
4191/*
4192 * cifs_build_path_to_root returns full path to root when we do not have an
4193 * exiting connection (tcon)
4194 */
4195static char *
4196build_unc_path_to_root(const struct smb_vol *vol,
David Brazdil0f672f62019-12-10 10:32:29 +00004197 const struct cifs_sb_info *cifs_sb, bool useppath)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004198{
4199 char *full_path, *pos;
David Brazdil0f672f62019-12-10 10:32:29 +00004200 unsigned int pplen = useppath && vol->prepath ?
4201 strlen(vol->prepath) + 1 : 0;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004202 unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1);
4203
David Brazdil0f672f62019-12-10 10:32:29 +00004204 if (unc_len > MAX_TREE_SIZE)
4205 return ERR_PTR(-EINVAL);
4206
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004207 full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL);
4208 if (full_path == NULL)
4209 return ERR_PTR(-ENOMEM);
4210
David Brazdil0f672f62019-12-10 10:32:29 +00004211 memcpy(full_path, vol->UNC, unc_len);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004212 pos = full_path + unc_len;
4213
4214 if (pplen) {
4215 *pos = CIFS_DIR_SEP(cifs_sb);
David Brazdil0f672f62019-12-10 10:32:29 +00004216 memcpy(pos + 1, vol->prepath, pplen);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004217 pos += pplen;
4218 }
4219
4220 *pos = '\0'; /* add trailing null */
4221 convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
4222 cifs_dbg(FYI, "%s: full_path=%s\n", __func__, full_path);
4223 return full_path;
4224}
4225
David Brazdil0f672f62019-12-10 10:32:29 +00004226/**
4227 * expand_dfs_referral - Perform a dfs referral query and update the cifs_sb
4228 *
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004229 *
4230 * If a referral is found, cifs_sb->mountdata will be (re-)allocated
4231 * to a string containing updated options for the submount. Otherwise it
4232 * will be left untouched.
4233 *
4234 * Returns the rc from get_dfs_path to the caller, which can be used to
4235 * determine whether there were referrals.
4236 */
4237static int
4238expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
4239 struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb,
Olivier Deprez157378f2022-04-04 15:47:50 +02004240 char *ref_path)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004241{
4242 int rc;
David Brazdil0f672f62019-12-10 10:32:29 +00004243 struct dfs_info3_param referral = {0};
Olivier Deprez157378f2022-04-04 15:47:50 +02004244 char *full_path = NULL, *mdata = NULL;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004245
David Brazdil0f672f62019-12-10 10:32:29 +00004246 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
4247 return -EREMOTE;
4248
4249 full_path = build_unc_path_to_root(volume_info, cifs_sb, true);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004250 if (IS_ERR(full_path))
4251 return PTR_ERR(full_path);
4252
David Brazdil0f672f62019-12-10 10:32:29 +00004253 rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
4254 ref_path, &referral, NULL);
4255 if (!rc) {
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004256 char *fake_devname = NULL;
4257
4258 mdata = cifs_compose_mount_options(cifs_sb->mountdata,
David Brazdil0f672f62019-12-10 10:32:29 +00004259 full_path + 1, &referral,
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004260 &fake_devname);
David Brazdil0f672f62019-12-10 10:32:29 +00004261 free_dfs_info_param(&referral);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004262
4263 if (IS_ERR(mdata)) {
4264 rc = PTR_ERR(mdata);
4265 mdata = NULL;
4266 } else {
David Brazdil0f672f62019-12-10 10:32:29 +00004267 cifs_cleanup_volume_info_contents(volume_info);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004268 rc = cifs_setup_volume_info(volume_info, mdata,
David Brazdil0f672f62019-12-10 10:32:29 +00004269 fake_devname, false);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004270 }
4271 kfree(fake_devname);
4272 kfree(cifs_sb->mountdata);
4273 cifs_sb->mountdata = mdata;
4274 }
4275 kfree(full_path);
4276 return rc;
4277}
David Brazdil0f672f62019-12-10 10:32:29 +00004278
4279static inline int get_next_dfs_tgt(const char *path,
4280 struct dfs_cache_tgt_list *tgt_list,
4281 struct dfs_cache_tgt_iterator **tgt_it)
4282{
4283 if (!*tgt_it)
4284 *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
4285 else
4286 *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it);
4287 return !*tgt_it ? -EHOSTDOWN : 0;
4288}
4289
4290static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it,
4291 struct smb_vol *fake_vol, struct smb_vol *vol)
4292{
4293 const char *tgt = dfs_cache_get_tgt_name(tgt_it);
4294 int len = strlen(tgt) + 2;
4295 char *new_unc;
4296
4297 new_unc = kmalloc(len, GFP_KERNEL);
4298 if (!new_unc)
4299 return -ENOMEM;
4300 scnprintf(new_unc, len, "\\%s", tgt);
4301
4302 kfree(vol->UNC);
4303 vol->UNC = new_unc;
4304
4305 if (fake_vol->prepath) {
4306 kfree(vol->prepath);
4307 vol->prepath = fake_vol->prepath;
4308 fake_vol->prepath = NULL;
4309 }
4310 memcpy(&vol->dstaddr, &fake_vol->dstaddr, sizeof(vol->dstaddr));
4311
4312 return 0;
4313}
4314
Olivier Deprez157378f2022-04-04 15:47:50 +02004315static int setup_dfs_tgt_conn(const char *path, const char *full_path,
David Brazdil0f672f62019-12-10 10:32:29 +00004316 const struct dfs_cache_tgt_iterator *tgt_it,
Olivier Deprez157378f2022-04-04 15:47:50 +02004317 struct cifs_sb_info *cifs_sb, struct smb_vol *vol, unsigned int *xid,
4318 struct TCP_Server_Info **server, struct cifs_ses **ses,
David Brazdil0f672f62019-12-10 10:32:29 +00004319 struct cifs_tcon **tcon)
4320{
4321 int rc;
4322 struct dfs_info3_param ref = {0};
4323 char *mdata = NULL, *fake_devname = NULL;
4324 struct smb_vol fake_vol = {NULL};
4325
4326 cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path);
4327
4328 rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref);
4329 if (rc)
4330 return rc;
4331
Olivier Deprez157378f2022-04-04 15:47:50 +02004332 mdata = cifs_compose_mount_options(cifs_sb->mountdata, full_path + 1, &ref, &fake_devname);
David Brazdil0f672f62019-12-10 10:32:29 +00004333 free_dfs_info_param(&ref);
4334
4335 if (IS_ERR(mdata)) {
4336 rc = PTR_ERR(mdata);
4337 mdata = NULL;
4338 } else {
4339 cifs_dbg(FYI, "%s: fake_devname: %s\n", __func__, fake_devname);
4340 rc = cifs_setup_volume_info(&fake_vol, mdata, fake_devname,
4341 false);
4342 }
4343 kfree(mdata);
4344 kfree(fake_devname);
4345
4346 if (!rc) {
4347 /*
4348 * We use a 'fake_vol' here because we need pass it down to the
4349 * mount_{get,put} functions to test connection against new DFS
4350 * targets.
4351 */
4352 mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon);
4353 rc = mount_get_conns(&fake_vol, cifs_sb, xid, server, ses,
4354 tcon);
Olivier Deprez157378f2022-04-04 15:47:50 +02004355 if (!rc || (*server && *ses)) {
David Brazdil0f672f62019-12-10 10:32:29 +00004356 /*
4357 * We were able to connect to new target server.
4358 * Update current volume info with new target server.
4359 */
4360 rc = update_vol_info(tgt_it, &fake_vol, vol);
4361 }
4362 }
4363 cifs_cleanup_volume_info_contents(&fake_vol);
4364 return rc;
4365}
4366
Olivier Deprez157378f2022-04-04 15:47:50 +02004367static int do_dfs_failover(const char *path, const char *full_path, struct cifs_sb_info *cifs_sb,
4368 struct smb_vol *vol, struct cifs_ses *root_ses, unsigned int *xid,
4369 struct TCP_Server_Info **server, struct cifs_ses **ses,
4370 struct cifs_tcon **tcon)
David Brazdil0f672f62019-12-10 10:32:29 +00004371{
4372 int rc;
4373 struct dfs_cache_tgt_list tgt_list;
4374 struct dfs_cache_tgt_iterator *tgt_it = NULL;
4375
4376 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
4377 return -EOPNOTSUPP;
4378
4379 rc = dfs_cache_noreq_find(path, NULL, &tgt_list);
4380 if (rc)
4381 return rc;
4382
4383 for (;;) {
4384 /* Get next DFS target server - if any */
4385 rc = get_next_dfs_tgt(path, &tgt_list, &tgt_it);
4386 if (rc)
4387 break;
4388 /* Connect to next DFS target */
Olivier Deprez157378f2022-04-04 15:47:50 +02004389 rc = setup_dfs_tgt_conn(path, full_path, tgt_it, cifs_sb, vol, xid, server, ses,
4390 tcon);
4391 if (!rc || (*server && *ses))
David Brazdil0f672f62019-12-10 10:32:29 +00004392 break;
4393 }
4394 if (!rc) {
4395 /*
4396 * Update DFS target hint in DFS referral cache with the target
4397 * server we successfully reconnected to.
4398 */
4399 rc = dfs_cache_update_tgthint(*xid, root_ses ? root_ses : *ses,
4400 cifs_sb->local_nls,
4401 cifs_remap(cifs_sb), path,
4402 tgt_it);
4403 }
4404 dfs_cache_free_tgts(&tgt_list);
4405 return rc;
4406}
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004407#endif
4408
David Brazdil0f672f62019-12-10 10:32:29 +00004409int
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004410cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
4411 const char *devname, bool is_smb3)
4412{
4413 int rc = 0;
4414
4415 if (cifs_parse_mount_options(mount_data, devname, volume_info, is_smb3))
4416 return -EINVAL;
4417
4418 if (volume_info->nullauth) {
4419 cifs_dbg(FYI, "Anonymous login\n");
4420 kfree(volume_info->username);
4421 volume_info->username = NULL;
4422 } else if (volume_info->username) {
4423 /* BB fixme parse for domain name here */
4424 cifs_dbg(FYI, "Username: %s\n", volume_info->username);
4425 } else {
4426 cifs_dbg(VFS, "No username specified\n");
4427 /* In userspace mount helper we can get user name from alternate
4428 locations such as env variables and files on disk */
4429 return -EINVAL;
4430 }
4431
4432 /* this is needed for ASCII cp to Unicode converts */
4433 if (volume_info->iocharset == NULL) {
4434 /* load_nls_default cannot return null */
4435 volume_info->local_nls = load_nls_default();
4436 } else {
4437 volume_info->local_nls = load_nls(volume_info->iocharset);
4438 if (volume_info->local_nls == NULL) {
4439 cifs_dbg(VFS, "CIFS mount error: iocharset %s not found\n",
4440 volume_info->iocharset);
4441 return -ELIBACC;
4442 }
4443 }
4444
4445 return rc;
4446}
4447
4448struct smb_vol *
4449cifs_get_volume_info(char *mount_data, const char *devname, bool is_smb3)
4450{
4451 int rc;
4452 struct smb_vol *volume_info;
4453
4454 volume_info = kmalloc(sizeof(struct smb_vol), GFP_KERNEL);
4455 if (!volume_info)
4456 return ERR_PTR(-ENOMEM);
4457
4458 rc = cifs_setup_volume_info(volume_info, mount_data, devname, is_smb3);
4459 if (rc) {
4460 cifs_cleanup_volume_info(volume_info);
4461 volume_info = ERR_PTR(rc);
4462 }
4463
4464 return volume_info;
4465}
4466
4467static int
4468cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
4469 unsigned int xid,
4470 struct cifs_tcon *tcon,
4471 struct cifs_sb_info *cifs_sb,
David Brazdil0f672f62019-12-10 10:32:29 +00004472 char *full_path,
4473 int added_treename)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004474{
4475 int rc;
4476 char *s;
4477 char sep, tmp;
David Brazdil0f672f62019-12-10 10:32:29 +00004478 int skip = added_treename ? 1 : 0;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004479
4480 sep = CIFS_DIR_SEP(cifs_sb);
4481 s = full_path;
4482
4483 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, "");
4484 while (rc == 0) {
4485 /* skip separators */
4486 while (*s == sep)
4487 s++;
4488 if (!*s)
4489 break;
4490 /* next separator */
4491 while (*s && *s != sep)
4492 s++;
David Brazdil0f672f62019-12-10 10:32:29 +00004493 /*
4494 * if the treename is added, we then have to skip the first
4495 * part within the separators
4496 */
4497 if (skip) {
4498 skip = 0;
4499 continue;
4500 }
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004501 /*
4502 * temporarily null-terminate the path at the end of
4503 * the current component
4504 */
4505 tmp = *s;
4506 *s = 0;
4507 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
4508 full_path);
4509 *s = tmp;
4510 }
4511 return rc;
4512}
4513
David Brazdil0f672f62019-12-10 10:32:29 +00004514/*
4515 * Check if path is remote (e.g. a DFS share). Return -EREMOTE if it is,
4516 * otherwise 0.
4517 */
4518static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb_vol *vol,
4519 const unsigned int xid,
4520 struct TCP_Server_Info *server,
4521 struct cifs_tcon *tcon)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004522{
4523 int rc;
David Brazdil0f672f62019-12-10 10:32:29 +00004524 char *full_path;
4525
4526 if (!server->ops->is_path_accessible)
4527 return -EOPNOTSUPP;
4528
4529 /*
4530 * cifs_build_path_to_root works only when we have a valid tcon
4531 */
4532 full_path = cifs_build_path_to_root(vol, cifs_sb, tcon,
4533 tcon->Flags & SMB_SHARE_IS_IN_DFS);
4534 if (full_path == NULL)
4535 return -ENOMEM;
4536
4537 cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
4538
4539 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
4540 full_path);
4541 if (rc != 0 && rc != -EREMOTE) {
4542 kfree(full_path);
4543 return rc;
4544 }
4545
4546 if (rc != -EREMOTE) {
4547 rc = cifs_are_all_path_components_accessible(server, xid, tcon,
4548 cifs_sb, full_path, tcon->Flags & SMB_SHARE_IS_IN_DFS);
4549 if (rc != 0) {
Olivier Deprez157378f2022-04-04 15:47:50 +02004550 cifs_server_dbg(VFS, "cannot query dirs between root and final path, enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
David Brazdil0f672f62019-12-10 10:32:29 +00004551 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
4552 rc = 0;
4553 }
4554 }
4555
4556 kfree(full_path);
4557 return rc;
4558}
4559
4560#ifdef CONFIG_CIFS_DFS_UPCALL
Olivier Deprez157378f2022-04-04 15:47:50 +02004561static void set_root_ses(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
4562 struct cifs_ses **root_ses)
Olivier Deprez0e641232021-09-23 10:07:05 +02004563{
Olivier Deprez157378f2022-04-04 15:47:50 +02004564 if (ses) {
4565 spin_lock(&cifs_tcp_ses_lock);
4566 ses->ses_count++;
4567 if (ses->tcon_ipc)
4568 ses->tcon_ipc->remap = cifs_remap(cifs_sb);
4569 spin_unlock(&cifs_tcp_ses_lock);
4570 }
4571 *root_ses = ses;
4572}
4573
4574static void put_root_ses(struct cifs_ses *ses)
4575{
4576 if (ses)
4577 cifs_put_smb_ses(ses);
4578}
4579
4580/* Check if a path component is remote and then update @dfs_path accordingly */
4581static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb_vol *vol,
4582 const unsigned int xid, struct TCP_Server_Info *server,
4583 struct cifs_tcon *tcon, char **dfs_path)
4584{
4585 char *path, *s;
4586 char sep = CIFS_DIR_SEP(cifs_sb), tmp;
4587 char *npath;
4588 int rc = 0;
4589 int added_treename = tcon->Flags & SMB_SHARE_IS_IN_DFS;
4590 int skip = added_treename;
4591
4592 path = cifs_build_path_to_root(vol, cifs_sb, tcon, added_treename);
4593 if (!path)
4594 return -ENOMEM;
4595
4596 /*
4597 * Walk through the path components in @path and check if they're accessible. In case any of
4598 * the components is -EREMOTE, then update @dfs_path with the next DFS referral request path
4599 * (NOT including the remaining components).
4600 */
4601 s = path;
4602 do {
4603 /* skip separators */
4604 while (*s && *s == sep)
4605 s++;
4606 if (!*s)
4607 break;
4608 /* next separator */
4609 while (*s && *s != sep)
4610 s++;
4611 /*
4612 * if the treename is added, we then have to skip the first
4613 * part within the separators
4614 */
4615 if (skip) {
4616 skip = 0;
4617 continue;
4618 }
4619 tmp = *s;
4620 *s = 0;
4621 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, path);
4622 if (rc && rc == -EREMOTE) {
4623 struct smb_vol v = {NULL};
4624 /* if @path contains a tree name, skip it in the prefix path */
4625 if (added_treename) {
4626 rc = cifs_parse_devname(path, &v);
4627 if (rc)
4628 break;
4629 rc = -EREMOTE;
4630 npath = build_unc_path_to_root(&v, cifs_sb, true);
4631 cifs_cleanup_volume_info_contents(&v);
4632 } else {
4633 v.UNC = vol->UNC;
4634 v.prepath = path + 1;
4635 npath = build_unc_path_to_root(&v, cifs_sb, true);
4636 }
4637 if (IS_ERR(npath)) {
4638 rc = PTR_ERR(npath);
4639 break;
4640 }
4641 kfree(*dfs_path);
4642 *dfs_path = npath;
4643 }
4644 *s = tmp;
4645 } while (rc == 0);
4646
4647 kfree(path);
4648 return rc;
Olivier Deprez0e641232021-09-23 10:07:05 +02004649}
4650
David Brazdil0f672f62019-12-10 10:32:29 +00004651int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
4652{
4653 int rc = 0;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004654 unsigned int xid;
Olivier Deprez157378f2022-04-04 15:47:50 +02004655 struct TCP_Server_Info *server = NULL;
4656 struct cifs_ses *ses = NULL, *root_ses = NULL;
David Brazdil0f672f62019-12-10 10:32:29 +00004657 struct cifs_tcon *tcon = NULL;
Olivier Deprez157378f2022-04-04 15:47:50 +02004658 int count = 0;
4659 char *ref_path = NULL, *full_path = NULL;
4660 char *oldmnt = NULL;
4661 char *mntdata = NULL;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004662
David Brazdil0f672f62019-12-10 10:32:29 +00004663 rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon);
David Brazdil0f672f62019-12-10 10:32:29 +00004664 /*
Olivier Deprez157378f2022-04-04 15:47:50 +02004665 * Unconditionally try to get an DFS referral (even cached) to determine whether it is an
4666 * DFS mount.
David Brazdil0f672f62019-12-10 10:32:29 +00004667 *
Olivier Deprez157378f2022-04-04 15:47:50 +02004668 * Skip prefix path to provide support for DFS referrals from w2k8 servers which don't seem
4669 * to respond with PATH_NOT_COVERED to requests that include the prefix.
David Brazdil0f672f62019-12-10 10:32:29 +00004670 */
Olivier Deprez157378f2022-04-04 15:47:50 +02004671 if (dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), vol->UNC + 1, NULL,
4672 NULL)) {
4673 /* No DFS referral was returned. Looks like a regular share. */
4674 if (rc)
4675 goto error;
4676 /* Check if it is fully accessible and then mount it */
4677 rc = is_path_remote(cifs_sb, vol, xid, server, tcon);
4678 if (!rc)
4679 goto out;
4680 if (rc != -EREMOTE)
4681 goto error;
David Brazdil0f672f62019-12-10 10:32:29 +00004682 }
Olivier Deprez157378f2022-04-04 15:47:50 +02004683 /* Save mount options */
4684 mntdata = kstrndup(cifs_sb->mountdata, strlen(cifs_sb->mountdata), GFP_KERNEL);
4685 if (!mntdata) {
David Brazdil0f672f62019-12-10 10:32:29 +00004686 rc = -ENOMEM;
4687 goto error;
4688 }
Olivier Deprez157378f2022-04-04 15:47:50 +02004689 /* Get path of DFS root */
4690 ref_path = build_unc_path_to_root(vol, cifs_sb, false);
4691 if (IS_ERR(ref_path)) {
4692 rc = PTR_ERR(ref_path);
4693 ref_path = NULL;
David Brazdil0f672f62019-12-10 10:32:29 +00004694 goto error;
4695 }
David Brazdil0f672f62019-12-10 10:32:29 +00004696
Olivier Deprez157378f2022-04-04 15:47:50 +02004697 set_root_ses(cifs_sb, ses, &root_ses);
4698 do {
4699 /* Save full path of last DFS path we used to resolve final target server */
David Brazdil0f672f62019-12-10 10:32:29 +00004700 kfree(full_path);
Olivier Deprez157378f2022-04-04 15:47:50 +02004701 full_path = build_unc_path_to_root(vol, cifs_sb, !!count);
David Brazdil0f672f62019-12-10 10:32:29 +00004702 if (IS_ERR(full_path)) {
4703 rc = PTR_ERR(full_path);
4704 full_path = NULL;
4705 break;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004706 }
Olivier Deprez157378f2022-04-04 15:47:50 +02004707 /* Chase referral */
4708 oldmnt = cifs_sb->mountdata;
4709 rc = expand_dfs_referral(xid, root_ses, vol, cifs_sb, ref_path + 1);
David Brazdil0f672f62019-12-10 10:32:29 +00004710 if (rc)
4711 break;
Olivier Deprez157378f2022-04-04 15:47:50 +02004712 /* Connect to new DFS target only if we were redirected */
4713 if (oldmnt != cifs_sb->mountdata) {
David Brazdil0f672f62019-12-10 10:32:29 +00004714 mount_put_conns(cifs_sb, xid, server, ses, tcon);
Olivier Deprez157378f2022-04-04 15:47:50 +02004715 rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon);
David Brazdil0f672f62019-12-10 10:32:29 +00004716 }
Olivier Deprez157378f2022-04-04 15:47:50 +02004717 if (rc && !server && !ses) {
4718 /* Failed to connect. Try to connect to other targets in the referral. */
4719 rc = do_dfs_failover(ref_path + 1, full_path, cifs_sb, vol, root_ses, &xid,
4720 &server, &ses, &tcon);
David Brazdil0f672f62019-12-10 10:32:29 +00004721 }
Olivier Deprez157378f2022-04-04 15:47:50 +02004722 if (rc == -EACCES || rc == -EOPNOTSUPP || !server || !ses)
4723 break;
4724 if (!tcon)
4725 continue;
4726 /* Make sure that requests go through new root servers */
4727 if (is_tcon_dfs(tcon)) {
4728 put_root_ses(root_ses);
4729 set_root_ses(cifs_sb, ses, &root_ses);
4730 }
4731 /* Check for remaining path components and then continue chasing them (-EREMOTE) */
4732 rc = check_dfs_prepath(cifs_sb, vol, xid, server, tcon, &ref_path);
4733 /* Prevent recursion on broken link referrals */
4734 if (rc == -EREMOTE && ++count > MAX_NESTED_LINKS)
4735 rc = -ELOOP;
4736 } while (rc == -EREMOTE);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004737
4738 if (rc)
David Brazdil0f672f62019-12-10 10:32:29 +00004739 goto error;
Olivier Deprez157378f2022-04-04 15:47:50 +02004740 put_root_ses(root_ses);
4741 root_ses = NULL;
4742 kfree(ref_path);
4743 ref_path = NULL;
4744 /*
4745 * Store DFS full path in both superblock and tree connect structures.
4746 *
4747 * For DFS root mounts, the prefix path (cifs_sb->prepath) is preserved during reconnect so
4748 * only the root path is set in cifs_sb->origin_fullpath and tcon->dfs_path. And for DFS
4749 * links, the prefix path is included in both and may be changed during reconnect. See
4750 * cifs_tree_connect().
4751 */
4752 cifs_sb->origin_fullpath = kstrndup(full_path, strlen(full_path), GFP_KERNEL);
David Brazdil0f672f62019-12-10 10:32:29 +00004753 if (!cifs_sb->origin_fullpath) {
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004754 rc = -ENOMEM;
David Brazdil0f672f62019-12-10 10:32:29 +00004755 goto error;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004756 }
Olivier Deprez157378f2022-04-04 15:47:50 +02004757 spin_lock(&cifs_tcp_ses_lock);
4758 tcon->dfs_path = full_path;
4759 full_path = NULL;
4760 tcon->remap = cifs_remap(cifs_sb);
David Brazdil0f672f62019-12-10 10:32:29 +00004761 spin_unlock(&cifs_tcp_ses_lock);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004762
Olivier Deprez157378f2022-04-04 15:47:50 +02004763 /* Add original volume information for DFS cache to be used when refreshing referrals */
4764 rc = dfs_cache_add_vol(mntdata, vol, cifs_sb->origin_fullpath);
4765 if (rc)
David Brazdil0f672f62019-12-10 10:32:29 +00004766 goto error;
David Brazdil0f672f62019-12-10 10:32:29 +00004767 /*
4768 * After reconnecting to a different server, unique ids won't
4769 * match anymore, so we disable serverino. This prevents
4770 * dentry revalidation to think the dentry are stale (ESTALE).
4771 */
4772 cifs_autodisable_serverino(cifs_sb);
Olivier Deprez157378f2022-04-04 15:47:50 +02004773 /*
4774 * Force the use of prefix path to support failover on DFS paths that
4775 * resolve to targets that have different prefix paths.
4776 */
4777 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
4778 kfree(cifs_sb->prepath);
4779 cifs_sb->prepath = vol->prepath;
4780 vol->prepath = NULL;
4781
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004782out:
4783 free_xid(xid);
Olivier Deprez157378f2022-04-04 15:47:50 +02004784 cifs_try_adding_channels(ses);
David Brazdil0f672f62019-12-10 10:32:29 +00004785 return mount_setup_tlink(cifs_sb, ses, tcon);
4786
4787error:
Olivier Deprez157378f2022-04-04 15:47:50 +02004788 kfree(ref_path);
David Brazdil0f672f62019-12-10 10:32:29 +00004789 kfree(full_path);
Olivier Deprez157378f2022-04-04 15:47:50 +02004790 kfree(mntdata);
4791 kfree(cifs_sb->origin_fullpath);
4792 put_root_ses(root_ses);
David Brazdil0f672f62019-12-10 10:32:29 +00004793 mount_put_conns(cifs_sb, xid, server, ses, tcon);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004794 return rc;
4795}
David Brazdil0f672f62019-12-10 10:32:29 +00004796#else
4797int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
4798{
4799 int rc = 0;
4800 unsigned int xid;
4801 struct cifs_ses *ses;
4802 struct cifs_tcon *tcon;
4803 struct TCP_Server_Info *server;
4804
4805 rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon);
4806 if (rc)
4807 goto error;
4808
4809 if (tcon) {
4810 rc = is_path_remote(cifs_sb, vol, xid, server, tcon);
4811 if (rc == -EREMOTE)
4812 rc = -EOPNOTSUPP;
4813 if (rc)
4814 goto error;
4815 }
4816
4817 free_xid(xid);
4818
4819 return mount_setup_tlink(cifs_sb, ses, tcon);
4820
4821error:
4822 mount_put_conns(cifs_sb, xid, server, ses, tcon);
4823 return rc;
4824}
4825#endif
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004826
4827/*
4828 * Issue a TREE_CONNECT request.
4829 */
4830int
4831CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
4832 const char *tree, struct cifs_tcon *tcon,
4833 const struct nls_table *nls_codepage)
4834{
4835 struct smb_hdr *smb_buffer;
4836 struct smb_hdr *smb_buffer_response;
4837 TCONX_REQ *pSMB;
4838 TCONX_RSP *pSMBr;
4839 unsigned char *bcc_ptr;
4840 int rc = 0;
4841 int length;
4842 __u16 bytes_left, count;
4843
4844 if (ses == NULL)
4845 return -EIO;
4846
4847 smb_buffer = cifs_buf_get();
4848 if (smb_buffer == NULL)
4849 return -ENOMEM;
4850
4851 smb_buffer_response = smb_buffer;
4852
4853 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
4854 NULL /*no tid */ , 4 /*wct */ );
4855
4856 smb_buffer->Mid = get_next_mid(ses->server);
4857 smb_buffer->Uid = ses->Suid;
4858 pSMB = (TCONX_REQ *) smb_buffer;
4859 pSMBr = (TCONX_RSP *) smb_buffer_response;
4860
4861 pSMB->AndXCommand = 0xFF;
4862 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
4863 bcc_ptr = &pSMB->Password[0];
4864 if (tcon->pipe || (ses->server->sec_mode & SECMODE_USER)) {
4865 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
4866 *bcc_ptr = 0; /* password is null byte */
4867 bcc_ptr++; /* skip password */
4868 /* already aligned so no need to do it below */
4869 } else {
4870 pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
4871 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
4872 specified as required (when that support is added to
4873 the vfs in the future) as only NTLM or the much
4874 weaker LANMAN (which we do not send by default) is accepted
4875 by Samba (not sure whether other servers allow
4876 NTLMv2 password here) */
4877#ifdef CONFIG_CIFS_WEAK_PW_HASH
4878 if ((global_secflags & CIFSSEC_MAY_LANMAN) &&
4879 (ses->sectype == LANMAN))
4880 calc_lanman_hash(tcon->password, ses->server->cryptkey,
4881 ses->server->sec_mode &
4882 SECMODE_PW_ENCRYPT ? true : false,
4883 bcc_ptr);
4884 else
4885#endif /* CIFS_WEAK_PW_HASH */
4886 rc = SMBNTencrypt(tcon->password, ses->server->cryptkey,
4887 bcc_ptr, nls_codepage);
4888 if (rc) {
4889 cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n",
4890 __func__, rc);
4891 cifs_buf_release(smb_buffer);
4892 return rc;
4893 }
4894
4895 bcc_ptr += CIFS_AUTH_RESP_SIZE;
4896 if (ses->capabilities & CAP_UNICODE) {
4897 /* must align unicode strings */
4898 *bcc_ptr = 0; /* null byte password */
4899 bcc_ptr++;
4900 }
4901 }
4902
4903 if (ses->server->sign)
4904 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4905
4906 if (ses->capabilities & CAP_STATUS32) {
4907 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
4908 }
4909 if (ses->capabilities & CAP_DFS) {
4910 smb_buffer->Flags2 |= SMBFLG2_DFS;
4911 }
4912 if (ses->capabilities & CAP_UNICODE) {
4913 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
4914 length =
4915 cifs_strtoUTF16((__le16 *) bcc_ptr, tree,
4916 6 /* max utf8 char length in bytes */ *
4917 (/* server len*/ + 256 /* share len */), nls_codepage);
4918 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
4919 bcc_ptr += 2; /* skip trailing null */
4920 } else { /* ASCII */
4921 strcpy(bcc_ptr, tree);
4922 bcc_ptr += strlen(tree) + 1;
4923 }
4924 strcpy(bcc_ptr, "?????");
4925 bcc_ptr += strlen("?????");
4926 bcc_ptr += 1;
4927 count = bcc_ptr - &pSMB->Password[0];
Olivier Deprez157378f2022-04-04 15:47:50 +02004928 be32_add_cpu(&pSMB->hdr.smb_buf_length, count);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00004929 pSMB->ByteCount = cpu_to_le16(count);
4930
4931 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
4932 0);
4933
4934 /* above now done in SendReceive */
4935 if (rc == 0) {
4936 bool is_unicode;
4937
4938 tcon->tidStatus = CifsGood;
4939 tcon->need_reconnect = false;
4940 tcon->tid = smb_buffer_response->Tid;
4941 bcc_ptr = pByteArea(smb_buffer_response);
4942 bytes_left = get_bcc(smb_buffer_response);
4943 length = strnlen(bcc_ptr, bytes_left - 2);
4944 if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
4945 is_unicode = true;
4946 else
4947 is_unicode = false;
4948
4949
4950 /* skip service field (NB: this field is always ASCII) */
4951 if (length == 3) {
4952 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
4953 (bcc_ptr[2] == 'C')) {
4954 cifs_dbg(FYI, "IPC connection\n");
4955 tcon->ipc = true;
4956 tcon->pipe = true;
4957 }
4958 } else if (length == 2) {
4959 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
4960 /* the most common case */
4961 cifs_dbg(FYI, "disk share connection\n");
4962 }
4963 }
4964 bcc_ptr += length + 1;
4965 bytes_left -= (length + 1);
4966 strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
4967
4968 /* mostly informational -- no need to fail on error here */
4969 kfree(tcon->nativeFileSystem);
4970 tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr,
4971 bytes_left, is_unicode,
4972 nls_codepage);
4973
4974 cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem);
4975
4976 if ((smb_buffer_response->WordCount == 3) ||
4977 (smb_buffer_response->WordCount == 7))
4978 /* field is in same location */
4979 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
4980 else
4981 tcon->Flags = 0;
4982 cifs_dbg(FYI, "Tcon flags: 0x%x\n", tcon->Flags);
4983 }
4984
4985 cifs_buf_release(smb_buffer);
4986 return rc;
4987}
4988
4989static void delayed_free(struct rcu_head *p)
4990{
4991 struct cifs_sb_info *sbi = container_of(p, struct cifs_sb_info, rcu);
4992 unload_nls(sbi->local_nls);
4993 kfree(sbi);
4994}
4995
4996void
4997cifs_umount(struct cifs_sb_info *cifs_sb)
4998{
4999 struct rb_root *root = &cifs_sb->tlink_tree;
5000 struct rb_node *node;
5001 struct tcon_link *tlink;
5002
5003 cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
5004
5005 spin_lock(&cifs_sb->tlink_tree_lock);
5006 while ((node = rb_first(root))) {
5007 tlink = rb_entry(node, struct tcon_link, tl_rbnode);
5008 cifs_get_tlink(tlink);
5009 clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
5010 rb_erase(node, root);
5011
5012 spin_unlock(&cifs_sb->tlink_tree_lock);
5013 cifs_put_tlink(tlink);
5014 spin_lock(&cifs_sb->tlink_tree_lock);
5015 }
5016 spin_unlock(&cifs_sb->tlink_tree_lock);
5017
5018 kfree(cifs_sb->mountdata);
5019 kfree(cifs_sb->prepath);
David Brazdil0f672f62019-12-10 10:32:29 +00005020#ifdef CONFIG_CIFS_DFS_UPCALL
5021 dfs_cache_del_vol(cifs_sb->origin_fullpath);
5022 kfree(cifs_sb->origin_fullpath);
5023#endif
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00005024 call_rcu(&cifs_sb->rcu, delayed_free);
5025}
5026
5027int
5028cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
5029{
5030 int rc = 0;
Olivier Deprez157378f2022-04-04 15:47:50 +02005031 struct TCP_Server_Info *server = cifs_ses_server(ses);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00005032
5033 if (!server->ops->need_neg || !server->ops->negotiate)
5034 return -ENOSYS;
5035
5036 /* only send once per connect */
5037 if (!server->ops->need_neg(server))
5038 return 0;
5039
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00005040 rc = server->ops->negotiate(xid, ses);
5041 if (rc == 0) {
5042 spin_lock(&GlobalMid_Lock);
5043 if (server->tcpStatus == CifsNeedNegotiate)
5044 server->tcpStatus = CifsGood;
5045 else
5046 rc = -EHOSTDOWN;
5047 spin_unlock(&GlobalMid_Lock);
5048 }
5049
5050 return rc;
5051}
5052
5053int
5054cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
5055 struct nls_table *nls_info)
5056{
5057 int rc = -ENOSYS;
Olivier Deprez157378f2022-04-04 15:47:50 +02005058 struct TCP_Server_Info *server = cifs_ses_server(ses);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00005059
Olivier Deprez157378f2022-04-04 15:47:50 +02005060 if (!ses->binding) {
5061 ses->capabilities = server->capabilities;
5062 if (linuxExtEnabled == 0)
5063 ses->capabilities &= (~server->vals->cap_unix);
5064
5065 if (ses->auth_key.response) {
5066 cifs_dbg(FYI, "Free previous auth_key.response = %p\n",
5067 ses->auth_key.response);
5068 kfree(ses->auth_key.response);
5069 ses->auth_key.response = NULL;
5070 ses->auth_key.len = 0;
5071 }
5072 }
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00005073
5074 cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n",
5075 server->sec_mode, server->capabilities, server->timeAdj);
5076
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00005077 if (server->ops->sess_setup)
5078 rc = server->ops->sess_setup(xid, ses, nls_info);
5079
5080 if (rc)
David Brazdil0f672f62019-12-10 10:32:29 +00005081 cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00005082
5083 return rc;
5084}
5085
5086static int
5087cifs_set_vol_auth(struct smb_vol *vol, struct cifs_ses *ses)
5088{
5089 vol->sectype = ses->sectype;
5090
5091 /* krb5 is special, since we don't need username or pw */
5092 if (vol->sectype == Kerberos)
5093 return 0;
5094
5095 return cifs_set_cifscreds(vol, ses);
5096}
5097
5098static struct cifs_tcon *
5099cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
5100{
5101 int rc;
5102 struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb);
5103 struct cifs_ses *ses;
5104 struct cifs_tcon *tcon = NULL;
5105 struct smb_vol *vol_info;
5106
5107 vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL);
5108 if (vol_info == NULL)
5109 return ERR_PTR(-ENOMEM);
5110
5111 vol_info->local_nls = cifs_sb->local_nls;
5112 vol_info->linux_uid = fsuid;
5113 vol_info->cred_uid = fsuid;
5114 vol_info->UNC = master_tcon->treeName;
5115 vol_info->retry = master_tcon->retry;
5116 vol_info->nocase = master_tcon->nocase;
5117 vol_info->nohandlecache = master_tcon->nohandlecache;
5118 vol_info->local_lease = master_tcon->local_lease;
Olivier Deprez0e641232021-09-23 10:07:05 +02005119 vol_info->no_lease = master_tcon->no_lease;
5120 vol_info->resilient = master_tcon->use_resilient;
5121 vol_info->persistent = master_tcon->use_persistent;
5122 vol_info->handle_timeout = master_tcon->handle_timeout;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00005123 vol_info->no_linux_ext = !master_tcon->unix_ext;
Olivier Deprez0e641232021-09-23 10:07:05 +02005124 vol_info->linux_ext = master_tcon->posix_extensions;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00005125 vol_info->sectype = master_tcon->ses->sectype;
5126 vol_info->sign = master_tcon->ses->sign;
Olivier Deprez0e641232021-09-23 10:07:05 +02005127 vol_info->seal = master_tcon->seal;
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00005128
5129 rc = cifs_set_vol_auth(vol_info, master_tcon->ses);
5130 if (rc) {
5131 tcon = ERR_PTR(rc);
5132 goto out;
5133 }
5134
5135 /* get a reference for the same TCP session */
5136 spin_lock(&cifs_tcp_ses_lock);
5137 ++master_tcon->ses->server->srv_count;
5138 spin_unlock(&cifs_tcp_ses_lock);
5139
5140 ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
5141 if (IS_ERR(ses)) {
5142 tcon = (struct cifs_tcon *)ses;
5143 cifs_put_tcp_session(master_tcon->ses->server, 0);
5144 goto out;
5145 }
5146
5147 tcon = cifs_get_tcon(ses, vol_info);
5148 if (IS_ERR(tcon)) {
5149 cifs_put_smb_ses(ses);
5150 goto out;
5151 }
5152
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00005153 if (cap_unix(ses))
5154 reset_cifs_unix_caps(0, tcon, NULL, vol_info);
5155
5156out:
5157 kfree(vol_info->username);
Olivier Deprez157378f2022-04-04 15:47:50 +02005158 kfree_sensitive(vol_info->password);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00005159 kfree(vol_info);
5160
5161 return tcon;
5162}
5163
5164struct cifs_tcon *
5165cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb)
5166{
5167 return tlink_tcon(cifs_sb_master_tlink(cifs_sb));
5168}
5169
5170/* find and return a tlink with given uid */
5171static struct tcon_link *
5172tlink_rb_search(struct rb_root *root, kuid_t uid)
5173{
5174 struct rb_node *node = root->rb_node;
5175 struct tcon_link *tlink;
5176
5177 while (node) {
5178 tlink = rb_entry(node, struct tcon_link, tl_rbnode);
5179
5180 if (uid_gt(tlink->tl_uid, uid))
5181 node = node->rb_left;
5182 else if (uid_lt(tlink->tl_uid, uid))
5183 node = node->rb_right;
5184 else
5185 return tlink;
5186 }
5187 return NULL;
5188}
5189
5190/* insert a tcon_link into the tree */
5191static void
5192tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink)
5193{
5194 struct rb_node **new = &(root->rb_node), *parent = NULL;
5195 struct tcon_link *tlink;
5196
5197 while (*new) {
5198 tlink = rb_entry(*new, struct tcon_link, tl_rbnode);
5199 parent = *new;
5200
5201 if (uid_gt(tlink->tl_uid, new_tlink->tl_uid))
5202 new = &((*new)->rb_left);
5203 else
5204 new = &((*new)->rb_right);
5205 }
5206
5207 rb_link_node(&new_tlink->tl_rbnode, parent, new);
5208 rb_insert_color(&new_tlink->tl_rbnode, root);
5209}
5210
5211/*
5212 * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
5213 * current task.
5214 *
5215 * If the superblock doesn't refer to a multiuser mount, then just return
5216 * the master tcon for the mount.
5217 *
5218 * First, search the rbtree for an existing tcon for this fsuid. If one
5219 * exists, then check to see if it's pending construction. If it is then wait
5220 * for construction to complete. Once it's no longer pending, check to see if
5221 * it failed and either return an error or retry construction, depending on
5222 * the timeout.
5223 *
5224 * If one doesn't exist then insert a new tcon_link struct into the tree and
5225 * try to construct a new one.
5226 */
5227struct tcon_link *
5228cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
5229{
5230 int ret;
5231 kuid_t fsuid = current_fsuid();
5232 struct tcon_link *tlink, *newtlink;
5233
5234 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
5235 return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
5236
5237 spin_lock(&cifs_sb->tlink_tree_lock);
5238 tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
5239 if (tlink)
5240 cifs_get_tlink(tlink);
5241 spin_unlock(&cifs_sb->tlink_tree_lock);
5242
5243 if (tlink == NULL) {
5244 newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
5245 if (newtlink == NULL)
5246 return ERR_PTR(-ENOMEM);
5247 newtlink->tl_uid = fsuid;
5248 newtlink->tl_tcon = ERR_PTR(-EACCES);
5249 set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
5250 set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
5251 cifs_get_tlink(newtlink);
5252
5253 spin_lock(&cifs_sb->tlink_tree_lock);
5254 /* was one inserted after previous search? */
5255 tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
5256 if (tlink) {
5257 cifs_get_tlink(tlink);
5258 spin_unlock(&cifs_sb->tlink_tree_lock);
5259 kfree(newtlink);
5260 goto wait_for_construction;
5261 }
5262 tlink = newtlink;
5263 tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
5264 spin_unlock(&cifs_sb->tlink_tree_lock);
5265 } else {
5266wait_for_construction:
5267 ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
5268 TASK_INTERRUPTIBLE);
5269 if (ret) {
5270 cifs_put_tlink(tlink);
5271 return ERR_PTR(-ERESTARTSYS);
5272 }
5273
5274 /* if it's good, return it */
5275 if (!IS_ERR(tlink->tl_tcon))
5276 return tlink;
5277
5278 /* return error if we tried this already recently */
5279 if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) {
5280 cifs_put_tlink(tlink);
5281 return ERR_PTR(-EACCES);
5282 }
5283
5284 if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags))
5285 goto wait_for_construction;
5286 }
5287
5288 tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid);
5289 clear_bit(TCON_LINK_PENDING, &tlink->tl_flags);
5290 wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING);
5291
5292 if (IS_ERR(tlink->tl_tcon)) {
5293 cifs_put_tlink(tlink);
5294 return ERR_PTR(-EACCES);
5295 }
5296
5297 return tlink;
5298}
5299
5300/*
5301 * periodic workqueue job that scans tcon_tree for a superblock and closes
5302 * out tcons.
5303 */
5304static void
5305cifs_prune_tlinks(struct work_struct *work)
5306{
5307 struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info,
5308 prune_tlinks.work);
5309 struct rb_root *root = &cifs_sb->tlink_tree;
5310 struct rb_node *node;
5311 struct rb_node *tmp;
5312 struct tcon_link *tlink;
5313
5314 /*
5315 * Because we drop the spinlock in the loop in order to put the tlink
5316 * it's not guarded against removal of links from the tree. The only
5317 * places that remove entries from the tree are this function and
5318 * umounts. Because this function is non-reentrant and is canceled
5319 * before umount can proceed, this is safe.
5320 */
5321 spin_lock(&cifs_sb->tlink_tree_lock);
5322 node = rb_first(root);
5323 while (node != NULL) {
5324 tmp = node;
5325 node = rb_next(tmp);
5326 tlink = rb_entry(tmp, struct tcon_link, tl_rbnode);
5327
5328 if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) ||
5329 atomic_read(&tlink->tl_count) != 0 ||
5330 time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies))
5331 continue;
5332
5333 cifs_get_tlink(tlink);
5334 clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
5335 rb_erase(tmp, root);
5336
5337 spin_unlock(&cifs_sb->tlink_tree_lock);
5338 cifs_put_tlink(tlink);
5339 spin_lock(&cifs_sb->tlink_tree_lock);
5340 }
5341 spin_unlock(&cifs_sb->tlink_tree_lock);
5342
5343 queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
5344 TLINK_IDLE_EXPIRE);
5345}
Olivier Deprez157378f2022-04-04 15:47:50 +02005346
5347#ifdef CONFIG_CIFS_DFS_UPCALL
5348int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc)
5349{
5350 int rc;
5351 struct TCP_Server_Info *server = tcon->ses->server;
5352 const struct smb_version_operations *ops = server->ops;
5353 struct dfs_cache_tgt_list tl;
5354 struct dfs_cache_tgt_iterator *it = NULL;
5355 char *tree;
5356 const char *tcp_host;
5357 size_t tcp_host_len;
5358 const char *dfs_host;
5359 size_t dfs_host_len;
5360 char *share = NULL, *prefix = NULL;
5361 struct dfs_info3_param ref = {0};
5362 bool isroot;
5363
5364 tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL);
5365 if (!tree)
5366 return -ENOMEM;
5367
5368 /* If it is not dfs or there was no cached dfs referral, then reconnect to same share */
5369 if (!tcon->dfs_path || dfs_cache_noreq_find(tcon->dfs_path + 1, &ref, &tl)) {
5370 if (tcon->ipc) {
5371 scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname);
5372 rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
5373 } else {
5374 rc = ops->tree_connect(xid, tcon->ses, tcon->treeName, tcon, nlsc);
5375 }
5376 goto out;
5377 }
5378
5379 isroot = ref.server_type == DFS_TYPE_ROOT;
5380 free_dfs_info_param(&ref);
5381
5382 extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len);
5383
5384 for (it = dfs_cache_get_tgt_iterator(&tl); it; it = dfs_cache_get_next_tgt(&tl, it)) {
5385 bool target_match;
5386
5387 kfree(share);
5388 kfree(prefix);
5389 share = NULL;
5390 prefix = NULL;
5391
5392 rc = dfs_cache_get_tgt_share(tcon->dfs_path + 1, it, &share, &prefix);
5393 if (rc) {
5394 cifs_dbg(VFS, "%s: failed to parse target share %d\n",
5395 __func__, rc);
5396 continue;
5397 }
5398
5399 extract_unc_hostname(share, &dfs_host, &dfs_host_len);
5400
5401 if (dfs_host_len != tcp_host_len
5402 || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
5403 cifs_dbg(FYI, "%s: %.*s doesn't match %.*s\n", __func__, (int)dfs_host_len,
5404 dfs_host, (int)tcp_host_len, tcp_host);
5405
5406 rc = match_target_ip(server, dfs_host, dfs_host_len, &target_match);
5407 if (rc) {
5408 cifs_dbg(VFS, "%s: failed to match target ip: %d\n", __func__, rc);
5409 break;
5410 }
5411
5412 if (!target_match) {
5413 cifs_dbg(FYI, "%s: skipping target\n", __func__);
5414 continue;
5415 }
5416 }
5417
5418 if (tcon->ipc) {
5419 scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", share);
5420 rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
5421 } else {
5422 scnprintf(tree, MAX_TREE_SIZE, "\\%s", share);
5423 rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
5424 /* Only handle prefix paths of DFS link targets */
5425 if (!rc && !isroot) {
5426 rc = update_super_prepath(tcon, prefix);
5427 break;
5428 }
5429 }
5430 if (rc == -EREMOTE)
5431 break;
5432 }
5433
5434 kfree(share);
5435 kfree(prefix);
5436
5437 if (!rc) {
5438 if (it)
5439 rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1, it);
5440 else
5441 rc = -ENOENT;
5442 }
5443 dfs_cache_free_tgts(&tl);
5444out:
5445 kfree(tree);
5446 return rc;
5447}
5448#else
5449int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc)
5450{
5451 const struct smb_version_operations *ops = tcon->ses->server->ops;
5452
5453 return ops->tree_connect(xid, tcon->ses, tcon->treeName, tcon, nlsc);
5454}
5455#endif