Annotation of embedaddon/sudo/common/sudo_debug.c, revision 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>