Annotation of embedaddon/sudo/plugins/sudoers/iolog.c, revision 1.1
1.1 ! misho 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>