Define a new plugin type that receives accept and reject messages.

This can be used to implement logging-only plugins.
The plugin functions now take an errstr argument that can be used
to return an error string to be logged on failure or error.
This commit is contained in:
Todd C. Miller
2020-01-30 13:25:34 -07:00
parent 88f9f2ba9a
commit 22105009d8
8 changed files with 983 additions and 211 deletions

View File

@@ -1,7 +1,7 @@
.\" .\"
.\" SPDX-License-Identifier: ISC .\" SPDX-License-Identifier: ISC
.\" .\"
.\" Copyright (c) 2009-2019 Todd C. Miller <Todd.Miller@sudo.ws> .\" Copyright (c) 2009-2020 Todd C. Miller <Todd.Miller@sudo.ws>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above .\" purpose with or without fee is hereby granted, provided that the above
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd December 5, 2019 .Dd Januarry 28, 2020
.Dt SUDO_PLUGIN @mansectform@ .Dt SUDO_PLUGIN @mansectform@
.Os Sudo @PACKAGE_VERSION@ .Os Sudo @PACKAGE_VERSION@
.Sh NAME .Sh NAME
@@ -70,17 +70,19 @@ struct policy_plugin {
int (*open)(unsigned int version, sudo_conv_t conversation, int (*open)(unsigned int version, sudo_conv_t conversation,
sudo_printf_t plugin_printf, char * const settings[], sudo_printf_t plugin_printf, char * const settings[],
char * const user_info[], char * const user_env[], char * const user_info[], char * const user_env[],
char * const plugin_options[]); char * const plugin_options[], const char **errstr);
void (*close)(int exit_status, int error); void (*close)(int exit_status, int error);
int (*show_version)(int verbose); int (*show_version)(int verbose, const char **errstr);
int (*check_policy)(int argc, char * const argv[], int (*check_policy)(int argc, char * const argv[],
char *env_add[], char **command_info[], char *env_add[], char **command_info[],
char **argv_out[], char **user_env_out[]); char **argv_out[], char **user_env_out[],
const char **errstr);
int (*list)(int argc, char * const argv[], int verbose, int (*list)(int argc, char * const argv[], int verbose,
const char *list_user); const char *list_user, const char **errstr);
int (*validate)(void); int (*validate)(const char **errstr);
void (*invalidate)(int remove); void (*invalidate)(int remove);
int (*init_session)(struct passwd *pwd, char **user_env[]); int (*init_session)(struct passwd *pwd, char **user_env[],
const char **errstr);
void (*register_hooks)(int version, void (*register_hooks)(int version,
int (*register_hook)(struct sudo_hook *hook)); int (*register_hook)(struct sudo_hook *hook));
void (*deregister_hooks)(int version, void (*deregister_hooks)(int version,
@@ -110,7 +112,7 @@ built against.
int (*open)(unsigned int version, sudo_conv_t conversation, int (*open)(unsigned int version, sudo_conv_t conversation,
sudo_printf_t plugin_printf, char * const settings[], sudo_printf_t plugin_printf, char * const settings[],
char * const user_info[], char * const user_env[], char * const user_info[], char * const user_env[],
char * const plugin_options[]); char * const plugin_options[], const char **errstr);
.Ed .Ed
.Pp .Pp
Returns 1 on success, 0 on failure, \-1 if a general error occurred, Returns 1 on success, 0 on failure, \-1 if a general error occurred,
@@ -441,32 +443,6 @@ The process ID of the running
.Nm sudo .Nm sudo
process. process.
Only available starting with API version 1.2. Only available starting with API version 1.2.
.It plugin_options
Any (non-comment) strings immediately after the plugin path are
passed 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.
.Pp
NOTE: the
.Em plugin_options
parameter is only available starting with
API version 1.2.
A plugin
.Sy must
check the API version specified
by the
.Nm sudo
front end before using
.Em plugin_options .
Failure to do so may result in a crash.
.It ppid=int .It ppid=int
The parent process ID of the running The parent process ID of the running
.Nm sudo .Nm sudo
@@ -518,6 +494,53 @@ field will never include one
itself but the itself but the
.Em value .Em value
might. might.
.It plugin_options
Any (non-comment) strings immediately after the plugin path are
passed 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.
.Pp
NOTE: the
.Em plugin_options
parameter is only available starting with
API version 1.2.
A plugin
.Sy must
check the API version specified
by the
.Nm sudo
front end before using
.Em plugin_options .
Failure to do so may result in a crash.
.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 .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El .El
.It close .It close
.Bd -literal -compact .Bd -literal -compact
@@ -585,7 +608,7 @@ front end may execute the command directly instead of running
it as a child process. it as a child process.
.It show_version .It show_version
.Bd -literal -compact .Bd -literal -compact
int (*show_version)(int verbose); int (*show_version)(int verbose, const char **errstr);
.Ed .Ed
.Pp .Pp
The The
@@ -602,16 +625,45 @@ or
.Fn plugin_printf .Fn plugin_printf
function using function using
.Dv SUDO_CONV_INFO_MSG . .Dv SUDO_CONV_INFO_MSG .
If the user requests detailed version information, the verbose flag will be set.
.Pp .Pp
Returns 1 on success, 0 on failure, \-1 if a general error occurred, Returns 1 on success, 0 on failure, \-1 if a general error occurred,
or \-2 if there was a usage error, although the return value is currently or \-2 if there was a usage error, although the return value is currently
ignored. ignored.
.Pp
The function arguments are as follows:
.Bl -tag -width 4n
.It verbose
If the user requests detailed version information, the
.Em verbose
flag will be set to 1.
.It errstr
If the
.Fn show_version
function returns a value other than 1, the plugin may
store a message describing the failure or error in
.Em errstr .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El
.It check_policy .It check_policy
.Bd -literal -compact .Bd -literal -compact
int (*check_policy)(int argc, char * const argv[], int (*check_policy)(int argc, char * const argv[],
char *env_add[], char **command_info[], char *env_add[], char **command_info[],
char **argv_out[], char **user_env_out[]); char **argv_out[], char **user_env_out[],
const char **errstr);
.Ed .Ed
.Pp .Pp
The The
@@ -1006,11 +1058,32 @@ The
.Dv NULL Ns -terminated .Dv NULL Ns -terminated
environment vector to use when executing the command. environment vector to use when executing the command.
The plugin is responsible for allocating and populating the vector. The plugin is responsible for allocating and populating the vector.
.It errstr
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 .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El .El
.It list .It list
.Bd -literal -compact .Bd -literal -compact
int (*list)(int argc, char * const argv[], int (*list)(int argc, char * const argv[],
int verbose, const char *list_user); int verbose, const char *list_user, const char **errstr);
.Ed .Ed
.Pp .Pp
List available privileges for the invoking user. List available privileges for the invoking user.
@@ -1057,10 +1130,31 @@ allows it.
If If
.Dv NULL , .Dv NULL ,
the plugin should list the privileges of the invoking user. the plugin should list the privileges of the invoking user.
.It errstr
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 .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El .El
.It validate .It validate
.Bd -literal -compact .Bd -literal -compact
int (*validate)(void); int (*validate)(const char **errstr);
.Ed .Ed
.Pp .Pp
The The
@@ -1091,6 +1185,31 @@ function with
.Dv SUDO_CONF_ERROR_MSG .Dv SUDO_CONF_ERROR_MSG
to present additional to present additional
error information to the user. error information to the user.
.Pp
The function arguments are as follows:
.Bl -tag -width 4n
.It errstr
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 .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El
.It invalidate .It invalidate
.Bd -literal -compact .Bd -literal -compact
void (*invalidate)(int remove); void (*invalidate)(int remove);
@@ -1100,8 +1219,7 @@ The
.Fn invalidate .Fn invalidate
function is called when function is called when
.Nm sudo .Nm sudo
is called with is run with the
the
.Fl k .Fl k
or or
.Fl K .Fl K
@@ -1321,6 +1439,27 @@ front end doesn't support API
version 1.15 or higher, version 1.15 or higher,
.Fn event_alloc .Fn event_alloc
will not be set. will not be set.
.It errstr
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 .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El .El
.Pp .Pp
.Em Policy Plugin Version Macros .Em Policy Plugin Version Macros
@@ -1352,20 +1491,26 @@ struct io_plugin {
sudo_printf_t plugin_printf, char * const settings[], sudo_printf_t plugin_printf, char * const settings[],
char * const user_info[], char * const command_info[], char * const user_info[], char * const command_info[],
int argc, char * const argv[], char * const user_env[], int argc, char * const argv[], char * const user_env[],
char * const plugin_options[]); char * const plugin_options[], const char **errstr);
void (*close)(int exit_status, int error); /* wait status or error */ void (*close)(int exit_status, int error); /* wait status or error */
int (*show_version)(int verbose); int (*show_version)(int verbose, const char **errstr);
int (*log_ttyin)(const char *buf, unsigned int len); int (*log_ttyin)(const char *buf, unsigned int len,
int (*log_ttyout)(const char *buf, unsigned int len); const char **errstr);
int (*log_stdin)(const char *buf, unsigned int len); int (*log_ttyout)(const char *buf, unsigned int len,
int (*log_stdout)(const char *buf, unsigned int len); const char **errstr);
int (*log_stderr)(const char *buf, unsigned int len); int (*log_stdin)(const char *buf, unsigned int len,
const char **errstr);
int (*log_stdout)(const char *buf, unsigned int len,
const char **errstr);
int (*log_stderr)(const char *buf, unsigned int len,
const char **errstr);
void (*register_hooks)(int version, void (*register_hooks)(int version,
int (*register_hook)(struct sudo_hook *hook)); int (*register_hook)(struct sudo_hook *hook));
void (*deregister_hooks)(int version, void (*deregister_hooks)(int version,
int (*deregister_hook)(struct sudo_hook *hook)); int (*deregister_hook)(struct sudo_hook *hook));
int (*change_winsize)(unsigned int lines, unsigned int cols); int (*change_winsize)(unsigned int lines, unsigned int cols,
int (*log_suspend)(int signo); const char **errstr);
int (*log_suspend)(int signo, const char **errstr);
struct sudo_plugin_event * (*event_alloc)(void); struct sudo_plugin_event * (*event_alloc)(void);
}; };
.Ed .Ed
@@ -1621,6 +1766,27 @@ by the
front end before using front end before using
.Em plugin_options . .Em plugin_options .
Failure to do so may result in a crash. Failure to do so may result in a crash.
.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 .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El .El
.It close .It close
.Bd -literal -compact .Bd -literal -compact
@@ -1678,14 +1844,43 @@ or
.Fn plugin_printf .Fn plugin_printf
function using function using
.Dv SUDO_CONV_INFO_MSG . .Dv SUDO_CONV_INFO_MSG .
If the user requests detailed version information, the verbose flag will be set.
.Pp .Pp
Returns 1 on success, 0 on failure, \-1 if a general error occurred, Returns 1 on success, 0 on failure, \-1 if a general error occurred,
or \-2 if there was a usage error, although the return value is currently or \-2 if there was a usage error, although the return value is currently
ignored. ignored.
.Pp
The function arguments are as follows:
.Bl -tag -width 4n
.It verbose
If the user requests detailed version information, the
.Em verbose
flag will be set to 1.
.It errstr
If the
.Fn show_version
function returns a value other than 1, the plugin may
store a message describing the failure or error in
.Em errstr .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El
.It log_ttyin .It log_ttyin
.Bd -literal -compact .Bd -literal -compact
int (*log_ttyin)(const char *buf, unsigned int len); int (*log_ttyin)(const char *buf, unsigned int len,
const char **errstr);
.Ed .Ed
.Pp .Pp
The The
@@ -1706,10 +1901,32 @@ The buffer containing user input.
The length of The length of
.Em buf .Em buf
in bytes. in bytes.
.It errstr
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 .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El .El
.It log_ttyout .It log_ttyout
.Bd -literal -compact .Bd -literal -compact
int (*log_ttyout)(const char *buf, unsigned int len); int (*log_ttyout)(const char *buf, unsigned int len,
const char **errstr);
.Ed .Ed
.Pp .Pp
The The
@@ -1729,10 +1946,32 @@ The buffer containing command output.
The length of The length of
.Em buf .Em buf
in bytes. in bytes.
.It errstr
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 .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El .El
.It log_stdin .It log_stdin
.Bd -literal -compact .Bd -literal -compact
int (*log_stdin)(const char *buf, unsigned int len); int (*log_stdin)(const char *buf, unsigned int len,
const char **errstr);
.Ed .Ed
.Pp .Pp
The The
@@ -1754,10 +1993,32 @@ The buffer containing user input.
The length of The length of
.Em buf .Em buf
in bytes. in bytes.
.It errstr
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 .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El .El
.It log_stdout .It log_stdout
.Bd -literal -compact .Bd -literal -compact
int (*log_stdout)(const char *buf, unsigned int len); int (*log_stdout)(const char *buf, unsigned int len,
const char **errstr);
.Ed .Ed
.Pp .Pp
The The
@@ -1779,10 +2040,32 @@ The buffer containing command output.
The length of The length of
.Em buf .Em buf
in bytes. in bytes.
.It errstr
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 .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El .El
.It log_stderr .It log_stderr
.Bd -literal -compact .Bd -literal -compact
int (*log_stderr)(const char *buf, unsigned int len); int (*log_stderr)(const char *buf, unsigned int len,
const char **errstr);
.Ed .Ed
.Pp .Pp
The The
@@ -1804,6 +2087,27 @@ The buffer containing command output.
The length of The length of
.Em buf .Em buf
in bytes. in bytes.
.It errstr
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 .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El .El
.It register_hooks .It register_hooks
See the See the
@@ -1817,7 +2121,8 @@ section for a description of
.Li deregister_hooks . .Li deregister_hooks .
.It change_winsize .It change_winsize
.Bd -literal -compact .Bd -literal -compact
int (*change_winsize)(unsigned int lines, unsigned int cols); int (*change_winsize)(unsigned int lines, unsigned int cols,
const char **errstr);
.Ed .Ed
.Pp .Pp
The The
@@ -1829,24 +2134,76 @@ list.
Returns \-1 if an error occurred, in which case no further calls to Returns \-1 if an error occurred, in which case no further calls to
.Fn change_winsize .Fn change_winsize
will be made, will be made,
.Pp
The function arguments are as follows:
.Bl -tag -width 4n
.It lines
The number of lines (rows) in the resized terminal.
.It cols
The number of columns in the resized terminal.
.It errstr
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 .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.El
.It log_suspend .It log_suspend
.Bd -literal -compact .Bd -literal -compact
int (*log_suspend)(int signo); int (*log_suspend)(int signo, const char **errstr);
.Ed .Ed
.Pp .Pp
The The
.Fn log_suspend .Fn log_suspend
function is called whenever a command is suspended or resumed. function is called whenever a command is suspended or resumed.
The
.Fa signo
argument is either the signal that caused the command to be suspended or
.Dv SIGCONT
if the command was resumed.
Logging this information makes it possible to skip the period of time when Logging this information makes it possible to skip the period of time when
the command was suspended during playback of a session. the command was suspended during playback of a session.
Returns \-1 if an error occurred, in which case no further calls to Returns \-1 if an error occurred, in which case no further calls to
.Fn log_suspend .Fn log_suspend
will be made, will be made,
.Pp
The function arguments are as follows:
.Bl -tag -width 4n
.It signo
The signal that caused the command to be suspended, or
.Dv SIGCONT
if the command was resumed.
.It errstr
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 .
The
.Nm sudo
front end will then pass this value to any registered audit plugins.
.Pp
NOTE: the
.Em errstr
parameter is only available starting with
API version 1.15.
A plugin
.Sy must
check the API version specified by the
.Nm sudo
front end before using
.Em errstr .
Failure to do so may result in a crash.
.It event_alloc .It event_alloc
.Bd -literal -compact .Bd -literal -compact
struct sudo_plugin_event * (*event_alloc)(void); struct sudo_plugin_event * (*event_alloc)(void);
@@ -2930,6 +3287,13 @@ The
field was added to the policy_plugin and io_plugin structs. field was added to the policy_plugin and io_plugin structs.
.Pp .Pp
The The
.Fa errstr
argument was added to the policy and I/O plugin functions
which the plugin function can use to return an error string.
This string may be used by the audit plugin to report failure or
error conditions set by the other plugins.
.Pp
The
.Fn close .Fn close
function is now is called regardless of whether or not a command function is now is called regardless of whether or not a command
was actually executed. was actually executed.

