]> granicus.if.org Git - sudo/commitdiff
Make the behavior when we cannot write to a log or audit file
authorTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 17 Aug 2016 13:22:51 +0000 (07:22 -0600)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 17 Aug 2016 13:22:51 +0000 (07:22 -0600)
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

13 files changed:
doc/sudoers.cat
doc/sudoers.man.in
doc/sudoers.mdoc.in
plugins/sudoers/def_data.c
plugins/sudoers/def_data.h
plugins/sudoers/def_data.in
plugins/sudoers/defaults.c
plugins/sudoers/iolog.c
plugins/sudoers/policy.c
plugins/sudoers/sudoers.c
src/exec_pty.c
src/sudo.c
src/sudo.h

index 9c6a9cc81ce523ca07eb7f784014ba2f5616668a..79c792f35a46374e379bc2a1bf3fa39f4ea74cae 100644 (file)
@@ -1027,11 +1027,37 @@ S\bSU\bUD\bDO\bOE\bER\bRS\bS O\bOP\bPT\bTI\bIO\bON\bNS\bS
 
                        This flag is _\bo_\bf_\bf by default.
 
+     ignore_audit_errors
+                       Allow commands to be run even if s\bsu\bud\bdo\boe\ber\brs\bs 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 s\bsu\bud\bdo\boe\ber\brs\bs supports audit logging,
+                       including FreeBSD, Linux, Mac OS X and Solaris.  This
+                       flag is _\bo_\bn by default.
+
      ignore_dot        If set, s\bsu\bud\bdo\bo will ignore "." or "" (both denoting
                        current directory) in the PATH environment variable;
                        the PATH itself is not modified.  This flag is _\bo_\bf_\bf by
                        default.
 
+     ignore_iolog_errors
+                       Allow commands to be run even if s\bsu\bud\bdo\boe\ber\brs\bs 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 _\bo_\bf_\bf by default.
+
+     ignore_logfile_errors
+                       Allow commands to be run even if s\bsu\bud\bdo\boe\ber\brs\bs 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 s\bsu\bud\bdo\boe\ber\brs\bs is configured to use file-based logging
+                       via the _\bl_\bo_\bg_\bf_\bi_\bl_\be option.  This flag is _\bo_\bn by default.
+
      ignore_local_sudoers
                        If set via LDAP, parsing of _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\be_\br_\bs will be
                        skipped.  This is intended for Enterprises that wish to
@@ -2543,4 +2569,4 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
      file distributed with s\bsu\bud\bdo\bo 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
index ba88c76435e2ed5ab77b2290933262f6e29b8684..7c780476bbeaf576108c334f9ba970d216be9ab7 100644 (file)
@@ -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
index 33c4813eb5400b2fc5225c78f1b37330692b2efc..166c64666e7355af4aedd1c1985c6ca8b9bb1ad0 100644 (file)
@@ -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
index 6d7178232de0b92305f0aa6d5fcbf9dd2dc359dc..7b84efcc97ed079373e204763c8dc72d541bc3d2 100644 (file)
@@ -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
     }
index 85f43c23a23d473615e4611db9dda6dcc62e1bfc..6f99d3fd50786b1de4c8170ab8e4e8bd1a2bc49d 100644 (file)
 #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,
index db76d53426a3caf494d57ef0e91342995960343c..57f198661dd9d9ba0da57a490231fcaa05f68aa1 100644 (file)
@@ -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"
index 5d2274b921d41e4ad7c8f10327667f93f38f2d99..1b562941da265c1f2e11e951240b2d96f4e82890 100644 (file)
@@ -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)
index 61c3130897d0018bdf7d6c2e202c98963ea11052..d4db4ce3cb4afdf020827a25cd8bd1d8428478c2 100644 (file)
@@ -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);
 }
 
index 2b551e6b2cd8693ec2af0d1df692970dca39c645..65332e28c5837336e8eb185f692594773e6ce902 100644 (file)
@@ -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;
index 74b02dcee4af6f3ebcc7fb3dd7f6b1227f57c3d6..72ddae204319cee990eea6deb690552911d72be5 100644 (file)
@@ -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;
     }
 
index fdc8af0724cf5efc209b866611f072d8daa3d85c..8035920389e93a65cbfd6af499718b24d5aaef31 100644 (file)
@@ -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.
index 58085e9e73e5b0a44765b271ef52a8dcc9185d4e..b711c0bd31e58317d5d0d5fcc3145ae0b24625c6 100644 (file)
@@ -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;
index e871acde4e019a2e41bf14072e47c3f8cc6fb703..490f1d437f081040dddd7923aee7ad852167ddd6 100644 (file)
@@ -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;