version 1.1.1.1, 2012/02/21 16:23:02
|
version 1.1.1.3, 2012/10/09 09:29:52
|
Line 73 static char *new_logline(const char *, int);
|
Line 73 static char *new_logline(const char *, int);
|
|
|
extern sigjmp_buf error_jmp; |
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 93 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 116 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_FIRST "%8s : %s" |
Line 128 do_syslog(int pri, char *msg)
|
Line 132 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; |
|
|
#ifdef HAVE_SETLOCALE |
#ifdef HAVE_SETLOCALE |
const char *old_locale = estrdup(setlocale(LC_ALL, NULL)); |
const char *old_locale = estrdup(setlocale(LC_ALL, NULL)); |
|
#endif |
|
debug_decl(do_syslog, SUDO_DEBUG_LOGGING) |
|
|
|
#ifdef HAVE_SETLOCALE |
if (!setlocale(LC_ALL, def_sudoers_locale)) |
if (!setlocale(LC_ALL, def_sudoers_locale)) |
setlocale(LC_ALL, "C"); |
setlocale(LC_ALL, "C"); |
#endif /* HAVE_SETLOCALE */ |
#endif /* HAVE_SETLOCALE */ |
Line 174 do_syslog(int pri, char *msg)
|
Line 181 do_syslog(int pri, char *msg)
|
setlocale(LC_ALL, old_locale); |
setlocale(LC_ALL, old_locale); |
efree((void *)old_locale); |
efree((void *)old_locale); |
#endif /* HAVE_SETLOCALE */ |
#endif /* HAVE_SETLOCALE */ |
|
|
|
debug_return; |
} |
} |
|
|
static void |
static void |
Line 184 do_logfile(char *msg)
|
Line 193 do_logfile(char *msg)
|
mode_t oldmask; |
mode_t oldmask; |
time_t now; |
time_t now; |
FILE *fp; |
FILE *fp; |
|
debug_decl(do_logfile, SUDO_DEBUG_LOGGING) |
|
|
oldmask = umask(077); |
oldmask = umask(077); |
fp = fopen(def_logfile, "a"); |
fp = fopen(def_logfile, "a"); |
Line 233 do_logfile(char *msg)
|
Line 243 do_logfile(char *msg)
|
efree((void *)old_locale); |
efree((void *)old_locale); |
#endif /* HAVE_SETLOCALE */ |
#endif /* HAVE_SETLOCALE */ |
} |
} |
|
debug_return; |
} |
} |
|
|
/* |
/* |
* Log and mail the denial message, optionally informing the user. |
* Log and mail the denial message, optionally informing the user. |
*/ |
*/ |
void | static void |
log_denial(int status, int inform_user) | log_denial(int status, bool inform_user) |
{ |
{ |
char *message; | char *logline, *message; |
char *logline; | debug_decl(log_denial, SUDO_DEBUG_LOGGING) |
|
|
/* Set error message. */ |
/* Set error message. */ |
if (ISSET(status, FLAG_NO_USER)) |
if (ISSET(status, FLAG_NO_USER)) |
Line 289 log_denial(int status, int inform_user)
|
Line 300 log_denial(int status, int inform_user)
|
do_logfile(logline); |
do_logfile(logline); |
|
|
efree(logline); |
efree(logline); |
|
debug_return; |
} |
} |
|
|
/* |
/* |
|
* Log and audit that user was not allowed to run the command. |
|
*/ |
|
void |
|
log_failure(int status, int flags) |
|
{ |
|
debug_decl(log_failure, SUDO_DEBUG_LOGGING) |
|
bool inform_user = true; |
|
|
|
/* Handle auditing first. */ |
|
if (ISSET(status, FLAG_NO_USER | FLAG_NO_HOST)) |
|
audit_failure(NewArgv, _("No user or host")); |
|
else |
|
audit_failure(NewArgv, _("validation failure")); |
|
|
|
/* 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(_("%s: command not found"), user_cmnd); |
|
else if (flags == NOT_FOUND_DOT) |
|
warningx(_("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, int tries) |
|
{ |
|
int flags = NO_MAIL; |
|
debug_decl(log_auth_failure, SUDO_DEBUG_LOGGING) |
|
|
|
/* Handle auditing first. */ |
|
audit_failure(NewArgv, _("authentication failure")); |
|
|
|
/* |
|
* 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 (ISSET(status, VALIDATE_OK)) { |
|
/* Command allowed, auth failed; do we need to send mail? */ |
|
if (def_mail_badpass || def_mail_always) |
|
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; |
|
} |
|
|
|
/* |
|
* If sudoers denied the command we'll log that separately. |
|
*/ |
|
if (ISSET(status, FLAG_BAD_PASSWORD)) { |
|
log_error(flags, ngettext("%d incorrect password attempt", |
|
"%d incorrect password attempts", tries), tries); |
|
} else if (ISSET(status, FLAG_NON_INTERACTIVE)) { |
|
log_error(flags, _("a password is required")); |
|
} |
|
|
|
debug_return; |
|
} |
|
|
|
/* |
* Log and potentially mail the allowed command. |
* Log and potentially mail the allowed command. |
*/ |
*/ |
void |
void |
log_allowed(int status) |
log_allowed(int status) |
{ |
{ |
char *logline; |
char *logline; |
|
debug_decl(log_allowed, SUDO_DEBUG_LOGGING) |
|
|
logline = new_logline(NULL, 0); |
logline = new_logline(NULL, 0); |
|
|
Line 313 log_allowed(int status)
|
Line 407 log_allowed(int status)
|
do_logfile(logline); |
do_logfile(logline); |
|
|
efree(logline); |
efree(logline); |
|
debug_return; |
} |
} |
|
|
void | /* |
log_error(int flags, const char *fmt, ...) | * Perform logging for log_error()/log_fatal() |
| */ |
| static void |
| vlog_error(int flags, const char *fmt, va_list ap) |
{ |
{ |
int serrno = errno; |
int serrno = errno; |
char *message; | char *logline, *message; |
char *logline; | debug_decl(vlog_error, SUDO_DEBUG_LOGGING) |
va_list ap; | |
|
|
/* Expand printf-style format + args. */ |
/* Expand printf-style format + args. */ |
va_start(ap, fmt); |
|
evasprintf(&message, fmt, ap); |
evasprintf(&message, fmt, ap); |
va_end(ap); |
|
|
|
/* Become root if we are not already to avoid user interference */ |
/* Become root if we are not already to avoid user interference */ |
set_perms(PERM_ROOT|PERM_NOEXIT); |
set_perms(PERM_ROOT|PERM_NOEXIT); |
Line 357 log_error(int flags, const char *fmt, ...)
|
Line 452 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); |
| } |
|
|
efree(logline); |
efree(logline); |
|
|
restore_perms(); |
restore_perms(); |
|
|
if (!ISSET(flags, NO_EXIT)) { | debug_return; |
plugin_cleanup(0); | |
siglongjmp(error_jmp, 1); | |
} | |
} |
} |
|
|
|
void |
|
log_error(int flags, const char *fmt, ...) |
|
{ |
|
va_list ap; |
|
debug_decl(log_error, SUDO_DEBUG_LOGGING) |
|
|
|
/* Log the error. */ |
|
va_start(ap, fmt); |
|
vlog_error(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_error(flags, fmt, ap); |
|
va_end(ap); |
|
|
|
/* Exit the plugin. */ |
|
plugin_cleanup(0); |
|
sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); |
|
siglongjmp(error_jmp, 1); |
|
} |
|
|
#define MAX_MAILFLAGS 63 |
#define MAX_MAILFLAGS 63 |
|
|
/* |
/* |
Line 396 send_mail(const char *fmt, ...)
|
Line 521 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; |
|
|
/* 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")); |
error(1, _("unable to fork")); |
Line 413 send_mail(const char *fmt, ...)
|
Line 539 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 555 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 463 send_mail(const char *fmt, ...)
|
Line 591 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: |
Line 482 send_mail(const char *fmt, ...)
|
Line 616 send_mail(const char *fmt, ...)
|
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 516 send_mail(const char *fmt, ...)
|
Line 652 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 561 send_mail(const char *fmt, ...)
|
Line 699 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 709 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 603 new_logline(const char *message, int serrno)
|
Line 743 new_logline(const char *message, int serrno)
|
char *errstr = NULL; |
char *errstr = NULL; |
char *evstr = NULL; |
char *evstr = NULL; |
char *line, sessid[7], *tsid = NULL; |
char *line, sessid[7], *tsid = NULL; |
|
debug_decl(new_logline, SUDO_DEBUG_LOGGING) |
|
|
/* 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) { |
Line 723 new_logline(const char *message, int serrno)
|
Line 864 new_logline(const char *message, int serrno)
|
} |
} |
} |
} |
|
|
return line; | debug_return_str(line); |
toobig: |
toobig: |
errorx(1, _("internal error: insufficient space for log line")); |
errorx(1, _("internal error: insufficient space for log line")); |
} |
} |