View File

@@ -1,7 +1,7 @@
/* /*
* SPDX-License-Identifier: ISC * SPDX-License-Identifier: ISC
* *
* Copyright (c) 2009-2018 Todd C. Miller <Todd.Miller@sudo.ws> * Copyright (c) 2009-2020 Todd C. Miller <Todd.Miller@sudo.ws>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -162,17 +162,18 @@ struct policy_plugin {
int (*open)(unsigned int version, sudo_conv_t conversation, int (*open)(unsigned int version, sudo_conv_t conversation,
sudo_printf_t sudo_printf, char * const settings[], sudo_printf_t sudo_printf, char * const settings[],
char * const user_info[], char * const user_env[], char * const user_info[], char * const user_env[],
char * const plugin_options[]); char * const plugin_options[], const char **errstr);
void (*close)(int exit_status, int error); /* wait status or error */ void (*close)(int exit_status, int error); /* wait status or error */
int (*show_version)(int verbose); int (*show_version)(int verbose);
int (*check_policy)(int argc, char * const argv[], int (*check_policy)(int argc, char * const argv[],
char *env_add[], char **command_info[], char *env_add[], char **command_info[],
char **argv_out[], char **user_env_out[]); char **argv_out[], char **user_env_out[], const char **errstr);
int (*list)(int argc, char * const argv[], int verbose, int (*list)(int argc, char * const argv[], int verbose,
const char *list_user); const char *list_user, const char **errstr);
int (*validate)(void); int (*validate)(const char **errstr);
void (*invalidate)(int remove); void (*invalidate)(int remove);
int (*init_session)(struct passwd *pwd, char **user_env_out[]); int (*init_session)(struct passwd *pwd, char **user_env_out[],
const char **errstr);
void (*register_hooks)(int version, int (*register_hook)(struct sudo_hook *hook)); void (*register_hooks)(int version, int (*register_hook)(struct sudo_hook *hook));
void (*deregister_hooks)(int version, int (*deregister_hook)(struct sudo_hook *hook)); void (*deregister_hooks)(int version, int (*deregister_hook)(struct sudo_hook *hook));
struct sudo_plugin_event * (*event_alloc)(void); struct sudo_plugin_event * (*event_alloc)(void);
@@ -187,19 +188,47 @@ struct io_plugin {
sudo_printf_t sudo_printf, char * const settings[], sudo_printf_t sudo_printf, char * const settings[],
char * const user_info[], char * const command_info[], char * const user_info[], char * const command_info[],
int argc, char * const argv[], char * const user_env[], int argc, char * const argv[], char * const user_env[],
char * const plugin_options[]); char * const plugin_options[], const char **errstr);
void (*close)(int exit_status, int error); /* wait status or error */ void (*close)(int exit_status, int error); /* wait status or error */
int (*show_version)(int verbose); int (*show_version)(int verbose);
int (*log_ttyin)(const char *buf, unsigned int len); int (*log_ttyin)(const char *buf, unsigned int len, const char **errstr);
int (*log_ttyout)(const char *buf, unsigned int len); int (*log_ttyout)(const char *buf, unsigned int len, const char **errstr);
int (*log_stdin)(const char *buf, unsigned int len); int (*log_stdin)(const char *buf, unsigned int len, const char **errstr);
int (*log_stdout)(const char *buf, unsigned int len); int (*log_stdout)(const char *buf, unsigned int len, const char **errstr);
int (*log_stderr)(const char *buf, unsigned int len); int (*log_stderr)(const char *buf, unsigned int len, const char **errstr);
void (*register_hooks)(int version,
int (*register_hook)(struct sudo_hook *hook));
void (*deregister_hooks)(int version,
int (*deregister_hook)(struct sudo_hook *hook));
int (*change_winsize)(unsigned int line, unsigned int cols,
const char **errstr);
int (*log_suspend)(int signo, const char **errstr);
struct sudo_plugin_event * (*event_alloc)(void);
};
/* Audit plugin type and defines */
struct audit_plugin {
#define SUDO_AUDIT_PLUGIN 3
unsigned int type; /* always SUDO_AUDIT_PLUGIN */
unsigned int version; /* always SUDO_API_VERSION */
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 plugin_options[], const char **errstr);
void (*close)(int exit_status, int error);
int (*accept)(const char *plugin_name, unsigned int plugin_type,
char * const command_info[], char * const run_argv[],
char * const run_envp[], const char **errstr);
int (*reject)(const char *plugin_name, unsigned int plugin_type,
const char *audit_msg, char * const command_info[],
const char **errstr);
int (*error)(const char *plugin_name, unsigned int plugin_type,
const char *audit_msg, char * const command_info[],
const char **errstr);
int (*show_version)(int verbose);
void (*register_hooks)(int version, int (*register_hook)(struct sudo_hook *hook)); void (*register_hooks)(int version, int (*register_hook)(struct sudo_hook *hook));
void (*deregister_hooks)(int version, int (*deregister_hook)(struct sudo_hook *hook)); void (*deregister_hooks)(int version, int (*deregister_hook)(struct sudo_hook *hook));
int (*change_winsize)(unsigned int line, unsigned int cols);
int (*log_suspend)(int signo);
struct sudo_plugin_event * (*event_alloc)(void);
}; };
/* Sudoers group plugin version major/minor */ /* Sudoers group plugin version major/minor */

