* [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication @ 2025-05-16 15:22 Maria Alexeeva 2025-06-14 3:42 ` Vitaly Chikunov 0 siblings, 1 reply; 16+ messages in thread From: Maria Alexeeva @ 2025-05-16 15:22 UTC (permalink / raw) To: linux-cifs, samba-technical, sfrench, pc; +Cc: Maria Alexeeva, Ivan Volchenko Paths to domain-based dfs resources are defined using the domain name of the server in the format: \\DOMAIN.NAME>\<dfsroot>\<path> The CIFS module, when requesting a TGS, uses the server name (<DOMAIN.NAME>) it obtained from the UNC for the initial connection. It then composes an SPN that does not match any entities in the domain because it is the domain name itself. To eliminate this behavior, a hostname option is added, which is the name of the server to connect to and is used in composing the SPN. In the future this option will be used in the cifs-utils development. Suggested-by: Ivan Volchenko <ivolchenko86@gmail.com> Signed-off-by: Maria Alexeeva <alxvmr@altlinux.org> --- fs/smb/client/fs_context.c | 35 +++++++++++++++++++++++++++++------ fs/smb/client/fs_context.h | 3 +++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index a634a34d4086..74de0a9de664 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -177,6 +177,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_string("password2", Opt_pass2), 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), @@ -825,16 +826,23 @@ 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; } @@ -1518,6 +1526,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 9e83302ce4b8..cf0478b1eff9 100644 --- a/fs/smb/client/fs_context.h +++ b/fs/smb/client/fs_context.h @@ -184,6 +184,7 @@ enum cifs_param { Opt_pass, Opt_pass2, Opt_ip, + Opt_hostname, Opt_domain, Opt_srcaddr, Opt_iocharset, @@ -214,6 +215,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; @@ -226,6 +228,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]; base-commit: bec6f00f120ea68ba584def5b7416287e7dd29a7 -- 2.42.2 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication 2025-05-16 15:22 [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication Maria Alexeeva @ 2025-06-14 3:42 ` Vitaly Chikunov 2025-07-03 12:59 ` Maria Alexeeva 0 siblings, 1 reply; 16+ messages in thread From: Vitaly Chikunov @ 2025-06-14 3:42 UTC (permalink / raw) To: Maria Alexeeva; +Cc: linux-cifs, samba-technical, sfrench, pc, Ivan Volchenko Maria, On Fri, May 16, 2025 at 07:22:01PM +0400, Maria Alexeeva wrote: > Paths to domain-based dfs resources are defined using the domain name > of the server in the format: > \\DOMAIN.NAME>\<dfsroot>\<path> > > The CIFS module, when requesting a TGS, uses the server name > (<DOMAIN.NAME>) it obtained from the UNC for the initial connection. > It then composes an SPN that does not match any entities > in the domain because it is the domain name itself. For a casual reader like me it's hard to understand (this abbreviation filled message) what it's all about. And why we can't just change system hostname for example. Also, the summary (subject) message is 180 character which is way above 75 characters suggested in submitting-patches.rst. > > To eliminate this behavior, a hostname option is added, which is > the name of the server to connect to and is used in composing the SPN. > In the future this option will be used in the cifs-utils development. > > Suggested-by: Ivan Volchenko <ivolchenko86@gmail.com> > Signed-off-by: Maria Alexeeva <alxvmr@altlinux.org> > --- > fs/smb/client/fs_context.c | 35 +++++++++++++++++++++++++++++------ > fs/smb/client/fs_context.h | 3 +++ > 2 files changed, 32 insertions(+), 6 deletions(-) > > diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c > index a634a34d4086..74de0a9de664 100644 > --- a/fs/smb/client/fs_context.c > +++ b/fs/smb/client/fs_context.c > @@ -177,6 +177,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { > fsparam_string("password2", Opt_pass2), > 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), > @@ -825,16 +826,23 @@ 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; I am not familiar with the smb codebase but are you sure this will not cause a race? > + 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; > } > @@ -1518,6 +1526,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 9e83302ce4b8..cf0478b1eff9 100644 > --- a/fs/smb/client/fs_context.h > +++ b/fs/smb/client/fs_context.h > @@ -184,6 +184,7 @@ enum cifs_param { > Opt_pass, > Opt_pass2, > Opt_ip, > + Opt_hostname, > Opt_domain, > Opt_srcaddr, > Opt_iocharset, > @@ -214,6 +215,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; > @@ -226,6 +228,7 @@ struct smb3_fs_context { > char *domainname; > char *source; > char *server_hostname; > + char *opt_hostname; Perhaps, smb3_fs_context_dup and smb3_cleanup_fs_context_contents should be aware of these new fields too. Thanks, > char *UNC; > char *nodename; > char workstation_name[CIFS_MAX_WORKSTATION_LEN]; > > base-commit: bec6f00f120ea68ba584def5b7416287e7dd29a7 > -- > 2.42.2 > ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication 2025-06-14 3:42 ` Vitaly Chikunov @ 2025-07-03 12:59 ` Maria Alexeeva 2025-07-24 22:14 ` Steve French 0 siblings, 1 reply; 16+ messages in thread From: Maria Alexeeva @ 2025-07-03 12:59 UTC (permalink / raw) To: Vitaly Chikunov; +Cc: linux-cifs, samba-technical, sfrench, pc, Ivan Volchenko On 6/14/25 07:42, Vitaly Chikunov wrote: > Maria, > > On Fri, May 16, 2025 at 07:22:01PM +0400, Maria Alexeeva wrote: >> Paths to domain-based dfs resources are defined using the domain name >> of the server in the format: >> \\DOMAIN.NAME>\<dfsroot>\<path> >> >> The CIFS module, when requesting a TGS, uses the server name >> (<DOMAIN.NAME>) it obtained from the UNC for the initial connection. >> It then composes an SPN that does not match any entities >> in the domain because it is the domain name itself. > For a casual reader like me it's hard to understand (this abbreviation > filled message) what it's all about. And why we can't just change system > hostname for example. This option is needed to transfer the real name of the server to which the connection is taking place, when using the UNC path in the form of domain-based DFS. The system hostname has nothing to do with it. > Also, the summary (subject) message is 180 character which is way above > 75 characters suggested in submitting-patches.rst. > >> To eliminate this behavior, a hostname option is added, which is >> the name of the server to connect to and is used in composing the SPN. >> In the future this option will be used in the cifs-utils development. >> >> Suggested-by: Ivan Volchenko <ivolchenko86@gmail.com> >> Signed-off-by: Maria Alexeeva <alxvmr@altlinux.org> >> --- >> fs/smb/client/fs_context.c | 35 +++++++++++++++++++++++++++++------ >> fs/smb/client/fs_context.h | 3 +++ >> 2 files changed, 32 insertions(+), 6 deletions(-) >> >> diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c >> index a634a34d4086..74de0a9de664 100644 >> --- a/fs/smb/client/fs_context.c >> +++ b/fs/smb/client/fs_context.c >> @@ -177,6 +177,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { >> fsparam_string("password2", Opt_pass2), >> 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), >> @@ -825,16 +826,23 @@ 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; > I am not familiar with the smb codebase but are you sure this will not > cause a race? The race condition will not occur. ctx->server_hostname is also used in smb3_parse_devname inside smb3_fs_context_parse_param. smb3_fs_context_parse_param is called earlier than the updated smb3_fs_context_validate, which is called inside smb3_get_tree: static const struct fs_context_operations smb3_fs_context_ops = { .free = smb3_fs_context_free, .parse_param = smb3_fs_context_parse_param, .parse_monolithic = smb3_fs_context_parse_monolithic, .get_tree = smb3_get_tree, .reconfigure = smb3_reconfigure, }; >> + 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; >> } >> @@ -1518,6 +1526,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 9e83302ce4b8..cf0478b1eff9 100644 >> --- a/fs/smb/client/fs_context.h >> +++ b/fs/smb/client/fs_context.h >> @@ -184,6 +184,7 @@ enum cifs_param { >> Opt_pass, >> Opt_pass2, >> Opt_ip, >> + Opt_hostname, >> Opt_domain, >> Opt_srcaddr, >> Opt_iocharset, >> @@ -214,6 +215,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; >> @@ -226,6 +228,7 @@ struct smb3_fs_context { >> char *domainname; >> char *source; >> char *server_hostname; >> + char *opt_hostname; > Perhaps, smb3_fs_context_dup and smb3_cleanup_fs_context_contents should > be aware of these new fields too. smb3_cleanup_fs_context_contents should be aware of these new fields too. Clearing in smb3_cleanup_fs_context_contents is not necessary, because if opt_hostname != NULL, then the pointer in server_hostname is replaced (it is pre-cleared by kfree), respectively, everything will be cleared by itself with the current code. In smb3_fs_context_dup, opt_hostname does not need to be processed, since this variable is essentially temporary. Immediately after parsing with the parameter, its value goes to server_hostname and it is no longer needed by itself. > Thanks, > >> char *UNC; >> char *nodename; >> char workstation_name[CIFS_MAX_WORKSTATION_LEN]; >> >> base-commit: bec6f00f120ea68ba584def5b7416287e7dd29a7 >> -- >> 2.42.2 >> Apologies for the overly long subject line and unclear description. Thanks. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication 2025-07-03 12:59 ` Maria Alexeeva @ 2025-07-24 22:14 ` Steve French 2025-07-24 22:50 ` Steve French 0 siblings, 1 reply; 16+ messages in thread From: Steve French @ 2025-07-24 22:14 UTC (permalink / raw) To: alxvmr Cc: Vitaly Chikunov, linux-cifs, Ivan Volchenko, samba-technical, pc, Tom Talpey I will update the mount parm name, similar to what Tom suggested to "dfs_domain_hostname" to be less confusing. Let me know if you had a v2 of the patch with other changes On Thu, Jul 3, 2025 at 8:00 AM Maria Alexeeva via samba-technical <samba-technical@lists.samba.org> wrote: > > On 6/14/25 07:42, Vitaly Chikunov wrote: > > Maria, > > > > On Fri, May 16, 2025 at 07:22:01PM +0400, Maria Alexeeva wrote: > >> Paths to domain-based dfs resources are defined using the domain name > >> of the server in the format: > >> \\DOMAIN.NAME>\<dfsroot>\<path> > >> > >> The CIFS module, when requesting a TGS, uses the server name > >> (<DOMAIN.NAME>) it obtained from the UNC for the initial connection. > >> It then composes an SPN that does not match any entities > >> in the domain because it is the domain name itself. > > For a casual reader like me it's hard to understand (this abbreviation > > filled message) what it's all about. And why we can't just change system > > hostname for example. > > This option is needed to transfer the real name of the server to which > the connection is taking place, > when using the UNC path in the form of domain-based DFS. The system > hostname has nothing to do with it. > > > Also, the summary (subject) message is 180 character which is way above > > 75 characters suggested in submitting-patches.rst. > > > >> To eliminate this behavior, a hostname option is added, which is > >> the name of the server to connect to and is used in composing the SPN. > >> In the future this option will be used in the cifs-utils development. > >> > >> Suggested-by: Ivan Volchenko <ivolchenko86@gmail.com> > >> Signed-off-by: Maria Alexeeva <alxvmr@altlinux.org> > >> --- > >> fs/smb/client/fs_context.c | 35 +++++++++++++++++++++++++++++------ > >> fs/smb/client/fs_context.h | 3 +++ > >> 2 files changed, 32 insertions(+), 6 deletions(-) > >> > >> diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c > >> index a634a34d4086..74de0a9de664 100644 > >> --- a/fs/smb/client/fs_context.c > >> +++ b/fs/smb/client/fs_context.c > >> @@ -177,6 +177,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { > >> fsparam_string("password2", Opt_pass2), > >> 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), > >> @@ -825,16 +826,23 @@ 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; > > I am not familiar with the smb codebase but are you sure this will not > > cause a race? > > The race condition will not occur. > ctx->server_hostname is also used in smb3_parse_devname inside > smb3_fs_context_parse_param. > smb3_fs_context_parse_param is called earlier than the updated > smb3_fs_context_validate, which is called inside smb3_get_tree: > > static const struct fs_context_operations smb3_fs_context_ops = { > .free = smb3_fs_context_free, > .parse_param = smb3_fs_context_parse_param, > .parse_monolithic = smb3_fs_context_parse_monolithic, > .get_tree = smb3_get_tree, > .reconfigure = smb3_reconfigure, > }; > > >> + 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; > >> } > >> @@ -1518,6 +1526,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 9e83302ce4b8..cf0478b1eff9 100644 > >> --- a/fs/smb/client/fs_context.h > >> +++ b/fs/smb/client/fs_context.h > >> @@ -184,6 +184,7 @@ enum cifs_param { > >> Opt_pass, > >> Opt_pass2, > >> Opt_ip, > >> + Opt_hostname, > >> Opt_domain, > >> Opt_srcaddr, > >> Opt_iocharset, > >> @@ -214,6 +215,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; > >> @@ -226,6 +228,7 @@ struct smb3_fs_context { > >> char *domainname; > >> char *source; > >> char *server_hostname; > >> + char *opt_hostname; > > Perhaps, smb3_fs_context_dup and smb3_cleanup_fs_context_contents should > > be aware of these new fields too. > > smb3_cleanup_fs_context_contents should be aware of these new fields too. > > Clearing in smb3_cleanup_fs_context_contents is not necessary, because > if opt_hostname != NULL, > then the pointer in server_hostname is replaced (it is pre-cleared by > kfree), respectively, everything > will be cleared by itself with the current code. > > In smb3_fs_context_dup, opt_hostname does not need to be processed, > since this variable is > essentially temporary. Immediately after parsing with the parameter, its > value goes to > server_hostname and it is no longer needed by itself. > > > Thanks, > > > >> char *UNC; > >> char *nodename; > >> char workstation_name[CIFS_MAX_WORKSTATION_LEN]; > >> > >> base-commit: bec6f00f120ea68ba584def5b7416287e7dd29a7 > >> -- > >> 2.42.2 > >> > > Apologies for the overly long subject line and unclear description. > Thanks. > -- Thanks, Steve ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication 2025-07-24 22:14 ` Steve French @ 2025-07-24 22:50 ` Steve French 2025-07-30 16:54 ` Maria Alexeeva 0 siblings, 1 reply; 16+ messages in thread From: Steve French @ 2025-07-24 22:50 UTC (permalink / raw) To: alxvmr Cc: Vitaly Chikunov, linux-cifs, Ivan Volchenko, samba-technical, pc, Tom Talpey Maria, Since this looks like it depends on a cifs-utils change, can you update your kernel patch with review comments (e.g. changing mount parm to "dfs_domain_hostname", and there were at least two others in the thread, e.g. fixing the noisy warning that the patch adds) and then show the cifs-utils change, so we can make the upcoming merge window. On Thu, Jul 24, 2025 at 5:14 PM Steve French <smfrench@gmail.com> wrote: > > I will update the mount parm name, similar to what Tom suggested to > "dfs_domain_hostname" to be less confusing. > > Let me know if you had a v2 of the patch with other changes > > On Thu, Jul 3, 2025 at 8:00 AM Maria Alexeeva via samba-technical > <samba-technical@lists.samba.org> wrote: > > > > On 6/14/25 07:42, Vitaly Chikunov wrote: > > > Maria, > > > > > > On Fri, May 16, 2025 at 07:22:01PM +0400, Maria Alexeeva wrote: > > >> Paths to domain-based dfs resources are defined using the domain name > > >> of the server in the format: > > >> \\DOMAIN.NAME>\<dfsroot>\<path> > > >> > > >> The CIFS module, when requesting a TGS, uses the server name > > >> (<DOMAIN.NAME>) it obtained from the UNC for the initial connection. > > >> It then composes an SPN that does not match any entities > > >> in the domain because it is the domain name itself. > > > For a casual reader like me it's hard to understand (this abbreviation > > > filled message) what it's all about. And why we can't just change system > > > hostname for example. > > > > This option is needed to transfer the real name of the server to which > > the connection is taking place, > > when using the UNC path in the form of domain-based DFS. The system > > hostname has nothing to do with it. > > > > > Also, the summary (subject) message is 180 character which is way above > > > 75 characters suggested in submitting-patches.rst. > > > > > >> To eliminate this behavior, a hostname option is added, which is > > >> the name of the server to connect to and is used in composing the SPN. > > >> In the future this option will be used in the cifs-utils development. > > >> > > >> Suggested-by: Ivan Volchenko <ivolchenko86@gmail.com> > > >> Signed-off-by: Maria Alexeeva <alxvmr@altlinux.org> > > >> --- > > >> fs/smb/client/fs_context.c | 35 +++++++++++++++++++++++++++++------ > > >> fs/smb/client/fs_context.h | 3 +++ > > >> 2 files changed, 32 insertions(+), 6 deletions(-) > > >> > > >> diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c > > >> index a634a34d4086..74de0a9de664 100644 > > >> --- a/fs/smb/client/fs_context.c > > >> +++ b/fs/smb/client/fs_context.c > > >> @@ -177,6 +177,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { > > >> fsparam_string("password2", Opt_pass2), > > >> 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), > > >> @@ -825,16 +826,23 @@ 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; > > > I am not familiar with the smb codebase but are you sure this will not > > > cause a race? > > > > The race condition will not occur. > > ctx->server_hostname is also used in smb3_parse_devname inside > > smb3_fs_context_parse_param. > > smb3_fs_context_parse_param is called earlier than the updated > > smb3_fs_context_validate, which is called inside smb3_get_tree: > > > > static const struct fs_context_operations smb3_fs_context_ops = { > > .free = smb3_fs_context_free, > > .parse_param = smb3_fs_context_parse_param, > > .parse_monolithic = smb3_fs_context_parse_monolithic, > > .get_tree = smb3_get_tree, > > .reconfigure = smb3_reconfigure, > > }; > > > > >> + 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; > > >> } > > >> @@ -1518,6 +1526,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 9e83302ce4b8..cf0478b1eff9 100644 > > >> --- a/fs/smb/client/fs_context.h > > >> +++ b/fs/smb/client/fs_context.h > > >> @@ -184,6 +184,7 @@ enum cifs_param { > > >> Opt_pass, > > >> Opt_pass2, > > >> Opt_ip, > > >> + Opt_hostname, > > >> Opt_domain, > > >> Opt_srcaddr, > > >> Opt_iocharset, > > >> @@ -214,6 +215,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; > > >> @@ -226,6 +228,7 @@ struct smb3_fs_context { > > >> char *domainname; > > >> char *source; > > >> char *server_hostname; > > >> + char *opt_hostname; > > > Perhaps, smb3_fs_context_dup and smb3_cleanup_fs_context_contents should > > > be aware of these new fields too. > > > > smb3_cleanup_fs_context_contents should be aware of these new fields too. > > > > Clearing in smb3_cleanup_fs_context_contents is not necessary, because > > if opt_hostname != NULL, > > then the pointer in server_hostname is replaced (it is pre-cleared by > > kfree), respectively, everything > > will be cleared by itself with the current code. > > > > In smb3_fs_context_dup, opt_hostname does not need to be processed, > > since this variable is > > essentially temporary. Immediately after parsing with the parameter, its > > value goes to > > server_hostname and it is no longer needed by itself. > > > > > Thanks, > > > > > >> char *UNC; > > >> char *nodename; > > >> char workstation_name[CIFS_MAX_WORKSTATION_LEN]; > > >> > > >> base-commit: bec6f00f120ea68ba584def5b7416287e7dd29a7 > > >> -- > > >> 2.42.2 > > >> > > > > Apologies for the overly long subject line and unclear description. > > Thanks. > > > > > -- > Thanks, > > Steve -- Thanks, Steve ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication 2025-07-24 22:50 ` Steve French @ 2025-07-30 16:54 ` Maria Alexeeva 2025-07-30 17:03 ` [PATCH v2] fs/smb/client/fs_context: Add dfs_domain_hostname " Maria Alexeeva ` (2 more replies) 0 siblings, 3 replies; 16+ messages in thread From: Maria Alexeeva @ 2025-07-30 16:54 UTC (permalink / raw) To: Steve French Cc: pc, linux-cifs, Ivan Volchenko, samba-technical, Vitaly Chikunov, Tom Talpey Steve, It seems some of the discussion with review comments fell outside this thread (I can only find vt@altlinux.org Vitaly Chikunov's remarks). Could you please point me to where the rest of the feedback can be found (e.g., about fixing the noisy warning the patch adds and other comments)? An updated patch for fs/smb/client/fs_context has been prepared, renaming the option to dfs_domain_hostname. There's suggestion to further rename it to dfs_server_hostname - what are your thoughts on this? The patches will follow in subsequent messages. Thanks! On 7/25/25 02:50, Steve French via samba-technical wrote: > Maria, > Since this looks like it depends on a cifs-utils change, can you > update your kernel patch with review comments (e.g. changing mount > parm to "dfs_domain_hostname", and there were at least two others in > the thread, e.g. fixing the noisy warning that the patch adds) and > then show the cifs-utils change, so we can make the upcoming merge > window. > > On Thu, Jul 24, 2025 at 5:14 PM Steve French <smfrench@gmail.com> wrote: >> >> I will update the mount parm name, similar to what Tom suggested to >> "dfs_domain_hostname" to be less confusing. >> >> Let me know if you had a v2 of the patch with other changes >> >> On Thu, Jul 3, 2025 at 8:00 AM Maria Alexeeva via samba-technical >> <samba-technical@lists.samba.org> wrote: >>> >>> On 6/14/25 07:42, Vitaly Chikunov wrote: >>>> Maria, >>>> >>>> On Fri, May 16, 2025 at 07:22:01PM +0400, Maria Alexeeva wrote: >>>>> Paths to domain-based dfs resources are defined using the domain name >>>>> of the server in the format: >>>>> \\DOMAIN.NAME>\<dfsroot>\<path> >>>>> >>>>> The CIFS module, when requesting a TGS, uses the server name >>>>> (<DOMAIN.NAME>) it obtained from the UNC for the initial connection. >>>>> It then composes an SPN that does not match any entities >>>>> in the domain because it is the domain name itself. >>>> For a casual reader like me it's hard to understand (this abbreviation >>>> filled message) what it's all about. And why we can't just change system >>>> hostname for example. >>> >>> This option is needed to transfer the real name of the server to which >>> the connection is taking place, >>> when using the UNC path in the form of domain-based DFS. The system >>> hostname has nothing to do with it. >>> >>>> Also, the summary (subject) message is 180 character which is way above >>>> 75 characters suggested in submitting-patches.rst. >>>> >>>>> To eliminate this behavior, a hostname option is added, which is >>>>> the name of the server to connect to and is used in composing the SPN. >>>>> In the future this option will be used in the cifs-utils development. >>>>> >>>>> Suggested-by: Ivan Volchenko <ivolchenko86@gmail.com> >>>>> Signed-off-by: Maria Alexeeva <alxvmr@altlinux.org> >>>>> --- >>>>> fs/smb/client/fs_context.c | 35 +++++++++++++++++++++++++++++------ >>>>> fs/smb/client/fs_context.h | 3 +++ >>>>> 2 files changed, 32 insertions(+), 6 deletions(-) >>>>> >>>>> diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c >>>>> index a634a34d4086..74de0a9de664 100644 >>>>> --- a/fs/smb/client/fs_context.c >>>>> +++ b/fs/smb/client/fs_context.c >>>>> @@ -177,6 +177,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { >>>>> fsparam_string("password2", Opt_pass2), >>>>> 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), >>>>> @@ -825,16 +826,23 @@ 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; >>>> I am not familiar with the smb codebase but are you sure this will not >>>> cause a race? >>> >>> The race condition will not occur. >>> ctx->server_hostname is also used in smb3_parse_devname inside >>> smb3_fs_context_parse_param. >>> smb3_fs_context_parse_param is called earlier than the updated >>> smb3_fs_context_validate, which is called inside smb3_get_tree: >>> >>> static const struct fs_context_operations smb3_fs_context_ops = { >>> .free = smb3_fs_context_free, >>> .parse_param = smb3_fs_context_parse_param, >>> .parse_monolithic = smb3_fs_context_parse_monolithic, >>> .get_tree = smb3_get_tree, >>> .reconfigure = smb3_reconfigure, >>> }; >>> >>>>> + 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; >>>>> } >>>>> @@ -1518,6 +1526,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 9e83302ce4b8..cf0478b1eff9 100644 >>>>> --- a/fs/smb/client/fs_context.h >>>>> +++ b/fs/smb/client/fs_context.h >>>>> @@ -184,6 +184,7 @@ enum cifs_param { >>>>> Opt_pass, >>>>> Opt_pass2, >>>>> Opt_ip, >>>>> + Opt_hostname, >>>>> Opt_domain, >>>>> Opt_srcaddr, >>>>> Opt_iocharset, >>>>> @@ -214,6 +215,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; >>>>> @@ -226,6 +228,7 @@ struct smb3_fs_context { >>>>> char *domainname; >>>>> char *source; >>>>> char *server_hostname; >>>>> + char *opt_hostname; >>>> Perhaps, smb3_fs_context_dup and smb3_cleanup_fs_context_contents should >>>> be aware of these new fields too. >>> >>> smb3_cleanup_fs_context_contents should be aware of these new fields too. >>> >>> Clearing in smb3_cleanup_fs_context_contents is not necessary, because >>> if opt_hostname != NULL, >>> then the pointer in server_hostname is replaced (it is pre-cleared by >>> kfree), respectively, everything >>> will be cleared by itself with the current code. >>> >>> In smb3_fs_context_dup, opt_hostname does not need to be processed, >>> since this variable is >>> essentially temporary. Immediately after parsing with the parameter, its >>> value goes to >>> server_hostname and it is no longer needed by itself. >>> >>>> Thanks, >>>> >>>>> char *UNC; >>>>> char *nodename; >>>>> char workstation_name[CIFS_MAX_WORKSTATION_LEN]; >>>>> >>>>> base-commit: bec6f00f120ea68ba584def5b7416287e7dd29a7 >>>>> -- >>>>> 2.42.2 >>>>> >>> >>> Apologies for the overly long subject line and unclear description. >>> Thanks. >>> >> >> >> -- >> Thanks, >> >> Steve > > > ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2] fs/smb/client/fs_context: Add dfs_domain_hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication 2025-07-30 16:54 ` Maria Alexeeva @ 2025-07-30 17:03 ` Maria Alexeeva 2025-07-30 17:09 ` [PATCH] mount.cifs: add support for domain-based DFS targets with Kerberos via hostname resolution Maria Alexeeva 2025-07-31 14:00 ` [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication Steve French 2 siblings, 0 replies; 16+ messages in thread From: Maria Alexeeva @ 2025-07-30 17:03 UTC (permalink / raw) To: smfrench Cc: pc, linux-cifs, ivolchenko86, samba-technical, vt, tom, Maria Alexeeva Paths to domain-based dfs resources are defined using the domain name of the server in the format: \DOMAIN.NAME>\<dfsroot>\<path> The CIFS module, when requesting a TGS, uses the server name (<DOMAIN.NAME>) it obtained from the UNC for the initial connection. It then composes an SPN that does not match any entities in the domain because it is the domain name itself. To eliminate this behavior, a dfs_domain_hostname option is added, which is the name of the server to connect to and is used in composing the SPN. In the future this option will be used in the cifs-utils development. Suggested-by: Ivan Volchenko <ivolchenko86@gmail.com> Signed-off-by: Maria Alexeeva <alxvmr@altlinux.org> --- fs/smb/client/fs_context.c | 35 +++++++++++++++++++++++++++++------ fs/smb/client/fs_context.h | 3 +++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index 59ccc2229ab3..27df14ea2ced 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -177,6 +177,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_string("password2", Opt_pass2), fsparam_string("ip", Opt_ip), fsparam_string("addr", Opt_ip), + fsparam_string("dfs_domain_hostname", Opt_dfs_domain_hostname), fsparam_string("domain", Opt_domain), fsparam_string("dom", Opt_domain), fsparam_string("srcaddr", Opt_srcaddr), @@ -825,16 +826,23 @@ static int smb3_fs_context_validate(struct fs_context *fc) return -ENOENT; } + if (ctx->got_dfs_domain_hostname) { + kfree(ctx->server_hostname); + ctx->server_hostname = ctx->dfs_domain_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; } @@ -1518,6 +1526,21 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, } ctx->got_ip = true; break; + case Opt_dfs_domain_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->dfs_domain_hostname); + ctx->dfs_domain_hostname = kstrdup(param->string, GFP_KERNEL); + if (ctx->dfs_domain_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_dfs_domain_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 9e83302ce4b8..da6193cffd09 100644 --- a/fs/smb/client/fs_context.h +++ b/fs/smb/client/fs_context.h @@ -184,6 +184,7 @@ enum cifs_param { Opt_pass, Opt_pass2, Opt_ip, + Opt_dfs_domain_hostname, Opt_domain, Opt_srcaddr, Opt_iocharset, @@ -214,6 +215,7 @@ struct smb3_fs_context { bool gid_specified; bool sloppy; bool got_ip; + bool got_dfs_domain_hostname; bool got_version; bool got_rsize; bool got_wsize; @@ -226,6 +228,7 @@ struct smb3_fs_context { char *domainname; char *source; char *server_hostname; + char *dfs_domain_hostname; char *UNC; char *nodename; char workstation_name[CIFS_MAX_WORKSTATION_LEN]; base-commit: 038d61fd642278bab63ee8ef722c50d10ab01e8f -- 2.50.1 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH] mount.cifs: add support for domain-based DFS targets with Kerberos via hostname resolution 2025-07-30 16:54 ` Maria Alexeeva 2025-07-30 17:03 ` [PATCH v2] fs/smb/client/fs_context: Add dfs_domain_hostname " Maria Alexeeva @ 2025-07-30 17:09 ` Maria Alexeeva 2025-07-31 14:00 ` [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication Steve French 2 siblings, 0 replies; 16+ messages in thread From: Maria Alexeeva @ 2025-07-30 17:09 UTC (permalink / raw) To: smfrench Cc: pc, linux-cifs, ivolchenko86, samba-technical, vt, tom, Maria Alexeeva Enhance the mount.cifs utility to support mounting of domain-based DFS shares using Kerberos authentication by enabling hostname-based resolution of DFS targets. Previously, only IP addresses were resolved and passed to the kernel, which prevented Kerberos from functioning properly with DFS shares that require hostname-based access. This patch: 1. Adds hostlist support to track hostnames alongside resolved IP addresses. 2. Modifies resolve_host() into resolve_host_with_names() to collect both IPs and associated DNS names. 3. Updates mount retry logic to iterate over hostnames as well as addresses. 4. Appends hostname= mount option when available to allow the kernel to use hostname for Kerberos validation. 5. Includes fallback to existing logic when Kerberos is not used. 6. Introduces helper iterlist() to simplify parsing of comma-separated lists. 7. Buffer size fix for AD site names: Updates the buffer size used to store Active Directory site names from MAXCDNAME to MAXLABEL, in line with Active Directory specifications. According to [MS-ADTS] and RFC 1035, site names in AD are limited to DNS label size (MAXLABEL, 63 bytes), not full domain name size (MAXCDNAME, 255 bytes). Suggested-by: Ivan Volchenko <ivolchenko86@gmail.com> Signed-off-by: Maria Alexeeva <alxvmr@altlinux.org> --- cldap_ping.c | 2 +- cldap_ping.h | 2 +- mount.cifs.c | 28 +++++++++++++++++----------- resolve_host.c | 43 ++++++++++++++++++++++++++++++++++++------- resolve_host.h | 5 +++++ util.c | 14 ++++++++++++++ util.h | 1 + 7 files changed, 75 insertions(+), 20 deletions(-) diff --git a/cldap_ping.c b/cldap_ping.c index 5c20f84..e8cba50 100644 --- a/cldap_ping.c +++ b/cldap_ping.c @@ -280,7 +280,7 @@ int netlogon_get_client_site(char *netlogon_response, size_t netlogon_size, char for (int i=0; i < 8; i++) { // iterate over DnsForestName, DnsDomainName, NetbiosDomainName, NetbiosComputerName, UserName, DcSiteName // to finally get to our desired ClientSiteName field - if (read_dns_string(netlogon_response, netlogon_size, sitename, MAXCDNAME, &offset) < 0) { + if (read_dns_string(netlogon_response, netlogon_size, sitename, MAXLABEL, &offset) < 0) { return CLDAP_PING_PARSE_ERROR_NETLOGON; } } diff --git a/cldap_ping.h b/cldap_ping.h index 9a23e72..a15a14c 100644 --- a/cldap_ping.h +++ b/cldap_ping.h @@ -8,7 +8,7 @@ // returns CLDAP_PING_TRYNEXT if you should use another dc // any other error code < 0 is a fatal error -// site_name must be of MAXCDNAME size! +// site_name must be of MAXLABEL size! int cldap_ping(char *domain, sa_family_t family, void *addr, char *site_name); #endif /* _CLDAP_PING_H_ */ diff --git a/mount.cifs.c b/mount.cifs.c index 1923913..d50af71 100644 --- a/mount.cifs.c +++ b/mount.cifs.c @@ -190,6 +190,7 @@ struct parsed_mount_info { char password[MOUNT_PASSWD_SIZE + 1]; char password2[MOUNT_PASSWD_SIZE + 1]; char addrlist[MAX_ADDR_LIST_LEN]; + char hostlist[MAX_HOST_LIST_LEN]; unsigned int got_user:1; unsigned int got_password:1; unsigned int got_password2:1; @@ -1939,6 +1940,7 @@ assemble_mountinfo(struct parsed_mount_info *parsed_info, { int rc; char *newopts = NULL; + char *hostlist; rc = drop_capabilities(0); if (rc) @@ -1983,8 +1985,10 @@ assemble_mountinfo(struct parsed_mount_info *parsed_info, if (rc) goto assemble_exit; + parsed_info->hostlist[0] = '\0'; if (parsed_info->addrlist[0] == '\0') { - rc = resolve_host(parsed_info->host, parsed_info->addrlist); + hostlist = parsed_info->is_krb5 ? parsed_info->hostlist : NULL; + rc = resolve_host_with_names(parsed_info->host, parsed_info->addrlist, hostlist); if (rc == 0 && parsed_info->verboseflag) fprintf(stderr, "Host \"%s\" resolved to the following IP addresses: %s\n", parsed_info->host, parsed_info->addrlist); } @@ -2142,6 +2146,7 @@ int main(int argc, char **argv) char *options = NULL; char *orig_dev = NULL; char *currentaddress, *nextaddress; + char *currenthost, *nexthost; char *value = NULL; char *ep = NULL; int rc = 0; @@ -2300,12 +2305,14 @@ assemble_retry: } currentaddress = parsed_info->addrlist; - nextaddress = strchr(currentaddress, ','); - if (nextaddress) - *nextaddress++ = '\0'; + nextaddress = NULL; + currenthost = parsed_info->hostlist; + nexthost = NULL; mount_retry: options[0] = '\0'; + iterlist(¤taddress, &nextaddress); + iterlist(¤thost, &nexthost); if (!currentaddress) { fprintf(stderr, "Unable to find suitable address.\n"); rc = parsed_info->nofail ? 0 : EX_FAIL; @@ -2329,9 +2336,14 @@ mount_retry: strlcat(options, parsed_info->prefix, options_size); } - if (sloppy) + if (sloppy || currenthost) strlcat(options, ",sloppy", options_size); + if (currenthost) { + strlcat(options, ",dfs_domain_hostname=", options_size); + strlcat(options, currenthost, options_size); + } + if (parsed_info->verboseflag) fprintf(stderr, "%s kernel mount options: %s", thisprogram, options); @@ -2378,12 +2390,6 @@ mount_retry: fprintf(stderr, "mount error(%d): could not connect to %s", errno, currentaddress); } - currentaddress = nextaddress; - if (currentaddress) { - nextaddress = strchr(currentaddress, ','); - if (nextaddress) - *nextaddress++ = '\0'; - } goto mount_retry; case ENODEV: fprintf(stderr, diff --git a/resolve_host.c b/resolve_host.c index 918c6ad..5b6aed8 100644 --- a/resolve_host.c +++ b/resolve_host.c @@ -37,7 +37,7 @@ /* * resolve hostname to comma-separated list of address(es) */ -int resolve_host(const char *host, char *addrstr) { +int resolve_host_with_names(const char *host, char *addrstr, char *hoststr) { int rc; /* 10 for max width of decimal scopeid */ char tmpbuf[NI_MAXHOST + 1 + 10 + 1]; @@ -114,7 +114,7 @@ int resolve_host(const char *host, char *addrstr) { // Is this a DFS domain where we need to do a cldap ping to find the closest node? - if (count_v4 > 1 || count_v6 > 1) { + if (count_v4 > 1 || count_v6 > 1 || hoststr) { int res; ns_msg global_domain_handle; unsigned char global_domain_lookup[4096]; @@ -122,6 +122,8 @@ int resolve_host(const char *host, char *addrstr) { unsigned char site_domain_lookup[4096]; char dname[MAXCDNAME]; int srv_cnt; + int number_addresses = 0; + const char *hostname; res = res_init(); if (res != 0) @@ -144,7 +146,7 @@ int resolve_host(const char *host, char *addrstr) { // No or just one DC we are done if (srv_cnt < 2) - goto resolve_host_out; + goto resolve_host_global; char site_name[MAXCDNAME]; site_name[0] = '\0'; @@ -200,7 +202,6 @@ int resolve_host(const char *host, char *addrstr) { if (res < 0) goto resolve_host_out; - int number_addresses = 0; for (int i = 0; i < ns_msg_count(site_domain_handle, ns_s_ar); i++) { if (i > MAX_ADDRESSES) break; @@ -214,6 +215,7 @@ int resolve_host(const char *host, char *addrstr) { case ns_t_aaaa: if (ns_rr_rdlen(rr) != NS_IN6ADDRSZ) continue; + hostname = ns_rr_name(rr); ipaddr = inet_ntop(AF_INET6, ns_rr_rdata(rr), tmpbuf, sizeof(tmpbuf)); if (!ipaddr) { @@ -224,6 +226,7 @@ int resolve_host(const char *host, char *addrstr) { case ns_t_a: if (ns_rr_rdlen(rr) != NS_INADDRSZ) continue; + hostname = ns_rr_name(rr); ipaddr = inet_ntop(AF_INET, ns_rr_rdata(rr), tmpbuf, sizeof(tmpbuf)); if (!ipaddr) { @@ -237,14 +240,22 @@ int resolve_host(const char *host, char *addrstr) { number_addresses++; - if (i == 0) + if (i == 0) { *addrstr = '\0'; - else + if (hoststr) + *hoststr = '\0'; + } else { strlcat(addrstr, ",", MAX_ADDR_LIST_LEN); + if (hoststr) + strlcat(hoststr, ",", MAX_ADDR_LIST_LEN); + } strlcat(addrstr, tmpbuf, MAX_ADDR_LIST_LEN); + if (hoststr) + strlcat(hoststr, hostname, MAX_HOST_LIST_LEN); } +resolve_host_global: // Preferred site ips is now the first entry in addrstr, fill up with other sites till MAX_ADDRESS for (int i = 0; i < ns_msg_count(global_domain_handle, ns_s_ar); i++) { if (number_addresses > MAX_ADDRESSES) @@ -259,6 +270,7 @@ int resolve_host(const char *host, char *addrstr) { case ns_t_aaaa: if (ns_rr_rdlen(rr) != NS_IN6ADDRSZ) continue; + hostname = ns_rr_name(rr); ipaddr = inet_ntop(AF_INET6, ns_rr_rdata(rr), tmpbuf, sizeof(tmpbuf)); if (!ipaddr) { @@ -269,6 +281,7 @@ int resolve_host(const char *host, char *addrstr) { case ns_t_a: if (ns_rr_rdlen(rr) != NS_INADDRSZ) continue; + hostname = ns_rr_name(rr); ipaddr = inet_ntop(AF_INET, ns_rr_rdata(rr), tmpbuf, sizeof(tmpbuf)); if (!ipaddr) { @@ -280,6 +293,12 @@ int resolve_host(const char *host, char *addrstr) { continue; } + if (number_addresses == 0) { + *addrstr = '\0'; + if (hoststr) + *hoststr = '\0'; + } + char *found = strstr(addrstr, tmpbuf); if (found) { @@ -293,9 +312,15 @@ int resolve_host(const char *host, char *addrstr) { } } + if (number_addresses > 0) { + strlcat(addrstr, ",", MAX_ADDR_LIST_LEN); + if (hoststr) + strlcat(hoststr, ",", MAX_HOST_LIST_LEN); + } number_addresses++; - strlcat(addrstr, ",", MAX_ADDR_LIST_LEN); strlcat(addrstr, tmpbuf, MAX_ADDR_LIST_LEN); + if (hoststr) + strlcat(hoststr, hostname, MAX_HOST_LIST_LEN); } } @@ -303,3 +328,7 @@ resolve_host_out: freeaddrinfo(addrlist); return rc; } + +int resolve_host(const char *host, char *addrstr) { + return resolve_host_with_names(host, addrstr, NULL); +} diff --git a/resolve_host.h b/resolve_host.h index f2b19e6..b507757 100644 --- a/resolve_host.h +++ b/resolve_host.h @@ -22,6 +22,7 @@ #define _RESOLVE_HOST_H_ #include <arpa/inet.h> +#include <resolv.h> /* currently maximum length of IPv6 address string */ #define MAX_ADDRESS_LEN INET6_ADDRSTRLEN @@ -31,6 +32,10 @@ /* limit list of addresses to MAX_ADDRESSES max-size addrs */ #define MAX_ADDR_LIST_LEN ((MAX_ADDRESS_LEN + 1) * MAX_ADDRESSES) +/* limit list of hostnames to MAX_ADDRESSES max-size names */ +#define MAX_HOST_LIST_LEN ((MAXCDNAME + 1) * MAX_ADDRESSES) + +extern int resolve_host_with_names(const char *host, char *addrstr, char *hoststr); extern int resolve_host(const char *host, char *addrstr); #endif /* _RESOLVE_HOST_H_ */ diff --git a/util.c b/util.c index 546f284..c722df5 100644 --- a/util.c +++ b/util.c @@ -83,3 +83,17 @@ getusername(uid_t uid) return username; } +int +iterlist(char **curr, char **next) { + if (!*curr || *curr[0] == '\0' || *curr == *next) { + *curr = *next = NULL; + return 0; + } + *curr = *next ? *next : *curr; + *next = strchr(*curr, ','); + if (*next) + *(*next)++ = '\0'; + else + *next = *curr; + return 1; +} diff --git a/util.h b/util.h index 2864130..59e4200 100644 --- a/util.h +++ b/util.h @@ -29,5 +29,6 @@ extern size_t strlcpy(char *d, const char *s, size_t bufsize); extern size_t strlcat(char *d, const char *s, size_t bufsize); extern char *getusername(uid_t uid); +extern int iterlist(char **curr, char **next); #endif /* _LIBUTIL_H */ base-commit: edac7178bec9520fb57d14946e67f5dd33b82d43 -- 2.50.1 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication 2025-07-30 16:54 ` Maria Alexeeva 2025-07-30 17:03 ` [PATCH v2] fs/smb/client/fs_context: Add dfs_domain_hostname " Maria Alexeeva 2025-07-30 17:09 ` [PATCH] mount.cifs: add support for domain-based DFS targets with Kerberos via hostname resolution Maria Alexeeva @ 2025-07-31 14:00 ` Steve French 2025-09-08 13:24 ` Maria Alexeeva 2025-12-30 16:47 ` [PATCH v3 0/1] Add hostname option for CIFS module Maria Alexeeva 2 siblings, 2 replies; 16+ messages in thread From: Steve French @ 2025-07-31 14:00 UTC (permalink / raw) To: alxvmr Cc: pc, linux-cifs, Ivan Volchenko, samba-technical, Vitaly Chikunov, Tom Talpey I don't have any strong opinion on: "dfs_server_hostname" vs "dfs_domain_hostname" whichever makes more sense. I will look to see if I can find any more threads on this in earlier email On Wed, Jul 30, 2025 at 11:54 AM Maria Alexeeva <alxvmr@altlinux.org> wrote: > > Steve, > It seems some of the discussion with review comments fell outside this > thread (I can only find vt@altlinux.org Vitaly Chikunov's remarks). > Could you please point me to where the rest of the feedback can be > found (e.g., about fixing the noisy warning the patch adds and > other comments)? > > An updated patch for fs/smb/client/fs_context has been prepared, renaming > the option to dfs_domain_hostname. There's suggestion to further rename > it to dfs_server_hostname - what are your thoughts on this? > > The patches will follow in subsequent messages. > > Thanks! > > On 7/25/25 02:50, Steve French via samba-technical wrote: > > Maria, > > Since this looks like it depends on a cifs-utils change, can you > > update your kernel patch with review comments (e.g. changing mount > > parm to "dfs_domain_hostname", and there were at least two others in > > the thread, e.g. fixing the noisy warning that the patch adds) and > > then show the cifs-utils change, so we can make the upcoming merge > > window. > > > > On Thu, Jul 24, 2025 at 5:14 PM Steve French <smfrench@gmail.com> wrote: > >> > >> I will update the mount parm name, similar to what Tom suggested to > >> "dfs_domain_hostname" to be less confusing. > >> > >> Let me know if you had a v2 of the patch with other changes > >> > >> On Thu, Jul 3, 2025 at 8:00 AM Maria Alexeeva via samba-technical > >> <samba-technical@lists.samba.org> wrote: > >>> > >>> On 6/14/25 07:42, Vitaly Chikunov wrote: > >>>> Maria, > >>>> > >>>> On Fri, May 16, 2025 at 07:22:01PM +0400, Maria Alexeeva wrote: > >>>>> Paths to domain-based dfs resources are defined using the domain name > >>>>> of the server in the format: > >>>>> \\DOMAIN.NAME>\<dfsroot>\<path> > >>>>> > >>>>> The CIFS module, when requesting a TGS, uses the server name > >>>>> (<DOMAIN.NAME>) it obtained from the UNC for the initial connection. > >>>>> It then composes an SPN that does not match any entities > >>>>> in the domain because it is the domain name itself. > >>>> For a casual reader like me it's hard to understand (this abbreviation > >>>> filled message) what it's all about. And why we can't just change system > >>>> hostname for example. > >>> > >>> This option is needed to transfer the real name of the server to which > >>> the connection is taking place, > >>> when using the UNC path in the form of domain-based DFS. The system > >>> hostname has nothing to do with it. > >>> > >>>> Also, the summary (subject) message is 180 character which is way above > >>>> 75 characters suggested in submitting-patches.rst. > >>>> > >>>>> To eliminate this behavior, a hostname option is added, which is > >>>>> the name of the server to connect to and is used in composing the SPN. > >>>>> In the future this option will be used in the cifs-utils development. > >>>>> > >>>>> Suggested-by: Ivan Volchenko <ivolchenko86@gmail.com> > >>>>> Signed-off-by: Maria Alexeeva <alxvmr@altlinux.org> > >>>>> --- > >>>>> fs/smb/client/fs_context.c | 35 +++++++++++++++++++++++++++++------ > >>>>> fs/smb/client/fs_context.h | 3 +++ > >>>>> 2 files changed, 32 insertions(+), 6 deletions(-) > >>>>> > >>>>> diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c > >>>>> index a634a34d4086..74de0a9de664 100644 > >>>>> --- a/fs/smb/client/fs_context.c > >>>>> +++ b/fs/smb/client/fs_context.c > >>>>> @@ -177,6 +177,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { > >>>>> fsparam_string("password2", Opt_pass2), > >>>>> 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), > >>>>> @@ -825,16 +826,23 @@ 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; > >>>> I am not familiar with the smb codebase but are you sure this will not > >>>> cause a race? > >>> > >>> The race condition will not occur. > >>> ctx->server_hostname is also used in smb3_parse_devname inside > >>> smb3_fs_context_parse_param. > >>> smb3_fs_context_parse_param is called earlier than the updated > >>> smb3_fs_context_validate, which is called inside smb3_get_tree: > >>> > >>> static const struct fs_context_operations smb3_fs_context_ops = { > >>> .free = smb3_fs_context_free, > >>> .parse_param = smb3_fs_context_parse_param, > >>> .parse_monolithic = smb3_fs_context_parse_monolithic, > >>> .get_tree = smb3_get_tree, > >>> .reconfigure = smb3_reconfigure, > >>> }; > >>> > >>>>> + 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; > >>>>> } > >>>>> @@ -1518,6 +1526,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 9e83302ce4b8..cf0478b1eff9 100644 > >>>>> --- a/fs/smb/client/fs_context.h > >>>>> +++ b/fs/smb/client/fs_context.h > >>>>> @@ -184,6 +184,7 @@ enum cifs_param { > >>>>> Opt_pass, > >>>>> Opt_pass2, > >>>>> Opt_ip, > >>>>> + Opt_hostname, > >>>>> Opt_domain, > >>>>> Opt_srcaddr, > >>>>> Opt_iocharset, > >>>>> @@ -214,6 +215,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; > >>>>> @@ -226,6 +228,7 @@ struct smb3_fs_context { > >>>>> char *domainname; > >>>>> char *source; > >>>>> char *server_hostname; > >>>>> + char *opt_hostname; > >>>> Perhaps, smb3_fs_context_dup and smb3_cleanup_fs_context_contents should > >>>> be aware of these new fields too. > >>> > >>> smb3_cleanup_fs_context_contents should be aware of these new fields too. > >>> > >>> Clearing in smb3_cleanup_fs_context_contents is not necessary, because > >>> if opt_hostname != NULL, > >>> then the pointer in server_hostname is replaced (it is pre-cleared by > >>> kfree), respectively, everything > >>> will be cleared by itself with the current code. > >>> > >>> In smb3_fs_context_dup, opt_hostname does not need to be processed, > >>> since this variable is > >>> essentially temporary. Immediately after parsing with the parameter, its > >>> value goes to > >>> server_hostname and it is no longer needed by itself. > >>> > >>>> Thanks, > >>>> > >>>>> char *UNC; > >>>>> char *nodename; > >>>>> char workstation_name[CIFS_MAX_WORKSTATION_LEN]; > >>>>> > >>>>> base-commit: bec6f00f120ea68ba584def5b7416287e7dd29a7 > >>>>> -- > >>>>> 2.42.2 > >>>>> > >>> > >>> Apologies for the overly long subject line and unclear description. > >>> Thanks. > >>> > >> > >> > >> -- > >> Thanks, > >> > >> Steve > > > > > > > -- Thanks, Steve ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication 2025-07-31 14:00 ` [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication Steve French @ 2025-09-08 13:24 ` Maria Alexeeva 2025-12-30 16:47 ` [PATCH v3 0/1] Add hostname option for CIFS module Maria Alexeeva 1 sibling, 0 replies; 16+ messages in thread From: Maria Alexeeva @ 2025-09-08 13:24 UTC (permalink / raw) To: Steve French Cc: pc, linux-cifs, Ivan Volchenko, samba-technical, Tom Talpey, Vitaly Chikunov Good day! Could you please let me know if you have managed to find the messages with comments/feedback? This is important for us to make the corresponding changes to the proposed patches. On 7/31/25 18:00, Steve French via samba-technical wrote: > I don't have any strong opinion on: "dfs_server_hostname" vs > "dfs_domain_hostname" whichever makes more sense. > > I will look to see if I can find any more threads on this in earlier email > > On Wed, Jul 30, 2025 at 11:54 AM Maria Alexeeva <alxvmr@altlinux.org> wrote: >> >> Steve, >> It seems some of the discussion with review comments fell outside this >> thread (I can only find vt@altlinux.org Vitaly Chikunov's remarks). >> Could you please point me to where the rest of the feedback can be >> found (e.g., about fixing the noisy warning the patch adds and >> other comments)? >> >> An updated patch for fs/smb/client/fs_context has been prepared, renaming >> the option to dfs_domain_hostname. There's suggestion to further rename >> it to dfs_server_hostname - what are your thoughts on this? >> >> The patches will follow in subsequent messages. >> >> Thanks! >> >> On 7/25/25 02:50, Steve French via samba-technical wrote: >>> Maria, >>> Since this looks like it depends on a cifs-utils change, can you >>> update your kernel patch with review comments (e.g. changing mount >>> parm to "dfs_domain_hostname", and there were at least two others in >>> the thread, e.g. fixing the noisy warning that the patch adds) and >>> then show the cifs-utils change, so we can make the upcoming merge >>> window. >>> >>> On Thu, Jul 24, 2025 at 5:14 PM Steve French <smfrench@gmail.com> wrote: >>>> >>>> I will update the mount parm name, similar to what Tom suggested to >>>> "dfs_domain_hostname" to be less confusing. >>>> >>>> Let me know if you had a v2 of the patch with other changes ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 0/1] Add hostname option for CIFS module 2025-07-31 14:00 ` [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication Steve French 2025-09-08 13:24 ` Maria Alexeeva @ 2025-12-30 16:47 ` Maria Alexeeva 2025-12-30 16:47 ` [PATCH v3 1/1] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication Maria Alexeeva 2025-12-30 16:50 ` [PATCH v2] mount.cifs: add support for domain-based DFS targets with Kerberos via hostname resolution Maria Alexeeva 1 sibling, 2 replies; 16+ messages in thread From: Maria Alexeeva @ 2025-12-30 16:47 UTC (permalink / raw) To: smfrench; +Cc: pc, linux-cifs, samba-technical, tom, vt, Maria Alexeeva Good afternoon! Unfortunately, our correspondence was interrupted at the stage of discussing the shortcomings of the previous patch versions - we still have not received the promised comments and suggestions from you. We have decided to revert to using the name hostname for this option, as its application is not limited solely to domain-based DFS resources. For example, it can also be used for mounting via CNAME. We will send the updated versions of the patches for both the CIFS module and cifs-utils in the following emails. Maria Alexeeva (1): fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication fs/smb/client/fs_context.c | 35 +++++++++++++++++++++++++++++------ fs/smb/client/fs_context.h | 3 +++ 2 files changed, 32 insertions(+), 6 deletions(-) base-commit: f8f9c1f4d0c7a64600e2ca312dec824a0bc2f1da -- 2.50.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 1/1] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication 2025-12-30 16:47 ` [PATCH v3 0/1] Add hostname option for CIFS module Maria Alexeeva @ 2025-12-30 16:47 ` Maria Alexeeva 2026-02-23 18:02 ` Steve French 2026-02-27 18:46 ` Paulo Alcantara 2025-12-30 16:50 ` [PATCH v2] mount.cifs: add support for domain-based DFS targets with Kerberos via hostname resolution Maria Alexeeva 1 sibling, 2 replies; 16+ messages in thread From: Maria Alexeeva @ 2025-12-30 16:47 UTC (permalink / raw) To: smfrench Cc: pc, linux-cifs, samba-technical, tom, vt, Maria Alexeeva, Ivan Volchenko Paths to domain-based dfs resources are defined using the domain name of the server in the format: \\<DOMAIN.NAME>\<dfsroot>\<path> The CIFS module, when requesting a TGS, uses the server name (<DOMAIN.NAME>) it obtained from the UNC for the initial connection. It then composes an SPN that does not match any entities in the domain because it is the domain name itself. To eliminate this behavior, a hostname option is added, which is the name of the server to connect to and is used in composing the SPN. In the future this option will be used in the cifs-utils development. Suggested-by: Ivan Volchenko <ivolchenko86@gmail.com> Signed-off-by: Maria Alexeeva <alxvmr@altlinux.org> --- fs/smb/client/fs_context.c | 35 +++++++++++++++++++++++++++++------ fs/smb/client/fs_context.h | 3 +++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index d4291d3a9a48..f0d1895fe4bb 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -177,6 +177,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_string("password2", Opt_pass2), 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), @@ -866,16 +867,23 @@ 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; } @@ -1591,6 +1599,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 7af7cbbe4208..ff1a04661ef5 100644 --- a/fs/smb/client/fs_context.h +++ b/fs/smb/client/fs_context.h @@ -184,6 +184,7 @@ enum cifs_param { Opt_pass, Opt_pass2, Opt_ip, + Opt_hostname, Opt_domain, Opt_srcaddr, Opt_iocharset, @@ -214,6 +215,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; @@ -226,6 +228,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]; -- 2.50.1 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v3 1/1] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication 2025-12-30 16:47 ` [PATCH v3 1/1] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication Maria Alexeeva @ 2026-02-23 18:02 ` Steve French 2026-02-27 18:46 ` Paulo Alcantara 1 sibling, 0 replies; 16+ messages in thread From: Steve French @ 2026-02-23 18:02 UTC (permalink / raw) To: Maria Alexeeva; +Cc: pc, linux-cifs, samba-technical, tom, vt, Ivan Volchenko tentatively merged into cifs-2.6.git for-next pending more review and testing. Maria, Have you verified that behavior hasn't changed when hostname not specified on mount - the fallback to default hostname code was a little confusing to read? On Tue, Dec 30, 2025 at 10:48 AM Maria Alexeeva <alxvmr@altlinux.org> wrote: > > Paths to domain-based dfs resources are defined using the domain name > of the server in the format: > \\<DOMAIN.NAME>\<dfsroot>\<path> > > The CIFS module, when requesting a TGS, uses the server name > (<DOMAIN.NAME>) it obtained from the UNC for the initial connection. > It then composes an SPN that does not match any entities > in the domain because it is the domain name itself. > > To eliminate this behavior, a hostname option is added, which is > the name of the server to connect to and is used in composing the SPN. > In the future this option will be used in the cifs-utils development. > > Suggested-by: Ivan Volchenko <ivolchenko86@gmail.com> > Signed-off-by: Maria Alexeeva <alxvmr@altlinux.org> > --- > fs/smb/client/fs_context.c | 35 +++++++++++++++++++++++++++++------ > fs/smb/client/fs_context.h | 3 +++ > 2 files changed, 32 insertions(+), 6 deletions(-) > > diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c > index d4291d3a9a48..f0d1895fe4bb 100644 > --- a/fs/smb/client/fs_context.c > +++ b/fs/smb/client/fs_context.c > @@ -177,6 +177,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { > fsparam_string("password2", Opt_pass2), > 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), > @@ -866,16 +867,23 @@ 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; > } > @@ -1591,6 +1599,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 7af7cbbe4208..ff1a04661ef5 100644 > --- a/fs/smb/client/fs_context.h > +++ b/fs/smb/client/fs_context.h > @@ -184,6 +184,7 @@ enum cifs_param { > Opt_pass, > Opt_pass2, > Opt_ip, > + Opt_hostname, > Opt_domain, > Opt_srcaddr, > Opt_iocharset, > @@ -214,6 +215,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; > @@ -226,6 +228,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]; > -- > 2.50.1 > -- Thanks, Steve ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v3 1/1] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication 2025-12-30 16:47 ` [PATCH v3 1/1] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication Maria Alexeeva 2026-02-23 18:02 ` Steve French @ 2026-02-27 18:46 ` Paulo Alcantara [not found] ` <CAG5KTOZ6s4AjE0e66D9CMnZTP68YHzUb6p9nQKgeZeBV9ZVVBw@mail.gmail.com> 1 sibling, 1 reply; 16+ messages in thread From: Paulo Alcantara @ 2026-02-27 18:46 UTC (permalink / raw) To: Maria Alexeeva, smfrench Cc: linux-cifs, samba-technical, tom, vt, Maria Alexeeva, Ivan Volchenko Maria Alexeeva <alxvmr@altlinux.org> writes: > Paths to domain-based dfs resources are defined using the domain name > of the server in the format: > \\<DOMAIN.NAME>\<dfsroot>\<path> > > The CIFS module, when requesting a TGS, uses the server name > (<DOMAIN.NAME>) it obtained from the UNC for the initial connection. > It then composes an SPN that does not match any entities > in the domain because it is the domain name itself. > > To eliminate this behavior, a hostname option is added, which is > the name of the server to connect to and is used in composing the SPN. > In the future this option will be used in the cifs-utils development. > > Suggested-by: Ivan Volchenko <ivolchenko86@gmail.com> > Signed-off-by: Maria Alexeeva <alxvmr@altlinux.org> > --- > fs/smb/client/fs_context.c | 35 +++++++++++++++++++++++++++++------ > fs/smb/client/fs_context.h | 3 +++ > 2 files changed, 32 insertions(+), 6 deletions(-) > > diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c > index d4291d3a9a48..f0d1895fe4bb 100644 > --- a/fs/smb/client/fs_context.c > +++ b/fs/smb/client/fs_context.c > @@ -177,6 +177,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { > fsparam_string("password2", Opt_pass2), > 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), > @@ -866,16 +867,23 @@ 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"); This is just too verbose. Consider using pr_notice_once() or cifs_dbg(VFS | ONCE, ...). > + } > + > 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; > } > @@ -1591,6 +1599,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; > + } No need to kstrdup() @param->string. You can simply replace it with ctx->opt_hostname = no_free_ptr(param->string); > + cifs_dbg(FYI, "Host name set\n"); When debugging is enabled, there will be messages logged saying that 'hostname=' has been passed, so no need for this debug message. > + 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 7af7cbbe4208..ff1a04661ef5 100644 > --- a/fs/smb/client/fs_context.h > +++ b/fs/smb/client/fs_context.h > @@ -184,6 +184,7 @@ enum cifs_param { > Opt_pass, > Opt_pass2, > Opt_ip, > + Opt_hostname, > Opt_domain, > Opt_srcaddr, > Opt_iocharset, > @@ -214,6 +215,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; > @@ -226,6 +228,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]; You're introducing a new field to smb3_fs_context structure but forgot to update smb3_fs_context_dup() and smb3_cleanup_fs_context_contents(). This will break automounts as well as leak smb3_fs_context::opt_hostname. ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <CAG5KTOZ6s4AjE0e66D9CMnZTP68YHzUb6p9nQKgeZeBV9ZVVBw@mail.gmail.com>]
* Re: [PATCH v3 1/1] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication [not found] ` <CAG5KTOZ6s4AjE0e66D9CMnZTP68YHzUb6p9nQKgeZeBV9ZVVBw@mail.gmail.com> @ 2026-02-27 21:07 ` Paulo Alcantara 0 siblings, 0 replies; 16+ messages in thread From: Paulo Alcantara @ 2026-02-27 21:07 UTC (permalink / raw) To: Иван Волченко Cc: Maria Alexeeva, smfrench, linux-cifs, samba-technical, tom, vt Иван Волченко <ivolchenko86@gmail.com> writes: > пт, 27 февр. 2026 г. в 22:46, Paulo Alcantara <pc@manguebit.org>: > >> Maria Alexeeva <alxvmr@altlinux.org> writes: >> >> > diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c >> > index d4291d3a9a48..f0d1895fe4bb 100644 >> > --- a/fs/smb/client/fs_context.c >> > +++ b/fs/smb/client/fs_context.c >> > @@ -177,6 +177,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] >> = { >> > fsparam_string("password2", Opt_pass2), >> > 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), >> > @@ -866,16 +867,23 @@ 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"); >> >> This is just too verbose. Consider using pr_notice_once() or >> cifs_dbg(VFS | ONCE, ...). >> >> > I intentionally used pr_notice() here because the message corresponds > to a mount-time event. Using pr_notice_once() would suppress the log > after the first mount, which would make subsequent mount operations > invisible in the logs. > Since this path is only executed during filesystem mount, it should > not be a high-frequency path. Can You provide scenarios > when that verbosity is the problem? Consider an DFS mount with hundreds of DFS links. For every DFS link accessed and automounted, this message would be get logged for every mount. Note that the automount will inherit parent mount's fs context, hence it will have @got_opt_hostname set to true in the new fs context. >> > + } >> > + >> > 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; >> > } >> > @@ -1591,6 +1599,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; >> > + } >> >> No need to kstrdup() @param->string. You can simply replace it with >> >> ctx->opt_hostname = no_free_ptr(param->string); >> >> > + cifs_dbg(FYI, "Host name set\n"); >> >> When debugging is enabled, there will be messages logged saying that >> 'hostname=' has been passed, so no need for this debug message. >> >> > I use kstrdup similar to other options processing code and to simplify > further > processing of the replaced "server_hostname" field (see below). > I will think about no_free_ptr if it's that important. Is it? This is an unnecessary memory allocation. Could you point out the other places where kstrdup() is being used for @param->string in mainline kernel? >> + 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 7af7cbbe4208..ff1a04661ef5 100644 >> > --- a/fs/smb/client/fs_context.h >> > +++ b/fs/smb/client/fs_context.h >> > @@ -184,6 +184,7 @@ enum cifs_param { >> > Opt_pass, >> > Opt_pass2, >> > Opt_ip, >> > + Opt_hostname, >> > Opt_domain, >> > Opt_srcaddr, >> > Opt_iocharset, >> > @@ -214,6 +215,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; >> > @@ -226,6 +228,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]; >> >> You're introducing a new field to smb3_fs_context structure but forgot >> to update smb3_fs_context_dup() and smb3_cleanup_fs_context_contents(). >> >> This will break automounts as well as leak >> smb3_fs_context::opt_hostname. >> > > > There is no any leak and there is no need to process "opt_hostname" > explicitly in smb3_fs_context_dup() and smb3_cleanup_fs_context_contents(), > because it's just a temporary pointer, that just copied into > "server_hostname" (if specified, i.e. not null), What happens if @ctx->opt_hostname was set and an invalid option that follows it was passed? IIUC, @ctx->server_hostname will not be set to @ctx->opt_hostname and smb3_cleanup_fs_context_contents() will be called, without freeing @ctx->opt_hostname. Besides, regarding the automount I mentioned above, if @ctx->got_opt_hostname was set, the new mount will set @ctx->server_hostname to @ctx->opt_hostname, causing an UAF bug. ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2] mount.cifs: add support for domain-based DFS targets with Kerberos via hostname resolution 2025-12-30 16:47 ` [PATCH v3 0/1] Add hostname option for CIFS module Maria Alexeeva 2025-12-30 16:47 ` [PATCH v3 1/1] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication Maria Alexeeva @ 2025-12-30 16:50 ` Maria Alexeeva 1 sibling, 0 replies; 16+ messages in thread From: Maria Alexeeva @ 2025-12-30 16:50 UTC (permalink / raw) To: smfrench Cc: pc, linux-cifs, samba-technical, tom, vt, Maria Alexeeva, Ivan Volchenko Enhance the mount.cifs utility to support mounting of domain-based DFS shares using Kerberos authentication by enabling hostname-based resolution of DFS targets. Previously, only IP addresses were resolved and passed to the kernel, which prevented Kerberos from functioning properly with DFS shares that require hostname-based access. This patch: 1. Adds hostlist support to track hostnames alongside resolved IP addresses. 2. Modifies resolve_host() into resolve_host_with_names() to collect both IPs and associated DNS names. 3. Updates mount retry logic to iterate over hostnames as well as addresses. 4. Appends hostname= mount option when available to allow the kernel to use hostname for Kerberos validation. 5. Includes fallback to existing logic when Kerberos is not used. 6. Introduces helper iterlist() to simplify parsing of comma-separated lists. 7. Buffer size fix for AD site names: Updates the buffer size used to store Active Directory site names from MAXCDNAME to MAXLABEL, in line with Active Directory specifications. According to [MS-ADTS] and RFC 1035, site names in AD are limited to DNS label size (MAXLABEL, 63 bytes), not full domain name size (MAXCDNAME, 255 bytes). Suggested-by: Ivan Volchenko <ivolchenko86@gmail.com> Signed-off-by: Maria Alexeeva <alxvmr@altlinux.org> --- cldap_ping.c | 2 +- cldap_ping.h | 2 +- mount.cifs.c | 28 +++++++++++++++++----------- resolve_host.c | 43 ++++++++++++++++++++++++++++++++++++------- resolve_host.h | 5 +++++ util.c | 14 ++++++++++++++ util.h | 1 + 7 files changed, 75 insertions(+), 20 deletions(-) diff --git a/cldap_ping.c b/cldap_ping.c index 5c20f84..e8cba50 100644 --- a/cldap_ping.c +++ b/cldap_ping.c @@ -280,7 +280,7 @@ int netlogon_get_client_site(char *netlogon_response, size_t netlogon_size, char for (int i=0; i < 8; i++) { // iterate over DnsForestName, DnsDomainName, NetbiosDomainName, NetbiosComputerName, UserName, DcSiteName // to finally get to our desired ClientSiteName field - if (read_dns_string(netlogon_response, netlogon_size, sitename, MAXCDNAME, &offset) < 0) { + if (read_dns_string(netlogon_response, netlogon_size, sitename, MAXLABEL, &offset) < 0) { return CLDAP_PING_PARSE_ERROR_NETLOGON; } } diff --git a/cldap_ping.h b/cldap_ping.h index 9a23e72..a15a14c 100644 --- a/cldap_ping.h +++ b/cldap_ping.h @@ -8,7 +8,7 @@ // returns CLDAP_PING_TRYNEXT if you should use another dc // any other error code < 0 is a fatal error -// site_name must be of MAXCDNAME size! +// site_name must be of MAXLABEL size! int cldap_ping(char *domain, sa_family_t family, void *addr, char *site_name); #endif /* _CLDAP_PING_H_ */ diff --git a/mount.cifs.c b/mount.cifs.c index 1923913..dc3925a 100644 --- a/mount.cifs.c +++ b/mount.cifs.c @@ -190,6 +190,7 @@ struct parsed_mount_info { char password[MOUNT_PASSWD_SIZE + 1]; char password2[MOUNT_PASSWD_SIZE + 1]; char addrlist[MAX_ADDR_LIST_LEN]; + char hostlist[MAX_HOST_LIST_LEN]; unsigned int got_user:1; unsigned int got_password:1; unsigned int got_password2:1; @@ -1939,6 +1940,7 @@ assemble_mountinfo(struct parsed_mount_info *parsed_info, { int rc; char *newopts = NULL; + char *hostlist; rc = drop_capabilities(0); if (rc) @@ -1983,8 +1985,10 @@ assemble_mountinfo(struct parsed_mount_info *parsed_info, if (rc) goto assemble_exit; + parsed_info->hostlist[0] = '\0'; if (parsed_info->addrlist[0] == '\0') { - rc = resolve_host(parsed_info->host, parsed_info->addrlist); + hostlist = parsed_info->is_krb5 ? parsed_info->hostlist : NULL; + rc = resolve_host_with_names(parsed_info->host, parsed_info->addrlist, hostlist); if (rc == 0 && parsed_info->verboseflag) fprintf(stderr, "Host \"%s\" resolved to the following IP addresses: %s\n", parsed_info->host, parsed_info->addrlist); } @@ -2142,6 +2146,7 @@ int main(int argc, char **argv) char *options = NULL; char *orig_dev = NULL; char *currentaddress, *nextaddress; + char *currenthost, *nexthost; char *value = NULL; char *ep = NULL; int rc = 0; @@ -2300,12 +2305,14 @@ assemble_retry: } currentaddress = parsed_info->addrlist; - nextaddress = strchr(currentaddress, ','); - if (nextaddress) - *nextaddress++ = '\0'; + nextaddress = NULL; + currenthost = parsed_info->hostlist; + nexthost = NULL; mount_retry: options[0] = '\0'; + iterlist(¤taddress, &nextaddress); + iterlist(¤thost, &nexthost); if (!currentaddress) { fprintf(stderr, "Unable to find suitable address.\n"); rc = parsed_info->nofail ? 0 : EX_FAIL; @@ -2329,9 +2336,14 @@ mount_retry: strlcat(options, parsed_info->prefix, options_size); } - if (sloppy) + if (sloppy || currenthost) strlcat(options, ",sloppy", options_size); + if (currenthost) { + strlcat(options, ",hostname=", options_size); + strlcat(options, currenthost, options_size); + } + if (parsed_info->verboseflag) fprintf(stderr, "%s kernel mount options: %s", thisprogram, options); @@ -2378,12 +2390,6 @@ mount_retry: fprintf(stderr, "mount error(%d): could not connect to %s", errno, currentaddress); } - currentaddress = nextaddress; - if (currentaddress) { - nextaddress = strchr(currentaddress, ','); - if (nextaddress) - *nextaddress++ = '\0'; - } goto mount_retry; case ENODEV: fprintf(stderr, diff --git a/resolve_host.c b/resolve_host.c index 918c6ad..5b6aed8 100644 --- a/resolve_host.c +++ b/resolve_host.c @@ -37,7 +37,7 @@ /* * resolve hostname to comma-separated list of address(es) */ -int resolve_host(const char *host, char *addrstr) { +int resolve_host_with_names(const char *host, char *addrstr, char *hoststr) { int rc; /* 10 for max width of decimal scopeid */ char tmpbuf[NI_MAXHOST + 1 + 10 + 1]; @@ -114,7 +114,7 @@ int resolve_host(const char *host, char *addrstr) { // Is this a DFS domain where we need to do a cldap ping to find the closest node? - if (count_v4 > 1 || count_v6 > 1) { + if (count_v4 > 1 || count_v6 > 1 || hoststr) { int res; ns_msg global_domain_handle; unsigned char global_domain_lookup[4096]; @@ -122,6 +122,8 @@ int resolve_host(const char *host, char *addrstr) { unsigned char site_domain_lookup[4096]; char dname[MAXCDNAME]; int srv_cnt; + int number_addresses = 0; + const char *hostname; res = res_init(); if (res != 0) @@ -144,7 +146,7 @@ int resolve_host(const char *host, char *addrstr) { // No or just one DC we are done if (srv_cnt < 2) - goto resolve_host_out; + goto resolve_host_global; char site_name[MAXCDNAME]; site_name[0] = '\0'; @@ -200,7 +202,6 @@ int resolve_host(const char *host, char *addrstr) { if (res < 0) goto resolve_host_out; - int number_addresses = 0; for (int i = 0; i < ns_msg_count(site_domain_handle, ns_s_ar); i++) { if (i > MAX_ADDRESSES) break; @@ -214,6 +215,7 @@ int resolve_host(const char *host, char *addrstr) { case ns_t_aaaa: if (ns_rr_rdlen(rr) != NS_IN6ADDRSZ) continue; + hostname = ns_rr_name(rr); ipaddr = inet_ntop(AF_INET6, ns_rr_rdata(rr), tmpbuf, sizeof(tmpbuf)); if (!ipaddr) { @@ -224,6 +226,7 @@ int resolve_host(const char *host, char *addrstr) { case ns_t_a: if (ns_rr_rdlen(rr) != NS_INADDRSZ) continue; + hostname = ns_rr_name(rr); ipaddr = inet_ntop(AF_INET, ns_rr_rdata(rr), tmpbuf, sizeof(tmpbuf)); if (!ipaddr) { @@ -237,14 +240,22 @@ int resolve_host(const char *host, char *addrstr) { number_addresses++; - if (i == 0) + if (i == 0) { *addrstr = '\0'; - else + if (hoststr) + *hoststr = '\0'; + } else { strlcat(addrstr, ",", MAX_ADDR_LIST_LEN); + if (hoststr) + strlcat(hoststr, ",", MAX_ADDR_LIST_LEN); + } strlcat(addrstr, tmpbuf, MAX_ADDR_LIST_LEN); + if (hoststr) + strlcat(hoststr, hostname, MAX_HOST_LIST_LEN); } +resolve_host_global: // Preferred site ips is now the first entry in addrstr, fill up with other sites till MAX_ADDRESS for (int i = 0; i < ns_msg_count(global_domain_handle, ns_s_ar); i++) { if (number_addresses > MAX_ADDRESSES) @@ -259,6 +270,7 @@ int resolve_host(const char *host, char *addrstr) { case ns_t_aaaa: if (ns_rr_rdlen(rr) != NS_IN6ADDRSZ) continue; + hostname = ns_rr_name(rr); ipaddr = inet_ntop(AF_INET6, ns_rr_rdata(rr), tmpbuf, sizeof(tmpbuf)); if (!ipaddr) { @@ -269,6 +281,7 @@ int resolve_host(const char *host, char *addrstr) { case ns_t_a: if (ns_rr_rdlen(rr) != NS_INADDRSZ) continue; + hostname = ns_rr_name(rr); ipaddr = inet_ntop(AF_INET, ns_rr_rdata(rr), tmpbuf, sizeof(tmpbuf)); if (!ipaddr) { @@ -280,6 +293,12 @@ int resolve_host(const char *host, char *addrstr) { continue; } + if (number_addresses == 0) { + *addrstr = '\0'; + if (hoststr) + *hoststr = '\0'; + } + char *found = strstr(addrstr, tmpbuf); if (found) { @@ -293,9 +312,15 @@ int resolve_host(const char *host, char *addrstr) { } } + if (number_addresses > 0) { + strlcat(addrstr, ",", MAX_ADDR_LIST_LEN); + if (hoststr) + strlcat(hoststr, ",", MAX_HOST_LIST_LEN); + } number_addresses++; - strlcat(addrstr, ",", MAX_ADDR_LIST_LEN); strlcat(addrstr, tmpbuf, MAX_ADDR_LIST_LEN); + if (hoststr) + strlcat(hoststr, hostname, MAX_HOST_LIST_LEN); } } @@ -303,3 +328,7 @@ resolve_host_out: freeaddrinfo(addrlist); return rc; } + +int resolve_host(const char *host, char *addrstr) { + return resolve_host_with_names(host, addrstr, NULL); +} diff --git a/resolve_host.h b/resolve_host.h index f2b19e6..b507757 100644 --- a/resolve_host.h +++ b/resolve_host.h @@ -22,6 +22,7 @@ #define _RESOLVE_HOST_H_ #include <arpa/inet.h> +#include <resolv.h> /* currently maximum length of IPv6 address string */ #define MAX_ADDRESS_LEN INET6_ADDRSTRLEN @@ -31,6 +32,10 @@ /* limit list of addresses to MAX_ADDRESSES max-size addrs */ #define MAX_ADDR_LIST_LEN ((MAX_ADDRESS_LEN + 1) * MAX_ADDRESSES) +/* limit list of hostnames to MAX_ADDRESSES max-size names */ +#define MAX_HOST_LIST_LEN ((MAXCDNAME + 1) * MAX_ADDRESSES) + +extern int resolve_host_with_names(const char *host, char *addrstr, char *hoststr); extern int resolve_host(const char *host, char *addrstr); #endif /* _RESOLVE_HOST_H_ */ diff --git a/util.c b/util.c index 546f284..1f7aaa8 100644 --- a/util.c +++ b/util.c @@ -83,3 +83,17 @@ getusername(uid_t uid) return username; } +int +iterlist(char **curr, char **next) { + if (!*curr || *curr[0] == '\0' || *curr == *next) { + *curr = *next = NULL; + return 0; + } + *curr = *next ? *next : *curr; + *next = strchr(*curr, ','); + if (*next) + *(*next)++ = '\0'; + else + *next = *curr; + return 1; +} diff --git a/util.h b/util.h index 2864130..59e4200 100644 --- a/util.h +++ b/util.h @@ -29,5 +29,6 @@ extern size_t strlcpy(char *d, const char *s, size_t bufsize); extern size_t strlcat(char *d, const char *s, size_t bufsize); extern char *getusername(uid_t uid); +extern int iterlist(char **curr, char **next); #endif /* _LIBUTIL_H */ base-commit: 25ba696a213f9a6d7b4fcdd157757695710c8886 -- 2.50.1 ^ permalink raw reply related [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-02-27 21:07 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-16 15:22 [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication Maria Alexeeva
2025-06-14 3:42 ` Vitaly Chikunov
2025-07-03 12:59 ` Maria Alexeeva
2025-07-24 22:14 ` Steve French
2025-07-24 22:50 ` Steve French
2025-07-30 16:54 ` Maria Alexeeva
2025-07-30 17:03 ` [PATCH v2] fs/smb/client/fs_context: Add dfs_domain_hostname " Maria Alexeeva
2025-07-30 17:09 ` [PATCH] mount.cifs: add support for domain-based DFS targets with Kerberos via hostname resolution Maria Alexeeva
2025-07-31 14:00 ` [PATCH] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication Steve French
2025-09-08 13:24 ` Maria Alexeeva
2025-12-30 16:47 ` [PATCH v3 0/1] Add hostname option for CIFS module Maria Alexeeva
2025-12-30 16:47 ` [PATCH v3 1/1] fs/smb/client/fs_context: Add hostname option for CIFS module to work with domain-based dfs resources with Kerberos authentication Maria Alexeeva
2026-02-23 18:02 ` Steve French
2026-02-27 18:46 ` Paulo Alcantara
[not found] ` <CAG5KTOZ6s4AjE0e66D9CMnZTP68YHzUb6p9nQKgeZeBV9ZVVBw@mail.gmail.com>
2026-02-27 21:07 ` Paulo Alcantara
2025-12-30 16:50 ` [PATCH v2] mount.cifs: add support for domain-based DFS targets with Kerberos via hostname resolution Maria Alexeeva
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox