diff --git a/lib/iolog/iolog_path.c b/lib/iolog/iolog_path.c index 7e7c9de2b3..11bd73d3f9 100644 --- a/lib/iolog/iolog_path.c +++ b/lib/iolog/iolog_path.c @@ -37,6 +37,39 @@ #include #include +/* + * Double any '%' characters in the first len bytes of str so they + * are not interpreted as escapes when the path is expanded further. + * Returns the new length or (size_t)-1 if it would not fit in size. + */ +static size_t +escape_percent(char *str, size_t len, size_t size) +{ + size_t i, n, nesc = 0; + debug_decl(escape_percent, SUDO_DEBUG_UTIL); + + for (i = 0; i < len; i++) { + if (str[i] == '%') + nesc++; + } + if (nesc == 0) + debug_return_size_t(len); + if (len + nesc >= size) + debug_return_size_t((size_t)-1); + + /* Shift right from the end, duplicating each '%'. */ + for (i = len, n = nesc; n > 0; ) { + if (i-- == 0) + debug_return_size_t((size_t)-1); + str[i + n] = str[i]; + if (str[i] == '%') { + n--; + str[i + n] = '%'; + } + } + debug_return_size_t(len + nesc); +} + /* * Expand any escape sequences in inpath, returning the expanded path. */ @@ -72,14 +105,20 @@ expand_iolog_path(const char *inpath, char *path, size_t pathlen, closure); if (len >= (size_t)(pathend - dst)) goto bad; + /* The value may contain '%', treat it as a literal. */ + len = escape_percent(dst, len, (size_t)(pathend - dst)); + if (len == (size_t)-1) + goto bad; dst += len; src = endbrace; continue; } } } else if (src[1] == '%') { - /* Collapse %% -> % */ - src++; + /* Copy %% as-is, it is collapsed after expansion. */ + if (dst + 1 >= pathend) + goto bad; + *dst++ = *src++; } else { /* May need strftime() */ strfit = true; @@ -117,6 +156,14 @@ expand_iolog_path(const char *inpath, char *path, size_t pathlen, memcpy(path, tmpbuf, len); dst = path + len; *dst = '\0'; + } else { + /* No strftime() needed, collapse %% -> % ourselves. */ + for (src = dst = path; *src != '\0'; src++) { + if (src[0] == '%' && src[1] == '%') + src++; + *dst++ = *src; + } + *dst = '\0'; } debug_return_bool(true); diff --git a/lib/iolog/regress/iolog_path/data b/lib/iolog/regress/iolog_path/data index 48dc87e9d3..4dec6fe091 100644 --- a/lib/iolog/regress/iolog_path/data +++ b/lib/iolog/regress/iolog_path/data @@ -94,3 +94,39 @@ su nobody/root/su +000001 +%D +nogroup +root +wheel +somehost +x%Hy +/var/log/sudo-io/%{user}/%Y +%{command}_%Y%m%d +/var/log/sudo-io/%%D/%Y +x%%Hy_%Y%m%d + +000001 +nobody +nogroup +root +wheel +somehost +su +/var/log/sudo-io/%%Y_%Y +%{seq} +/var/log/sudo-io/%%Y_%Y +00/00/01 + +000001 +50% +nogroup +root +wheel +somehost +su +/var/log/sudo-io/%{user} +%{seq} +/var/log/sudo-io/50%% +00/00/01 +