File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers / iolog.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:23:02 2012 UTC (12 years, 4 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_3p2, HEAD
sudo

    1: /*
    2:  * Copyright (c) 2009-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/time.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_STRING_H
   33: # include <string.h>
   34: #endif /* HAVE_STRING_H */
   35: #ifdef HAVE_STRINGS_H
   36: # include <strings.h>
   37: #endif /* HAVE_STRINGS_H */
   38: #ifdef HAVE_UNISTD_H
   39: # include <unistd.h>
   40: #endif /* HAVE_UNISTD_H */
   41: #if TIME_WITH_SYS_TIME
   42: # include <time.h>
   43: #endif
   44: #include <errno.h>
   45: #include <fcntl.h>
   46: #include <signal.h>
   47: #include <setjmp.h>
   48: #include <pwd.h>
   49: #include <grp.h>
   50: #ifdef HAVE_ZLIB_H
   51: # include <zlib.h>
   52: #endif
   53: 
   54: #include "sudoers.h"
   55: 
   56: /* plugin_error.c */
   57: extern sigjmp_buf error_jmp;
   58: 
   59: union io_fd {
   60:     FILE *f;
   61: #ifdef HAVE_ZLIB_H
   62:     gzFile g;
   63: #endif
   64:     void *v;
   65: };
   66: 
   67: struct script_buf {
   68:     int len; /* buffer length (how much read in) */
   69:     int off; /* write position (how much already consumed) */
   70:     char buf[16 * 1024];
   71: };
   72: 
   73: /* XXX - separate sudoers.h and iolog.h? */
   74: #undef runas_pw
   75: #undef runas_gr
   76: 
   77: struct iolog_details {
   78:     const char *cwd;
   79:     const char *tty;
   80:     const char *user;
   81:     const char *command;
   82:     const char *iolog_path;
   83:     struct passwd *runas_pw;
   84:     struct group *runas_gr;
   85:     int iolog_stdin;
   86:     int iolog_stdout;
   87:     int iolog_stderr;
   88:     int iolog_ttyin;
   89:     int iolog_ttyout;
   90: };
   91: 
   92: #define IOFD_STDIN	0
   93: #define IOFD_STDOUT	1
   94: #define IOFD_STDERR	2
   95: #define IOFD_TTYIN	3
   96: #define IOFD_TTYOUT	4
   97: #define IOFD_TIMING	5
   98: #define IOFD_MAX	6
   99: 
  100: #define SESSID_MAX	2176782336U
  101: 
  102: static int iolog_compress;
  103: static struct timeval last_time;
  104: static union io_fd io_fds[IOFD_MAX];
  105: extern struct io_plugin sudoers_io;
  106: 
  107: /*
  108:  * Create parent directories for path as needed, but not path itself.
  109:  */
  110: static void
  111: mkdir_parents(char *path)
  112: {
  113:     struct stat sb;
  114:     char *slash = path;
  115: 
  116:     for (;;) {
  117: 	if ((slash = strchr(slash + 1, '/')) == NULL)
  118: 	    break;
  119: 	*slash = '\0';
  120: 	if (stat(path, &sb) != 0) {
  121: 	    if (mkdir(path, S_IRWXU) != 0)
  122: 		log_error(USE_ERRNO, _("unable to mkdir %s"), path);
  123: 	} else if (!S_ISDIR(sb.st_mode)) {
  124: 	    log_error(0, _("%s: %s"), path, strerror(ENOTDIR));
  125: 	}
  126: 	*slash = '/';
  127:     }
  128: }
  129: 
  130: /*
  131:  * Read the on-disk sequence number, set sessid to the next
  132:  * number, and update the on-disk copy.
  133:  * Uses file locking to avoid sequence number collisions.
  134:  */
  135: void
  136: io_nextid(char *iolog_dir, char sessid[7])
  137: {
  138:     struct stat sb;
  139:     char buf[32], *ep;
  140:     int fd, i;
  141:     unsigned long id = 0;
  142:     int len;
  143:     ssize_t nread;
  144:     char pathbuf[PATH_MAX];
  145:     static const char b36char[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  146: 
  147:     /*
  148:      * Create I/O log directory if it doesn't already exist.
  149:      */
  150:     mkdir_parents(iolog_dir);
  151:     if (stat(iolog_dir, &sb) != 0) {
  152: 	if (mkdir(iolog_dir, S_IRWXU) != 0)
  153: 	    log_error(USE_ERRNO, _("unable to mkdir %s"), iolog_dir);
  154:     } else if (!S_ISDIR(sb.st_mode)) {
  155: 	log_error(0, _("%s exists but is not a directory (0%o)"),
  156: 	    iolog_dir, (unsigned int) sb.st_mode);
  157:     }
  158: 
  159:     /*
  160:      * Open sequence file
  161:      */
  162:     len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", iolog_dir);
  163:     if (len <= 0 || len >= sizeof(pathbuf)) {
  164: 	errno = ENAMETOOLONG;
  165: 	log_error(USE_ERRNO, "%s/seq", pathbuf);
  166:     }
  167:     fd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
  168:     if (fd == -1)
  169: 	log_error(USE_ERRNO, _("unable to open %s"), pathbuf);
  170:     lock_file(fd, SUDO_LOCK);
  171: 
  172:     /* Read seq number (base 36). */
  173:     nread = read(fd, buf, sizeof(buf));
  174:     if (nread != 0) {
  175: 	if (nread == -1)
  176: 	    log_error(USE_ERRNO, _("unable to read %s"), pathbuf);
  177: 	id = strtoul(buf, &ep, 36);
  178: 	if (buf == ep || id >= SESSID_MAX)
  179: 	    log_error(0, _("invalid sequence number %s"), pathbuf);
  180:     }
  181:     id++;
  182: 
  183:     /*
  184:      * Convert id to a string and stash in sessid.
  185:      * Note that that least significant digits go at the end of the string.
  186:      */
  187:     for (i = 5; i >= 0; i--) {
  188: 	buf[i] = b36char[id % 36];
  189: 	id /= 36;
  190:     }
  191:     buf[6] = '\n';
  192: 
  193:     /* Stash id logging purposes */
  194:     memcpy(sessid, buf, 6);
  195:     sessid[6] = '\0';
  196: 
  197:     /* Rewind and overwrite old seq file. */
  198:     if (lseek(fd, 0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7)
  199: 	log_error(USE_ERRNO, _("unable to write to %s"), pathbuf);
  200:     close(fd);
  201: }
  202: 
  203: /*
  204:  * Copy iolog_path to pathbuf and create the directory and any intermediate
  205:  * directories.  If iolog_path ends in 'XXXXXX', use mkdtemp().
  206:  */
  207: static size_t
  208: mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize)
  209: {
  210:     size_t len;
  211: 
  212:     len = strlcpy(pathbuf, iolog_path, pathsize);
  213:     if (len >= pathsize) {
  214: 	errno = ENAMETOOLONG;
  215: 	log_error(USE_ERRNO, "%s", iolog_path);
  216:     }
  217: 
  218:     /*
  219:      * Create path and intermediate subdirs as needed.
  220:      * If path ends in at least 6 Xs (ala POSIX mktemp), use mkdtemp().
  221:      */
  222:     mkdir_parents(pathbuf);
  223:     if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0) {
  224: 	if (mkdtemp(pathbuf) == NULL)
  225: 	    log_error(USE_ERRNO, _("unable to create %s"), pathbuf);
  226:     } else {
  227: 	if (mkdir(pathbuf, S_IRWXU) != 0)
  228: 	    log_error(USE_ERRNO, _("unable to create %s"), pathbuf);
  229:     }
  230: 
  231:     return len;
  232: }
  233: 
  234: /*
  235:  * Append suffix to pathbuf after len chars and open the resulting file.
  236:  * Note that the size of pathbuf is assumed to be PATH_MAX.
  237:  * Uses zlib if docompress is TRUE.
  238:  * Returns the open file handle which has the close-on-exec flag set.
  239:  */
  240: static void *
  241: open_io_fd(char *pathbuf, size_t len, const char *suffix, int docompress)
  242: {
  243:     void *vfd = NULL;
  244:     int fd;
  245: 
  246:     pathbuf[len] = '\0';
  247:     strlcat(pathbuf, suffix, PATH_MAX);
  248:     fd = open(pathbuf, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
  249:     if (fd != -1) {
  250: 	fcntl(fd, F_SETFD, FD_CLOEXEC);
  251: #ifdef HAVE_ZLIB_H
  252: 	if (docompress)
  253: 	    vfd = gzdopen(fd, "w");
  254: 	else
  255: #endif
  256: 	    vfd = fdopen(fd, "w");
  257:     }
  258:     return vfd;
  259: }
  260: 
  261: /*
  262:  * Pull out I/O log related data from user_info and command_info arrays.
  263:  */
  264: static void
  265: iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
  266:     char * const command_info[])
  267: {
  268:     const char *runas_uid_str = "0", *runas_euid_str = NULL;
  269:     const char *runas_gid_str = "0", *runas_egid_str = NULL;
  270:     char id[MAX_UID_T_LEN + 2], *ep;
  271:     char * const *cur;
  272:     unsigned long ulval;
  273:     uid_t runas_uid = 0;
  274:     gid_t runas_gid = 0;
  275: 
  276:     memset(details, 0, sizeof(*details));
  277: 
  278:     for (cur = user_info; *cur != NULL; cur++) {
  279: 	switch (**cur) {
  280: 	case 'c':
  281: 	    if (strncmp(*cur, "cwd=", sizeof("cwd=") - 1) == 0) {
  282: 		details->cwd = *cur + sizeof("cwd=") - 1;
  283: 		continue;
  284: 	    }
  285: 	    break;
  286: 	case 't':
  287: 	    if (strncmp(*cur, "tty=", sizeof("tty=") - 1) == 0) {
  288: 		details->tty = *cur + sizeof("tty=") - 1;
  289: 		continue;
  290: 	    }
  291: 	    break;
  292: 	case 'u':
  293: 	    if (strncmp(*cur, "user=", sizeof("user=") - 1) == 0) {
  294: 		details->user = *cur + sizeof("user=") - 1;
  295: 		continue;
  296: 	    }
  297: 	    break;
  298: 	}
  299:     }
  300: 
  301:     for (cur = command_info; *cur != NULL; cur++) {
  302: 	switch (**cur) {
  303: 	case 'c':
  304: 	    if (strncmp(*cur, "command=", sizeof("command=") - 1) == 0) {
  305: 		details->command = *cur + sizeof("command=") - 1;
  306: 		continue;
  307: 	    }
  308: 	    break;
  309: 	case 'i':
  310: 	    if (strncmp(*cur, "iolog_path=", sizeof("iolog_path=") - 1) == 0) {
  311: 		details->iolog_path = *cur + sizeof("iolog_path=") - 1;
  312: 		continue;
  313: 	    }
  314: 	    if (strncmp(*cur, "iolog_stdin=", sizeof("iolog_stdin=") - 1) == 0) {
  315: 		if (atobool(*cur + sizeof("iolog_stdin=") - 1) == TRUE)
  316: 		    details->iolog_stdin = TRUE;
  317: 		continue;
  318: 	    }
  319: 	    if (strncmp(*cur, "iolog_stdout=", sizeof("iolog_stdout=") - 1) == 0) {
  320: 		if (atobool(*cur + sizeof("iolog_stdout=") - 1) == TRUE)
  321: 		    details->iolog_stdout = TRUE;
  322: 		continue;
  323: 	    }
  324: 	    if (strncmp(*cur, "iolog_stderr=", sizeof("iolog_stderr=") - 1) == 0) {
  325: 		if (atobool(*cur + sizeof("iolog_stderr=") - 1) == TRUE)
  326: 		    details->iolog_stderr = TRUE;
  327: 		continue;
  328: 	    }
  329: 	    if (strncmp(*cur, "iolog_ttyin=", sizeof("iolog_ttyin=") - 1) == 0) {
  330: 		if (atobool(*cur + sizeof("iolog_ttyin=") - 1) == TRUE)
  331: 		    details->iolog_ttyin = TRUE;
  332: 		continue;
  333: 	    }
  334: 	    if (strncmp(*cur, "iolog_ttyout=", sizeof("iolog_ttyout=") - 1) == 0) {
  335: 		if (atobool(*cur + sizeof("iolog_ttyout=") - 1) == TRUE)
  336: 		    details->iolog_ttyout = TRUE;
  337: 		continue;
  338: 	    }
  339: 	    if (strncmp(*cur, "iolog_compress=", sizeof("iolog_compress=") - 1) == 0) {
  340: 		if (atobool(*cur + sizeof("iolog_compress=") - 1) == TRUE)
  341: 		    iolog_compress = TRUE; /* must be global */
  342: 		continue;
  343: 	    }
  344: 	    break;
  345: 	case 'r':
  346: 	    if (strncmp(*cur, "runas_gid=", sizeof("runas_gid=") - 1) == 0) {
  347: 		runas_gid_str = *cur + sizeof("runas_gid=") - 1;
  348: 		continue;
  349: 	    }
  350: 	    if (strncmp(*cur, "runas_egid=", sizeof("runas_egid=") - 1) == 0) {
  351: 		runas_egid_str = *cur + sizeof("runas_egid=") - 1;
  352: 		continue;
  353: 	    }
  354: 	    if (strncmp(*cur, "runas_uid=", sizeof("runas_uid=") - 1) == 0) {
  355: 		runas_uid_str = *cur + sizeof("runas_uid=") - 1;
  356: 		continue;
  357: 	    }
  358: 	    if (strncmp(*cur, "runas_euid=", sizeof("runas_euid=") - 1) == 0) {
  359: 		runas_euid_str = *cur + sizeof("runas_euid=") - 1;
  360: 		continue;
  361: 	    }
  362: 	    break;
  363: 	}
  364:     }
  365: 
  366:     /*
  367:      * Lookup runas user and group, preferring effective over real uid/gid.
  368:      */
  369:     if (runas_euid_str != NULL)
  370: 	runas_uid_str = runas_euid_str;
  371:     if (runas_uid_str != NULL) {
  372: 	errno = 0;
  373: 	ulval = strtoul(runas_uid_str, &ep, 0);
  374: 	if (*runas_uid_str != '\0' && *ep == '\0' &&
  375: 	    (errno != ERANGE || ulval != ULONG_MAX)) {
  376: 	    runas_uid = (uid_t)ulval;
  377: 	}
  378:     }
  379:     if (runas_egid_str != NULL)
  380: 	runas_gid_str = runas_egid_str;
  381:     if (runas_gid_str != NULL) {
  382: 	errno = 0;
  383: 	ulval = strtoul(runas_gid_str, &ep, 0);
  384: 	if (*runas_gid_str != '\0' && *ep == '\0' &&
  385: 	    (errno != ERANGE || ulval != ULONG_MAX)) {
  386: 	    runas_gid = (gid_t)ulval;
  387: 	}
  388:     }
  389: 
  390:     details->runas_pw = sudo_getpwuid(runas_uid);
  391:     if (details->runas_pw == NULL) {
  392: 	id[0] = '#';
  393: 	strlcpy(&id[1], runas_uid_str, sizeof(id) - 1);
  394: 	details->runas_pw = sudo_fakepwnam(id, runas_gid);
  395:     }
  396: 
  397:     if (runas_gid != details->runas_pw->pw_gid) {
  398: 	details->runas_gr = sudo_getgrgid(runas_gid);
  399: 	if (details->runas_gr == NULL) {
  400: 	    id[0] = '#';
  401: 	    strlcpy(&id[1], runas_gid_str, sizeof(id) - 1);
  402: 	    details->runas_gr = sudo_fakegrnam(id);
  403: 	}
  404:     }
  405: }
  406: 
  407: static int
  408: sudoers_io_open(unsigned int version, sudo_conv_t conversation,
  409:     sudo_printf_t plugin_printf, char * const settings[],
  410:     char * const user_info[], char * const command_info[],
  411:     int argc, char * const argv[], char * const user_env[])
  412: {
  413:     struct iolog_details details;
  414:     char pathbuf[PATH_MAX], sessid[7];
  415:     char *tofree = NULL;
  416:     char * const *cur;
  417:     FILE *io_logfile;
  418:     size_t len;
  419:     int rval = -1;
  420: 
  421:     if (!sudo_conv)
  422: 	sudo_conv = conversation;
  423:     if (!sudo_printf)
  424: 	sudo_printf = plugin_printf;
  425: 
  426:     /* If we have no command (because -V was specified) just return. */
  427:     if (argc == 0)
  428: 	return TRUE;
  429: 
  430:     if (sigsetjmp(error_jmp, 1)) {
  431: 	/* called via error(), errorx() or log_error() */
  432: 	rval = -1;
  433: 	goto done;
  434:     }
  435: 
  436:     bindtextdomain("sudoers", LOCALEDIR);
  437: 
  438:     sudo_setpwent();
  439:     sudo_setgrent();
  440: 
  441:     /*
  442:      * Pull iolog settings out of command_info, if any.
  443:      */
  444:     iolog_deserialize_info(&details, user_info, command_info);
  445:     /* Did policy module disable I/O logging? */
  446:     if (!details.iolog_stdin && !details.iolog_ttyin &&
  447: 	!details.iolog_stdout && !details.iolog_stderr &&
  448: 	!details.iolog_ttyout) {
  449: 	rval = FALSE;
  450: 	goto done;
  451:     }
  452: 
  453:     /* If no I/O log path defined we need to figure it out ourselves. */
  454:     if (details.iolog_path == NULL) {
  455: 	/* Get next session ID and convert it into a path. */
  456: 	tofree = emalloc(sizeof(_PATH_SUDO_IO_LOGDIR) + sizeof(sessid) + 2);
  457: 	memcpy(tofree, _PATH_SUDO_IO_LOGDIR, sizeof(_PATH_SUDO_IO_LOGDIR));
  458: 	io_nextid(tofree, sessid);
  459: 	snprintf(tofree + sizeof(_PATH_SUDO_IO_LOGDIR), sizeof(sessid) + 2,
  460: 	    "%c%c/%c%c/%c%c", sessid[0], sessid[1], sessid[2], sessid[3],
  461: 	    sessid[4], sessid[5]);
  462: 	details.iolog_path = tofree;
  463:     }
  464: 
  465:     /*
  466:      * Make local copy of I/O log path and create it, along with any
  467:      * intermediate subdirs.  Calls mkdtemp() if iolog_path ends in XXXXXX.
  468:      */
  469:     len = mkdir_iopath(details.iolog_path, pathbuf, sizeof(pathbuf));
  470:     if (len >= sizeof(pathbuf))
  471: 	goto done;
  472: 
  473:     /*
  474:      * We create 7 files: a log file, a timing file and 5 for input/output.
  475:      */
  476:     io_logfile = open_io_fd(pathbuf, len, "/log", FALSE);
  477:     if (io_logfile == NULL)
  478: 	log_error(USE_ERRNO, _("unable to create %s"), pathbuf);
  479: 
  480:     io_fds[IOFD_TIMING].v = open_io_fd(pathbuf, len, "/timing",
  481: 	iolog_compress);
  482:     if (io_fds[IOFD_TIMING].v == NULL)
  483: 	log_error(USE_ERRNO, _("unable to create %s"), pathbuf);
  484: 
  485:     if (details.iolog_ttyin) {
  486: 	io_fds[IOFD_TTYIN].v = open_io_fd(pathbuf, len, "/ttyin",
  487: 	    iolog_compress);
  488: 	if (io_fds[IOFD_TTYIN].v == NULL)
  489: 	    log_error(USE_ERRNO, _("unable to create %s"), pathbuf);
  490:     } else {
  491: 	sudoers_io.log_ttyin = NULL;
  492:     }
  493:     if (details.iolog_stdin) {
  494: 	io_fds[IOFD_STDIN].v = open_io_fd(pathbuf, len, "/stdin",
  495: 	    iolog_compress);
  496: 	if (io_fds[IOFD_STDIN].v == NULL)
  497: 	    log_error(USE_ERRNO, _("unable to create %s"), pathbuf);
  498:     } else {
  499: 	sudoers_io.log_stdin = NULL;
  500:     }
  501:     if (details.iolog_ttyout) {
  502: 	io_fds[IOFD_TTYOUT].v = open_io_fd(pathbuf, len, "/ttyout",
  503: 	    iolog_compress);
  504: 	if (io_fds[IOFD_TTYOUT].v == NULL)
  505: 	    log_error(USE_ERRNO, _("unable to create %s"), pathbuf);
  506:     } else {
  507: 	sudoers_io.log_ttyout = NULL;
  508:     }
  509:     if (details.iolog_stdout) {
  510: 	io_fds[IOFD_STDOUT].v = open_io_fd(pathbuf, len, "/stdout",
  511: 	    iolog_compress);
  512: 	if (io_fds[IOFD_STDOUT].v == NULL)
  513: 	    log_error(USE_ERRNO, _("unable to create %s"), pathbuf);
  514:     } else {
  515: 	sudoers_io.log_stdout = NULL;
  516:     }
  517:     if (details.iolog_stderr) {
  518: 	io_fds[IOFD_STDERR].v = open_io_fd(pathbuf, len, "/stderr",
  519: 	    iolog_compress);
  520: 	if (io_fds[IOFD_STDERR].v == NULL)
  521: 	    log_error(USE_ERRNO, _("unable to create %s"), pathbuf);
  522:     } else {
  523: 	sudoers_io.log_stderr = NULL;
  524:     }
  525: 
  526:     gettimeofday(&last_time, NULL);
  527: 
  528:     fprintf(io_logfile, "%ld:%s:%s:%s:%s\n", (long)last_time.tv_sec,
  529: 	details.user ? details.user : "unknown", details.runas_pw->pw_name,
  530: 	details.runas_gr ? details.runas_gr->gr_name : "",
  531: 	details.tty ? details.tty : "unknown");
  532:     fputs(details.cwd ? details.cwd : "unknown", io_logfile);
  533:     fputc('\n', io_logfile);
  534:     fputs(details.command ? details.command : "unknown", io_logfile);
  535:     for (cur = &argv[1]; *cur != NULL; cur++) {
  536: 	fputc(' ', io_logfile);
  537: 	fputs(*cur, io_logfile);
  538:     }
  539:     fputc('\n', io_logfile);
  540:     fclose(io_logfile);
  541: 
  542:     rval = TRUE;
  543: 
  544: done:
  545:     efree(tofree);
  546:     if (details.runas_pw)
  547: 	pw_delref(details.runas_pw);
  548:     sudo_endpwent();
  549:     if (details.runas_gr)
  550: 	gr_delref(details.runas_gr);
  551:     sudo_endgrent();
  552: 
  553:     return rval;
  554: }
  555: 
  556: static void
  557: sudoers_io_close(int exit_status, int error)
  558: {
  559:     int i;
  560: 
  561:     if (sigsetjmp(error_jmp, 1)) {
  562: 	/* called via error(), errorx() or log_error() */
  563: 	return;
  564:     }
  565: 
  566:     for (i = 0; i < IOFD_MAX; i++) {
  567: 	if (io_fds[i].v == NULL)
  568: 	    continue;
  569: #ifdef HAVE_ZLIB_H
  570: 	if (iolog_compress)
  571: 	    gzclose(io_fds[i].g);
  572: 	else
  573: #endif
  574: 	    fclose(io_fds[i].f);
  575:     }
  576: }
  577: 
  578: static int
  579: sudoers_io_version(int verbose)
  580: {
  581:     if (sigsetjmp(error_jmp, 1)) {
  582: 	/* called via error(), errorx() or log_error() */
  583: 	return -1;
  584:     }
  585: 
  586:     sudo_printf(SUDO_CONV_INFO_MSG, "Sudoers I/O plugin version %s\n",
  587: 	PACKAGE_VERSION);
  588: 
  589:     return TRUE;
  590: }
  591: 
  592: /*
  593:  * Generic I/O logging function.  Called by the I/O logging entry points.
  594:  */
  595: static int
  596: sudoers_io_log(const char *buf, unsigned int len, int idx)
  597: {
  598:     struct timeval now, delay;
  599: 
  600:     gettimeofday(&now, NULL);
  601: 
  602:     if (sigsetjmp(error_jmp, 1)) {
  603: 	/* called via error(), errorx() or log_error() */
  604: 	return -1;
  605:     }
  606: 
  607: #ifdef HAVE_ZLIB_H
  608:     if (iolog_compress)
  609: 	gzwrite(io_fds[idx].g, buf, len);
  610:     else
  611: #endif
  612: 	fwrite(buf, 1, len, io_fds[idx].f);
  613:     delay.tv_sec = now.tv_sec;
  614:     delay.tv_usec = now.tv_usec;
  615:     timevalsub(&delay, &last_time);
  616: #ifdef HAVE_ZLIB_H
  617:     if (iolog_compress)
  618: 	gzprintf(io_fds[IOFD_TIMING].g, "%d %f %d\n", idx,
  619: 	    delay.tv_sec + ((double)delay.tv_usec / 1000000), len);
  620:     else
  621: #endif
  622: 	fprintf(io_fds[IOFD_TIMING].f, "%d %f %d\n", idx,
  623: 	    delay.tv_sec + ((double)delay.tv_usec / 1000000), len);
  624:     last_time.tv_sec = now.tv_sec;
  625:     last_time.tv_usec = now.tv_usec;
  626: 
  627:     return TRUE;
  628: }
  629: 
  630: static int
  631: sudoers_io_log_ttyin(const char *buf, unsigned int len)
  632: {
  633:     return sudoers_io_log(buf, len, IOFD_TTYIN);
  634: }
  635: 
  636: static int
  637: sudoers_io_log_ttyout(const char *buf, unsigned int len)
  638: {
  639:     return sudoers_io_log(buf, len, IOFD_TTYOUT);
  640: }
  641: 
  642: static int
  643: sudoers_io_log_stdin(const char *buf, unsigned int len)
  644: {
  645:     return sudoers_io_log(buf, len, IOFD_STDIN);
  646: }
  647: 
  648: static int
  649: sudoers_io_log_stdout(const char *buf, unsigned int len)
  650: {
  651:     return sudoers_io_log(buf, len, IOFD_STDOUT);
  652: }
  653: 
  654: static int
  655: sudoers_io_log_stderr(const char *buf, unsigned int len)
  656: {
  657:     return sudoers_io_log(buf, len, IOFD_STDERR);
  658: }
  659: 
  660: struct io_plugin sudoers_io = {
  661:     SUDO_IO_PLUGIN,
  662:     SUDO_API_VERSION,
  663:     sudoers_io_open,
  664:     sudoers_io_close,
  665:     sudoers_io_version,
  666:     sudoers_io_log_ttyin,
  667:     sudoers_io_log_ttyout,
  668:     sudoers_io_log_stdin,
  669:     sudoers_io_log_stdout,
  670:     sudoers_io_log_stderr
  671: };

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