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];
76 debug_decl(sudoers_io_version, SUDO_DEBUG_UTIL)
78 if (sessid[0] == '\0')
79 io_nextid(def_iolog_dir, sessid);
81 /* Path is of the form /var/log/sudo-io/00/00/01. */
82 len = snprintf(str, strsize, "%c%c/%c%c/%c%c", sessid[0],
83 sessid[1], sessid[2], sessid[3], sessid[4], sessid[5]);
85 debug_return_size_t(strsize); /* handle non-standard snprintf() */
86 debug_return_size_t(len);
90 fill_user(char *str, size_t strsize)
92 debug_decl(fill_user, SUDO_DEBUG_UTIL)
93 debug_return_size_t(strlcpy(str, user_name, strsize));
97 fill_group(char *str, size_t strsize)
101 debug_decl(fill_group, SUDO_DEBUG_UTIL)
103 if ((grp = sudo_getgrgid(user_gid)) != NULL) {
104 len = strlcpy(str, grp->gr_name, strsize);
108 len = snprintf(str + len, strsize - len, "#%u",
109 (unsigned int) user_gid);
111 debug_return_size_t(len);
115 fill_runas_user(char *str, size_t strsize)
117 debug_decl(fill_runas_user, SUDO_DEBUG_UTIL)
118 debug_return_size_t(strlcpy(str, runas_pw->pw_name, strsize));
122 fill_runas_group(char *str, size_t strsize)
126 debug_decl(fill_runas_group, SUDO_DEBUG_UTIL)
128 if (runas_gr != NULL) {
129 len = strlcpy(str, runas_gr->gr_name, strsize);
131 if ((grp = sudo_getgrgid(runas_pw->pw_gid)) != NULL) {
132 len = strlcpy(str, grp->gr_name, strsize);
136 len = snprintf(str + len, strsize - len, "#%u",
137 (unsigned int) runas_pw->pw_gid);
140 debug_return_size_t(len);
144 fill_hostname(char *str, size_t strsize)
146 debug_decl(fill_hostname, SUDO_DEBUG_UTIL)
147 debug_return_size_t(strlcpy(str, user_shost, strsize));
151 fill_command(char *str, size_t strsize)
153 debug_decl(fill_command, SUDO_DEBUG_UTIL)
154 debug_return_size_t(strlcpy(str, user_base, strsize));
158 * Concatenate dir + file, expanding any escape sequences.
159 * Returns the concatenated path and sets slashp point to
160 * the path separator between the expanded dir and file.
163 expand_iolog_path(const char *prefix, const char *dir, const char *file,
166 size_t len, prelen = 0;
167 char *dst, *dst0, *path, *pathend, tmpbuf[PATH_MAX];
168 const char *endbrace, *src = dir;
171 debug_decl(expand_iolog_path, SUDO_DEBUG_UTIL)
173 /* Expanded path must be <= PATH_MAX */
175 prelen = strlen(prefix);
176 dst = path = emalloc(prelen + PATH_MAX);
178 pathend = path + prelen + PATH_MAX;
180 /* Copy prefix, if present. */
181 if (prefix != NULL) {
182 memcpy(path, prefix, prelen);
187 /* Trim leading slashes from file component. */
191 for (pass = 0; pass < 3; pass++) {
198 /* Trim trailing slashes from dir component. */
199 while (dst - path - 1 > prelen && dst[-1] == '/')
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));
224 if (len >= (size_t)(pathend - dst))
231 } else if (src[1] == '%') {
232 /* Collapse %% -> % */
235 /* May need strftime() */
239 /* Need at least 2 chars, including the NUL terminator. */
240 if (dst + 1 >= pathend)
246 /* Expand strftime escapes as needed. */
252 timeptr = localtime(&now);
254 #ifdef HAVE_SETLOCALE
255 if (!setlocale(LC_ALL, def_sudoers_locale)) {
256 warningx(_("unable to set locale to \"%s\", using \"C\""),
258 setlocale(LC_ALL, "C");
261 /* We only calls strftime() on the current part of the buffer. */
262 tmpbuf[sizeof(tmpbuf) - 1] = '\0';
263 len = strftime(tmpbuf, sizeof(tmpbuf), dst0, timeptr);
265 #ifdef HAVE_SETLOCALE
266 setlocale(LC_ALL, "");
268 if (len == 0 || tmpbuf[sizeof(tmpbuf) - 1] != '\0')
269 goto bad; /* strftime() failed, buf too small? */
271 if (len >= (size_t)(pathend - dst0))
272 goto bad; /* expanded buffer too big to fit. */
273 memcpy(dst0, tmpbuf, len);
279 debug_return_str(path);
282 debug_return_str(NULL);