Annotation of embedaddon/sudo/plugins/sudoers/iolog_path.c, revision 1.1.1.3
1.1 misho 1: /*
2: * Copyright (c) 2011 Todd C. Miller <Todd.Miller@courtesan.com>
3: *
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.
7: *
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.
15: */
16:
17: #include <config.h>
18:
19: #include <sys/types.h>
20: #include <stdio.h>
21: #ifdef STDC_HEADERS
22: # include <stdlib.h>
23: # include <stddef.h>
24: #else
25: # ifdef HAVE_STDLIB_H
26: # include <stdlib.h>
27: # endif
28: #endif /* STDC_HEADERS */
29: #ifdef HAVE_STRING_H
30: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
31: # include <memory.h>
32: # endif
33: # include <string.h>
34: #endif /* HAVE_STRING_H */
35: #ifdef HAVE_STRINGS_H
36: # include <strings.h>
37: #endif /* HAVE_STRINGS_H */
38: #ifdef HAVE_SETLOCALE
39: # include <locale.h>
40: #endif
41: #include <pwd.h>
42: #include <grp.h>
43: #include <time.h>
44:
45: #include "sudoers.h"
46:
47: struct path_escape {
48: const char *name;
1.1.1.3 ! misho 49: size_t (*copy_fn)(char *, size_t, char *);
1.1 misho 50: };
51:
1.1.1.3 ! misho 52: static size_t fill_seq(char *, size_t, char *);
! 53: static size_t fill_user(char *, size_t, char *);
! 54: static size_t fill_group(char *, size_t, char *);
! 55: static size_t fill_runas_user(char *, size_t, char *);
! 56: static size_t fill_runas_group(char *, size_t, char *);
! 57: static size_t fill_hostname(char *, size_t, char *);
! 58: static size_t fill_command(char *, size_t, char *);
1.1 misho 59:
1.1.1.3 ! misho 60: /* Note: "seq" must be first in the list. */
! 61: static struct path_escape io_path_escapes[] = {
1.1 misho 62: { "seq", fill_seq },
63: { "user", fill_user },
64: { "group", fill_group },
65: { "runas_user", fill_runas_user },
66: { "runas_group", fill_runas_group },
67: { "hostname", fill_hostname },
68: { "command", fill_command },
69: { NULL, NULL }
70: };
71:
72: static size_t
1.1.1.3 ! misho 73: fill_seq(char *str, size_t strsize, char *logdir)
1.1 misho 74: {
75: static char sessid[7];
76: int len;
1.1.1.2 misho 77: debug_decl(sudoers_io_version, SUDO_DEBUG_UTIL)
1.1 misho 78:
79: if (sessid[0] == '\0')
1.1.1.3 ! misho 80: io_nextid(logdir, def_iolog_dir, sessid);
1.1 misho 81:
82: /* Path is of the form /var/log/sudo-io/00/00/01. */
83: len = snprintf(str, strsize, "%c%c/%c%c/%c%c", sessid[0],
84: sessid[1], sessid[2], sessid[3], sessid[4], sessid[5]);
85: if (len < 0)
1.1.1.2 misho 86: debug_return_size_t(strsize); /* handle non-standard snprintf() */
87: debug_return_size_t(len);
1.1 misho 88: }
89:
90: static size_t
1.1.1.3 ! misho 91: fill_user(char *str, size_t strsize, char *unused)
1.1 misho 92: {
1.1.1.2 misho 93: debug_decl(fill_user, SUDO_DEBUG_UTIL)
94: debug_return_size_t(strlcpy(str, user_name, strsize));
1.1 misho 95: }
96:
97: static size_t
1.1.1.3 ! misho 98: fill_group(char *str, size_t strsize, char *unused)
1.1 misho 99: {
100: struct group *grp;
101: size_t len;
1.1.1.2 misho 102: debug_decl(fill_group, SUDO_DEBUG_UTIL)
1.1 misho 103:
104: if ((grp = sudo_getgrgid(user_gid)) != NULL) {
105: len = strlcpy(str, grp->gr_name, strsize);
1.1.1.3 ! misho 106: sudo_gr_delref(grp);
1.1 misho 107: } else {
108: len = strlen(str);
109: len = snprintf(str + len, strsize - len, "#%u",
110: (unsigned int) user_gid);
111: }
1.1.1.2 misho 112: debug_return_size_t(len);
1.1 misho 113: }
114:
115: static size_t
1.1.1.3 ! misho 116: fill_runas_user(char *str, size_t strsize, char *unused)
1.1 misho 117: {
1.1.1.2 misho 118: debug_decl(fill_runas_user, SUDO_DEBUG_UTIL)
119: debug_return_size_t(strlcpy(str, runas_pw->pw_name, strsize));
1.1 misho 120: }
121:
122: static size_t
1.1.1.3 ! misho 123: fill_runas_group(char *str, size_t strsize, char *unused)
1.1 misho 124: {
125: struct group *grp;
126: size_t len;
1.1.1.2 misho 127: debug_decl(fill_runas_group, SUDO_DEBUG_UTIL)
1.1 misho 128:
129: if (runas_gr != NULL) {
130: len = strlcpy(str, runas_gr->gr_name, strsize);
131: } else {
132: if ((grp = sudo_getgrgid(runas_pw->pw_gid)) != NULL) {
133: len = strlcpy(str, grp->gr_name, strsize);
1.1.1.3 ! misho 134: sudo_gr_delref(grp);
1.1 misho 135: } else {
136: len = strlen(str);
137: len = snprintf(str + len, strsize - len, "#%u",
138: (unsigned int) runas_pw->pw_gid);
139: }
140: }
1.1.1.2 misho 141: debug_return_size_t(len);
1.1 misho 142: }
143:
144: static size_t
1.1.1.3 ! misho 145: fill_hostname(char *str, size_t strsize, char *unused)
1.1 misho 146: {
1.1.1.2 misho 147: debug_decl(fill_hostname, SUDO_DEBUG_UTIL)
148: debug_return_size_t(strlcpy(str, user_shost, strsize));
1.1 misho 149: }
150:
151: static size_t
1.1.1.3 ! misho 152: fill_command(char *str, size_t strsize, char *unused)
1.1 misho 153: {
1.1.1.2 misho 154: debug_decl(fill_command, SUDO_DEBUG_UTIL)
155: debug_return_size_t(strlcpy(str, user_base, strsize));
1.1 misho 156: }
157:
158: /*
159: * Concatenate dir + file, expanding any escape sequences.
160: * Returns the concatenated path and sets slashp point to
161: * the path separator between the expanded dir and file.
162: */
163: char *
164: expand_iolog_path(const char *prefix, const char *dir, const char *file,
165: char **slashp)
166: {
167: size_t len, prelen = 0;
168: char *dst, *dst0, *path, *pathend, tmpbuf[PATH_MAX];
1.1.1.3 ! misho 169: char *slash = NULL;
1.1 misho 170: const char *endbrace, *src = dir;
1.1.1.3 ! misho 171: static struct path_escape *escapes;
1.1.1.2 misho 172: int pass;
173: bool strfit;
174: debug_decl(expand_iolog_path, SUDO_DEBUG_UTIL)
1.1 misho 175:
176: /* Expanded path must be <= PATH_MAX */
177: if (prefix != NULL)
178: prelen = strlen(prefix);
179: dst = path = emalloc(prelen + PATH_MAX);
180: *path = '\0';
181: pathend = path + prelen + PATH_MAX;
182:
183: /* Copy prefix, if present. */
184: if (prefix != NULL) {
185: memcpy(path, prefix, prelen);
186: dst += prelen;
187: *dst = '\0';
188: }
189:
190: /* Trim leading slashes from file component. */
191: while (*file == '/')
192: file++;
193:
194: for (pass = 0; pass < 3; pass++) {
1.1.1.2 misho 195: strfit = false;
1.1 misho 196: switch (pass) {
197: case 0:
198: src = dir;
1.1.1.3 ! misho 199: escapes = io_path_escapes + 1; /* skip "${seq}" */
1.1 misho 200: break;
201: case 1:
202: /* Trim trailing slashes from dir component. */
203: while (dst - path - 1 > prelen && dst[-1] == '/')
204: dst--;
1.1.1.3 ! misho 205: /* The NUL will be replaced with a '/' at the end. */
! 206: if (dst + 1 >= pathend)
! 207: goto bad;
! 208: slash = dst++;
! 209: continue;
1.1 misho 210: case 2:
211: src = file;
1.1.1.3 ! misho 212: escapes = io_path_escapes;
1.1 misho 213: break;
214: }
215: dst0 = dst;
216: for (; *src != '\0'; src++) {
217: if (src[0] == '%') {
218: if (src[1] == '{') {
219: endbrace = strchr(src + 2, '}');
220: if (endbrace != NULL) {
221: struct path_escape *esc;
222: len = (size_t)(endbrace - src - 2);
223: for (esc = escapes; esc->name != NULL; esc++) {
224: if (strncmp(src + 2, esc->name, len) == 0 &&
225: esc->name[len] == '\0')
226: break;
227: }
228: if (esc->name != NULL) {
1.1.1.3 ! misho 229: len = esc->copy_fn(dst, (size_t)(pathend - dst),
! 230: path + prelen);
1.1 misho 231: if (len >= (size_t)(pathend - dst))
232: goto bad;
233: dst += len;
234: src = endbrace;
235: continue;
236: }
237: }
238: } else if (src[1] == '%') {
239: /* Collapse %% -> % */
240: src++;
241: } else {
242: /* May need strftime() */
243: strfit = 1;
244: }
245: }
246: /* Need at least 2 chars, including the NUL terminator. */
247: if (dst + 1 >= pathend)
248: goto bad;
249: *dst++ = *src;
250: }
251: *dst = '\0';
252:
253: /* Expand strftime escapes as needed. */
254: if (strfit) {
255: time_t now;
256: struct tm *timeptr;
257:
258: time(&now);
259: timeptr = localtime(&now);
260:
261: #ifdef HAVE_SETLOCALE
262: if (!setlocale(LC_ALL, def_sudoers_locale)) {
263: warningx(_("unable to set locale to \"%s\", using \"C\""),
264: def_sudoers_locale);
265: setlocale(LC_ALL, "C");
266: }
267: #endif
268: /* We only calls strftime() on the current part of the buffer. */
269: tmpbuf[sizeof(tmpbuf) - 1] = '\0';
270: len = strftime(tmpbuf, sizeof(tmpbuf), dst0, timeptr);
271:
272: #ifdef HAVE_SETLOCALE
273: setlocale(LC_ALL, "");
274: #endif
275: if (len == 0 || tmpbuf[sizeof(tmpbuf) - 1] != '\0')
276: goto bad; /* strftime() failed, buf too small? */
277:
278: if (len >= (size_t)(pathend - dst0))
279: goto bad; /* expanded buffer too big to fit. */
280: memcpy(dst0, tmpbuf, len);
281: dst = dst0 + len;
282: *dst = '\0';
283: }
284: }
1.1.1.3 ! misho 285: if (slashp)
! 286: *slashp = slash;
! 287: *slash = '/';
1.1 misho 288:
1.1.1.2 misho 289: debug_return_str(path);
1.1 misho 290: bad:
291: efree(path);
1.1.1.2 misho 292: debug_return_str(NULL);
1.1 misho 293: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>