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
.\"
.\" 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
.\" 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
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd December 5, 2019
.Dd Januarry 28, 2020
.Dt SUDO_PLUGIN @mansectform@
.Os Sudo @PACKAGE_VERSION@
.Sh NAME
@@ -70,17 +70,19 @@ struct policy_plugin {
int (*open)(unsigned int version, sudo_conv_t conversation,
sudo_printf_t plugin_printf, char * const settings[],
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);
int (*show_version)(int verbose);
int (*show_version)(int verbose, const char **errstr);
int (*check_policy)(int argc, char * const argv[],
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,
const char *list_user);
int (*validate)(void);
const char *list_user, const char **errstr);
int (*validate)(const char **errstr);
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,
int (*register_hook)(struct sudo_hook *hook));
void (*deregister_hooks)(int version,
@@ -110,7 +112,7 @@ built against.
int (*open)(unsigned int version, sudo_conv_t conversation,
sudo_printf_t plugin_printf, char * const settings[],
char * const user_info[], char * const user_env[],
char * const plugin_options[]);
char * const plugin_options[], const char **errstr);
.Ed
.Pp
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
process.
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
The parent process ID of the running
.Nm sudo
@@ -518,6 +494,53 @@ field will never include one
itself but the
.Em value
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
.It close
.Bd -literal -compact
@@ -585,7 +608,7 @@ front end may execute the command directly instead of running
it as a child process.
.It show_version
.Bd -literal -compact
int (*show_version)(int verbose);
int (*show_version)(int verbose, const char **errstr);
.Ed
.Pp
The
@@ -602,16 +625,45 @@ or
.Fn plugin_printf
function using
.Dv SUDO_CONV_INFO_MSG .
If the user requests detailed version information, the verbose flag will be set.
.Pp
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
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
.Bd -literal -compact
int (*check_policy)(int argc, char * const argv[],
char *env_add[], char **command_info[],
char **argv_out[], char **user_env_out[]);
char **argv_out[], char **user_env_out[],
const char **errstr);
.Ed
.Pp
The
@@ -1006,11 +1058,32 @@ The
.Dv NULL Ns -terminated
environment vector to use when executing the command.
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
.It list
.Bd -literal -compact
int (*list)(int argc, char * const argv[],
int verbose, const char *list_user);
int verbose, const char *list_user, const char **errstr);
.Ed
.Pp
List available privileges for the invoking user.
@@ -1057,10 +1130,31 @@ allows it.
If
.Dv NULL ,
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
.It validate
.Bd -literal -compact
int (*validate)(void);
int (*validate)(const char **errstr);
.Ed
.Pp
The
@@ -1091,6 +1185,31 @@ 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 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
.Bd -literal -compact
void (*invalidate)(int remove);
@@ -1100,8 +1219,7 @@ The
.Fn invalidate
function is called when
.Nm sudo
is called with
the
is run with the
.Fl k
or
.Fl K
@@ -1321,6 +1439,27 @@ front end doesn't support API
version 1.15 or higher,
.Fn event_alloc
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
.Pp
.Em Policy Plugin Version Macros
@@ -1352,20 +1491,26 @@ struct io_plugin {
sudo_printf_t plugin_printf, char * const settings[],
char * const user_info[], char * const command_info[],
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 */
int (*show_version)(int verbose);
int (*log_ttyin)(const char *buf, unsigned int len);
int (*log_ttyout)(const char *buf, unsigned int len);
int (*log_stdin)(const char *buf, unsigned int len);
int (*log_stdout)(const char *buf, unsigned int len);
int (*log_stderr)(const char *buf, unsigned int len);
int (*show_version)(int verbose, const char **errstr);
int (*log_ttyin)(const char *buf, unsigned int len,
const char **errstr);
int (*log_ttyout)(const char *buf, unsigned int len,
const char **errstr);
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,
int (*register_hook)(struct sudo_hook *hook));
void (*deregister_hooks)(int version,
int (*deregister_hook)(struct sudo_hook *hook));
int (*change_winsize)(unsigned int lines, unsigned int cols);
int (*log_suspend)(int signo);
int (*change_winsize)(unsigned int lines, unsigned int cols,
const char **errstr);
int (*log_suspend)(int signo, const char **errstr);
struct sudo_plugin_event * (*event_alloc)(void);
};
.Ed
@@ -1621,6 +1766,27 @@ by the
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
.It close
.Bd -literal -compact
@@ -1678,14 +1844,43 @@ or
.Fn plugin_printf
function using
.Dv SUDO_CONV_INFO_MSG .
If the user requests detailed version information, the verbose flag will be set.
.Pp
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
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
.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
.Pp
The
@@ -1706,10 +1901,32 @@ The buffer containing user input.
The length of
.Em buf
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
.It log_ttyout
.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
.Pp
The
@@ -1729,10 +1946,32 @@ The buffer containing command output.
The length of
.Em buf
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
.It log_stdin
.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
.Pp
The
@@ -1754,10 +1993,32 @@ The buffer containing user input.
The length of
.Em buf
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
.It log_stdout
.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
.Pp
The
@@ -1779,10 +2040,32 @@ The buffer containing command output.
The length of
.Em buf
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
.It log_stderr
.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
.Pp
The
@@ -1804,6 +2087,27 @@ The buffer containing command output.
The length of
.Em buf
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
.It register_hooks
See the
@@ -1817,7 +2121,8 @@ section for a description of
.Li deregister_hooks .
.It change_winsize
.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
.Pp
The
@@ -1829,24 +2134,76 @@ list.
Returns \-1 if an error occurred, in which case no further calls to
.Fn change_winsize
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
.Bd -literal -compact
int (*log_suspend)(int signo);
int (*log_suspend)(int signo, const char **errstr);
.Ed
.Pp
The
.Fn log_suspend
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
the command was suspended during playback of a session.
Returns \-1 if an error occurred, in which case no further calls to
.Fn log_suspend
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
.Bd -literal -compact
struct sudo_plugin_event * (*event_alloc)(void);
@@ -2930,6 +3287,13 @@ The
field was added to the policy_plugin and io_plugin structs.
.Pp
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
function is now is called regardless of whether or not a command
was actually executed.

