diff --git a/doc/sudo_plugin.man.in b/doc/sudo_plugin.man.in index 155e7eadc..bd5bae828 100644 --- a/doc/sudo_plugin.man.in +++ b/doc/sudo_plugin.man.in @@ -16,7 +16,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.TH "SUDO_PLUGIN" "5" "February 5, 2020" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDO_PLUGIN" "5" "February 10, 2020" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -605,6 +605,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .sp NOTE: the \fIerrstr\fR @@ -1208,6 +1213,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .sp NOTE: the \fIerrstr\fR @@ -1291,6 +1301,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .sp NOTE: the \fIerrstr\fR @@ -1356,6 +1371,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .sp NOTE: the \fIerrstr\fR @@ -1636,6 +1656,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .sp NOTE: the \fIerrstr\fR @@ -2005,6 +2030,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .sp NOTE: the \fIerrstr\fR @@ -2130,6 +2160,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .sp NOTE: the \fIerrstr\fR @@ -2184,6 +2219,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .sp NOTE: the \fIerrstr\fR @@ -2240,6 +2280,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .sp NOTE: the \fIerrstr\fR @@ -2296,6 +2341,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .sp NOTE: the \fIerrstr\fR @@ -2352,6 +2402,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .sp NOTE: the \fIerrstr\fR @@ -2418,6 +2473,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .sp NOTE: the \fIerrstr\fR @@ -2469,6 +2529,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .sp NOTE: the \fIerrstr\fR @@ -2778,6 +2843,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .PD 0 .PP .RE @@ -2914,6 +2984,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .PD 0 .PP .RE @@ -2986,6 +3061,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .PD 0 .PP .RE @@ -3058,6 +3138,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .PD 0 .PP .RE @@ -3110,26 +3195,28 @@ struct approval_plugin { #define SUDO_APPROVAL_PLUGIN 4 unsigned int type; /* always SUDO_APPROVAL_PLUGIN */ unsigned int version; /* always SUDO_API_VERSION */ - int (*check)(unsigned int version, sudo_conv_t conversation, + int (*open)(unsigned int version, sudo_conv_t conversation, sudo_printf_t sudo_printf, char * const settings[], char * const user_info[], int submit_optind, char * const submit_argv[], char * const submit_envp[], - char * const command_info[], char * const run_argv[], - char * const run_envp[], char * const plugin_options[], - const char **errstr); - int (*show_version)(unsigned int version, sudo_conv_t conversation, - sudo_printf_t sudo_printf, int verbose); + char * const plugin_options[], const char **errstr); + void (*close)(void); + int (*check)(char * const command_info[], char * const run_argv[], + char * const run_envp[], const char **errstr); + int (*show_version)(int verbose); }; .RE .fi .PP An approval plugin can be used to apply extra constraints after a command has been accepted by the policy plugin. -Unlike the other plugin types, there are no -\fBopen\fR() +Unlike the other plugin types, it does not remain open until the command +completes. +The plugin is opened before a call to +\fBcheck\fR() or -\fBclose\fR() -functions; functions in an approval function are stand-alone. +\fBshow_version\fR() +and closed immediately after. Multiple approval plugins may be specified in sudo.conf(@mansectform@). .PP @@ -3152,28 +3239,29 @@ This allows to determine the API version the plugin was built against. .TP 6n -check -.br +open .nf .RS 6n -int (*check)(unsigned int version, sudo_conv_t conversation, +int (*open)(unsigned int version, sudo_conv_t conversation, sudo_printf_t sudo_printf, char * const settings[], char * const user_info[], int submit_optind, char * const submit_argv[], char * const submit_envp[], - char * const command_info[], char * const run_argv[], - char * const run_envp[], char * const plugin_options[], - const char **errstr); + char * const plugin_options[], const char **errstr); .RE .fi .RS 6n .sp The approval +\fBopen\fR() +function is run immediately before a call to the plugin's \fBcheck\fR() -function is run after the policy plugin -\fBcheck\fR() -function and before any I/O logging plugins. -If multiple approval plugins are loaded, they must all succeeed for -the command to be allowed. +or +\fBshow_version\fR() +functions. +It is only called if the version is being requested or if the +policy plugin's +\fBcheck_policy\fR() +function has returned successfully. It returns 1 on success, 0 on failure, \-1 if a general error occurred, or \-2 if there was a usage error. In the latter case, @@ -3310,6 +3398,98 @@ itself but the \fIvalue\fR might. .TP 6n +plugin_options +Any (non-comment) strings immediately after the plugin path are +treated as arguments to the plugin. +These arguments are split on a white space boundary and are passed to +the plugin in the form of a +\fRNULL\fR-terminated +array of strings. +If no arguments were specified, +\fIplugin_options\fR +will be the +\fRNULL\fR +pointer. +.TP 6n +errstr +If the +\fBopen\fR() +function returns a value other than 1, the plugin may +store a message describing the failure or error in +\fIerrstr\fR. +The +\fBsudo\fR +front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. +.PD 0 +.PP +.RE +.PD +.TP 6n +close +.br +.nf +.RS 6n +void (*close)(void); +.RE +.fi +.RS 6n +.sp +The +\fBclose\fR() +function is called after the approval plugin's +\fBcheck\fR() +or +\fBshow_version\fR() +functions have been called. +It takes no arguments. +The +\fBclose\fR() +function is typically used to perform plugin-specific cleanup, +such as the freeing of memory objects allocated by the plugin. +If the plugin does not need to perform any cleanup, +\fBclose\fR() +may be set to the +\fRNULL\fR +pointer. +.RE +.TP 6n +check +.br +.nf +.RS 6n +int (*check)(char * const command_info[], char * const run_argv[], + char * const run_envp[], const char **errstr); +.RE +.fi +.RS 6n +.sp +The approval +\fBcheck\fR() +function is run after the policy plugin +\fBcheck_policy\fR() +function and before any I/O logging plugins. +If multiple approval plugins are loaded, they must all succeeed for +the command to be allowed. +It returns 1 on success, 0 on failure, \-1 if a general error occurred, +or \-2 if there was a usage error. +In the latter case, +\fBsudo\fR +will print a usage message before it exits. +If an error occurs, the plugin may optionally call the +\fBconversation\fR() +or +\fBplugin_printf\fR() +function with +\fRSUDO_CONF_ERROR_MSG\fR +to present additional error information to the user. +.sp +The function arguments are as follows: +.TP 6n command_info A vector of information describing the command being run in the form of \(lqname=value\(rq @@ -3363,19 +3543,6 @@ itself but the \fIvalue\fR might. .TP 6n -plugin_options -Any (non-comment) strings immediately after the plugin path are -treated as arguments to the plugin. -These arguments are split on a white space boundary and are passed to -the plugin in the form of a -\fRNULL\fR-terminated -array of strings. -If no arguments were specified, -\fIplugin_options\fR -will be the -\fRNULL\fR -pointer. -.TP 6n errstr If the \fBopen\fR() @@ -3385,6 +3552,11 @@ store a message describing the failure or error in The \fBsudo\fR front end will then pass this value to any registered audit plugins. +The string stored in +\fIerrstr\fR +must remain valid until the plugin's +\fBclose\fR() +function is called. .PD 0 .PP .RE diff --git a/doc/sudo_plugin.mdoc.in b/doc/sudo_plugin.mdoc.in index 14e778cba..f8fbbfda6 100644 --- a/doc/sudo_plugin.mdoc.in +++ b/doc/sudo_plugin.mdoc.in @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd February 5, 2020 +.Dd February 10, 2020 .Dt SUDO_PLUGIN @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -533,13 +533,18 @@ If the .Fn open function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .Pp NOTE: the -.Em errstr +.Fa errstr parameter is only available starting with API version 1.15. A plugin @@ -547,7 +552,7 @@ A plugin check the API version specified by the .Nm sudo front end before using -.Em errstr . +.Fa errstr . Failure to do so may result in a crash. .El .It close @@ -1069,13 +1074,18 @@ If the .Fn check_policy function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .Pp NOTE: the -.Em errstr +.Fa errstr parameter is only available starting with API version 1.15. A plugin @@ -1083,7 +1093,7 @@ A plugin check the API version specified by the .Nm sudo front end before using -.Em errstr . +.Fa errstr . Failure to do so may result in a crash. .El .It list @@ -1141,13 +1151,18 @@ If the .Fn list function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .Pp NOTE: the -.Em errstr +.Fa errstr parameter is only available starting with API version 1.15. A plugin @@ -1155,7 +1170,7 @@ A plugin check the API version specified by the .Nm sudo front end before using -.Em errstr . +.Fa errstr . Failure to do so may result in a crash. .El .It validate @@ -1199,13 +1214,18 @@ If the .Fn validate function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .Pp NOTE: the -.Em errstr +.Fa errstr parameter is only available starting with API version 1.15. A plugin @@ -1213,7 +1233,7 @@ A plugin check the API version specified by the .Nm sudo front end before using -.Em errstr . +.Fa errstr . Failure to do so may result in a crash. .El .It invalidate @@ -1450,13 +1470,18 @@ If the .Fn init_session function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .Pp NOTE: the -.Em errstr +.Fa errstr parameter is only available starting with API version 1.15. A plugin @@ -1464,7 +1489,7 @@ A plugin check the API version specified by the .Nm sudo front end before using -.Em errstr . +.Fa errstr . Failure to do so may result in a crash. .El .Pp @@ -1800,13 +1825,18 @@ If the .Fn open function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .Pp NOTE: the -.Em errstr +.Fa errstr parameter is only available starting with API version 1.15. A plugin @@ -1814,7 +1844,7 @@ A plugin check the API version specified by the .Nm sudo front end before using -.Em errstr . +.Fa errstr . Failure to do so may result in a crash. .El .It close @@ -1901,13 +1931,18 @@ If the .Fn log_ttyin function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .Pp NOTE: the -.Em errstr +.Fa errstr parameter is only available starting with API version 1.15. A plugin @@ -1915,7 +1950,7 @@ A plugin check the API version specified by the .Nm sudo front end before using -.Em errstr . +.Fa errstr . Failure to do so may result in a crash. .El .It log_ttyout @@ -1946,13 +1981,18 @@ If the .Fn log_ttyout function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .Pp NOTE: the -.Em errstr +.Fa errstr parameter is only available starting with API version 1.15. A plugin @@ -1960,7 +2000,7 @@ A plugin check the API version specified by the .Nm sudo front end before using -.Em errstr . +.Fa errstr . Failure to do so may result in a crash. .El .It log_stdin @@ -1993,13 +2033,18 @@ If the .Fn log_stdin function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .Pp NOTE: the -.Em errstr +.Fa errstr parameter is only available starting with API version 1.15. A plugin @@ -2007,7 +2052,7 @@ A plugin check the API version specified by the .Nm sudo front end before using -.Em errstr . +.Fa errstr . Failure to do so may result in a crash. .El .It log_stdout @@ -2040,13 +2085,18 @@ If the .Fn log_stdout function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .Pp NOTE: the -.Em errstr +.Fa errstr parameter is only available starting with API version 1.15. A plugin @@ -2054,7 +2104,7 @@ A plugin check the API version specified by the .Nm sudo front end before using -.Em errstr . +.Fa errstr . Failure to do so may result in a crash. .El .It log_stderr @@ -2087,13 +2137,18 @@ If the .Fn log_stderr function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .Pp NOTE: the -.Em errstr +.Fa errstr parameter is only available starting with API version 1.15. A plugin @@ -2101,7 +2156,7 @@ A plugin check the API version specified by the .Nm sudo front end before using -.Em errstr . +.Fa errstr . Failure to do so may result in a crash. .El .It register_hooks @@ -2141,13 +2196,18 @@ If the .Fn change_winsize function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .Pp NOTE: the -.Em errstr +.Fa errstr parameter is only available starting with API version 1.15. A plugin @@ -2155,7 +2215,7 @@ A plugin check the API version specified by the .Nm sudo front end before using -.Em errstr . +.Fa errstr . Failure to do so may result in a crash. .El .It log_suspend @@ -2183,13 +2243,18 @@ If the .Fn log_suspend function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .Pp NOTE: the -.Em errstr +.Fa errstr parameter is only available starting with API version 1.15. A plugin @@ -2197,7 +2262,7 @@ A plugin check the API version specified by the .Nm sudo front end before using -.Em errstr . +.Fa errstr . Failure to do so may result in a crash. .It event_alloc .Bd -literal -compact @@ -2472,10 +2537,15 @@ If the .Fn open function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .El .It close .Bd -literal -compact @@ -2587,10 +2657,15 @@ If the .Fn accept function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .El .It reject .Bd -literal -compact @@ -2648,10 +2723,15 @@ If the .Fn reject function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .El .It error .Bd -literal -compact @@ -2708,10 +2788,15 @@ If the .Fn error function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .El .It show_version .Bd -literal -compact @@ -2754,25 +2839,27 @@ struct approval_plugin { #define SUDO_APPROVAL_PLUGIN 4 unsigned int type; /* always SUDO_APPROVAL_PLUGIN */ unsigned int version; /* always SUDO_API_VERSION */ - int (*check)(unsigned int version, sudo_conv_t conversation, + int (*open)(unsigned int version, sudo_conv_t conversation, sudo_printf_t sudo_printf, char * const settings[], char * const user_info[], int submit_optind, char * const submit_argv[], char * const submit_envp[], - char * const command_info[], char * const run_argv[], - char * const run_envp[], char * const plugin_options[], - const char **errstr); - int (*show_version)(unsigned int version, sudo_conv_t conversation, - sudo_printf_t sudo_printf, int verbose); + char * const plugin_options[], const char **errstr); + void (*close)(void); + int (*check)(char * const command_info[], char * const run_argv[], + char * const run_envp[], const char **errstr); + int (*show_version)(int verbose); }; .Ed .Pp An approval plugin can be used to apply extra constraints after a command has been accepted by the policy plugin. -Unlike the other plugin types, there are no -.Fn open +Unlike the other plugin types, it does not remain open until the command +completes. +The plugin is opened before a call to +.Fn check or -.Fn close -functions; functions in an approval function are stand-alone. +.Fn show_version +and closed immediately after. Multiple approval plugins may be specified in .Xr sudo.conf @mansectform@ . .Pp @@ -2793,24 +2880,26 @@ This allows .Nm sudo to determine the API version the plugin was built against. -.It check +.It open .Bd -literal -compact -int (*check)(unsigned int version, sudo_conv_t conversation, +int (*open)(unsigned int version, sudo_conv_t conversation, sudo_printf_t sudo_printf, char * const settings[], char * const user_info[], int submit_optind, char * const submit_argv[], char * const submit_envp[], - char * const command_info[], char * const run_argv[], - char * const run_envp[], char * const plugin_options[], - const char **errstr); + char * const plugin_options[], const char **errstr); .Ed .Pp The approval +.Fn open +function is run immediately before a call to the plugin's .Fn check -function is run after the policy plugin -.Fn check -function and before any I/O logging plugins. -If multiple approval plugins are loaded, they must all succeeed for -the command to be allowed. +or +.Fn show_version +functions. +It is only called if the version is being requested or if the +policy plugin's +.Fn check_policy +function has returned successfully. It returns 1 on success, 0 on failure, \-1 if a general error occurred, or \-2 if there was a usage error. In the latter case, @@ -2939,6 +3028,83 @@ field will never include one itself but the .Em value might. +.It plugin_options +Any (non-comment) strings immediately after the plugin path are +treated as arguments to the plugin. +These arguments are split on a white space boundary and are passed to +the plugin in the form of a +.Dv NULL Ns -terminated +array of strings. +If no arguments were specified, +.Em plugin_options +will be the +.Dv NULL +pointer. +.It errstr +If the +.Fn open +function returns a value other than 1, the plugin may +store a message describing the failure or error in +.Fa errstr . +The +.Nm sudo +front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. +.El +.It close +.Bd -literal -compact +void (*close)(void); +.Ed +.Pp +The +.Fn close +function is called after the approval plugin's +.Fn check +or +.Fn show_version +functions have been called. +It takes no arguments. +The +.Fn close +function is typically used to perform plugin-specific cleanup, +such as the freeing of memory objects allocated by the plugin. +If the plugin does not need to perform any cleanup, +.Fn close +may be set to the +.Dv NULL +pointer. +.It check +.Bd -literal -compact +int (*check)(char * const command_info[], char * const run_argv[], + char * const run_envp[], const char **errstr); +.Ed +.Pp +The approval +.Fn check +function is run after the policy plugin +.Fn check_policy +function and before any I/O logging plugins. +If multiple approval plugins are loaded, they must all succeeed for +the command to be allowed. +It returns 1 on success, 0 on failure, \-1 if a general error occurred, +or \-2 if there was a usage error. +In the latter case, +.Nm sudo +will print a usage message before it exits. +If an error occurs, the plugin may optionally call the +.Fn conversation +or +.Fn plugin_printf +function with +.Dv SUDO_CONF_ERROR_MSG +to present additional error information to the user. +.Pp +The function arguments are as follows: +.Bl -tag -width 4n .It command_info A vector of information describing the command being run in the form of .Dq name=value @@ -2989,27 +3155,20 @@ field will never include one itself but the .Em value might. -.It plugin_options -Any (non-comment) strings immediately after the plugin path are -treated as arguments to the plugin. -These arguments are split on a white space boundary and are passed to -the plugin in the form of a -.Dv NULL Ns -terminated -array of strings. -If no arguments were specified, -.Em plugin_options -will be the -.Dv NULL -pointer. .It errstr If the .Fn open function returns a value other than 1, the plugin may store a message describing the failure or error in -.Em errstr . +.Fa errstr . The .Nm sudo front end will then pass this value to any registered audit plugins. +The string stored in +.Fa errstr +must remain valid until the plugin's +.Fn close +function is called. .El .It show_version .Bd -literal -compact diff --git a/include/sudo_plugin.h b/include/sudo_plugin.h index e857be266..955b0cc96 100644 --- a/include/sudo_plugin.h +++ b/include/sudo_plugin.h @@ -242,15 +242,15 @@ struct approval_plugin { #define SUDO_APPROVAL_PLUGIN 4 unsigned int type; /* always SUDO_APPROVAL_PLUGIN */ unsigned int version; /* always SUDO_API_VERSION */ - int (*check)(unsigned int version, sudo_conv_t conversation, + int (*open)(unsigned int version, sudo_conv_t conversation, sudo_printf_t sudo_printf, char * const settings[], char * const user_info[], int submit_optind, char * const submit_argv[], char * const submit_envp[], - char * const command_info[], char * const run_argv[], - char * const run_envp[], char * const plugin_options[], - const char **errstr); - int (*show_version)(unsigned int version, sudo_conv_t conversation, - sudo_printf_t sudo_printf, int verbose); + char * const plugin_options[], const char **errstr); + void (*close)(void); + int (*check)(char * const command_info[], char * const run_argv[], + char * const run_envp[], const char **errstr); + int (*show_version)(int verbose); }; /* Sudoers group plugin version major/minor */ diff --git a/plugins/sample_approval/sample_approval.c b/plugins/sample_approval/sample_approval.c index 12a999e5b..a97bde39e 100644 --- a/plugins/sample_approval/sample_approval.c +++ b/plugins/sample_approval/sample_approval.c @@ -52,6 +52,7 @@ #include "sudo_util.h" static int approval_debug_instance = SUDO_DEBUG_INSTANCE_INITIALIZER; +sudo_printf_t sudo_printf; /* * Parse the "filename flags,..." debug_flags entry and insert a new @@ -93,22 +94,21 @@ oom: } static int -approval_check(unsigned int version, sudo_conv_t conversation, +sample_approval_open(unsigned int version, sudo_conv_t conversation, sudo_printf_t plugin_printf, char * const settings[], char * const user_info[], int submit_optind, char * const submit_argv[], - char * const submit_envp[], char * const command_info[], - char * const run_argv[], char * const run_envp[], - char * const plugin_options[], const char **errstr) + char * const submit_envp[], char * const plugin_options[], + const char **errstr) { struct sudo_conf_debug_file_list debug_files = TAILQ_HEAD_INITIALIZER(debug_files); struct sudo_debug_file *debug_file; const char *cp, *plugin_path = NULL; char * const *cur; - struct tm *tm; - time_t now; int ret = -1; - debug_decl(approval_check, SUDO_DEBUG_PLUGIN); + debug_decl_vars(sample_approval_open, SUDO_DEBUG_PLUGIN); + + sudo_printf = plugin_printf; /* Initialize the debug subsystem. */ for (cur = settings; (cp = *cur) != NULL; cur++) { @@ -129,25 +129,9 @@ approval_check(unsigned int version, sudo_conv_t conversation, sudo_debug_register(plugin_path, NULL, NULL, &debug_files); if (approval_debug_instance == SUDO_DEBUG_INSTANCE_ERROR) { *errstr = U_("unable to initialize debugging"); - goto bad; + goto done; } - } - - /* - * Only approve requests that are within business hours, - * which are 9am - 5pm local time. Does not check holidays. - */ - ret = 0; - if (time(&now) == -1 || (tm = localtime(&now)) == NULL) - goto bad; - if (tm->tm_wday < 1 || tm->tm_wday > 5) { - /* bad weekday */ - goto bad; - } - if (tm->tm_hour < 9 || tm->tm_hour > 17 || - (tm->tm_hour == 17 && tm->tm_min > 0)) { - /* bad hour */ - goto bad; + sudo_debug_enter(__func__, __FILE__, __LINE__, sudo_debug_subsys); } ret = 1; @@ -157,12 +141,6 @@ oom: sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); *errstr = U_("unable to allocate memory"); -bad: - if (ret == 0) { - *errstr = U_("You are not allowed to use sudo outside business hours"); - plugin_printf(SUDO_CONV_ERROR_MSG, "%s\n", *errstr); - } - done: while ((debug_file = TAILQ_FIRST(&debug_files)) != NULL) { TAILQ_REMOVE(&debug_files, debug_file, entries); @@ -174,13 +152,57 @@ done: debug_return_int(ret); } +static void +sample_approval_close(void) +{ + debug_decl(sample_approval_close, SUDO_DEBUG_PLUGIN); + + /* Nothing here, we could store a NULL pointer instead. */ + + debug_return; +} + static int -approval_show_version(unsigned int version, sudo_conv_t conversation, - sudo_printf_t plugin_printf, int verbose) +sample_approval_check(char * const command_info[], char * const run_argv[], + char * const run_envp[], const char **errstr) +{ + struct tm *tm; + time_t now; + int ret = 0; + debug_decl(sample_approval_check, SUDO_DEBUG_PLUGIN); + + /* + * Only approve requests that are within business hours, + * which are 9am - 5pm local time. Does not check holidays. + */ + if (time(&now) == -1 || (tm = localtime(&now)) == NULL) + goto done; + if (tm->tm_wday < 1 || tm->tm_wday > 5) { + /* bad weekday */ + goto done; + } + if (tm->tm_hour < 9 || tm->tm_hour > 17 || + (tm->tm_hour == 17 && tm->tm_min > 0)) { + /* bad hour */ + goto done; + } + ret = 1; + +done: + if (ret == 0) { + *errstr = U_("You are not allowed to use sudo outside business hours"); + sudo_printf(SUDO_CONV_ERROR_MSG, "%s\n", *errstr); + } + + debug_return_int(ret); +} + +static int +sample_approval_show_version(int verbose) { debug_decl(approval_show_version, SUDO_DEBUG_PLUGIN); - plugin_printf(SUDO_CONV_INFO_MSG, "sample approval plugin version %s\n", + sudo_printf(SUDO_CONV_INFO_MSG, "sample approval plugin version %s\n", PACKAGE_VERSION); debug_return_int(true); @@ -189,6 +211,8 @@ approval_show_version(unsigned int version, sudo_conv_t conversation, __dso_public struct approval_plugin sample_approval = { SUDO_APPROVAL_PLUGIN, SUDO_API_VERSION, - approval_check, - approval_show_version + sample_approval_open, + sample_approval_close, + sample_approval_check, + sample_approval_show_version }; diff --git a/src/sudo.c b/src/sudo.c index 8cd28d844..4f086170a 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -144,7 +144,9 @@ static void approval_check(struct sudo_settings *settings, char * const user_info[], int submit_optind, char * const submit_argv[], char * const submit_envp[], char * const command_info[], char * const run_argv[], char * const run_envp[]); -static void approval_show_version(int verbose); +static void approval_show_version(int verbose, struct sudo_settings *settings, + char * const user_info[], int submit_optind, char * const submit_argv[], + char * const submit_envp[]); __dso_public int main(int argc, char *argv[], char *envp[]); @@ -246,7 +248,8 @@ main(int argc, char *argv[], char *envp[]) policy_show_version(!user_details.uid); iolog_show_version(!user_details.uid, settings, user_info, nargc, nargv, envp); - approval_show_version(!user_details.uid); + approval_show_version(!user_details.uid, settings, user_info, + submit_optind, argv, envp); audit_show_version(!user_details.uid); break; case MODE_VALIDATE: @@ -1704,36 +1707,79 @@ audit_error(const char *plugin_name, unsigned int plugin_type, } static int -approval_check_int(struct plugin_container *plugin, +approval_open_int(struct plugin_container *plugin, struct sudo_settings *settings, char * const user_info[], - int submit_optind, char * const submit_argv[], char * const submit_envp[], - char * const command_info[], char * const run_argv[], - char * const run_envp[], const char **errstr) + int submit_optind, char * const submit_argv[], char * const submit_envp[]) { char **plugin_settings; + const char *errstr = NULL; int ret; - debug_decl(approval_check_int, SUDO_DEBUG_PCOMM); + debug_decl(approval_open_int, SUDO_DEBUG_PCOMM); /* Convert struct sudo_settings to plugin_settings[] */ plugin_settings = format_plugin_settings(plugin, settings); - if (plugin_settings == NULL) { - sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - debug_return_int(-1); - } + if (plugin_settings == NULL) + sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - sudo_debug_set_active_instance(plugin->debug_instance); - ret = plugin->u.approval->check(SUDO_API_VERSION, sudo_conversation, - sudo_conversation_printf, plugin_settings, user_info, - submit_optind, submit_argv, submit_envp, command_info, run_argv, - run_envp, plugin->options, errstr); + sudo_debug_set_active_instance(SUDO_DEBUG_INSTANCE_INITIALIZER); + ret = plugin->u.approval->open(SUDO_API_VERSION, sudo_conversation, + sudo_conversation_printf, plugin_settings, user_info, submit_optind, + submit_argv, submit_envp, plugin->options, &errstr); + + /* Stash plugin debug instance ID if set in open() function. */ + plugin->debug_instance = sudo_debug_get_active_instance(); sudo_debug_set_active_instance(sudo_debug_instance); - sudo_debug_printf(SUDO_DEBUG_INFO, "approval plugin %s returns %d (%s)", - plugin->name, ret, *errstr ? *errstr : ""); + switch (ret) { + case 1: + break; + case 0: + /* approval plugin asked to be disabled, remove and free. */ + unlink_plugin(&approval_plugins, plugin); + break; + case -2: + usage(); + break; + default: + /* XXX - audit */ + sudo_fatalx(U_("error initializing approval plugin %s"), + plugin->name); + } debug_return_int(ret); } +static void +approval_show_version(int verbose, struct sudo_settings *settings, + char * const user_info[], int submit_optind, char * const submit_argv[], + char * const submit_envp[]) +{ + struct plugin_container *plugin, *next; + int ok; + debug_decl(approval_show_version, SUDO_DEBUG_PCOMM); + + /* + * Approval plugin us only open for the life of the show_version() call. + */ + TAILQ_FOREACH_SAFE(plugin, &approval_plugins, entries, next) { + if (plugin->u.approval->show_version == NULL) + continue; + + ok = approval_open_int(plugin, settings, user_info, submit_optind, + submit_argv, submit_envp); + if (ok == 1) { + /* Return value of show_version currently ignored. */ + sudo_debug_set_active_instance(plugin->debug_instance); + plugin->u.approval->show_version(verbose); + if (plugin->u.approval->close != NULL) + plugin->u.approval->close(); + sudo_debug_set_active_instance(sudo_debug_instance); + } + } + + debug_return; +} + /* * Run approval checks (there may be more than one). * This is a "one-shot" plugin that has no open/close and is only @@ -1747,12 +1793,27 @@ approval_check(struct sudo_settings *settings, char * const user_info[], { struct plugin_container *plugin, *next; const char *errstr = NULL; + int ok; debug_decl(approval_check, SUDO_DEBUG_PCOMM); + /* + * Approval plugin us only open for the life of the check() call. + */ TAILQ_FOREACH_SAFE(plugin, &approval_plugins, entries, next) { - int ok = approval_check_int(plugin, settings, user_info, - submit_optind, submit_argv, submit_envp, command_info, run_argv, - run_envp, &errstr); + if (plugin->u.approval->check == NULL) + continue; + + ok = approval_open_int(plugin, settings, user_info, submit_optind, + submit_argv, submit_envp); + if (ok != 1) + continue; + + sudo_debug_set_active_instance(plugin->debug_instance); + ok = plugin->u.approval->check(command_info, run_argv, run_envp, + &errstr); + sudo_debug_set_active_instance(sudo_debug_instance); + sudo_debug_printf(SUDO_DEBUG_INFO, "approval plugin %s returns %d (%s)", + plugin->name, ok, errstr ? errstr : ""); switch (ok) { case 0: @@ -1763,7 +1824,7 @@ approval_check(struct sudo_settings *settings, char * const user_info[], case 1: audit_accept(plugin->name, SUDO_APPROVAL_PLUGIN, command_info, run_argv, run_envp); - continue; + break; case -1: audit_error(plugin->name, SUDO_APPROVAL_PLUGIN, errstr ? errstr : _("approval plugin error"), @@ -1774,29 +1835,20 @@ approval_check(struct sudo_settings *settings, char * const user_info[], break; } - if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15)) - policy_close(0, EPERM); - audit_close(SUDO_PLUGIN_NO_STATUS, 0); - exit(EXIT_FAILURE); /* approval plugin printed error message */ - } - - debug_return; -} - -static void -approval_show_version(int verbose) -{ - struct plugin_container *plugin; - debug_decl(approval_show_version, SUDO_DEBUG_PCOMM); - - TAILQ_FOREACH(plugin, &approval_plugins, entries) { - if (plugin->u.approval->show_version != NULL) { - /* Return value of show_version currently ignored. */ + /* Close approval plugin now that errstr has been consumed. */ + if (plugin->u.approval->close != NULL) { sudo_debug_set_active_instance(plugin->debug_instance); - plugin->u.approval->show_version(SUDO_API_VERSION, - sudo_conversation, sudo_conversation_printf, verbose); + plugin->u.approval->close(); sudo_debug_set_active_instance(sudo_debug_instance); } + + /* On error, close policy and audit plugins then exit. */ + if (ok != 1) { + if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15)) + policy_close(0, EPERM); + audit_close(SUDO_PLUGIN_NO_STATUS, 0); + exit(EXIT_FAILURE); /* approval plugin printed error message */ + } } debug_return;