Annotation of embedaddon/sudo/plugins/sudoers/iolog_path.c, revision 1.1.1.2

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;
                     49:     size_t (*copy_fn)(char *, size_t);
                     50: };
                     51: 
                     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);
                     59: 
                     60: static struct path_escape escapes[] = {
                     61:     { "seq", fill_seq },
                     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 },
                     68:     { NULL, NULL }
                     69: };
                     70: 
                     71: static size_t
                     72: fill_seq(char *str, size_t strsize)
                     73: {
                     74:     static char sessid[7];
                     75:     int len;
1.1.1.2 ! misho      76:     debug_decl(sudoers_io_version, SUDO_DEBUG_UTIL)
1.1       misho      77: 
                     78:     if (sessid[0] == '\0')
                     79:        io_nextid(def_iolog_dir, sessid);
                     80: 
                     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]);
                     84:     if (len < 0)
1.1.1.2 ! misho      85:        debug_return_size_t(strsize); /* handle non-standard snprintf() */
        !            86:     debug_return_size_t(len);
1.1       misho      87: }
                     88: 
                     89: static size_t
                     90: fill_user(char *str, size_t strsize)
                     91: {
1.1.1.2 ! misho      92:     debug_decl(fill_user, SUDO_DEBUG_UTIL)
        !            93:     debug_return_size_t(strlcpy(str, user_name, strsize));
1.1       misho      94: }
                     95: 
                     96: static size_t
                     97: fill_group(char *str, size_t strsize)
                     98: {
                     99:     struct group *grp;
                    100:     size_t len;
1.1.1.2 ! misho     101:     debug_decl(fill_group, SUDO_DEBUG_UTIL)
1.1       misho     102: 
                    103:     if ((grp = sudo_getgrgid(user_gid)) != NULL) {
                    104:        len = strlcpy(str, grp->gr_name, strsize);
                    105:        gr_delref(grp);
                    106:     } else {
                    107:        len = strlen(str);
                    108:        len = snprintf(str + len, strsize - len, "#%u",
                    109:            (unsigned int) user_gid);
                    110:     }
1.1.1.2 ! misho     111:     debug_return_size_t(len);
1.1       misho     112: }
                    113: 
                    114: static size_t
                    115: fill_runas_user(char *str, size_t strsize)
                    116: {
1.1.1.2 ! misho     117:     debug_decl(fill_runas_user, SUDO_DEBUG_UTIL)
        !           118:     debug_return_size_t(strlcpy(str, runas_pw->pw_name, strsize));
1.1       misho     119: }
                    120: 
                    121: static size_t
                    122: fill_runas_group(char *str, size_t strsize)
                    123: {
                    124:     struct group *grp;
                    125:     size_t len;
1.1.1.2 ! misho     126:     debug_decl(fill_runas_group, SUDO_DEBUG_UTIL)
1.1       misho     127: 
                    128:     if (runas_gr != NULL) {
                    129:        len = strlcpy(str, runas_gr->gr_name, strsize);
                    130:     } else {
                    131:        if ((grp = sudo_getgrgid(runas_pw->pw_gid)) != NULL) {
                    132:            len = strlcpy(str, grp->gr_name, strsize);
                    133:            gr_delref(grp);
                    134:        } else {
                    135:            len = strlen(str);
                    136:            len = snprintf(str + len, strsize - len, "#%u",
                    137:                (unsigned int) runas_pw->pw_gid);
                    138:        }
                    139:     }
1.1.1.2 ! misho     140:     debug_return_size_t(len);
1.1       misho     141: }
                    142: 
                    143: static size_t
                    144: fill_hostname(char *str, size_t strsize)
                    145: {
1.1.1.2 ! misho     146:     debug_decl(fill_hostname, SUDO_DEBUG_UTIL)
        !           147:     debug_return_size_t(strlcpy(str, user_shost, strsize));
1.1       misho     148: }
                    149: 
                    150: static size_t
                    151: fill_command(char *str, size_t strsize)
                    152: {
1.1.1.2 ! misho     153:     debug_decl(fill_command, SUDO_DEBUG_UTIL)
        !           154:     debug_return_size_t(strlcpy(str, user_base, strsize));
1.1       misho     155: }
                    156: 
                    157: /*
                    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.
                    161:  */
                    162: char *
                    163: expand_iolog_path(const char *prefix, const char *dir, const char *file,
                    164:     char **slashp)
                    165: {
                    166:     size_t len, prelen = 0;
                    167:     char *dst, *dst0, *path, *pathend, tmpbuf[PATH_MAX];
                    168:     const char *endbrace, *src = dir;
1.1.1.2 ! misho     169:     int pass;
        !           170:     bool strfit;
        !           171:     debug_decl(expand_iolog_path, SUDO_DEBUG_UTIL)
1.1       misho     172: 
                    173:     /* Expanded path must be <= PATH_MAX */
                    174:     if (prefix != NULL)
                    175:        prelen = strlen(prefix);
                    176:     dst = path = emalloc(prelen + PATH_MAX);
                    177:     *path = '\0';
                    178:     pathend = path + prelen + PATH_MAX;
                    179: 
                    180:     /* Copy prefix, if present. */
                    181:     if (prefix != NULL) {
                    182:        memcpy(path, prefix, prelen);
                    183:        dst += prelen;
                    184:        *dst = '\0';
                    185:     }
                    186: 
                    187:     /* Trim leading slashes from file component. */
                    188:     while (*file == '/')
                    189:        file++;
                    190: 
                    191:     for (pass = 0; pass < 3; pass++) {
1.1.1.2 ! misho     192:        strfit = false;
1.1       misho     193:        switch (pass) {
                    194:        case 0:
                    195:            src = dir;
                    196:            break;
                    197:        case 1:
                    198:            /* Trim trailing slashes from dir component. */
                    199:            while (dst - path - 1 > prelen && dst[-1] == '/')
                    200:                dst--;
                    201:            if (slashp)
                    202:                *slashp = dst;
                    203:            src = "/";
                    204:            break;
                    205:        case 2:
                    206:            src = file;
                    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:                            if (len >= (size_t)(pathend - dst))
                    225:                                goto bad;
                    226:                            dst += len;
                    227:                            src = endbrace;
                    228:                            continue;
                    229:                        }
                    230:                    }
                    231:                } else if (src[1] == '%') {
                    232:                    /* Collapse %% -> % */
                    233:                    src++;
                    234:                } else {
                    235:                    /* May need strftime() */
                    236:                    strfit = 1;
                    237:                }
                    238:            }
                    239:            /* Need at least 2 chars, including the NUL terminator. */
                    240:            if (dst + 1 >= pathend)
                    241:                goto bad;
                    242:            *dst++ = *src;
                    243:        }
                    244:        *dst = '\0';
                    245: 
                    246:        /* Expand strftime escapes as needed. */
                    247:        if (strfit) {
                    248:            time_t now;
                    249:            struct tm *timeptr;
                    250: 
                    251:            time(&now);
                    252:            timeptr = localtime(&now);
                    253: 
                    254: #ifdef HAVE_SETLOCALE
                    255:            if (!setlocale(LC_ALL, def_sudoers_locale)) {
                    256:                warningx(_("unable to set locale to \"%s\", using \"C\""),
                    257:                    def_sudoers_locale);
                    258:                setlocale(LC_ALL, "C");
                    259:            }
                    260: #endif
                    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);
                    264: 
                    265: #ifdef HAVE_SETLOCALE
                    266:            setlocale(LC_ALL, "");
                    267: #endif
                    268:            if (len == 0 || tmpbuf[sizeof(tmpbuf) - 1] != '\0')
                    269:                goto bad;               /* strftime() failed, buf too small? */
                    270: 
                    271:            if (len >= (size_t)(pathend - dst0))
                    272:                goto bad;               /* expanded buffer too big to fit. */
                    273:            memcpy(dst0, tmpbuf, len);
                    274:            dst = dst0 + len;
                    275:            *dst = '\0';
                    276:        }
                    277:     }
                    278: 
1.1.1.2 ! misho     279:     debug_return_str(path);
1.1       misho     280: bad:
                    281:     efree(path);
1.1.1.2 ! misho     282:     debug_return_str(NULL);
1.1       misho     283: }

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