2 * Copyright (c) 2011-2013 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 */
46 size_t (*copy_fn)(char *, size_t, char *);
50 fill_seq(char *str, size_t strsize, char *logdir)
53 debug_decl(fill_seq, SUDO_DEBUG_UTIL)
54 debug_return_size_t(strlcpy(str, "%{seq}", strsize));
56 static char sessid[7];
58 debug_decl(fill_seq, SUDO_DEBUG_UTIL)
60 if (sessid[0] == '\0')
61 io_nextid(logdir, def_iolog_dir, sessid);
63 /* Path is of the form /var/log/sudo-io/00/00/01. */
64 len = snprintf(str, strsize, "%c%c/%c%c/%c%c", sessid[0],
65 sessid[1], sessid[2], sessid[3], sessid[4], sessid[5]);
67 debug_return_size_t(strsize); /* handle non-standard snprintf() */
68 debug_return_size_t(len);
69 #endif /* SUDOERS_NO_SEQ */
73 fill_user(char *str, size_t strsize, char *unused)
75 debug_decl(fill_user, SUDO_DEBUG_UTIL)
76 debug_return_size_t(strlcpy(str, user_name, strsize));
80 fill_group(char *str, size_t strsize, char *unused)
84 debug_decl(fill_group, SUDO_DEBUG_UTIL)
86 if ((grp = sudo_getgrgid(user_gid)) != NULL) {
87 len = strlcpy(str, grp->gr_name, strsize);
91 len = snprintf(str + len, strsize - len, "#%u",
92 (unsigned int) user_gid);
94 debug_return_size_t(len);
98 fill_runas_user(char *str, size_t strsize, char *unused)
100 debug_decl(fill_runas_user, SUDO_DEBUG_UTIL)
101 debug_return_size_t(strlcpy(str, runas_pw->pw_name, strsize));
105 fill_runas_group(char *str, size_t strsize, char *unused)
109 debug_decl(fill_runas_group, SUDO_DEBUG_UTIL)
111 if (runas_gr != NULL) {
112 len = strlcpy(str, runas_gr->gr_name, strsize);
114 if ((grp = sudo_getgrgid(runas_pw->pw_gid)) != NULL) {
115 len = strlcpy(str, grp->gr_name, strsize);
119 len = snprintf(str + len, strsize - len, "#%u",
120 (unsigned int) runas_pw->pw_gid);
123 debug_return_size_t(len);
127 fill_hostname(char *str, size_t strsize, char *unused)
129 debug_decl(fill_hostname, SUDO_DEBUG_UTIL)
130 debug_return_size_t(strlcpy(str, user_shost, strsize));
134 fill_command(char *str, size_t strsize, char *unused)
136 debug_decl(fill_command, SUDO_DEBUG_UTIL)
137 debug_return_size_t(strlcpy(str, user_base, strsize));
140 /* Note: "seq" must be first in the list. */
141 static struct path_escape io_path_escapes[] = {
143 { "user", fill_user },
144 { "group", fill_group },
145 { "runas_user", fill_runas_user },
146 { "runas_group", fill_runas_group },
147 { "hostname", fill_hostname },
148 { "command", fill_command },
153 * Concatenate dir + file, expanding any escape sequences.
154 * Returns the concatenated path and sets slashp point to
155 * the path separator between the expanded dir and file.
158 expand_iolog_path(const char *prefix, const char *dir, const char *file,
161 size_t len, prelen = 0;
162 char *dst, *dst0, *path, *pathend, tmpbuf[PATH_MAX];
164 const char *endbrace, *src = dir;
165 struct path_escape *escapes = NULL;
168 debug_decl(expand_iolog_path, SUDO_DEBUG_UTIL)
170 /* Expanded path must be <= PATH_MAX */
172 prelen = strlen(prefix);
173 dst = path = emalloc(prelen + PATH_MAX);
175 pathend = path + prelen + PATH_MAX;
177 /* Copy prefix, if present. */
178 if (prefix != NULL) {
179 memcpy(path, prefix, prelen);
184 /* Trim leading slashes from file component. */
188 for (pass = 0; pass < 3; pass++) {
193 escapes = io_path_escapes + 1; /* skip "%{seq}" */
196 /* Trim trailing slashes from dir component. */
197 while (dst - path - 1 > prelen && dst[-1] == '/')
199 /* The NUL will be replaced with a '/' at the end. */
200 if (dst + 1 >= pathend)
206 escapes = io_path_escapes;
210 for (; *src != '\0'; src++) {
213 endbrace = strchr(src + 2, '}');
214 if (endbrace != NULL) {
215 struct path_escape *esc;
216 len = (size_t)(endbrace - src - 2);
217 for (esc = escapes; esc->name != NULL; esc++) {
218 if (strncmp(src + 2, esc->name, len) == 0 &&
219 esc->name[len] == '\0')
222 if (esc->name != NULL) {
223 len = esc->copy_fn(dst, (size_t)(pathend - dst),
225 if (len >= (size_t)(pathend - dst))
232 } else if (src[1] == '%') {
233 /* Collapse %% -> % */
236 /* May need strftime() */
240 /* Need at least 2 chars, including the NUL terminator. */
241 if (dst + 1 >= pathend)
247 /* Expand strftime escapes as needed. */
253 timeptr = localtime(&now);
255 /* Use sudoers locale for strftime() */
256 sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
258 /* We only calls strftime() on the current part of the buffer. */
259 tmpbuf[sizeof(tmpbuf) - 1] = '\0';
260 len = strftime(tmpbuf, sizeof(tmpbuf), dst0, timeptr);
262 /* Restore old locale. */
263 sudoers_setlocale(oldlocale, NULL);
265 if (len == 0 || tmpbuf[sizeof(tmpbuf) - 1] != '\0')
266 goto bad; /* strftime() failed, buf too small? */
268 if (len >= (size_t)(pathend - dst0))
269 goto bad; /* expanded buffer too big to fit. */
270 memcpy(dst0, tmpbuf, len);
279 debug_return_str(path);
282 debug_return_str(NULL);