View File

@@ -201,6 +201,7 @@ static bool
log_ttyin(const char *buf, unsigned int n, struct io_buffer *iob) log_ttyin(const char *buf, unsigned int n, struct io_buffer *iob)
{ {
struct plugin_container *plugin; struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask; sigset_t omask;
bool ret = true; bool ret = true;
debug_decl(log_ttyin, SUDO_DEBUG_EXEC); debug_decl(log_ttyin, SUDO_DEBUG_EXEC);
@@ -211,11 +212,17 @@ log_ttyin(const char *buf, unsigned int n, struct io_buffer *iob)
int rc; int rc;
sudo_debug_set_active_instance(plugin->debug_instance); sudo_debug_set_active_instance(plugin->debug_instance);
rc = plugin->u.io->log_ttyin(buf, n); rc = plugin->u.io->log_ttyin(buf, n, &errstr);
if (rc <= 0) { if (rc <= 0) {
if (rc < 0) { if (rc < 0) {
/* Error: disable plugin's I/O function. */ /* Error: disable plugin's I/O function. */
plugin->u.io->log_ttyin = NULL; plugin->u.io->log_ttyin = NULL;
audit_error(plugin->name, SUDO_IO_PLUGIN,
errstr ? errstr : _("I/O plugin error"), NULL);
} else {
audit_reject(plugin->name, SUDO_IO_PLUGIN,
errstr ? errstr : _("command rejected by I/O plugin"),
NULL);
} }
ret = false; ret = false;
break; break;
@@ -233,6 +240,7 @@ static bool
log_stdin(const char *buf, unsigned int n, struct io_buffer *iob) log_stdin(const char *buf, unsigned int n, struct io_buffer *iob)
{ {
struct plugin_container *plugin; struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask; sigset_t omask;
bool ret = true; bool ret = true;
debug_decl(log_stdin, SUDO_DEBUG_EXEC); debug_decl(log_stdin, SUDO_DEBUG_EXEC);
@@ -243,11 +251,17 @@ log_stdin(const char *buf, unsigned int n, struct io_buffer *iob)
int rc; int rc;
sudo_debug_set_active_instance(plugin->debug_instance); sudo_debug_set_active_instance(plugin->debug_instance);
rc = plugin->u.io->log_stdin(buf, n); rc = plugin->u.io->log_stdin(buf, n, &errstr);
if (rc <= 0) { if (rc <= 0) {
if (rc < 0) { if (rc < 0) {
/* Error: disable plugin's I/O function. */ /* Error: disable plugin's I/O function. */
plugin->u.io->log_stdin = NULL; plugin->u.io->log_stdin = NULL;
audit_error(plugin->name, SUDO_IO_PLUGIN,
errstr ? errstr : _("I/O plugin error"), NULL);
} else {
audit_reject(plugin->name, SUDO_IO_PLUGIN,
errstr ? errstr : _("command rejected by I/O plugin"),
NULL);
} }
ret = false; ret = false;
break; break;
@@ -265,6 +279,7 @@ static bool
log_ttyout(const char *buf, unsigned int n, struct io_buffer *iob) log_ttyout(const char *buf, unsigned int n, struct io_buffer *iob)
{ {
struct plugin_container *plugin; struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask; sigset_t omask;
bool ret = true; bool ret = true;
debug_decl(log_ttyout, SUDO_DEBUG_EXEC); debug_decl(log_ttyout, SUDO_DEBUG_EXEC);
@@ -275,11 +290,17 @@ log_ttyout(const char *buf, unsigned int n, struct io_buffer *iob)
int rc; int rc;
sudo_debug_set_active_instance(plugin->debug_instance); sudo_debug_set_active_instance(plugin->debug_instance);
rc = plugin->u.io->log_ttyout(buf, n); rc = plugin->u.io->log_ttyout(buf, n, &errstr);
if (rc <= 0) { if (rc <= 0) {
if (rc < 0) { if (rc < 0) {
/* Error: disable plugin's I/O function. */ /* Error: disable plugin's I/O function. */
plugin->u.io->log_ttyout = NULL; plugin->u.io->log_ttyout = NULL;
audit_error(plugin->name, SUDO_IO_PLUGIN,
errstr ? errstr : _("I/O plugin error"), NULL);
} else {
audit_reject(plugin->name, SUDO_IO_PLUGIN,
errstr ? errstr : _("command rejected by I/O plugin"),
NULL);
} }
ret = false; ret = false;
break; break;
@@ -308,6 +329,7 @@ static bool
log_stdout(const char *buf, unsigned int n, struct io_buffer *iob) log_stdout(const char *buf, unsigned int n, struct io_buffer *iob)
{ {
struct plugin_container *plugin; struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask; sigset_t omask;
bool ret = true; bool ret = true;
debug_decl(log_stdout, SUDO_DEBUG_EXEC); debug_decl(log_stdout, SUDO_DEBUG_EXEC);
@@ -318,11 +340,17 @@ log_stdout(const char *buf, unsigned int n, struct io_buffer *iob)
int rc; int rc;
sudo_debug_set_active_instance(plugin->debug_instance); sudo_debug_set_active_instance(plugin->debug_instance);
rc = plugin->u.io->log_stdout(buf, n); rc = plugin->u.io->log_stdout(buf, n, &errstr);
if (rc <= 0) { if (rc <= 0) {
if (rc < 0) { if (rc < 0) {
/* Error: disable plugin's I/O function. */ /* Error: disable plugin's I/O function. */
plugin->u.io->log_stdout = NULL; plugin->u.io->log_stdout = NULL;
audit_error(plugin->name, SUDO_IO_PLUGIN,
errstr ? errstr : _("I/O plugin error"), NULL);
} else {
audit_reject(plugin->name, SUDO_IO_PLUGIN,
errstr ? errstr : _("command rejected by I/O plugin"),
NULL);
} }
ret = false; ret = false;
break; break;
@@ -351,6 +379,7 @@ static bool
log_stderr(const char *buf, unsigned int n, struct io_buffer *iob) log_stderr(const char *buf, unsigned int n, struct io_buffer *iob)
{ {
struct plugin_container *plugin; struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask; sigset_t omask;
bool ret = true; bool ret = true;
debug_decl(log_stderr, SUDO_DEBUG_EXEC); debug_decl(log_stderr, SUDO_DEBUG_EXEC);
@@ -361,11 +390,17 @@ log_stderr(const char *buf, unsigned int n, struct io_buffer *iob)
int rc; int rc;
sudo_debug_set_active_instance(plugin->debug_instance); sudo_debug_set_active_instance(plugin->debug_instance);
rc = plugin->u.io->log_stderr(buf, n); rc = plugin->u.io->log_stderr(buf, n, &errstr);
if (rc <= 0) { if (rc <= 0) {
if (rc < 0) { if (rc < 0) {
/* Error: disable plugin's I/O function. */ /* Error: disable plugin's I/O function. */
plugin->u.io->log_stderr = NULL; plugin->u.io->log_stderr = NULL;
audit_error(plugin->name, SUDO_IO_PLUGIN,
errstr ? errstr : _("I/O plugin error"), NULL);
} else {
audit_reject(plugin->name, SUDO_IO_PLUGIN,
errstr ? errstr : _("command rejected by I/O plugin"),
NULL);
} }
ret = false; ret = false;
break; break;
@@ -394,6 +429,7 @@ static void
log_suspend(int signo) log_suspend(int signo)
{ {
struct plugin_container *plugin; struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask; sigset_t omask;
debug_decl(log_suspend, SUDO_DEBUG_EXEC); debug_decl(log_suspend, SUDO_DEBUG_EXEC);
@@ -405,12 +441,12 @@ log_suspend(int signo)
int rc; int rc;
sudo_debug_set_active_instance(plugin->debug_instance); sudo_debug_set_active_instance(plugin->debug_instance);
rc = plugin->u.io->log_suspend(signo); rc = plugin->u.io->log_suspend(signo, &errstr);
if (rc <= 0) { if (rc <= 0) {
if (rc < 0) { /* Error: disable plugin's I/O function. */
/* Error: disable plugin's I/O function. */ plugin->u.io->log_suspend = NULL;
plugin->u.io->log_suspend = NULL; audit_error(plugin->name, SUDO_IO_PLUGIN,
} errstr ? errstr : _("error logging suspend"), NULL);
break; break;
} }
} }
@@ -426,6 +462,7 @@ static void
log_winchange(unsigned int rows, unsigned int cols) log_winchange(unsigned int rows, unsigned int cols)
{ {
struct plugin_container *plugin; struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask; sigset_t omask;
debug_decl(log_winchange, SUDO_DEBUG_EXEC); debug_decl(log_winchange, SUDO_DEBUG_EXEC);
@@ -437,12 +474,12 @@ log_winchange(unsigned int rows, unsigned int cols)
int rc; int rc;
sudo_debug_set_active_instance(plugin->debug_instance); sudo_debug_set_active_instance(plugin->debug_instance);
rc = plugin->u.io->change_winsize(rows, cols); rc = plugin->u.io->change_winsize(rows, cols, &errstr);
if (rc <= 0) { if (rc <= 0) {
if (rc < 0) { /* Error: disable plugin's I/O function. */
/* Error: disable plugin's I/O function. */ plugin->u.io->change_winsize = NULL;
plugin->u.io->change_winsize = NULL; audit_error(plugin->name, SUDO_IO_PLUGIN,
} errstr ? errstr : _("error changing window size"), NULL);
break; break;
} }
} }

View File

@@ -242,7 +242,8 @@ cleanup:
*/ */
static bool static bool
sudo_load_plugin(struct plugin_container *policy_plugin, sudo_load_plugin(struct plugin_container *policy_plugin,
struct plugin_container_list *io_plugins, struct plugin_info *info) struct plugin_container_list *io_plugins,
struct plugin_container_list *audit_plugins, struct plugin_info *info)
{ {
struct plugin_container *container = NULL; struct plugin_container *container = NULL;
struct generic_plugin *plugin; struct generic_plugin *plugin;
@@ -315,6 +316,20 @@ sudo_load_plugin(struct plugin_container *policy_plugin,
goto done; goto done;
TAILQ_INSERT_TAIL(io_plugins, container, entries); TAILQ_INSERT_TAIL(io_plugins, container, entries);
break; break;
case SUDO_AUDIT_PLUGIN:
if (plugin_exists(audit_plugins, info)) {
plugin = sudo_plugin_try_to_clone(handle, info->symbol_name);
if (plugin == NULL) {
sudo_warnx(U_("ignoring duplicate audit plugin \"%s\" in %s, line %d"),
info->symbol_name, _PATH_SUDO_CONF, info->lineno);
ret = true;
goto done;
}
}
if ((container = new_container(handle, path, plugin, info)) == NULL)
goto done;
TAILQ_INSERT_TAIL(audit_plugins, container, entries);
break;
default: default:
sudo_warnx(U_("error in %s, line %d while loading plugin \"%s\""), sudo_warnx(U_("error in %s, line %d while loading plugin \"%s\""),
_PATH_SUDO_CONF, info->lineno, info->symbol_name); _PATH_SUDO_CONF, info->lineno, info->symbol_name);
@@ -354,7 +369,8 @@ free_plugin_info(struct plugin_info *info)
*/ */
bool bool
sudo_load_plugins(struct plugin_container *policy_plugin, sudo_load_plugins(struct plugin_container *policy_plugin,
struct plugin_container_list *io_plugins) struct plugin_container_list *io_plugins,
struct plugin_container_list *audit_plugins)
{ {
struct plugin_container *container; struct plugin_container *container;
struct plugin_info_list *plugins; struct plugin_info_list *plugins;
@@ -365,7 +381,7 @@ sudo_load_plugins(struct plugin_container *policy_plugin,
/* Walk the plugin list from sudo.conf, if any and free it. */ /* Walk the plugin list from sudo.conf, if any and free it. */
plugins = sudo_conf_plugins(); plugins = sudo_conf_plugins();
TAILQ_FOREACH_SAFE(info, plugins, entries, next) { TAILQ_FOREACH_SAFE(info, plugins, entries, next) {
ret = sudo_load_plugin(policy_plugin, io_plugins, info); ret = sudo_load_plugin(policy_plugin, io_plugins, audit_plugins, info);
if (!ret) if (!ret)
goto done; goto done;
free_plugin_info(info); free_plugin_info(info);
@@ -391,7 +407,7 @@ sudo_load_plugins(struct plugin_container *policy_plugin,
goto done; goto done;
} }
/* info->options = NULL; */ /* info->options = NULL; */
ret = sudo_load_plugin(policy_plugin, io_plugins, info); ret = sudo_load_plugin(policy_plugin, io_plugins, audit_plugins, info);
free_plugin_info(info); free_plugin_info(info);
if (!ret) if (!ret)
goto done; goto done;
@@ -411,7 +427,7 @@ sudo_load_plugins(struct plugin_container *policy_plugin,
goto done; goto done;
} }
/* info->options = NULL; */ /* info->options = NULL; */
ret = sudo_load_plugin(policy_plugin, io_plugins, info); ret = sudo_load_plugin(policy_plugin, io_plugins, audit_plugins, info);
free_plugin_info(info); free_plugin_info(info);
if (!ret) if (!ret)
goto done; goto done;

View File

@@ -240,7 +240,7 @@ parse_env_list(struct environment *e, char *list)
* for the command to be run (if we are running one). * for the command to be run (if we are running one).
*/ */
int int
parse_args(int argc, char **argv, int *nargc, char ***nargv, parse_args(int argc, char **argv, int *old_optind, int *nargc, char ***nargv,
struct sudo_settings **settingsp, char ***env_addp) struct sudo_settings **settingsp, char ***env_addp)
{ {
struct environment extra_env; struct environment extra_env;
@@ -501,6 +501,7 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv,
argc -= optind; argc -= optind;
argv += optind; argv += optind;
*old_optind = optind;
if (!mode) { if (!mode) {
/* Defer -k mode setting until we know whether it is a flag or not */ /* Defer -k mode setting until we know whether it is a flag or not */
@@ -617,12 +618,29 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv,
argc = ac; argc = ac;
} }
/*
* For sudoedit we need to rewrite argv
*/
if (mode == MODE_EDIT) { if (mode == MODE_EDIT) {
#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID)
char **av;
int ac;
av = reallocarray(NULL, argc + 2, sizeof(char *));
if (av == NULL)
sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
if (!gc_add(GC_PTR, av))
exit(1);
/* Must have the command in argv[0]. */ /* Must have the command in argv[0]. */
argc++; av[0] = "sudoedit";
argv--; for (ac = 0; argv[ac] != NULL; ac++) {
argv[0] = "sudoedit"; av[ac + 1] = argv[ac];
}
av[++ac] = NULL;
argv = av;
argc = ac;
#else #else
sudo_fatalx(U_("sudoedit is not supported on this platform")); sudo_fatalx(U_("sudoedit is not supported on this platform"));
#endif #endif

View File

@@ -1,7 +1,7 @@
/* /*
* SPDX-License-Identifier: ISC * SPDX-License-Identifier: ISC
* *
* Copyright (c) 2009-2019 Todd C. Miller <Todd.Miller@sudo.ws> * Copyright (c) 2009-2020 Todd C. Miller <Todd.Miller@sudo.ws>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -75,6 +75,7 @@
*/ */
struct plugin_container policy_plugin; struct plugin_container policy_plugin;
struct plugin_container_list io_plugins = TAILQ_HEAD_INITIALIZER(io_plugins); struct plugin_container_list io_plugins = TAILQ_HEAD_INITIALIZER(io_plugins);
struct plugin_container_list audit_plugins = TAILQ_HEAD_INITIALIZER(audit_plugins);
struct user_details user_details; struct user_details user_details;
const char *list_user; /* extern for parse_args.c */ const char *list_user; /* extern for parse_args.c */
int sudo_debug_instance = SUDO_DEBUG_INSTANCE_INITIALIZER; int sudo_debug_instance = SUDO_DEBUG_INSTANCE_INITIALIZER;
@@ -106,15 +107,15 @@ static void command_info_to_details(char * const info[],
static void gc_init(void); static void gc_init(void);
/* Policy plugin convenience functions. */ /* Policy plugin convenience functions. */
static int policy_open(struct sudo_settings *settings, static void policy_open(struct sudo_settings *settings,
char * const user_info[], char * const user_env[]); char * const user_info[], char * const user_env[]);
static void policy_close(int exit_status, int error); static void policy_close(int exit_status, int error);
static int policy_show_version(int verbose); static int policy_show_version(int verbose);
static int policy_check(int argc, char * const argv[], char *env_add[], static void policy_check(int argc, char * const argv[], char *env_add[],
char **command_info[], char **argv_out[], char **user_env_out[]); char **command_info[], char **argv_out[], char **user_env_out[]);
static int policy_list(int argc, char * const argv[], int verbose, static void policy_list(int argc, char * const argv[],
const char *list_user); int verbose, const char *list_user, char * const envp[]);
static int policy_validate(void); static void policy_validate(char * const argv[], char * const envp[]);
static void policy_invalidate(int remove); static void policy_invalidate(int remove);
/* I/O log plugin convenience functions. */ /* I/O log plugin convenience functions. */
@@ -125,18 +126,28 @@ static void iolog_close(int exit_status, int error);
static void iolog_show_version(int verbose, struct sudo_settings *settings, static void iolog_show_version(int verbose, struct sudo_settings *settings,
char * const user_info[], int argc, char * const argv[], char * const user_info[], int argc, char * const argv[],
char * const user_env[]); char * const user_env[]);
static void iolog_unlink(struct plugin_container *plugin); static void unlink_plugin(struct plugin_container_list *plugin_list, struct plugin_container *plugin);
static void free_plugin_container(struct plugin_container *plugin, bool ioplugin); static void free_plugin_container(struct plugin_container *plugin, bool ioplugin);
/* Audit plugin convenience functions. */
static void audit_open(struct sudo_settings *settings, char * const user_info[],
int submit_optind, char * const submit_argv[], char * const submit_envp[]);
static void audit_close(int exit_status, int error);
static void audit_show_version(int verbose);
static void audit_accept(const char *plugin_name,
unsigned int plugin_type, char * const command_info[],
char * const run_argv[], char * const run_envp[]);
__dso_public int main(int argc, char *argv[], char *envp[]); __dso_public int main(int argc, char *argv[], char *envp[]);
int int
main(int argc, char *argv[], char *envp[]) main(int argc, char *argv[], char *envp[])
{ {
int nargc, ok, status = 0; int nargc, status = 0;
char **nargv, **env_add; char **nargv, **env_add, **user_info;
char **user_info, **command_info, **argv_out, **user_env_out; char **command_info = NULL, **argv_out = NULL, **user_env_out = NULL;
struct sudo_settings *settings; struct sudo_settings *settings;
int submit_optind;
sigset_t mask; sigset_t mask;
debug_decl_vars(main, SUDO_DEBUG_MAIN); debug_decl_vars(main, SUDO_DEBUG_MAIN);
@@ -194,7 +205,8 @@ main(int argc, char *argv[], char *envp[])
disable_coredump(); disable_coredump();
/* Parse command line arguments. */ /* Parse command line arguments. */
sudo_mode = parse_args(argc, argv, &nargc, &nargv, &settings, &env_add); sudo_mode = parse_args(argc, argv, &submit_optind, &nargc, &nargv,
&settings, &env_add);
sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_mode %d", sudo_mode); sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_mode %d", sudo_mode);
/* Print sudo version early, in case of plugin init failure. */ /* Print sudo version early, in case of plugin init failure. */
@@ -208,54 +220,44 @@ main(int argc, char *argv[], char *envp[])
sudo_warn_set_conversation(sudo_conversation); sudo_warn_set_conversation(sudo_conversation);
/* Load plugins. */ /* Load plugins. */
if (!sudo_load_plugins(&policy_plugin, &io_plugins)) if (!sudo_load_plugins(&policy_plugin, &io_plugins, &audit_plugins))
sudo_fatalx(U_("fatal error, unable to load plugins")); sudo_fatalx(U_("fatal error, unable to load plugins"));
/* Allocate event base so plugin can use it. */ /* Allocate event base so plugin can use it. */
if ((sudo_event_base = sudo_ev_base_alloc()) == NULL) if ((sudo_event_base = sudo_ev_base_alloc()) == NULL)
sudo_fatalx("%s", U_("unable to allocate memory")); sudo_fatalx("%s", U_("unable to allocate memory"));
/* Open policy plugin. */ /* Open policy and audit plugins. */
ok = policy_open(settings, user_info, envp); /* XXX - audit policy_open errors */
if (ok != 1) { audit_open(settings, user_info, submit_optind, argv, envp);
if (ok == -2) policy_open(settings, user_info, envp);
usage(1);
else
sudo_fatalx(U_("unable to initialize policy plugin"));
}
switch (sudo_mode & MODE_MASK) { switch (sudo_mode & MODE_MASK) {
case MODE_VERSION: case MODE_VERSION:
policy_show_version(!user_details.uid); policy_show_version(!user_details.uid);
iolog_show_version(!user_details.uid, settings, user_info, iolog_show_version(!user_details.uid, settings, user_info,
nargc, nargv, envp); nargc, nargv, envp);
audit_show_version(!user_details.uid);
break; break;
case MODE_VALIDATE: case MODE_VALIDATE:
case MODE_VALIDATE|MODE_INVALIDATE: case MODE_VALIDATE|MODE_INVALIDATE:
ok = policy_validate(); policy_validate(nargv, envp);
exit(ok != 1); break;
case MODE_KILL: case MODE_KILL:
case MODE_INVALIDATE: case MODE_INVALIDATE:
policy_invalidate(sudo_mode == MODE_KILL); policy_invalidate(sudo_mode == MODE_KILL);
exit(0);
break; break;
case MODE_CHECK: case MODE_CHECK:
case MODE_CHECK|MODE_INVALIDATE: case MODE_CHECK|MODE_INVALIDATE:
case MODE_LIST: case MODE_LIST:
case MODE_LIST|MODE_INVALIDATE: case MODE_LIST|MODE_INVALIDATE:
ok = policy_list(nargc, nargv, ISSET(sudo_mode, MODE_LONG_LIST), policy_list(nargc, nargv, ISSET(sudo_mode, MODE_LONG_LIST),
list_user); list_user, envp);
exit(ok != 1); break;
case MODE_EDIT: case MODE_EDIT:
case MODE_RUN: case MODE_RUN:
ok = policy_check(nargc, nargv, env_add, &command_info, &argv_out, policy_check(nargc, nargv, env_add, &command_info, &argv_out,
&user_env_out); &user_env_out);
sudo_debug_printf(SUDO_DEBUG_INFO, "policy plugin returns %d", ok);
if (ok != 1) {
if (ok == -2)
usage(1);
exit(EXIT_FAILURE); /* plugin printed error message */
}
/* Reset nargv/nargc based on argv_out. */ /* Reset nargv/nargc based on argv_out. */
/* XXX - leaks old nargv in shell mode */ /* XXX - leaks old nargv in shell mode */
@@ -264,10 +266,14 @@ main(int argc, char *argv[], char *envp[])
if (nargc == 0) if (nargc == 0)
sudo_fatalx(U_("plugin did not return a command to execute")); sudo_fatalx(U_("plugin did not return a command to execute"));
/* Open I/O plugins once policy plugin succeeds. */ /* Open I/O plugin once policy plugin succeeds. */
iolog_open(settings, user_info, command_info, nargc, nargv, iolog_open(settings, user_info, command_info, nargc, nargv,
user_env_out); user_env_out);
/* Audit command we are going to run. */
audit_accept(policy_plugin.name, SUDO_POLICY_PLUGIN, command_info,
nargv, user_env_out);
/* Setup command details and run command/edit. */ /* Setup command details and run command/edit. */
command_info_to_details(command_info, &command_details); command_info_to_details(command_info, &command_details);
command_details.tty = user_details.tty; command_details.tty = user_details.tty;
@@ -941,6 +947,7 @@ run_command(struct command_details *details)
/* exec_setup() or execve() returned an error. */ /* exec_setup() or execve() returned an error. */
policy_close(0, cstat.val); policy_close(0, cstat.val);
iolog_close(0, cstat.val); iolog_close(0, cstat.val);
audit_close(0, cstat.val);
break; break;
case CMD_WSTATUS: case CMD_WSTATUS:
/* Command ran, exited or was killed. */ /* Command ran, exited or was killed. */
@@ -951,6 +958,7 @@ run_command(struct command_details *details)
#endif #endif
policy_close(status, 0); policy_close(status, 0);
iolog_close(status, 0); iolog_close(status, 0);
audit_close(status, 0);
break; break;
default: default:
sudo_warnx(U_("unexpected child termination condition: %d"), cstat.type); sudo_warnx(U_("unexpected child termination condition: %d"), cstat.type);
@@ -1022,20 +1030,19 @@ bad:
debug_return_ptr(NULL); debug_return_ptr(NULL);
} }
static int static void
policy_open(struct sudo_settings *settings, char * const user_info[], policy_open(struct sudo_settings *settings, char * const user_info[],
char * const user_env[]) char * const user_env[])
{ {
char **plugin_settings; char **plugin_settings;
int ret; const char *errstr = NULL;
int ok;
debug_decl(policy_open, SUDO_DEBUG_PCOMM); debug_decl(policy_open, SUDO_DEBUG_PCOMM);
/* Convert struct sudo_settings to plugin_settings[] */ /* Convert struct sudo_settings to plugin_settings[] */
plugin_settings = format_plugin_settings(&policy_plugin, settings); plugin_settings = format_plugin_settings(&policy_plugin, settings);
if (plugin_settings == NULL) { if (plugin_settings == NULL)
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
debug_return_int(-1);
}
/* /*
* Backwards compatibility for older API versions * Backwards compatibility for older API versions
@@ -1044,21 +1051,30 @@ policy_open(struct sudo_settings *settings, char * const user_info[],
switch (policy_plugin.u.generic->version) { switch (policy_plugin.u.generic->version) {
case SUDO_API_MKVERSION(1, 0): case SUDO_API_MKVERSION(1, 0):
case SUDO_API_MKVERSION(1, 1): case SUDO_API_MKVERSION(1, 1):
ret = policy_plugin.u.policy_1_0->open(policy_plugin.u.io_1_0->version, ok = policy_plugin.u.policy_1_0->open(policy_plugin.u.io_1_0->version,
sudo_conversation_1_7, sudo_conversation_printf, plugin_settings, sudo_conversation_1_7, sudo_conversation_printf, plugin_settings,
user_info, user_env); user_info, user_env);
break; break;
default: default:
ret = policy_plugin.u.policy->open(SUDO_API_VERSION, sudo_conversation, ok = policy_plugin.u.policy->open(SUDO_API_VERSION, sudo_conversation,
sudo_conversation_printf, plugin_settings, user_info, user_env, sudo_conversation_printf, plugin_settings, user_info, user_env,
policy_plugin.options); policy_plugin.options, &errstr);
} }
/* Stash plugin debug instance ID if set in open() function. */ /* Stash plugin debug instance ID if set in open() function. */
policy_plugin.debug_instance = sudo_debug_get_active_instance(); policy_plugin.debug_instance = sudo_debug_get_active_instance();
sudo_debug_set_active_instance(sudo_debug_instance); sudo_debug_set_active_instance(sudo_debug_instance);
debug_return_int(ret); if (ok != 1) {
if (ok == -2)
usage(1);
else {
/* XXX - audit */
sudo_fatalx(U_("unable to initialize policy plugin"));
}
}
debug_return;
} }
static void static void
@@ -1083,33 +1099,35 @@ policy_close(int exit_status, int error_code)
errno = error_code; errno = error_code;
sudo_warn(U_("unable to execute %s"), command_details.command); sudo_warn(U_("unable to execute %s"), command_details.command);
} }
debug_return; debug_return;
} }
static int static int
policy_show_version(int verbose) policy_show_version(int verbose)
{ {
int ret; int ret = true;
debug_decl(policy_show_version, SUDO_DEBUG_PCOMM); debug_decl(policy_show_version, SUDO_DEBUG_PCOMM);
if (policy_plugin.u.policy->show_version == NULL)
debug_return_int(true);
sudo_debug_set_active_instance(policy_plugin.debug_instance); sudo_debug_set_active_instance(policy_plugin.debug_instance);
ret = policy_plugin.u.policy->show_version(verbose); if (policy_plugin.u.policy->show_version != NULL)
ret = policy_plugin.u.policy->show_version(verbose);
if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15)) { if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15)) {
if (policy_plugin.u.policy->close != NULL) if (policy_plugin.u.policy->close != NULL)
policy_plugin.u.policy->close(0, 0); policy_plugin.u.policy->close(0, 0);
} }
sudo_debug_set_active_instance(sudo_debug_instance); sudo_debug_set_active_instance(sudo_debug_instance);
debug_return_int(ret); debug_return_int(ret);
} }
static int static void
policy_check(int argc, char * const argv[], policy_check(int argc, char * const argv[],
char *env_add[], char **command_info[], char **argv_out[], char *env_add[], char **command_info[], char **argv_out[],
char **user_env_out[]) char **user_env_out[])
{ {
int ret; const char *errstr = NULL;
int ok;
debug_decl(policy_check, SUDO_DEBUG_PCOMM); debug_decl(policy_check, SUDO_DEBUG_PCOMM);
if (policy_plugin.u.policy->check_policy == NULL) { if (policy_plugin.u.policy->check_policy == NULL) {
@@ -1117,65 +1135,132 @@ policy_check(int argc, char * const argv[],
policy_plugin.name); policy_plugin.name);
} }
sudo_debug_set_active_instance(policy_plugin.debug_instance); sudo_debug_set_active_instance(policy_plugin.debug_instance);
ret = policy_plugin.u.policy->check_policy(argc, argv, env_add, ok = policy_plugin.u.policy->check_policy(argc, argv, env_add,
command_info, argv_out, user_env_out); command_info, argv_out, user_env_out, &errstr);
/* On success, the close method will be called by sudo_edit/run_command. */
if (ret != 1) {
if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15)) {
if (policy_plugin.u.policy->close != NULL)
policy_plugin.u.policy->close(0, 0);
}
}
sudo_debug_set_active_instance(sudo_debug_instance); sudo_debug_set_active_instance(sudo_debug_instance);
debug_return_int(ret); sudo_debug_printf(SUDO_DEBUG_INFO, "policy plugin returns %d (%s)",
ok, errstr ? errstr : "");
/* On success, the close method will be called by sudo_edit/run_command. */
if (ok != 1) {
switch (ok) {
case 0:
audit_reject(policy_plugin.name, SUDO_POLICY_PLUGIN,
errstr ? errstr : _("command rejected by policy"),
*command_info);
break;
case -1:
audit_error(policy_plugin.name, SUDO_POLICY_PLUGIN,
errstr ? errstr : _("policy plugin error"),
*command_info);
break;
case -2:
usage(1);
break;
}
/* Policy must be closed after auditing to avoid use after free. */
if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15))
policy_close(0, 0);
exit(EXIT_FAILURE); /* policy plugin printed error message */
}
debug_return;
} }
static int static void
policy_list(int argc, char * const argv[], int verbose, const char *list_user) policy_list(int argc, char * const argv[], int verbose,
const char *list_user, char * const envp[])
{ {
int ret; const char *errstr = NULL;
/* TODO: add list_user */
char * const command_info[] = {
"command=list",
NULL
};
int ok;
debug_decl(policy_list, SUDO_DEBUG_PCOMM); debug_decl(policy_list, SUDO_DEBUG_PCOMM);
if (policy_plugin.u.policy->list == NULL) { if (policy_plugin.u.policy->list == NULL) {
sudo_warnx(U_("policy plugin %s does not support listing privileges"), sudo_fatalx(U_("policy plugin %s does not support listing privileges"),
policy_plugin.name); policy_plugin.name);
debug_return_int(false);
} }
sudo_debug_set_active_instance(policy_plugin.debug_instance); sudo_debug_set_active_instance(policy_plugin.debug_instance);
ret = policy_plugin.u.policy->list(argc, argv, verbose, list_user); ok = policy_plugin.u.policy->list(argc, argv, verbose, list_user, &errstr);
if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15)) {
if (policy_plugin.u.policy->close != NULL)
policy_plugin.u.policy->close(0, 0);
}
sudo_debug_set_active_instance(sudo_debug_instance); sudo_debug_set_active_instance(sudo_debug_instance);
debug_return_int(ret);
switch (ok) {
case 1:
audit_accept(policy_plugin.name, SUDO_POLICY_PLUGIN,
command_info, argv, envp);
break;
case 0:
audit_reject(policy_plugin.name, SUDO_POLICY_PLUGIN,
errstr ? errstr : _("command rejected by policy"),
command_info);
break;
default:
audit_error(policy_plugin.name, SUDO_POLICY_PLUGIN,
errstr ? errstr : _("policy plugin error"),
command_info);
break;
}
/* Policy must be closed after auditing to avoid use after free. */
if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15))
policy_close(0, 0);
exit(ok != 1);
} }
static int static void
policy_validate(void) policy_validate(char * const argv[], char * const envp[])
{ {
int ret; const char *errstr = NULL;
char * const command_info[] = {
"command=validate",
NULL
};
int ok = 0;
debug_decl(policy_validate, SUDO_DEBUG_PCOMM); debug_decl(policy_validate, SUDO_DEBUG_PCOMM);
if (policy_plugin.u.policy->validate == NULL) { if (policy_plugin.u.policy->validate == NULL) {
sudo_warnx(U_("policy plugin %s does not support the -v option"), sudo_fatalx(U_("policy plugin %s does not support the -v option"),
policy_plugin.name); policy_plugin.name);
debug_return_int(false);
} }
sudo_debug_set_active_instance(policy_plugin.debug_instance); sudo_debug_set_active_instance(policy_plugin.debug_instance);
ret = policy_plugin.u.policy->validate(); ok = policy_plugin.u.policy->validate(&errstr);
if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15)) {
if (policy_plugin.u.policy->close != NULL)
policy_plugin.u.policy->close(0, 0);
}
sudo_debug_set_active_instance(sudo_debug_instance); sudo_debug_set_active_instance(sudo_debug_instance);
debug_return_int(ret);
switch (ok) {
case 1:
audit_accept(policy_plugin.name, SUDO_POLICY_PLUGIN, command_info,
argv, envp);
break;
case 0:
audit_reject(policy_plugin.name, SUDO_POLICY_PLUGIN,
errstr ? errstr : _("command rejected by policy"),
command_info);
break;
default:
audit_error(policy_plugin.name, SUDO_POLICY_PLUGIN,
errstr ? errstr : _("policy plugin error"),
command_info);
break;
}
/* Policy must be closed after auditing to avoid use after free. */
if (policy_plugin.u.policy->version >= SUDO_API_MKVERSION(1, 15))
policy_close(0, 0);
exit(ok != 1);
} }
static void static void
policy_invalidate(int remove) policy_invalidate(int remove)
{ {
debug_decl(policy_invalidate, SUDO_DEBUG_PCOMM); debug_decl(policy_invalidate, SUDO_DEBUG_PCOMM);
if (policy_plugin.u.policy->invalidate == NULL) { if (policy_plugin.u.policy->invalidate == NULL) {
sudo_fatalx(U_("policy plugin %s does not support the -k/-K options"), sudo_fatalx(U_("policy plugin %s does not support the -k/-K options"),
policy_plugin.name); policy_plugin.name);
@@ -1187,12 +1272,14 @@ policy_invalidate(int remove)
policy_plugin.u.policy->close(0, 0); policy_plugin.u.policy->close(0, 0);
} }
sudo_debug_set_active_instance(sudo_debug_instance); sudo_debug_set_active_instance(sudo_debug_instance);
debug_return;
exit(EXIT_SUCCESS);
} }
int int
policy_init_session(struct command_details *details) policy_init_session(struct command_details *details)
{ {
const char *errstr = NULL;
int ret = true; int ret = true;
debug_decl(policy_init_session, SUDO_DEBUG_PCOMM); debug_decl(policy_init_session, SUDO_DEBUG_PCOMM);
@@ -1223,9 +1310,10 @@ policy_init_session(struct command_details *details)
break; break;
default: default:
ret = policy_plugin.u.policy->init_session(details->pw, ret = policy_plugin.u.policy->init_session(details->pw,
&details->envp); &details->envp, &errstr);
} }
sudo_debug_set_active_instance(sudo_debug_instance); sudo_debug_set_active_instance(sudo_debug_instance);
/* TODO: audit on error */
} }
done: done:
debug_return_int(ret); debug_return_int(ret);
@@ -1234,7 +1322,7 @@ done:
static int static int
iolog_open_int(struct plugin_container *plugin, struct sudo_settings *settings, iolog_open_int(struct plugin_container *plugin, struct sudo_settings *settings,
char * const user_info[], char * const command_info[], char * const user_info[], char * const command_info[],
int argc, char * const argv[], char * const user_env[]) int argc, char * const argv[], char * const user_env[], const char **errstr)
{ {
char **plugin_settings; char **plugin_settings;
int ret; int ret;
@@ -1265,7 +1353,7 @@ iolog_open_int(struct plugin_container *plugin, struct sudo_settings *settings,
default: default:
ret = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation, ret = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation,
sudo_conversation_printf, plugin_settings, user_info, command_info, sudo_conversation_printf, plugin_settings, user_info, command_info,
argc, argv, user_env, plugin->options); argc, argv, user_env, plugin->options, errstr);
} }
/* Stash plugin debug instance ID if set in open() function. */ /* Stash plugin debug instance ID if set in open() function. */
@@ -1281,22 +1369,26 @@ iolog_open(struct sudo_settings *settings, char * const user_info[],
char * const user_env[]) char * const user_env[])
{ {
struct plugin_container *plugin, *next; struct plugin_container *plugin, *next;
const char *errstr = NULL;
debug_decl(iolog_open, SUDO_DEBUG_PCOMM); debug_decl(iolog_open, SUDO_DEBUG_PCOMM);
/* XXX - iolog_open should audit errors */
TAILQ_FOREACH_SAFE(plugin, &io_plugins, entries, next) { TAILQ_FOREACH_SAFE(plugin, &io_plugins, entries, next) {
int ok = iolog_open_int(plugin, settings, user_info, int ok = iolog_open_int(plugin, settings, user_info,
command_info, argc, argv, user_env); command_info, argc, argv, user_env, &errstr);
switch (ok) { switch (ok) {
case 1: case 1:
break; break;
case 0: case 0:
/* I/O plugin asked to be disabled, remove and free. */ /* I/O plugin asked to be disabled, remove and free. */
iolog_unlink(plugin); /* XXX - audit */
unlink_plugin(&io_plugins, plugin);
break; break;
case -2: case -2:
usage(1); usage(1);
break; break;
default: default:
/* XXX - audit error */
sudo_fatalx(U_("error initializing I/O plugin %s"), sudo_fatalx(U_("error initializing I/O plugin %s"),
plugin->name); plugin->name);
} }
@@ -1336,23 +1428,24 @@ iolog_show_version(int verbose, struct sudo_settings *settings,
char * const user_info[], int argc, char * const argv[], char * const user_info[], int argc, char * const argv[],
char * const user_env[]) char * const user_env[])
{ {
const char *errstr = NULL;
struct plugin_container *plugin; struct plugin_container *plugin;
debug_decl(iolog_show_version, SUDO_DEBUG_PCOMM); debug_decl(iolog_show_version, SUDO_DEBUG_PCOMM);
TAILQ_FOREACH(plugin, &io_plugins, entries) { TAILQ_FOREACH(plugin, &io_plugins, entries) {
int ok = iolog_open_int(plugin, settings, user_info, NULL, int ok = iolog_open_int(plugin, settings, user_info, NULL,
argc, argv, user_env); argc, argv, user_env, &errstr);
if (ok != -1) { if (ok != -1) {
sudo_debug_set_active_instance(plugin->debug_instance);
if (plugin->u.io->show_version != NULL) { if (plugin->u.io->show_version != NULL) {
sudo_debug_set_active_instance(plugin->debug_instance);
/* Return value of show_version currently ignored. */ /* Return value of show_version currently ignored. */
plugin->u.io->show_version(verbose); plugin->u.io->show_version(verbose);
if (plugin->u.io->version >= SUDO_API_MKVERSION(1, 15)) {
if (plugin->u.io->close != NULL)
plugin->u.io->close(0, 0);
}
sudo_debug_set_active_instance(sudo_debug_instance);
} }
if (plugin->u.io->version >= SUDO_API_MKVERSION(1, 15)) {
if (plugin->u.io->close != NULL)
plugin->u.io->close(0, 0);
}
sudo_debug_set_active_instance(sudo_debug_instance);
} }
} }
@@ -1360,26 +1453,234 @@ iolog_show_version(int verbose, struct sudo_settings *settings,
} }
/* /*
* Remove the specified I/O logging plugin from the io_plugins list. * Remove the specified plugin from the plugins list.
* Deregisters any hooks before unlinking, then frees the container. * Deregisters any hooks before unlinking, then frees the container.
*/ */
static void static void
iolog_unlink(struct plugin_container *plugin) unlink_plugin(struct plugin_container_list *plugin_list,
struct plugin_container *plugin)
{ {
debug_decl(iolog_unlink, SUDO_DEBUG_PCOMM); void (*deregister_hooks)(int , int (*)(struct sudo_hook *)) = NULL;
debug_decl(unlink_plugin, SUDO_DEBUG_PCOMM);
/* Deregister hooks, if any. */ /* Deregister hooks, if any. */
if (plugin->u.io->version >= SUDO_API_MKVERSION(1, 2)) { if (plugin->u.generic->version >= SUDO_API_MKVERSION(1, 2)) {
if (plugin->u.io->deregister_hooks != NULL) { switch (plugin->u.generic->type) {
case SUDO_IO_PLUGIN:
deregister_hooks = plugin->u.io->deregister_hooks;
break;
case SUDO_AUDIT_PLUGIN:
deregister_hooks = plugin->u.audit->deregister_hooks;
break;
default:
sudo_debug_printf(SUDO_DEBUG_ERROR,
"%s: unsupported plugin type %d", __func__,
plugin->u.generic->type);
break;
}
}
if (deregister_hooks != NULL) {
sudo_debug_set_active_instance(plugin->debug_instance);
deregister_hooks(SUDO_HOOK_VERSION, deregister_hook);
sudo_debug_set_active_instance(sudo_debug_instance);
}
/* Remove from plugin list and free. */
TAILQ_REMOVE(plugin_list, plugin, entries);
free_plugin_container(plugin, true);
debug_return;
}
static int
audit_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[], const char **errstr)
{
char **plugin_settings;
int ret;
debug_decl(audit_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);
}
sudo_debug_set_active_instance(plugin->debug_instance);
ret = plugin->u.audit->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);
debug_return_int(ret);
}
static void
audit_open(struct sudo_settings *settings, char * const user_info[],
int submit_optind, char * const submit_argv[], char * const submit_envp[])
{
struct plugin_container *plugin, *next;
const char *errstr = NULL;
debug_decl(audit_open, SUDO_DEBUG_PCOMM);
TAILQ_FOREACH_SAFE(plugin, &audit_plugins, entries, next) {
int ok = audit_open_int(plugin, settings, user_info,
submit_optind, submit_argv, submit_envp, &errstr);
switch (ok) {
case 1:
break;
case 0:
/* Audit plugin asked to be disabled, remove and free. */
unlink_plugin(&audit_plugins, plugin);
break;
case -2:
usage(1);
break;
default:
/* TODO: pass error message to other audit plugins */
sudo_fatalx(U_("error initializing audit plugin %s"),
plugin->name);
}
}
debug_return;
}
static void
audit_close(int exit_status, int error_code)
{
struct plugin_container *plugin;
debug_decl(audit_close, SUDO_DEBUG_PCOMM);
TAILQ_FOREACH(plugin, &audit_plugins, entries) {
if (plugin->u.audit->close != NULL) {
sudo_debug_set_active_instance(plugin->debug_instance); sudo_debug_set_active_instance(plugin->debug_instance);
plugin->u.io->deregister_hooks(SUDO_HOOK_VERSION, plugin->u.audit->close(exit_status, error_code);
deregister_hook);
sudo_debug_set_active_instance(sudo_debug_instance); sudo_debug_set_active_instance(sudo_debug_instance);
} }
} }
/* Remove from io_plugins list and free. */
TAILQ_REMOVE(&io_plugins, plugin, entries); debug_return;
free_plugin_container(plugin, true); }
static void
audit_show_version(int verbose)
{
struct plugin_container *plugin;
debug_decl(audit_show_version, SUDO_DEBUG_PCOMM);
TAILQ_FOREACH(plugin, &audit_plugins, entries) {
sudo_debug_set_active_instance(plugin->debug_instance);
if (plugin->u.audit->show_version != NULL) {
/* Return value of show_version currently ignored. */
plugin->u.audit->show_version(verbose);
}
if (plugin->u.audit->close != NULL)
plugin->u.audit->close(0, 0);
sudo_debug_set_active_instance(sudo_debug_instance);
}
debug_return;
}
/*
* Command accepted by policy.
* See command_info[] for additional info.
* XXX - actual environment may be updated by policy_init_session().
*/
static void
audit_accept(const char *plugin_name, unsigned int plugin_type,
char * const command_info[], char * const run_argv[],
char * const run_envp[])
{
struct plugin_container *plugin;
const char *errstr = NULL;
int ok;
debug_decl(audit_accept, SUDO_DEBUG_PCOMM);
/* XXX - kill command if can't audit accept event */
TAILQ_FOREACH(plugin, &audit_plugins, entries) {
if (plugin->u.audit->accept == NULL)
continue;
sudo_debug_set_active_instance(plugin->debug_instance);
ok = plugin->u.audit->accept(plugin_name, plugin_type,
command_info, run_argv, run_envp, &errstr);
if (ok != 1) {
/* XXX - fatal error? log error with other audit modules? */
sudo_debug_printf(SUDO_DEBUG_ERROR,
"%s: plugin %s accept failed, ret %d", __func__,
plugin->name, ok);
}
sudo_debug_set_active_instance(sudo_debug_instance);
}
debug_return;
}
/*
* Command rejected by policy or I/O plugin.
*/
void
audit_reject(const char *plugin_name, unsigned int plugin_type,
const char *audit_msg, char * const command_info[])
{
struct plugin_container *plugin;
const char *errstr = NULL;
int ok;
debug_decl(audit_reject, SUDO_DEBUG_PCOMM);
TAILQ_FOREACH(plugin, &audit_plugins, entries) {
if (plugin->u.audit->reject == NULL)
continue;
sudo_debug_set_active_instance(plugin->debug_instance);
ok = plugin->u.audit->reject(plugin_name, plugin_type,
audit_msg, command_info, &errstr);
if (ok != 1) {
/* TODO: notify other audit plugins of the error. */
sudo_debug_printf(SUDO_DEBUG_ERROR,
"%s: plugin %s reject failed, ret %d", __func__,
plugin->name, ok);
}
sudo_debug_set_active_instance(sudo_debug_instance);
}
debug_return;
}
/*
* Error from policy or I/O plugin.
*/
void
audit_error(const char *plugin_name, unsigned int plugin_type,
const char *audit_msg, char * const command_info[])
{
struct plugin_container *plugin;
const char *errstr = NULL;
int ok;
debug_decl(audit_error, SUDO_DEBUG_PCOMM);
TAILQ_FOREACH(plugin, &audit_plugins, entries) {
if (plugin->u.audit->error == NULL)
continue;
sudo_debug_set_active_instance(plugin->debug_instance);
ok = plugin->u.audit->error(plugin_name, plugin_type,
audit_msg, command_info, &errstr);
if (ok != 1) {
/* TODO: notify other audit plugins of the error. */
sudo_debug_printf(SUDO_DEBUG_ERROR,
"%s: plugin %s error failed, ret %d", __func__,
plugin->name, ok);
}
sudo_debug_set_active_instance(sudo_debug_instance);
}
debug_return; debug_return;
} }

View File

@@ -207,8 +207,8 @@ char *tgetpass(const char *prompt, int timeout, int flags,
int sudo_execute(struct command_details *details, struct command_status *cstat); int sudo_execute(struct command_details *details, struct command_status *cstat);
/* parse_args.c */ /* parse_args.c */
int parse_args(int argc, char **argv, int *nargc, char ***nargv, int parse_args(int argc, char **argv, int *old_optind, int *nargc,
struct sudo_settings **settingsp, char ***env_addp); char ***nargv, struct sudo_settings **settingsp, char ***env_addp);
extern int tgetpass_flags; extern int tgetpass_flags;
/* get_pty.c */ /* get_pty.c */
@@ -221,6 +221,10 @@ int os_init_common(int argc, char *argv[], char *envp[]);
bool gc_add(enum sudo_gc_types type, void *v); bool gc_add(enum sudo_gc_types type, void *v);
bool set_user_groups(struct command_details *details); bool set_user_groups(struct command_details *details);
struct sudo_plugin_event *sudo_plugin_event_alloc(void); struct sudo_plugin_event *sudo_plugin_event_alloc(void);
void audit_reject(const char *plugin_name, unsigned int plugin_type,
const char *audit_msg, char * const command_info[]);
void audit_error(const char *plugin_name, unsigned int plugin_type,
const char *audit_msg, char * const command_info[]);
extern const char *list_user; extern const char *list_user;
extern struct user_details user_details; extern struct user_details user_details;
extern int sudo_debug_instance; extern int sudo_debug_instance;

View File

@@ -100,6 +100,7 @@ struct plugin_container {
struct io_plugin *io; struct io_plugin *io;
struct io_plugin_1_0 *io_1_0; struct io_plugin_1_0 *io_1_0;
struct io_plugin_1_1 *io_1_1; struct io_plugin_1_1 *io_1_1;
struct audit_plugin *audit;
} u; } u;
}; };
TAILQ_HEAD(plugin_container_list, plugin_container); TAILQ_HEAD(plugin_container_list, plugin_container);
@@ -117,6 +118,7 @@ struct sudo_plugin_event_int {
extern struct plugin_container policy_plugin; extern struct plugin_container policy_plugin;
extern struct plugin_container_list io_plugins; extern struct plugin_container_list io_plugins;
extern struct plugin_container_list audit_plugins;
int sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[], int sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
struct sudo_conv_reply replies[], struct sudo_conv_callback *callback); struct sudo_conv_reply replies[], struct sudo_conv_callback *callback);
@@ -125,6 +127,7 @@ int sudo_conversation_1_7(int num_msgs, const struct sudo_conv_message msgs[],
int sudo_conversation_printf(int msg_type, const char *fmt, ...); int sudo_conversation_printf(int msg_type, const char *fmt, ...);
bool sudo_load_plugins(struct plugin_container *policy_plugin, bool sudo_load_plugins(struct plugin_container *policy_plugin,
struct plugin_container_list *io_plugins); struct plugin_container_list *io_plugins,
struct plugin_container_list *audit_plugins);
#endif /* SUDO_PLUGIN_INT_H */ #endif /* SUDO_PLUGIN_INT_H */