xref: /openbmc/linux/fs/smb/client/fs_context.c (revision e8aee4f4)
138c8a9a5SSteve French // SPDX-License-Identifier: GPL-2.0-or-later
238c8a9a5SSteve French /*
338c8a9a5SSteve French  *   Copyright (C) 2020, Microsoft Corporation.
438c8a9a5SSteve French  *
538c8a9a5SSteve French  *   Author(s): Steve French <stfrench@microsoft.com>
638c8a9a5SSteve French  *              David Howells <dhowells@redhat.com>
738c8a9a5SSteve French  */
838c8a9a5SSteve French 
938c8a9a5SSteve French /*
1038c8a9a5SSteve French #include <linux/module.h>
1138c8a9a5SSteve French #include <linux/nsproxy.h>
1238c8a9a5SSteve French #include <linux/slab.h>
1338c8a9a5SSteve French #include <linux/magic.h>
1438c8a9a5SSteve French #include <linux/security.h>
1538c8a9a5SSteve French #include <net/net_namespace.h>
1638c8a9a5SSteve French #ifdef CONFIG_CIFS_DFS_UPCALL
1738c8a9a5SSteve French #include "dfs_cache.h"
1838c8a9a5SSteve French #endif
1938c8a9a5SSteve French */
2038c8a9a5SSteve French 
2138c8a9a5SSteve French #include <linux/ctype.h>
2238c8a9a5SSteve French #include <linux/fs_context.h>
2338c8a9a5SSteve French #include <linux/fs_parser.h>
2438c8a9a5SSteve French #include <linux/fs.h>
2538c8a9a5SSteve French #include <linux/mount.h>
2638c8a9a5SSteve French #include <linux/parser.h>
2738c8a9a5SSteve French #include <linux/utsname.h>
2838c8a9a5SSteve French #include "cifsfs.h"
2938c8a9a5SSteve French #include "cifspdu.h"
3038c8a9a5SSteve French #include "cifsglob.h"
3138c8a9a5SSteve French #include "cifsproto.h"
3238c8a9a5SSteve French #include "cifs_unicode.h"
3338c8a9a5SSteve French #include "cifs_debug.h"
3438c8a9a5SSteve French #include "cifs_fs_sb.h"
3538c8a9a5SSteve French #include "ntlmssp.h"
3638c8a9a5SSteve French #include "nterr.h"
3738c8a9a5SSteve French #include "rfc1002pdu.h"
3838c8a9a5SSteve French #include "fs_context.h"
3938c8a9a5SSteve French 
40ba55f8a9SPaulo Alcantara DEFINE_MUTEX(cifs_mount_mutex);
4138c8a9a5SSteve French 
4238c8a9a5SSteve French static const match_table_t cifs_smb_version_tokens = {
4338c8a9a5SSteve French 	{ Smb_1, SMB1_VERSION_STRING },
4438c8a9a5SSteve French 	{ Smb_20, SMB20_VERSION_STRING},
4538c8a9a5SSteve French 	{ Smb_21, SMB21_VERSION_STRING },
4638c8a9a5SSteve French 	{ Smb_30, SMB30_VERSION_STRING },
4738c8a9a5SSteve French 	{ Smb_302, SMB302_VERSION_STRING },
4838c8a9a5SSteve French 	{ Smb_302, ALT_SMB302_VERSION_STRING },
4938c8a9a5SSteve French 	{ Smb_311, SMB311_VERSION_STRING },
5038c8a9a5SSteve French 	{ Smb_311, ALT_SMB311_VERSION_STRING },
5138c8a9a5SSteve French 	{ Smb_3any, SMB3ANY_VERSION_STRING },
5238c8a9a5SSteve French 	{ Smb_default, SMBDEFAULT_VERSION_STRING },
5338c8a9a5SSteve French 	{ Smb_version_err, NULL }
5438c8a9a5SSteve French };
5538c8a9a5SSteve French 
5638c8a9a5SSteve French static const match_table_t cifs_secflavor_tokens = {
5738c8a9a5SSteve French 	{ Opt_sec_krb5, "krb5" },
5838c8a9a5SSteve French 	{ Opt_sec_krb5i, "krb5i" },
5938c8a9a5SSteve French 	{ Opt_sec_krb5p, "krb5p" },
6038c8a9a5SSteve French 	{ Opt_sec_ntlmsspi, "ntlmsspi" },
6138c8a9a5SSteve French 	{ Opt_sec_ntlmssp, "ntlmssp" },
6238c8a9a5SSteve French 	{ Opt_sec_ntlmv2, "nontlm" },
6338c8a9a5SSteve French 	{ Opt_sec_ntlmv2, "ntlmv2" },
6438c8a9a5SSteve French 	{ Opt_sec_ntlmv2i, "ntlmv2i" },
6538c8a9a5SSteve French 	{ Opt_sec_none, "none" },
6638c8a9a5SSteve French 
6738c8a9a5SSteve French 	{ Opt_sec_err, NULL }
6838c8a9a5SSteve French };
6938c8a9a5SSteve French 
7038c8a9a5SSteve French const struct fs_parameter_spec smb3_fs_parameters[] = {
7138c8a9a5SSteve French 	/* Mount options that take no arguments */
7238c8a9a5SSteve French 	fsparam_flag_no("user_xattr", Opt_user_xattr),
7338c8a9a5SSteve French 	fsparam_flag_no("forceuid", Opt_forceuid),
7438c8a9a5SSteve French 	fsparam_flag_no("multichannel", Opt_multichannel),
7538c8a9a5SSteve French 	fsparam_flag_no("forcegid", Opt_forcegid),
7638c8a9a5SSteve French 	fsparam_flag("noblocksend", Opt_noblocksend),
7738c8a9a5SSteve French 	fsparam_flag("noautotune", Opt_noautotune),
7838c8a9a5SSteve French 	fsparam_flag("nolease", Opt_nolease),
7938c8a9a5SSteve French 	fsparam_flag_no("hard", Opt_hard),
8038c8a9a5SSteve French 	fsparam_flag_no("soft", Opt_soft),
8138c8a9a5SSteve French 	fsparam_flag_no("perm", Opt_perm),
8238c8a9a5SSteve French 	fsparam_flag("nodelete", Opt_nodelete),
8338c8a9a5SSteve French 	fsparam_flag_no("mapposix", Opt_mapposix),
8438c8a9a5SSteve French 	fsparam_flag("mapchars", Opt_mapchars),
8538c8a9a5SSteve French 	fsparam_flag("nomapchars", Opt_nomapchars),
8638c8a9a5SSteve French 	fsparam_flag_no("sfu", Opt_sfu),
8738c8a9a5SSteve French 	fsparam_flag("nodfs", Opt_nodfs),
8838c8a9a5SSteve French 	fsparam_flag_no("posixpaths", Opt_posixpaths),
8938c8a9a5SSteve French 	fsparam_flag_no("unix", Opt_unix),
9038c8a9a5SSteve French 	fsparam_flag_no("linux", Opt_unix),
9138c8a9a5SSteve French 	fsparam_flag_no("posix", Opt_unix),
9238c8a9a5SSteve French 	fsparam_flag("nocase", Opt_nocase),
9338c8a9a5SSteve French 	fsparam_flag("ignorecase", Opt_nocase),
9438c8a9a5SSteve French 	fsparam_flag_no("brl", Opt_brl),
9538c8a9a5SSteve French 	fsparam_flag_no("handlecache", Opt_handlecache),
9638c8a9a5SSteve French 	fsparam_flag("forcemandatorylock", Opt_forcemandatorylock),
9738c8a9a5SSteve French 	fsparam_flag("forcemand", Opt_forcemandatorylock),
9838c8a9a5SSteve French 	fsparam_flag("setuidfromacl", Opt_setuidfromacl),
9938c8a9a5SSteve French 	fsparam_flag("idsfromsid", Opt_setuidfromacl),
10038c8a9a5SSteve French 	fsparam_flag_no("setuids", Opt_setuids),
10138c8a9a5SSteve French 	fsparam_flag_no("dynperm", Opt_dynperm),
10238c8a9a5SSteve French 	fsparam_flag_no("intr", Opt_intr),
10338c8a9a5SSteve French 	fsparam_flag_no("strictsync", Opt_strictsync),
10438c8a9a5SSteve French 	fsparam_flag_no("serverino", Opt_serverino),
10538c8a9a5SSteve French 	fsparam_flag("rwpidforward", Opt_rwpidforward),
10638c8a9a5SSteve French 	fsparam_flag("cifsacl", Opt_cifsacl),
10738c8a9a5SSteve French 	fsparam_flag_no("acl", Opt_acl),
10838c8a9a5SSteve French 	fsparam_flag("locallease", Opt_locallease),
10938c8a9a5SSteve French 	fsparam_flag("sign", Opt_sign),
11038c8a9a5SSteve French 	fsparam_flag("ignore_signature", Opt_ignore_signature),
11138c8a9a5SSteve French 	fsparam_flag("signloosely", Opt_ignore_signature),
11238c8a9a5SSteve French 	fsparam_flag("seal", Opt_seal),
11338c8a9a5SSteve French 	fsparam_flag("noac", Opt_noac),
11438c8a9a5SSteve French 	fsparam_flag("fsc", Opt_fsc),
11538c8a9a5SSteve French 	fsparam_flag("mfsymlinks", Opt_mfsymlinks),
11638c8a9a5SSteve French 	fsparam_flag("multiuser", Opt_multiuser),
11738c8a9a5SSteve French 	fsparam_flag("sloppy", Opt_sloppy),
11838c8a9a5SSteve French 	fsparam_flag("nosharesock", Opt_nosharesock),
11938c8a9a5SSteve French 	fsparam_flag_no("persistenthandles", Opt_persistent),
12038c8a9a5SSteve French 	fsparam_flag_no("resilienthandles", Opt_resilient),
12138c8a9a5SSteve French 	fsparam_flag_no("tcpnodelay", Opt_tcp_nodelay),
12238c8a9a5SSteve French 	fsparam_flag("nosparse", Opt_nosparse),
12338c8a9a5SSteve French 	fsparam_flag("domainauto", Opt_domainauto),
12438c8a9a5SSteve French 	fsparam_flag("rdma", Opt_rdma),
12538c8a9a5SSteve French 	fsparam_flag("modesid", Opt_modesid),
12638c8a9a5SSteve French 	fsparam_flag("modefromsid", Opt_modesid),
12738c8a9a5SSteve French 	fsparam_flag("rootfs", Opt_rootfs),
12838c8a9a5SSteve French 	fsparam_flag("compress", Opt_compress),
12938c8a9a5SSteve French 	fsparam_flag("witness", Opt_witness),
13038c8a9a5SSteve French 
13138c8a9a5SSteve French 	/* Mount options which take numeric value */
13238c8a9a5SSteve French 	fsparam_u32("backupuid", Opt_backupuid),
13338c8a9a5SSteve French 	fsparam_u32("backupgid", Opt_backupgid),
13438c8a9a5SSteve French 	fsparam_u32("uid", Opt_uid),
13538c8a9a5SSteve French 	fsparam_u32("cruid", Opt_cruid),
13638c8a9a5SSteve French 	fsparam_u32("gid", Opt_gid),
13738c8a9a5SSteve French 	fsparam_u32("file_mode", Opt_file_mode),
13838c8a9a5SSteve French 	fsparam_u32("dirmode", Opt_dirmode),
13938c8a9a5SSteve French 	fsparam_u32("dir_mode", Opt_dirmode),
14038c8a9a5SSteve French 	fsparam_u32("port", Opt_port),
14138c8a9a5SSteve French 	fsparam_u32("min_enc_offload", Opt_min_enc_offload),
142b4ca2942SShyam Prasad N 	fsparam_u32("retrans", Opt_retrans),
14338c8a9a5SSteve French 	fsparam_u32("esize", Opt_min_enc_offload),
14438c8a9a5SSteve French 	fsparam_u32("bsize", Opt_blocksize),
14538c8a9a5SSteve French 	fsparam_u32("rasize", Opt_rasize),
14638c8a9a5SSteve French 	fsparam_u32("rsize", Opt_rsize),
14738c8a9a5SSteve French 	fsparam_u32("wsize", Opt_wsize),
14838c8a9a5SSteve French 	fsparam_u32("actimeo", Opt_actimeo),
14938c8a9a5SSteve French 	fsparam_u32("acdirmax", Opt_acdirmax),
15038c8a9a5SSteve French 	fsparam_u32("acregmax", Opt_acregmax),
15138c8a9a5SSteve French 	fsparam_u32("closetimeo", Opt_closetimeo),
15238c8a9a5SSteve French 	fsparam_u32("echo_interval", Opt_echo_interval),
15338c8a9a5SSteve French 	fsparam_u32("max_credits", Opt_max_credits),
1546a50d71dSSteve French 	fsparam_u32("max_cached_dirs", Opt_max_cached_dirs),
15538c8a9a5SSteve French 	fsparam_u32("handletimeout", Opt_handletimeout),
15638c8a9a5SSteve French 	fsparam_u64("snapshot", Opt_snapshot),
15738c8a9a5SSteve French 	fsparam_u32("max_channels", Opt_max_channels),
15838c8a9a5SSteve French 
15938c8a9a5SSteve French 	/* Mount options which take string value */
16038c8a9a5SSteve French 	fsparam_string("source", Opt_source),
16138c8a9a5SSteve French 	fsparam_string("user", Opt_user),
16238c8a9a5SSteve French 	fsparam_string("username", Opt_user),
16338c8a9a5SSteve French 	fsparam_string("pass", Opt_pass),
16438c8a9a5SSteve French 	fsparam_string("password", Opt_pass),
16508bedfbcSSteve French 	fsparam_string("password2", Opt_pass2),
16638c8a9a5SSteve French 	fsparam_string("ip", Opt_ip),
16738c8a9a5SSteve French 	fsparam_string("addr", Opt_ip),
16838c8a9a5SSteve French 	fsparam_string("domain", Opt_domain),
16938c8a9a5SSteve French 	fsparam_string("dom", Opt_domain),
17038c8a9a5SSteve French 	fsparam_string("srcaddr", Opt_srcaddr),
17138c8a9a5SSteve French 	fsparam_string("iocharset", Opt_iocharset),
17238c8a9a5SSteve French 	fsparam_string("netbiosname", Opt_netbiosname),
17338c8a9a5SSteve French 	fsparam_string("servern", Opt_servern),
17438c8a9a5SSteve French 	fsparam_string("ver", Opt_ver),
17538c8a9a5SSteve French 	fsparam_string("vers", Opt_vers),
17638c8a9a5SSteve French 	fsparam_string("sec", Opt_sec),
17738c8a9a5SSteve French 	fsparam_string("cache", Opt_cache),
178c1468c7eSPaulo Alcantara 	fsparam_string("reparse", Opt_reparse),
17938c8a9a5SSteve French 
18038c8a9a5SSteve French 	/* Arguments that should be ignored */
18138c8a9a5SSteve French 	fsparam_flag("guest", Opt_ignore),
18238c8a9a5SSteve French 	fsparam_flag("noatime", Opt_ignore),
18338c8a9a5SSteve French 	fsparam_flag("relatime", Opt_ignore),
18438c8a9a5SSteve French 	fsparam_flag("_netdev", Opt_ignore),
18538c8a9a5SSteve French 	fsparam_flag_no("suid", Opt_ignore),
18638c8a9a5SSteve French 	fsparam_flag_no("exec", Opt_ignore),
18738c8a9a5SSteve French 	fsparam_flag_no("dev", Opt_ignore),
18838c8a9a5SSteve French 	fsparam_flag_no("mand", Opt_ignore),
18938c8a9a5SSteve French 	fsparam_flag_no("auto", Opt_ignore),
19038c8a9a5SSteve French 	fsparam_string("cred", Opt_ignore),
19138c8a9a5SSteve French 	fsparam_string("credentials", Opt_ignore),
19238c8a9a5SSteve French 	/*
19338c8a9a5SSteve French 	 * UNC and prefixpath is now extracted from Opt_source
19438c8a9a5SSteve French 	 * in the new mount API so we can just ignore them going forward.
19538c8a9a5SSteve French 	 */
19638c8a9a5SSteve French 	fsparam_string("unc", Opt_ignore),
19738c8a9a5SSteve French 	fsparam_string("prefixpath", Opt_ignore),
19838c8a9a5SSteve French 	{}
19938c8a9a5SSteve French };
20038c8a9a5SSteve French 
20138c8a9a5SSteve French static int
cifs_parse_security_flavors(struct fs_context * fc,char * value,struct smb3_fs_context * ctx)20238c8a9a5SSteve French cifs_parse_security_flavors(struct fs_context *fc, char *value, struct smb3_fs_context *ctx)
20338c8a9a5SSteve French {
20438c8a9a5SSteve French 
20538c8a9a5SSteve French 	substring_t args[MAX_OPT_ARGS];
20638c8a9a5SSteve French 
20738c8a9a5SSteve French 	/*
20838c8a9a5SSteve French 	 * With mount options, the last one should win. Reset any existing
20938c8a9a5SSteve French 	 * settings back to default.
21038c8a9a5SSteve French 	 */
21138c8a9a5SSteve French 	ctx->sectype = Unspecified;
21238c8a9a5SSteve French 	ctx->sign = false;
21338c8a9a5SSteve French 
21438c8a9a5SSteve French 	switch (match_token(value, cifs_secflavor_tokens, args)) {
21538c8a9a5SSteve French 	case Opt_sec_krb5p:
216c5e3ec78SSteve French 		cifs_errorf(fc, "sec=krb5p is not supported. Use sec=krb5,seal instead\n");
21738c8a9a5SSteve French 		return 1;
21838c8a9a5SSteve French 	case Opt_sec_krb5i:
21938c8a9a5SSteve French 		ctx->sign = true;
22038c8a9a5SSteve French 		fallthrough;
22138c8a9a5SSteve French 	case Opt_sec_krb5:
22238c8a9a5SSteve French 		ctx->sectype = Kerberos;
22338c8a9a5SSteve French 		break;
22438c8a9a5SSteve French 	case Opt_sec_ntlmsspi:
22538c8a9a5SSteve French 		ctx->sign = true;
22638c8a9a5SSteve French 		fallthrough;
22738c8a9a5SSteve French 	case Opt_sec_ntlmssp:
22838c8a9a5SSteve French 		ctx->sectype = RawNTLMSSP;
22938c8a9a5SSteve French 		break;
23038c8a9a5SSteve French 	case Opt_sec_ntlmv2i:
23138c8a9a5SSteve French 		ctx->sign = true;
23238c8a9a5SSteve French 		fallthrough;
23338c8a9a5SSteve French 	case Opt_sec_ntlmv2:
23438c8a9a5SSteve French 		ctx->sectype = NTLMv2;
23538c8a9a5SSteve French 		break;
23638c8a9a5SSteve French 	case Opt_sec_none:
23738c8a9a5SSteve French 		ctx->nullauth = 1;
238270d73e6SScott Mayhew 		kfree(ctx->username);
239270d73e6SScott Mayhew 		ctx->username = NULL;
24038c8a9a5SSteve French 		break;
24138c8a9a5SSteve French 	default:
24238c8a9a5SSteve French 		cifs_errorf(fc, "bad security option: %s\n", value);
24338c8a9a5SSteve French 		return 1;
24438c8a9a5SSteve French 	}
24538c8a9a5SSteve French 
24638c8a9a5SSteve French 	return 0;
24738c8a9a5SSteve French }
24838c8a9a5SSteve French 
24938c8a9a5SSteve French static const match_table_t cifs_cacheflavor_tokens = {
25038c8a9a5SSteve French 	{ Opt_cache_loose, "loose" },
25138c8a9a5SSteve French 	{ Opt_cache_strict, "strict" },
25238c8a9a5SSteve French 	{ Opt_cache_none, "none" },
25338c8a9a5SSteve French 	{ Opt_cache_ro, "ro" },
25438c8a9a5SSteve French 	{ Opt_cache_rw, "singleclient" },
25538c8a9a5SSteve French 	{ Opt_cache_err, NULL }
25638c8a9a5SSteve French };
25738c8a9a5SSteve French 
25838c8a9a5SSteve French static int
cifs_parse_cache_flavor(struct fs_context * fc,char * value,struct smb3_fs_context * ctx)25938c8a9a5SSteve French cifs_parse_cache_flavor(struct fs_context *fc, char *value, struct smb3_fs_context *ctx)
26038c8a9a5SSteve French {
26138c8a9a5SSteve French 	substring_t args[MAX_OPT_ARGS];
26238c8a9a5SSteve French 
26338c8a9a5SSteve French 	switch (match_token(value, cifs_cacheflavor_tokens, args)) {
26438c8a9a5SSteve French 	case Opt_cache_loose:
26538c8a9a5SSteve French 		ctx->direct_io = false;
26638c8a9a5SSteve French 		ctx->strict_io = false;
26738c8a9a5SSteve French 		ctx->cache_ro = false;
26838c8a9a5SSteve French 		ctx->cache_rw = false;
26938c8a9a5SSteve French 		break;
27038c8a9a5SSteve French 	case Opt_cache_strict:
27138c8a9a5SSteve French 		ctx->direct_io = false;
27238c8a9a5SSteve French 		ctx->strict_io = true;
27338c8a9a5SSteve French 		ctx->cache_ro = false;
27438c8a9a5SSteve French 		ctx->cache_rw = false;
27538c8a9a5SSteve French 		break;
27638c8a9a5SSteve French 	case Opt_cache_none:
27738c8a9a5SSteve French 		ctx->direct_io = true;
27838c8a9a5SSteve French 		ctx->strict_io = false;
27938c8a9a5SSteve French 		ctx->cache_ro = false;
28038c8a9a5SSteve French 		ctx->cache_rw = false;
28138c8a9a5SSteve French 		break;
28238c8a9a5SSteve French 	case Opt_cache_ro:
28338c8a9a5SSteve French 		ctx->direct_io = false;
28438c8a9a5SSteve French 		ctx->strict_io = false;
28538c8a9a5SSteve French 		ctx->cache_ro = true;
28638c8a9a5SSteve French 		ctx->cache_rw = false;
28738c8a9a5SSteve French 		break;
28838c8a9a5SSteve French 	case Opt_cache_rw:
28938c8a9a5SSteve French 		ctx->direct_io = false;
29038c8a9a5SSteve French 		ctx->strict_io = false;
29138c8a9a5SSteve French 		ctx->cache_ro = false;
29238c8a9a5SSteve French 		ctx->cache_rw = true;
29338c8a9a5SSteve French 		break;
29438c8a9a5SSteve French 	default:
29538c8a9a5SSteve French 		cifs_errorf(fc, "bad cache= option: %s\n", value);
29638c8a9a5SSteve French 		return 1;
29738c8a9a5SSteve French 	}
29838c8a9a5SSteve French 	return 0;
29938c8a9a5SSteve French }
30038c8a9a5SSteve French 
301c1468c7eSPaulo Alcantara static const match_table_t reparse_flavor_tokens = {
302c1468c7eSPaulo Alcantara 	{ Opt_reparse_default,	"default" },
303c1468c7eSPaulo Alcantara 	{ Opt_reparse_nfs,	"nfs" },
304c1468c7eSPaulo Alcantara 	{ Opt_reparse_wsl,	"wsl" },
305c1468c7eSPaulo Alcantara 	{ Opt_reparse_err,	NULL },
306c1468c7eSPaulo Alcantara };
307c1468c7eSPaulo Alcantara 
parse_reparse_flavor(struct fs_context * fc,char * value,struct smb3_fs_context * ctx)308c1468c7eSPaulo Alcantara static int parse_reparse_flavor(struct fs_context *fc, char *value,
309c1468c7eSPaulo Alcantara 				struct smb3_fs_context *ctx)
310c1468c7eSPaulo Alcantara {
311c1468c7eSPaulo Alcantara 	substring_t args[MAX_OPT_ARGS];
312c1468c7eSPaulo Alcantara 
313c1468c7eSPaulo Alcantara 	switch (match_token(value, reparse_flavor_tokens, args)) {
314c1468c7eSPaulo Alcantara 	case Opt_reparse_default:
315c1468c7eSPaulo Alcantara 		ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT;
316c1468c7eSPaulo Alcantara 		break;
317c1468c7eSPaulo Alcantara 	case Opt_reparse_nfs:
318c1468c7eSPaulo Alcantara 		ctx->reparse_type = CIFS_REPARSE_TYPE_NFS;
319c1468c7eSPaulo Alcantara 		break;
320c1468c7eSPaulo Alcantara 	case Opt_reparse_wsl:
321df0a8a19SPaulo Alcantara 		ctx->reparse_type = CIFS_REPARSE_TYPE_WSL;
322df0a8a19SPaulo Alcantara 		break;
323c1468c7eSPaulo Alcantara 	default:
324c1468c7eSPaulo Alcantara 		cifs_errorf(fc, "bad reparse= option: %s\n", value);
325c1468c7eSPaulo Alcantara 		return 1;
326c1468c7eSPaulo Alcantara 	}
327c1468c7eSPaulo Alcantara 	return 0;
328c1468c7eSPaulo Alcantara }
329c1468c7eSPaulo Alcantara 
33038c8a9a5SSteve French #define DUP_CTX_STR(field)						\
33138c8a9a5SSteve French do {									\
33238c8a9a5SSteve French 	if (ctx->field) {						\
33338c8a9a5SSteve French 		new_ctx->field = kstrdup(ctx->field, GFP_ATOMIC);	\
33438c8a9a5SSteve French 		if (new_ctx->field == NULL) {				\
33538c8a9a5SSteve French 			smb3_cleanup_fs_context_contents(new_ctx);	\
33638c8a9a5SSteve French 			return -ENOMEM;					\
33738c8a9a5SSteve French 		}							\
33838c8a9a5SSteve French 	}								\
33938c8a9a5SSteve French } while (0)
34038c8a9a5SSteve French 
34138c8a9a5SSteve French int
smb3_fs_context_dup(struct smb3_fs_context * new_ctx,struct smb3_fs_context * ctx)34238c8a9a5SSteve French smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx)
34338c8a9a5SSteve French {
34438c8a9a5SSteve French 	memcpy(new_ctx, ctx, sizeof(*ctx));
34538c8a9a5SSteve French 	new_ctx->prepath = NULL;
34638c8a9a5SSteve French 	new_ctx->nodename = NULL;
34738c8a9a5SSteve French 	new_ctx->username = NULL;
34838c8a9a5SSteve French 	new_ctx->password = NULL;
34908bedfbcSSteve French 	new_ctx->password2 = NULL;
35038c8a9a5SSteve French 	new_ctx->server_hostname = NULL;
35138c8a9a5SSteve French 	new_ctx->domainname = NULL;
35238c8a9a5SSteve French 	new_ctx->UNC = NULL;
35338c8a9a5SSteve French 	new_ctx->source = NULL;
35438c8a9a5SSteve French 	new_ctx->iocharset = NULL;
35538c8a9a5SSteve French 	new_ctx->leaf_fullpath = NULL;
35638c8a9a5SSteve French 	/*
35738c8a9a5SSteve French 	 * Make sure to stay in sync with smb3_cleanup_fs_context_contents()
35838c8a9a5SSteve French 	 */
35938c8a9a5SSteve French 	DUP_CTX_STR(prepath);
36038c8a9a5SSteve French 	DUP_CTX_STR(username);
36138c8a9a5SSteve French 	DUP_CTX_STR(password);
36208bedfbcSSteve French 	DUP_CTX_STR(password2);
36338c8a9a5SSteve French 	DUP_CTX_STR(server_hostname);
36438c8a9a5SSteve French 	DUP_CTX_STR(UNC);
36538c8a9a5SSteve French 	DUP_CTX_STR(source);
36638c8a9a5SSteve French 	DUP_CTX_STR(domainname);
36738c8a9a5SSteve French 	DUP_CTX_STR(nodename);
36838c8a9a5SSteve French 	DUP_CTX_STR(iocharset);
36938c8a9a5SSteve French 	DUP_CTX_STR(leaf_fullpath);
37038c8a9a5SSteve French 
37138c8a9a5SSteve French 	return 0;
37238c8a9a5SSteve French }
37338c8a9a5SSteve French 
37438c8a9a5SSteve French static int
cifs_parse_smb_version(struct fs_context * fc,char * value,struct smb3_fs_context * ctx,bool is_smb3)37538c8a9a5SSteve French cifs_parse_smb_version(struct fs_context *fc, char *value, struct smb3_fs_context *ctx, bool is_smb3)
37638c8a9a5SSteve French {
37738c8a9a5SSteve French 	substring_t args[MAX_OPT_ARGS];
37838c8a9a5SSteve French 
37938c8a9a5SSteve French 	switch (match_token(value, cifs_smb_version_tokens, args)) {
38038c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
38138c8a9a5SSteve French 	case Smb_1:
38238c8a9a5SSteve French 		if (disable_legacy_dialects) {
38338c8a9a5SSteve French 			cifs_errorf(fc, "mount with legacy dialect disabled\n");
38438c8a9a5SSteve French 			return 1;
38538c8a9a5SSteve French 		}
38638c8a9a5SSteve French 		if (is_smb3) {
38738c8a9a5SSteve French 			cifs_errorf(fc, "vers=1.0 (cifs) not permitted when mounting with smb3\n");
38838c8a9a5SSteve French 			return 1;
38938c8a9a5SSteve French 		}
39038c8a9a5SSteve French 		cifs_errorf(fc, "Use of the less secure dialect vers=1.0 is not recommended unless required for access to very old servers\n");
39138c8a9a5SSteve French 		ctx->ops = &smb1_operations;
39238c8a9a5SSteve French 		ctx->vals = &smb1_values;
39338c8a9a5SSteve French 		break;
39438c8a9a5SSteve French 	case Smb_20:
39538c8a9a5SSteve French 		if (disable_legacy_dialects) {
39638c8a9a5SSteve French 			cifs_errorf(fc, "mount with legacy dialect disabled\n");
39738c8a9a5SSteve French 			return 1;
39838c8a9a5SSteve French 		}
39938c8a9a5SSteve French 		if (is_smb3) {
40038c8a9a5SSteve French 			cifs_errorf(fc, "vers=2.0 not permitted when mounting with smb3\n");
40138c8a9a5SSteve French 			return 1;
40238c8a9a5SSteve French 		}
40338c8a9a5SSteve French 		ctx->ops = &smb20_operations;
40438c8a9a5SSteve French 		ctx->vals = &smb20_values;
40538c8a9a5SSteve French 		break;
40638c8a9a5SSteve French #else
40738c8a9a5SSteve French 	case Smb_1:
40838c8a9a5SSteve French 		cifs_errorf(fc, "vers=1.0 (cifs) mount not permitted when legacy dialects disabled\n");
40938c8a9a5SSteve French 		return 1;
41038c8a9a5SSteve French 	case Smb_20:
41138c8a9a5SSteve French 		cifs_errorf(fc, "vers=2.0 mount not permitted when legacy dialects disabled\n");
41238c8a9a5SSteve French 		return 1;
41338c8a9a5SSteve French #endif /* CIFS_ALLOW_INSECURE_LEGACY */
41438c8a9a5SSteve French 	case Smb_21:
41538c8a9a5SSteve French 		ctx->ops = &smb21_operations;
41638c8a9a5SSteve French 		ctx->vals = &smb21_values;
41738c8a9a5SSteve French 		break;
41838c8a9a5SSteve French 	case Smb_30:
41938c8a9a5SSteve French 		ctx->ops = &smb30_operations;
42038c8a9a5SSteve French 		ctx->vals = &smb30_values;
42138c8a9a5SSteve French 		break;
42238c8a9a5SSteve French 	case Smb_302:
42338c8a9a5SSteve French 		ctx->ops = &smb30_operations; /* currently identical with 3.0 */
42438c8a9a5SSteve French 		ctx->vals = &smb302_values;
42538c8a9a5SSteve French 		break;
42638c8a9a5SSteve French 	case Smb_311:
42738c8a9a5SSteve French 		ctx->ops = &smb311_operations;
42838c8a9a5SSteve French 		ctx->vals = &smb311_values;
42938c8a9a5SSteve French 		break;
43038c8a9a5SSteve French 	case Smb_3any:
43138c8a9a5SSteve French 		ctx->ops = &smb30_operations; /* currently identical with 3.0 */
43238c8a9a5SSteve French 		ctx->vals = &smb3any_values;
43338c8a9a5SSteve French 		break;
43438c8a9a5SSteve French 	case Smb_default:
43538c8a9a5SSteve French 		ctx->ops = &smb30_operations;
43638c8a9a5SSteve French 		ctx->vals = &smbdefault_values;
43738c8a9a5SSteve French 		break;
43838c8a9a5SSteve French 	default:
43938c8a9a5SSteve French 		cifs_errorf(fc, "Unknown vers= option specified: %s\n", value);
44038c8a9a5SSteve French 		return 1;
44138c8a9a5SSteve French 	}
44238c8a9a5SSteve French 	return 0;
44338c8a9a5SSteve French }
44438c8a9a5SSteve French 
smb3_parse_opt(const char * options,const char * key,char ** val)44538c8a9a5SSteve French int smb3_parse_opt(const char *options, const char *key, char **val)
44638c8a9a5SSteve French {
44738c8a9a5SSteve French 	int rc = -ENOENT;
44838c8a9a5SSteve French 	char *opts, *orig, *p;
44938c8a9a5SSteve French 
45038c8a9a5SSteve French 	orig = opts = kstrdup(options, GFP_KERNEL);
45138c8a9a5SSteve French 	if (!opts)
45238c8a9a5SSteve French 		return -ENOMEM;
45338c8a9a5SSteve French 
45438c8a9a5SSteve French 	while ((p = strsep(&opts, ","))) {
45538c8a9a5SSteve French 		char *nval;
45638c8a9a5SSteve French 
45738c8a9a5SSteve French 		if (!*p)
45838c8a9a5SSteve French 			continue;
45938c8a9a5SSteve French 		if (strncasecmp(p, key, strlen(key)))
46038c8a9a5SSteve French 			continue;
46138c8a9a5SSteve French 		nval = strchr(p, '=');
46238c8a9a5SSteve French 		if (nval) {
46338c8a9a5SSteve French 			if (nval == p)
46438c8a9a5SSteve French 				continue;
46538c8a9a5SSteve French 			*nval++ = 0;
46638c8a9a5SSteve French 			*val = kstrdup(nval, GFP_KERNEL);
46738c8a9a5SSteve French 			rc = !*val ? -ENOMEM : 0;
46838c8a9a5SSteve French 			goto out;
46938c8a9a5SSteve French 		}
47038c8a9a5SSteve French 	}
47138c8a9a5SSteve French out:
47238c8a9a5SSteve French 	kfree(orig);
47338c8a9a5SSteve French 	return rc;
47438c8a9a5SSteve French }
47538c8a9a5SSteve French 
47638c8a9a5SSteve French /*
47738c8a9a5SSteve French  * Remove duplicate path delimiters. Windows is supposed to do that
47838c8a9a5SSteve French  * but there are some bugs that prevent rename from working if there are
47938c8a9a5SSteve French  * multiple delimiters.
48038c8a9a5SSteve French  *
48149024ec8SPaulo Alcantara  * Return a sanitized duplicate of @path or NULL for empty prefix paths.
48249024ec8SPaulo Alcantara  * Otherwise, return ERR_PTR.
48349024ec8SPaulo Alcantara  *
48449024ec8SPaulo Alcantara  * @gfp indicates the GFP_* flags for kstrdup.
48538c8a9a5SSteve French  * The caller is responsible for freeing the original.
48638c8a9a5SSteve French  */
48738c8a9a5SSteve French #define IS_DELIM(c) ((c) == '/' || (c) == '\\')
cifs_sanitize_prepath(char * prepath,gfp_t gfp)48838c8a9a5SSteve French char *cifs_sanitize_prepath(char *prepath, gfp_t gfp)
48938c8a9a5SSteve French {
49038c8a9a5SSteve French 	char *cursor1 = prepath, *cursor2 = prepath;
49149024ec8SPaulo Alcantara 	char *s;
49238c8a9a5SSteve French 
49338c8a9a5SSteve French 	/* skip all prepended delimiters */
49438c8a9a5SSteve French 	while (IS_DELIM(*cursor1))
49538c8a9a5SSteve French 		cursor1++;
49638c8a9a5SSteve French 
49738c8a9a5SSteve French 	/* copy the first letter */
49838c8a9a5SSteve French 	*cursor2 = *cursor1;
49938c8a9a5SSteve French 
50038c8a9a5SSteve French 	/* copy the remainder... */
50138c8a9a5SSteve French 	while (*(cursor1++)) {
50238c8a9a5SSteve French 		/* ... skipping all duplicated delimiters */
50338c8a9a5SSteve French 		if (IS_DELIM(*cursor1) && IS_DELIM(*cursor2))
50438c8a9a5SSteve French 			continue;
50538c8a9a5SSteve French 		*(++cursor2) = *cursor1;
50638c8a9a5SSteve French 	}
50738c8a9a5SSteve French 
50838c8a9a5SSteve French 	/* if the last character is a delimiter, skip it */
50938c8a9a5SSteve French 	if (IS_DELIM(*(cursor2 - 1)))
51038c8a9a5SSteve French 		cursor2--;
51138c8a9a5SSteve French 
51249024ec8SPaulo Alcantara 	*cursor2 = '\0';
51349024ec8SPaulo Alcantara 	if (!*prepath)
51449024ec8SPaulo Alcantara 		return NULL;
51549024ec8SPaulo Alcantara 	s = kstrdup(prepath, gfp);
51649024ec8SPaulo Alcantara 	if (!s)
51749024ec8SPaulo Alcantara 		return ERR_PTR(-ENOMEM);
51849024ec8SPaulo Alcantara 	return s;
51949024ec8SPaulo Alcantara }
52049024ec8SPaulo Alcantara 
52149024ec8SPaulo Alcantara /*
52249024ec8SPaulo Alcantara  * Return full path based on the values of @ctx->{UNC,prepath}.
52349024ec8SPaulo Alcantara  *
52449024ec8SPaulo Alcantara  * It is assumed that both values were already parsed by smb3_parse_devname().
52549024ec8SPaulo Alcantara  */
smb3_fs_context_fullpath(const struct smb3_fs_context * ctx,char dirsep)52649024ec8SPaulo Alcantara char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx, char dirsep)
52749024ec8SPaulo Alcantara {
52849024ec8SPaulo Alcantara 	size_t ulen, plen;
52949024ec8SPaulo Alcantara 	char *s;
53049024ec8SPaulo Alcantara 
53149024ec8SPaulo Alcantara 	ulen = strlen(ctx->UNC);
53249024ec8SPaulo Alcantara 	plen = ctx->prepath ? strlen(ctx->prepath) + 1 : 0;
53349024ec8SPaulo Alcantara 
53449024ec8SPaulo Alcantara 	s = kmalloc(ulen + plen + 1, GFP_KERNEL);
53549024ec8SPaulo Alcantara 	if (!s)
53649024ec8SPaulo Alcantara 		return ERR_PTR(-ENOMEM);
53749024ec8SPaulo Alcantara 	memcpy(s, ctx->UNC, ulen);
53849024ec8SPaulo Alcantara 	if (plen) {
53949024ec8SPaulo Alcantara 		s[ulen] = dirsep;
54049024ec8SPaulo Alcantara 		memcpy(s + ulen + 1, ctx->prepath, plen);
54149024ec8SPaulo Alcantara 	}
54249024ec8SPaulo Alcantara 	s[ulen + plen] = '\0';
54349024ec8SPaulo Alcantara 	convert_delimiter(s, dirsep);
54449024ec8SPaulo Alcantara 	return s;
54538c8a9a5SSteve French }
54638c8a9a5SSteve French 
54738c8a9a5SSteve French /*
54838c8a9a5SSteve French  * Parse a devname into substrings and populate the ctx->UNC and ctx->prepath
54938c8a9a5SSteve French  * fields with the result. Returns 0 on success and an error otherwise
55038c8a9a5SSteve French  * (e.g. ENOMEM or EINVAL)
55138c8a9a5SSteve French  */
55238c8a9a5SSteve French int
smb3_parse_devname(const char * devname,struct smb3_fs_context * ctx)55338c8a9a5SSteve French smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx)
55438c8a9a5SSteve French {
55538c8a9a5SSteve French 	char *pos;
55638c8a9a5SSteve French 	const char *delims = "/\\";
55738c8a9a5SSteve French 	size_t len;
55849024ec8SPaulo Alcantara 	int rc;
55938c8a9a5SSteve French 
56038c8a9a5SSteve French 	if (unlikely(!devname || !*devname)) {
56138c8a9a5SSteve French 		cifs_dbg(VFS, "Device name not specified\n");
56238c8a9a5SSteve French 		return -EINVAL;
56338c8a9a5SSteve French 	}
56438c8a9a5SSteve French 
56538c8a9a5SSteve French 	/* make sure we have a valid UNC double delimiter prefix */
56638c8a9a5SSteve French 	len = strspn(devname, delims);
56738c8a9a5SSteve French 	if (len != 2)
56838c8a9a5SSteve French 		return -EINVAL;
56938c8a9a5SSteve French 
57038c8a9a5SSteve French 	/* find delimiter between host and sharename */
57138c8a9a5SSteve French 	pos = strpbrk(devname + 2, delims);
57238c8a9a5SSteve French 	if (!pos)
57338c8a9a5SSteve French 		return -EINVAL;
57438c8a9a5SSteve French 
57538c8a9a5SSteve French 	/* record the server hostname */
57638c8a9a5SSteve French 	kfree(ctx->server_hostname);
57738c8a9a5SSteve French 	ctx->server_hostname = kstrndup(devname + 2, pos - devname - 2, GFP_KERNEL);
57838c8a9a5SSteve French 	if (!ctx->server_hostname)
57938c8a9a5SSteve French 		return -ENOMEM;
58038c8a9a5SSteve French 
58138c8a9a5SSteve French 	/* skip past delimiter */
58238c8a9a5SSteve French 	++pos;
58338c8a9a5SSteve French 
58438c8a9a5SSteve French 	/* now go until next delimiter or end of string */
58538c8a9a5SSteve French 	len = strcspn(pos, delims);
58649024ec8SPaulo Alcantara 	if (!len)
58749024ec8SPaulo Alcantara 		return -EINVAL;
58838c8a9a5SSteve French 
58938c8a9a5SSteve French 	/* move "pos" up to delimiter or NULL */
59038c8a9a5SSteve French 	pos += len;
59138c8a9a5SSteve French 	kfree(ctx->UNC);
59238c8a9a5SSteve French 	ctx->UNC = kstrndup(devname, pos - devname, GFP_KERNEL);
59338c8a9a5SSteve French 	if (!ctx->UNC)
59438c8a9a5SSteve French 		return -ENOMEM;
59538c8a9a5SSteve French 
59638c8a9a5SSteve French 	convert_delimiter(ctx->UNC, '\\');
59738c8a9a5SSteve French 
59838c8a9a5SSteve French 	/* skip any delimiter */
59938c8a9a5SSteve French 	if (*pos == '/' || *pos == '\\')
60038c8a9a5SSteve French 		pos++;
60138c8a9a5SSteve French 
60238c8a9a5SSteve French 	kfree(ctx->prepath);
60338c8a9a5SSteve French 	ctx->prepath = NULL;
60438c8a9a5SSteve French 
60538c8a9a5SSteve French 	/* If pos is NULL then no prepath */
60638c8a9a5SSteve French 	if (!*pos)
60738c8a9a5SSteve French 		return 0;
60838c8a9a5SSteve French 
60938c8a9a5SSteve French 	ctx->prepath = cifs_sanitize_prepath(pos, GFP_KERNEL);
61049024ec8SPaulo Alcantara 	if (IS_ERR(ctx->prepath)) {
61149024ec8SPaulo Alcantara 		rc = PTR_ERR(ctx->prepath);
61249024ec8SPaulo Alcantara 		ctx->prepath = NULL;
61349024ec8SPaulo Alcantara 		return rc;
61449024ec8SPaulo Alcantara 	}
61538c8a9a5SSteve French 
61638c8a9a5SSteve French 	return 0;
61738c8a9a5SSteve French }
61838c8a9a5SSteve French 
61938c8a9a5SSteve French static void smb3_fs_context_free(struct fs_context *fc);
62038c8a9a5SSteve French static int smb3_fs_context_parse_param(struct fs_context *fc,
62138c8a9a5SSteve French 				       struct fs_parameter *param);
62238c8a9a5SSteve French static int smb3_fs_context_parse_monolithic(struct fs_context *fc,
62338c8a9a5SSteve French 					    void *data);
62438c8a9a5SSteve French static int smb3_get_tree(struct fs_context *fc);
62538c8a9a5SSteve French static int smb3_reconfigure(struct fs_context *fc);
62638c8a9a5SSteve French 
62738c8a9a5SSteve French static const struct fs_context_operations smb3_fs_context_ops = {
62838c8a9a5SSteve French 	.free			= smb3_fs_context_free,
62938c8a9a5SSteve French 	.parse_param		= smb3_fs_context_parse_param,
63038c8a9a5SSteve French 	.parse_monolithic	= smb3_fs_context_parse_monolithic,
63138c8a9a5SSteve French 	.get_tree		= smb3_get_tree,
63238c8a9a5SSteve French 	.reconfigure		= smb3_reconfigure,
63338c8a9a5SSteve French };
63438c8a9a5SSteve French 
63538c8a9a5SSteve French /*
63638c8a9a5SSteve French  * Parse a monolithic block of data from sys_mount().
63738c8a9a5SSteve French  * smb3_fs_context_parse_monolithic - Parse key[=val][,key[=val]]* mount data
63838c8a9a5SSteve French  * @ctx: The superblock configuration to fill in.
63938c8a9a5SSteve French  * @data: The data to parse
64038c8a9a5SSteve French  *
64138c8a9a5SSteve French  * Parse a blob of data that's in key[=val][,key[=val]]* form.  This can be
64238c8a9a5SSteve French  * called from the ->monolithic_mount_data() fs_context operation.
64338c8a9a5SSteve French  *
64438c8a9a5SSteve French  * Returns 0 on success or the error returned by the ->parse_option() fs_context
64538c8a9a5SSteve French  * operation on failure.
64638c8a9a5SSteve French  */
smb3_fs_context_parse_monolithic(struct fs_context * fc,void * data)64738c8a9a5SSteve French static int smb3_fs_context_parse_monolithic(struct fs_context *fc,
64838c8a9a5SSteve French 					   void *data)
64938c8a9a5SSteve French {
65038c8a9a5SSteve French 	char *options = data, *key;
65138c8a9a5SSteve French 	int ret = 0;
65238c8a9a5SSteve French 
65338c8a9a5SSteve French 	if (!options)
65438c8a9a5SSteve French 		return 0;
65538c8a9a5SSteve French 
65638c8a9a5SSteve French 	ret = security_sb_eat_lsm_opts(options, &fc->security);
65738c8a9a5SSteve French 	if (ret)
65838c8a9a5SSteve French 		return ret;
65938c8a9a5SSteve French 
66038c8a9a5SSteve French 	/* BB Need to add support for sep= here TBD */
66138c8a9a5SSteve French 	while ((key = strsep(&options, ",")) != NULL) {
66238c8a9a5SSteve French 		size_t len;
66338c8a9a5SSteve French 		char *value;
66438c8a9a5SSteve French 
66538c8a9a5SSteve French 		if (*key == 0)
66638c8a9a5SSteve French 			break;
66738c8a9a5SSteve French 
66838c8a9a5SSteve French 		/* Check if following character is the deliminator If yes,
66938c8a9a5SSteve French 		 * we have encountered a double deliminator reset the NULL
67038c8a9a5SSteve French 		 * character to the deliminator
67138c8a9a5SSteve French 		 */
67238c8a9a5SSteve French 		while (options && options[0] == ',') {
67338c8a9a5SSteve French 			len = strlen(key);
67438c8a9a5SSteve French 			strcpy(key + len, options);
67538c8a9a5SSteve French 			options = strchr(options, ',');
67638c8a9a5SSteve French 			if (options)
67738c8a9a5SSteve French 				*options++ = 0;
67838c8a9a5SSteve French 		}
67938c8a9a5SSteve French 
68038c8a9a5SSteve French 
68138c8a9a5SSteve French 		len = 0;
68238c8a9a5SSteve French 		value = strchr(key, '=');
68338c8a9a5SSteve French 		if (value) {
68438c8a9a5SSteve French 			if (value == key)
68538c8a9a5SSteve French 				continue;
68638c8a9a5SSteve French 			*value++ = 0;
68738c8a9a5SSteve French 			len = strlen(value);
68838c8a9a5SSteve French 		}
68938c8a9a5SSteve French 
69038c8a9a5SSteve French 		ret = vfs_parse_fs_string(fc, key, value, len);
69138c8a9a5SSteve French 		if (ret < 0)
69238c8a9a5SSteve French 			break;
69338c8a9a5SSteve French 	}
69438c8a9a5SSteve French 
69538c8a9a5SSteve French 	return ret;
69638c8a9a5SSteve French }
69738c8a9a5SSteve French 
69838c8a9a5SSteve French /*
69938c8a9a5SSteve French  * Validate the preparsed information in the config.
70038c8a9a5SSteve French  */
smb3_fs_context_validate(struct fs_context * fc)70138c8a9a5SSteve French static int smb3_fs_context_validate(struct fs_context *fc)
70238c8a9a5SSteve French {
70338c8a9a5SSteve French 	struct smb3_fs_context *ctx = smb3_fc2context(fc);
70438c8a9a5SSteve French 
70538c8a9a5SSteve French 	if (ctx->rdma && ctx->vals->protocol_id < SMB30_PROT_ID) {
70638c8a9a5SSteve French 		cifs_errorf(fc, "SMB Direct requires Version >=3.0\n");
70738c8a9a5SSteve French 		return -EOPNOTSUPP;
70838c8a9a5SSteve French 	}
70938c8a9a5SSteve French 
71038c8a9a5SSteve French #ifndef CONFIG_KEYS
71138c8a9a5SSteve French 	/* Muliuser mounts require CONFIG_KEYS support */
71238c8a9a5SSteve French 	if (ctx->multiuser) {
71338c8a9a5SSteve French 		cifs_errorf(fc, "Multiuser mounts require kernels with CONFIG_KEYS enabled\n");
71438c8a9a5SSteve French 		return -1;
71538c8a9a5SSteve French 	}
71638c8a9a5SSteve French #endif
71738c8a9a5SSteve French 
71838c8a9a5SSteve French 	if (ctx->got_version == false)
71938c8a9a5SSteve French 		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");
72038c8a9a5SSteve French 
72138c8a9a5SSteve French 
72238c8a9a5SSteve French 	if (!ctx->UNC) {
72338c8a9a5SSteve French 		cifs_errorf(fc, "CIFS mount error: No usable UNC path provided in device string!\n");
72438c8a9a5SSteve French 		return -1;
72538c8a9a5SSteve French 	}
72638c8a9a5SSteve French 
72738c8a9a5SSteve French 	/* make sure UNC has a share name */
72838c8a9a5SSteve French 	if (strlen(ctx->UNC) < 3 || !strchr(ctx->UNC + 3, '\\')) {
72938c8a9a5SSteve French 		cifs_errorf(fc, "Malformed UNC. Unable to find share name.\n");
73038c8a9a5SSteve French 		return -ENOENT;
73138c8a9a5SSteve French 	}
73238c8a9a5SSteve French 
73338c8a9a5SSteve French 	if (!ctx->got_ip) {
73438c8a9a5SSteve French 		int len;
73538c8a9a5SSteve French 		const char *slash;
73638c8a9a5SSteve French 
73738c8a9a5SSteve French 		/* No ip= option specified? Try to get it from UNC */
73838c8a9a5SSteve French 		/* Use the address part of the UNC. */
73938c8a9a5SSteve French 		slash = strchr(&ctx->UNC[2], '\\');
74038c8a9a5SSteve French 		len = slash - &ctx->UNC[2];
74138c8a9a5SSteve French 		if (!cifs_convert_address((struct sockaddr *)&ctx->dstaddr,
74238c8a9a5SSteve French 					  &ctx->UNC[2], len)) {
74338c8a9a5SSteve French 			pr_err("Unable to determine destination address\n");
74438c8a9a5SSteve French 			return -EHOSTUNREACH;
74538c8a9a5SSteve French 		}
74638c8a9a5SSteve French 	}
74738c8a9a5SSteve French 
74838c8a9a5SSteve French 	/* set the port that we got earlier */
74938c8a9a5SSteve French 	cifs_set_port((struct sockaddr *)&ctx->dstaddr, ctx->port);
75038c8a9a5SSteve French 
751fc1860a1STakayuki Nagata 	if (ctx->uid_specified && !ctx->forceuid_specified) {
752fc1860a1STakayuki Nagata 		ctx->override_uid = 1;
753fc1860a1STakayuki Nagata 		pr_notice("enabling forceuid mount option implicitly because uid= option is specified\n");
754fc1860a1STakayuki Nagata 	}
755fc1860a1STakayuki Nagata 
756fc1860a1STakayuki Nagata 	if (ctx->gid_specified && !ctx->forcegid_specified) {
757fc1860a1STakayuki Nagata 		ctx->override_gid = 1;
758fc1860a1STakayuki Nagata 		pr_notice("enabling forcegid mount option implicitly because gid= option is specified\n");
759fc1860a1STakayuki Nagata 	}
760fc1860a1STakayuki Nagata 
76138c8a9a5SSteve French 	if (ctx->override_uid && !ctx->uid_specified) {
76238c8a9a5SSteve French 		ctx->override_uid = 0;
76338c8a9a5SSteve French 		pr_notice("ignoring forceuid mount option specified with no uid= option\n");
76438c8a9a5SSteve French 	}
76538c8a9a5SSteve French 
76638c8a9a5SSteve French 	if (ctx->override_gid && !ctx->gid_specified) {
76738c8a9a5SSteve French 		ctx->override_gid = 0;
76838c8a9a5SSteve French 		pr_notice("ignoring forcegid mount option specified with no gid= option\n");
76938c8a9a5SSteve French 	}
77038c8a9a5SSteve French 
77138c8a9a5SSteve French 	return 0;
77238c8a9a5SSteve French }
77338c8a9a5SSteve French 
smb3_get_tree_common(struct fs_context * fc)77438c8a9a5SSteve French static int smb3_get_tree_common(struct fs_context *fc)
77538c8a9a5SSteve French {
77638c8a9a5SSteve French 	struct smb3_fs_context *ctx = smb3_fc2context(fc);
77738c8a9a5SSteve French 	struct dentry *root;
77838c8a9a5SSteve French 	int rc = 0;
77938c8a9a5SSteve French 
78038c8a9a5SSteve French 	root = cifs_smb3_do_mount(fc->fs_type, 0, ctx);
78138c8a9a5SSteve French 	if (IS_ERR(root))
78238c8a9a5SSteve French 		return PTR_ERR(root);
78338c8a9a5SSteve French 
78438c8a9a5SSteve French 	fc->root = root;
78538c8a9a5SSteve French 
78638c8a9a5SSteve French 	return rc;
78738c8a9a5SSteve French }
78838c8a9a5SSteve French 
78938c8a9a5SSteve French /*
79038c8a9a5SSteve French  * Create an SMB3 superblock from the parameters passed.
79138c8a9a5SSteve French  */
smb3_get_tree(struct fs_context * fc)79238c8a9a5SSteve French static int smb3_get_tree(struct fs_context *fc)
79338c8a9a5SSteve French {
79438c8a9a5SSteve French 	int err = smb3_fs_context_validate(fc);
79538c8a9a5SSteve French 	int ret;
79638c8a9a5SSteve French 
79738c8a9a5SSteve French 	if (err)
79838c8a9a5SSteve French 		return err;
799ba55f8a9SPaulo Alcantara 	cifs_mount_lock();
80038c8a9a5SSteve French 	ret = smb3_get_tree_common(fc);
801ba55f8a9SPaulo Alcantara 	cifs_mount_unlock();
80238c8a9a5SSteve French 	return ret;
80338c8a9a5SSteve French }
80438c8a9a5SSteve French 
smb3_fs_context_free(struct fs_context * fc)80538c8a9a5SSteve French static void smb3_fs_context_free(struct fs_context *fc)
80638c8a9a5SSteve French {
80738c8a9a5SSteve French 	struct smb3_fs_context *ctx = smb3_fc2context(fc);
80838c8a9a5SSteve French 
80938c8a9a5SSteve French 	smb3_cleanup_fs_context(ctx);
81038c8a9a5SSteve French }
81138c8a9a5SSteve French 
81238c8a9a5SSteve French /*
81338c8a9a5SSteve French  * Compare the old and new proposed context during reconfigure
81438c8a9a5SSteve French  * and check if the changes are compatible.
81538c8a9a5SSteve French  */
smb3_verify_reconfigure_ctx(struct fs_context * fc,struct smb3_fs_context * new_ctx,struct smb3_fs_context * old_ctx,bool need_recon)81638c8a9a5SSteve French static int smb3_verify_reconfigure_ctx(struct fs_context *fc,
81738c8a9a5SSteve French 				       struct smb3_fs_context *new_ctx,
8187e8cffa4SSteve French 				       struct smb3_fs_context *old_ctx, bool need_recon)
81938c8a9a5SSteve French {
82038c8a9a5SSteve French 	if (new_ctx->posix_paths != old_ctx->posix_paths) {
82138c8a9a5SSteve French 		cifs_errorf(fc, "can not change posixpaths during remount\n");
82238c8a9a5SSteve French 		return -EINVAL;
82338c8a9a5SSteve French 	}
82438c8a9a5SSteve French 	if (new_ctx->sectype != old_ctx->sectype) {
82538c8a9a5SSteve French 		cifs_errorf(fc, "can not change sec during remount\n");
82638c8a9a5SSteve French 		return -EINVAL;
82738c8a9a5SSteve French 	}
82838c8a9a5SSteve French 	if (new_ctx->multiuser != old_ctx->multiuser) {
82938c8a9a5SSteve French 		cifs_errorf(fc, "can not change multiuser during remount\n");
83038c8a9a5SSteve French 		return -EINVAL;
83138c8a9a5SSteve French 	}
83238c8a9a5SSteve French 	if (new_ctx->UNC &&
83338c8a9a5SSteve French 	    (!old_ctx->UNC || strcmp(new_ctx->UNC, old_ctx->UNC))) {
83438c8a9a5SSteve French 		cifs_errorf(fc, "can not change UNC during remount\n");
83538c8a9a5SSteve French 		return -EINVAL;
83638c8a9a5SSteve French 	}
83738c8a9a5SSteve French 	if (new_ctx->username &&
83838c8a9a5SSteve French 	    (!old_ctx->username || strcmp(new_ctx->username, old_ctx->username))) {
83938c8a9a5SSteve French 		cifs_errorf(fc, "can not change username during remount\n");
84038c8a9a5SSteve French 		return -EINVAL;
84138c8a9a5SSteve French 	}
84238c8a9a5SSteve French 	if (new_ctx->password &&
84338c8a9a5SSteve French 	    (!old_ctx->password || strcmp(new_ctx->password, old_ctx->password))) {
8447e8cffa4SSteve French 		if (need_recon == false) {
8457e8cffa4SSteve French 			cifs_errorf(fc,
8467e8cffa4SSteve French 				    "can not change password of active session during remount\n");
84738c8a9a5SSteve French 			return -EINVAL;
8487e8cffa4SSteve French 		} else if (old_ctx->sectype == Kerberos) {
8497e8cffa4SSteve French 			cifs_errorf(fc,
8507e8cffa4SSteve French 				    "can not change password for Kerberos via remount\n");
8517e8cffa4SSteve French 			return -EINVAL;
8527e8cffa4SSteve French 		}
85338c8a9a5SSteve French 	}
85438c8a9a5SSteve French 	if (new_ctx->domainname &&
85538c8a9a5SSteve French 	    (!old_ctx->domainname || strcmp(new_ctx->domainname, old_ctx->domainname))) {
85638c8a9a5SSteve French 		cifs_errorf(fc, "can not change domainname during remount\n");
85738c8a9a5SSteve French 		return -EINVAL;
85838c8a9a5SSteve French 	}
85938c8a9a5SSteve French 	if (strcmp(new_ctx->workstation_name, old_ctx->workstation_name)) {
86038c8a9a5SSteve French 		cifs_errorf(fc, "can not change workstation_name during remount\n");
86138c8a9a5SSteve French 		return -EINVAL;
86238c8a9a5SSteve French 	}
86338c8a9a5SSteve French 	if (new_ctx->nodename &&
86438c8a9a5SSteve French 	    (!old_ctx->nodename || strcmp(new_ctx->nodename, old_ctx->nodename))) {
86538c8a9a5SSteve French 		cifs_errorf(fc, "can not change nodename during remount\n");
86638c8a9a5SSteve French 		return -EINVAL;
86738c8a9a5SSteve French 	}
86838c8a9a5SSteve French 	if (new_ctx->iocharset &&
86938c8a9a5SSteve French 	    (!old_ctx->iocharset || strcmp(new_ctx->iocharset, old_ctx->iocharset))) {
87038c8a9a5SSteve French 		cifs_errorf(fc, "can not change iocharset during remount\n");
87138c8a9a5SSteve French 		return -EINVAL;
87238c8a9a5SSteve French 	}
87338c8a9a5SSteve French 
87438c8a9a5SSteve French 	return 0;
87538c8a9a5SSteve French }
87638c8a9a5SSteve French 
87738c8a9a5SSteve French #define STEAL_STRING(cifs_sb, ctx, field)				\
87838c8a9a5SSteve French do {									\
87938c8a9a5SSteve French 	kfree(ctx->field);						\
88038c8a9a5SSteve French 	ctx->field = cifs_sb->ctx->field;				\
88138c8a9a5SSteve French 	cifs_sb->ctx->field = NULL;					\
88238c8a9a5SSteve French } while (0)
88338c8a9a5SSteve French 
88438c8a9a5SSteve French #define STEAL_STRING_SENSITIVE(cifs_sb, ctx, field)			\
88538c8a9a5SSteve French do {									\
88638c8a9a5SSteve French 	kfree_sensitive(ctx->field);					\
88738c8a9a5SSteve French 	ctx->field = cifs_sb->ctx->field;				\
88838c8a9a5SSteve French 	cifs_sb->ctx->field = NULL;					\
88938c8a9a5SSteve French } while (0)
89038c8a9a5SSteve French 
smb3_reconfigure(struct fs_context * fc)89138c8a9a5SSteve French static int smb3_reconfigure(struct fs_context *fc)
89238c8a9a5SSteve French {
89338c8a9a5SSteve French 	struct smb3_fs_context *ctx = smb3_fc2context(fc);
89438c8a9a5SSteve French 	struct dentry *root = fc->root;
89538c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb);
8967e8cffa4SSteve French 	struct cifs_ses *ses = cifs_sb_master_tcon(cifs_sb)->ses;
8977e8cffa4SSteve French 	bool need_recon = false;
89838c8a9a5SSteve French 	int rc;
89938c8a9a5SSteve French 
9007e8cffa4SSteve French 	if (ses->expired_pwd)
9017e8cffa4SSteve French 		need_recon = true;
9027e8cffa4SSteve French 
9037e8cffa4SSteve French 	rc = smb3_verify_reconfigure_ctx(fc, ctx, cifs_sb->ctx, need_recon);
90438c8a9a5SSteve French 	if (rc)
90538c8a9a5SSteve French 		return rc;
90638c8a9a5SSteve French 
90738c8a9a5SSteve French 	/*
90838c8a9a5SSteve French 	 * We can not change UNC/username/password/domainname/
90938c8a9a5SSteve French 	 * workstation_name/nodename/iocharset
91038c8a9a5SSteve French 	 * during reconnect so ignore what we have in the new context and
91138c8a9a5SSteve French 	 * just use what we already have in cifs_sb->ctx.
91238c8a9a5SSteve French 	 */
91338c8a9a5SSteve French 	STEAL_STRING(cifs_sb, ctx, UNC);
91438c8a9a5SSteve French 	STEAL_STRING(cifs_sb, ctx, source);
91538c8a9a5SSteve French 	STEAL_STRING(cifs_sb, ctx, username);
9167e8cffa4SSteve French 	if (need_recon == false)
91738c8a9a5SSteve French 		STEAL_STRING_SENSITIVE(cifs_sb, ctx, password);
9187e8cffa4SSteve French 	else  {
9197e8cffa4SSteve French 		kfree_sensitive(ses->password);
9207e8cffa4SSteve French 		ses->password = kstrdup(ctx->password, GFP_KERNEL);
92108bedfbcSSteve French 		kfree_sensitive(ses->password2);
92208bedfbcSSteve French 		ses->password2 = kstrdup(ctx->password2, GFP_KERNEL);
9237e8cffa4SSteve French 	}
92438c8a9a5SSteve French 	STEAL_STRING(cifs_sb, ctx, domainname);
92538c8a9a5SSteve French 	STEAL_STRING(cifs_sb, ctx, nodename);
92638c8a9a5SSteve French 	STEAL_STRING(cifs_sb, ctx, iocharset);
92738c8a9a5SSteve French 
92838c8a9a5SSteve French 	/* if rsize or wsize not passed in on remount, use previous values */
92938c8a9a5SSteve French 	if (ctx->rsize == 0)
93038c8a9a5SSteve French 		ctx->rsize = cifs_sb->ctx->rsize;
93138c8a9a5SSteve French 	if (ctx->wsize == 0)
93238c8a9a5SSteve French 		ctx->wsize = cifs_sb->ctx->wsize;
93338c8a9a5SSteve French 
93438c8a9a5SSteve French 
93538c8a9a5SSteve French 	smb3_cleanup_fs_context_contents(cifs_sb->ctx);
93638c8a9a5SSteve French 	rc = smb3_fs_context_dup(cifs_sb->ctx, ctx);
93738c8a9a5SSteve French 	smb3_update_mnt_flags(cifs_sb);
93838c8a9a5SSteve French #ifdef CONFIG_CIFS_DFS_UPCALL
93938c8a9a5SSteve French 	if (!rc)
94038c8a9a5SSteve French 		rc = dfs_cache_remount_fs(cifs_sb);
94138c8a9a5SSteve French #endif
94238c8a9a5SSteve French 
94338c8a9a5SSteve French 	return rc;
94438c8a9a5SSteve French }
94538c8a9a5SSteve French 
smb3_fs_context_parse_param(struct fs_context * fc,struct fs_parameter * param)94638c8a9a5SSteve French static int smb3_fs_context_parse_param(struct fs_context *fc,
94738c8a9a5SSteve French 				      struct fs_parameter *param)
94838c8a9a5SSteve French {
94938c8a9a5SSteve French 	struct fs_parse_result result;
95038c8a9a5SSteve French 	struct smb3_fs_context *ctx = smb3_fc2context(fc);
95138c8a9a5SSteve French 	int i, opt;
95238c8a9a5SSteve French 	bool is_smb3 = !strcmp(fc->fs_type->name, "smb3");
95338c8a9a5SSteve French 	bool skip_parsing = false;
95438c8a9a5SSteve French 	kuid_t uid;
95538c8a9a5SSteve French 	kgid_t gid;
95638c8a9a5SSteve French 
95738c8a9a5SSteve French 	cifs_dbg(FYI, "CIFS: parsing cifs mount option '%s'\n", param->key);
95838c8a9a5SSteve French 
95938c8a9a5SSteve French 	/*
96038c8a9a5SSteve French 	 * fs_parse can not handle string options with an empty value so
96138c8a9a5SSteve French 	 * we will need special handling of them.
96238c8a9a5SSteve French 	 */
96338c8a9a5SSteve French 	if (param->type == fs_value_is_string && param->string[0] == 0) {
96438c8a9a5SSteve French 		if (!strcmp("pass", param->key) || !strcmp("password", param->key)) {
96538c8a9a5SSteve French 			skip_parsing = true;
96638c8a9a5SSteve French 			opt = Opt_pass;
96738c8a9a5SSteve French 		} else if (!strcmp("user", param->key) || !strcmp("username", param->key)) {
96838c8a9a5SSteve French 			skip_parsing = true;
96938c8a9a5SSteve French 			opt = Opt_user;
97038c8a9a5SSteve French 		}
97138c8a9a5SSteve French 	}
97238c8a9a5SSteve French 
97338c8a9a5SSteve French 	if (!skip_parsing) {
97438c8a9a5SSteve French 		opt = fs_parse(fc, smb3_fs_parameters, param, &result);
97538c8a9a5SSteve French 		if (opt < 0)
97638c8a9a5SSteve French 			return ctx->sloppy ? 1 : opt;
97738c8a9a5SSteve French 	}
97838c8a9a5SSteve French 
97938c8a9a5SSteve French 	switch (opt) {
98038c8a9a5SSteve French 	case Opt_compress:
981e8aee4f4SEnzo Matsumiya 		ctx->compress = true;
98238c8a9a5SSteve French 		cifs_dbg(VFS,
98338c8a9a5SSteve French 			"SMB3 compression support is experimental\n");
98438c8a9a5SSteve French 		break;
98538c8a9a5SSteve French 	case Opt_nodfs:
98638c8a9a5SSteve French 		ctx->nodfs = 1;
98738c8a9a5SSteve French 		break;
98838c8a9a5SSteve French 	case Opt_hard:
98938c8a9a5SSteve French 		if (result.negated) {
99038c8a9a5SSteve French 			if (ctx->retry == 1)
99138c8a9a5SSteve French 				cifs_dbg(VFS, "conflicting hard vs. soft mount options\n");
99238c8a9a5SSteve French 			ctx->retry = 0;
99338c8a9a5SSteve French 		} else
99438c8a9a5SSteve French 			ctx->retry = 1;
99538c8a9a5SSteve French 		break;
99638c8a9a5SSteve French 	case Opt_soft:
99738c8a9a5SSteve French 		if (result.negated)
99838c8a9a5SSteve French 			ctx->retry = 1;
99938c8a9a5SSteve French 		else {
100038c8a9a5SSteve French 			if (ctx->retry == 1)
100138c8a9a5SSteve French 				cifs_dbg(VFS, "conflicting hard vs soft mount options\n");
100238c8a9a5SSteve French 			ctx->retry = 0;
100338c8a9a5SSteve French 		}
100438c8a9a5SSteve French 		break;
100538c8a9a5SSteve French 	case Opt_mapposix:
100638c8a9a5SSteve French 		if (result.negated)
100738c8a9a5SSteve French 			ctx->remap = false;
100838c8a9a5SSteve French 		else {
100938c8a9a5SSteve French 			ctx->remap = true;
101038c8a9a5SSteve French 			ctx->sfu_remap = false; /* disable SFU mapping */
101138c8a9a5SSteve French 		}
101238c8a9a5SSteve French 		break;
101338c8a9a5SSteve French 	case Opt_mapchars:
101438c8a9a5SSteve French 		if (result.negated)
101538c8a9a5SSteve French 			ctx->sfu_remap = false;
101638c8a9a5SSteve French 		else {
101738c8a9a5SSteve French 			ctx->sfu_remap = true;
101838c8a9a5SSteve French 			ctx->remap = false; /* disable SFM (mapposix) mapping */
101938c8a9a5SSteve French 		}
102038c8a9a5SSteve French 		break;
102138c8a9a5SSteve French 	case Opt_user_xattr:
102238c8a9a5SSteve French 		if (result.negated)
102338c8a9a5SSteve French 			ctx->no_xattr = 1;
102438c8a9a5SSteve French 		else
102538c8a9a5SSteve French 			ctx->no_xattr = 0;
102638c8a9a5SSteve French 		break;
102738c8a9a5SSteve French 	case Opt_forceuid:
102838c8a9a5SSteve French 		if (result.negated)
102938c8a9a5SSteve French 			ctx->override_uid = 0;
103038c8a9a5SSteve French 		else
103138c8a9a5SSteve French 			ctx->override_uid = 1;
1032fc1860a1STakayuki Nagata 		ctx->forceuid_specified = true;
103338c8a9a5SSteve French 		break;
103438c8a9a5SSteve French 	case Opt_forcegid:
103538c8a9a5SSteve French 		if (result.negated)
103638c8a9a5SSteve French 			ctx->override_gid = 0;
103738c8a9a5SSteve French 		else
103838c8a9a5SSteve French 			ctx->override_gid = 1;
1039fc1860a1STakayuki Nagata 		ctx->forcegid_specified = true;
104038c8a9a5SSteve French 		break;
104138c8a9a5SSteve French 	case Opt_perm:
104238c8a9a5SSteve French 		if (result.negated)
104338c8a9a5SSteve French 			ctx->noperm = 1;
104438c8a9a5SSteve French 		else
104538c8a9a5SSteve French 			ctx->noperm = 0;
104638c8a9a5SSteve French 		break;
104738c8a9a5SSteve French 	case Opt_dynperm:
104838c8a9a5SSteve French 		if (result.negated)
104938c8a9a5SSteve French 			ctx->dynperm = 0;
105038c8a9a5SSteve French 		else
105138c8a9a5SSteve French 			ctx->dynperm = 1;
105238c8a9a5SSteve French 		break;
105338c8a9a5SSteve French 	case Opt_sfu:
105438c8a9a5SSteve French 		if (result.negated)
105538c8a9a5SSteve French 			ctx->sfu_emul = 0;
105638c8a9a5SSteve French 		else
105738c8a9a5SSteve French 			ctx->sfu_emul = 1;
105838c8a9a5SSteve French 		break;
105938c8a9a5SSteve French 	case Opt_noblocksend:
106038c8a9a5SSteve French 		ctx->noblocksnd = 1;
106138c8a9a5SSteve French 		break;
106238c8a9a5SSteve French 	case Opt_noautotune:
106338c8a9a5SSteve French 		ctx->noautotune = 1;
106438c8a9a5SSteve French 		break;
106538c8a9a5SSteve French 	case Opt_nolease:
106638c8a9a5SSteve French 		ctx->no_lease = 1;
106738c8a9a5SSteve French 		break;
106838c8a9a5SSteve French 	case Opt_nosparse:
106938c8a9a5SSteve French 		ctx->no_sparse = 1;
107038c8a9a5SSteve French 		break;
107138c8a9a5SSteve French 	case Opt_nodelete:
107238c8a9a5SSteve French 		ctx->nodelete = 1;
107338c8a9a5SSteve French 		break;
107438c8a9a5SSteve French 	case Opt_multichannel:
107538c8a9a5SSteve French 		if (result.negated) {
107638c8a9a5SSteve French 			ctx->multichannel = false;
107738c8a9a5SSteve French 			ctx->max_channels = 1;
107838c8a9a5SSteve French 		} else {
107938c8a9a5SSteve French 			ctx->multichannel = true;
108038c8a9a5SSteve French 			/* if number of channels not specified, default to 2 */
108138c8a9a5SSteve French 			if (ctx->max_channels < 2)
108238c8a9a5SSteve French 				ctx->max_channels = 2;
108338c8a9a5SSteve French 		}
108438c8a9a5SSteve French 		break;
108538c8a9a5SSteve French 	case Opt_uid:
108638c8a9a5SSteve French 		uid = make_kuid(current_user_ns(), result.uint_32);
108738c8a9a5SSteve French 		if (!uid_valid(uid))
108838c8a9a5SSteve French 			goto cifs_parse_mount_err;
108938c8a9a5SSteve French 		ctx->linux_uid = uid;
109038c8a9a5SSteve French 		ctx->uid_specified = true;
109138c8a9a5SSteve French 		break;
109238c8a9a5SSteve French 	case Opt_cruid:
109338c8a9a5SSteve French 		uid = make_kuid(current_user_ns(), result.uint_32);
109438c8a9a5SSteve French 		if (!uid_valid(uid))
109538c8a9a5SSteve French 			goto cifs_parse_mount_err;
109638c8a9a5SSteve French 		ctx->cred_uid = uid;
109738c8a9a5SSteve French 		ctx->cruid_specified = true;
109838c8a9a5SSteve French 		break;
109938c8a9a5SSteve French 	case Opt_backupuid:
110038c8a9a5SSteve French 		uid = make_kuid(current_user_ns(), result.uint_32);
110138c8a9a5SSteve French 		if (!uid_valid(uid))
110238c8a9a5SSteve French 			goto cifs_parse_mount_err;
110338c8a9a5SSteve French 		ctx->backupuid = uid;
110438c8a9a5SSteve French 		ctx->backupuid_specified = true;
110538c8a9a5SSteve French 		break;
110638c8a9a5SSteve French 	case Opt_backupgid:
110738c8a9a5SSteve French 		gid = make_kgid(current_user_ns(), result.uint_32);
110838c8a9a5SSteve French 		if (!gid_valid(gid))
110938c8a9a5SSteve French 			goto cifs_parse_mount_err;
111038c8a9a5SSteve French 		ctx->backupgid = gid;
111138c8a9a5SSteve French 		ctx->backupgid_specified = true;
111238c8a9a5SSteve French 		break;
111338c8a9a5SSteve French 	case Opt_gid:
111438c8a9a5SSteve French 		gid = make_kgid(current_user_ns(), result.uint_32);
111538c8a9a5SSteve French 		if (!gid_valid(gid))
111638c8a9a5SSteve French 			goto cifs_parse_mount_err;
111738c8a9a5SSteve French 		ctx->linux_gid = gid;
111838c8a9a5SSteve French 		ctx->gid_specified = true;
111938c8a9a5SSteve French 		break;
112038c8a9a5SSteve French 	case Opt_port:
112138c8a9a5SSteve French 		ctx->port = result.uint_32;
112238c8a9a5SSteve French 		break;
112338c8a9a5SSteve French 	case Opt_file_mode:
112438c8a9a5SSteve French 		ctx->file_mode = result.uint_32;
112538c8a9a5SSteve French 		break;
112638c8a9a5SSteve French 	case Opt_dirmode:
112738c8a9a5SSteve French 		ctx->dir_mode = result.uint_32;
112838c8a9a5SSteve French 		break;
112938c8a9a5SSteve French 	case Opt_min_enc_offload:
113038c8a9a5SSteve French 		ctx->min_offload = result.uint_32;
113138c8a9a5SSteve French 		break;
1132b4ca2942SShyam Prasad N 	case Opt_retrans:
1133b4ca2942SShyam Prasad N 		ctx->retrans = result.uint_32;
1134b4ca2942SShyam Prasad N 		break;
113538c8a9a5SSteve French 	case Opt_blocksize:
113638c8a9a5SSteve French 		/*
113738c8a9a5SSteve French 		 * inode blocksize realistically should never need to be
113838c8a9a5SSteve French 		 * less than 16K or greater than 16M and default is 1MB.
113938c8a9a5SSteve French 		 * Note that small inode block sizes (e.g. 64K) can lead
114038c8a9a5SSteve French 		 * to very poor performance of common tools like cp and scp
114138c8a9a5SSteve French 		 */
114238c8a9a5SSteve French 		if ((result.uint_32 < CIFS_MAX_MSGSIZE) ||
114338c8a9a5SSteve French 		   (result.uint_32 > (4 * SMB3_DEFAULT_IOSIZE))) {
114438c8a9a5SSteve French 			cifs_errorf(fc, "%s: Invalid blocksize\n",
114538c8a9a5SSteve French 				__func__);
114638c8a9a5SSteve French 			goto cifs_parse_mount_err;
114738c8a9a5SSteve French 		}
114838c8a9a5SSteve French 		ctx->bsize = result.uint_32;
114938c8a9a5SSteve French 		ctx->got_bsize = true;
115038c8a9a5SSteve French 		break;
115138c8a9a5SSteve French 	case Opt_rasize:
115238c8a9a5SSteve French 		/*
115338c8a9a5SSteve French 		 * readahead size realistically should never need to be
115438c8a9a5SSteve French 		 * less than 1M (CIFS_DEFAULT_IOSIZE) or greater than 32M
115538c8a9a5SSteve French 		 * (perhaps an exception should be considered in the
115638c8a9a5SSteve French 		 * for the case of a large number of channels
115738c8a9a5SSteve French 		 * when multichannel is negotiated) since that would lead
115838c8a9a5SSteve French 		 * to plenty of parallel I/O in flight to the server.
115938c8a9a5SSteve French 		 * Note that smaller read ahead sizes would
116038c8a9a5SSteve French 		 * hurt performance of common tools like cp and scp
116138c8a9a5SSteve French 		 * which often trigger sequential i/o with read ahead
116238c8a9a5SSteve French 		 */
116338c8a9a5SSteve French 		if ((result.uint_32 > (8 * SMB3_DEFAULT_IOSIZE)) ||
116438c8a9a5SSteve French 		    (result.uint_32 < CIFS_DEFAULT_IOSIZE)) {
116538c8a9a5SSteve French 			cifs_errorf(fc, "%s: Invalid rasize %d vs. %d\n",
116638c8a9a5SSteve French 				__func__, result.uint_32, SMB3_DEFAULT_IOSIZE);
116738c8a9a5SSteve French 			goto cifs_parse_mount_err;
116838c8a9a5SSteve French 		}
116938c8a9a5SSteve French 		ctx->rasize = result.uint_32;
117038c8a9a5SSteve French 		break;
117138c8a9a5SSteve French 	case Opt_rsize:
117238c8a9a5SSteve French 		ctx->rsize = result.uint_32;
117338c8a9a5SSteve French 		ctx->got_rsize = true;
117438c8a9a5SSteve French 		break;
117538c8a9a5SSteve French 	case Opt_wsize:
117638c8a9a5SSteve French 		ctx->wsize = result.uint_32;
117738c8a9a5SSteve French 		ctx->got_wsize = true;
11784145ccffSSteve French 		if (ctx->wsize % PAGE_SIZE != 0) {
11794145ccffSSteve French 			ctx->wsize = round_down(ctx->wsize, PAGE_SIZE);
11804145ccffSSteve French 			if (ctx->wsize == 0) {
11814145ccffSSteve French 				ctx->wsize = PAGE_SIZE;
11824145ccffSSteve French 				cifs_dbg(VFS, "wsize too small, reset to minimum %ld\n", PAGE_SIZE);
11834145ccffSSteve French 			} else {
11844145ccffSSteve French 				cifs_dbg(VFS,
11854145ccffSSteve French 					 "wsize rounded down to %d to multiple of PAGE_SIZE %ld\n",
11864145ccffSSteve French 					 ctx->wsize, PAGE_SIZE);
11874145ccffSSteve French 			}
11884145ccffSSteve French 		}
118938c8a9a5SSteve French 		break;
119038c8a9a5SSteve French 	case Opt_acregmax:
119138c8a9a5SSteve French 		ctx->acregmax = HZ * result.uint_32;
119238c8a9a5SSteve French 		if (ctx->acregmax > CIFS_MAX_ACTIMEO) {
119338c8a9a5SSteve French 			cifs_errorf(fc, "acregmax too large\n");
119438c8a9a5SSteve French 			goto cifs_parse_mount_err;
119538c8a9a5SSteve French 		}
119638c8a9a5SSteve French 		break;
119738c8a9a5SSteve French 	case Opt_acdirmax:
119838c8a9a5SSteve French 		ctx->acdirmax = HZ * result.uint_32;
119938c8a9a5SSteve French 		if (ctx->acdirmax > CIFS_MAX_ACTIMEO) {
120038c8a9a5SSteve French 			cifs_errorf(fc, "acdirmax too large\n");
120138c8a9a5SSteve French 			goto cifs_parse_mount_err;
120238c8a9a5SSteve French 		}
120338c8a9a5SSteve French 		break;
120438c8a9a5SSteve French 	case Opt_actimeo:
120538c8a9a5SSteve French 		if (HZ * result.uint_32 > CIFS_MAX_ACTIMEO) {
120638c8a9a5SSteve French 			cifs_errorf(fc, "timeout too large\n");
120738c8a9a5SSteve French 			goto cifs_parse_mount_err;
120838c8a9a5SSteve French 		}
120938c8a9a5SSteve French 		if ((ctx->acdirmax != CIFS_DEF_ACTIMEO) ||
121038c8a9a5SSteve French 		    (ctx->acregmax != CIFS_DEF_ACTIMEO)) {
121138c8a9a5SSteve French 			cifs_errorf(fc, "actimeo ignored since acregmax or acdirmax specified\n");
121238c8a9a5SSteve French 			break;
121338c8a9a5SSteve French 		}
121438c8a9a5SSteve French 		ctx->acdirmax = ctx->acregmax = HZ * result.uint_32;
121538c8a9a5SSteve French 		break;
121638c8a9a5SSteve French 	case Opt_closetimeo:
121738c8a9a5SSteve French 		ctx->closetimeo = HZ * result.uint_32;
121838c8a9a5SSteve French 		if (ctx->closetimeo > SMB3_MAX_DCLOSETIMEO) {
121938c8a9a5SSteve French 			cifs_errorf(fc, "closetimeo too large\n");
122038c8a9a5SSteve French 			goto cifs_parse_mount_err;
122138c8a9a5SSteve French 		}
122238c8a9a5SSteve French 		break;
122338c8a9a5SSteve French 	case Opt_echo_interval:
122438c8a9a5SSteve French 		ctx->echo_interval = result.uint_32;
122538c8a9a5SSteve French 		break;
122638c8a9a5SSteve French 	case Opt_snapshot:
122738c8a9a5SSteve French 		ctx->snapshot_time = result.uint_64;
122838c8a9a5SSteve French 		break;
122938c8a9a5SSteve French 	case Opt_max_credits:
123038c8a9a5SSteve French 		if (result.uint_32 < 20 || result.uint_32 > 60000) {
123138c8a9a5SSteve French 			cifs_errorf(fc, "%s: Invalid max_credits value\n",
123238c8a9a5SSteve French 				 __func__);
123338c8a9a5SSteve French 			goto cifs_parse_mount_err;
123438c8a9a5SSteve French 		}
123538c8a9a5SSteve French 		ctx->max_credits = result.uint_32;
123638c8a9a5SSteve French 		break;
123738c8a9a5SSteve French 	case Opt_max_channels:
123838c8a9a5SSteve French 		if (result.uint_32 < 1 || result.uint_32 > CIFS_MAX_CHANNELS) {
123938c8a9a5SSteve French 			cifs_errorf(fc, "%s: Invalid max_channels value, needs to be 1-%d\n",
124038c8a9a5SSteve French 				 __func__, CIFS_MAX_CHANNELS);
124138c8a9a5SSteve French 			goto cifs_parse_mount_err;
124238c8a9a5SSteve French 		}
124338c8a9a5SSteve French 		ctx->max_channels = result.uint_32;
124438c8a9a5SSteve French 		/* If more than one channel requested ... they want multichan */
124538c8a9a5SSteve French 		if (result.uint_32 > 1)
124638c8a9a5SSteve French 			ctx->multichannel = true;
124738c8a9a5SSteve French 		break;
12486a50d71dSSteve French 	case Opt_max_cached_dirs:
12496a50d71dSSteve French 		if (result.uint_32 < 1) {
12506a50d71dSSteve French 			cifs_errorf(fc, "%s: Invalid max_cached_dirs, needs to be 1 or more\n",
12516a50d71dSSteve French 				    __func__);
12526a50d71dSSteve French 			goto cifs_parse_mount_err;
12536a50d71dSSteve French 		}
12546a50d71dSSteve French 		ctx->max_cached_dirs = result.uint_32;
12556a50d71dSSteve French 		break;
125638c8a9a5SSteve French 	case Opt_handletimeout:
125738c8a9a5SSteve French 		ctx->handle_timeout = result.uint_32;
125838c8a9a5SSteve French 		if (ctx->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) {
125938c8a9a5SSteve French 			cifs_errorf(fc, "Invalid handle cache timeout, longer than 16 minutes\n");
126038c8a9a5SSteve French 			goto cifs_parse_mount_err;
126138c8a9a5SSteve French 		}
126238c8a9a5SSteve French 		break;
126338c8a9a5SSteve French 	case Opt_source:
126438c8a9a5SSteve French 		kfree(ctx->UNC);
126538c8a9a5SSteve French 		ctx->UNC = NULL;
126638c8a9a5SSteve French 		switch (smb3_parse_devname(param->string, ctx)) {
126738c8a9a5SSteve French 		case 0:
126838c8a9a5SSteve French 			break;
126938c8a9a5SSteve French 		case -ENOMEM:
127038c8a9a5SSteve French 			cifs_errorf(fc, "Unable to allocate memory for devname\n");
127138c8a9a5SSteve French 			goto cifs_parse_mount_err;
127238c8a9a5SSteve French 		case -EINVAL:
127338c8a9a5SSteve French 			cifs_errorf(fc, "Malformed UNC in devname\n");
127438c8a9a5SSteve French 			goto cifs_parse_mount_err;
127538c8a9a5SSteve French 		default:
127638c8a9a5SSteve French 			cifs_errorf(fc, "Unknown error parsing devname\n");
127738c8a9a5SSteve French 			goto cifs_parse_mount_err;
127838c8a9a5SSteve French 		}
127949024ec8SPaulo Alcantara 		ctx->source = smb3_fs_context_fullpath(ctx, '/');
128049024ec8SPaulo Alcantara 		if (IS_ERR(ctx->source)) {
128149024ec8SPaulo Alcantara 			ctx->source = NULL;
128238c8a9a5SSteve French 			cifs_errorf(fc, "OOM when copying UNC string\n");
128338c8a9a5SSteve French 			goto cifs_parse_mount_err;
128438c8a9a5SSteve French 		}
128549024ec8SPaulo Alcantara 		fc->source = kstrdup(ctx->source, GFP_KERNEL);
128638c8a9a5SSteve French 		if (fc->source == NULL) {
128738c8a9a5SSteve French 			cifs_errorf(fc, "OOM when copying UNC string\n");
128838c8a9a5SSteve French 			goto cifs_parse_mount_err;
128938c8a9a5SSteve French 		}
129038c8a9a5SSteve French 		break;
129138c8a9a5SSteve French 	case Opt_user:
129238c8a9a5SSteve French 		kfree(ctx->username);
129338c8a9a5SSteve French 		ctx->username = NULL;
1294270d73e6SScott Mayhew 		if (ctx->nullauth)
1295270d73e6SScott Mayhew 			break;
129638c8a9a5SSteve French 		if (strlen(param->string) == 0) {
129738c8a9a5SSteve French 			/* null user, ie. anonymous authentication */
129838c8a9a5SSteve French 			ctx->nullauth = 1;
129938c8a9a5SSteve French 			break;
130038c8a9a5SSteve French 		}
130138c8a9a5SSteve French 
130238c8a9a5SSteve French 		if (strnlen(param->string, CIFS_MAX_USERNAME_LEN) >
130338c8a9a5SSteve French 		    CIFS_MAX_USERNAME_LEN) {
130438c8a9a5SSteve French 			pr_warn("username too long\n");
130538c8a9a5SSteve French 			goto cifs_parse_mount_err;
130638c8a9a5SSteve French 		}
130738c8a9a5SSteve French 		ctx->username = kstrdup(param->string, GFP_KERNEL);
130838c8a9a5SSteve French 		if (ctx->username == NULL) {
130938c8a9a5SSteve French 			cifs_errorf(fc, "OOM when copying username string\n");
131038c8a9a5SSteve French 			goto cifs_parse_mount_err;
131138c8a9a5SSteve French 		}
131238c8a9a5SSteve French 		break;
131338c8a9a5SSteve French 	case Opt_pass:
131438c8a9a5SSteve French 		kfree_sensitive(ctx->password);
131538c8a9a5SSteve French 		ctx->password = NULL;
131638c8a9a5SSteve French 		if (strlen(param->string) == 0)
131738c8a9a5SSteve French 			break;
131838c8a9a5SSteve French 
131938c8a9a5SSteve French 		ctx->password = kstrdup(param->string, GFP_KERNEL);
132038c8a9a5SSteve French 		if (ctx->password == NULL) {
132138c8a9a5SSteve French 			cifs_errorf(fc, "OOM when copying password string\n");
132238c8a9a5SSteve French 			goto cifs_parse_mount_err;
132338c8a9a5SSteve French 		}
132438c8a9a5SSteve French 		break;
132508bedfbcSSteve French 	case Opt_pass2:
132608bedfbcSSteve French 		kfree_sensitive(ctx->password2);
132708bedfbcSSteve French 		ctx->password2 = NULL;
132808bedfbcSSteve French 		if (strlen(param->string) == 0)
132908bedfbcSSteve French 			break;
133008bedfbcSSteve French 
133108bedfbcSSteve French 		ctx->password2 = kstrdup(param->string, GFP_KERNEL);
133208bedfbcSSteve French 		if (ctx->password2 == NULL) {
133308bedfbcSSteve French 			cifs_errorf(fc, "OOM when copying password2 string\n");
133408bedfbcSSteve French 			goto cifs_parse_mount_err;
133508bedfbcSSteve French 		}
133608bedfbcSSteve French 		break;
133738c8a9a5SSteve French 	case Opt_ip:
133838c8a9a5SSteve French 		if (strlen(param->string) == 0) {
133938c8a9a5SSteve French 			ctx->got_ip = false;
134038c8a9a5SSteve French 			break;
134138c8a9a5SSteve French 		}
134238c8a9a5SSteve French 		if (!cifs_convert_address((struct sockaddr *)&ctx->dstaddr,
134338c8a9a5SSteve French 					  param->string,
134438c8a9a5SSteve French 					  strlen(param->string))) {
134538c8a9a5SSteve French 			pr_err("bad ip= option (%s)\n", param->string);
134638c8a9a5SSteve French 			goto cifs_parse_mount_err;
134738c8a9a5SSteve French 		}
134838c8a9a5SSteve French 		ctx->got_ip = true;
134938c8a9a5SSteve French 		break;
135038c8a9a5SSteve French 	case Opt_domain:
135138c8a9a5SSteve French 		if (strnlen(param->string, CIFS_MAX_DOMAINNAME_LEN)
135238c8a9a5SSteve French 				== CIFS_MAX_DOMAINNAME_LEN) {
135338c8a9a5SSteve French 			pr_warn("domain name too long\n");
135438c8a9a5SSteve French 			goto cifs_parse_mount_err;
135538c8a9a5SSteve French 		}
135638c8a9a5SSteve French 
135738c8a9a5SSteve French 		kfree(ctx->domainname);
135838c8a9a5SSteve French 		ctx->domainname = kstrdup(param->string, GFP_KERNEL);
135938c8a9a5SSteve French 		if (ctx->domainname == NULL) {
136038c8a9a5SSteve French 			cifs_errorf(fc, "OOM when copying domainname string\n");
136138c8a9a5SSteve French 			goto cifs_parse_mount_err;
136238c8a9a5SSteve French 		}
136338c8a9a5SSteve French 		cifs_dbg(FYI, "Domain name set\n");
136438c8a9a5SSteve French 		break;
136538c8a9a5SSteve French 	case Opt_srcaddr:
136638c8a9a5SSteve French 		if (!cifs_convert_address(
136738c8a9a5SSteve French 				(struct sockaddr *)&ctx->srcaddr,
136838c8a9a5SSteve French 				param->string, strlen(param->string))) {
136938c8a9a5SSteve French 			pr_warn("Could not parse srcaddr: %s\n",
137038c8a9a5SSteve French 				param->string);
137138c8a9a5SSteve French 			goto cifs_parse_mount_err;
137238c8a9a5SSteve French 		}
137338c8a9a5SSteve French 		break;
137438c8a9a5SSteve French 	case Opt_iocharset:
137538c8a9a5SSteve French 		if (strnlen(param->string, 1024) >= 65) {
137638c8a9a5SSteve French 			pr_warn("iocharset name too long\n");
137738c8a9a5SSteve French 			goto cifs_parse_mount_err;
137838c8a9a5SSteve French 		}
137938c8a9a5SSteve French 
138038c8a9a5SSteve French 		if (strncasecmp(param->string, "default", 7) != 0) {
138138c8a9a5SSteve French 			kfree(ctx->iocharset);
138238c8a9a5SSteve French 			ctx->iocharset = kstrdup(param->string, GFP_KERNEL);
138338c8a9a5SSteve French 			if (ctx->iocharset == NULL) {
138438c8a9a5SSteve French 				cifs_errorf(fc, "OOM when copying iocharset string\n");
138538c8a9a5SSteve French 				goto cifs_parse_mount_err;
138638c8a9a5SSteve French 			}
138738c8a9a5SSteve French 		}
138838c8a9a5SSteve French 		/* if iocharset not set then load_nls_default
138938c8a9a5SSteve French 		 * is used by caller
139038c8a9a5SSteve French 		 */
139138c8a9a5SSteve French 		cifs_dbg(FYI, "iocharset set to %s\n", ctx->iocharset);
139238c8a9a5SSteve French 		break;
139338c8a9a5SSteve French 	case Opt_netbiosname:
139438c8a9a5SSteve French 		memset(ctx->source_rfc1001_name, 0x20,
139538c8a9a5SSteve French 			RFC1001_NAME_LEN);
139638c8a9a5SSteve French 		/*
139738c8a9a5SSteve French 		 * FIXME: are there cases in which a comma can
139838c8a9a5SSteve French 		 * be valid in workstation netbios name (and
139938c8a9a5SSteve French 		 * need special handling)?
140038c8a9a5SSteve French 		 */
140138c8a9a5SSteve French 		for (i = 0; i < RFC1001_NAME_LEN; i++) {
140238c8a9a5SSteve French 			/* don't ucase netbiosname for user */
140338c8a9a5SSteve French 			if (param->string[i] == 0)
140438c8a9a5SSteve French 				break;
140538c8a9a5SSteve French 			ctx->source_rfc1001_name[i] = param->string[i];
140638c8a9a5SSteve French 		}
140738c8a9a5SSteve French 		/* The string has 16th byte zero still from
140838c8a9a5SSteve French 		 * set at top of the function
140938c8a9a5SSteve French 		 */
141038c8a9a5SSteve French 		if (i == RFC1001_NAME_LEN && param->string[i] != 0)
141138c8a9a5SSteve French 			pr_warn("netbiosname longer than 15 truncated\n");
141238c8a9a5SSteve French 		break;
141338c8a9a5SSteve French 	case Opt_servern:
141438c8a9a5SSteve French 		/* last byte, type, is 0x20 for servr type */
141538c8a9a5SSteve French 		memset(ctx->target_rfc1001_name, 0x20,
141638c8a9a5SSteve French 			RFC1001_NAME_LEN_WITH_NULL);
141738c8a9a5SSteve French 		/*
141838c8a9a5SSteve French 		 * BB are there cases in which a comma can be valid in this
141938c8a9a5SSteve French 		 * workstation netbios name (and need special handling)?
142038c8a9a5SSteve French 		 */
142138c8a9a5SSteve French 
142238c8a9a5SSteve French 		/* user or mount helper must uppercase the netbios name */
142338c8a9a5SSteve French 		for (i = 0; i < 15; i++) {
142438c8a9a5SSteve French 			if (param->string[i] == 0)
142538c8a9a5SSteve French 				break;
142638c8a9a5SSteve French 			ctx->target_rfc1001_name[i] = param->string[i];
142738c8a9a5SSteve French 		}
142838c8a9a5SSteve French 
142938c8a9a5SSteve French 		/* The string has 16th byte zero still from set at top of function */
143038c8a9a5SSteve French 		if (i == RFC1001_NAME_LEN && param->string[i] != 0)
143138c8a9a5SSteve French 			pr_warn("server netbiosname longer than 15 truncated\n");
143238c8a9a5SSteve French 		break;
143338c8a9a5SSteve French 	case Opt_ver:
143438c8a9a5SSteve French 		/* version of mount userspace tools, not dialect */
143538c8a9a5SSteve French 		/* If interface changes in mount.cifs bump to new ver */
143638c8a9a5SSteve French 		if (strncasecmp(param->string, "1", 1) == 0) {
143738c8a9a5SSteve French 			if (strlen(param->string) > 1) {
143838c8a9a5SSteve French 				pr_warn("Bad mount helper ver=%s. Did you want SMB1 (CIFS) dialect and mean to type vers=1.0 instead?\n",
143938c8a9a5SSteve French 					param->string);
144038c8a9a5SSteve French 				goto cifs_parse_mount_err;
144138c8a9a5SSteve French 			}
144238c8a9a5SSteve French 			/* This is the default */
144338c8a9a5SSteve French 			break;
144438c8a9a5SSteve French 		}
144538c8a9a5SSteve French 		/* For all other value, error */
144638c8a9a5SSteve French 		pr_warn("Invalid mount helper version specified\n");
144738c8a9a5SSteve French 		goto cifs_parse_mount_err;
144838c8a9a5SSteve French 	case Opt_vers:
144938c8a9a5SSteve French 		/* protocol version (dialect) */
145038c8a9a5SSteve French 		if (cifs_parse_smb_version(fc, param->string, ctx, is_smb3) != 0)
145138c8a9a5SSteve French 			goto cifs_parse_mount_err;
145238c8a9a5SSteve French 		ctx->got_version = true;
145338c8a9a5SSteve French 		break;
145438c8a9a5SSteve French 	case Opt_sec:
145538c8a9a5SSteve French 		if (cifs_parse_security_flavors(fc, param->string, ctx) != 0)
145638c8a9a5SSteve French 			goto cifs_parse_mount_err;
145738c8a9a5SSteve French 		break;
145838c8a9a5SSteve French 	case Opt_cache:
145938c8a9a5SSteve French 		if (cifs_parse_cache_flavor(fc, param->string, ctx) != 0)
146038c8a9a5SSteve French 			goto cifs_parse_mount_err;
146138c8a9a5SSteve French 		break;
146238c8a9a5SSteve French 	case Opt_witness:
146338c8a9a5SSteve French #ifndef CONFIG_CIFS_SWN_UPCALL
146438c8a9a5SSteve French 		cifs_errorf(fc, "Witness support needs CONFIG_CIFS_SWN_UPCALL config option\n");
146538c8a9a5SSteve French 			goto cifs_parse_mount_err;
146638c8a9a5SSteve French #endif
146738c8a9a5SSteve French 		ctx->witness = true;
146838c8a9a5SSteve French 		pr_warn_once("Witness protocol support is experimental\n");
146938c8a9a5SSteve French 		break;
147038c8a9a5SSteve French 	case Opt_rootfs:
147138c8a9a5SSteve French #ifndef CONFIG_CIFS_ROOT
147238c8a9a5SSteve French 		cifs_dbg(VFS, "rootfs support requires CONFIG_CIFS_ROOT config option\n");
147338c8a9a5SSteve French 		goto cifs_parse_mount_err;
147438c8a9a5SSteve French #endif
147538c8a9a5SSteve French 		ctx->rootfs = true;
147638c8a9a5SSteve French 		break;
147738c8a9a5SSteve French 	case Opt_posixpaths:
147838c8a9a5SSteve French 		if (result.negated)
147938c8a9a5SSteve French 			ctx->posix_paths = 0;
148038c8a9a5SSteve French 		else
148138c8a9a5SSteve French 			ctx->posix_paths = 1;
148238c8a9a5SSteve French 		break;
148338c8a9a5SSteve French 	case Opt_unix:
148438c8a9a5SSteve French 		if (result.negated) {
148538c8a9a5SSteve French 			if (ctx->linux_ext == 1)
148638c8a9a5SSteve French 				pr_warn_once("conflicting posix mount options specified\n");
148738c8a9a5SSteve French 			ctx->linux_ext = 0;
148838c8a9a5SSteve French 			ctx->no_linux_ext = 1;
148938c8a9a5SSteve French 		} else {
149038c8a9a5SSteve French 			if (ctx->no_linux_ext == 1)
149138c8a9a5SSteve French 				pr_warn_once("conflicting posix mount options specified\n");
149238c8a9a5SSteve French 			ctx->linux_ext = 1;
149338c8a9a5SSteve French 			ctx->no_linux_ext = 0;
149438c8a9a5SSteve French 		}
149538c8a9a5SSteve French 		break;
149638c8a9a5SSteve French 	case Opt_nocase:
149738c8a9a5SSteve French 		ctx->nocase = 1;
149838c8a9a5SSteve French 		break;
149938c8a9a5SSteve French 	case Opt_brl:
150038c8a9a5SSteve French 		if (result.negated) {
150138c8a9a5SSteve French 			/*
150238c8a9a5SSteve French 			 * turn off mandatory locking in mode
150338c8a9a5SSteve French 			 * if remote locking is turned off since the
150438c8a9a5SSteve French 			 * local vfs will do advisory
150538c8a9a5SSteve French 			 */
150638c8a9a5SSteve French 			if (ctx->file_mode ==
150738c8a9a5SSteve French 				(S_IALLUGO & ~(S_ISUID | S_IXGRP)))
150838c8a9a5SSteve French 				ctx->file_mode = S_IALLUGO;
150938c8a9a5SSteve French 			ctx->nobrl =  1;
151038c8a9a5SSteve French 		} else
151138c8a9a5SSteve French 			ctx->nobrl =  0;
151238c8a9a5SSteve French 		break;
151338c8a9a5SSteve French 	case Opt_handlecache:
151438c8a9a5SSteve French 		if (result.negated)
151538c8a9a5SSteve French 			ctx->nohandlecache = 1;
151638c8a9a5SSteve French 		else
151738c8a9a5SSteve French 			ctx->nohandlecache = 0;
151838c8a9a5SSteve French 		break;
151938c8a9a5SSteve French 	case Opt_forcemandatorylock:
152038c8a9a5SSteve French 		ctx->mand_lock = 1;
152138c8a9a5SSteve French 		break;
152238c8a9a5SSteve French 	case Opt_setuids:
152338c8a9a5SSteve French 		ctx->setuids = result.negated;
152438c8a9a5SSteve French 		break;
152538c8a9a5SSteve French 	case Opt_intr:
152638c8a9a5SSteve French 		ctx->intr = !result.negated;
152738c8a9a5SSteve French 		break;
152838c8a9a5SSteve French 	case Opt_setuidfromacl:
152938c8a9a5SSteve French 		ctx->setuidfromacl = 1;
153038c8a9a5SSteve French 		break;
153138c8a9a5SSteve French 	case Opt_strictsync:
153238c8a9a5SSteve French 		ctx->nostrictsync = result.negated;
153338c8a9a5SSteve French 		break;
153438c8a9a5SSteve French 	case Opt_serverino:
153538c8a9a5SSteve French 		ctx->server_ino = !result.negated;
153638c8a9a5SSteve French 		break;
153738c8a9a5SSteve French 	case Opt_rwpidforward:
153838c8a9a5SSteve French 		ctx->rwpidforward = 1;
153938c8a9a5SSteve French 		break;
154038c8a9a5SSteve French 	case Opt_modesid:
154138c8a9a5SSteve French 		ctx->mode_ace = 1;
154238c8a9a5SSteve French 		break;
154338c8a9a5SSteve French 	case Opt_cifsacl:
154438c8a9a5SSteve French 		ctx->cifs_acl = !result.negated;
154538c8a9a5SSteve French 		break;
154638c8a9a5SSteve French 	case Opt_acl:
154738c8a9a5SSteve French 		ctx->no_psx_acl = result.negated;
154838c8a9a5SSteve French 		break;
154938c8a9a5SSteve French 	case Opt_locallease:
155038c8a9a5SSteve French 		ctx->local_lease = 1;
155138c8a9a5SSteve French 		break;
155238c8a9a5SSteve French 	case Opt_sign:
155338c8a9a5SSteve French 		ctx->sign = true;
155438c8a9a5SSteve French 		break;
155538c8a9a5SSteve French 	case Opt_ignore_signature:
155638c8a9a5SSteve French 		ctx->sign = true;
155738c8a9a5SSteve French 		ctx->ignore_signature = true;
155838c8a9a5SSteve French 		break;
155938c8a9a5SSteve French 	case Opt_seal:
156038c8a9a5SSteve French 		/* we do not do the following in secFlags because seal
156138c8a9a5SSteve French 		 * is a per tree connection (mount) not a per socket
156238c8a9a5SSteve French 		 * or per-smb connection option in the protocol
156338c8a9a5SSteve French 		 * vol->secFlg |= CIFSSEC_MUST_SEAL;
156438c8a9a5SSteve French 		 */
156538c8a9a5SSteve French 		ctx->seal = 1;
156638c8a9a5SSteve French 		break;
156738c8a9a5SSteve French 	case Opt_noac:
156838c8a9a5SSteve French 		pr_warn("Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
156938c8a9a5SSteve French 		break;
157038c8a9a5SSteve French 	case Opt_fsc:
157138c8a9a5SSteve French #ifndef CONFIG_CIFS_FSCACHE
157238c8a9a5SSteve French 		cifs_errorf(fc, "FS-Cache support needs CONFIG_CIFS_FSCACHE kernel config option set\n");
157338c8a9a5SSteve French 		goto cifs_parse_mount_err;
157438c8a9a5SSteve French #endif
157538c8a9a5SSteve French 		ctx->fsc = true;
157638c8a9a5SSteve French 		break;
157738c8a9a5SSteve French 	case Opt_mfsymlinks:
157838c8a9a5SSteve French 		ctx->mfsymlinks = true;
157938c8a9a5SSteve French 		break;
158038c8a9a5SSteve French 	case Opt_multiuser:
158138c8a9a5SSteve French 		ctx->multiuser = true;
158238c8a9a5SSteve French 		break;
158338c8a9a5SSteve French 	case Opt_sloppy:
158438c8a9a5SSteve French 		ctx->sloppy = true;
158538c8a9a5SSteve French 		break;
158638c8a9a5SSteve French 	case Opt_nosharesock:
158738c8a9a5SSteve French 		ctx->nosharesock = true;
158838c8a9a5SSteve French 		break;
158938c8a9a5SSteve French 	case Opt_persistent:
159038c8a9a5SSteve French 		if (result.negated) {
159138c8a9a5SSteve French 			ctx->nopersistent = true;
159238c8a9a5SSteve French 			if (ctx->persistent) {
159338c8a9a5SSteve French 				cifs_errorf(fc, "persistenthandles mount options conflict\n");
159438c8a9a5SSteve French 				goto cifs_parse_mount_err;
159538c8a9a5SSteve French 			}
159638c8a9a5SSteve French 		} else {
159738c8a9a5SSteve French 			ctx->persistent = true;
159838c8a9a5SSteve French 			if ((ctx->nopersistent) || (ctx->resilient)) {
159938c8a9a5SSteve French 				cifs_errorf(fc, "persistenthandles mount options conflict\n");
160038c8a9a5SSteve French 				goto cifs_parse_mount_err;
160138c8a9a5SSteve French 			}
160238c8a9a5SSteve French 		}
160338c8a9a5SSteve French 		break;
160438c8a9a5SSteve French 	case Opt_resilient:
160538c8a9a5SSteve French 		if (result.negated) {
160638c8a9a5SSteve French 			ctx->resilient = false; /* already the default */
160738c8a9a5SSteve French 		} else {
160838c8a9a5SSteve French 			ctx->resilient = true;
160938c8a9a5SSteve French 			if (ctx->persistent) {
161038c8a9a5SSteve French 				cifs_errorf(fc, "persistenthandles mount options conflict\n");
161138c8a9a5SSteve French 				goto cifs_parse_mount_err;
161238c8a9a5SSteve French 			}
161338c8a9a5SSteve French 		}
161438c8a9a5SSteve French 		break;
161538c8a9a5SSteve French 	case Opt_tcp_nodelay:
161638c8a9a5SSteve French 		/* tcp nodelay should not usually be needed since we CORK/UNCORK the socket */
161738c8a9a5SSteve French 		if (result.negated)
161838c8a9a5SSteve French 			ctx->sockopt_tcp_nodelay = false;
161938c8a9a5SSteve French 		else
162038c8a9a5SSteve French 			ctx->sockopt_tcp_nodelay = true;
162138c8a9a5SSteve French 		break;
162238c8a9a5SSteve French 	case Opt_domainauto:
162338c8a9a5SSteve French 		ctx->domainauto = true;
162438c8a9a5SSteve French 		break;
162538c8a9a5SSteve French 	case Opt_rdma:
162638c8a9a5SSteve French 		ctx->rdma = true;
162738c8a9a5SSteve French 		break;
1628c1468c7eSPaulo Alcantara 	case Opt_reparse:
1629c1468c7eSPaulo Alcantara 		if (parse_reparse_flavor(fc, param->string, ctx))
1630c1468c7eSPaulo Alcantara 			goto cifs_parse_mount_err;
1631c1468c7eSPaulo Alcantara 		break;
163238c8a9a5SSteve French 	}
163338c8a9a5SSteve French 	/* case Opt_ignore: - is ignored as expected ... */
163438c8a9a5SSteve French 
163538c8a9a5SSteve French 	return 0;
163638c8a9a5SSteve French 
163738c8a9a5SSteve French  cifs_parse_mount_err:
163838c8a9a5SSteve French 	kfree_sensitive(ctx->password);
1639e6e43b8aSQuang Le 	ctx->password = NULL;
164008bedfbcSSteve French 	kfree_sensitive(ctx->password2);
164108bedfbcSSteve French 	ctx->password2 = NULL;
164238c8a9a5SSteve French 	return -EINVAL;
164338c8a9a5SSteve French }
164438c8a9a5SSteve French 
smb3_init_fs_context(struct fs_context * fc)164538c8a9a5SSteve French int smb3_init_fs_context(struct fs_context *fc)
164638c8a9a5SSteve French {
164738c8a9a5SSteve French 	struct smb3_fs_context *ctx;
164838c8a9a5SSteve French 	char *nodename = utsname()->nodename;
164938c8a9a5SSteve French 	int i;
165038c8a9a5SSteve French 
165138c8a9a5SSteve French 	ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL);
165238c8a9a5SSteve French 	if (unlikely(!ctx))
165338c8a9a5SSteve French 		return -ENOMEM;
165438c8a9a5SSteve French 
165538c8a9a5SSteve French 	strscpy(ctx->workstation_name, nodename, sizeof(ctx->workstation_name));
165638c8a9a5SSteve French 
165738c8a9a5SSteve French 	/*
165838c8a9a5SSteve French 	 * does not have to be perfect mapping since field is
165938c8a9a5SSteve French 	 * informational, only used for servers that do not support
166038c8a9a5SSteve French 	 * port 445 and it can be overridden at mount time
166138c8a9a5SSteve French 	 */
166238c8a9a5SSteve French 	memset(ctx->source_rfc1001_name, 0x20, RFC1001_NAME_LEN);
166338c8a9a5SSteve French 	for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++)
166438c8a9a5SSteve French 		ctx->source_rfc1001_name[i] = toupper(nodename[i]);
166538c8a9a5SSteve French 
166638c8a9a5SSteve French 	ctx->source_rfc1001_name[RFC1001_NAME_LEN] = 0;
166738c8a9a5SSteve French 	/*
166838c8a9a5SSteve French 	 * null target name indicates to use *SMBSERVR default called name
166938c8a9a5SSteve French 	 *  if we end up sending RFC1001 session initialize
167038c8a9a5SSteve French 	 */
167138c8a9a5SSteve French 	ctx->target_rfc1001_name[0] = 0;
167238c8a9a5SSteve French 	ctx->cred_uid = current_uid();
167338c8a9a5SSteve French 	ctx->linux_uid = current_uid();
167438c8a9a5SSteve French 	ctx->linux_gid = current_gid();
167538c8a9a5SSteve French 	/* By default 4MB read ahead size, 1MB block size */
167638c8a9a5SSteve French 	ctx->bsize = CIFS_DEFAULT_IOSIZE; /* can improve cp performance significantly */
167738c8a9a5SSteve French 	ctx->rasize = 0; /* 0 = use default (ie negotiated rsize) for read ahead pages */
167838c8a9a5SSteve French 
167938c8a9a5SSteve French 	/*
168038c8a9a5SSteve French 	 * default to SFM style remapping of seven reserved characters
168138c8a9a5SSteve French 	 * unless user overrides it or we negotiate CIFS POSIX where
168238c8a9a5SSteve French 	 * it is unnecessary.  Can not simultaneously use more than one mapping
168338c8a9a5SSteve French 	 * since then readdir could list files that open could not open
168438c8a9a5SSteve French 	 */
168538c8a9a5SSteve French 	ctx->remap = true;
168638c8a9a5SSteve French 
168738c8a9a5SSteve French 	/* default to only allowing write access to owner of the mount */
168838c8a9a5SSteve French 	ctx->dir_mode = ctx->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
168938c8a9a5SSteve French 
169038c8a9a5SSteve French 	/* ctx->retry default is 0 (i.e. "soft" limited retry not hard retry) */
169138c8a9a5SSteve French 	/* default is always to request posix paths. */
169238c8a9a5SSteve French 	ctx->posix_paths = 1;
169338c8a9a5SSteve French 	/* default to using server inode numbers where available */
169438c8a9a5SSteve French 	ctx->server_ino = 1;
169538c8a9a5SSteve French 
169638c8a9a5SSteve French 	/* default is to use strict cifs caching semantics */
169738c8a9a5SSteve French 	ctx->strict_io = true;
169838c8a9a5SSteve French 
169938c8a9a5SSteve French 	ctx->acregmax = CIFS_DEF_ACTIMEO;
170038c8a9a5SSteve French 	ctx->acdirmax = CIFS_DEF_ACTIMEO;
170138c8a9a5SSteve French 	ctx->closetimeo = SMB3_DEF_DCLOSETIMEO;
17026a50d71dSSteve French 	ctx->max_cached_dirs = MAX_CACHED_FIDS;
170338c8a9a5SSteve French 	/* Most clients set timeout to 0, allows server to use its default */
170438c8a9a5SSteve French 	ctx->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */
170538c8a9a5SSteve French 
170638c8a9a5SSteve French 	/* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */
170738c8a9a5SSteve French 	ctx->ops = &smb30_operations;
170838c8a9a5SSteve French 	ctx->vals = &smbdefault_values;
170938c8a9a5SSteve French 
171038c8a9a5SSteve French 	ctx->echo_interval = SMB_ECHO_INTERVAL_DEFAULT;
171138c8a9a5SSteve French 
171238c8a9a5SSteve French 	/* default to no multichannel (single server connection) */
171338c8a9a5SSteve French 	ctx->multichannel = false;
171438c8a9a5SSteve French 	ctx->max_channels = 1;
171538c8a9a5SSteve French 
171638c8a9a5SSteve French 	ctx->backupuid_specified = false; /* no backup intent for a user */
171738c8a9a5SSteve French 	ctx->backupgid_specified = false; /* no backup intent for a group */
171838c8a9a5SSteve French 
1719b4ca2942SShyam Prasad N 	ctx->retrans = 1;
1720c1468c7eSPaulo Alcantara 	ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT;
1721b4ca2942SShyam Prasad N 
172238c8a9a5SSteve French /*
172338c8a9a5SSteve French  *	short int override_uid = -1;
172438c8a9a5SSteve French  *	short int override_gid = -1;
172538c8a9a5SSteve French  *	char *nodename = strdup(utsname()->nodename);
172638c8a9a5SSteve French  *	struct sockaddr *dstaddr = (struct sockaddr *)&vol->dstaddr;
172738c8a9a5SSteve French  */
172838c8a9a5SSteve French 
172938c8a9a5SSteve French 	fc->fs_private = ctx;
173038c8a9a5SSteve French 	fc->ops = &smb3_fs_context_ops;
173138c8a9a5SSteve French 	return 0;
173238c8a9a5SSteve French }
173338c8a9a5SSteve French 
173438c8a9a5SSteve French void
smb3_cleanup_fs_context_contents(struct smb3_fs_context * ctx)173538c8a9a5SSteve French smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx)
173638c8a9a5SSteve French {
173738c8a9a5SSteve French 	if (ctx == NULL)
173838c8a9a5SSteve French 		return;
173938c8a9a5SSteve French 
174038c8a9a5SSteve French 	/*
174138c8a9a5SSteve French 	 * Make sure this stays in sync with smb3_fs_context_dup()
174238c8a9a5SSteve French 	 */
174338c8a9a5SSteve French 	kfree(ctx->username);
174438c8a9a5SSteve French 	ctx->username = NULL;
174538c8a9a5SSteve French 	kfree_sensitive(ctx->password);
174638c8a9a5SSteve French 	ctx->password = NULL;
174708bedfbcSSteve French 	kfree_sensitive(ctx->password2);
174808bedfbcSSteve French 	ctx->password2 = NULL;
174938c8a9a5SSteve French 	kfree(ctx->server_hostname);
175038c8a9a5SSteve French 	ctx->server_hostname = NULL;
175138c8a9a5SSteve French 	kfree(ctx->UNC);
175238c8a9a5SSteve French 	ctx->UNC = NULL;
175338c8a9a5SSteve French 	kfree(ctx->source);
175438c8a9a5SSteve French 	ctx->source = NULL;
175538c8a9a5SSteve French 	kfree(ctx->domainname);
175638c8a9a5SSteve French 	ctx->domainname = NULL;
175738c8a9a5SSteve French 	kfree(ctx->nodename);
175838c8a9a5SSteve French 	ctx->nodename = NULL;
175938c8a9a5SSteve French 	kfree(ctx->iocharset);
176038c8a9a5SSteve French 	ctx->iocharset = NULL;
176138c8a9a5SSteve French 	kfree(ctx->prepath);
176238c8a9a5SSteve French 	ctx->prepath = NULL;
176338c8a9a5SSteve French 	kfree(ctx->leaf_fullpath);
176438c8a9a5SSteve French 	ctx->leaf_fullpath = NULL;
176538c8a9a5SSteve French }
176638c8a9a5SSteve French 
176738c8a9a5SSteve French void
smb3_cleanup_fs_context(struct smb3_fs_context * ctx)176838c8a9a5SSteve French smb3_cleanup_fs_context(struct smb3_fs_context *ctx)
176938c8a9a5SSteve French {
177038c8a9a5SSteve French 	if (!ctx)
177138c8a9a5SSteve French 		return;
177238c8a9a5SSteve French 	smb3_cleanup_fs_context_contents(ctx);
177338c8a9a5SSteve French 	kfree(ctx);
177438c8a9a5SSteve French }
177538c8a9a5SSteve French 
smb3_update_mnt_flags(struct cifs_sb_info * cifs_sb)177638c8a9a5SSteve French void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb)
177738c8a9a5SSteve French {
177838c8a9a5SSteve French 	struct smb3_fs_context *ctx = cifs_sb->ctx;
177938c8a9a5SSteve French 
178038c8a9a5SSteve French 	if (ctx->nodfs)
178138c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_DFS;
178238c8a9a5SSteve French 	else
178338c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_DFS;
178438c8a9a5SSteve French 
178538c8a9a5SSteve French 	if (ctx->noperm)
178638c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
178738c8a9a5SSteve French 	else
178838c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_PERM;
178938c8a9a5SSteve French 
179038c8a9a5SSteve French 	if (ctx->setuids)
179138c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
179238c8a9a5SSteve French 	else
179338c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SET_UID;
179438c8a9a5SSteve French 
179538c8a9a5SSteve French 	if (ctx->setuidfromacl)
179638c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UID_FROM_ACL;
179738c8a9a5SSteve French 	else
179838c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_UID_FROM_ACL;
179938c8a9a5SSteve French 
180038c8a9a5SSteve French 	if (ctx->server_ino)
180138c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
180238c8a9a5SSteve French 	else
180338c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
180438c8a9a5SSteve French 
180538c8a9a5SSteve French 	if (ctx->remap)
180638c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR;
180738c8a9a5SSteve French 	else
180838c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MAP_SFM_CHR;
180938c8a9a5SSteve French 
181038c8a9a5SSteve French 	if (ctx->sfu_remap)
181138c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
181238c8a9a5SSteve French 	else
181338c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MAP_SPECIAL_CHR;
181438c8a9a5SSteve French 
181538c8a9a5SSteve French 	if (ctx->no_xattr)
181638c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
181738c8a9a5SSteve French 	else
181838c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_XATTR;
181938c8a9a5SSteve French 
182038c8a9a5SSteve French 	if (ctx->sfu_emul)
182138c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
182238c8a9a5SSteve French 	else
182338c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_UNX_EMUL;
182438c8a9a5SSteve French 
182538c8a9a5SSteve French 	if (ctx->nobrl)
182638c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
182738c8a9a5SSteve French 	else
182838c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_BRL;
182938c8a9a5SSteve French 
183038c8a9a5SSteve French 	if (ctx->nohandlecache)
183138c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_HANDLE_CACHE;
183238c8a9a5SSteve French 	else
183338c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_HANDLE_CACHE;
183438c8a9a5SSteve French 
183538c8a9a5SSteve French 	if (ctx->nostrictsync)
183638c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
183738c8a9a5SSteve French 	else
183838c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NOSSYNC;
183938c8a9a5SSteve French 
184038c8a9a5SSteve French 	if (ctx->mand_lock)
184138c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
184238c8a9a5SSteve French 	else
184338c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NOPOSIXBRL;
184438c8a9a5SSteve French 
184538c8a9a5SSteve French 	if (ctx->rwpidforward)
184638c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD;
184738c8a9a5SSteve French 	else
184838c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_RWPIDFORWARD;
184938c8a9a5SSteve French 
185038c8a9a5SSteve French 	if (ctx->mode_ace)
185138c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MODE_FROM_SID;
185238c8a9a5SSteve French 	else
185338c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MODE_FROM_SID;
185438c8a9a5SSteve French 
185538c8a9a5SSteve French 	if (ctx->cifs_acl)
185638c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
185738c8a9a5SSteve French 	else
185838c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_ACL;
185938c8a9a5SSteve French 
186038c8a9a5SSteve French 	if (ctx->backupuid_specified)
186138c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID;
186238c8a9a5SSteve French 	else
186338c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_BACKUPUID;
186438c8a9a5SSteve French 
186538c8a9a5SSteve French 	if (ctx->backupgid_specified)
186638c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID;
186738c8a9a5SSteve French 	else
186838c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_BACKUPGID;
186938c8a9a5SSteve French 
187038c8a9a5SSteve French 	if (ctx->override_uid)
187138c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
187238c8a9a5SSteve French 	else
187338c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_OVERR_UID;
187438c8a9a5SSteve French 
187538c8a9a5SSteve French 	if (ctx->override_gid)
187638c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
187738c8a9a5SSteve French 	else
187838c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_OVERR_GID;
187938c8a9a5SSteve French 
188038c8a9a5SSteve French 	if (ctx->dynperm)
188138c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
188238c8a9a5SSteve French 	else
188338c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_DYNPERM;
188438c8a9a5SSteve French 
188538c8a9a5SSteve French 	if (ctx->fsc)
188638c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE;
188738c8a9a5SSteve French 	else
188838c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_FSCACHE;
188938c8a9a5SSteve French 
189038c8a9a5SSteve French 	if (ctx->multiuser)
189138c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER |
189238c8a9a5SSteve French 					    CIFS_MOUNT_NO_PERM);
189338c8a9a5SSteve French 	else
189438c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MULTIUSER;
189538c8a9a5SSteve French 
189638c8a9a5SSteve French 
189738c8a9a5SSteve French 	if (ctx->strict_io)
189838c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO;
189938c8a9a5SSteve French 	else
190038c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_STRICT_IO;
190138c8a9a5SSteve French 
190238c8a9a5SSteve French 	if (ctx->direct_io)
190338c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
190438c8a9a5SSteve French 	else
190538c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_DIRECT_IO;
190638c8a9a5SSteve French 
190738c8a9a5SSteve French 	if (ctx->mfsymlinks)
190838c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
190938c8a9a5SSteve French 	else
191038c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MF_SYMLINKS;
191138c8a9a5SSteve French 	if (ctx->mfsymlinks) {
191238c8a9a5SSteve French 		if (ctx->sfu_emul) {
191338c8a9a5SSteve French 			/*
191438c8a9a5SSteve French 			 * Our SFU ("Services for Unix" emulation does not allow
191538c8a9a5SSteve French 			 * creating symlinks but does allow reading existing SFU
191638c8a9a5SSteve French 			 * symlinks (it does allow both creating and reading SFU
191738c8a9a5SSteve French 			 * style mknod and FIFOs though). When "mfsymlinks" and
191838c8a9a5SSteve French 			 * "sfu" are both enabled at the same time, it allows
191938c8a9a5SSteve French 			 * reading both types of symlinks, but will only create
192038c8a9a5SSteve French 			 * them with mfsymlinks format. This allows better
192138c8a9a5SSteve French 			 * Apple compatibility (probably better for Samba too)
192238c8a9a5SSteve French 			 * while still recognizing old Windows style symlinks.
192338c8a9a5SSteve French 			 */
192438c8a9a5SSteve French 			cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
192538c8a9a5SSteve French 		}
192638c8a9a5SSteve French 	}
192738c8a9a5SSteve French 	cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SHUTDOWN;
192838c8a9a5SSteve French 
192938c8a9a5SSteve French 	return;
193038c8a9a5SSteve French }
1931