File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers / iolog_path.c
Revision 1.1.1.6 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:12:54 2014 UTC (10 years, 1 month ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_10p3_0, v1_8_10p3, HEAD
sudo v 1.8.10p3

    1: /*
    2:  * Copyright (c) 2011-2013 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: #include <pwd.h>
   39: #include <grp.h>
   40: #include <time.h>
   41: 
   42: #include "sudoers.h"
   43: 
   44: struct path_escape {
   45:     const char *name;
   46:     size_t (*copy_fn)(char *, size_t, char *);
   47: };
   48: 
   49: static size_t
   50: fill_seq(char *str, size_t strsize, char *logdir)
   51: {
   52: #ifdef SUDOERS_NO_SEQ
   53:     debug_decl(fill_seq, SUDO_DEBUG_UTIL)
   54:     debug_return_size_t(strlcpy(str, "%{seq}", strsize));
   55: #else
   56:     static char sessid[7];
   57:     int len;
   58:     debug_decl(fill_seq, SUDO_DEBUG_UTIL)
   59: 
   60:     if (sessid[0] == '\0')
   61: 	io_nextid(logdir, def_iolog_dir, sessid);
   62: 
   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]);
   66:     if (len < 0)
   67: 	debug_return_size_t(strsize); /* handle non-standard snprintf() */
   68:     debug_return_size_t(len);
   69: #endif /* SUDOERS_NO_SEQ */
   70: }
   71: 
   72: static size_t
   73: fill_user(char *str, size_t strsize, char *unused)
   74: {
   75:     debug_decl(fill_user, SUDO_DEBUG_UTIL)
   76:     debug_return_size_t(strlcpy(str, user_name, strsize));
   77: }
   78: 
   79: static size_t
   80: fill_group(char *str, size_t strsize, char *unused)
   81: {
   82:     struct group *grp;
   83:     size_t len;
   84:     debug_decl(fill_group, SUDO_DEBUG_UTIL)
   85: 
   86:     if ((grp = sudo_getgrgid(user_gid)) != NULL) {
   87: 	len = strlcpy(str, grp->gr_name, strsize);
   88: 	sudo_gr_delref(grp);
   89:     } else {
   90: 	len = strlen(str);
   91: 	len = snprintf(str + len, strsize - len, "#%u",
   92: 	    (unsigned int) user_gid);
   93:     }
   94:     debug_return_size_t(len);
   95: }
   96: 
   97: static size_t
   98: fill_runas_user(char *str, size_t strsize, char *unused)
   99: {
  100:     debug_decl(fill_runas_user, SUDO_DEBUG_UTIL)
  101:     debug_return_size_t(strlcpy(str, runas_pw->pw_name, strsize));
  102: }
  103: 
  104: static size_t
  105: fill_runas_group(char *str, size_t strsize, char *unused)
  106: {
  107:     struct group *grp;
  108:     size_t len;
  109:     debug_decl(fill_runas_group, SUDO_DEBUG_UTIL)
  110: 
  111:     if (runas_gr != NULL) {
  112: 	len = strlcpy(str, runas_gr->gr_name, strsize);
  113:     } else {
  114: 	if ((grp = sudo_getgrgid(runas_pw->pw_gid)) != NULL) {
  115: 	    len = strlcpy(str, grp->gr_name, strsize);
  116: 	    sudo_gr_delref(grp);
  117: 	} else {
  118: 	    len = strlen(str);
  119: 	    len = snprintf(str + len, strsize - len, "#%u",
  120: 		(unsigned int) runas_pw->pw_gid);
  121: 	}
  122:     }
  123:     debug_return_size_t(len);
  124: }
  125: 
  126: static size_t
  127: fill_hostname(char *str, size_t strsize, char *unused)
  128: {
  129:     debug_decl(fill_hostname, SUDO_DEBUG_UTIL)
  130:     debug_return_size_t(strlcpy(str, user_shost, strsize));
  131: }
  132: 
  133: static size_t
  134: fill_command(char *str, size_t strsize, char *unused)
  135: {
  136:     debug_decl(fill_command, SUDO_DEBUG_UTIL)
  137:     debug_return_size_t(strlcpy(str, user_base, strsize));
  138: }
  139: 
  140: /* Note: "seq" must be first in the list. */
  141: static struct path_escape io_path_escapes[] = {
  142:     { "seq", fill_seq },
  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 },
  149:     { NULL, NULL }
  150: };
  151: 
  152: /*
  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.
  156:  */
  157: char *
  158: expand_iolog_path(const char *prefix, const char *dir, const char *file,
  159:     char **slashp)
  160: {
  161:     size_t len, prelen = 0;
  162:     char *dst, *dst0, *path, *pathend, tmpbuf[PATH_MAX];
  163:     char *slash = NULL;
  164:     const char *endbrace, *src = dir;
  165:     struct path_escape *escapes = NULL;
  166:     int pass, oldlocale;
  167:     bool strfit;
  168:     debug_decl(expand_iolog_path, SUDO_DEBUG_UTIL)
  169: 
  170:     /* Expanded path must be <= PATH_MAX */
  171:     if (prefix != NULL)
  172: 	prelen = strlen(prefix);
  173:     dst = path = emalloc(prelen + PATH_MAX);
  174:     *path = '\0';
  175:     pathend = path + prelen + PATH_MAX;
  176: 
  177:     /* Copy prefix, if present. */
  178:     if (prefix != NULL) {
  179: 	memcpy(path, prefix, prelen);
  180: 	dst += prelen;
  181: 	*dst = '\0';
  182:     }
  183: 
  184:     /* Trim leading slashes from file component. */
  185:     while (*file == '/')
  186: 	file++;
  187: 
  188:     for (pass = 0; pass < 3; pass++) {
  189: 	strfit = false;
  190: 	switch (pass) {
  191: 	case 0:
  192: 	    src = dir;
  193: 	    escapes = io_path_escapes + 1; /* skip "%{seq}" */
  194: 	    break;
  195: 	case 1:
  196: 	    /* Trim trailing slashes from dir component. */
  197: 	    while (dst > path + prelen + 1 && dst[-1] == '/')
  198: 		dst--;
  199: 	    /* The NUL will be replaced with a '/' at the end. */
  200: 	    if (dst + 1 >= pathend)
  201: 		goto bad;
  202: 	    slash = dst++;
  203: 	    continue;
  204: 	case 2:
  205: 	    src = file;
  206: 	    escapes = io_path_escapes;
  207: 	    break;
  208: 	}
  209: 	dst0 = dst;
  210: 	for (; *src != '\0'; src++) {
  211: 	    if (src[0] == '%') {
  212: 		if (src[1] == '{') {
  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')
  220: 				break;
  221: 			}
  222: 			if (esc->name != NULL) {
  223: 			    len = esc->copy_fn(dst, (size_t)(pathend - dst),
  224: 				path + prelen);
  225: 			    if (len >= (size_t)(pathend - dst))
  226: 				goto bad;
  227: 			    dst += len;
  228: 			    src = endbrace;
  229: 			    continue;
  230: 			}
  231: 		    }
  232: 		} else if (src[1] == '%') {
  233: 		    /* Collapse %% -> % */
  234: 		    src++;
  235: 		} else {
  236: 		    /* May need strftime() */
  237: 		    strfit = 1;
  238: 		}
  239: 	    }
  240: 	    /* Need at least 2 chars, including the NUL terminator. */
  241: 	    if (dst + 1 >= pathend)
  242: 		goto bad;
  243: 	    *dst++ = *src;
  244: 	}
  245: 	*dst = '\0';
  246: 
  247: 	/* Expand strftime escapes as needed. */
  248: 	if (strfit) {
  249: 	    time_t now;
  250: 	    struct tm *timeptr;
  251: 
  252: 	    time(&now);
  253: 	    if ((timeptr = localtime(&now)) == NULL)
  254: 		goto bad;
  255: 
  256: 	    /* Use sudoers locale for strftime() */
  257: 	    sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
  258: 
  259: 	    /* We only call strftime() on the current part of the buffer. */
  260: 	    tmpbuf[sizeof(tmpbuf) - 1] = '\0';
  261: 	    len = strftime(tmpbuf, sizeof(tmpbuf), dst0, timeptr);
  262: 
  263: 	    /* Restore old locale. */
  264: 	    sudoers_setlocale(oldlocale, NULL);
  265: 
  266: 	    if (len == 0 || tmpbuf[sizeof(tmpbuf) - 1] != '\0')
  267: 		goto bad;		/* strftime() failed, buf too small? */
  268: 
  269: 	    if (len >= (size_t)(pathend - dst0))
  270: 		goto bad;		/* expanded buffer too big to fit. */
  271: 	    memcpy(dst0, tmpbuf, len);
  272: 	    dst = dst0 + len;
  273: 	    *dst = '\0';
  274: 	}
  275:     }
  276:     if (slashp)
  277: 	*slashp = slash;
  278:     *slash = '/';
  279: 
  280:     debug_return_str(path);
  281: bad:
  282:     efree(path);
  283:     debug_return_str(NULL);
  284: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>