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

1.1       misho       1: /*
1.1.1.4   misho       2:  * Copyright (c) 2011-2013 Todd C. Miller <Todd.Miller@courtesan.com>
1.1       misho       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;
1.1.1.3   misho      46:     size_t (*copy_fn)(char *, size_t, char *);
1.1       misho      47: };
                     48: 
                     49: static size_t
1.1.1.3   misho      50: fill_seq(char *str, size_t strsize, char *logdir)
1.1       misho      51: {
1.1.1.4   misho      52: #ifdef SUDOERS_NO_SEQ
                     53:     debug_decl(fill_seq, SUDO_DEBUG_UTIL)
                     54:     debug_return_size_t(strlcpy(str, "%{seq}", strsize));
                     55: #else
1.1       misho      56:     static char sessid[7];
                     57:     int len;
1.1.1.4   misho      58:     debug_decl(fill_seq, SUDO_DEBUG_UTIL)
1.1       misho      59: 
                     60:     if (sessid[0] == '\0')
1.1.1.3   misho      61:        io_nextid(logdir, def_iolog_dir, sessid);
1.1       misho      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)
1.1.1.2   misho      67:        debug_return_size_t(strsize); /* handle non-standard snprintf() */
                     68:     debug_return_size_t(len);
1.1.1.4   misho      69: #endif /* SUDOERS_NO_SEQ */
1.1       misho      70: }
                     71: 
                     72: static size_t
1.1.1.3   misho      73: fill_user(char *str, size_t strsize, char *unused)
1.1       misho      74: {
1.1.1.2   misho      75:     debug_decl(fill_user, SUDO_DEBUG_UTIL)
                     76:     debug_return_size_t(strlcpy(str, user_name, strsize));
1.1       misho      77: }
                     78: 
                     79: static size_t
1.1.1.3   misho      80: fill_group(char *str, size_t strsize, char *unused)
1.1       misho      81: {
                     82:     struct group *grp;
                     83:     size_t len;
1.1.1.2   misho      84:     debug_decl(fill_group, SUDO_DEBUG_UTIL)
1.1       misho      85: 
                     86:     if ((grp = sudo_getgrgid(user_gid)) != NULL) {
                     87:        len = strlcpy(str, grp->gr_name, strsize);
1.1.1.3   misho      88:        sudo_gr_delref(grp);
1.1       misho      89:     } else {
                     90:        len = strlen(str);
                     91:        len = snprintf(str + len, strsize - len, "#%u",
                     92:            (unsigned int) user_gid);
                     93:     }
1.1.1.2   misho      94:     debug_return_size_t(len);
1.1       misho      95: }
                     96: 
                     97: static size_t
1.1.1.3   misho      98: fill_runas_user(char *str, size_t strsize, char *unused)
1.1       misho      99: {
1.1.1.2   misho     100:     debug_decl(fill_runas_user, SUDO_DEBUG_UTIL)
                    101:     debug_return_size_t(strlcpy(str, runas_pw->pw_name, strsize));
1.1       misho     102: }
                    103: 
                    104: static size_t
1.1.1.3   misho     105: fill_runas_group(char *str, size_t strsize, char *unused)
1.1       misho     106: {
                    107:     struct group *grp;
                    108:     size_t len;
1.1.1.2   misho     109:     debug_decl(fill_runas_group, SUDO_DEBUG_UTIL)
1.1       misho     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);
1.1.1.3   misho     116:            sudo_gr_delref(grp);
1.1       misho     117:        } else {
                    118:            len = strlen(str);
                    119:            len = snprintf(str + len, strsize - len, "#%u",
                    120:                (unsigned int) runas_pw->pw_gid);
                    121:        }
                    122:     }
1.1.1.2   misho     123:     debug_return_size_t(len);
1.1       misho     124: }
                    125: 
                    126: static size_t
1.1.1.3   misho     127: fill_hostname(char *str, size_t strsize, char *unused)
1.1       misho     128: {
1.1.1.2   misho     129:     debug_decl(fill_hostname, SUDO_DEBUG_UTIL)
                    130:     debug_return_size_t(strlcpy(str, user_shost, strsize));
1.1       misho     131: }
                    132: 
                    133: static size_t
1.1.1.3   misho     134: fill_command(char *str, size_t strsize, char *unused)
1.1       misho     135: {
1.1.1.2   misho     136:     debug_decl(fill_command, SUDO_DEBUG_UTIL)
                    137:     debug_return_size_t(strlcpy(str, user_base, strsize));
1.1       misho     138: }
                    139: 
1.1.1.4   misho     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: 
1.1       misho     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];
1.1.1.3   misho     163:     char *slash = NULL;
1.1       misho     164:     const char *endbrace, *src = dir;
1.1.1.4   misho     165:     struct path_escape *escapes = NULL;
                    166:     int pass, oldlocale;
1.1.1.2   misho     167:     bool strfit;
                    168:     debug_decl(expand_iolog_path, SUDO_DEBUG_UTIL)
1.1       misho     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++) {
1.1.1.2   misho     189:        strfit = false;
1.1       misho     190:        switch (pass) {
                    191:        case 0:
                    192:            src = dir;
1.1.1.4   misho     193:            escapes = io_path_escapes + 1; /* skip "%{seq}" */
1.1       misho     194:            break;
                    195:        case 1:
                    196:            /* Trim trailing slashes from dir component. */
1.1.1.6 ! misho     197:            while (dst > path + prelen + 1 && dst[-1] == '/')
1.1       misho     198:                dst--;
1.1.1.3   misho     199:            /* The NUL will be replaced with a '/' at the end. */
                    200:            if (dst + 1 >= pathend)
                    201:                goto bad;
                    202:            slash = dst++;
                    203:            continue;
1.1       misho     204:        case 2:
                    205:            src = file;
1.1.1.3   misho     206:            escapes = io_path_escapes;
1.1       misho     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) {
1.1.1.3   misho     223:                            len = esc->copy_fn(dst, (size_t)(pathend - dst),
                    224:                                path + prelen);
1.1       misho     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);
1.1.1.6 ! misho     253:            if ((timeptr = localtime(&now)) == NULL)
        !           254:                goto bad;
1.1       misho     255: 
1.1.1.4   misho     256:            /* Use sudoers locale for strftime() */
                    257:            sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
                    258: 
1.1.1.5   misho     259:            /* We only call strftime() on the current part of the buffer. */
1.1       misho     260:            tmpbuf[sizeof(tmpbuf) - 1] = '\0';
                    261:            len = strftime(tmpbuf, sizeof(tmpbuf), dst0, timeptr);
                    262: 
1.1.1.4   misho     263:            /* Restore old locale. */
                    264:            sudoers_setlocale(oldlocale, NULL);
                    265: 
1.1       misho     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:     }
1.1.1.3   misho     276:     if (slashp)
                    277:        *slashp = slash;
                    278:     *slash = '/';
1.1       misho     279: 
1.1.1.2   misho     280:     debug_return_str(path);
1.1       misho     281: bad:
                    282:     efree(path);
1.1.1.2   misho     283:     debug_return_str(NULL);
1.1       misho     284: }

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