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

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

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