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

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

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