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>