Annotation of embedaddon/sudo/common/sudo_debug.c, revision 1.1.1.1

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 <sys/param.h>
                     21: #include <sys/stat.h>
                     22: #include <sys/uio.h>
                     23: #include <stdio.h>
                     24: #ifdef STDC_HEADERS
                     25: # include <stdlib.h>
                     26: # include <stddef.h>
                     27: #else
                     28: # ifdef HAVE_STDLIB_H
                     29: #  include <stdlib.h>
                     30: # endif
                     31: #endif /* STDC_HEADERS */
                     32: #ifdef HAVE_STDBOOL_H
                     33: # include <stdbool.h>
                     34: #else
                     35: # include "compat/stdbool.h"
                     36: #endif
                     37: #ifdef HAVE_STRING_H
                     38: # include <string.h>
                     39: #endif /* HAVE_STRING_H */
                     40: #ifdef HAVE_STRINGS_H
                     41: # include <strings.h>
                     42: #endif /* HAVE_STRINGS_H */
                     43: #ifdef HAVE_UNISTD_H
                     44: # include <unistd.h>
                     45: #endif /* HAVE_UNISTD_H */
                     46: #include <ctype.h>
                     47: #include <errno.h>
                     48: #include <fcntl.h>
                     49: #include <time.h>
                     50: 
                     51: #include "missing.h"
                     52: #include "alloc.h"
                     53: #include "error.h"
                     54: #include "gettext.h"
                     55: #include "sudo_plugin.h"
                     56: #include "sudo_debug.h"
                     57: 
                     58: /*
                     59:  * The debug priorities and subsystems are currently hard-coded.
                     60:  * In the future we might consider allowing plugins to register their
                     61:  * own subsystems and provide direct access to the debugging API.
                     62:  */
                     63: 
                     64: /* Note: this must match the order in sudo_debug.h */
                     65: const char *const sudo_debug_priorities[] = {
                     66:     "crit",
                     67:     "err",
                     68:     "warn",
                     69:     "notice",
                     70:     "diag",
                     71:     "info",
                     72:     "trace",
                     73:     "debug",
                     74:     NULL
                     75: };
                     76: 
                     77: /* Note: this must match the order in sudo_debug.h */
                     78: const char *const sudo_debug_subsystems[] = {
                     79:     "main",
                     80:     "args",
                     81:     "exec",
                     82:     "pty",
                     83:     "utmp",
                     84:     "conv",
                     85:     "pcomm",
                     86:     "util",
                     87:     "netif",
                     88:     "audit",
                     89:     "edit",
                     90:     "selinux",
                     91:     "ldap",
                     92:     "match",
                     93:     "parser",
                     94:     "alias",
                     95:     "defaults",
                     96:     "auth",
                     97:     "env",
                     98:     "logging",
                     99:     "nss",
                    100:     "rbtree",
                    101:     "perms",
                    102:     "plugin",
                    103:     "hooks",
                    104:     NULL
                    105: };
                    106: 
                    107: #define NUM_SUBSYSTEMS (sizeof(sudo_debug_subsystems) / sizeof(sudo_debug_subsystems[0]) - 1)
                    108: 
                    109: /* Values for sudo_debug_mode */
                    110: #define SUDO_DEBUG_MODE_DISABLED       0
                    111: #define SUDO_DEBUG_MODE_FILE           1
                    112: #define SUDO_DEBUG_MODE_CONV           2
                    113: 
                    114: static int sudo_debug_settings[NUM_SUBSYSTEMS];
                    115: static int sudo_debug_fd = -1;
                    116: static int sudo_debug_mode;
                    117: static char sudo_debug_pidstr[(((sizeof(int) * 8) + 2) / 3) + 3];
                    118: static size_t sudo_debug_pidlen;
                    119: 
                    120: extern sudo_conv_t sudo_conv;
                    121: 
                    122: /*
                    123:  * Parse settings string from sudo.conf and open debugfile.
                    124:  * Returns 1 on success, 0 if cannot open debugfile.
                    125:  * Unsupported subsystems and priorities are silently ignored.
                    126:  */
                    127: int sudo_debug_init(const char *debugfile, const char *settings)
                    128: {
                    129:     char *buf, *cp, *subsys, *pri;
                    130:     int i, j;
                    131: 
                    132:     /* Init per-subsystems settings to -1 since 0 is a valid priority. */
                    133:     for (i = 0; i < NUM_SUBSYSTEMS; i++)
                    134:        sudo_debug_settings[i] = -1;
                    135: 
                    136:     /* Open debug file if specified. */
                    137:     if (debugfile != NULL) {
                    138:        if (sudo_debug_fd != -1)
                    139:            close(sudo_debug_fd);
                    140:        sudo_debug_fd = open(debugfile, O_WRONLY|O_APPEND|O_CREAT,
                    141:            S_IRUSR|S_IWUSR);
                    142:        if (sudo_debug_fd == -1)
                    143:            return 0;
                    144:        (void)fcntl(sudo_debug_fd, F_SETFD, FD_CLOEXEC);
                    145:        sudo_debug_mode = SUDO_DEBUG_MODE_FILE;
                    146:     } else {
                    147:        /* Called from the plugin, no debug file. */
                    148:        sudo_debug_mode = SUDO_DEBUG_MODE_CONV;
                    149:     }
                    150: 
                    151:     /* Parse settings string. */
                    152:     buf = estrdup(settings);
                    153:     for ((cp = strtok(buf, ",")); cp != NULL; (cp = strtok(NULL, ","))) {
                    154:        /* Should be in the form subsys@pri. */
                    155:        subsys = cp;
                    156:        if ((pri = strchr(cp, '@')) == NULL)
                    157:            continue;
                    158:        *pri++ = '\0';
                    159: 
                    160:        /* Look up priority and subsystem, fill in sudo_debug_settings[]. */
                    161:        for (i = 0; sudo_debug_priorities[i] != NULL; i++) {
                    162:            if (strcasecmp(pri, sudo_debug_priorities[i]) == 0) {
                    163:                for (j = 0; sudo_debug_subsystems[j] != NULL; j++) {
                    164:                    if (strcasecmp(subsys, "all") == 0) {
                    165:                        sudo_debug_settings[j] = i;
                    166:                        continue;
                    167:                    }
                    168:                    if (strcasecmp(subsys, sudo_debug_subsystems[j]) == 0) {
                    169:                        sudo_debug_settings[j] = i;
                    170:                        break;
                    171:                    }
                    172:                }
                    173:                break;
                    174:            }
                    175:        }
                    176:     }
                    177:     efree(buf);
                    178: 
                    179:     (void)snprintf(sudo_debug_pidstr, sizeof(sudo_debug_pidstr), "[%d] ",
                    180:        (int)getpid());
                    181:     sudo_debug_pidlen = strlen(sudo_debug_pidstr);
                    182: 
                    183:     return 1;
                    184: }
                    185: 
                    186: pid_t
                    187: sudo_debug_fork(void)
                    188: {
                    189:     pid_t pid;
                    190: 
                    191:     if ((pid = fork()) == 0) {
                    192:        (void)snprintf(sudo_debug_pidstr, sizeof(sudo_debug_pidstr), "[%d] ",
                    193:            (int)getpid());
                    194:        sudo_debug_pidlen = strlen(sudo_debug_pidstr);
                    195:     }
                    196: 
                    197:     return pid;
                    198: }
                    199: 
                    200: void
                    201: sudo_debug_enter(const char *func, const char *file, int line,
                    202:     int subsys)
                    203: {
                    204:     sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE,
                    205:        "-> %s @ %s:%d", func, file, line);
                    206: }
                    207: 
                    208: void sudo_debug_exit(const char *func, const char *file, int line,
                    209:     int subsys)
                    210: {
                    211:     sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE,
                    212:        "<- %s @ %s:%d", func, file, line);
                    213: }
                    214: 
                    215: void sudo_debug_exit_int(const char *func, const char *file, int line,
                    216:     int subsys, int rval)
                    217: {
                    218:     sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE,
                    219:        "<- %s @ %s:%d := %d", func, file, line, rval);
                    220: }
                    221: 
                    222: void sudo_debug_exit_long(const char *func, const char *file, int line,
                    223:     int subsys, long rval)
                    224: {
                    225:     sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE,
                    226:        "<- %s @ %s:%d := %ld", func, file, line, rval);
                    227: }
                    228: 
                    229: void sudo_debug_exit_size_t(const char *func, const char *file, int line,
                    230:     int subsys, size_t rval)
                    231: {
                    232:     /* XXX - should use %zu but our snprintf.c doesn't support it */
                    233:     sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE,
                    234:        "<- %s @ %s:%d := %lu", func, file, line, (unsigned long)rval);
                    235: }
                    236: 
                    237: /* We use int, not bool, here for functions that return -1 on error. */
                    238: void sudo_debug_exit_bool(const char *func, const char *file, int line,
                    239:     int subsys, int rval)
                    240: {
                    241:     if (rval == true || rval == false) {
                    242:        sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE,
                    243:            "<- %s @ %s:%d := %s", func, file, line, rval ? "true" : "false");
                    244:     } else {
                    245:        sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE,
                    246:            "<- %s @ %s:%d := %d", func, file, line, rval);
                    247:     }
                    248: }
                    249: 
                    250: void sudo_debug_exit_str(const char *func, const char *file, int line,
                    251:     int subsys, const char *rval)
                    252: {
                    253:     sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE,
                    254:        "<- %s @ %s:%d := %s", func, file, line, rval ? rval : "(null)");
                    255: }
                    256: 
                    257: void sudo_debug_exit_str_masked(const char *func, const char *file, int line,
                    258:     int subsys, const char *rval)
                    259: {
                    260:     static const char stars[] = "********************************************************************************";
                    261:     int len = rval ? strlen(rval) : sizeof("(null)") - 1;
                    262: 
                    263:     sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE,
                    264:        "<- %s @ %s:%d := %.*s", func, file, line, len, rval ? stars : "(null)");
                    265: }
                    266: 
                    267: void sudo_debug_exit_ptr(const char *func, const char *file, int line,
                    268:     int subsys, const void *rval)
                    269: {
                    270:     sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE,
                    271:        "<- %s @ %s:%d := %p", func, file, line, rval);
                    272: }
                    273: 
                    274: static void
                    275: sudo_debug_write_conv(const char *func, const char *file, int lineno,
                    276:     const char *str, int len, int errno_val)
                    277: {
                    278:     struct sudo_conv_message msg;
                    279:     struct sudo_conv_reply repl;
                    280:     char *buf = NULL;
                    281: 
                    282:     /* Call conversation function */
                    283:     if (sudo_conv != NULL) {
                    284:        /* Remove the newline at the end if appending extra info. */
                    285:        if (str[len - 1] == '\n')
                    286:            len--;
                    287: 
                    288:        if (func != NULL && file != NULL && lineno != 0) {
                    289:            if (errno_val) {
                    290:                easprintf(&buf, "%.*s: %s @ %s() %s:%d", len, str,
                    291:                    strerror(errno_val), func, file, lineno);
                    292:            } else {
                    293:                easprintf(&buf, "%.*s @ %s() %s:%d", len, str,
                    294:                    func, file, lineno);
                    295:            }
                    296:            str = buf;
                    297:        } else if (errno_val) {
                    298:            easprintf(&buf, "%.*s: %s", len, str, strerror(errno_val));
                    299:            str = buf;
                    300:        }
                    301:        memset(&msg, 0, sizeof(msg));
                    302:        memset(&repl, 0, sizeof(repl));
                    303:        msg.msg_type = SUDO_CONV_DEBUG_MSG;
                    304:        msg.msg = str;
                    305:        sudo_conv(1, &msg, &repl);
                    306:        if (buf != NULL)
                    307:            efree(buf);
                    308:     }
                    309: }
                    310: 
                    311: static void
                    312: sudo_debug_write_file(const char *func, const char *file, int lineno,
                    313:     const char *str, int len, int errno_val)
                    314: {
                    315:     char *timestr, numbuf[(((sizeof(int) * 8) + 2) / 3) + 2];
                    316:     time_t now;
                    317:     struct iovec iov[12];
                    318:     int iovcnt = 4;
                    319:     bool need_newline = false;
                    320: 
                    321:     /* Prepend program name and pid with a trailing space. */
                    322:     iov[1].iov_base = (char *)getprogname();
                    323:     iov[1].iov_len = strlen(iov[1].iov_base);
                    324:     iov[2].iov_base = sudo_debug_pidstr;
                    325:     iov[2].iov_len = sudo_debug_pidlen;
                    326: 
                    327:     /* Add string along with newline if it doesn't have one. */
                    328:     iov[3].iov_base = (char *)str;
                    329:     iov[3].iov_len = len;
                    330:     if (str[len - 1] != '\n')
                    331:        need_newline = true;
                    332: 
                    333:     /* Append error string if errno is specified. */
                    334:     if (errno_val) {
                    335:        iov[iovcnt].iov_base = ": ";
                    336:        iov[iovcnt].iov_len = 2;
                    337:        iovcnt++;
                    338:        iov[iovcnt].iov_base = strerror(errno_val);
                    339:        iov[iovcnt].iov_len = strlen(iov[iovcnt].iov_base);
                    340:        iovcnt++;
                    341: 
                    342:        /* Move newline to the end. */
                    343:        if (!need_newline) {
                    344:            need_newline = true;
                    345:            iov[3].iov_len--;
                    346:        }
                    347:     }
                    348: 
                    349:     /* If function, file and lineno are specified, append them. */
                    350:     if (func != NULL && file != NULL && lineno != 0) {
                    351:        iov[iovcnt].iov_base = " @ ";
                    352:        iov[iovcnt].iov_len = 3;
                    353:        iovcnt++;
                    354: 
                    355:        iov[iovcnt].iov_base = (char *)func;
                    356:        iov[iovcnt].iov_len = strlen(func);
                    357:        iovcnt++;
                    358: 
                    359:        iov[iovcnt].iov_base = "() ";
                    360:        iov[iovcnt].iov_len = 3;
                    361:        iovcnt++;
                    362: 
                    363:        iov[iovcnt].iov_base = (char *)file;
                    364:        iov[iovcnt].iov_len = strlen(file);
                    365:        iovcnt++;
                    366: 
                    367:        (void)snprintf(numbuf, sizeof(numbuf), ":%d", lineno);
                    368:        iov[iovcnt].iov_base = numbuf;
                    369:        iov[iovcnt].iov_len = strlen(numbuf);
                    370:        iovcnt++;
                    371: 
                    372:        /* Move newline to the end. */
                    373:        if (!need_newline) {
                    374:            need_newline = true;
                    375:            iov[3].iov_len--;
                    376:        }
                    377:     }
                    378: 
                    379:     /* Append newline as needed. */
                    380:     if (need_newline) {
                    381:        /* force newline */
                    382:        iov[iovcnt].iov_base = "\n";
                    383:        iov[iovcnt].iov_len = 1;
                    384:        iovcnt++;
                    385:     }
                    386: 
                    387:     /* Do timestamp last due to ctime's static buffer. */
                    388:     now = time(NULL);
                    389:     timestr = ctime(&now) + 4;
                    390:     timestr[15] = ' '; /* replace year with a space */
                    391:     timestr[16] = '\0';
                    392:     iov[0].iov_base = timestr;
                    393:     iov[0].iov_len = 16;
                    394: 
                    395:     /* Write message in a single syscall */
                    396:     ignore_result(writev(sudo_debug_fd, iov, iovcnt));
                    397: }
                    398: 
                    399: void
                    400: sudo_debug_write2(const char *func, const char *file, int lineno,
                    401:     const char *str, int len, int errno_val)
                    402: {
                    403:     if (len <= 0)
                    404:        return;
                    405: 
                    406:     switch (sudo_debug_mode) {
                    407:     case SUDO_DEBUG_MODE_CONV:
                    408:        sudo_debug_write_conv(func, file, lineno, str, len, errno_val);
                    409:        break;
                    410:     case SUDO_DEBUG_MODE_FILE:
                    411:        sudo_debug_write_file(func, file, lineno, str, len, errno_val);
                    412:        break;
                    413:     }
                    414: }
                    415: 
                    416: /* XXX - turn into a macro */
                    417: void
                    418: sudo_debug_write(const char *str, int len, int errno_val)
                    419: {
                    420:     sudo_debug_write2(NULL, NULL, 0, str, len, errno_val);
                    421: }
                    422: 
                    423: void
                    424: sudo_debug_printf2(const char *func, const char *file, int lineno, int level,
                    425:     const char *fmt, ...)
                    426: {
                    427:     int buflen, pri, subsys, saved_errno = errno;
                    428:     va_list ap;
                    429:     char *buf;
                    430: 
                    431:     if (!sudo_debug_mode)
                    432:        return;
                    433: 
                    434:     /* Extract pri and subsystem from level. */
                    435:     pri = SUDO_DEBUG_PRI(level);
                    436:     subsys = SUDO_DEBUG_SUBSYS(level);
                    437: 
                    438:     /* Make sure we want debug info at this level. */
                    439:     if (subsys < NUM_SUBSYSTEMS && sudo_debug_settings[subsys] >= pri) {
                    440:        va_start(ap, fmt);
                    441:        buflen = vasprintf(&buf, fmt, ap);
                    442:        va_end(ap);
                    443:        if (buflen != -1) {
                    444:            int errcode = ISSET(level, SUDO_DEBUG_ERRNO) ? saved_errno : 0;
                    445:            if (ISSET(level, SUDO_DEBUG_LINENO))
                    446:                sudo_debug_write2(func, file, lineno, buf, buflen, errcode);
                    447:            else
                    448:                sudo_debug_write2(NULL, NULL, 0, buf, buflen, errcode);
                    449:            free(buf);
                    450:        }
                    451:     }
                    452: 
                    453:     errno = saved_errno;
                    454: }
                    455: 
                    456: void
                    457: sudo_debug_execve2(int level, const char *path, char *const argv[], char *const envp[])
                    458: {
                    459:     char * const *av;
                    460:     char *buf, *cp;
                    461:     int buflen, pri, subsys, log_envp = 0;
                    462:     size_t plen;
                    463: 
                    464:     if (!sudo_debug_mode)
                    465:        return;
                    466: 
                    467:     /* Extract pri and subsystem from level. */
                    468:     pri = SUDO_DEBUG_PRI(level);
                    469:     subsys = SUDO_DEBUG_SUBSYS(level);
                    470: 
                    471:     /* Make sure we want debug info at this level. */
                    472:     if (subsys >= NUM_SUBSYSTEMS || sudo_debug_settings[subsys] < pri)
                    473:        return;
                    474: 
                    475:     /* Log envp for debug level "debug". */
                    476:     if (sudo_debug_settings[subsys] >= SUDO_DEBUG_DEBUG - 1 && envp[0] != NULL)
                    477:        log_envp = 1;
                    478: 
                    479: #define EXEC_PREFIX "exec "
                    480: 
                    481:     /* Alloc and build up buffer. */
                    482:     plen = strlen(path);
                    483:     buflen = sizeof(EXEC_PREFIX) -1 + plen;
                    484:     if (argv[0] != NULL) {
                    485:        buflen += sizeof(" []") - 1;
                    486:        for (av = argv; *av; av++)
                    487:            buflen += strlen(*av) + 1;
                    488:        buflen--;
                    489:     }
                    490:     if (log_envp) {
                    491:        buflen += sizeof(" []") - 1;
                    492:        for (av = envp; *av; av++)
                    493:            buflen += strlen(*av) + 1;
                    494:        buflen--;
                    495:     }
                    496:     buf = malloc(buflen + 1);
                    497:     if (buf == NULL)
                    498:        return;
                    499: 
                    500:     /* Copy prefix and command. */
                    501:     memcpy(buf, EXEC_PREFIX, sizeof(EXEC_PREFIX) - 1);
                    502:     cp = buf + sizeof(EXEC_PREFIX) - 1;
                    503:     memcpy(cp, path, plen);
                    504:     cp += plen;
                    505: 
                    506:     /* Copy argv. */
                    507:     if (argv[0] != NULL) {
                    508:        *cp++ = ' ';
                    509:        *cp++ = '[';
                    510:        for (av = argv; *av; av++) {
                    511:            size_t avlen = strlen(*av);
                    512:            memcpy(cp, *av, avlen);
                    513:            cp += avlen;
                    514:            *cp++ = ' ';
                    515:        }
                    516:        cp[-1] = ']';
                    517:     }
                    518: 
                    519:     if (log_envp) {
                    520:        *cp++ = ' ';
                    521:        *cp++ = '[';
                    522:        for (av = envp; *av; av++) {
                    523:            size_t avlen = strlen(*av);
                    524:            memcpy(cp, *av, avlen);
                    525:            cp += avlen;
                    526:            *cp++ = ' ';
                    527:        }
                    528:        cp[-1] = ']';
                    529:     }
                    530: 
                    531:     *cp = '\0';
                    532: 
                    533:     sudo_debug_write(buf, buflen, 0);
                    534:     free(buf);
                    535: }
                    536: 
                    537: /*
                    538:  * Dup sudo_debug_fd to the specified value so we don't
                    539:  * close it when calling closefrom().
                    540:  */
                    541: int
                    542: sudo_debug_fd_set(int fd)
                    543: {
                    544:     if (sudo_debug_fd != -1 && fd != sudo_debug_fd) {
                    545:        if (dup2(sudo_debug_fd, fd) == -1)
                    546:            return -1;
                    547:        (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
                    548:        close(sudo_debug_fd);
                    549:        sudo_debug_fd = fd;
                    550:     }
                    551:     return sudo_debug_fd;
                    552: }

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