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 * Concatenate dir + file, expanding any escape sequences.
152 * Returns the concatenated path and sets slashp point to
153 * the path separator between the expanded dir and file.
156 expand_iolog_path(const char *prefix, const char *dir, const char *file,
159 size_t len, prelen = 0;
160 char *dst, *dst0, *path, *pathend, tmpbuf[PATH_MAX];
161 const char *endbrace, *src = dir;
164 /* Expanded path must be <= PATH_MAX */
166 prelen = strlen(prefix);
167 dst = path = emalloc(prelen + PATH_MAX);
169 pathend = path + prelen + PATH_MAX;
171 /* Copy prefix, if present. */
172 if (prefix != NULL) {
173 memcpy(path, prefix, prelen);
178 /* Trim leading slashes from file component. */
182 for (pass = 0; pass < 3; pass++) {
189 /* Trim trailing slashes from dir component. */
190 while (dst - path - 1 > prelen && dst[-1] == '/')
201 for (; *src != '\0'; src++) {
204 endbrace = strchr(src + 2, '}');
205 if (endbrace != NULL) {
206 struct path_escape *esc;
207 len = (size_t)(endbrace - src - 2);
208 for (esc = escapes; esc->name != NULL; esc++) {
209 if (strncmp(src + 2, esc->name, len) == 0 &&
210 esc->name[len] == '\0')
213 if (esc->name != NULL) {
214 len = esc->copy_fn(dst, (size_t)(pathend - dst));
215 if (len >= (size_t)(pathend - dst))
222 } else if (src[1] == '%') {
223 /* Collapse %% -> % */
226 /* May need strftime() */
230 /* Need at least 2 chars, including the NUL terminator. */
231 if (dst + 1 >= pathend)
237 /* Expand strftime escapes as needed. */
243 timeptr = localtime(&now);
245 #ifdef HAVE_SETLOCALE
246 if (!setlocale(LC_ALL, def_sudoers_locale)) {
247 warningx(_("unable to set locale to \"%s\", using \"C\""),
249 setlocale(LC_ALL, "C");
252 /* We only calls strftime() on the current part of the buffer. */
253 tmpbuf[sizeof(tmpbuf) - 1] = '\0';
254 len = strftime(tmpbuf, sizeof(tmpbuf), dst0, timeptr);
256 #ifdef HAVE_SETLOCALE
257 setlocale(LC_ALL, "");
259 if (len == 0 || tmpbuf[sizeof(tmpbuf) - 1] != '\0')
260 goto bad; /* strftime() failed, buf too small? */
262 if (len >= (size_t)(pathend - dst0))
263 goto bad; /* expanded buffer too big to fit. */
264 memcpy(dst0, tmpbuf, len);