From: Todd C. Miller Date: Mon, 20 Mar 2017 16:25:58 +0000 (-0600) Subject: Add iolog_flush option. X-Git-Tag: SUDO_1_8_20^2~73 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c4e703696a19283135a44d1b6e07c517634aa22c;p=sudo Add iolog_flush option. --- diff --git a/doc/sudoers.cat b/doc/sudoers.cat index 39752453c..b0caee934 100644 --- a/doc/sudoers.cat +++ b/doc/sudoers.cat @@ -1615,6 +1615,16 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS will be truncated and overwritten unless _i_o_l_o_g___f_i_l_e ends in six or more Xs. + iolog_flush If set, ssuuddoo will flush I/O log data to disk after each + write instead of buffering it. This makes it possible + to view the logs in real-time as the program is + executing but may significantly reduce the + effectiveness of I/O log compression. This flag is _o_f_f + by default. + + This setting is only supported by version 1.8.20 or + higher. + iolog_group The group name to look up when setting the group ID on new I/O log files and directories. By default, I/O log files and directories inherit the group ID of the @@ -2241,12 +2251,14 @@ II//OO LLOOGG FFIILLEESS _s_t_d_e_r_r standard error to a pipe or redirected to a file All files other than _l_o_g are compressed in gzip format unless the - _c_o_m_p_r_e_s_s___i_o option has been disabled. Due to buffering, it is not - possible to display the I/O logs in real-time as the program is - executing. The I/O log data will not be complete until the program run - by ssuuddoo has exited or has been terminated by a signal. The output - portion of an I/O log file can be viewed with the sudoreplay(1m) utility, - which can also be used to list or search the available logs. + _c_o_m_p_r_e_s_s___i_o flag has been disabled. Due to buffering, it is not normally + possible to display the I/O logs in real-time as the program is executing + The I/O log data will not be complete until the program run by ssuuddoo has + exited or has been terminated by a signal. The _i_o_l_o_g___f_l_u_s_h flag can be + used to disable buffering, in which case I/O log data is written to disk + as soon as it is available. The output portion of an I/O log file can be + viewed with the sudoreplay(1m) utility, which can also be used to list or + search the available logs. Note that user input may contain sensitive information such as passwords (even if they are not echoed to the screen), which will be stored in the @@ -2748,4 +2760,4 @@ DDIISSCCLLAAIIMMEERR file distributed with ssuuddoo or https://www.sudo.ws/license.html for complete details. -Sudo 1.8.20 March 17, 2017 Sudo 1.8.20 +Sudo 1.8.20 March 20, 2017 Sudo 1.8.20 diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in index a9ff75415..49dbd77ad 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" "March 17, 2017" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDOERS" "5" "March 20, 2017" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -3315,6 +3315,19 @@ ends in six or more \fRX\fRs. .TP 18n +iolog_flush +If set, +\fBsudo\fR +will flush I/O log data to disk after each write instead of buffering it. +This makes it possible to view the logs in real-time as the program +is executing but may significantly reduce the effectiveness of I/O +log compression. +This flag is +\fIoff\fR +by default. +.sp +This setting is only supported by version 1.8.20 or higher. +.TP 18n iolog_group The group name to look up when setting the group ID on new I/O log files and directories. @@ -4467,12 +4480,16 @@ All files other than \fIlog\fR are compressed in gzip format unless the \fIcompress_io\fR -option has been disabled. -Due to buffering, it is not possible to display the I/O logs in -real-time as the program is executing. +flag has been disabled. +Due to buffering, it is not normally possible to display the I/O logs in +real-time as the program is executing The I/O log data will not be complete until the program run by \fBsudo\fR has exited or has been terminated by a signal. +The +\fIiolog_flush\fR +flag can be used to disable buffering, in which case I/O log data +is written to disk as soon as it is available. The output portion of an I/O log file can be viewed with the sudoreplay(@mansectsu@) utility, which can also be used to list or search the available logs. diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in index 97ac155c7..e872b7c6a 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 March 17, 2017 +.Dd March 20, 2017 .Dt SUDOERS @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -3109,6 +3109,18 @@ overwritten unless ends in six or more .Li X Ns s . +.It iolog_flush +If set, +.Nm sudo +will flush I/O log data to disk after each write instead of buffering it. +This makes it possible to view the logs in real-time as the program +is executing but may significantly reduce the effectiveness of I/O +log compression. +This flag is +.Em off +by default. +.Pp +This setting is only supported by version 1.8.20 or higher. .It iolog_group The group name to look up when setting the group ID on new I/O log files and directories. @@ -4148,12 +4160,16 @@ All files other than .Pa log are compressed in gzip format unless the .Em compress_io -option has been disabled. -Due to buffering, it is not possible to display the I/O logs in -real-time as the program is executing. +flag has been disabled. +Due to buffering, it is not normally possible to display the I/O logs in +real-time as the program is executing The I/O log data will not be complete until the program run by .Nm sudo has exited or has been terminated by a signal. +The +.Em iolog_flush +flag can be used to disable buffering, in which case I/O log data +is written to disk as soon as it is available. The output portion of an I/O log file can be viewed with the .Xr sudoreplay @mansectsu@ utility, which can also be used to list or search the available logs. diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c index 501d7804e..331a6b428 100644 --- a/plugins/sudoers/def_data.c +++ b/plugins/sudoers/def_data.c @@ -457,6 +457,10 @@ struct sudo_defs_types sudo_defs_table[] = { "user_command_timeouts", T_FLAG, N_("Allow the user to specify a timeout on the command line"), NULL, + }, { + "iolog_flush", T_FLAG, + N_("Flush I/O log data to disk immediately instead of buffering it"), + NULL, }, { NULL, 0, NULL } diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h index 2f749b53b..c52335236 100644 --- a/plugins/sudoers/def_data.h +++ b/plugins/sudoers/def_data.h @@ -212,6 +212,8 @@ #define def_command_timeout (sudo_defs_table[I_COMMAND_TIMEOUT].sd_un.ival) #define I_USER_COMMAND_TIMEOUTS 106 #define def_user_command_timeouts (sudo_defs_table[I_USER_COMMAND_TIMEOUTS].sd_un.flag) +#define I_IOLOG_FLUSH 107 +#define def_iolog_flush (sudo_defs_table[I_IOLOG_FLUSH].sd_un.flag) enum def_tuple { never, diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in index b5fb4d92e..a005a6c01 100644 --- a/plugins/sudoers/def_data.in +++ b/plugins/sudoers/def_data.in @@ -335,3 +335,6 @@ command_timeout user_command_timeouts T_FLAG "Allow the user to specify a timeout on the command line" +iolog_flush + T_FLAG + "Flush I/O log data to disk immediately instead of buffering it" diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c index f1ab3c406..058659d51 100644 --- a/plugins/sudoers/iolog.c +++ b/plugins/sudoers/iolog.c @@ -710,6 +710,7 @@ iolog_deserialize_info(struct iolog_details *details, char * const user_info[], /* * Write the "/log" file that contains the user and command info. + * This file is not compressed. */ static bool write_info_log(char *pathbuf, size_t len, struct iolog_details *details, @@ -748,6 +749,57 @@ write_info_log(char *pathbuf, size_t len, struct iolog_details *details, debug_return_bool(ret); } +#ifdef HAVE_ZLIB_H +static const char * +gzstrerror(gzFile file) +{ + int errnum; + + return gzerror(file, &errnum); +} +#endif /* HAVE_ZLIB_H */ + +/* + * Write to an I/O log, compressing if iolog_compress is enabled. + * If def_iolog_flush is true, flush the buffer immediately. + */ +static const char * +iolog_write(const void *buf, unsigned int len, int idx) +{ + const char *errstr = NULL; + debug_decl(iolog_write, SUDOERS_DEBUG_PLUGIN) + +#ifdef HAVE_ZLIB_H + if (iolog_compress) { + if (gzwrite(io_log_files[idx].fd.g, buf, len) != (int)len) { + errstr = gzstrerror(io_log_files[idx].fd.g); + goto done; + } + if (def_iolog_flush) { + if (gzflush(io_log_files[idx].fd.g, Z_SYNC_FLUSH) != Z_OK) { + errstr = gzstrerror(io_log_files[idx].fd.g); + goto done; + } + } + } else +#endif + { + if (fwrite(buf, 1, len, io_log_files[idx].fd.f) != len) { + errstr = strerror(errno); + goto done; + } + if (def_iolog_flush) { + if (fflush(io_log_files[idx].fd.f) != 0) { + errstr = strerror(errno); + goto done; + } + } + } + +done: + debug_return_const_str(errstr); +} + static int sudoers_io_open(unsigned int version, sudo_conv_t conversation, sudo_printf_t plugin_printf, char * const settings[], @@ -915,13 +967,15 @@ sudoers_io_version(int verbose) /* * Generic I/O logging function. Called by the I/O logging entry points. + * Returns 1 on success and -1 on error. */ static int sudoers_io_log(const char *buf, unsigned int len, int idx) { struct timeval now, delay; + char tbuf[1024]; const char *errstr = NULL; - int ret = true; + int ret = -1; debug_decl(sudoers_io_version, SUDOERS_DEBUG_PLUGIN) if (io_log_files[idx].fd.v == NULL) { @@ -932,41 +986,28 @@ sudoers_io_log(const char *buf, unsigned int len, int idx) gettimeofday(&now, NULL); -#ifdef HAVE_ZLIB_H - if (iolog_compress) { - if (gzwrite(io_log_files[idx].fd.g, (const voidp)buf, len) != (int)len) { - int errnum; + /* Write I/O log file entry. */ + errstr = iolog_write(buf, len, idx); + if (errstr != NULL) + goto done; - errstr = gzerror(io_log_files[idx].fd.g, &errnum); - ret = -1; - } - } else -#endif - { - if (fwrite(buf, 1, len, io_log_files[idx].fd.f) != len) { - errstr = strerror(errno); - ret = -1; - } - } + /* Write timing file entry. */ 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) { - int errnum; - - errstr = gzerror(io_log_files[IOFD_TIMING].fd.g, &errnum); - ret = -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) { - errstr = strerror(errno); - ret = -1; - } + len = (unsigned int)snprintf(tbuf, sizeof(tbuf), "%d %f %u\n", idx, + delay.tv_sec + ((double)delay.tv_usec / 1000000), len); + if (len >= sizeof(tbuf)) { + /* Not actually possible due to the size of tbuf[]. */ + errstr = strerror(EOVERFLOW); + goto done; } + errstr = iolog_write(tbuf, len, IOFD_TIMING); + if (errstr != NULL) + goto done; + + /* Success. */ + ret = 1; + +done: last_time.tv_sec = now.tv_sec; last_time.tv_usec = now.tv_usec; @@ -980,7 +1021,7 @@ sudoers_io_log(const char *buf, unsigned int len, int idx) /* Ignore errors if they occur if the policy says so. */ if (iolog_details.ignore_iolog_errors) - ret = true; + ret = 1; } debug_return_int(ret);