2 * Copyright (c) 2011 Todd C. Miller <Todd.Miller@courtesan.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
28 #endif /* STDC_HEADERS */
30 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
34 #endif /* HAVE_STRING_H */
37 #endif /* HAVE_STRINGS_H */
49 size_t (*copy_fn)(char *, size_t);
52 static size_t fill_seq(char *, size_t);
53 static size_t fill_user(char *, size_t);
54 static size_t fill_group(char *, size_t);
55 static size_t fill_runas_user(char *, size_t);
56 static size_t fill_runas_group(char *, size_t);
57 static size_t fill_hostname(char *, size_t);
58 static size_t fill_command(char *, size_t);
60 static struct path_escape escapes[] = {
62 { "user", fill_user },
63 { "group", fill_group },
64 { "runas_user", fill_runas_user },
65 { "runas_group", fill_runas_group },
66 { "hostname", fill_hostname },
67 { "command", fill_command },
72 fill_seq(char *str, size_t strsize)
74 static char sessid[7];
77 if (sessid[0] == '\0')
78 io_nextid(def_iolog_dir, sessid);
80 /* Path is of the form /var/log/sudo-io/00/00/01. */
81 len = snprintf(str, strsize, "%c%c/%c%c/%c%c", sessid[0],
82 sessid[1], sessid[2], sessid[3], sessid[4], sessid[5]);
84 return strsize; /* handle non-standard snprintf() */
89 fill_user(char *str, size_t strsize)
91 return strlcpy(str, user_name, strsize);
95 fill_group(char *str, size_t strsize)
100 if ((grp = sudo_getgrgid(user_gid)) != NULL) {
101 len = strlcpy(str, grp->gr_name, strsize);
105 len = snprintf(str + len, strsize - len, "#%u",
106 (unsigned int) user_gid);
112 fill_runas_user(char *str, size_t strsize)
114 return strlcpy(str, runas_pw->pw_name, strsize);
118 fill_runas_group(char *str, size_t strsize)
123 if (runas_gr != NULL) {
124 len = strlcpy(str, runas_gr->gr_name, strsize);
126 if ((grp = sudo_getgrgid(runas_pw->pw_gid)) != NULL) {
127 len = strlcpy(str, grp->gr_name, strsize);
131 len = snprintf(str + len, strsize - len, "#%u",
132 (unsigned int) runas_pw->pw_gid);
139 fill_hostname(char *str, size_t strsize)
141 return strlcpy(str, user_shost, strsize);
145 fill_command(char *str, size_t strsize)
147 return strlcpy(str, user_base, strsize);
151 expand_iolog_path(const char *prefix, const char *dir, const char *file,
154 size_t plen = 0, psize = 1024;
156 const char *src = dir, *ep;
157 int pass, strfit = FALSE;
159 /* Concatenate dir + file -> path, expanding any escape sequences. */
160 dst = path = emalloc(psize);
163 /* Trim leading slashes from file component. */
167 if (prefix != NULL) {
168 plen = strlcpy(path, prefix, psize);
171 for (pass = 0; pass < 3; pass++) {
177 /* Trim trailing slashes from dir component. */
178 while (dst > path && dst[-1] == '/')
188 for (; *src != '\0'; src++) {
191 ep = strchr(src + 2, '}');
193 struct path_escape *esc;
194 size_t len = (size_t)(ep - src - 2);
195 for (esc = escapes; esc->name != NULL; esc++) {
196 if (strncmp(src + 2, esc->name, len) == 0 &&
197 esc->name[len] == '\0')
200 if (esc->name != NULL) {
202 len = esc->copy_fn(dst, psize - (dst - path));
203 if (len < psize - (dst - path))
205 path = erealloc3(path, 2, psize);
215 } else if (src[1] == '%') {
216 /* Collapse %% -> % */
219 /* May need strftime() */
223 /* Need at least 2 chars, including the NUL terminator. */
224 if (plen + 2 >= psize) {
225 path = erealloc3(path, 2, psize);
241 timeptr = localtime(&now);
243 #ifdef HAVE_SETLOCALE
244 if (!setlocale(LC_ALL, def_sudoers_locale)) {
245 warningx("unable to set locale to \"%s\", using \"C\"",
247 setlocale(LC_ALL, "C");
250 /* Double the size of the buffer until it is big enough to expand. */
253 buf = erealloc(buf, psize);
254 buf[psize - 1] = '\0';
255 } while (!strftime(buf, psize, path, timeptr) || buf[psize - 1] != '\0');
256 #ifdef HAVE_SETLOCALE
257 setlocale(LC_ALL, "");
260 *slashp = buf + (*slashp - path);