diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index ca39d01077cd..f1b2adb5f6ba 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -162,6 +162,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_string("password", Opt_pass), fsparam_string("ip", Opt_ip), fsparam_string("addr", Opt_ip), + fsparam_string("hostname", Opt_hostname), fsparam_string("domain", Opt_domain), fsparam_string("dom", Opt_domain), fsparam_string("srcaddr", Opt_srcaddr), @@ -658,16 +659,20 @@ static int smb3_fs_context_validate(struct fs_context *fc) return -ENOENT; } + if (ctx->got_opt_hostname) { + kfree(ctx->server_hostname); + ctx->server_hostname = ctx->opt_hostname; + pr_notice("changing server hostname to name provided in hostname= option\n"); + } + if (!ctx->got_ip) { int len; - const char *slash; - /* No ip= option specified? Try to get it from UNC */ - /* Use the address part of the UNC. */ - slash = strchr(&ctx->UNC[2], '\\'); - len = slash - &ctx->UNC[2]; + /* No ip= option specified? Try to get it from server_hostname */ + /* Use the address part of the UNC parsed into server_hostname or hostname= option if specified. */ + len = strlen(ctx->server_hostname); if (!cifs_convert_address((struct sockaddr *)&ctx->dstaddr, - &ctx->UNC[2], len)) { + ctx->server_hostname, len)) { pr_err("Unable to determine destination address\n"); return -EHOSTUNREACH; } @@ -1214,6 +1219,21 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, } ctx->got_ip = true; break; + case Opt_hostname: + if (strnlen(param->string, CIFS_NI_MAXHOST) == CIFS_NI_MAXHOST) { + pr_warn("host name too long\n"); + goto cifs_parse_mount_err; + } + + kfree(ctx->opt_hostname); + ctx->opt_hostname = kstrdup(param->string, GFP_KERNEL); + if (ctx->opt_hostname == NULL) { + cifs_errorf(fc, "OOM when copying hostname string\n"); + goto cifs_parse_mount_err; + } + cifs_dbg(FYI, "Host name set\n"); + ctx->got_opt_hostname = true; + break; case Opt_domain: if (strnlen(param->string, CIFS_MAX_DOMAINNAME_LEN) == CIFS_MAX_DOMAINNAME_LEN) { diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h index 319a91b7f670..92342cd2b650 100644 --- a/fs/smb/client/fs_context.h +++ b/fs/smb/client/fs_context.h @@ -137,6 +137,7 @@ enum cifs_param { Opt_user, Opt_pass, Opt_ip, + Opt_hostname, Opt_domain, Opt_srcaddr, Opt_iocharset, @@ -161,6 +162,7 @@ struct smb3_fs_context { bool gid_specified; bool sloppy; bool got_ip; + bool got_opt_hostname; bool got_version; bool got_rsize; bool got_wsize; @@ -172,6 +174,7 @@ struct smb3_fs_context { char *domainname; char *source; char *server_hostname; + char *opt_hostname; char *UNC; char *nodename; char workstation_name[CIFS_MAX_WORKSTATION_LEN];