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

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