aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/fs/smb/client/fs_context.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--fs/smb/client/fs_context.c124
1 files changed, 115 insertions, 9 deletions
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index 5c5a52019efa..49123f458d0c 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -67,6 +67,12 @@ static const match_table_t cifs_secflavor_tokens = {
{ Opt_sec_err, NULL }
};
+static const match_table_t cifs_upcall_target = {
+ { Opt_upcall_target_mount, "mount" },
+ { Opt_upcall_target_application, "app" },
+ { Opt_upcall_target_err, NULL }
+};
+
const struct fs_parameter_spec smb3_fs_parameters[] = {
/* Mount options that take no arguments */
fsparam_flag_no("user_xattr", Opt_user_xattr),
@@ -178,6 +184,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
fsparam_string("sec", Opt_sec),
fsparam_string("cache", Opt_cache),
fsparam_string("reparse", Opt_reparse),
+ fsparam_string("upcall_target", Opt_upcalltarget),
/* Arguments that should be ignored */
fsparam_flag("guest", Opt_ignore),
@@ -248,6 +255,29 @@ cifs_parse_security_flavors(struct fs_context *fc, char *value, struct smb3_fs_c
return 0;
}
+static int
+cifs_parse_upcall_target(struct fs_context *fc, char *value, struct smb3_fs_context *ctx)
+{
+ substring_t args[MAX_OPT_ARGS];
+
+ ctx->upcall_target = UPTARGET_UNSPECIFIED;
+
+ switch (match_token(value, cifs_upcall_target, args)) {
+ case Opt_upcall_target_mount:
+ ctx->upcall_target = UPTARGET_MOUNT;
+ break;
+ case Opt_upcall_target_application:
+ ctx->upcall_target = UPTARGET_APP;
+ break;
+
+ default:
+ cifs_errorf(fc, "bad upcall target: %s\n", value);
+ return 1;
+ }
+
+ return 0;
+}
+
static const match_table_t cifs_cacheflavor_tokens = {
{ Opt_cache_loose, "loose" },
{ Opt_cache_strict, "strict" },
@@ -890,12 +920,37 @@ do { \
cifs_sb->ctx->field = NULL; \
} while (0)
+int smb3_sync_session_ctx_passwords(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
+{
+ if (ses->password &&
+ cifs_sb->ctx->password &&
+ strcmp(ses->password, cifs_sb->ctx->password)) {
+ kfree_sensitive(cifs_sb->ctx->password);
+ cifs_sb->ctx->password = kstrdup(ses->password, GFP_KERNEL);
+ if (!cifs_sb->ctx->password)
+ return -ENOMEM;
+ }
+ if (ses->password2 &&
+ cifs_sb->ctx->password2 &&
+ strcmp(ses->password2, cifs_sb->ctx->password2)) {
+ kfree_sensitive(cifs_sb->ctx->password2);
+ cifs_sb->ctx->password2 = kstrdup(ses->password2, GFP_KERNEL);
+ if (!cifs_sb->ctx->password2) {
+ kfree_sensitive(cifs_sb->ctx->password);
+ cifs_sb->ctx->password = NULL;
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
static int smb3_reconfigure(struct fs_context *fc)
{
struct smb3_fs_context *ctx = smb3_fc2context(fc);
struct dentry *root = fc->root;
struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb);
struct cifs_ses *ses = cifs_sb_master_tcon(cifs_sb)->ses;
+ char *new_password = NULL, *new_password2 = NULL;
bool need_recon = false;
int rc;
@@ -915,21 +970,63 @@ static int smb3_reconfigure(struct fs_context *fc)
STEAL_STRING(cifs_sb, ctx, UNC);
STEAL_STRING(cifs_sb, ctx, source);
STEAL_STRING(cifs_sb, ctx, username);
+
if (need_recon == false)
STEAL_STRING_SENSITIVE(cifs_sb, ctx, password);
else {
- kfree_sensitive(ses->password);
- ses->password = kstrdup(ctx->password, GFP_KERNEL);
- if (!ses->password)
- return -ENOMEM;
- kfree_sensitive(ses->password2);
- ses->password2 = kstrdup(ctx->password2, GFP_KERNEL);
- if (!ses->password2) {
- kfree_sensitive(ses->password);
- ses->password = NULL;
+ if (ctx->password) {
+ new_password = kstrdup(ctx->password, GFP_KERNEL);
+ if (!new_password)
+ return -ENOMEM;
+ } else
+ STEAL_STRING_SENSITIVE(cifs_sb, ctx, password);
+ }
+
+ /*
+ * if a new password2 has been specified, then reset it's value
+ * inside the ses struct
+ */
+ if (ctx->password2) {
+ new_password2 = kstrdup(ctx->password2, GFP_KERNEL);
+ if (!new_password2) {
+ kfree_sensitive(new_password);
return -ENOMEM;
}
+ } else
+ STEAL_STRING_SENSITIVE(cifs_sb, ctx, password2);
+
+ /*
+ * we may update the passwords in the ses struct below. Make sure we do
+ * not race with smb2_reconnect
+ */
+ mutex_lock(&ses->session_mutex);
+
+ /*
+ * smb2_reconnect may swap password and password2 in case session setup
+ * failed. First get ctx passwords in sync with ses passwords. It should
+ * be okay to do this even if this function were to return an error at a
+ * later stage
+ */
+ rc = smb3_sync_session_ctx_passwords(cifs_sb, ses);
+ if (rc) {
+ mutex_unlock(&ses->session_mutex);
+ return rc;
}
+
+ /*
+ * now that allocations for passwords are done, commit them
+ */
+ if (new_password) {
+ kfree_sensitive(ses->password);
+ ses->password = new_password;
+ }
+ if (new_password2) {
+ kfree_sensitive(ses->password2);
+ ses->password2 = new_password2;
+ }
+
+ mutex_unlock(&ses->session_mutex);
+
STEAL_STRING(cifs_sb, ctx, domainname);
STEAL_STRING(cifs_sb, ctx, nodename);
STEAL_STRING(cifs_sb, ctx, iocharset);
@@ -1450,6 +1547,10 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
if (cifs_parse_security_flavors(fc, param->string, ctx) != 0)
goto cifs_parse_mount_err;
break;
+ case Opt_upcalltarget:
+ if (cifs_parse_upcall_target(fc, param->string, ctx) != 0)
+ goto cifs_parse_mount_err;
+ break;
case Opt_cache:
if (cifs_parse_cache_flavor(fc, param->string, ctx) != 0)
goto cifs_parse_mount_err;
@@ -1627,6 +1728,11 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
}
/* case Opt_ignore: - is ignored as expected ... */
+ if (ctx->multiuser && ctx->upcall_target == UPTARGET_MOUNT) {
+ cifs_errorf(fc, "multiuser mount option not supported with upcalltarget set as 'mount'\n");
+ goto cifs_parse_mount_err;
+ }
+
return 0;
cifs_parse_mount_err: