From d9da92951adf2e78da8bb84f5d6f413e313c543a Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Wed, 20 Sep 2023 09:00:27 -0600 Subject: [PATCH] Replace '/' with '_' in paths using the user, group or host name. --- docs/sudoers.man.in | 11 ++++++++ docs/sudoers.mdoc.in | 11 ++++++++ plugins/sudoers/iolog_path_escapes.c | 40 +++++++++++++++++++++++----- plugins/sudoers/toke.c | 32 +++++++++++++++++----- plugins/sudoers/toke.l | 32 +++++++++++++++++----- 5 files changed, 107 insertions(+), 19 deletions(-) diff --git a/docs/sudoers.man.in b/docs/sudoers.man.in index 33d676f48..8481210de 100644 --- a/docs/sudoers.man.in +++ b/docs/sudoers.man.in @@ -2483,6 +2483,11 @@ will cause \fBsudo\fR to include the file \fI/etc/sudoers.xerxes\fR. +Any path name separator characters +(\(oq/\(cq) +present in the host name will be replaced with an underbar +(\(oq_\(cq) +during expansion. .PP The \fI@includedir\fR @@ -4654,6 +4659,12 @@ To include a literal character, the string \(oq%%\(cq should be used. +.sp +Any path name separator characters +(\(oq/\(cq) +present in the user, group or host name will be replaced with an underbar +(\(oq_\(cq) +during expansion. .RE .TP 18n iolog_file diff --git a/docs/sudoers.mdoc.in b/docs/sudoers.mdoc.in index 9c7bade91..4bc3b30a4 100644 --- a/docs/sudoers.mdoc.in +++ b/docs/sudoers.mdoc.in @@ -2353,6 +2353,11 @@ will cause .Nm sudo to include the file .Pa /etc/sudoers.xerxes . +Any path name separator characters +.Pq Ql / +present in the host name will be replaced with an underbar +.Pq Ql _ +during expansion. .Pp The .Em @includedir @@ -4400,6 +4405,12 @@ To include a literal character, the string .Ql %% should be used. +.Pp +Any path name separator characters +.Pq Ql / +present in the user, group or host name will be replaced with an underbar +.Pq Ql _ +during expansion. .It iolog_file The path name, relative to .Em iolog_dir , diff --git a/plugins/sudoers/iolog_path_escapes.c b/plugins/sudoers/iolog_path_escapes.c index de4a3cb28..1b85387a0 100644 --- a/plugins/sudoers/iolog_path_escapes.c +++ b/plugins/sudoers/iolog_path_escapes.c @@ -33,6 +33,32 @@ #include "sudoers.h" #include "sudo_iolog.h" +/* + * Like strlcpy(3) but replaces '/' with '_'. + */ +static size_t +strlcpy_no_slash(char *dst, const char *src, size_t size) +{ + size_t len = 0; + char ch; + debug_decl(strlcpy_no_slash, SUDOERS_DEBUG_UTIL); + + while ((ch = *src++) != '\0') { + if (size > 1) { + /* Replace '/' with '_' */ + if (ch == '/') + ch = '_'; + *dst++ = ch; + size--; + } + len++; + } + if (size > 0) + *dst = '\0'; + + debug_return_size_t(len); +} + static size_t fill_seq(char *str, size_t strsize, void *v) { @@ -64,7 +90,7 @@ fill_user(char *str, size_t strsize, void *v) { struct sudoers_context *ctx = v; debug_decl(fill_user, SUDOERS_DEBUG_UTIL); - debug_return_size_t(strlcpy(str, ctx->user.name, strsize)); + debug_return_size_t(strlcpy_no_slash(str, ctx->user.name, strsize)); } static size_t @@ -76,7 +102,7 @@ fill_group(char *str, size_t strsize, void *v) debug_decl(fill_group, SUDOERS_DEBUG_UTIL); if ((grp = sudo_getgrgid(ctx->user.gid)) != NULL) { - len = strlcpy(str, grp->gr_name, strsize); + len = strlcpy_no_slash(str, grp->gr_name, strsize); sudo_gr_delref(grp); } else { len = (size_t)snprintf(str, strsize, "#%u", (unsigned int)ctx->user.gid); @@ -89,7 +115,7 @@ fill_runas_user(char *str, size_t strsize, void *v) { struct sudoers_context *ctx = v; debug_decl(fill_runas_user, SUDOERS_DEBUG_UTIL); - debug_return_size_t(strlcpy(str, ctx->runas.pw->pw_name, strsize)); + debug_return_size_t(strlcpy_no_slash(str, ctx->runas.pw->pw_name, strsize)); } static size_t @@ -101,10 +127,10 @@ fill_runas_group(char *str, size_t strsize, void *v) debug_decl(fill_runas_group, SUDOERS_DEBUG_UTIL); if (ctx->runas.gr != NULL) { - len = strlcpy(str, ctx->runas.gr->gr_name, strsize); + len = strlcpy_no_slash(str, ctx->runas.gr->gr_name, strsize); } else { if ((grp = sudo_getgrgid(ctx->runas.pw->pw_gid)) != NULL) { - len = strlcpy(str, grp->gr_name, strsize); + len = strlcpy_no_slash(str, grp->gr_name, strsize); sudo_gr_delref(grp); } else { len = (size_t)snprintf(str, strsize, "#%u", @@ -119,7 +145,7 @@ fill_hostname(char *str, size_t strsize, void *v) { struct sudoers_context *ctx = v; debug_decl(fill_hostname, SUDOERS_DEBUG_UTIL); - debug_return_size_t(strlcpy(str, ctx->user.shost, strsize)); + debug_return_size_t(strlcpy_no_slash(str, ctx->user.shost, strsize)); } static size_t @@ -127,7 +153,7 @@ fill_command(char *str, size_t strsize, void *v) { struct sudoers_context *ctx = v; debug_decl(fill_command, SUDOERS_DEBUG_UTIL); - debug_return_size_t(strlcpy(str, ctx->user.cmnd_base, strsize)); + debug_return_size_t(strlcpy_no_slash(str, ctx->user.cmnd_base, strsize)); } /* Note: "seq" must be first in the list. */ diff --git a/plugins/sudoers/toke.c b/plugins/sudoers/toke.c index 18cfe39a6..b44a6b22d 100644 --- a/plugins/sudoers/toke.c +++ b/plugins/sudoers/toke.c @@ -5938,8 +5938,8 @@ expand_include(const char *src, const char *host) { const char *path = sudoers_search_path ? sudoers_search_path : sudoers; const char *path_end = path + strlen(path); + char *dst, *dst0 = NULL, *dynamic_host = NULL; const char *cp, *ep; - char *dst0, *dst; size_t dst_size, src_len; size_t nhost = 0; debug_decl(expand_include, SUDOERS_DEBUG_PARSER); @@ -5965,18 +5965,35 @@ expand_include(const char *src, const char *host) cp++; } + /* Check for a path separator in the host name, replace with '_'. */ + if (nhost != 0 && strchr(host, '/') != NULL) { + dynamic_host = malloc(strlen(host) + 1); + if (dynamic_host == NULL) { + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + goto bad; + } + for (dst = dynamic_host; *host != '\0'; host++) { + if (*host == '/') { + *dst++ = '_'; + continue; + } + *dst++ = *host; + } + *dst = '\0'; + host = dynamic_host; + } + if (*src == '/') { /* Fully-qualified path, make a copy and expand %h escapes. */ dst_size = src_len + (nhost * strlen(host)) - (nhost * 2) + 1; dst0 = sudo_rcstr_alloc(dst_size - 1); if (dst0 == NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - sudoerserror(NULL); - debug_return_str(NULL); + goto bad; } if (strlcpy_expand_host(dst0, src, host, dst_size) >= dst_size) goto oflow; - debug_return_str(dst0); + goto done; } /* @@ -5999,8 +6016,7 @@ expand_include(const char *src, const char *host) dst = dst0 = sudo_rcstr_alloc(dst_size - 1); if (dst0 == NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - sudoerserror(NULL); - debug_return_str(NULL); + goto bad; } for (cp = sudo_strsplit(path, path_end, ":", &ep); cp != NULL; cp = sudo_strsplit(NULL, path_end, ":", &ep)) { @@ -6032,10 +6048,14 @@ expand_include(const char *src, const char *host) } *dst = '\0'; +done: + free(dynamic_host); debug_return_str(dst0); oflow: sudo_warnx(U_("internal error, %s overflow"), __func__); +bad: sudoerserror(NULL); + free(dynamic_host); free(dst0); debug_return_str(NULL); } diff --git a/plugins/sudoers/toke.l b/plugins/sudoers/toke.l index fd6d04e81..d6fcb25b3 100644 --- a/plugins/sudoers/toke.l +++ b/plugins/sudoers/toke.l @@ -1159,8 +1159,8 @@ expand_include(const char *src, const char *host) { const char *path = sudoers_search_path ? sudoers_search_path : sudoers; const char *path_end = path + strlen(path); + char *dst, *dst0 = NULL, *dynamic_host = NULL; const char *cp, *ep; - char *dst0, *dst; size_t dst_size, src_len; size_t nhost = 0; debug_decl(expand_include, SUDOERS_DEBUG_PARSER); @@ -1186,18 +1186,35 @@ expand_include(const char *src, const char *host) cp++; } + /* Check for a path separator in the host name, replace with '_'. */ + if (nhost != 0 && strchr(host, '/') != NULL) { + dynamic_host = malloc(strlen(host) + 1); + if (dynamic_host == NULL) { + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + goto bad; + } + for (dst = dynamic_host; *host != '\0'; host++) { + if (*host == '/') { + *dst++ = '_'; + continue; + } + *dst++ = *host; + } + *dst = '\0'; + host = dynamic_host; + } + if (*src == '/') { /* Fully-qualified path, make a copy and expand %h escapes. */ dst_size = src_len + (nhost * strlen(host)) - (nhost * 2) + 1; dst0 = sudo_rcstr_alloc(dst_size - 1); if (dst0 == NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - sudoerserror(NULL); - debug_return_str(NULL); + goto bad; } if (strlcpy_expand_host(dst0, src, host, dst_size) >= dst_size) goto oflow; - debug_return_str(dst0); + goto done; } /* @@ -1220,8 +1237,7 @@ expand_include(const char *src, const char *host) dst = dst0 = sudo_rcstr_alloc(dst_size - 1); if (dst0 == NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - sudoerserror(NULL); - debug_return_str(NULL); + goto bad; } for (cp = sudo_strsplit(path, path_end, ":", &ep); cp != NULL; cp = sudo_strsplit(NULL, path_end, ":", &ep)) { @@ -1253,10 +1269,14 @@ expand_include(const char *src, const char *host) } *dst = '\0'; +done: + free(dynamic_host); debug_return_str(dst0); oflow: sudo_warnx(U_("internal error, %s overflow"), __func__); +bad: sudoerserror(NULL); + free(dynamic_host); free(dst0); debug_return_str(NULL); }