Return to logging.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers |
1.1 ! misho 1: /* ! 2: * Copyright (c) 1994-1996, 1998-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: * Sponsored in part by the Defense Advanced Research Projects ! 17: * Agency (DARPA) and Air Force Research Laboratory, Air Force ! 18: * Materiel Command, USAF, under agreement number F39502-99-1-0512. ! 19: */ ! 20: ! 21: #ifdef __TANDEM ! 22: # include <floss.h> ! 23: #endif ! 24: ! 25: #include <config.h> ! 26: ! 27: #include <sys/types.h> ! 28: #include <sys/param.h> ! 29: #include <sys/stat.h> ! 30: #include <sys/ioctl.h> ! 31: #include <sys/wait.h> ! 32: #include <stdio.h> ! 33: #ifdef STDC_HEADERS ! 34: # include <stdlib.h> ! 35: # include <stddef.h> ! 36: #else ! 37: # ifdef HAVE_STDLIB_H ! 38: # include <stdlib.h> ! 39: # endif ! 40: #endif /* STDC_HEADERS */ ! 41: #ifdef HAVE_STRING_H ! 42: # include <string.h> ! 43: #endif /* HAVE_STRING_H */ ! 44: #ifdef HAVE_STRINGS_H ! 45: # include <strings.h> ! 46: #endif /* HAVE_STRINGS_H */ ! 47: #ifdef HAVE_UNISTD_H ! 48: # include <unistd.h> ! 49: #endif /* HAVE_UNISTD_H */ ! 50: #ifdef HAVE_SETLOCALE ! 51: # include <locale.h> ! 52: #endif /* HAVE_SETLOCALE */ ! 53: #ifdef HAVE_NL_LANGINFO ! 54: # include <langinfo.h> ! 55: #endif /* HAVE_NL_LANGINFO */ ! 56: #include <pwd.h> ! 57: #include <grp.h> ! 58: #include <signal.h> ! 59: #include <time.h> ! 60: #include <ctype.h> ! 61: #include <errno.h> ! 62: #include <fcntl.h> ! 63: #include <setjmp.h> ! 64: ! 65: #include "sudoers.h" ! 66: ! 67: static void do_syslog(int, char *); ! 68: static void do_logfile(char *); ! 69: static void send_mail(const char *fmt, ...); ! 70: static int should_mail(int); ! 71: static void mysyslog(int, const char *, ...); ! 72: static char *new_logline(const char *, int); ! 73: ! 74: extern sigjmp_buf error_jmp; ! 75: ! 76: #define MAXSYSLOGTRIES 16 /* num of retries for broken syslogs */ ! 77: ! 78: /* ! 79: * We do an openlog(3)/closelog(3) for each message because some ! 80: * authentication methods (notably PAM) use syslog(3) for their ! 81: * own nefarious purposes and may call openlog(3) and closelog(3). ! 82: * Note that because we don't want to assume that all systems have ! 83: * vsyslog(3) (HP-UX doesn't) "%m" will not be expanded. ! 84: * Sadly this is a maze of #ifdefs. ! 85: */ ! 86: static void ! 87: mysyslog(int pri, const char *fmt, ...) ! 88: { ! 89: #ifdef BROKEN_SYSLOG ! 90: int i; ! 91: #endif ! 92: char buf[MAXSYSLOGLEN+1]; ! 93: va_list ap; ! 94: ! 95: va_start(ap, fmt); ! 96: #ifdef LOG_NFACILITIES ! 97: openlog("sudo", 0, def_syslog); ! 98: #else ! 99: openlog("sudo", 0); ! 100: #endif ! 101: vsnprintf(buf, sizeof(buf), fmt, ap); ! 102: #ifdef BROKEN_SYSLOG ! 103: /* ! 104: * Some versions of syslog(3) don't guarantee success and return ! 105: * an int (notably HP-UX < 10.0). So, if at first we don't succeed, ! 106: * try, try again... ! 107: */ ! 108: for (i = 0; i < MAXSYSLOGTRIES; i++) ! 109: if (syslog(pri, "%s", buf) == 0) ! 110: break; ! 111: #else ! 112: syslog(pri, "%s", buf); ! 113: #endif /* BROKEN_SYSLOG */ ! 114: va_end(ap); ! 115: closelog(); ! 116: } ! 117: ! 118: #define FMT_FIRST "%8s : %s" ! 119: #define FMT_CONTD "%8s : (command continued) %s" ! 120: ! 121: /* ! 122: * Log a message to syslog, pre-pending the username and splitting the ! 123: * message into parts if it is longer than MAXSYSLOGLEN. ! 124: */ ! 125: static void ! 126: do_syslog(int pri, char *msg) ! 127: { ! 128: size_t len, maxlen; ! 129: char *p, *tmp, save; ! 130: const char *fmt; ! 131: ! 132: #ifdef HAVE_SETLOCALE ! 133: const char *old_locale = estrdup(setlocale(LC_ALL, NULL)); ! 134: if (!setlocale(LC_ALL, def_sudoers_locale)) ! 135: setlocale(LC_ALL, "C"); ! 136: #endif /* HAVE_SETLOCALE */ ! 137: ! 138: /* ! 139: * Log the full line, breaking into multiple syslog(3) calls if necessary ! 140: */ ! 141: fmt = _(FMT_FIRST); ! 142: maxlen = MAXSYSLOGLEN - (strlen(fmt) - 5 + strlen(user_name)); ! 143: for (p = msg; *p != '\0'; ) { ! 144: len = strlen(p); ! 145: if (len > maxlen) { ! 146: /* ! 147: * Break up the line into what will fit on one syslog(3) line ! 148: * Try to avoid breaking words into several lines if possible. ! 149: */ ! 150: tmp = memrchr(p, ' ', maxlen); ! 151: if (tmp == NULL) ! 152: tmp = p + maxlen; ! 153: ! 154: /* NULL terminate line, but save the char to restore later */ ! 155: save = *tmp; ! 156: *tmp = '\0'; ! 157: ! 158: mysyslog(pri, fmt, user_name, p); ! 159: ! 160: *tmp = save; /* restore saved character */ ! 161: ! 162: /* Advance p and eliminate leading whitespace */ ! 163: for (p = tmp; *p == ' '; p++) ! 164: ; ! 165: } else { ! 166: mysyslog(pri, fmt, user_name, p); ! 167: p += len; ! 168: } ! 169: fmt = _(FMT_CONTD); ! 170: maxlen = MAXSYSLOGLEN - (strlen(fmt) - 5 + strlen(user_name)); ! 171: } ! 172: ! 173: #ifdef HAVE_SETLOCALE ! 174: setlocale(LC_ALL, old_locale); ! 175: efree((void *)old_locale); ! 176: #endif /* HAVE_SETLOCALE */ ! 177: } ! 178: ! 179: static void ! 180: do_logfile(char *msg) ! 181: { ! 182: char *full_line; ! 183: size_t len; ! 184: mode_t oldmask; ! 185: time_t now; ! 186: FILE *fp; ! 187: ! 188: oldmask = umask(077); ! 189: fp = fopen(def_logfile, "a"); ! 190: (void) umask(oldmask); ! 191: if (fp == NULL) { ! 192: send_mail(_("unable to open log file: %s: %s"), ! 193: def_logfile, strerror(errno)); ! 194: } else if (!lock_file(fileno(fp), SUDO_LOCK)) { ! 195: send_mail(_("unable to lock log file: %s: %s"), ! 196: def_logfile, strerror(errno)); ! 197: } else { ! 198: #ifdef HAVE_SETLOCALE ! 199: const char *old_locale = estrdup(setlocale(LC_ALL, NULL)); ! 200: if (!setlocale(LC_ALL, def_sudoers_locale)) ! 201: setlocale(LC_ALL, "C"); ! 202: #endif /* HAVE_SETLOCALE */ ! 203: ! 204: now = time(NULL); ! 205: if (def_loglinelen < sizeof(LOG_INDENT)) { ! 206: /* Don't pretty-print long log file lines (hard to grep) */ ! 207: if (def_log_host) ! 208: (void) fprintf(fp, "%s : %s : HOST=%s : %s\n", ! 209: get_timestr(now, def_log_year), user_name, user_shost, msg); ! 210: else ! 211: (void) fprintf(fp, "%s : %s : %s\n", ! 212: get_timestr(now, def_log_year), user_name, msg); ! 213: } else { ! 214: if (def_log_host) ! 215: len = easprintf(&full_line, "%s : %s : HOST=%s : %s", ! 216: get_timestr(now, def_log_year), user_name, user_shost, msg); ! 217: else ! 218: len = easprintf(&full_line, "%s : %s : %s", ! 219: get_timestr(now, def_log_year), user_name, msg); ! 220: ! 221: /* ! 222: * Print out full_line with word wrap around def_loglinelen chars. ! 223: */ ! 224: writeln_wrap(fp, full_line, len, def_loglinelen); ! 225: efree(full_line); ! 226: } ! 227: (void) fflush(fp); ! 228: (void) lock_file(fileno(fp), SUDO_UNLOCK); ! 229: (void) fclose(fp); ! 230: ! 231: #ifdef HAVE_SETLOCALE ! 232: setlocale(LC_ALL, old_locale); ! 233: efree((void *)old_locale); ! 234: #endif /* HAVE_SETLOCALE */ ! 235: } ! 236: } ! 237: ! 238: /* ! 239: * Log and mail the denial message, optionally informing the user. ! 240: */ ! 241: void ! 242: log_denial(int status, int inform_user) ! 243: { ! 244: char *message; ! 245: char *logline; ! 246: ! 247: /* Set error message. */ ! 248: if (ISSET(status, FLAG_NO_USER)) ! 249: message = _("user NOT in sudoers"); ! 250: else if (ISSET(status, FLAG_NO_HOST)) ! 251: message = _("user NOT authorized on host"); ! 252: else ! 253: message = _("command not allowed"); ! 254: ! 255: logline = new_logline(message, 0); ! 256: ! 257: if (should_mail(status)) ! 258: send_mail("%s", logline); /* send mail based on status */ ! 259: ! 260: /* Inform the user if they failed to authenticate. */ ! 261: if (inform_user) { ! 262: if (ISSET(status, FLAG_NO_USER)) { ! 263: sudo_printf(SUDO_CONV_ERROR_MSG, _("%s is not in the sudoers " ! 264: "file. This incident will be reported.\n"), user_name); ! 265: } else if (ISSET(status, FLAG_NO_HOST)) { ! 266: sudo_printf(SUDO_CONV_ERROR_MSG, _("%s is not allowed to run sudo " ! 267: "on %s. This incident will be reported.\n"), ! 268: user_name, user_shost); ! 269: } else if (ISSET(status, FLAG_NO_CHECK)) { ! 270: sudo_printf(SUDO_CONV_ERROR_MSG, _("Sorry, user %s may not run " ! 271: "sudo on %s.\n"), user_name, user_shost); ! 272: } else { ! 273: sudo_printf(SUDO_CONV_ERROR_MSG, _("Sorry, user %s is not allowed " ! 274: "to execute '%s%s%s' as %s%s%s on %s.\n"), ! 275: user_name, user_cmnd, user_args ? " " : "", ! 276: user_args ? user_args : "", ! 277: list_pw ? list_pw->pw_name : runas_pw ? ! 278: runas_pw->pw_name : user_name, runas_gr ? ":" : "", ! 279: runas_gr ? runas_gr->gr_name : "", user_host); ! 280: } ! 281: } ! 282: ! 283: /* ! 284: * Log via syslog and/or a file. ! 285: */ ! 286: if (def_syslog) ! 287: do_syslog(def_syslog_badpri, logline); ! 288: if (def_logfile) ! 289: do_logfile(logline); ! 290: ! 291: efree(logline); ! 292: } ! 293: ! 294: /* ! 295: * Log and potentially mail the allowed command. ! 296: */ ! 297: void ! 298: log_allowed(int status) ! 299: { ! 300: char *logline; ! 301: ! 302: logline = new_logline(NULL, 0); ! 303: ! 304: if (should_mail(status)) ! 305: send_mail("%s", logline); /* send mail based on status */ ! 306: ! 307: /* ! 308: * Log via syslog and/or a file. ! 309: */ ! 310: if (def_syslog) ! 311: do_syslog(def_syslog_goodpri, logline); ! 312: if (def_logfile) ! 313: do_logfile(logline); ! 314: ! 315: efree(logline); ! 316: } ! 317: ! 318: void ! 319: log_error(int flags, const char *fmt, ...) ! 320: { ! 321: int serrno = errno; ! 322: char *message; ! 323: char *logline; ! 324: va_list ap; ! 325: ! 326: /* Expand printf-style format + args. */ ! 327: va_start(ap, fmt); ! 328: evasprintf(&message, fmt, ap); ! 329: va_end(ap); ! 330: ! 331: /* Become root if we are not already to avoid user interference */ ! 332: set_perms(PERM_ROOT|PERM_NOEXIT); ! 333: ! 334: if (ISSET(flags, MSG_ONLY)) ! 335: logline = message; ! 336: else ! 337: logline = new_logline(message, ISSET(flags, USE_ERRNO) ? serrno : 0); ! 338: ! 339: /* ! 340: * Tell the user. ! 341: */ ! 342: if (!ISSET(flags, NO_STDERR)) { ! 343: if (ISSET(flags, USE_ERRNO)) ! 344: warning("%s", message); ! 345: else ! 346: warningx("%s", message); ! 347: } ! 348: if (logline != message) ! 349: efree(message); ! 350: ! 351: /* ! 352: * Send a copy of the error via mail. ! 353: */ ! 354: if (!ISSET(flags, NO_MAIL)) ! 355: send_mail("%s", logline); ! 356: ! 357: /* ! 358: * Log to syslog and/or a file. ! 359: */ ! 360: if (def_syslog) ! 361: do_syslog(def_syslog_badpri, logline); ! 362: if (def_logfile) ! 363: do_logfile(logline); ! 364: ! 365: efree(logline); ! 366: ! 367: restore_perms(); ! 368: ! 369: if (!ISSET(flags, NO_EXIT)) { ! 370: plugin_cleanup(0); ! 371: siglongjmp(error_jmp, 1); ! 372: } ! 373: } ! 374: ! 375: #define MAX_MAILFLAGS 63 ! 376: ! 377: /* ! 378: * Send a message to MAILTO user ! 379: */ ! 380: static void ! 381: send_mail(const char *fmt, ...) ! 382: { ! 383: FILE *mail; ! 384: char *p; ! 385: int fd, pfd[2], status; ! 386: pid_t pid, rv; ! 387: sigaction_t sa; ! 388: va_list ap; ! 389: #ifndef NO_ROOT_MAILER ! 390: static char *root_envp[] = { ! 391: "HOME=/", ! 392: "PATH=/usr/bin:/bin:/usr/sbin:/sbin", ! 393: "LOGNAME=root", ! 394: "USERNAME=root", ! 395: "USER=root", ! 396: NULL ! 397: }; ! 398: #endif /* NO_ROOT_MAILER */ ! 399: ! 400: /* Just return if mailer is disabled. */ ! 401: if (!def_mailerpath || !def_mailto) ! 402: return; ! 403: ! 404: /* Fork and return, child will daemonize. */ ! 405: switch (pid = fork()) { ! 406: case -1: ! 407: /* Error. */ ! 408: error(1, _("unable to fork")); ! 409: break; ! 410: case 0: ! 411: /* Child. */ ! 412: switch (pid = fork()) { ! 413: case -1: ! 414: /* Error. */ ! 415: mysyslog(LOG_ERR, _("unable to fork: %m")); ! 416: _exit(1); ! 417: case 0: ! 418: /* Grandchild continues below. */ ! 419: break; ! 420: default: ! 421: /* Parent will wait for us. */ ! 422: _exit(0); ! 423: } ! 424: break; ! 425: default: ! 426: /* Parent. */ ! 427: do { ! 428: rv = waitpid(pid, &status, 0); ! 429: } while (rv == -1 && errno == EINTR); ! 430: return; ! 431: } ! 432: ! 433: /* Daemonize - disassociate from session/tty. */ ! 434: if (setsid() == -1) ! 435: warning("setsid"); ! 436: if (chdir("/") == -1) ! 437: warning("chdir(/)"); ! 438: if ((fd = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) { ! 439: (void) dup2(fd, STDIN_FILENO); ! 440: (void) dup2(fd, STDOUT_FILENO); ! 441: (void) dup2(fd, STDERR_FILENO); ! 442: } ! 443: ! 444: #ifdef HAVE_SETLOCALE ! 445: if (!setlocale(LC_ALL, def_sudoers_locale)) { ! 446: setlocale(LC_ALL, "C"); ! 447: efree(def_sudoers_locale); ! 448: def_sudoers_locale = estrdup("C"); ! 449: } ! 450: #endif /* HAVE_SETLOCALE */ ! 451: ! 452: /* Close password, group and other fds so we don't leak. */ ! 453: sudo_endpwent(); ! 454: sudo_endgrent(); ! 455: closefrom(STDERR_FILENO + 1); ! 456: ! 457: /* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */ ! 458: zero_bytes(&sa, sizeof(sa)); ! 459: sigemptyset(&sa.sa_mask); ! 460: sa.sa_flags = SA_INTERRUPT; ! 461: sa.sa_handler = SIG_IGN; ! 462: (void) sigaction(SIGPIPE, &sa, NULL); ! 463: ! 464: if (pipe(pfd) == -1) { ! 465: mysyslog(LOG_ERR, _("unable to open pipe: %m")); ! 466: _exit(1); ! 467: } ! 468: ! 469: switch (pid = fork()) { ! 470: case -1: ! 471: /* Error. */ ! 472: mysyslog(LOG_ERR, _("unable to fork: %m")); ! 473: _exit(1); ! 474: break; ! 475: case 0: ! 476: { ! 477: char *argv[MAX_MAILFLAGS + 1]; ! 478: char *mpath, *mflags; ! 479: int i; ! 480: ! 481: /* Child, set stdin to output side of the pipe */ ! 482: if (pfd[0] != STDIN_FILENO) { ! 483: if (dup2(pfd[0], STDIN_FILENO) == -1) { ! 484: mysyslog(LOG_ERR, _("unable to dup stdin: %m")); ! 485: _exit(127); ! 486: } ! 487: (void) close(pfd[0]); ! 488: } ! 489: (void) close(pfd[1]); ! 490: ! 491: /* Build up an argv based on the mailer path and flags */ ! 492: mflags = estrdup(def_mailerflags); ! 493: mpath = estrdup(def_mailerpath); ! 494: if ((argv[0] = strrchr(mpath, ' '))) ! 495: argv[0]++; ! 496: else ! 497: argv[0] = mpath; ! 498: ! 499: i = 1; ! 500: if ((p = strtok(mflags, " \t"))) { ! 501: do { ! 502: argv[i] = p; ! 503: } while (++i < MAX_MAILFLAGS && (p = strtok(NULL, " \t"))); ! 504: } ! 505: argv[i] = NULL; ! 506: ! 507: /* ! 508: * Depending on the config, either run the mailer as root ! 509: * (so user cannot kill it) or as the user (for the paranoid). ! 510: */ ! 511: #ifndef NO_ROOT_MAILER ! 512: set_perms(PERM_ROOT|PERM_NOEXIT); ! 513: execve(mpath, argv, root_envp); ! 514: #else ! 515: set_perms(PERM_FULL_USER|PERM_NOEXIT); ! 516: execv(mpath, argv); ! 517: #endif /* NO_ROOT_MAILER */ ! 518: mysyslog(LOG_ERR, _("unable to execute %s: %m"), mpath); ! 519: _exit(127); ! 520: } ! 521: break; ! 522: } ! 523: ! 524: (void) close(pfd[0]); ! 525: mail = fdopen(pfd[1], "w"); ! 526: ! 527: /* Pipes are all setup, send message. */ ! 528: (void) fprintf(mail, "To: %s\nFrom: %s\nAuto-Submitted: %s\nSubject: ", ! 529: def_mailto, def_mailfrom ? def_mailfrom : user_name, "auto-generated"); ! 530: for (p = def_mailsub; *p; p++) { ! 531: /* Expand escapes in the subject */ ! 532: if (*p == '%' && *(p+1) != '%') { ! 533: switch (*(++p)) { ! 534: case 'h': ! 535: (void) fputs(user_host, mail); ! 536: break; ! 537: case 'u': ! 538: (void) fputs(user_name, mail); ! 539: break; ! 540: default: ! 541: p--; ! 542: break; ! 543: } ! 544: } else ! 545: (void) fputc(*p, mail); ! 546: } ! 547: ! 548: #ifdef HAVE_NL_LANGINFO ! 549: if (strcmp(def_sudoers_locale, "C") != 0) ! 550: (void) fprintf(mail, "\nContent-Type: text/plain; charset=\"%s\"\nContent-Transfer-Encoding: 8bit", nl_langinfo(CODESET)); ! 551: #endif /* HAVE_NL_LANGINFO */ ! 552: ! 553: (void) fprintf(mail, "\n\n%s : %s : %s : ", user_host, ! 554: get_timestr(time(NULL), def_log_year), user_name); ! 555: va_start(ap, fmt); ! 556: (void) vfprintf(mail, fmt, ap); ! 557: va_end(ap); ! 558: fputs("\n\n", mail); ! 559: ! 560: fclose(mail); ! 561: do { ! 562: rv = waitpid(pid, &status, 0); ! 563: } while (rv == -1 && errno == EINTR); ! 564: _exit(0); ! 565: } ! 566: ! 567: /* ! 568: * Determine whether we should send mail based on "status" and defaults options. ! 569: */ ! 570: static int ! 571: should_mail(int status) ! 572: { ! 573: ! 574: return def_mail_always || ISSET(status, VALIDATE_ERROR) || ! 575: (def_mail_no_user && ISSET(status, FLAG_NO_USER)) || ! 576: (def_mail_no_host && ISSET(status, FLAG_NO_HOST)) || ! 577: (def_mail_no_perms && !ISSET(status, VALIDATE_OK)); ! 578: } ! 579: ! 580: #define LL_TTY_STR "TTY=" ! 581: #define LL_CWD_STR "PWD=" /* XXX - should be CWD= */ ! 582: #define LL_USER_STR "USER=" ! 583: #define LL_GROUP_STR "GROUP=" ! 584: #define LL_ENV_STR "ENV=" ! 585: #define LL_CMND_STR "COMMAND=" ! 586: #define LL_TSID_STR "TSID=" ! 587: ! 588: #define IS_SESSID(s) ( \ ! 589: isalnum((unsigned char)(s)[0]) && isalnum((unsigned char)(s)[1]) && \ ! 590: (s)[2] == '/' && \ ! 591: isalnum((unsigned char)(s)[3]) && isalnum((unsigned char)(s)[4]) && \ ! 592: (s)[5] == '/' && \ ! 593: isalnum((unsigned char)(s)[6]) && isalnum((unsigned char)(s)[7]) && \ ! 594: (s)[8] == '\0') ! 595: ! 596: /* ! 597: * Allocate and fill in a new logline. ! 598: */ ! 599: static char * ! 600: new_logline(const char *message, int serrno) ! 601: { ! 602: size_t len = 0; ! 603: char *errstr = NULL; ! 604: char *evstr = NULL; ! 605: char *line, sessid[7], *tsid = NULL; ! 606: ! 607: /* A TSID may be a sudoers-style session ID or a free-form string. */ ! 608: if (sudo_user.iolog_file != NULL) { ! 609: if (IS_SESSID(sudo_user.iolog_file)) { ! 610: sessid[0] = sudo_user.iolog_file[0]; ! 611: sessid[1] = sudo_user.iolog_file[1]; ! 612: sessid[2] = sudo_user.iolog_file[3]; ! 613: sessid[3] = sudo_user.iolog_file[4]; ! 614: sessid[4] = sudo_user.iolog_file[6]; ! 615: sessid[5] = sudo_user.iolog_file[7]; ! 616: sessid[6] = '\0'; ! 617: tsid = sessid; ! 618: } else { ! 619: tsid = sudo_user.iolog_file; ! 620: } ! 621: } ! 622: ! 623: /* ! 624: * Compute line length ! 625: */ ! 626: if (message != NULL) ! 627: len += strlen(message) + 3; ! 628: if (serrno) { ! 629: errstr = strerror(serrno); ! 630: len += strlen(errstr) + 3; ! 631: } ! 632: len += sizeof(LL_TTY_STR) + 2 + strlen(user_tty); ! 633: len += sizeof(LL_CWD_STR) + 2 + strlen(user_cwd); ! 634: if (runas_pw != NULL) ! 635: len += sizeof(LL_USER_STR) + 2 + strlen(runas_pw->pw_name); ! 636: if (runas_gr != NULL) ! 637: len += sizeof(LL_GROUP_STR) + 2 + strlen(runas_gr->gr_name); ! 638: if (tsid != NULL) ! 639: len += sizeof(LL_TSID_STR) + 2 + strlen(tsid); ! 640: if (sudo_user.env_vars != NULL) { ! 641: size_t evlen = 0; ! 642: char * const *ep; ! 643: ! 644: for (ep = sudo_user.env_vars; *ep != NULL; ep++) ! 645: evlen += strlen(*ep) + 1; ! 646: evstr = emalloc(evlen); ! 647: evstr[0] = '\0'; ! 648: for (ep = sudo_user.env_vars; *ep != NULL; ep++) { ! 649: strlcat(evstr, *ep, evlen); ! 650: strlcat(evstr, " ", evlen); /* NOTE: last one will fail */ ! 651: } ! 652: len += sizeof(LL_ENV_STR) + 2 + evlen; ! 653: } ! 654: if (user_cmnd != NULL) { ! 655: /* Note: we log "sudo -l command arg ..." as "list command arg ..." */ ! 656: len += sizeof(LL_CMND_STR) - 1 + strlen(user_cmnd); ! 657: if (ISSET(sudo_mode, MODE_CHECK)) ! 658: len += sizeof("list ") - 1; ! 659: if (user_args != NULL) ! 660: len += strlen(user_args) + 1; ! 661: } ! 662: ! 663: /* ! 664: * Allocate and build up the line. ! 665: */ ! 666: line = emalloc(++len); ! 667: line[0] = '\0'; ! 668: ! 669: if (message != NULL) { ! 670: if (strlcat(line, message, len) >= len || ! 671: strlcat(line, errstr ? " : " : " ; ", len) >= len) ! 672: goto toobig; ! 673: } ! 674: if (serrno) { ! 675: if (strlcat(line, errstr, len) >= len || ! 676: strlcat(line, " ; ", len) >= len) ! 677: goto toobig; ! 678: } ! 679: if (strlcat(line, LL_TTY_STR, len) >= len || ! 680: strlcat(line, user_tty, len) >= len || ! 681: strlcat(line, " ; ", len) >= len) ! 682: goto toobig; ! 683: if (strlcat(line, LL_CWD_STR, len) >= len || ! 684: strlcat(line, user_cwd, len) >= len || ! 685: strlcat(line, " ; ", len) >= len) ! 686: goto toobig; ! 687: if (runas_pw != NULL) { ! 688: if (strlcat(line, LL_USER_STR, len) >= len || ! 689: strlcat(line, runas_pw->pw_name, len) >= len || ! 690: strlcat(line, " ; ", len) >= len) ! 691: goto toobig; ! 692: } ! 693: if (runas_gr != NULL) { ! 694: if (strlcat(line, LL_GROUP_STR, len) >= len || ! 695: strlcat(line, runas_gr->gr_name, len) >= len || ! 696: strlcat(line, " ; ", len) >= len) ! 697: goto toobig; ! 698: } ! 699: if (tsid != NULL) { ! 700: if (strlcat(line, LL_TSID_STR, len) >= len || ! 701: strlcat(line, tsid, len) >= len || ! 702: strlcat(line, " ; ", len) >= len) ! 703: goto toobig; ! 704: } ! 705: if (evstr != NULL) { ! 706: if (strlcat(line, LL_ENV_STR, len) >= len || ! 707: strlcat(line, evstr, len) >= len || ! 708: strlcat(line, " ; ", len) >= len) ! 709: goto toobig; ! 710: efree(evstr); ! 711: } ! 712: if (user_cmnd != NULL) { ! 713: if (strlcat(line, LL_CMND_STR, len) >= len) ! 714: goto toobig; ! 715: if (ISSET(sudo_mode, MODE_CHECK) && strlcat(line, "list ", len) >= len) ! 716: goto toobig; ! 717: if (strlcat(line, user_cmnd, len) >= len) ! 718: goto toobig; ! 719: if (user_args != NULL) { ! 720: if (strlcat(line, " ", len) >= len || ! 721: strlcat(line, user_args, len) >= len) ! 722: goto toobig; ! 723: } ! 724: } ! 725: ! 726: return line; ! 727: toobig: ! 728: errorx(1, _("internal error: insufficient space for log line")); ! 729: }