version 1.1.1.1, 2012/02/21 16:23:02
|
version 1.1.1.6, 2014/06/15 16:12:54
|
Line 1
|
Line 1
|
/* |
/* |
* Copyright (c) 1994-1996, 1998-2011 Todd C. Miller <Todd.Miller@courtesan.com> | * Copyright (c) 1994-1996, 1998-2013 Todd C. Miller <Todd.Miller@courtesan.com> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
Line 25
|
Line 25
|
#include <config.h> |
#include <config.h> |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/param.h> |
|
#include <sys/stat.h> |
#include <sys/stat.h> |
#include <sys/ioctl.h> |
#include <sys/ioctl.h> |
#include <sys/wait.h> |
#include <sys/wait.h> |
Line 47
|
Line 46
|
#ifdef HAVE_UNISTD_H |
#ifdef HAVE_UNISTD_H |
# include <unistd.h> |
# include <unistd.h> |
#endif /* HAVE_UNISTD_H */ |
#endif /* HAVE_UNISTD_H */ |
#ifdef HAVE_SETLOCALE |
|
# include <locale.h> |
|
#endif /* HAVE_SETLOCALE */ |
|
#ifdef HAVE_NL_LANGINFO |
#ifdef HAVE_NL_LANGINFO |
# include <langinfo.h> |
# include <langinfo.h> |
#endif /* HAVE_NL_LANGINFO */ |
#endif /* HAVE_NL_LANGINFO */ |
Line 60
|
Line 56
|
#include <ctype.h> |
#include <ctype.h> |
#include <errno.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <fcntl.h> |
#include <setjmp.h> |
|
|
|
#include "sudoers.h" |
#include "sudoers.h" |
|
|
|
/* Special message for log_warning() so we know to use ngettext() */ |
|
#define INCORRECT_PASSWORD_ATTEMPT ((char *)0x01) |
|
|
static void do_syslog(int, char *); |
static void do_syslog(int, char *); |
static void do_logfile(char *); |
static void do_logfile(char *); |
static void send_mail(const char *fmt, ...); |
static void send_mail(const char *fmt, ...); |
Line 71 static int should_mail(int);
|
Line 69 static int should_mail(int);
|
static void mysyslog(int, const char *, ...); |
static void mysyslog(int, const char *, ...); |
static char *new_logline(const char *, int); |
static char *new_logline(const char *, int); |
|
|
extern sigjmp_buf error_jmp; | extern char **NewArgv; /* XXX - for auditing */ |
|
|
#define MAXSYSLOGTRIES 16 /* num of retries for broken syslogs */ |
#define MAXSYSLOGTRIES 16 /* num of retries for broken syslogs */ |
|
|
Line 91 mysyslog(int pri, const char *fmt, ...)
|
Line 89 mysyslog(int pri, const char *fmt, ...)
|
#endif |
#endif |
char buf[MAXSYSLOGLEN+1]; |
char buf[MAXSYSLOGLEN+1]; |
va_list ap; |
va_list ap; |
|
debug_decl(mysyslog, SUDO_DEBUG_LOGGING) |
|
|
va_start(ap, fmt); |
va_start(ap, fmt); |
#ifdef LOG_NFACILITIES |
#ifdef LOG_NFACILITIES |
Line 113 mysyslog(int pri, const char *fmt, ...)
|
Line 112 mysyslog(int pri, const char *fmt, ...)
|
#endif /* BROKEN_SYSLOG */ |
#endif /* BROKEN_SYSLOG */ |
va_end(ap); |
va_end(ap); |
closelog(); |
closelog(); |
|
debug_return; |
} |
} |
|
|
#define FMT_FIRST "%8s : %s" |
|
#define FMT_CONTD "%8s : (command continued) %s" |
|
|
|
/* |
/* |
* Log a message to syslog, pre-pending the username and splitting the |
* Log a message to syslog, pre-pending the username and splitting the |
* message into parts if it is longer than MAXSYSLOGLEN. |
* message into parts if it is longer than MAXSYSLOGLEN. |
Line 128 do_syslog(int pri, char *msg)
|
Line 125 do_syslog(int pri, char *msg)
|
size_t len, maxlen; |
size_t len, maxlen; |
char *p, *tmp, save; |
char *p, *tmp, save; |
const char *fmt; |
const char *fmt; |
|
int oldlocale; |
|
debug_decl(do_syslog, SUDO_DEBUG_LOGGING) |
|
|
#ifdef HAVE_SETLOCALE | sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); |
const char *old_locale = estrdup(setlocale(LC_ALL, NULL)); | |
if (!setlocale(LC_ALL, def_sudoers_locale)) | |
setlocale(LC_ALL, "C"); | |
#endif /* HAVE_SETLOCALE */ | |
|
|
/* |
/* |
* Log the full line, breaking into multiple syslog(3) calls if necessary |
* Log the full line, breaking into multiple syslog(3) calls if necessary |
*/ |
*/ |
fmt = _(FMT_FIRST); | fmt = _("%8s : %s"); |
maxlen = MAXSYSLOGLEN - (strlen(fmt) - 5 + strlen(user_name)); |
maxlen = MAXSYSLOGLEN - (strlen(fmt) - 5 + strlen(user_name)); |
for (p = msg; *p != '\0'; ) { |
for (p = msg; *p != '\0'; ) { |
len = strlen(p); |
len = strlen(p); |
Line 166 do_syslog(int pri, char *msg)
|
Line 161 do_syslog(int pri, char *msg)
|
mysyslog(pri, fmt, user_name, p); |
mysyslog(pri, fmt, user_name, p); |
p += len; |
p += len; |
} |
} |
fmt = _(FMT_CONTD); | fmt = _("%8s : (command continued) %s"); |
maxlen = MAXSYSLOGLEN - (strlen(fmt) - 5 + strlen(user_name)); |
maxlen = MAXSYSLOGLEN - (strlen(fmt) - 5 + strlen(user_name)); |
} |
} |
|
|
#ifdef HAVE_SETLOCALE | sudoers_setlocale(oldlocale, NULL); |
setlocale(LC_ALL, old_locale); | |
efree((void *)old_locale); | debug_return; |
#endif /* HAVE_SETLOCALE */ | |
} |
} |
|
|
static void |
static void |
Line 182 do_logfile(char *msg)
|
Line 176 do_logfile(char *msg)
|
char *full_line; |
char *full_line; |
size_t len; |
size_t len; |
mode_t oldmask; |
mode_t oldmask; |
time_t now; | int oldlocale; |
FILE *fp; |
FILE *fp; |
|
debug_decl(do_logfile, SUDO_DEBUG_LOGGING) |
|
|
|
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); |
|
|
oldmask = umask(077); |
oldmask = umask(077); |
fp = fopen(def_logfile, "a"); |
fp = fopen(def_logfile, "a"); |
(void) umask(oldmask); |
(void) umask(oldmask); |
Line 195 do_logfile(char *msg)
|
Line 192 do_logfile(char *msg)
|
send_mail(_("unable to lock log file: %s: %s"), |
send_mail(_("unable to lock log file: %s: %s"), |
def_logfile, strerror(errno)); |
def_logfile, strerror(errno)); |
} else { |
} else { |
#ifdef HAVE_SETLOCALE | const char *timestr = get_timestr(time(NULL), def_log_year); |
const char *old_locale = estrdup(setlocale(LC_ALL, NULL)); | if (timestr == NULL) |
if (!setlocale(LC_ALL, def_sudoers_locale)) | timestr = "invalid date"; |
setlocale(LC_ALL, "C"); | if ((size_t)def_loglinelen < sizeof(LOG_INDENT)) { |
#endif /* HAVE_SETLOCALE */ | |
| |
now = time(NULL); | |
if (def_loglinelen < sizeof(LOG_INDENT)) { | |
/* Don't pretty-print long log file lines (hard to grep) */ |
/* Don't pretty-print long log file lines (hard to grep) */ |
if (def_log_host) | if (def_log_host) { |
(void) fprintf(fp, "%s : %s : HOST=%s : %s\n", |
(void) fprintf(fp, "%s : %s : HOST=%s : %s\n", |
get_timestr(now, def_log_year), user_name, user_shost, msg); | timestr, user_name, user_srunhost, msg); |
else | } else { |
(void) fprintf(fp, "%s : %s : %s\n", | (void) fprintf(fp, "%s : %s : %s\n", timestr, user_name, msg); |
get_timestr(now, def_log_year), user_name, msg); | } |
} else { |
} else { |
if (def_log_host) | if (def_log_host) { |
len = easprintf(&full_line, "%s : %s : HOST=%s : %s", |
len = easprintf(&full_line, "%s : %s : HOST=%s : %s", |
get_timestr(now, def_log_year), user_name, user_shost, msg); | timestr, user_name, user_srunhost, msg); |
else | } else { |
len = easprintf(&full_line, "%s : %s : %s", |
len = easprintf(&full_line, "%s : %s : %s", |
get_timestr(now, def_log_year), user_name, msg); | timestr, user_name, msg); |
| } |
|
|
/* |
/* |
* Print out full_line with word wrap around def_loglinelen chars. |
* Print out full_line with word wrap around def_loglinelen chars. |
Line 227 do_logfile(char *msg)
|
Line 221 do_logfile(char *msg)
|
(void) fflush(fp); |
(void) fflush(fp); |
(void) lock_file(fileno(fp), SUDO_UNLOCK); |
(void) lock_file(fileno(fp), SUDO_UNLOCK); |
(void) fclose(fp); |
(void) fclose(fp); |
|
|
#ifdef HAVE_SETLOCALE |
|
setlocale(LC_ALL, old_locale); |
|
efree((void *)old_locale); |
|
#endif /* HAVE_SETLOCALE */ |
|
} |
} |
|
sudoers_setlocale(oldlocale, NULL); |
|
|
|
debug_return; |
} |
} |
|
|
/* |
/* |
* Log and mail the denial message, optionally informing the user. | * Log, audit and mail the denial message, optionally informing the user. |
*/ |
*/ |
void |
void |
log_denial(int status, int inform_user) | log_denial(int status, bool inform_user) |
{ |
{ |
char *message; | const char *message; |
char *logline; |
char *logline; |
|
int oldlocale; |
|
debug_decl(log_denial, SUDO_DEBUG_LOGGING) |
|
|
|
/* Handle auditing first (audit_failure() handles the locale itself). */ |
|
if (ISSET(status, FLAG_NO_USER | FLAG_NO_HOST)) |
|
audit_failure(NewArgv, N_("No user or host")); |
|
else |
|
audit_failure(NewArgv, N_("validation failure")); |
|
|
|
/* Log and mail messages should be in the sudoers locale. */ |
|
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); |
|
|
/* Set error message. */ |
/* Set error message. */ |
if (ISSET(status, FLAG_NO_USER)) |
if (ISSET(status, FLAG_NO_USER)) |
message = _("user NOT in sudoers"); |
message = _("user NOT in sudoers"); |
Line 254 log_denial(int status, int inform_user)
|
Line 257 log_denial(int status, int inform_user)
|
|
|
logline = new_logline(message, 0); |
logline = new_logline(message, 0); |
|
|
|
/* Become root if we are not already. */ |
|
set_perms(PERM_ROOT|PERM_NOEXIT); |
|
|
if (should_mail(status)) |
if (should_mail(status)) |
send_mail("%s", logline); /* send mail based on status */ |
send_mail("%s", logline); /* send mail based on status */ |
|
|
/* Inform the user if they failed to authenticate. */ | /* |
| * Log via syslog and/or a file. |
| */ |
| if (def_syslog) |
| do_syslog(def_syslog_badpri, logline); |
| if (def_logfile) |
| do_logfile(logline); |
| |
| restore_perms(); |
| |
| efree(logline); |
| |
| /* Restore locale. */ |
| sudoers_setlocale(oldlocale, NULL); |
| |
| /* Inform the user if they failed to authenticate (in their locale). */ |
if (inform_user) { |
if (inform_user) { |
|
sudoers_setlocale(SUDOERS_LOCALE_USER, &oldlocale); |
|
|
if (ISSET(status, FLAG_NO_USER)) { |
if (ISSET(status, FLAG_NO_USER)) { |
sudo_printf(SUDO_CONV_ERROR_MSG, _("%s is not in the sudoers " |
sudo_printf(SUDO_CONV_ERROR_MSG, _("%s is not in the sudoers " |
"file. This incident will be reported.\n"), user_name); |
"file. This incident will be reported.\n"), user_name); |
} else if (ISSET(status, FLAG_NO_HOST)) { |
} else if (ISSET(status, FLAG_NO_HOST)) { |
sudo_printf(SUDO_CONV_ERROR_MSG, _("%s is not allowed to run sudo " |
sudo_printf(SUDO_CONV_ERROR_MSG, _("%s is not allowed to run sudo " |
"on %s. This incident will be reported.\n"), |
"on %s. This incident will be reported.\n"), |
user_name, user_shost); | user_name, user_srunhost); |
} else if (ISSET(status, FLAG_NO_CHECK)) { |
} else if (ISSET(status, FLAG_NO_CHECK)) { |
sudo_printf(SUDO_CONV_ERROR_MSG, _("Sorry, user %s may not run " |
sudo_printf(SUDO_CONV_ERROR_MSG, _("Sorry, user %s may not run " |
"sudo on %s.\n"), user_name, user_shost); | "sudo on %s.\n"), user_name, user_srunhost); |
} else { |
} else { |
sudo_printf(SUDO_CONV_ERROR_MSG, _("Sorry, user %s is not allowed " |
sudo_printf(SUDO_CONV_ERROR_MSG, _("Sorry, user %s is not allowed " |
"to execute '%s%s%s' as %s%s%s on %s.\n"), |
"to execute '%s%s%s' as %s%s%s on %s.\n"), |
Line 278 log_denial(int status, int inform_user)
|
Line 301 log_denial(int status, int inform_user)
|
runas_pw->pw_name : user_name, runas_gr ? ":" : "", |
runas_pw->pw_name : user_name, runas_gr ? ":" : "", |
runas_gr ? runas_gr->gr_name : "", user_host); |
runas_gr ? runas_gr->gr_name : "", user_host); |
} |
} |
|
sudoers_setlocale(oldlocale, NULL); |
} |
} |
|
debug_return; |
|
} |
|
|
|
/* |
|
* Log and audit that user was not allowed to run the command. |
|
*/ |
|
void |
|
log_failure(int status, int flags) |
|
{ |
|
bool inform_user = true; |
|
debug_decl(log_failure, SUDO_DEBUG_LOGGING) |
|
|
|
/* The user doesn't always get to see the log message (path info). */ |
|
if (!ISSET(status, FLAG_NO_USER | FLAG_NO_HOST) && def_path_info && |
|
(flags == NOT_FOUND_DOT || flags == NOT_FOUND)) |
|
inform_user = false; |
|
log_denial(status, inform_user); |
|
|
|
if (!inform_user) { |
|
/* |
|
* We'd like to not leak path info at all here, but that can |
|
* *really* confuse the users. To really close the leak we'd |
|
* have to say "not allowed to run foo" even when the problem |
|
* is just "no foo in path" since the user can trivially set |
|
* their path to just contain a single dir. |
|
*/ |
|
if (flags == NOT_FOUND) |
|
warningx(U_("%s: command not found"), user_cmnd); |
|
else if (flags == NOT_FOUND_DOT) |
|
warningx(U_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd); |
|
} |
|
|
|
debug_return; |
|
} |
|
|
|
/* |
|
* Log and audit that user was not able to authenticate themselves. |
|
*/ |
|
void |
|
log_auth_failure(int status, unsigned int tries) |
|
{ |
|
int flags = NO_MAIL; |
|
debug_decl(log_auth_failure, SUDO_DEBUG_LOGGING) |
|
|
|
/* Handle auditing first. */ |
|
audit_failure(NewArgv, N_("authentication failure")); |
|
|
/* |
/* |
* Log via syslog and/or a file. | * Do we need to send mail? |
| * We want to avoid sending multiple messages for the same command |
| * so if we are going to send an email about the denial, that takes |
| * precedence. |
*/ |
*/ |
if (def_syslog) | if (ISSET(status, VALIDATE_OK)) { |
do_syslog(def_syslog_badpri, logline); | /* Command allowed, auth failed; do we need to send mail? */ |
if (def_logfile) | if (def_mail_badpass || def_mail_always) |
do_logfile(logline); | flags = 0; |
| } else { |
| /* Command denied, auth failed; make sure we don't send mail twice. */ |
| if (def_mail_badpass && !should_mail(status)) |
| flags = 0; |
| /* Don't log the bad password message, we'll log a denial instead. */ |
| flags |= NO_LOG; |
| } |
|
|
efree(logline); | /* |
| * If sudoers denied the command we'll log that separately. |
| */ |
| if (ISSET(status, FLAG_BAD_PASSWORD)) |
| log_warning(flags, INCORRECT_PASSWORD_ATTEMPT, tries); |
| else if (ISSET(status, FLAG_NON_INTERACTIVE)) |
| log_warning(flags, N_("a password is required")); |
| |
| debug_return; |
} |
} |
|
|
/* |
/* |
Line 298 void
|
Line 386 void
|
log_allowed(int status) |
log_allowed(int status) |
{ |
{ |
char *logline; |
char *logline; |
|
int oldlocale; |
|
debug_decl(log_allowed, SUDO_DEBUG_LOGGING) |
|
|
|
/* Log and mail messages should be in the sudoers locale. */ |
|
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); |
|
|
logline = new_logline(NULL, 0); |
logline = new_logline(NULL, 0); |
|
|
|
/* Become root if we are not already. */ |
|
set_perms(PERM_ROOT|PERM_NOEXIT); |
|
|
if (should_mail(status)) |
if (should_mail(status)) |
send_mail("%s", logline); /* send mail based on status */ |
send_mail("%s", logline); /* send mail based on status */ |
|
|
Line 312 log_allowed(int status)
|
Line 408 log_allowed(int status)
|
if (def_logfile) |
if (def_logfile) |
do_logfile(logline); |
do_logfile(logline); |
|
|
|
restore_perms(); |
|
|
efree(logline); |
efree(logline); |
|
|
|
sudoers_setlocale(oldlocale, NULL); |
|
|
|
debug_return; |
} |
} |
|
|
void | /* |
log_error(int flags, const char *fmt, ...) | * Perform logging for log_warning()/log_fatal() |
| */ |
| static void |
| vlog_warning(int flags, const char *fmt, va_list ap) |
{ |
{ |
int serrno = errno; | int oldlocale, serrno = errno; |
char *message; | char *logline, *message; |
char *logline; | va_list ap2; |
va_list ap; | debug_decl(vlog_error, SUDO_DEBUG_LOGGING) |
|
|
/* Expand printf-style format + args. */ | /* Need extra copy of ap for warning() below. */ |
va_start(ap, fmt); | if (!ISSET(flags, NO_STDERR)) |
evasprintf(&message, fmt, ap); | va_copy(ap2, ap); |
va_end(ap); | |
|
|
/* Become root if we are not already to avoid user interference */ | /* Log messages should be in the sudoers locale. */ |
set_perms(PERM_ROOT|PERM_NOEXIT); | sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); |
|
|
if (ISSET(flags, MSG_ONLY)) | /* Expand printf-style format + args (with a special case). */ |
logline = message; | if (fmt == INCORRECT_PASSWORD_ATTEMPT) { |
else | unsigned int tries = va_arg(ap, unsigned int); |
logline = new_logline(message, ISSET(flags, USE_ERRNO) ? serrno : 0); | easprintf(&message, ngettext("%u incorrect password attempt", |
| "%u incorrect password attempts", tries), tries); |
| } else { |
| evasprintf(&message, _(fmt), ap); |
| } |
|
|
/* | /* Log to debug file. */ |
* Tell the user. | if (USE_ERRNO) { |
*/ | sudo_debug_printf2(NULL, NULL, 0, |
if (!ISSET(flags, NO_STDERR)) { | SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|sudo_debug_subsys, "%s", message); |
if (ISSET(flags, USE_ERRNO)) | } else { |
warning("%s", message); | sudo_debug_printf2(NULL, NULL, 0, |
else | SUDO_DEBUG_WARN|sudo_debug_subsys, "%s", message); |
warningx("%s", message); | |
} |
} |
if (logline != message) | |
| if (ISSET(flags, MSG_ONLY)) { |
| logline = message; |
| } else { |
| logline = new_logline(message, ISSET(flags, USE_ERRNO) ? serrno : 0); |
efree(message); |
efree(message); |
|
} |
|
|
|
/* Become root if we are not already. */ |
|
set_perms(PERM_ROOT|PERM_NOEXIT); |
|
|
/* |
/* |
* Send a copy of the error via mail. |
* Send a copy of the error via mail. |
*/ |
*/ |
Line 357 log_error(int flags, const char *fmt, ...)
|
Line 472 log_error(int flags, const char *fmt, ...)
|
/* |
/* |
* Log to syslog and/or a file. |
* Log to syslog and/or a file. |
*/ |
*/ |
if (def_syslog) | if (!ISSET(flags, NO_LOG)) { |
do_syslog(def_syslog_badpri, logline); | if (def_syslog) |
if (def_logfile) | do_syslog(def_syslog_badpri, logline); |
do_logfile(logline); | if (def_logfile) |
| do_logfile(logline); |
| } |
|
|
|
restore_perms(); |
|
|
efree(logline); |
efree(logline); |
|
|
restore_perms(); | sudoers_setlocale(oldlocale, NULL); |
|
|
if (!ISSET(flags, NO_EXIT)) { | /* |
plugin_cleanup(0); | * Tell the user (in their locale). |
siglongjmp(error_jmp, 1); | */ |
| if (!ISSET(flags, NO_STDERR)) { |
| sudoers_setlocale(SUDOERS_LOCALE_USER, &oldlocale); |
| if (fmt == INCORRECT_PASSWORD_ATTEMPT) { |
| unsigned int tries = va_arg(ap2, unsigned int); |
| warningx_nodebug(ngettext("%u incorrect password attempt", |
| "%u incorrect password attempts", tries), tries); |
| } else { |
| if (ISSET(flags, USE_ERRNO)) |
| vwarning_nodebug(_(fmt), ap2); |
| else |
| vwarningx_nodebug(_(fmt), ap2); |
| } |
| sudoers_setlocale(oldlocale, NULL); |
| va_end(ap2); |
} |
} |
|
|
|
debug_return; |
} |
} |
|
|
|
void |
|
log_warning(int flags, const char *fmt, ...) |
|
{ |
|
va_list ap; |
|
debug_decl(log_error, SUDO_DEBUG_LOGGING) |
|
|
|
/* Log the error. */ |
|
va_start(ap, fmt); |
|
vlog_warning(flags, fmt, ap); |
|
va_end(ap); |
|
|
|
debug_return; |
|
} |
|
|
|
void |
|
log_fatal(int flags, const char *fmt, ...) |
|
{ |
|
va_list ap; |
|
debug_decl(log_error, SUDO_DEBUG_LOGGING) |
|
|
|
/* Log the error. */ |
|
va_start(ap, fmt); |
|
vlog_warning(flags, fmt, ap); |
|
va_end(ap); |
|
|
|
/* Exit the plugin. */ |
|
sudoers_cleanup(); |
|
sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); |
|
fatal_longjmp(1); |
|
} |
|
|
#define MAX_MAILFLAGS 63 |
#define MAX_MAILFLAGS 63 |
|
|
/* |
/* |
Line 382 send_mail(const char *fmt, ...)
|
Line 548 send_mail(const char *fmt, ...)
|
{ |
{ |
FILE *mail; |
FILE *mail; |
char *p; |
char *p; |
|
const char *timestr; |
int fd, pfd[2], status; |
int fd, pfd[2], status; |
pid_t pid, rv; |
pid_t pid, rv; |
sigaction_t sa; |
sigaction_t sa; |
|
struct stat sb; |
va_list ap; |
va_list ap; |
#ifndef NO_ROOT_MAILER |
#ifndef NO_ROOT_MAILER |
static char *root_envp[] = { |
static char *root_envp[] = { |
Line 396 send_mail(const char *fmt, ...)
|
Line 564 send_mail(const char *fmt, ...)
|
NULL |
NULL |
}; |
}; |
#endif /* NO_ROOT_MAILER */ |
#endif /* NO_ROOT_MAILER */ |
|
debug_decl(send_mail, SUDO_DEBUG_LOGGING) |
|
|
/* Just return if mailer is disabled. */ |
/* Just return if mailer is disabled. */ |
if (!def_mailerpath || !def_mailto) |
if (!def_mailerpath || !def_mailto) |
return; | debug_return; |
|
|
|
/* Make sure the mailer exists and is a regular file. */ |
|
if (stat(def_mailerpath, &sb) != 0 || !S_ISREG(sb.st_mode)) |
|
debug_return; |
|
|
/* Fork and return, child will daemonize. */ |
/* Fork and return, child will daemonize. */ |
switch (pid = fork()) { | switch (pid = sudo_debug_fork()) { |
case -1: |
case -1: |
/* Error. */ |
/* Error. */ |
error(1, _("unable to fork")); | fatal(U_("unable to fork")); |
break; |
break; |
case 0: |
case 0: |
/* Child. */ |
/* Child. */ |
Line 413 send_mail(const char *fmt, ...)
|
Line 586 send_mail(const char *fmt, ...)
|
case -1: |
case -1: |
/* Error. */ |
/* Error. */ |
mysyslog(LOG_ERR, _("unable to fork: %m")); |
mysyslog(LOG_ERR, _("unable to fork: %m")); |
|
sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to fork: %s", |
|
strerror(errno)); |
_exit(1); |
_exit(1); |
case 0: |
case 0: |
/* Grandchild continues below. */ |
/* Grandchild continues below. */ |
Line 427 send_mail(const char *fmt, ...)
|
Line 602 send_mail(const char *fmt, ...)
|
do { |
do { |
rv = waitpid(pid, &status, 0); |
rv = waitpid(pid, &status, 0); |
} while (rv == -1 && errno == EINTR); |
} while (rv == -1 && errno == EINTR); |
return; | return; /* not debug */ |
} |
} |
|
|
/* Daemonize - disassociate from session/tty. */ |
/* Daemonize - disassociate from session/tty. */ |
Line 441 send_mail(const char *fmt, ...)
|
Line 616 send_mail(const char *fmt, ...)
|
(void) dup2(fd, STDERR_FILENO); |
(void) dup2(fd, STDERR_FILENO); |
} |
} |
|
|
#ifdef HAVE_SETLOCALE | sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, NULL); |
if (!setlocale(LC_ALL, def_sudoers_locale)) { | |
setlocale(LC_ALL, "C"); | |
efree(def_sudoers_locale); | |
def_sudoers_locale = estrdup("C"); | |
} | |
#endif /* HAVE_SETLOCALE */ | |
|
|
/* Close password, group and other fds so we don't leak. */ |
/* Close password, group and other fds so we don't leak. */ |
sudo_endpwent(); |
sudo_endpwent(); |
Line 455 send_mail(const char *fmt, ...)
|
Line 624 send_mail(const char *fmt, ...)
|
closefrom(STDERR_FILENO + 1); |
closefrom(STDERR_FILENO + 1); |
|
|
/* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */ |
/* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */ |
zero_bytes(&sa, sizeof(sa)); | memset(&sa, 0, sizeof(sa)); |
sigemptyset(&sa.sa_mask); |
sigemptyset(&sa.sa_mask); |
sa.sa_flags = SA_INTERRUPT; |
sa.sa_flags = SA_INTERRUPT; |
sa.sa_handler = SIG_IGN; |
sa.sa_handler = SIG_IGN; |
Line 463 send_mail(const char *fmt, ...)
|
Line 632 send_mail(const char *fmt, ...)
|
|
|
if (pipe(pfd) == -1) { |
if (pipe(pfd) == -1) { |
mysyslog(LOG_ERR, _("unable to open pipe: %m")); |
mysyslog(LOG_ERR, _("unable to open pipe: %m")); |
|
sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to open pipe: %s", |
|
strerror(errno)); |
|
sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); |
_exit(1); |
_exit(1); |
} |
} |
|
|
switch (pid = fork()) { | switch (pid = sudo_debug_fork()) { |
case -1: |
case -1: |
/* Error. */ |
/* Error. */ |
mysyslog(LOG_ERR, _("unable to fork: %m")); |
mysyslog(LOG_ERR, _("unable to fork: %m")); |
|
sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to fork: %s", |
|
strerror(errno)); |
|
sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); |
_exit(1); |
_exit(1); |
break; |
break; |
case 0: |
case 0: |
{ |
{ |
char *argv[MAX_MAILFLAGS + 1]; |
char *argv[MAX_MAILFLAGS + 1]; |
char *mpath, *mflags; | char *mflags, *mpath = def_mailerpath; |
int i; |
int i; |
|
|
/* Child, set stdin to output side of the pipe */ |
/* Child, set stdin to output side of the pipe */ |
if (pfd[0] != STDIN_FILENO) { |
if (pfd[0] != STDIN_FILENO) { |
if (dup2(pfd[0], STDIN_FILENO) == -1) { |
if (dup2(pfd[0], STDIN_FILENO) == -1) { |
mysyslog(LOG_ERR, _("unable to dup stdin: %m")); |
mysyslog(LOG_ERR, _("unable to dup stdin: %m")); |
|
sudo_debug_printf(SUDO_DEBUG_ERROR, |
|
"unable to dup stdin: %s", strerror(errno)); |
_exit(127); |
_exit(127); |
} |
} |
(void) close(pfd[0]); |
(void) close(pfd[0]); |
Line 490 send_mail(const char *fmt, ...)
|
Line 667 send_mail(const char *fmt, ...)
|
|
|
/* Build up an argv based on the mailer path and flags */ |
/* Build up an argv based on the mailer path and flags */ |
mflags = estrdup(def_mailerflags); |
mflags = estrdup(def_mailerflags); |
mpath = estrdup(def_mailerpath); | if ((argv[0] = strrchr(mpath, '/'))) |
if ((argv[0] = strrchr(mpath, ' '))) | |
argv[0]++; |
argv[0]++; |
else |
else |
argv[0] = mpath; |
argv[0] = mpath; |
Line 516 send_mail(const char *fmt, ...)
|
Line 692 send_mail(const char *fmt, ...)
|
execv(mpath, argv); |
execv(mpath, argv); |
#endif /* NO_ROOT_MAILER */ |
#endif /* NO_ROOT_MAILER */ |
mysyslog(LOG_ERR, _("unable to execute %s: %m"), mpath); |
mysyslog(LOG_ERR, _("unable to execute %s: %m"), mpath); |
|
sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to execute %s: %s", |
|
mpath, strerror(errno)); |
_exit(127); |
_exit(127); |
} |
} |
break; |
break; |
Line 527 send_mail(const char *fmt, ...)
|
Line 705 send_mail(const char *fmt, ...)
|
/* Pipes are all setup, send message. */ |
/* Pipes are all setup, send message. */ |
(void) fprintf(mail, "To: %s\nFrom: %s\nAuto-Submitted: %s\nSubject: ", |
(void) fprintf(mail, "To: %s\nFrom: %s\nAuto-Submitted: %s\nSubject: ", |
def_mailto, def_mailfrom ? def_mailfrom : user_name, "auto-generated"); |
def_mailto, def_mailfrom ? def_mailfrom : user_name, "auto-generated"); |
for (p = def_mailsub; *p; p++) { | for (p = _(def_mailsub); *p; p++) { |
/* Expand escapes in the subject */ |
/* Expand escapes in the subject */ |
if (*p == '%' && *(p+1) != '%') { |
if (*p == '%' && *(p+1) != '%') { |
switch (*(++p)) { |
switch (*(++p)) { |
Line 550 send_mail(const char *fmt, ...)
|
Line 728 send_mail(const char *fmt, ...)
|
(void) fprintf(mail, "\nContent-Type: text/plain; charset=\"%s\"\nContent-Transfer-Encoding: 8bit", nl_langinfo(CODESET)); |
(void) fprintf(mail, "\nContent-Type: text/plain; charset=\"%s\"\nContent-Transfer-Encoding: 8bit", nl_langinfo(CODESET)); |
#endif /* HAVE_NL_LANGINFO */ |
#endif /* HAVE_NL_LANGINFO */ |
|
|
(void) fprintf(mail, "\n\n%s : %s : %s : ", user_host, | if ((timestr = get_timestr(time(NULL), def_log_year)) == NULL) |
get_timestr(time(NULL), def_log_year), user_name); | timestr = "invalid date"; |
| (void) fprintf(mail, "\n\n%s : %s : %s : ", user_host, timestr, user_name); |
va_start(ap, fmt); |
va_start(ap, fmt); |
(void) vfprintf(mail, fmt, ap); |
(void) vfprintf(mail, fmt, ap); |
va_end(ap); |
va_end(ap); |
Line 561 send_mail(const char *fmt, ...)
|
Line 740 send_mail(const char *fmt, ...)
|
do { |
do { |
rv = waitpid(pid, &status, 0); |
rv = waitpid(pid, &status, 0); |
} while (rv == -1 && errno == EINTR); |
} while (rv == -1 && errno == EINTR); |
|
sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); |
_exit(0); |
_exit(0); |
} |
} |
|
|
Line 570 send_mail(const char *fmt, ...)
|
Line 750 send_mail(const char *fmt, ...)
|
static int |
static int |
should_mail(int status) |
should_mail(int status) |
{ |
{ |
|
debug_decl(should_mail, SUDO_DEBUG_LOGGING) |
|
|
return def_mail_always || ISSET(status, VALIDATE_ERROR) || | debug_return_bool(def_mail_always || ISSET(status, VALIDATE_ERROR) || |
(def_mail_no_user && ISSET(status, FLAG_NO_USER)) || |
(def_mail_no_user && ISSET(status, FLAG_NO_USER)) || |
(def_mail_no_host && ISSET(status, FLAG_NO_HOST)) || |
(def_mail_no_host && ISSET(status, FLAG_NO_HOST)) || |
(def_mail_no_perms && !ISSET(status, VALIDATE_OK)); | (def_mail_no_perms && !ISSET(status, VALIDATE_OK))); |
} |
} |
|
|
#define LL_TTY_STR "TTY=" |
#define LL_TTY_STR "TTY=" |
Line 599 should_mail(int status)
|
Line 780 should_mail(int status)
|
static char * |
static char * |
new_logline(const char *message, int serrno) |
new_logline(const char *message, int serrno) |
{ |
{ |
|
char *line, *errstr = NULL, *evstr = NULL; |
|
#ifndef SUDOERS_NO_SEQ |
|
char sessid[7]; |
|
#endif |
|
const char *tsid = NULL; |
size_t len = 0; |
size_t len = 0; |
char *errstr = NULL; | debug_decl(new_logline, SUDO_DEBUG_LOGGING) |
char *evstr = NULL; | |
char *line, sessid[7], *tsid = NULL; | |
|
|
|
#ifndef SUDOERS_NO_SEQ |
/* A TSID may be a sudoers-style session ID or a free-form string. */ |
/* A TSID may be a sudoers-style session ID or a free-form string. */ |
if (sudo_user.iolog_file != NULL) { |
if (sudo_user.iolog_file != NULL) { |
if (IS_SESSID(sudo_user.iolog_file)) { |
if (IS_SESSID(sudo_user.iolog_file)) { |
Line 619 new_logline(const char *message, int serrno)
|
Line 804 new_logline(const char *message, int serrno)
|
tsid = sudo_user.iolog_file; |
tsid = sudo_user.iolog_file; |
} |
} |
} |
} |
|
#endif |
|
|
/* |
/* |
* Compute line length |
* Compute line length |
Line 723 new_logline(const char *message, int serrno)
|
Line 909 new_logline(const char *message, int serrno)
|
} |
} |
} |
} |
|
|
return line; | debug_return_str(line); |
toobig: |
toobig: |
errorx(1, _("internal error: insufficient space for log line")); | fatalx(U_("internal error: insufficient space for log line")); |
} |
} |