Add open and close functions to the approval plugin API.

We need a close function to be able to to free memory allocated for
errstr.  Unlike the other plugins, the close function is called
immediately after the plugin's check or show_version function.
The plugin does not remain open until the command completes.
This commit is contained in:
Todd C. Miller
2020-02-10 15:29:48 -07:00
parent 55b61b989f
commit 01a53f2865
5 changed files with 603 additions and 196 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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
};

View File

@@ -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;
}
/* 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->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;
}
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. */
sudo_debug_set_active_instance(plugin->debug_instance);
plugin->u.approval->show_version(SUDO_API_VERSION,
sudo_conversation, sudo_conversation_printf, verbose);
sudo_debug_set_active_instance(sudo_debug_instance);
}
}
debug_return;