View File

@@ -1,7 +1,7 @@
/*
* 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
* 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,
sudo_printf_t sudo_printf, char * const settings[],
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 */
int (*show_version)(int verbose);
int (*check_policy)(int argc, char * const argv[],
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,
const char *list_user);
int (*validate)(void);
const char *list_user, const char **errstr);
int (*validate)(const char **errstr);
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 (*deregister_hooks)(int version, int (*deregister_hook)(struct sudo_hook *hook));
struct sudo_plugin_event * (*event_alloc)(void);
@@ -187,19 +188,47 @@ struct io_plugin {
sudo_printf_t sudo_printf, char * const settings[],
char * const user_info[], char * const command_info[],
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 */
int (*show_version)(int verbose);
int (*log_ttyin)(const char *buf, unsigned int len);
int (*log_ttyout)(const char *buf, unsigned int len);
int (*log_stdin)(const char *buf, unsigned int len);
int (*log_stdout)(const char *buf, unsigned int len);
int (*log_stderr)(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, const char **errstr);
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,
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 (*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 */

View File

@@ -201,6 +201,7 @@ static bool
log_ttyin(const char *buf, unsigned int n, struct io_buffer *iob)
{
struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask;
bool ret = true;
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;
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) {
/* Error: disable plugin's I/O function. */
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;
break;
@@ -233,6 +240,7 @@ static bool
log_stdin(const char *buf, unsigned int n, struct io_buffer *iob)
{
struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask;
bool ret = true;
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;
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) {
/* Error: disable plugin's I/O function. */
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;
break;
@@ -265,6 +279,7 @@ static bool
log_ttyout(const char *buf, unsigned int n, struct io_buffer *iob)
{
struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask;
bool ret = true;
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;
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) {
/* Error: disable plugin's I/O function. */
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;
break;
@@ -308,6 +329,7 @@ static bool
log_stdout(const char *buf, unsigned int n, struct io_buffer *iob)
{
struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask;
bool ret = true;
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;
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) {
/* Error: disable plugin's I/O function. */
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;
break;
@@ -351,6 +379,7 @@ static bool
log_stderr(const char *buf, unsigned int n, struct io_buffer *iob)
{
struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask;
bool ret = true;
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;
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) {
/* Error: disable plugin's I/O function. */
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;
break;
@@ -394,6 +429,7 @@ static void
log_suspend(int signo)
{
struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask;
debug_decl(log_suspend, SUDO_DEBUG_EXEC);
@@ -405,12 +441,12 @@ log_suspend(int signo)
int rc;
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) {
/* Error: disable plugin's I/O function. */
plugin->u.io->log_suspend = NULL;
}
audit_error(plugin->name, SUDO_IO_PLUGIN,
errstr ? errstr : _("error logging suspend"), NULL);
break;
}
}
@@ -426,6 +462,7 @@ static void
log_winchange(unsigned int rows, unsigned int cols)
{
struct plugin_container *plugin;
const char *errstr = NULL;
sigset_t omask;
debug_decl(log_winchange, SUDO_DEBUG_EXEC);
@@ -437,12 +474,12 @@ log_winchange(unsigned int rows, unsigned int cols)
int rc;
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) {
/* Error: disable plugin's I/O function. */
plugin->u.io->change_winsize = NULL;
}
audit_error(plugin->name, SUDO_IO_PLUGIN,
errstr ? errstr : _("error changing window size"), NULL);
break;
}
}

View File

@@ -242,7 +242,8 @@ cleanup:
*/
static bool
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 generic_plugin *plugin;
@@ -315,6 +316,20 @@ sudo_load_plugin(struct plugin_container *policy_plugin,
goto done;
TAILQ_INSERT_TAIL(io_plugins, container, entries);
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:
sudo_warnx(U_("error in %s, line %d while loading plugin \"%s\""),
_PATH_SUDO_CONF, info->lineno, info->symbol_name);
@@ -354,7 +369,8 @@ free_plugin_info(struct plugin_info *info)
*/
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)
{
struct plugin_container *container;
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. */
plugins = sudo_conf_plugins();
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)
goto done;
free_plugin_info(info);
@@ -391,7 +407,7 @@ sudo_load_plugins(struct plugin_container *policy_plugin,
goto done;
}
/* 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);
if (!ret)
goto done;
@@ -411,7 +427,7 @@ sudo_load_plugins(struct plugin_container *policy_plugin,
goto done;
}
/* 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);
if (!ret)
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).
*/
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 environment extra_env;
@@ -501,6 +501,7 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv,
argc -= optind;
argv += optind;
*old_optind = optind;
if (!mode) {
/* 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;
}
/*
* For sudoedit we need to rewrite argv
*/
if (mode == MODE_EDIT) {
#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]. */
argc++;
argv--;
argv[0] = "sudoedit";
av[0] = "sudoedit";
for (ac = 0; argv[ac] != NULL; ac++) {
av[ac + 1] = argv[ac];
}
av[++ac] = NULL;
argv = av;
argc = ac;
#else
sudo_fatalx(U_("sudoedit is not supported on this platform"));
#endif

View File

@@ -1,7 +1,7 @@
/*
* 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
* purpose with or without fee is hereby granted, provided that the above
@@ -75,6 +75,7 @@
*/
struct plugin_container policy_plugin;
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;
const char *list_user; /* extern for parse_args.c */
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);
/* 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[]);
static void policy_close(int exit_status, int error);
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[]);
static int policy_list(int argc, char * const argv[], int verbose,
const char *list_user);
static int policy_validate(void);
static void policy_list(int argc, char * const argv[],
int verbose, const char *list_user, char * const envp[]);
static void policy_validate(char * const argv[], char * const envp[]);
static void policy_invalidate(int remove);
/* 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,
char * const user_info[], int argc, char * const argv[],
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);
/* 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[]);
int
main(int argc, char *argv[], char *envp[])
{
int nargc, ok, status = 0;
char **nargv, **env_add;
char **user_info, **command_info, **argv_out, **user_env_out;
int nargc, status = 0;
char **nargv, **env_add, **user_info;
char **command_info = NULL, **argv_out = NULL, **user_env_out = NULL;
struct sudo_settings *settings;
int submit_optind;
sigset_t mask;
debug_decl_vars(main, SUDO_DEBUG_MAIN);
@@ -194,7 +205,8 @@ main(int argc, char *argv[], char *envp[])
disable_coredump();
/* 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);
/* 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);
/* 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"));
/* Allocate event base so plugin can use it. */
if ((sudo_event_base = sudo_ev_base_alloc()) == NULL)
sudo_fatalx("%s", U_("unable to allocate memory"));
/* Open policy plugin. */
ok = policy_open(settings, user_info, envp);
if (ok != 1) {
if (ok == -2)
usage(1);
else
sudo_fatalx(U_("unable to initialize policy plugin"));
}
/* Open policy and audit plugins. */
/* XXX - audit policy_open errors */
audit_open(settings, user_info, submit_optind, argv, envp);
policy_open(settings, user_info, envp);
switch (sudo_mode & MODE_MASK) {
case MODE_VERSION:
policy_show_version(!user_details.uid);
iolog_show_version(!user_details.uid, settings, user_info,
nargc, nargv, envp);
audit_show_version(!user_details.uid);
break;
case MODE_VALIDATE:
case MODE_VALIDATE|MODE_INVALIDATE:
ok = policy_validate();
exit(ok != 1);
policy_validate(nargv, envp);
break;
case MODE_KILL:
case MODE_INVALIDATE:
policy_invalidate(sudo_mode == MODE_KILL);
exit(0);
break;
case MODE_CHECK:
case MODE_CHECK|MODE_INVALIDATE:
case MODE_LIST:
case MODE_LIST|MODE_INVALIDATE:
ok = policy_list(nargc, nargv, ISSET(sudo_mode, MODE_LONG_LIST),
list_user);
exit(ok != 1);
policy_list(nargc, nargv, ISSET(sudo_mode, MODE_LONG_LIST),
list_user, envp);
break;
case MODE_EDIT:
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);
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. */
/* XXX - leaks old nargv in shell mode */
@@ -264,10 +266,14 @@ main(int argc, char *argv[], char *envp[])
if (nargc == 0)
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,
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. */
command_info_to_details(command_info, &command_details);
command_details.tty = user_details.tty;
@@ -941,6 +947,7 @@ run_command(struct command_details *details)
/* exec_setup() or execve() returned an error. */
policy_close(0, cstat.val);
iolog_close(0, cstat.val);
audit_close(0, cstat.val);
break;
case CMD_WSTATUS:
/* Command ran, exited or was killed. */
@@ -951,6 +958,7 @@ run_command(struct command_details *details)
#endif
policy_close(status, 0);
iolog_close(status, 0);
audit_close(status, 0);
break;
default:
sudo_warnx(U_("unexpected child termination condition: %d"), cstat.type);
@@ -1022,20 +1030,19 @@ bad:
debug_return_ptr(NULL);
}
static int
static void
policy_open(struct sudo_settings *settings, char * const user_info[],
char * const user_env[])
{
char **plugin_settings;
int ret;
const char *errstr = NULL;
int ok;
debug_decl(policy_open, SUDO_DEBUG_PCOMM);
/* Convert struct sudo_settings to plugin_settings[] */
plugin_settings = format_plugin_settings(&policy_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"));
/*
* 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) {
case SUDO_API_MKVERSION(1, 0):
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,
user_info, user_env);
break;
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,
policy_plugin.options);
policy_plugin.options, &errstr);
}
/* Stash plugin debug instance ID if set in open() function. */
policy_plugin.debug_instance = sudo_debug_get_active_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
@@ -1083,33 +1099,35 @@ policy_close(int exit_status, int error_code)
errno = error_code;
sudo_warn(U_("unable to execute %s"), command_details.command);
}
debug_return;
}
static int
policy_show_version(int verbose)
{
int ret;
int ret = true;
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);
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->close != NULL)
policy_plugin.u.policy->close(0, 0);
}
sudo_debug_set_active_instance(sudo_debug_instance);
debug_return_int(ret);
}
static int
static void
policy_check(int argc, char * const argv[],
char *env_add[], char **command_info[], char **argv_out[],
char **user_env_out[])
{
int ret;
const char *errstr = NULL;
int ok;
debug_decl(policy_check, SUDO_DEBUG_PCOMM);
if (policy_plugin.u.policy->check_policy == NULL) {
@@ -1117,65 +1135,132 @@ policy_check(int argc, char * const argv[],
policy_plugin.name);
}
sudo_debug_set_active_instance(policy_plugin.debug_instance);
ret = policy_plugin.u.policy->check_policy(argc, argv, env_add,
command_info, argv_out, user_env_out);
/* 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);
}
}
ok = policy_plugin.u.policy->check_policy(argc, argv, env_add,
command_info, argv_out, user_env_out, &errstr);
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
policy_list(int argc, char * const argv[], int verbose, const char *list_user)
static void
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);
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);
debug_return_int(false);
}
sudo_debug_set_active_instance(policy_plugin.debug_instance);
ret = policy_plugin.u.policy->list(argc, argv, verbose, list_user);
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);
}
ok = policy_plugin.u.policy->list(argc, argv, verbose, list_user, &errstr);
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
policy_validate(void)
static 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);
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);
debug_return_int(false);
}
sudo_debug_set_active_instance(policy_plugin.debug_instance);
ret = policy_plugin.u.policy->validate();
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);
}
ok = policy_plugin.u.policy->validate(&errstr);
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
policy_invalidate(int remove)
{
debug_decl(policy_invalidate, SUDO_DEBUG_PCOMM);
if (policy_plugin.u.policy->invalidate == NULL) {
sudo_fatalx(U_("policy plugin %s does not support the -k/-K options"),
policy_plugin.name);
@@ -1187,12 +1272,14 @@ policy_invalidate(int remove)
policy_plugin.u.policy->close(0, 0);
}
sudo_debug_set_active_instance(sudo_debug_instance);
debug_return;
exit(EXIT_SUCCESS);
}
int
policy_init_session(struct command_details *details)
{
const char *errstr = NULL;
int ret = true;
debug_decl(policy_init_session, SUDO_DEBUG_PCOMM);
@@ -1223,9 +1310,10 @@ policy_init_session(struct command_details *details)
break;
default:
ret = policy_plugin.u.policy->init_session(details->pw,
&details->envp);
&details->envp, &errstr);
}
sudo_debug_set_active_instance(sudo_debug_instance);
/* TODO: audit on error */
}
done:
debug_return_int(ret);
@@ -1234,7 +1322,7 @@ done:
static int
iolog_open_int(struct plugin_container *plugin, struct sudo_settings *settings,
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;
int ret;
@@ -1265,7 +1353,7 @@ iolog_open_int(struct plugin_container *plugin, struct sudo_settings *settings,
default:
ret = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation,
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. */
@@ -1281,22 +1369,26 @@ iolog_open(struct sudo_settings *settings, char * const user_info[],
char * const user_env[])
{
struct plugin_container *plugin, *next;
const char *errstr = NULL;
debug_decl(iolog_open, SUDO_DEBUG_PCOMM);
/* XXX - iolog_open should audit errors */
TAILQ_FOREACH_SAFE(plugin, &io_plugins, entries, next) {
int ok = iolog_open_int(plugin, settings, user_info,
command_info, argc, argv, user_env);
command_info, argc, argv, user_env, &errstr);
switch (ok) {
case 1:
break;
case 0:
/* I/O plugin asked to be disabled, remove and free. */
iolog_unlink(plugin);
/* XXX - audit */
unlink_plugin(&io_plugins, plugin);
break;
case -2:
usage(1);
break;
default:
/* XXX - audit error */
sudo_fatalx(U_("error initializing I/O plugin %s"),
plugin->name);
}
@@ -1336,17 +1428,19 @@ iolog_show_version(int verbose, struct sudo_settings *settings,
char * const user_info[], int argc, char * const argv[],
char * const user_env[])
{
const char *errstr = NULL;
struct plugin_container *plugin;
debug_decl(iolog_show_version, SUDO_DEBUG_PCOMM);
TAILQ_FOREACH(plugin, &io_plugins, entries) {
int ok = iolog_open_int(plugin, settings, user_info, NULL,
argc, argv, user_env);
argc, argv, user_env, &errstr);
if (ok != -1) {
if (plugin->u.io->show_version != NULL) {
sudo_debug_set_active_instance(plugin->debug_instance);
if (plugin->u.io->show_version != NULL) {
/* Return value of show_version currently ignored. */
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);
@@ -1354,32 +1448,239 @@ iolog_show_version(int verbose, struct sudo_settings *settings,
sudo_debug_set_active_instance(sudo_debug_instance);
}
}
debug_return;
}
/*
* Remove the specified plugin from the plugins list.
* Deregisters any hooks before unlinking, then frees the container.
*/
static void
unlink_plugin(struct plugin_container_list *plugin_list,
struct plugin_container *plugin)
{
void (*deregister_hooks)(int , int (*)(struct sudo_hook *)) = NULL;
debug_decl(unlink_plugin, SUDO_DEBUG_PCOMM);
/* Deregister hooks, if any. */
if (plugin->u.generic->version >= SUDO_API_MKVERSION(1, 2)) {
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);
plugin->u.audit->close(exit_status, error_code);
sudo_debug_set_active_instance(sudo_debug_instance);
}
}
debug_return;
}
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;
}
/*
* Remove the specified I/O logging plugin from the io_plugins list.
* Deregisters any hooks before unlinking, then frees the container.
* Command accepted by policy.
* See command_info[] for additional info.
* XXX - actual environment may be updated by policy_init_session().
*/
static void
iolog_unlink(struct plugin_container *plugin)
audit_accept(const char *plugin_name, unsigned int plugin_type,
char * const command_info[], char * const run_argv[],
char * const run_envp[])
{
debug_decl(iolog_unlink, SUDO_DEBUG_PCOMM);
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;
/* Deregister hooks, if any. */
if (plugin->u.io->version >= SUDO_API_MKVERSION(1, 2)) {
if (plugin->u.io->deregister_hooks != NULL) {
sudo_debug_set_active_instance(plugin->debug_instance);
plugin->u.io->deregister_hooks(SUDO_HOOK_VERSION,
deregister_hook);
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);
}
/* Remove from io_plugins list and free. */
TAILQ_REMOVE(&io_plugins, plugin, entries);
free_plugin_container(plugin, true);
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);
/* parse_args.c */
int parse_args(int argc, char **argv, int *nargc, char ***nargv,
struct sudo_settings **settingsp, char ***env_addp);
int parse_args(int argc, char **argv, int *old_optind, int *nargc,
char ***nargv, struct sudo_settings **settingsp, char ***env_addp);
extern int tgetpass_flags;
/* 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 set_user_groups(struct command_details *details);
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 struct user_details user_details;
extern int sudo_debug_instance;

View File

@@ -100,6 +100,7 @@ struct plugin_container {
struct io_plugin *io;
struct io_plugin_1_0 *io_1_0;
struct io_plugin_1_1 *io_1_1;
struct audit_plugin *audit;
} u;
};
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_list io_plugins;
extern struct plugin_container_list audit_plugins;
int sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
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, ...);
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 */