Annotation of src/usr.bin/sudo/logging.c, Revision 1.20
1.1 millert 1: /*
1.17 millert 2: * Copyright (c) 1994-1996,1998-2007 Todd C. Miller <Todd.Miller@courtesan.com>
1.1 millert 3: *
1.15 millert 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.
1.1 millert 7: *
1.15 millert 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.
1.13 millert 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.
1.1 millert 19: */
20:
1.15 millert 21: #ifdef __TANDEM
22: # include <floss.h>
23: #endif
24:
1.17 millert 25: #include <config.h>
1.1 millert 26:
1.5 millert 27: #include <sys/types.h>
28: #include <sys/param.h>
29: #include <sys/stat.h>
1.20 ! millert 30: #include <sys/ioctl.h>
1.5 millert 31: #include <sys/wait.h>
1.1 millert 32: #include <stdio.h>
33: #ifdef STDC_HEADERS
1.5 millert 34: # include <stdlib.h>
35: # include <stddef.h>
36: #else
37: # ifdef HAVE_STDLIB_H
38: # include <stdlib.h>
39: # endif
1.1 millert 40: #endif /* STDC_HEADERS */
1.5 millert 41: #ifdef HAVE_STRING_H
42: # include <string.h>
43: #else
44: # ifdef HAVE_STRINGS_H
45: # include <strings.h>
46: # endif
47: #endif /* HAVE_STRING_H */
1.1 millert 48: #ifdef HAVE_UNISTD_H
1.5 millert 49: # include <unistd.h>
1.1 millert 50: #endif /* HAVE_UNISTD_H */
1.12 millert 51: #ifdef HAVE_ERR_H
52: # include <err.h>
53: #else
54: # include "emul/err.h"
55: #endif /* HAVE_ERR_H */
1.1 millert 56: #include <pwd.h>
57: #include <signal.h>
58: #include <time.h>
59: #include <errno.h>
1.20 ! millert 60: #include <fcntl.h>
1.1 millert 61:
62: #include "sudo.h"
63:
64: #ifndef lint
1.20 ! millert 65: __unused static const char rcsid[] = "$Sudo: logging.c,v 1.168.2.16 2008/06/22 20:23:57 millert Exp $";
1.1 millert 66: #endif /* lint */
67:
68: static void do_syslog __P((int, char *));
69: static void do_logfile __P((char *));
70: static void send_mail __P((char *));
71: static void mail_auth __P((int, char *));
72: static char *get_timestr __P((void));
1.5 millert 73: static void mysyslog __P((int, const char *, ...));
1.1 millert 74:
1.5 millert 75: #define MAXSYSLOGTRIES 16 /* num of retries for broken syslogs */
1.1 millert 76:
77: /*
1.5 millert 78: * We do an openlog(3)/closelog(3) for each message because some
79: * authentication methods (notably PAM) use syslog(3) for their
80: * own nefarious purposes and may call openlog(3) and closelog(3).
81: * Note that because we don't want to assume that all systems have
82: * vsyslog(3) (HP-UX doesn't) "%m" will not be expanded.
83: * Sadly this is a maze of #ifdefs.
1.1 millert 84: */
85: static void
1.5 millert 86: #ifdef __STDC__
87: mysyslog(int pri, const char *fmt, ...)
88: #else
89: mysyslog(pri, fmt, va_alist)
1.1 millert 90: int pri;
91: const char *fmt;
1.5 millert 92: va_dcl
93: #endif
1.1 millert 94: {
1.5 millert 95: #ifdef BROKEN_SYSLOG
1.1 millert 96: int i;
1.5 millert 97: #endif
98: char buf[MAXSYSLOGLEN+1];
99: va_list ap;
1.1 millert 100:
1.5 millert 101: #ifdef __STDC__
102: va_start(ap, fmt);
103: #else
104: va_start(ap);
105: #endif
106: #ifdef LOG_NFACILITIES
1.15 millert 107: openlog("sudo", 0, def_syslog);
1.5 millert 108: #else
1.12 millert 109: openlog("sudo", 0);
1.5 millert 110: #endif
111: vsnprintf(buf, sizeof(buf), fmt, ap);
112: #ifdef BROKEN_SYSLOG
113: /*
114: * Some versions of syslog(3) don't guarantee success and return
115: * an int (notably HP-UX < 10.0). So, if at first we don't succeed,
116: * try, try again...
117: */
1.1 millert 118: for (i = 0; i < MAXSYSLOGTRIES; i++)
1.5 millert 119: if (syslog(pri, "%s", buf) == 0)
1.1 millert 120: break;
121: #else
1.5 millert 122: syslog(pri, "%s", buf);
1.1 millert 123: #endif /* BROKEN_SYSLOG */
1.5 millert 124: va_end(ap);
125: closelog();
126: }
1.1 millert 127:
128: /*
129: * Log a message to syslog, pre-pending the username and splitting the
130: * message into parts if it is longer than MAXSYSLOGLEN.
131: */
132: static void
133: do_syslog(pri, msg)
134: int pri;
135: char *msg;
136: {
1.17 millert 137: size_t len, maxlen;
138: char *p, *tmp, save;
139: const char *fmt;
1.18 millert 140: const char *fmt_first = "%8s : %s";
141: const char *fmt_contd = "%8s : (command continued) %s";
1.1 millert 142:
143: /*
144: * Log the full line, breaking into multiple syslog(3) calls if necessary
145: */
1.17 millert 146: fmt = fmt_first;
147: maxlen = MAXSYSLOGLEN - (sizeof(fmt_first) - 6 + strlen(user_name));
148: for (p = msg; *p != '\0'; ) {
149: len = strlen(p);
150: if (len > maxlen) {
1.1 millert 151: /*
152: * Break up the line into what will fit on one syslog(3) line
1.17 millert 153: * Try to avoid breaking words into several lines if possible.
1.1 millert 154: */
1.17 millert 155: tmp = memrchr(p, ' ', maxlen);
156: if (tmp == NULL)
157: tmp = p + maxlen;
1.1 millert 158:
159: /* NULL terminate line, but save the char to restore later */
160: save = *tmp;
161: *tmp = '\0';
162:
1.17 millert 163: mysyslog(pri, fmt, user_name, p);
1.1 millert 164:
165: *tmp = save; /* restore saved character */
166:
1.17 millert 167: /* Advance p and eliminate leading whitespace */
168: for (p = tmp; *p == ' '; p++)
1.1 millert 169: ;
170: } else {
1.17 millert 171: mysyslog(pri, fmt, user_name, p);
172: p += len;
1.1 millert 173: }
1.17 millert 174: fmt = fmt_contd;
175: maxlen = MAXSYSLOGLEN - (sizeof(fmt_contd) - 6 + strlen(user_name));
1.1 millert 176: }
177: }
178:
179: static void
180: do_logfile(msg)
181: char *msg;
182: {
183: char *full_line;
184: char *beg, *oldend, *end;
185: FILE *fp;
186: mode_t oldmask;
1.9 millert 187: size_t maxlen;
1.1 millert 188:
189: oldmask = umask(077);
1.15 millert 190: maxlen = def_loglinelen > 0 ? def_loglinelen : 0;
191: fp = fopen(def_logfile, "a");
1.1 millert 192: (void) umask(oldmask);
193: if (fp == NULL) {
194: easprintf(&full_line, "Can't open log file: %s: %s",
1.15 millert 195: def_logfile, strerror(errno));
1.1 millert 196: send_mail(full_line);
1.17 millert 197: efree(full_line);
1.1 millert 198: } else if (!lock_file(fileno(fp), SUDO_LOCK)) {
199: easprintf(&full_line, "Can't lock log file: %s: %s",
1.15 millert 200: def_logfile, strerror(errno));
1.1 millert 201: send_mail(full_line);
1.17 millert 202: efree(full_line);
1.1 millert 203: } else {
1.15 millert 204: if (def_loglinelen == 0) {
1.1 millert 205: /* Don't pretty-print long log file lines (hard to grep) */
1.15 millert 206: if (def_log_host)
1.1 millert 207: (void) fprintf(fp, "%s : %s : HOST=%s : %s\n", get_timestr(),
208: user_name, user_shost, msg);
209: else
210: (void) fprintf(fp, "%s : %s : %s\n", get_timestr(),
211: user_name, msg);
212: } else {
1.15 millert 213: if (def_log_host)
1.1 millert 214: easprintf(&full_line, "%s : %s : HOST=%s : %s", get_timestr(),
215: user_name, user_shost, msg);
216: else
217: easprintf(&full_line, "%s : %s : %s", get_timestr(),
218: user_name, msg);
219:
220: /*
221: * Print out full_line with word wrap
222: */
223: beg = end = full_line;
224: while (beg) {
225: oldend = end;
226: end = strchr(oldend, ' ');
227:
228: if (maxlen > 0 && end) {
229: *end = '\0';
230: if (strlen(beg) > maxlen) {
231: /* too far, need to back up & print the line */
232:
233: if (beg == (char *)full_line)
234: maxlen -= 4; /* don't indent first line */
235:
236: *end = ' ';
237: if (oldend != beg) {
238: /* rewind & print */
239: end = oldend-1;
240: while (*end == ' ')
241: --end;
242: *(++end) = '\0';
243: (void) fprintf(fp, "%s\n ", beg);
244: *end = ' ';
245: } else {
246: (void) fprintf(fp, "%s\n ", beg);
247: }
248:
249: /* reset beg to point to the start of the new substr */
250: beg = end;
251: while (*beg == ' ')
252: ++beg;
253: } else {
254: /* we still have room */
255: *end = ' ';
256: }
257:
258: /* remove leading whitespace */
259: while (*end == ' ')
260: ++end;
261: } else {
262: /* final line */
263: (void) fprintf(fp, "%s\n", beg);
264: beg = NULL; /* exit condition */
265: }
266: }
1.17 millert 267: efree(full_line);
1.1 millert 268: }
269: (void) fflush(fp);
270: (void) lock_file(fileno(fp), SUDO_UNLOCK);
271: (void) fclose(fp);
272: }
273: }
274:
275: /*
276: * Two main functions, log_error() to log errors and log_auth() to
277: * log allow/deny messages.
278: */
279: void
280: log_auth(status, inform_user)
281: int status;
282: int inform_user;
283: {
1.17 millert 284: char *evstr = NULL;
1.1 millert 285: char *message;
286: char *logline;
287: int pri;
288:
1.15 millert 289: if (ISSET(status, VALIDATE_OK))
290: pri = def_syslog_goodpri;
1.1 millert 291: else
1.15 millert 292: pri = def_syslog_badpri;
1.1 millert 293:
294: /* Set error message, if any. */
1.15 millert 295: if (ISSET(status, VALIDATE_OK))
1.1 millert 296: message = "";
1.15 millert 297: else if (ISSET(status, FLAG_NO_USER))
1.1 millert 298: message = "user NOT in sudoers ; ";
1.15 millert 299: else if (ISSET(status, FLAG_NO_HOST))
1.1 millert 300: message = "user NOT authorized on host ; ";
1.15 millert 301: else if (ISSET(status, VALIDATE_NOT_OK))
1.1 millert 302: message = "command not allowed ; ";
303: else
304: message = "unknown error ; ";
305:
1.17 millert 306: if (sudo_user.env_vars != NULL) {
307: size_t len = 7; /* " ; ENV=" */
308: struct list_member *cur;
309: for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next)
310: len += strlen(cur->value) + 1;
311: evstr = emalloc(len);
312: strlcpy(evstr, " ; ENV=", len);
313: for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next) {
314: strlcat(evstr, cur->value, len);
315: strlcat(evstr, " ", len); /* NOTE: last one will fail */
316: }
317: }
318: easprintf(&logline, "%sTTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s%s%s",
319: message, user_tty, user_cwd, *user_runas, evstr ? evstr : "",
320: user_cmnd, user_args ? " " : "", user_args ? user_args : "");
1.1 millert 321:
322: mail_auth(status, logline); /* send mail based on status */
323:
324: /* Inform the user if they failed to authenticate. */
1.15 millert 325: if (inform_user && ISSET(status, VALIDATE_NOT_OK)) {
326: if (ISSET(status, FLAG_NO_USER))
1.1 millert 327: (void) fprintf(stderr, "%s is not in the sudoers file. %s",
328: user_name, "This incident will be reported.\n");
1.15 millert 329: else if (ISSET(status, FLAG_NO_HOST))
1.1 millert 330: (void) fprintf(stderr, "%s is not allowed to run sudo on %s. %s",
331: user_name, user_shost, "This incident will be reported.\n");
1.15 millert 332: else if (ISSET(status, FLAG_NO_CHECK))
1.1 millert 333: (void) fprintf(stderr, "Sorry, user %s may not run sudo on %s.\n",
334: user_name, user_shost);
335: else
336: (void) fprintf(stderr,
337: "Sorry, user %s is not allowed to execute '%s%s%s' as %s on %s.\n",
338: user_name, user_cmnd, user_args ? " " : "",
339: user_args ? user_args : "", *user_runas, user_host);
340: }
341:
342: /*
343: * Log via syslog and/or a file.
344: */
1.15 millert 345: if (def_syslog)
1.1 millert 346: do_syslog(pri, logline);
1.15 millert 347: if (def_logfile)
1.1 millert 348: do_logfile(logline);
349:
1.17 millert 350: efree(evstr);
351: efree(logline);
1.1 millert 352: }
353:
354: void
355: #ifdef __STDC__
356: log_error(int flags, const char *fmt, ...)
357: #else
1.17 millert 358: log_error(flags, fmt, va_alist)
359: int flags;
360: const char *fmt;
1.1 millert 361: va_dcl
362: #endif
363: {
364: int serrno = errno;
365: char *message;
366: char *logline;
1.17 millert 367: char *evstr = NULL;
1.1 millert 368: va_list ap;
369: #ifdef __STDC__
370: va_start(ap, fmt);
371: #else
372: va_start(ap);
373: #endif
374:
1.19 millert 375: /* Become root if we are not already to avoid user interference */
376: set_perms(PERM_ROOT);
1.1 millert 377:
378: /* Expand printf-style format + args. */
379: evasprintf(&message, fmt, ap);
380: va_end(ap);
381:
1.17 millert 382: if (sudo_user.env_vars != NULL) {
383: size_t len = 7; /* " ; ENV=" */
384: struct list_member *cur;
385: for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next)
386: len += strlen(cur->value) + 1;
387: evstr = emalloc(len);
388: strlcpy(evstr, " ; ENV=", len);
389: for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next) {
390: strlcat(evstr, cur->value, len);
391: strlcat(evstr, " ", len); /* NOTE: last one will fail */
392: }
393: }
394:
395: if (ISSET(flags, MSG_ONLY))
1.1 millert 396: logline = message;
1.17 millert 397: else if (ISSET(flags, USE_ERRNO)) {
1.1 millert 398: if (user_args) {
399: easprintf(&logline,
1.17 millert 400: "%s: %s ; TTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s %s",
1.1 millert 401: message, strerror(serrno), user_tty, user_cwd, *user_runas,
1.17 millert 402: evstr ? evstr : "", user_cmnd, user_args);
1.1 millert 403: } else {
404: easprintf(&logline,
1.17 millert 405: "%s: %s ; TTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s", message,
406: strerror(serrno), user_tty, user_cwd, *user_runas,
407: evstr ? evstr : "", user_cmnd);
1.1 millert 408: }
409: } else {
410: if (user_args) {
411: easprintf(&logline,
1.17 millert 412: "%s ; TTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s %s", message,
413: user_tty, user_cwd, *user_runas, evstr ? evstr : "",
414: user_cmnd, user_args);
1.1 millert 415: } else {
416: easprintf(&logline,
1.17 millert 417: "%s ; TTY=%s ; PWD=%s ; USER=%s%s ; COMMAND=%s", message,
418: user_tty, user_cwd, *user_runas, evstr ? evstr : "", user_cmnd);
1.1 millert 419: }
420: }
421:
422: /*
423: * Tell the user.
424: */
1.17 millert 425: if (ISSET(flags, USE_ERRNO))
1.12 millert 426: warn("%s", message);
427: else
428: warnx("%s", message);
1.1 millert 429:
430: /*
431: * Send a copy of the error via mail.
432: */
1.17 millert 433: if (!ISSET(flags, NO_MAIL))
1.1 millert 434: send_mail(logline);
435:
436: /*
437: * Log to syslog and/or a file.
438: */
1.15 millert 439: if (def_syslog)
440: do_syslog(def_syslog_badpri, logline);
441: if (def_logfile)
1.1 millert 442: do_logfile(logline);
443:
1.17 millert 444: efree(message);
1.5 millert 445: if (logline != message)
1.17 millert 446: efree(logline);
1.1 millert 447:
1.17 millert 448: if (!ISSET(flags, NO_EXIT))
1.1 millert 449: exit(1);
450: }
451:
452: #define MAX_MAILFLAGS 63
453:
454: /*
455: * Send a message to MAILTO user
456: */
457: static void
458: send_mail(line)
459: char *line;
460: {
461: FILE *mail;
462: char *p;
1.20 ! millert 463: int fd, pfd[2], status;
! 464: pid_t pid, rv;
! 465: sigaction_t sa;
1.7 millert 466: #ifndef NO_ROOT_MAILER
467: static char *root_envp[] = {
468: "HOME=/",
469: "PATH=/usr/bin:/bin",
470: "LOGNAME=root",
1.17 millert 471: "USERNAME=root",
1.7 millert 472: "USER=root",
473: NULL
474: };
475: #endif
1.1 millert 476:
477: /* Just return if mailer is disabled. */
1.15 millert 478: if (!def_mailerpath || !def_mailto)
1.1 millert 479: return;
480:
1.20 ! millert 481: /* Fork and return, child will daemonize. */
! 482: switch (pid = fork()) {
! 483: case -1:
! 484: /* Error */
! 485: err(1, "cannot fork");
! 486: break;
! 487: case 0:
! 488: /* Child */
! 489: switch (pid = fork()) {
! 490: case -1:
! 491: /* Error. */
! 492: mysyslog(LOG_ERR, "cannot fork: %m");
! 493: _exit(1);
! 494: case 0:
! 495: /* Grandchild continues below. */
! 496: break;
! 497: default:
! 498: /* Parent will wait for us. */
! 499: _exit(0);
! 500: }
! 501: break;
! 502: default:
! 503: /* Parent */
! 504: do {
! 505: #ifdef HAVE_WAITPID
! 506: rv = waitpid(pid, &status, 0);
! 507: #else
! 508: rv = wait(&status);
! 509: #endif
! 510: } while (rv == -1 && errno == EINTR);
! 511: return;
! 512: }
1.1 millert 513:
1.20 ! millert 514: /* Daemonize - disassociate from session/tty. */
! 515: #ifdef HAVE_SETSID
! 516: if (setsid() == -1)
! 517: warn("setsid");
! 518: #else
! 519: setpgrp(0, 0);
! 520: # ifdef TIOCNOTTY
! 521: if ((fd = open(_PATH_TTY, O_RDWR, 0644)) != -1) {
! 522: ioctl(fd, TIOCNOTTY, NULL);
! 523: close(fd);
! 524: }
! 525: # endif
! 526: #endif
! 527: chdir("/");
! 528: if ((fd = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) {
! 529: (void) dup2(fd, STDIN_FILENO);
! 530: (void) dup2(fd, STDOUT_FILENO);
! 531: (void) dup2(fd, STDERR_FILENO);
! 532: }
! 533:
! 534: /* Close password and other fds so we don't leak. */
! 535: endpwent();
! 536: closefrom(STDERR_FILENO + 1);
! 537:
! 538: /* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */
! 539: sigemptyset(&sa.sa_mask);
! 540: sa.sa_flags = 0;
! 541: sa.sa_handler = SIG_IGN;
! 542: (void) sigaction(SIGPIPE, &sa, NULL);
! 543:
! 544: if (pipe(pfd) == -1) {
! 545: mysyslog(LOG_ERR, "cannot open pipe: %m");
! 546: _exit(1);
! 547: }
1.1 millert 548:
1.2 millert 549: switch (pid = fork()) {
550: case -1:
551: /* Error. */
1.20 ! millert 552: mysyslog(LOG_ERR, "cannot fork: %m");
! 553: _exit(1);
1.2 millert 554: break;
555: case 0:
556: {
557: char *argv[MAX_MAILFLAGS + 1];
558: char *mpath, *mflags;
559: int i;
560:
1.5 millert 561: /* Child, set stdin to output side of the pipe */
562: if (pfd[0] != STDIN_FILENO) {
563: (void) dup2(pfd[0], STDIN_FILENO);
564: (void) close(pfd[0]);
565: }
1.2 millert 566: (void) close(pfd[1]);
567:
568: /* Build up an argv based the mailer path and flags */
1.15 millert 569: mflags = estrdup(def_mailerflags);
570: mpath = estrdup(def_mailerpath);
1.2 millert 571: if ((argv[0] = strrchr(mpath, ' ')))
572: argv[0]++;
573: else
574: argv[0] = mpath;
575:
576: i = 1;
577: if ((p = strtok(mflags, " \t"))) {
578: do {
579: argv[i] = p;
580: } while (++i < MAX_MAILFLAGS && (p = strtok(NULL, " \t")));
581: }
582: argv[i] = NULL;
1.1 millert 583:
1.7 millert 584: /*
585: * Depending on the config, either run the mailer as root
586: * (so user cannot kill it) or as the user (for the paranoid).
587: */
588: #ifndef NO_ROOT_MAILER
1.17 millert 589: set_perms(PERM_ROOT);
1.7 millert 590: execve(mpath, argv, root_envp);
591: #else
1.9 millert 592: set_perms(PERM_FULL_USER);
1.2 millert 593: execv(mpath, argv);
1.7 millert 594: #endif /* NO_ROOT_MAILER */
1.20 ! millert 595: mysyslog(LOG_ERR, "cannot execute %s: %m", mpath);
1.2 millert 596: _exit(127);
597: }
598: break;
599: }
1.1 millert 600:
1.5 millert 601: (void) close(pfd[0]);
1.2 millert 602: mail = fdopen(pfd[1], "w");
1.1 millert 603:
1.2 millert 604: /* Pipes are all setup, send message via sendmail. */
1.17 millert 605: (void) fprintf(mail, "To: %s\nFrom: %s\nAuto-Submitted: %s\nSubject: ",
606: def_mailto, user_name, "auto-generated");
1.15 millert 607: for (p = def_mailsub; *p; p++) {
1.2 millert 608: /* Expand escapes in the subject */
609: if (*p == '%' && *(p+1) != '%') {
610: switch (*(++p)) {
611: case 'h':
612: (void) fputs(user_host, mail);
613: break;
614: case 'u':
615: (void) fputs(user_name, mail);
616: break;
617: default:
618: p--;
619: break;
620: }
621: } else
622: (void) fputc(*p, mail);
623: }
624: (void) fprintf(mail, "\n\n%s : %s : %s : %s\n\n", user_host,
625: get_timestr(), user_name, line);
626: fclose(mail);
1.20 ! millert 627: do {
! 628: #ifdef HAVE_WAITPID
! 629: rv = waitpid(pid, &status, 0);
! 630: #else
! 631: rv = wait(&status);
! 632: #endif
! 633: } while (rv == -1 && errno == EINTR);
! 634: _exit(0);
1.1 millert 635: }
636:
637: /*
638: * Send mail based on the value of "status" and compile-time options.
639: */
640: static void
641: mail_auth(status, line)
642: int status;
643: char *line;
644: {
645: int mail_mask;
646:
647: /* If any of these bits are set in status, we send mail. */
1.15 millert 648: if (def_mail_always)
1.1 millert 649: mail_mask =
650: VALIDATE_ERROR|VALIDATE_OK|FLAG_NO_USER|FLAG_NO_HOST|VALIDATE_NOT_OK;
651: else {
652: mail_mask = VALIDATE_ERROR;
1.15 millert 653: if (def_mail_no_user)
654: SET(mail_mask, FLAG_NO_USER);
655: if (def_mail_no_host)
656: SET(mail_mask, FLAG_NO_HOST);
657: if (def_mail_no_perms)
658: SET(mail_mask, VALIDATE_NOT_OK);
1.1 millert 659: }
660:
661: if ((status & mail_mask) != 0)
662: send_mail(line);
663: }
664:
665: /*
666: * Return an ascii string with the current date + time
667: * Uses strftime() if available, else falls back to ctime().
668: */
669: static char *
670: get_timestr()
671: {
672: char *s;
673: time_t now = time((time_t) 0);
674: #ifdef HAVE_STRFTIME
675: static char buf[128];
676: struct tm *timeptr;
677:
678: timeptr = localtime(&now);
1.15 millert 679: if (def_log_year)
1.1 millert 680: s = "%h %e %T %Y";
681: else
682: s = "%h %e %T";
683:
684: /* strftime() does not guarantee to NUL-terminate so we must check. */
685: buf[sizeof(buf) - 1] = '\0';
686: if (strftime(buf, sizeof(buf), s, timeptr) && buf[sizeof(buf) - 1] == '\0')
687: return(buf);
688:
689: #endif /* HAVE_STRFTIME */
690:
691: s = ctime(&now) + 4; /* skip day of the week */
1.15 millert 692: if (def_log_year)
1.1 millert 693: s[20] = '\0'; /* avoid the newline */
694: else
695: s[15] = '\0'; /* don't care about year */
696:
697: return(s);
698: }