2 * Copyright (c) 1994-1996,1998-2001 Todd C. Miller <Todd.Miller@courtesan.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * 4. Products derived from this software may not be called "Sudo" nor
20 * may "Sudo" appear in their names without specific prior written
21 * permission from the author.
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
26 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <sys/types.h>
38 #include <sys/param.h>
49 #endif /* STDC_HEADERS */
53 # ifdef HAVE_STRINGS_H
56 #endif /* HAVE_STRING_H */
59 #endif /* HAVE_UNISTD_H */
68 static const char rcsid[] = "$Sudo: logging.c,v 1.153 2002/01/16 21:28:25 millert Exp $";
71 static void do_syslog __P((int, char *));
72 static void do_logfile __P((char *));
73 static void send_mail __P((char *));
74 static void mail_auth __P((int, char *));
75 static char *get_timestr __P((void));
76 static void mysyslog __P((int, const char *, ...));
78 #define MAXSYSLOGTRIES 16 /* num of retries for broken syslogs */
81 * We do an openlog(3)/closelog(3) for each message because some
82 * authentication methods (notably PAM) use syslog(3) for their
83 * own nefarious purposes and may call openlog(3) and closelog(3).
84 * Note that because we don't want to assume that all systems have
85 * vsyslog(3) (HP-UX doesn't) "%m" will not be expanded.
86 * Sadly this is a maze of #ifdefs.
90 mysyslog(int pri, const char *fmt, ...)
92 mysyslog(pri, fmt, va_alist)
101 char buf[MAXSYSLOGLEN+1];
109 #ifdef LOG_NFACILITIES
110 openlog(Argv[0], 0, def_ival(I_LOGFAC));
114 vsnprintf(buf, sizeof(buf), fmt, ap);
117 * Some versions of syslog(3) don't guarantee success and return
118 * an int (notably HP-UX < 10.0). So, if at first we don't succeed,
121 for (i = 0; i < MAXSYSLOGTRIES; i++)
122 if (syslog(pri, "%s", buf) == 0)
125 syslog(pri, "%s", buf);
126 #endif /* BROKEN_SYSLOG */
132 * Log a message to syslog, pre-pending the username and splitting the
133 * message into parts if it is longer than MAXSYSLOGLEN.
146 * Log the full line, breaking into multiple syslog(3) calls if necessary
148 for (p = msg, count = 0; *p && count < strlen(msg) / MAXSYSLOGLEN + 1;
150 if (strlen(p) > MAXSYSLOGLEN) {
152 * Break up the line into what will fit on one syslog(3) line
153 * Try to break on a word boundary if possible.
155 for (tmp = p + MAXSYSLOGLEN; tmp > p && *tmp != ' '; tmp--)
158 tmp = p + MAXSYSLOGLEN;
160 /* NULL terminate line, but save the char to restore later */
165 mysyslog(pri, "%8.8s : %s", user_name, p);
167 mysyslog(pri, "%8.8s : (command continued) %s", user_name, p);
169 *tmp = save; /* restore saved character */
171 /* Eliminate leading whitespace */
172 for (p = tmp; *p != ' ' && *p !='\0'; p++)
176 mysyslog(pri, "%8.8s : %s", user_name, p);
178 mysyslog(pri, "%8.8s : (command continued) %s", user_name, p);
188 char *beg, *oldend, *end;
191 int maxlen = def_ival(I_LOGLINELEN);
193 oldmask = umask(077);
194 fp = fopen(def_str(I_LOGFILE), "a");
195 (void) umask(oldmask);
197 easprintf(&full_line, "Can't open log file: %s: %s",
198 def_str(I_LOGFILE), strerror(errno));
199 send_mail(full_line);
201 } else if (!lock_file(fileno(fp), SUDO_LOCK)) {
202 easprintf(&full_line, "Can't lock log file: %s: %s",
203 def_str(I_LOGFILE), strerror(errno));
204 send_mail(full_line);
207 if (def_ival(I_LOGLINELEN) == 0) {
208 /* Don't pretty-print long log file lines (hard to grep) */
209 if (def_flag(I_LOG_HOST))
210 (void) fprintf(fp, "%s : %s : HOST=%s : %s\n", get_timestr(),
211 user_name, user_shost, msg);
213 (void) fprintf(fp, "%s : %s : %s\n", get_timestr(),
216 if (def_flag(I_LOG_HOST))
217 easprintf(&full_line, "%s : %s : HOST=%s : %s", get_timestr(),
218 user_name, user_shost, msg);
220 easprintf(&full_line, "%s : %s : %s", get_timestr(),
224 * Print out full_line with word wrap
226 beg = end = full_line;
229 end = strchr(oldend, ' ');
231 if (maxlen > 0 && end) {
233 if (strlen(beg) > maxlen) {
234 /* too far, need to back up & print the line */
236 if (beg == (char *)full_line)
237 maxlen -= 4; /* don't indent first line */
246 (void) fprintf(fp, "%s\n ", beg);
249 (void) fprintf(fp, "%s\n ", beg);
252 /* reset beg to point to the start of the new substr */
257 /* we still have room */
261 /* remove leading whitespace */
266 (void) fprintf(fp, "%s\n", beg);
267 beg = NULL; /* exit condition */
273 (void) lock_file(fileno(fp), SUDO_UNLOCK);
279 * Two main functions, log_error() to log errors and log_auth() to
280 * log allow/deny messages.
283 log_auth(status, inform_user)
291 if (status & VALIDATE_OK)
292 pri = def_ival(I_GOODPRI);
294 pri = def_ival(I_BADPRI);
296 /* Set error message, if any. */
297 if (status & VALIDATE_OK)
299 else if (status & FLAG_NO_USER)
300 message = "user NOT in sudoers ; ";
301 else if (status & FLAG_NO_HOST)
302 message = "user NOT authorized on host ; ";
303 else if (status & VALIDATE_NOT_OK)
304 message = "command not allowed ; ";
306 message = "unknown error ; ";
308 easprintf(&logline, "%sTTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s%s%s",
309 message, user_tty, user_cwd, *user_runas, user_cmnd,
310 user_args ? " " : "", user_args ? user_args : "");
312 mail_auth(status, logline); /* send mail based on status */
314 /* Inform the user if they failed to authenticate. */
315 if (inform_user && (status & VALIDATE_NOT_OK)) {
316 if (status & FLAG_NO_USER)
317 (void) fprintf(stderr, "%s is not in the sudoers file. %s",
318 user_name, "This incident will be reported.\n");
319 else if (status & FLAG_NO_HOST)
320 (void) fprintf(stderr, "%s is not allowed to run sudo on %s. %s",
321 user_name, user_shost, "This incident will be reported.\n");
322 else if (status & FLAG_NO_CHECK)
323 (void) fprintf(stderr, "Sorry, user %s may not run sudo on %s.\n",
324 user_name, user_shost);
326 (void) fprintf(stderr,
327 "Sorry, user %s is not allowed to execute '%s%s%s' as %s on %s.\n",
328 user_name, user_cmnd, user_args ? " " : "",
329 user_args ? user_args : "", *user_runas, user_host);
333 * Log via syslog and/or a file.
335 if (def_str(I_SYSLOG))
336 do_syslog(pri, logline);
337 if (def_str(I_LOGFILE))
345 log_error(int flags, const char *fmt, ...)
362 flags = va_arg(ap, int);
363 fmt = va_arg(ap, const char *);
366 /* Become root if we are not already to avoid user control */
368 set_perms(PERM_ROOT, 0);
370 /* Expand printf-style format + args. */
371 evasprintf(&message, fmt, ap);
374 if (flags & MSG_ONLY)
376 else if (flags & USE_ERRNO) {
379 "%s: %s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s %s",
380 message, strerror(serrno), user_tty, user_cwd, *user_runas,
381 user_cmnd, user_args);
384 "%s: %s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s", message,
385 strerror(serrno), user_tty, user_cwd, *user_runas, user_cmnd);
390 "%s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s %s", message,
391 user_tty, user_cwd, *user_runas, user_cmnd, user_args);
394 "%s ; TTY=%s ; PWD=%s ; USER=%s ; COMMAND=%s", message,
395 user_tty, user_cwd, *user_runas, user_cmnd);
402 (void) fprintf(stderr, "%s: %s", Argv[0], message);
403 if (flags & USE_ERRNO)
404 (void) fprintf(stderr, ": %s", strerror(serrno));
405 (void) fputc('\n', stderr);
408 * Send a copy of the error via mail.
410 if (!(flags & NO_MAIL))
414 * Log to syslog and/or a file.
416 if (def_str(I_SYSLOG))
417 do_syslog(def_ival(I_BADPRI), logline);
418 if (def_str(I_LOGFILE))
422 if (logline != message)
425 if (!(flags & NO_EXIT))
429 #define MAX_MAILFLAGS 63
432 * Send a message to MAILTO user
440 int pfd[2], pid, status;
442 #ifndef NO_ROOT_MAILER
443 static char *root_envp[] = {
445 "PATH=/usr/bin:/bin",
452 /* Just return if mailer is disabled. */
453 if (!def_str(I_MAILERPATH) || !def_str(I_MAILTO))
456 (void) sigemptyset(&set);
457 (void) sigaddset(&set, SIGCHLD);
458 (void) sigprocmask(SIG_BLOCK, &set, &oset);
460 if (pipe(pfd) == -1) {
461 (void) fprintf(stderr, "%s: cannot open pipe: %s\n",
462 Argv[0], strerror(errno));
466 switch (pid = fork()) {
469 (void) fprintf(stderr, "%s: cannot fork: %s\n",
470 Argv[0], strerror(errno));
475 char *argv[MAX_MAILFLAGS + 1];
476 char *mpath, *mflags;
479 /* Child, set stdin to output side of the pipe */
480 if (pfd[0] != STDIN_FILENO) {
481 (void) dup2(pfd[0], STDIN_FILENO);
482 (void) close(pfd[0]);
484 (void) close(pfd[1]);
486 /* Build up an argv based the mailer path and flags */
487 mflags = estrdup(def_str(I_MAILERFLAGS));
488 mpath = estrdup(def_str(I_MAILERPATH));
489 if ((argv[0] = strrchr(mpath, ' ')))
495 if ((p = strtok(mflags, " \t"))) {
498 } while (++i < MAX_MAILFLAGS && (p = strtok(NULL, " \t")));
502 /* Close password file so we don't leak the fd. */
506 * Depending on the config, either run the mailer as root
507 * (so user cannot kill it) or as the user (for the paranoid).
509 #ifndef NO_ROOT_MAILER
510 set_perms(PERM_FULL_ROOT, 0);
511 execve(mpath, argv, root_envp);
513 set_perms(PERM_FULL_USER, 0);
515 #endif /* NO_ROOT_MAILER */
521 (void) close(pfd[0]);
522 mail = fdopen(pfd[1], "w");
524 /* Pipes are all setup, send message via sendmail. */
525 (void) fprintf(mail, "To: %s\nFrom: %s\nSubject: ",
526 def_str(I_MAILTO), user_name);
527 for (p = def_str(I_MAILSUB); *p; p++) {
528 /* Expand escapes in the subject */
529 if (*p == '%' && *(p+1) != '%') {
532 (void) fputs(user_host, mail);
535 (void) fputs(user_name, mail);
542 (void) fputc(*p, mail);
544 (void) fprintf(mail, "\n\n%s : %s : %s : %s\n\n", user_host,
545 get_timestr(), user_name, line);
548 /* If mailer is done, wait for it now. If not reapchild will get it. */
550 (void) sudo_waitpid(pid, &status, WNOHANG);
552 (void) sigprocmask(SIG_SETMASK, &oset, NULL);
556 * Send mail based on the value of "status" and compile-time options.
559 mail_auth(status, line)
565 /* If any of these bits are set in status, we send mail. */
566 if (def_flag(I_MAIL_ALWAYS))
568 VALIDATE_ERROR|VALIDATE_OK|FLAG_NO_USER|FLAG_NO_HOST|VALIDATE_NOT_OK;
570 mail_mask = VALIDATE_ERROR;
571 if (def_flag(I_MAIL_NO_USER))
572 mail_mask |= FLAG_NO_USER;
573 if (def_flag(I_MAIL_NO_HOST))
574 mail_mask |= FLAG_NO_HOST;
575 if (def_flag(I_MAIL_NO_PERMS))
576 mail_mask |= VALIDATE_NOT_OK;
579 if ((status & mail_mask) != 0)
584 * SIGCHLD sig handler--wait for children as they die.
590 int status, serrno = errno;
593 while (sudo_waitpid(-1, &status, WNOHANG) != -1 && errno == EINTR)
596 (void) wait(&status);
602 * Return an ascii string with the current date + time
603 * Uses strftime() if available, else falls back to ctime().
609 time_t now = time((time_t) 0);
611 static char buf[128];
614 timeptr = localtime(&now);
615 if (def_flag(I_LOG_YEAR))
620 /* strftime() does not guarantee to NUL-terminate so we must check. */
621 buf[sizeof(buf) - 1] = '\0';
622 if (strftime(buf, sizeof(buf), s, timeptr) && buf[sizeof(buf) - 1] == '\0')
625 #endif /* HAVE_STRFTIME */
627 s = ctime(&now) + 4; /* skip day of the week */
628 if (def_flag(I_LOG_YEAR))
629 s[20] = '\0'; /* avoid the newline */
631 s[15] = '\0'; /* don't care about year */