From: Todd C. Miller Date: Wed, 17 Aug 2016 13:22:51 +0000 (-0600) Subject: Make the behavior when we cannot write to a log or audit file X-Git-Tag: SUDO_1_8_18^2~69 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ed18d0d5f8d9695a137236bb6b6786e2f19ef5df;p=sudo Make the behavior when we cannot write to a log or audit file configurable. File log failures are ignored by default for consistency with syslog. Audit errors are ignored by default to allow the admin to fix the issue. I/O log file errors are still fatal by default since if I/O logging is activated it is usually to have an audit trail. Bug #751 --- diff --git a/doc/sudoers.cat b/doc/sudoers.cat index 9c6a9cc81..79c792f35 100644 --- a/doc/sudoers.cat +++ b/doc/sudoers.cat @@ -1027,11 +1027,37 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS This flag is _o_f_f by default. + ignore_audit_errors + Allow commands to be run even if ssuuddooeerrss cannot write + to the audit log. If enabled, an audit log write + failure is not treated as a fatal error. If disabled, + a command may only be run after the audit event is + successfully written. This flag is only effective on + systems for which ssuuddooeerrss supports audit logging, + including FreeBSD, Linux, Mac OS X and Solaris. This + flag is _o_n by default. + ignore_dot If set, ssuuddoo will ignore "." or "" (both denoting current directory) in the PATH environment variable; the PATH itself is not modified. This flag is _o_f_f by default. + ignore_iolog_errors + Allow commands to be run even if ssuuddooeerrss cannot write + to the I/O log. If enabled, an I/O log write failure + is not treated as a fatal error. If disabled, the + command will be terminated if the I/O log cannot be + written to. This flag is _o_f_f by default. + + ignore_logfile_errors + Allow commands to be run even if ssuuddooeerrss cannot write + to the log file. If enabled, a log file write failure + is not treated as a fatal error. If disabled, a + command may only be run after the log file entry is + successfully written. This flag only has an effect + when ssuuddooeerrss is configured to use file-based logging + via the _l_o_g_f_i_l_e option. This flag is _o_n by default. + ignore_local_sudoers If set via LDAP, parsing of _/_e_t_c_/_s_u_d_o_e_r_s will be skipped. This is intended for Enterprises that wish to @@ -2543,4 +2569,4 @@ DDIISSCCLLAAIIMMEERR file distributed with ssuuddoo or https://www.sudo.ws/license.html for complete details. -Sudo 1.8.18 August 10, 2016 Sudo 1.8.18 +Sudo 1.8.18 August 17, 2016 Sudo 1.8.18 diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in index ba88c7643..7c780476b 100644 --- a/doc/sudoers.man.in +++ b/doc/sudoers.man.in @@ -21,7 +21,7 @@ .\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" -.TH "SUDOERS" "5" "August 10, 2016" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDOERS" "5" "August 17, 2016" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -2194,6 +2194,20 @@ This flag is by default. .RE .TP 18n +ignore_audit_errors +Allow commands to be run even if +\fBsudoers\fR +cannot write to the audit log. +If enabled, an audit log write failure is not treated as a fatal error. +If disabled, a command may only be run after the audit event is successfully +written. +This flag is only effective on systems for which +\fBsudoers\fR +supports audit logging, including FreeBSD, Linux, Mac OS X and Solaris. +This flag is +\fIon\fR +by default. +.TP 18n ignore_dot If set, \fBsudo\fR @@ -2206,6 +2220,32 @@ This flag is \fI@ignore_dot@\fR by default. .TP 18n +ignore_iolog_errors +Allow commands to be run even if +\fBsudoers\fR +cannot write to the I/O log. +If enabled, an I/O log write failure is not treated as a fatal error. +If disabled, the command will be terminated if the I/O log cannot be written to. +This flag is +\fIoff\fR +by default. +.TP 18n +ignore_logfile_errors +Allow commands to be run even if +\fBsudoers\fR +cannot write to the log file. +If enabled, a log file write failure is not treated as a fatal error. +If disabled, a command may only be run after the log file entry is successfully +written. +This flag only has an effect when +\fBsudoers\fR +is configured to use file-based logging via the +\fIlogfile\fR +option. +This flag is +\fIon\fR +by default. +.TP 18n ignore_local_sudoers If set via LDAP, parsing of \fI@sysconfdir@/sudoers\fR diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in index 33c4813eb..166c64666 100644 --- a/doc/sudoers.mdoc.in +++ b/doc/sudoers.mdoc.in @@ -19,7 +19,7 @@ .\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" -.Dd August 10, 2016 +.Dd August 17, 2016 .Dt SUDOERS @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -2057,6 +2057,19 @@ aliases from DNS. This flag is .Em @fqdn@ by default. +.It ignore_audit_errors +Allow commands to be run even if +.Nm +cannot write to the audit log. +If enabled, an audit log write failure is not treated as a fatal error. +If disabled, a command may only be run after the audit event is successfully +written. +This flag is only effective on systems for which +.Nm +supports audit logging, including FreeBSD, Linux, Mac OS X and Solaris. +This flag is +.Em on +by default. .It ignore_dot If set, .Nm sudo @@ -2068,6 +2081,30 @@ itself is not modified. This flag is .Em @ignore_dot@ by default. +.It ignore_iolog_errors +Allow commands to be run even if +.Nm +cannot write to the I/O log. +If enabled, an I/O log write failure is not treated as a fatal error. +If disabled, the command will be terminated if the I/O log cannot be written to. +This flag is +.Em off +by default. +.It ignore_logfile_errors +Allow commands to be run even if +.Nm +cannot write to the log file. +If enabled, a log file write failure is not treated as a fatal error. +If disabled, a command may only be run after the log file entry is successfully +written. +This flag only has an effect when +.Nm +is configured to use file-based logging via the +.Em logfile +option. +This flag is +.Em on +by default. .It ignore_local_sudoers If set via LDAP, parsing of .Pa @sysconfdir@/sudoers diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c index 6d7178232..7b84efcc9 100644 --- a/plugins/sudoers/def_data.c +++ b/plugins/sudoers/def_data.c @@ -402,6 +402,18 @@ struct sudo_defs_types sudo_defs_table[] = { "netgroup_tuple", T_FLAG, N_("Match netgroups based on the entire tuple: user, host and domain"), NULL, + }, { + "ignore_audit_errors", T_FLAG, + N_("Allow commands to be run even if sudo cannot write to the audit log"), + NULL, + }, { + "ignore_iolog_errors", T_FLAG, + N_("Allow commands to be run even if sudo cannot write to the I/O log"), + NULL, + }, { + "ignore_logfile_errors", T_FLAG, + N_("Allow commands to be run even if sudo cannot write to the log file"), + NULL, }, { NULL, 0, NULL } diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h index 85f43c23a..6f99d3fd5 100644 --- a/plugins/sudoers/def_data.h +++ b/plugins/sudoers/def_data.h @@ -188,6 +188,12 @@ #define I_ALWAYS_QUERY_GROUP_PLUGIN93 #define def_netgroup_tuple (sudo_defs_table[94].sd_un.flag) #define I_NETGROUP_TUPLE 94 +#define def_ignore_audit_errors (sudo_defs_table[95].sd_un.flag) +#define I_IGNORE_AUDIT_ERRORS 95 +#define def_ignore_iolog_errors (sudo_defs_table[96].sd_un.flag) +#define I_IGNORE_IOLOG_ERRORS 96 +#define def_ignore_logfile_errors (sudo_defs_table[97].sd_un.flag) +#define I_IGNORE_LOGFILE_ERRORS 97 enum def_tuple { never, diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in index db76d5342..57f198661 100644 --- a/plugins/sudoers/def_data.in +++ b/plugins/sudoers/def_data.in @@ -298,3 +298,12 @@ always_query_group_plugin netgroup_tuple T_FLAG "Match netgroups based on the entire tuple: user, host and domain" +ignore_audit_errors + T_FLAG + "Allow commands to be run even if sudo cannot write to the audit log" +ignore_iolog_errors + T_FLAG + "Allow commands to be run even if sudo cannot write to the I/O log" +ignore_logfile_errors + T_FLAG + "Allow commands to be run even if sudo cannot write to the log file" diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c index 5d2274b92..1b562941d 100644 --- a/plugins/sudoers/defaults.c +++ b/plugins/sudoers/defaults.c @@ -513,6 +513,9 @@ init_defaults(void) #ifdef HAVE_ZLIB_H def_compress_io = true; #endif + def_ignore_audit_errors = true; + def_ignore_iolog_errors = false; + def_ignore_logfile_errors = true; /* Now do the strings */ if ((def_mailto = strdup(MAILTO)) == NULL) diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c index 61c313089..d4db4ce3c 100644 --- a/plugins/sudoers/iolog.c +++ b/plugins/sudoers/iolog.c @@ -711,6 +711,7 @@ done: static void sudoers_io_close(int exit_status, int error) { + const char *errstr = NULL; int i; debug_decl(sudoers_io_close, SUDOERS_DEBUG_PLUGIN) @@ -718,13 +719,20 @@ sudoers_io_close(int exit_status, int error) if (io_log_files[i].fd.v == NULL) continue; #ifdef HAVE_ZLIB_H - if (iolog_compress) - gzclose(io_log_files[i].fd.g); - else + if (iolog_compress) { + int errnum; + + if (gzclose(io_log_files[i].fd.g) != Z_OK) + errstr = gzerror(io_log_files[i].fd.g, &errnum); + } else #endif - fclose(io_log_files[i].fd.f); + if (fclose(io_log_files[i].fd.f) != 0) + errstr = strerror(errno); } + if (errstr != NULL) + sudo_warnx(U_("unable to write to I/O log file: %s"), errstr); + sudoers_debug_deregister(); return; @@ -748,6 +756,8 @@ static int sudoers_io_log(const char *buf, unsigned int len, int idx) { struct timeval now, delay; + static bool warned = false; + const char *errstr = NULL; int rval = true; debug_decl(sudoers_io_version, SUDOERS_DEBUG_PLUGIN) @@ -761,30 +771,48 @@ sudoers_io_log(const char *buf, unsigned int len, int idx) #ifdef HAVE_ZLIB_H if (iolog_compress) { - if (gzwrite(io_log_files[idx].fd.g, (const voidp)buf, len) != (int)len) + if (gzwrite(io_log_files[idx].fd.g, (const voidp)buf, len) != (int)len) { + int errnum; + + errstr = gzerror(io_log_files[idx].fd.g, &errnum); rval = -1; + } } else #endif { - if (fwrite(buf, 1, len, io_log_files[idx].fd.f) != len) + if (fwrite(buf, 1, len, io_log_files[idx].fd.f) != len) { + errstr = strerror(errno); rval = -1; + } } sudo_timevalsub(&now, &last_time, &delay); #ifdef HAVE_ZLIB_H if (iolog_compress) { if (gzprintf(io_log_files[IOFD_TIMING].fd.g, "%d %f %u\n", idx, - delay.tv_sec + ((double)delay.tv_usec / 1000000), len) == 0) + delay.tv_sec + ((double)delay.tv_usec / 1000000), len) == 0) { + int errnum; + + errstr = gzerror(io_log_files[IOFD_TIMING].fd.g, &errnum); rval = -1; + } } else #endif { if (fprintf(io_log_files[IOFD_TIMING].fd.f, "%d %f %u\n", idx, - delay.tv_sec + ((double)delay.tv_usec / 1000000), len) < 0) + delay.tv_sec + ((double)delay.tv_usec / 1000000), len) < 0) { + errstr = strerror(errno); rval = -1; + } } last_time.tv_sec = now.tv_sec; last_time.tv_usec = now.tv_usec; + if (errstr != NULL && !warned) { + /* Only warn about I/O log file errors once. */ + sudo_warnx(U_("unable to write to I/O log file: %s"), errstr); + warned = true; + } + debug_return_int(rval); } diff --git a/plugins/sudoers/policy.c b/plugins/sudoers/policy.c index 2b551e6b2..65332e28c 100644 --- a/plugins/sudoers/policy.c +++ b/plugins/sudoers/policy.c @@ -532,6 +532,10 @@ sudoers_policy_exec_setup(char *argv[], char *envp[], mode_t cmnd_umask, if (asprintf(&command_info[info_len++], "closefrom=%d", def_closefrom) == -1) goto oom; } + if (def_ignore_iolog_errors) { + if ((command_info[info_len++] = strdup("ignore_iolog_errors=true")) == NULL) + goto oom; + } if (def_noexec) { if ((command_info[info_len++] = strdup("noexec=true")) == NULL) goto oom; diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 74b02dcee..72ddae204 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -492,7 +492,7 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], } } - if (!log_allowed(validated)) + if (!log_allowed(validated) && !def_ignore_logfile_errors) goto bad; switch (sudo_mode & MODE_MASK) { @@ -602,13 +602,13 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], goto done; goto bad; } - if (audit_success(edit_argc, edit_argv) != 0) + if (audit_success(edit_argc, edit_argv) != 0 && !def_ignore_audit_errors) goto done; /* We want to run the editor with the unmodified environment. */ env_swap_old(); } else { - if (audit_success(NewArgc, NewArgv) != 0) + if (audit_success(NewArgc, NewArgv) != 0 && !def_ignore_audit_errors) goto done; } diff --git a/src/exec_pty.c b/src/exec_pty.c index fdc8af072..803592038 100644 --- a/src/exec_pty.c +++ b/src/exec_pty.c @@ -89,6 +89,7 @@ static int ttymode = TERM_COOKED; static pid_t ppgrp, cmnd_pgrp, mon_pgrp; static sigset_t ttyblock; static struct io_buffer_list iobufs; +static bool ignore_iolog_errors; static void del_io_events(bool nonblocking); static int exec_monitor(struct command_details *details, int backchannel); @@ -218,7 +219,8 @@ log_ttyin(const char *buf, unsigned int n, struct io_buffer *iob) /* Error: disable plugin's I/O function. */ plugin->u.io->log_ttyin = NULL; } - rval = false; + if (!ignore_iolog_errors) + rval = false; break; } } @@ -250,7 +252,8 @@ log_stdin(const char *buf, unsigned int n, struct io_buffer *iob) /* Error: disable plugin's I/O function. */ plugin->u.io->log_stdin = NULL; } - rval = false; + if (!ignore_iolog_errors) + rval = false; break; } } @@ -282,7 +285,8 @@ log_ttyout(const char *buf, unsigned int n, struct io_buffer *iob) /* Error: disable plugin's I/O function. */ plugin->u.io->log_ttyout = NULL; } - rval = false; + if (!ignore_iolog_errors) + rval = false; break; } } @@ -326,7 +330,8 @@ log_stdout(const char *buf, unsigned int n, struct io_buffer *iob) /* Error: disable plugin's I/O function. */ plugin->u.io->log_stdout = NULL; } - rval = false; + if (!ignore_iolog_errors) + rval = false; break; } } @@ -370,7 +375,8 @@ log_stderr(const char *buf, unsigned int n, struct io_buffer *iob) /* Error: disable plugin's I/O function. */ plugin->u.io->log_stderr = NULL; } - rval = false; + if (!ignore_iolog_errors) + rval = false; break; } } @@ -676,7 +682,8 @@ write_callback(int fd, int what, void *v) } static void -io_buf_new(int rfd, int wfd, bool (*action)(const char *, unsigned int, struct io_buffer *), +io_buf_new(int rfd, int wfd, + bool (*action)(const char *, unsigned int, struct io_buffer *), struct io_buffer_list *head) { int n; @@ -742,6 +749,13 @@ fork_pty(struct command_details *details, int sv[], sigset_t *omask) sigaddset(&ttyblock, SIGTTIN); sigaddset(&ttyblock, SIGTTOU); + /* + * The security policy may tell us to ignore errors from the + * I/O log functions. + */ + if (!ISSET(details->flags, CD_IGNORE_IOLOG_ERRS)) + ignore_iolog_errors = true; + /* * Setup stdin/stdout/stderr for child, to be duped after forking. * In background mode there is no stdin. diff --git a/src/sudo.c b/src/sudo.c index 58085e9e7..b711c0bd3 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -675,6 +675,9 @@ command_info_to_details(char * const info[], struct command_details *details) break; } break; + case 'i': + SET_FLAG("ignore_iolog_errors=", CD_IGNORE_IOLOG_ERRS) + break; case 'l': SET_STRING("login_class=", login_class) break; diff --git a/src/sudo.h b/src/sudo.h index e871acde4..490f1d437 100644 --- a/src/sudo.h +++ b/src/sudo.h @@ -130,6 +130,7 @@ struct user_details { #define CD_SUDOEDIT_FOLLOW 0x10000 #define CD_SUDOEDIT_CHECKDIR 0x20000 #define CD_SET_GROUPS 0x40000 +#define CD_IGNORE_IOLOG_ERRS 0x80000 struct preserved_fd { TAILQ_ENTRY(preserved_fd) entries;