version 1.4, 2001/08/23 21:45:03 |
version 1.5, 2002/01/03 03:49:16 |
|
|
/* |
/* |
* Copyright (c) 1994-1996,1998-1999 Todd C. Miller <Todd.Miller@courtesan.com> |
* Copyright (c) 1994-1996,1998-2001 Todd C. Miller <Todd.Miller@courtesan.com> |
* All rights reserved. |
* All rights reserved. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
|
|
|
|
#include "config.h" |
#include "config.h" |
|
|
|
#include <sys/types.h> |
|
#include <sys/param.h> |
|
#include <sys/stat.h> |
|
#include <sys/wait.h> |
#include <stdio.h> |
#include <stdio.h> |
#ifdef STDC_HEADERS |
#ifdef STDC_HEADERS |
#include <stdlib.h> |
# include <stdlib.h> |
|
# include <stddef.h> |
|
#else |
|
# ifdef HAVE_STDLIB_H |
|
# include <stdlib.h> |
|
# endif |
#endif /* STDC_HEADERS */ |
#endif /* STDC_HEADERS */ |
#ifdef HAVE_UNISTD_H |
|
#include <unistd.h> |
|
#endif /* HAVE_UNISTD_H */ |
|
#ifdef HAVE_STRING_H |
#ifdef HAVE_STRING_H |
#include <string.h> |
# include <string.h> |
|
#else |
|
# ifdef HAVE_STRINGS_H |
|
# include <strings.h> |
|
# endif |
#endif /* HAVE_STRING_H */ |
#endif /* HAVE_STRING_H */ |
#ifdef HAVE_STRINGS_H |
#ifdef HAVE_UNISTD_H |
#include <strings.h> |
# include <unistd.h> |
#endif /* HAVE_STRINGS_H */ |
#endif /* HAVE_UNISTD_H */ |
#include <pwd.h> |
#include <pwd.h> |
#include <signal.h> |
#include <signal.h> |
#include <time.h> |
#include <time.h> |
#include <errno.h> |
#include <errno.h> |
#include <sys/types.h> |
|
#include <sys/param.h> |
|
#include <sys/stat.h> |
|
#include <sys/wait.h> |
|
|
|
#include "sudo.h" |
#include "sudo.h" |
|
|
#ifndef lint |
#ifndef lint |
static const char rcsid[] = "$Sudo: logging.c,v 1.140 2000/03/13 16:05:05 millert Exp $"; |
static const char rcsid[] = "$Sudo: logging.c,v 1.151 2001/12/14 23:33:38 millert Exp $"; |
#endif /* lint */ |
#endif /* lint */ |
|
|
static void do_syslog __P((int, char *)); |
static void do_syslog __P((int, char *)); |
|
|
static void send_mail __P((char *)); |
static void send_mail __P((char *)); |
static void mail_auth __P((int, char *)); |
static void mail_auth __P((int, char *)); |
static char *get_timestr __P((void)); |
static char *get_timestr __P((void)); |
|
static void mysyslog __P((int, const char *, ...)); |
|
|
#ifdef BROKEN_SYSLOG |
#define MAXSYSLOGTRIES 16 /* num of retries for broken syslogs */ |
# define MAXSYSLOGTRIES 16 /* num of retries for broken syslogs */ |
|
# define SYSLOG syslog_wrapper |
|
|
|
static void syslog_wrapper __P((int, char *, char *, char *)); |
|
|
|
/* |
/* |
* Some versions of syslog(3) don't guarantee success and return |
* We do an openlog(3)/closelog(3) for each message because some |
* an int (notably HP-UX < 10.0). So, if at first we don't succeed, |
* authentication methods (notably PAM) use syslog(3) for their |
* try, try again... |
* own nefarious purposes and may call openlog(3) and closelog(3). |
|
* Note that because we don't want to assume that all systems have |
|
* vsyslog(3) (HP-UX doesn't) "%m" will not be expanded. |
|
* Sadly this is a maze of #ifdefs. |
*/ |
*/ |
static void |
static void |
syslog_wrapper(pri, fmt, ap) |
#ifdef __STDC__ |
|
mysyslog(int pri, const char *fmt, ...) |
|
#else |
|
mysyslog(pri, fmt, va_alist) |
int pri; |
int pri; |
const char *fmt; |
const char *fmt; |
va_list ap; |
va_dcl |
|
#endif |
{ |
{ |
|
#ifdef BROKEN_SYSLOG |
int i; |
int i; |
|
#endif |
|
char buf[MAXSYSLOGLEN+1]; |
|
va_list ap; |
|
|
|
#ifdef __STDC__ |
|
va_start(ap, fmt); |
|
#else |
|
va_start(ap); |
|
#endif |
|
#ifdef LOG_NFACILITIES |
|
openlog(Argv[0], 0, def_ival(I_LOGFAC)); |
|
#else |
|
openlog(Argv[0], 0); |
|
#endif |
|
vsnprintf(buf, sizeof(buf), fmt, ap); |
|
#ifdef BROKEN_SYSLOG |
|
/* |
|
* Some versions of syslog(3) don't guarantee success and return |
|
* an int (notably HP-UX < 10.0). So, if at first we don't succeed, |
|
* try, try again... |
|
*/ |
for (i = 0; i < MAXSYSLOGTRIES; i++) |
for (i = 0; i < MAXSYSLOGTRIES; i++) |
if (vsyslog(pri, fmt, ap) == 0) |
if (syslog(pri, "%s", buf) == 0) |
break; |
break; |
} |
|
#else |
#else |
# define SYSLOG syslog |
syslog(pri, "%s", buf); |
#endif /* BROKEN_SYSLOG */ |
#endif /* BROKEN_SYSLOG */ |
|
va_end(ap); |
|
closelog(); |
|
} |
|
|
/* |
/* |
* Log a message to syslog, pre-pending the username and splitting the |
* Log a message to syslog, pre-pending the username and splitting the |
|
|
*tmp = '\0'; |
*tmp = '\0'; |
|
|
if (count == 0) |
if (count == 0) |
SYSLOG(pri, "%8.8s : %s", user_name, p); |
mysyslog(pri, "%8.8s : %s", user_name, p); |
else |
else |
SYSLOG(pri, "%8.8s : (command continued) %s", user_name, p); |
mysyslog(pri, "%8.8s : (command continued) %s", user_name, p); |
|
|
*tmp = save; /* restore saved character */ |
*tmp = save; /* restore saved character */ |
|
|
|
|
; |
; |
} else { |
} else { |
if (count == 0) |
if (count == 0) |
SYSLOG(pri, "%8.8s : %s", user_name, p); |
mysyslog(pri, "%8.8s : %s", user_name, p); |
else |
else |
SYSLOG(pri, "%8.8s : (command continued) %s", user_name, p); |
mysyslog(pri, "%8.8s : (command continued) %s", user_name, p); |
} |
} |
} |
} |
} |
} |
|
|
char *beg, *oldend, *end; |
char *beg, *oldend, *end; |
FILE *fp; |
FILE *fp; |
mode_t oldmask; |
mode_t oldmask; |
int maxlen = def_ival(I_LOGLEN); |
int maxlen = def_ival(I_LOGLINELEN); |
|
|
oldmask = umask(077); |
oldmask = umask(077); |
fp = fopen(def_str(I_LOGFILE), "a"); |
fp = fopen(def_str(I_LOGFILE), "a"); |
|
|
send_mail(full_line); |
send_mail(full_line); |
free(full_line); |
free(full_line); |
} else { |
} else { |
if (def_ival(I_LOGLEN) == 0) { |
if (def_ival(I_LOGLINELEN) == 0) { |
/* Don't pretty-print long log file lines (hard to grep) */ |
/* Don't pretty-print long log file lines (hard to grep) */ |
if (def_flag(I_LOG_HOST)) |
if (def_flag(I_LOG_HOST)) |
(void) fprintf(fp, "%s : %s : HOST=%s : %s\n", get_timestr(), |
(void) fprintf(fp, "%s : %s : HOST=%s : %s\n", get_timestr(), |
|
|
/* |
/* |
* Log via syslog and/or a file. |
* Log via syslog and/or a file. |
*/ |
*/ |
if (def_str(I_LOGFACSTR)) |
if (def_str(I_SYSLOG)) |
do_syslog(pri, logline); |
do_syslog(pri, logline); |
if (def_str(I_LOGFILE)) |
if (def_str(I_LOGFILE)) |
do_logfile(logline); |
do_logfile(logline); |
|
|
/* |
/* |
* Log to syslog and/or a file. |
* Log to syslog and/or a file. |
*/ |
*/ |
if (def_str(I_LOGFACSTR)) |
if (def_str(I_SYSLOG)) |
do_syslog(def_ival(I_BADPRI), logline); |
do_syslog(def_ival(I_BADPRI), logline); |
if (def_str(I_LOGFILE)) |
if (def_str(I_LOGFILE)) |
do_logfile(logline); |
do_logfile(logline); |
|
|
free(logline); |
free(message); |
if (message != logline) |
if (logline != message) |
free(message); |
free(logline); |
|
|
if (!(flags & NO_EXIT)) |
if (!(flags & NO_EXIT)) |
exit(1); |
exit(1); |
|
|
FILE *mail; |
FILE *mail; |
char *p; |
char *p; |
int pfd[2], pid, status; |
int pfd[2], pid, status; |
#ifdef POSIX_SIGNALS |
|
sigset_t set, oset; |
sigset_t set, oset; |
#else |
|
int omask; |
|
#endif /* POSIX_SIGNALS */ |
|
|
|
/* Just return if mailer is disabled. */ |
/* Just return if mailer is disabled. */ |
if (!def_str(I_MAILERPATH) || !def_str(I_MAILTO)) |
if (!def_str(I_MAILERPATH) || !def_str(I_MAILTO)) |
return; |
return; |
|
|
#ifdef POSIX_SIGNALS |
|
(void) sigemptyset(&set); |
(void) sigemptyset(&set); |
(void) sigaddset(&set, SIGCHLD); |
(void) sigaddset(&set, SIGCHLD); |
(void) sigprocmask(SIG_BLOCK, &set, &oset); |
(void) sigprocmask(SIG_BLOCK, &set, &oset); |
#else |
|
omask = sigblock(sigmask(SIGCHLD)); |
|
#endif /* POSIX_SIGNALS */ |
|
|
|
if (pipe(pfd) == -1) { |
if (pipe(pfd) == -1) { |
(void) fprintf(stderr, "%s: cannot open pipe: %s\n", |
(void) fprintf(stderr, "%s: cannot open pipe: %s\n", |
|
|
char *mpath, *mflags; |
char *mpath, *mflags; |
int i; |
int i; |
|
|
/* Child. */ |
/* Child, set stdin to output side of the pipe */ |
|
if (pfd[0] != STDIN_FILENO) { |
|
(void) dup2(pfd[0], STDIN_FILENO); |
|
(void) close(pfd[0]); |
|
} |
(void) close(pfd[1]); |
(void) close(pfd[1]); |
(void) dup2(pfd[0], STDIN_FILENO); |
|
(void) close(pfd[0]); |
|
|
|
/* Build up an argv based the mailer path and flags */ |
/* Build up an argv based the mailer path and flags */ |
mflags = estrdup(def_str(I_MAILERFLAGS)); |
mflags = estrdup(def_str(I_MAILERFLAGS)); |
|
|
} |
} |
argv[i] = NULL; |
argv[i] = NULL; |
|
|
|
/* Close password file so we don't leak the fd. */ |
|
endpwent(); |
|
|
/* Run mailer as root so user cannot kill it. */ |
/* Run mailer as root so user cannot kill it. */ |
set_perms(PERM_ROOT, 0); |
set_perms(PERM_ROOT, 0); |
execv(mpath, argv); |
execv(mpath, argv); |
|
|
break; |
break; |
} |
} |
|
|
mail = fdopen(pfd[1], "w"); |
|
(void) close(pfd[0]); |
(void) close(pfd[0]); |
|
mail = fdopen(pfd[1], "w"); |
|
|
/* Pipes are all setup, send message via sendmail. */ |
/* Pipes are all setup, send message via sendmail. */ |
(void) fprintf(mail, "To: %s\nFrom: %s\nSubject: ", |
(void) fprintf(mail, "To: %s\nFrom: %s\nSubject: ", |
|
|
#ifdef sudo_waitpid |
#ifdef sudo_waitpid |
(void) sudo_waitpid(pid, &status, WNOHANG); |
(void) sudo_waitpid(pid, &status, WNOHANG); |
#endif |
#endif |
#ifdef POSIX_SIGNALS |
|
(void) sigprocmask(SIG_SETMASK, &oset, NULL); |
(void) sigprocmask(SIG_SETMASK, &oset, NULL); |
#else |
|
(void) sigsetmask(omask); |
|
#endif /* POSIX_SIGNALS */ |
|
} |
} |
|
|
/* |
/* |
|
|
VALIDATE_ERROR|VALIDATE_OK|FLAG_NO_USER|FLAG_NO_HOST|VALIDATE_NOT_OK; |
VALIDATE_ERROR|VALIDATE_OK|FLAG_NO_USER|FLAG_NO_HOST|VALIDATE_NOT_OK; |
else { |
else { |
mail_mask = VALIDATE_ERROR; |
mail_mask = VALIDATE_ERROR; |
if (def_flag(I_MAIL_NOUSER)) |
if (def_flag(I_MAIL_NO_USER)) |
mail_mask |= FLAG_NO_USER; |
mail_mask |= FLAG_NO_USER; |
if (def_flag(I_MAIL_NOHOST)) |
if (def_flag(I_MAIL_NO_HOST)) |
mail_mask |= FLAG_NO_HOST; |
mail_mask |= FLAG_NO_HOST; |
if (def_flag(I_MAIL_NOPERMS)) |
if (def_flag(I_MAIL_NO_PERMS)) |
mail_mask |= VALIDATE_NOT_OK; |
mail_mask |= VALIDATE_NOT_OK; |
} |
} |
|
|
|
|
#else |
#else |
(void) wait(&status); |
(void) wait(&status); |
#endif |
#endif |
#ifndef POSIX_SIGNALS |
|
(void) signal(SIGCHLD, reapchild); |
|
#endif /* POSIX_SIGNALS */ |
|
errno = serrno; |
errno = serrno; |
} |
} |
|
|