--- embedaddon/sudo/doc/sudo_plugin.man.in 2012/02/21 16:23:02 1.1.1.1 +++ embedaddon/sudo/doc/sudo_plugin.man.in 2012/05/29 12:26:49 1.1.1.2 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2009-2011 Todd C. Miller +.\" Copyright (c) 2009-2012 Todd C. Miller .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -139,7 +139,7 @@ .\" ======================================================================== .\" .IX Title "SUDO_PLUGIN @mansectsu@" -.TH SUDO_PLUGIN @mansectsu@ "September 16, 2011" "1.8.3" "MAINTENANCE COMMANDS" +.TH SUDO_PLUGIN @mansectsu@ "April 23, 2012" "1.8.5" "MAINTENANCE COMMANDS" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -174,8 +174,9 @@ plugin. The \fIsymbol_name\fR is the name of the \f(C or \f(CW\*(C`struct io_plugin\*(C'\fR in the plugin shared object. The \fIpath\fR may be fully qualified or relative. If not fully qualified it is relative to the \fI@prefix@/libexec\fR directory. Any additional -parameters after the \fIpath\fR are ignored. Lines that don't begin -with \f(CW\*(C`Plugin\*(C'\fR or \f(CW\*(C`Path\*(C'\fR are silently ignored. +parameters after the \fIpath\fR are passed as options to the plugin's +\&\fIopen\fR function. Lines that don't begin with \f(CW\*(C`Plugin\*(C'\fR, \f(CW\*(C`Path\*(C'\fR, +\&\f(CW\*(C`Debug\*(C'\fR or \f(CW\*(C`Set\*(C'\fR are silently ignored. .PP The same shared object may contain multiple plugins, each with a different symbol name. The shared object file must be owned by uid @@ -188,13 +189,17 @@ This limitation does not apply to I/O plugins. \& # Default @sysconfdir@/sudo.conf file \& # \& # Format: -\& # Plugin plugin_name plugin_path +\& # Plugin plugin_name plugin_path plugin_options ... \& # Path askpass /path/to/askpass +\& # Path noexec /path/to/sudo_noexec.so +\& # Debug sudo /var/log/sudo_debug all@warn +\& # Set disable_coredump true \& # \& # The plugin_path is relative to @prefix@/libexec unless \& # fully qualified. \& # The plugin_name corresponds to a global symbol in the plugin \& # that contains the plugin interface structure. +\& # The plugin_options are optional. \& # \& Plugin sudoers_policy sudoers.so \& Plugin sudoers_io sudoers.so @@ -214,7 +219,8 @@ so that \fBsudo\fR can load it. \& unsigned int version; /* always SUDO_API_VERSION */ \& 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 user_info[], char * const user_env[], +\& char * const plugin_options[]); \& void (*close)(int exit_status, int error); \& int (*show_version)(int verbose); \& int (*check_policy)(int argc, char * const argv[], @@ -224,7 +230,11 @@ so that \fBsudo\fR can load it. \& const char *list_user); \& int (*validate)(void); \& void (*invalidate)(int remove); -\& int (*init_session)(struct passwd *pwd); +\& int (*init_session)(struct passwd *pwd, char **user_env[]); +\& void (*register_hooks)(int version, +\& int (*register_hook)(struct sudo_hook *hook)); +\& void (*deregister_hooks)(int version, +\& int (*deregister_hook)(struct sudo_hook *hook)); \& }; .Ve .PP @@ -240,10 +250,11 @@ This allows \fBsudo\fR to determine the \s-1API\s0 ver built against. .IP "open" 4 .IX Item "open" -.Vb 3 +.Vb 4 \& 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 user_info[], char * const user_env[], +\& char * const plugin_options[]); .Ve .Sp Returns 1 on success, 0 on failure, \-1 if a general error occurred, @@ -282,9 +293,30 @@ When parsing \fIsettings\fR, the plugin should split o equal sign ('=') since the \fIname\fR field will never include one itself but the \fIvalue\fR might. .RS 4 +.IP "debug_flags=string" 4 +.IX Item "debug_flags=string" +A comma-separated list of debug flags that correspond to \fBsudo\fR's +\&\f(CW\*(C`Debug\*(C'\fR entry in \fI@sysconfdir@/sudo.conf\fR, if there is one. The +flags are passed to the plugin as they appear in \fI@sysconfdir@/sudo.conf\fR. +The syntax used by \fBsudo\fR and the \fIsudoers\fR plugin is +\&\fIsubsystem\fR@\fIpriority\fR but the plugin is free to use a different +format so long as it does not include a command \f(CW\*(C`,\*(C'\fR. +.Sp +For reference, the priorities supported by the \fBsudo\fR front end and +\&\fIsudoers\fR are: \fIcrit\fR, \fIerr\fR, \fIwarn\fR, \fInotice\fR, \fIdiag\fR, +\&\fIinfo\fR, \fItrace\fR and \fIdebug\fR. +.Sp +The following subsystems are defined: \fImain\fR, \fImemory\fR, \fIargs\fR, +\&\fIexec\fR, \fIpty\fR, \fIutmp\fR, \fIconv\fR, \fIpcomm\fR, \fIutil\fR, \fIlist\fR, +\&\fInetif\fR, \fIaudit\fR, \fIedit\fR, \fIselinux\fR, \fIldap\fR, \fImatch\fR, \fIparser\fR, +\&\fIalias\fR, \fIdefaults\fR, \fIauth\fR, \fIenv\fR, \fIlogging\fR, \fInss\fR, \fIrbtree\fR, +\&\fIperms\fR, \fIplugin\fR. The subsystem \fIall\fR includes every subsystem. +.Sp +There is not currently a way to specify a set of debug flags specific +to the plugin\*(--the flags are shared by \fBsudo\fR and the plugin. .IP "debug_level=number" 4 .IX Item "debug_level=number" -A numeric debug level, from 1\-9, if specified via the \f(CW\*(C`\-D\*(C'\fR flag. +This setting has been deprecated in favor of \fIdebug_flags\fR. .IP "runas_user=string" 4 .IX Item "runas_user=string" The user name or uid to to run the command as, if specified via the @@ -392,12 +424,42 @@ When parsing \fIuser_info\fR, the plugin should split equal sign ('=') since the \fIname\fR field will never include one itself but the \fIvalue\fR might. .RS 4 +.IP "pid=int" 4 +.IX Item "pid=int" +The process \s-1ID\s0 of the running \fBsudo\fR process. +Only available starting with \s-1API\s0 version 1.2 +.IP "ppid=int" 4 +.IX Item "ppid=int" +The parent process \s-1ID\s0 of the running \fBsudo\fR process. +Only available starting with \s-1API\s0 version 1.2 +.IP "sid=int" 4 +.IX Item "sid=int" +The session \s-1ID\s0 of the running \fBsudo\fR process or 0 if \fBsudo\fR is +not part of a \s-1POSIX\s0 job control session. +Only available starting with \s-1API\s0 version 1.2 +.IP "pgid=int" 4 +.IX Item "pgid=int" +The \s-1ID\s0 of the process group that the running \fBsudo\fR process belongs +to. +Only available starting with \s-1API\s0 version 1.2 +.IP "tcpgid=int" 4 +.IX Item "tcpgid=int" +The \s-1ID\s0 of the forground process group associated with the terminal +device associcated with the \fBsudo\fR process or \-1 if there is no +terminal present. +Only available starting with \s-1API\s0 version 1.2 .IP "user=string" 4 .IX Item "user=string" The name of the user invoking \fBsudo\fR. +.IP "euid=uid_t" 4 +.IX Item "euid=uid_t" +The effective user \s-1ID\s0 of the user invoking \fBsudo\fR. .IP "uid=uid_t" 4 .IX Item "uid=uid_t" The real user \s-1ID\s0 of the user invoking \fBsudo\fR. +.IP "egid=gid_t" 4 +.IX Item "egid=gid_t" +The effective group \s-1ID\s0 of the user invoking \fBsudo\fR. .IP "gid=gid_t" 4 .IX Item "gid=gid_t" The real group \s-1ID\s0 of the user invoking \fBsudo\fR. @@ -436,6 +498,18 @@ The user's environment in the form of a \f(CW\*(C`NULL When parsing \fIuser_env\fR, the plugin should split on the \fBfirst\fR equal sign ('=') since the \fIname\fR field will never include one itself but the \fIvalue\fR might. +.IP "plugin_options" 4 +.IX Item "plugin_options" +Any (non-comment) strings immediately after the plugin path are +treated as arguments to the plugin. These arguments are split on +a white space boundary and are passed to the plugin in the form of +a \f(CW\*(C`NULL\*(C'\fR\-terminated array of strings. If no arguments were +specified, \fIplugin_options\fR will be the \s-1NULL\s0 pointer. +.Sp +\&\s-1NOTE:\s0 the \fIplugin_options\fR parameter is only available starting with +\&\s-1API\s0 version 1.2. A plugin \fBmust\fR check the \s-1API\s0 version specified +by the \fBsudo\fR front end before using \fIplugin_options\fR. Failure to +do so may result in a crash. .RE .RS 4 .RE @@ -753,28 +827,100 @@ support credential caching. .IP "init_session" 4 .IX Item "init_session" .Vb 1 -\& int (*init_session)(struct passwd *pwd); +\& int (*init_session)(struct passwd *pwd, char **user_envp[); .Ve .Sp -The \f(CW\*(C`init_session\*(C'\fR function is called when \fBsudo\fR sets up the -execution environment for the command, immediately before the -contents of the \fIcommand_info\fR list are applied (before the uid -changes). This can be used to do session setup that is not supported -by \fIcommand_info\fR, such as opening the \s-1PAM\s0 session. +The \f(CW\*(C`init_session\*(C'\fR function is called before \fBsudo\fR sets up the +execution environment for the command. It is run in the parent +\&\fBsudo\fR process and before any uid or gid changes. This can be used +to perform session setup that is not supported by \fIcommand_info\fR, +such as opening the \s-1PAM\s0 session. The \f(CW\*(C`close\*(C'\fR function can be +used to tear down the session that was opened by \f(CW\*(C`init_session\*(C'\fR. .Sp The \fIpwd\fR argument points to a passwd struct for the user the command will be run as if the uid the command will run as was found in the password database, otherwise it will be \s-1NULL\s0. .Sp +The \fIuser_env\fR argument points to the environment the command will +run in, in the form of a \f(CW\*(C`NULL\*(C'\fR\-terminated vector of \*(L"name=value\*(R" +strings. This is the same string passed back to the front end via +the Policy Plugin's \fIuser_env_out\fR parameter. If the \f(CW\*(C`init_session\*(C'\fR +function needs to modify the user environment, it should update the +pointer stored in \fIuser_env\fR. The expected use case is to merge +the contents of the \s-1PAM\s0 environment (if any) with the contents of +\&\fIuser_env\fR. \s-1NOTE:\s0 the \fIuser_env\fR parameter is only available +starting with \s-1API\s0 version 1.2. A plugin \fBmust\fR check the \s-1API\s0 +version specified by the \fBsudo\fR front end before using \fIuser_env\fR. +Failure to do so may result in a crash. +.Sp Returns 1 on success, 0 on failure and \-1 on error. On error, the plugin may optionally call the conversation or plugin_printf function with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present additional error information to the user. +.IP "register_hooks" 4 +.IX Item "register_hooks" +.Vb 2 +\& void (*register_hooks)(int version, +\& int (*register_hook)(struct sudo_hook *hook)); +.Ve +.Sp +The \f(CW\*(C`register_hooks\*(C'\fR function is called by the sudo front end to +register any hooks the plugin needs. If the plugin does not support +hooks, \f(CW\*(C`register_hooks\*(C'\fR should be set to the \s-1NULL\s0 pointer. +.Sp +The \fIversion\fR argument describes the version of the hooks \s-1API\s0 +supported by the \fBsudo\fR front end. +.Sp +The \f(CW\*(C`register_hook\*(C'\fR function should be used to register any supported +hooks the plugin needs. It returns 0 on success, 1 if the hook +type is not supported and \-1 if the major version in \f(CW\*(C`struct hook\*(C'\fR +does not match the front end's major hook \s-1API\s0 version. +.Sp +See the \*(L"Hook Function \s-1API\s0\*(R" section below for more information +about hooks. +.Sp +\&\s-1NOTE:\s0 the \f(CW\*(C`register_hooks\*(C'\fR function is only available starting +with \s-1API\s0 version 1.2. If the \fBsudo\fR front end doesn't support \s-1API\s0 +version 1.2 or higher, \f(CW\*(C`register_hooks\*(C'\fR will not be called. +.IP "deregister_hooks" 4 +.IX Item "deregister_hooks" +.Vb 2 +\& void (*deregister_hooks)(int version, +\& int (*deregister_hook)(struct sudo_hook *hook)); +.Ve +.Sp +The \f(CW\*(C`deregister_hooks\*(C'\fR function is called by the sudo front end +to deregister any hooks the plugin has registered. If the plugin +does not support hooks, \f(CW\*(C`deregister_hooks\*(C'\fR should be set to the +\&\s-1NULL\s0 pointer. +.Sp +The \fIversion\fR argument describes the version of the hooks \s-1API\s0 +supported by the \fBsudo\fR front end. +.Sp +The \f(CW\*(C`deregister_hook\*(C'\fR function should be used to deregister any +hooks that were put in place by the \f(CW\*(C`register_hook\*(C'\fR function. If +the plugin tries to deregister a hook that the front end does not +support, \f(CW\*(C`deregister_hook\*(C'\fR will return an error. +.Sp +See the \*(L"Hook Function \s-1API\s0\*(R" section below for more information +about hooks. +.Sp +\&\s-1NOTE:\s0 the \f(CW\*(C`deregister_hooks\*(C'\fR function is only available starting +with \s-1API\s0 version 1.2. If the \fBsudo\fR front end doesn't support \s-1API\s0 +version 1.2 or higher, \f(CW\*(C`deregister_hooks\*(C'\fR will not be called. .PP -\fIVersion macros\fR -.IX Subsection "Version macros" +\fIPolicy Plugin Version Macros\fR +.IX Subsection "Policy Plugin Version Macros" .PP -.Vb 8 +.Vb 6 +\& /* 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,\e +\& SUDO_API_VERSION_MINOR) +\& +\& /* Getters and setters for API version */ \& #define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16) \& #define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff) \& #define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \e @@ -783,11 +929,6 @@ error information to the user. \& #define SUDO_VERSION_SET_MINOR(vp, n) do { \e \& *(vp) = (*(vp) & 0xffff0000) | (n); \e \& } while(0) -\& -\& #define SUDO_API_VERSION_MAJOR 1 -\& #define SUDO_API_VERSION_MINOR 0 -\& #define SUDO_API_VERSION ((SUDO_API_VERSION_MAJOR << 16) | \e -\& SUDO_API_VERSION_MINOR) .Ve .SS "I/O Plugin \s-1API\s0" .IX Subsection "I/O Plugin API" @@ -799,7 +940,7 @@ error information to the user. \& int (*open)(unsigned int version, sudo_conv_t conversation \& sudo_printf_t plugin_printf, char * const settings[], \& char * const user_info[], int argc, char * const argv[], -\& char * const user_env[]); +\& char * const user_env[], char * const plugin_options[]); \& 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); @@ -807,6 +948,10 @@ error information to the user. \& 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); +\& void (*register_hooks)(int version, +\& int (*register_hook)(struct sudo_hook *hook)); +\& void (*deregister_hooks)(int version, +\& int (*deregister_hook)(struct sudo_hook *hook)); \& }; .Ve .PP @@ -845,7 +990,7 @@ built against. \& int (*open)(unsigned int version, sudo_conv_t conversation \& sudo_printf_t plugin_printf, char * const settings[], \& char * const user_info[], int argc, char * const argv[], -\& char * const user_env[]); +\& char * const user_env[], char * const plugin_options[]); .Ve .Sp The \fIopen\fR function is run before the \fIlog_input\fR, \fIlog_output\fR @@ -920,6 +1065,18 @@ The user's environment in the form of a \f(CW\*(C`NULL When parsing \fIuser_env\fR, the plugin should split on the \fBfirst\fR equal sign ('=') since the \fIname\fR field will never include one itself but the \fIvalue\fR might. +.IP "plugin_options" 4 +.IX Item "plugin_options" +Any (non-comment) strings immediately after the plugin path are +treated as arguments to the plugin. These arguments are split on +a white space boundary and are passed to the plugin in the form of +a \f(CW\*(C`NULL\*(C'\fR\-terminated array of strings. If no arguments were +specified, \fIplugin_options\fR will be the \s-1NULL\s0 pointer. +.Sp +\&\s-1NOTE:\s0 the \fIplugin_options\fR parameter is only available starting with +\&\s-1API\s0 version 1.2. A plugin \fBmust\fR check the \s-1API\s0 version specified +by the \fBsudo\fR front end before using \fIplugin_options\fR. Failure to +do so may result in a crash. .RE .RS 4 .RE @@ -1083,11 +1240,178 @@ The length of \fIbuf\fR in bytes. .RE .RS 4 .RE +.IP "register_hooks" 4 +.IX Item "register_hooks" +See the \*(L"Policy Plugin \s-1API\s0\*(R" section for a description of +\&\f(CW\*(C`register_hooks\*(C'\fR. +.IP "deregister_hooks" 4 +.IX Item "deregister_hooks" +See the \*(L"Policy Plugin \s-1API\s0\*(R" section for a description of +\&\f(CW\*(C`deregister_hooks\*(C'\fR. .PP -\fIVersion macros\fR -.IX Subsection "Version macros" +\fII/O Plugin Version Macros\fR +.IX Subsection "I/O Plugin Version Macros" .PP Same as for the \*(L"Policy Plugin \s-1API\s0\*(R". +.SS "Hook Function \s-1API\s0" +.IX Subsection "Hook Function API" +Beginning with plugin \s-1API\s0 version 1.2, it is possible to install +hooks for certain functions called by the \fBsudo\fR front end. +.PP +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 \s-1API\s0 will support +hooking internal \fBsudo\fR front end functions as well. +.PP +\fIHook structure\fR +.IX Subsection "Hook structure" +.PP +Hooks in \fBsudo\fR are described by the following structure: +.PP +.Vb 1 +\& typedef int (*sudo_hook_fn_t)(); +\& +\& struct sudo_hook { +\& int hook_version; +\& int hook_type; +\& sudo_hook_fn_t hook_fn; +\& void *closure; +\& }; +.Ve +.PP +The \f(CW\*(C`sudo_hook\*(C'\fR structure has the following fields: +.IP "hook_version" 4 +.IX Item "hook_version" +The \f(CW\*(C`hook_version\*(C'\fR field should be set to \s-1SUDO_HOOK_VERSION\s0. +.IP "hook_type" 4 +.IX Item "hook_type" +The \f(CW\*(C`hook_type\*(C'\fR field may be one of the following supported hook types: +.RS 4 +.IP "\s-1SUDO_HOOK_SETENV\s0" 4 +.IX Item "SUDO_HOOK_SETENV" +The C library \f(CW\*(C`setenv()\*(C'\fR function. Any registered hooks will run +before the C library implementation. The \f(CW\*(C`hook_fn\*(C'\fR field should +be a function that matches the following typedef: +.Sp +.Vb 2 +\& typedef int (*sudo_hook_fn_setenv_t)(const char *name, +\& const char *value, int overwrite, void *closure); +.Ve +.Sp +If the registered hook does not match the typedef the results are +unspecified. +.IP "\s-1SUDO_HOOK_UNSETENV\s0" 4 +.IX Item "SUDO_HOOK_UNSETENV" +The C library \f(CW\*(C`unsetenv()\*(C'\fR function. Any registered hooks will run +before the C library implementation. The \f(CW\*(C`hook_fn\*(C'\fR field should +be a function that matches the following typedef: +.Sp +.Vb 2 +\& typedef int (*sudo_hook_fn_unsetenv_t)(const char *name, +\& void *closure); +.Ve +.IP "\s-1SUDO_HOOK_GETENV\s0" 4 +.IX Item "SUDO_HOOK_GETENV" +The C library \f(CW\*(C`getenv()\*(C'\fR function. Any registered hooks will run +before the C library implementation. The \f(CW\*(C`hook_fn\*(C'\fR field should +be a function that matches the following typedef: +.Sp +.Vb 2 +\& typedef int (*sudo_hook_fn_getenv_t)(const char *name, +\& char **value, void *closure); +.Ve +.Sp +If the registered hook does not match the typedef the results are +unspecified. +.IP "\s-1SUDO_HOOK_PUTENV\s0" 4 +.IX Item "SUDO_HOOK_PUTENV" +The C library \f(CW\*(C`putenv()\*(C'\fR function. Any registered hooks will run +before the C library implementation. The \f(CW\*(C`hook_fn\*(C'\fR field should +be a function that matches the following typedef: +.Sp +.Vb 2 +\& typedef int (*sudo_hook_fn_putenv_t)(char *string, +\& void *closure); +.Ve +.Sp +If the registered hook does not match the typedef the results are +unspecified. +.RE +.RS 4 +.RE +.IP "hook_fn" 4 +.IX Item "hook_fn" +.Vb 1 +\& sudo_hook_fn_t hook_fn; +.Ve +.Sp +The \f(CW\*(C`hook_fn\*(C'\fR field should be set to the plugin's hook implementation. +The actual function arguments will vary depending on the \f(CW\*(C`hook_type\*(C'\fR +(see \f(CW\*(C`hook_type\*(C'\fR above). In all cases, the \f(CW\*(C`closure\*(C'\fR field of +\&\f(CW\*(C`struct sudo_hook\*(C'\fR is passed as the last function parameter. This +can be used to pass arbitrary data to the plugin's hook implementation. +.Sp +The function return value may be one of the following: +.RS 4 +.IP "\s-1SUDO_HOOK_RET_ERROR\s0" 4 +.IX Item "SUDO_HOOK_RET_ERROR" +The hook function encountered an error. +.IP "\s-1SUDO_HOOK_RET_NEXT\s0" 4 +.IX 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 \f(CW\*(C`getenv\*(C'\fR +hook might return \f(CW\*(C`SUDO_HOOK_RET_NEXT\*(C'\fR if the specified variable +was not found in the private copy of the environment. +.IP "\s-1SUDO_HOOK_RET_STOP\s0" 4 +.IX 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 \f(CW\*(C`setenv\*(C'\fR hook that operates on a private copy of +the environment but leaves \f(CW\*(C`environ\*(C'\fR unchanged. +.RE +.RS 4 +.RE +.PP +Note that it is very easy to create an infinite loop when hooking +C library functions. For example, a \f(CW\*(C`getenv\*(C'\fR hook that calls the +\&\f(CW\*(C`snprintf\*(C'\fR function may create a loop if the \f(CW\*(C`snprintf\*(C'\fR implementation +calls \f(CW\*(C`getenv\*(C'\fR 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. +.PP +.Vb 7 +\& 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; +.Ve +.PP +\fIHook \s-1API\s0 Version Macros\fR +.IX Subsection "Hook API Version Macros" +.PP +.Vb 6 +\& /* 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,\e +\& 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 { \e +\& *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \e +\& } while(0) +\& #define SUDO_HOOK_VERSION_SET_MINOR(vp, n) do { \e +\& *(vp) = (*(vp) & 0xffff0000) | (n); \e +\& } while(0) +.Ve .SS "Conversation \s-1API\s0" .IX Subsection "Conversation API" If the plugin needs to interact with the user, it may do so via the @@ -1100,13 +1424,14 @@ A printf-style function is also available that can be informational or error messages to the user, which is usually more convenient for simple messages where no use input is required. .PP -.Vb 11 +.Vb 12 \& struct sudo_conv_message { \& #define SUDO_CONV_PROMPT_ECHO_OFF 0x0001 /* do not echo user input */ \& #define SUDO_CONV_PROMPT_ECHO_ON 0x0002 /* echo user input */ \& #define SUDO_CONV_ERROR_MSG 0x0003 /* error message */ \& #define SUDO_CONV_INFO_MSG 0x0004 /* informational message */ \& #define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */ +\& #define SUDO_CONV_DEBUG_MSG 0x0006 /* debugging message */ \& #define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */ \& int msg_type; \& int timeout; @@ -1135,11 +1460,19 @@ freeing the reply buffer filled in to the \f(CW\*(C`st if any. .PP The printf-style function uses the same underlying mechanism as the -conversation function but only supports \f(CW\*(C`SUDO_CONV_INFO_MSG\*(C'\fR and -\&\f(CW\*(C`SUDO_CONV_ERROR_MSG\*(C'\fR for the \fImsg_type\fR parameter. It can be -more convenient than using the conversation function if no user -reply is needed and supports standard \fIprintf()\fR escape sequences. +conversation function but only supports \f(CW\*(C`SUDO_CONV_INFO_MSG\*(C'\fR, +\&\f(CW\*(C`SUDO_CONV_ERROR_MSG\*(C'\fR and \f(CW\*(C`SUDO_CONV_DEBUG_MSG\*(C'\fR for the \fImsg_type\fR +parameter. It can be more convenient than using the conversation +function if no user reply is needed and supports standard \fIprintf()\fR +escape sequences. .PP +Unlike, \f(CW\*(C`SUDO_CONV_INFO_MSG\*(C'\fR and \f(CW\*(C`SUDO_CONV_ERROR_MSG\*(C'\fR, messages +sent with the <\s-1SUDO_CONV_DEBUG_MSG\s0> \fImsg_type\fR are not directly +user-visible. Instead, they are logged to the file specified in +the \f(CW\*(C`Debug\*(C'\fR statement (if any) in the \fI@sysconfdir@/sudo.conf\fR +file. This allows a plugin to log debugging information and is +intended to be used in conjunction with the \fIdebug_flags\fR setting. +.PP See the sample plugin for an example of the conversation function usage. .SS "Sudoers Group Plugin \s-1API\s0" .IX Subsection "Sudoers Group Plugin API" @@ -1241,8 +1574,8 @@ present in the password database, \fIpwd\fR will be \f .RS 4 .RE .PP -\fIVersion Macros\fR -.IX Subsection "Version Macros" +\fIGroup \s-1API\s0 Version Macros\fR +.IX Subsection "Group API Version Macros" .PP .Vb 5 \& /* Sudoers group plugin version major/minor */ @@ -1261,6 +1594,28 @@ present in the password database, \fIpwd\fR will be \f \& *(vp) = (*(vp) & 0xffff0000) | (n); \e \& } while(0) .Ve +.SH "PLUGIN API CHANGELOG" +.IX Header "PLUGIN API CHANGELOG" +The following revisions have been made to the Sudo Plugin \s-1API\s0. +.IP "Version 1.0" 4 +.IX Item "Version 1.0" +Initial \s-1API\s0 version. +.IP "Version 1.1" 4 +.IX Item "Version 1.1" +The I/O logging plugin's \f(CW\*(C`open\*(C'\fR function was modified to take the +\&\f(CW\*(C`command_info\*(C'\fR list as an argument. +.IP "Version 1.2" 4 +.IX Item "Version 1.2" +The Policy and I/O logging plugins' \f(CW\*(C`open\*(C'\fR functions are now passed +a list of plugin options if any are specified in \fI@sysconfdir@/sudo.conf\fR. +.Sp +A simple hooks \s-1API\s0 has been introduced to allow plugins to hook in to the +system's environment handling functions. +.Sp +The \f(CW\*(C`init_session\*(C'\fR Policy plugin function is now passed a pointer +to the user environment which can be updated as needed. This can +be used to merge in environment variables stored in the \s-1PAM\s0 handle +before a command is run. .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fIsudoers\fR\|(@mansectform@), \fIsudo\fR\|(@mansectsu@)