mirror of
https://github.com/sudo-project/sudo.git
synced 2025-09-04 08:15:15 +00:00
Document hooks API
This commit is contained in:
@@ -103,6 +103,10 @@ so that B<sudo> can load it.
|
|||||||
int (*validate)(void);
|
int (*validate)(void);
|
||||||
void (*invalidate)(int remove);
|
void (*invalidate)(int remove);
|
||||||
int (*init_session)(struct passwd *pwd);
|
int (*init_session)(struct passwd *pwd);
|
||||||
|
void (*register_hooks)(int version,
|
||||||
|
int (*register_hook)(struct sudo_hook *hook));
|
||||||
|
void (*deregister_hooks)(int version,
|
||||||
|
int (*deregister_hook)(struct sudo_hook *hook));
|
||||||
};
|
};
|
||||||
|
|
||||||
The policy_plugin struct has the following fields:
|
The policy_plugin struct has the following fields:
|
||||||
@@ -755,10 +759,67 @@ On error, the plugin may optionally call the conversation or plugin_printf
|
|||||||
function with C<SUDO_CONF_ERROR_MSG> to present additional
|
function with C<SUDO_CONF_ERROR_MSG> to present additional
|
||||||
error information to the user.
|
error information to the user.
|
||||||
|
|
||||||
|
=item register_hooks
|
||||||
|
|
||||||
|
void (*register_hooks)(int version,
|
||||||
|
int (*register_hook)(struct sudo_hook *hook));
|
||||||
|
|
||||||
|
The C<register_hooks> function is called by the sudo front end to
|
||||||
|
register any hooks the plugin needs. If the plugin does not support
|
||||||
|
hooks, C<register_hooks> should be set to the NULL pointer.
|
||||||
|
|
||||||
|
The I<version> argument describes the version of the hooks API
|
||||||
|
supported by the B<sudo> front end.
|
||||||
|
|
||||||
|
The C<register_hook> function should be used to register any suppored
|
||||||
|
hooks the plugin needs. It returns 0 on success, 1 if the hook
|
||||||
|
type is not supported and -1 if the major version in C<struct hook>
|
||||||
|
does not match the front end's major hook API version.
|
||||||
|
|
||||||
|
See the L<Hook Function API> section below for more information
|
||||||
|
about hooks.
|
||||||
|
|
||||||
|
NOTE: the C<register_hooks> function is only available starting
|
||||||
|
with API version 1.2. If the B<sudo> front end doesn't support API
|
||||||
|
version 1.2 or higher, C<register_hooks> will not be called.
|
||||||
|
|
||||||
|
=item deregister_hooks
|
||||||
|
|
||||||
|
void (*deregister_hooks)(int version,
|
||||||
|
int (*deregister_hook)(struct sudo_hook *hook));
|
||||||
|
|
||||||
|
The C<deregister_hooks> function is called by the sudo front end
|
||||||
|
to deregister any hooks the plugin has registered. If the plugin
|
||||||
|
does not support hooks, C<deregister_hooks> should be set to the
|
||||||
|
NULL pointer.
|
||||||
|
|
||||||
|
The I<version> argument describes the version of the hooks API
|
||||||
|
supported by the B<sudo> front end.
|
||||||
|
|
||||||
|
The C<deregister_hook> function should be used to deregister any
|
||||||
|
hooks that were put in place by the C<register_hook> function. If
|
||||||
|
the plugin tries to deregister a hook that the front end does not
|
||||||
|
support, C<deregister_hook> will return an error.
|
||||||
|
|
||||||
|
See the L<Hook Function API> section below for more information
|
||||||
|
about hooks.
|
||||||
|
|
||||||
|
NOTE: the C<deregister_hooks> function is only available starting
|
||||||
|
with API version 1.2. If the B<sudo> front end doesn't support API
|
||||||
|
version 1.2 or higher, C<deregister_hooks> will not be called.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head3 Version macros
|
=head3 Policy Plugin Version Macros
|
||||||
|
|
||||||
|
/* Plugin API version major/minor. */
|
||||||
|
#define SUDO_API_VERSION_MAJOR 1
|
||||||
|
#define SUDO_API_VERSION_MINOR 2
|
||||||
|
#define SUDO_API_MKVERSION(x, y) ((x << 16) | y)
|
||||||
|
#define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR,\
|
||||||
|
SUDO_API_VERSION_MINOR)
|
||||||
|
|
||||||
|
/* Getters and setters for API version */
|
||||||
#define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16)
|
#define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16)
|
||||||
#define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
|
#define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
|
||||||
#define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \
|
#define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \
|
||||||
@@ -768,11 +829,6 @@ error information to the user.
|
|||||||
*(vp) = (*(vp) & 0xffff0000) | (n); \
|
*(vp) = (*(vp) & 0xffff0000) | (n); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#define SUDO_API_VERSION_MAJOR 1
|
|
||||||
#define SUDO_API_VERSION_MINOR 0
|
|
||||||
#define SUDO_API_VERSION ((SUDO_API_VERSION_MAJOR << 16) | \
|
|
||||||
SUDO_API_VERSION_MINOR)
|
|
||||||
|
|
||||||
=head2 I/O Plugin API
|
=head2 I/O Plugin API
|
||||||
|
|
||||||
struct io_plugin {
|
struct io_plugin {
|
||||||
@@ -790,6 +846,10 @@ error information to the user.
|
|||||||
int (*log_stdin)(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_stdout)(const char *buf, unsigned int len);
|
||||||
int (*log_stderr)(const char *buf, unsigned int len);
|
int (*log_stderr)(const char *buf, unsigned int len);
|
||||||
|
void (*register_hooks)(int version,
|
||||||
|
int (*register_hook)(struct sudo_hook *hook));
|
||||||
|
void (*deregister_hooks)(int version,
|
||||||
|
int (*deregister_hook)(struct sudo_hook *hook));
|
||||||
};
|
};
|
||||||
|
|
||||||
When an I/O plugin is loaded, B<sudo> runs the command in a pseudo-tty.
|
When an I/O plugin is loaded, B<sudo> runs the command in a pseudo-tty.
|
||||||
@@ -1095,12 +1155,185 @@ The length of I<buf> in bytes.
|
|||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
=item register_hooks
|
||||||
|
|
||||||
|
See the L<Policy Plugin API> section for a description of
|
||||||
|
C<register_hooks>.
|
||||||
|
|
||||||
|
=item deregister_hooks
|
||||||
|
|
||||||
|
See the L<Policy Plugin API> section for a description of
|
||||||
|
C<deregister_hooks>.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head3 Version macros
|
=head3 I/O Plugin Version Macros
|
||||||
|
|
||||||
Same as for the L<Policy Plugin API>.
|
Same as for the L<Policy Plugin API>.
|
||||||
|
|
||||||
|
=head2 Hook Function API
|
||||||
|
|
||||||
|
Beginning with plugin API version 1.2, it is possible to install
|
||||||
|
hooks for certain functions called by the B<sudo> front end.
|
||||||
|
|
||||||
|
Currently, the only supported hooks relate to the handling of
|
||||||
|
environment variables. Hooks can be used to intercept attempts to
|
||||||
|
get, set, or remove environment variables so that these changes can
|
||||||
|
be reflected in the version of the environment that is used to
|
||||||
|
execute a command. A future version of the API will support
|
||||||
|
hooking internal B<sudo> front end functions as well.
|
||||||
|
|
||||||
|
Environment-related hooks are disabled prior to the execution of
|
||||||
|
the C<init_session> policy plugin function (if any). This is
|
||||||
|
necessary because C<init_session> has no way of passing back a
|
||||||
|
modified environment pointer. However, since the user environment
|
||||||
|
specified by the C<check_policy> function is already in place, there
|
||||||
|
should be no need to hook the environment functions at that time.
|
||||||
|
|
||||||
|
=head3 Hook structure
|
||||||
|
|
||||||
|
Hooks in B<sudo> are described by the following structure:
|
||||||
|
|
||||||
|
typedef int (*sudo_hook_fn_t)();
|
||||||
|
|
||||||
|
struct sudo_hook {
|
||||||
|
int hook_version;
|
||||||
|
int hook_type;
|
||||||
|
sudo_hook_fn_t hook_fn;
|
||||||
|
void *closure;
|
||||||
|
};
|
||||||
|
|
||||||
|
The C<sudo_hook> structure has the following fields:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item hook_version
|
||||||
|
|
||||||
|
The C<hook_version> field should be set to SUDO_HOOK_VERSION.
|
||||||
|
|
||||||
|
=item hook_type
|
||||||
|
|
||||||
|
The C<hook_type> field may be one of the following supported hook types:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item SUDO_HOOK_SETENV
|
||||||
|
|
||||||
|
The C library C<setenv()> function. Any registered hooks will run
|
||||||
|
before the C library implementation. The C<hook_fn> field should
|
||||||
|
be a function that matches the following typedef:
|
||||||
|
|
||||||
|
typedef int (*sudo_hook_fn_setenv_t)(const char *name,
|
||||||
|
const char *value, int overwrite, void *closure);
|
||||||
|
|
||||||
|
If the registered hook does not match the typedef the results are
|
||||||
|
unspecified.
|
||||||
|
|
||||||
|
=item SUDO_HOOK_UNSETENV
|
||||||
|
|
||||||
|
The C library C<unsetenv()> function. Any registered hooks will run
|
||||||
|
before the C library implementation. The C<hook_fn> field should
|
||||||
|
be a function that matches the following typedef:
|
||||||
|
|
||||||
|
typedef int (*sudo_hook_fn_unsetenv_t)(const char *name,
|
||||||
|
void *closure);
|
||||||
|
|
||||||
|
=item SUDO_HOOK_GETENV
|
||||||
|
|
||||||
|
The C library C<getenv()> function. Any registered hooks will run
|
||||||
|
before the C library implementation. The C<hook_fn> field should
|
||||||
|
be a function that matches the following typedef:
|
||||||
|
|
||||||
|
typedef int (*sudo_hook_fn_getenv_t)(const char *name,
|
||||||
|
char **value, void *closure);
|
||||||
|
|
||||||
|
If the registered hook does not match the typedef the results are
|
||||||
|
unspecified.
|
||||||
|
|
||||||
|
=item SUDO_HOOK_PUTENV
|
||||||
|
|
||||||
|
The C library C<putenv()> function. Any registered hooks will run
|
||||||
|
before the C library implementation. The C<hook_fn> field should
|
||||||
|
be a function that matches the following typedef:
|
||||||
|
|
||||||
|
typedef int (*sudo_hook_fn_putenv_t)(char *string,
|
||||||
|
void *closure);
|
||||||
|
|
||||||
|
If the registered hook does not match the typedef the results are
|
||||||
|
unspecified.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=item hook_fn
|
||||||
|
|
||||||
|
sudo_hook_fn_t hook_fn;
|
||||||
|
|
||||||
|
The C<hook_fn> field should be set to the plugin's hook implementation.
|
||||||
|
The actual function arguments will vary depending on the C<hook_type>
|
||||||
|
(see C<hook_type> above). In all cases, the C<closure> field of
|
||||||
|
C<struct sudo_hook> is passed as the last function parameter. This
|
||||||
|
can be used to pass arbitrary data to the plugin's hook implementation.
|
||||||
|
|
||||||
|
The function return value may be one of the following:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item SUDO_HOOK_RET_ERROR
|
||||||
|
|
||||||
|
The hook function encountered an error.
|
||||||
|
|
||||||
|
=item SUDO_HOOK_RET_NEXT
|
||||||
|
|
||||||
|
The hook completed without error, go on to the next hook (including
|
||||||
|
the native implementation if applicable). For example, a C<getenv>
|
||||||
|
hook might return C<SUDO_HOOK_RET_NEXT> if the specified variable
|
||||||
|
was not found in the private copy of the environment.
|
||||||
|
|
||||||
|
=item SUDO_HOOK_RET_STOP
|
||||||
|
|
||||||
|
The hook completed without error, stop processing hooks for this
|
||||||
|
invocation. This can be used to replace the native implementation.
|
||||||
|
For example, a C<setenv> hook that operates on a private copy of
|
||||||
|
the environment but leaves C<environ> unchanged.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
Note that it is very easy to create an infinite loop when hooking
|
||||||
|
C library functions. For example, a C<getenv> hook that calls the
|
||||||
|
C<snprintf> function may create a loop if the C<snprintf> implementation
|
||||||
|
calls C<getenv> to check the locale. To prevent this, you may wish
|
||||||
|
to use a static variable in the hook function to guard against
|
||||||
|
nested calls. E.g.
|
||||||
|
|
||||||
|
static int in_progress = 0; /* avoid recursion */
|
||||||
|
if (in_progress)
|
||||||
|
return SUDO_HOOK_RET_NEXT;
|
||||||
|
in_progress = 1;
|
||||||
|
...
|
||||||
|
in_progress = 0;
|
||||||
|
return SUDO_HOOK_RET_STOP;
|
||||||
|
|
||||||
|
=head3 Hook API Version Macros
|
||||||
|
|
||||||
|
/* Hook API version major/minor */
|
||||||
|
#define SUDO_HOOK_VERSION_MAJOR 1
|
||||||
|
#define SUDO_HOOK_VERSION_MINOR 0
|
||||||
|
#define SUDO_HOOK_MKVERSION(x, y) ((x << 16) | y)
|
||||||
|
#define SUDO_HOOK_VERSION SUDO_HOOK_MKVERSION(SUDO_HOOK_VERSION_MAJOR,\
|
||||||
|
SUDO_HOOK_VERSION_MINOR)
|
||||||
|
|
||||||
|
/* Getters and setters for hook API version */
|
||||||
|
#define SUDO_HOOK_VERSION_GET_MAJOR(v) ((v) >> 16)
|
||||||
|
#define SUDO_HOOK_VERSION_GET_MINOR(v) ((v) & 0xffff)
|
||||||
|
#define SUDO_HOOK_VERSION_SET_MAJOR(vp, n) do { \
|
||||||
|
*(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \
|
||||||
|
} while(0)
|
||||||
|
#define SUDO_HOOK_VERSION_SET_MINOR(vp, n) do { \
|
||||||
|
*(vp) = (*(vp) & 0xffff0000) | (n); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
=head2 Conversation API
|
=head2 Conversation API
|
||||||
|
|
||||||
If the plugin needs to interact with the user, it may do so via the
|
If the plugin needs to interact with the user, it may do so via the
|
||||||
@@ -1268,7 +1501,7 @@ present in the password database, I<pwd> will be C<NULL>.
|
|||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head3 Version Macros
|
=head3 Group API Version Macros
|
||||||
|
|
||||||
/* Sudoers group plugin version major/minor */
|
/* Sudoers group plugin version major/minor */
|
||||||
#define GROUP_API_VERSION_MAJOR 1
|
#define GROUP_API_VERSION_MAJOR 1
|
||||||
|
Reference in New Issue
Block a user