update control to reflect move of primary repo to collab-maint
[debian/sudo] / doc / sudo_plugin.cat
index 2638092287bdb169fea481fdbe8f725986b58e63..1d9a9963fc926775c4b817678eb7785ab02f9548 100644 (file)
@@ -32,8 +32,8 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
        io_plugin in the plugin shared object.  The _\bp_\ba_\bt_\bh may be fully qualified
        or relative.  If not fully qualified it is relative to the
        _\b/_\bu_\bs_\br_\b/_\bl_\bo_\bc_\ba_\bl_\b/_\bl_\bi_\bb_\be_\bx_\be_\bc directory.  Any additional parameters after the _\bp_\ba_\bt_\bh
-       are ignored.  Lines that don't begin with Plugin or Path are silently
-       ignored.
+       are passed as options to the plugin's _\bo_\bp_\be_\bn function.  Lines that don't
+       begin with Plugin, Path, Debug or Set are silently ignored.
 
        The same shared object may contain multiple plugins, each with a
        different symbol name.  The shared object file must be owned by uid 0
@@ -45,13 +45,17 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
         # Default /etc/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 /usr/local/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
@@ -69,7 +73,8 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
             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[],
@@ -79,7 +84,11 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
                         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));
         };
 
        The policy_plugin struct has the following fields:
@@ -96,7 +105,8 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
        open
             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[]);
 
            Returns 1 on success, 0 on failure, -1 if a general error occurred,
            or -2 if there was a usage error.  In the latter case, s\bsu\bud\bdo\bo will
@@ -133,9 +143,31 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
                equal sign ('=') since the _\bn_\ba_\bm_\be field will never include one
                itself but the _\bv_\ba_\bl_\bu_\be might.
 
+               debug_flags=string
+                   A comma-separated list of debug flags that correspond to
+                   s\bsu\bud\bdo\bo's Debug entry in _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b._\bc_\bo_\bn_\bf, if there is one.  The
+                   flags are passed to the plugin as they appear in
+                   _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b._\bc_\bo_\bn_\bf.  The syntax used by s\bsu\bud\bdo\bo and the _\bs_\bu_\bd_\bo_\be_\br_\bs
+                   plugin is _\bs_\bu_\bb_\bs_\by_\bs_\bt_\be_\bm@_\bp_\br_\bi_\bo_\br_\bi_\bt_\by but the plugin is free to use
+                   a different format so long as it does not include a command
+                   ,.
+
+                   For reference, the priorities supported by the s\bsu\bud\bdo\bo front
+                   end and _\bs_\bu_\bd_\bo_\be_\br_\bs are: _\bc_\br_\bi_\bt, _\be_\br_\br, _\bw_\ba_\br_\bn, _\bn_\bo_\bt_\bi_\bc_\be, _\bd_\bi_\ba_\bg, _\bi_\bn_\bf_\bo,
+                   _\bt_\br_\ba_\bc_\be and _\bd_\be_\bb_\bu_\bg.
+
+                   The following subsystems are defined: _\bm_\ba_\bi_\bn, _\bm_\be_\bm_\bo_\br_\by, _\ba_\br_\bg_\bs,
+                   _\be_\bx_\be_\bc, _\bp_\bt_\by, _\bu_\bt_\bm_\bp, _\bc_\bo_\bn_\bv, _\bp_\bc_\bo_\bm_\bm, _\bu_\bt_\bi_\bl, _\bl_\bi_\bs_\bt, _\bn_\be_\bt_\bi_\bf, _\ba_\bu_\bd_\bi_\bt,
+                   _\be_\bd_\bi_\bt, _\bs_\be_\bl_\bi_\bn_\bu_\bx, _\bl_\bd_\ba_\bp, _\bm_\ba_\bt_\bc_\bh, _\bp_\ba_\br_\bs_\be_\br, _\ba_\bl_\bi_\ba_\bs, _\bd_\be_\bf_\ba_\bu_\bl_\bt_\bs, _\ba_\bu_\bt_\bh,
+                   _\be_\bn_\bv, _\bl_\bo_\bg_\bg_\bi_\bn_\bg, _\bn_\bs_\bs, _\br_\bb_\bt_\br_\be_\be, _\bp_\be_\br_\bm_\bs, _\bp_\bl_\bu_\bg_\bi_\bn.  The subsystem
+                   _\ba_\bl_\bl includes every subsystem.
+
+                   There is not currently a way to specify a set of debug
+                   flags specific to the plugin--the flags are shared by s\bsu\bud\bdo\bo
+                   and the plugin.
+
                debug_level=number
-                   A numeric debug level, from 1-9, if specified via the -D
-                   flag.
+                   This setting has been deprecated in favor of _\bd_\be_\bb_\bu_\bg_\b__\bf_\bl_\ba_\bg_\bs.
 
                runas_user=string
                    The user name or uid to to run the command as, if specified
@@ -244,12 +276,41 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
                equal sign ('=') since the _\bn_\ba_\bm_\be field will never include one
                itself but the _\bv_\ba_\bl_\bu_\be might.
 
+               pid=int
+                   The process ID of the running s\bsu\bud\bdo\bo process.  Only available
+                   starting with API version 1.2
+
+               ppid=int
+                   The parent process ID of the running s\bsu\bud\bdo\bo process.  Only
+                   available starting with API version 1.2
+
+               sid=int
+                   The session ID of the running s\bsu\bud\bdo\bo process or 0 if s\bsu\bud\bdo\bo is
+                   not part of a POSIX job control session.  Only available
+                   starting with API version 1.2
+
+               pgid=int
+                   The ID of the process group that the running s\bsu\bud\bdo\bo process
+                   belongs to.  Only available starting with API version 1.2
+
+               tcpgid=int
+                   The ID of the forground process group associated with the
+                   terminal device associcated with the s\bsu\bud\bdo\bo process or -1 if
+                   there is no terminal present.  Only available starting with
+                   API version 1.2
+
                user=string
                    The name of the user invoking s\bsu\bud\bdo\bo.
 
+               euid=uid_t
+                   The effective user ID of the user invoking s\bsu\bud\bdo\bo.
+
                uid=uid_t
                    The real user ID of the user invoking s\bsu\bud\bdo\bo.
 
+               egid=gid_t
+                   The effective group ID of the user invoking s\bsu\bud\bdo\bo.
+
                gid=gid_t
                    The real group ID of the user invoking s\bsu\bud\bdo\bo.
 
@@ -287,6 +348,18 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
                equal sign ('=') since the _\bn_\ba_\bm_\be field will never include one
                itself but the _\bv_\ba_\bl_\bu_\be might.
 
+           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 NULL-terminated array of strings.  If no arguments
+               were specified, _\bp_\bl_\bu_\bg_\bi_\bn_\b__\bo_\bp_\bt_\bi_\bo_\bn_\bs will be the NULL pointer.
+
+               NOTE: the _\bp_\bl_\bu_\bg_\bi_\bn_\b__\bo_\bp_\bt_\bi_\bo_\bn_\bs parameter is only available starting
+               with API version 1.2.  A plugin m\bmu\bus\bst\bt check the API version
+               specified by the s\bsu\bud\bdo\bo front end before using _\bp_\bl_\bu_\bg_\bi_\bn_\b__\bo_\bp_\bt_\bi_\bo_\bn_\bs.
+               Failure to do so may result in a crash.
+
        close
             void (*close)(int exit_status, int error);
 
@@ -583,25 +656,93 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
            support credential caching.
 
        init_session
-            int (*init_session)(struct passwd *pwd);
+            int (*init_session)(struct passwd *pwd, char **user_envp[);
 
-           The init_session function is called when s\bsu\bud\bdo\bo sets up the execution
-           environment for the command, immediately before the contents of the
-           _\bc_\bo_\bm_\bm_\ba_\bn_\bd_\b__\bi_\bn_\bf_\bo list are applied (before the uid changes).  This can
-           be used to do session setup that is not supported by _\bc_\bo_\bm_\bm_\ba_\bn_\bd_\b__\bi_\bn_\bf_\bo,
-           such as opening the PAM session.
+           The init_session function is called before s\bsu\bud\bdo\bo sets up the
+           execution environment for the command.  It is run in the parent
+           s\bsu\bud\bdo\bo process and before any uid or gid changes.  This can be used
+           to perform session setup that is not supported by _\bc_\bo_\bm_\bm_\ba_\bn_\bd_\b__\bi_\bn_\bf_\bo,
+           such as opening the PAM session.  The close function can be used to
+           tear down the session that was opened by init_session.
 
            The _\bp_\bw_\bd 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 NULL.
 
+           The _\bu_\bs_\be_\br_\b__\be_\bn_\bv argument points to the environment the command will
+           run in, in the form of a NULL-terminated vector of "name=value"
+           strings.  This is the same string passed back to the front end via
+           the Policy Plugin's _\bu_\bs_\be_\br_\b__\be_\bn_\bv_\b__\bo_\bu_\bt parameter.  If the init_session
+           function needs to modify the user environment, it should update the
+           pointer stored in _\bu_\bs_\be_\br_\b__\be_\bn_\bv.  The expected use case is to merge the
+           contents of the PAM environment (if any) with the contents of
+           _\bu_\bs_\be_\br_\b__\be_\bn_\bv.  NOTE: the _\bu_\bs_\be_\br_\b__\be_\bn_\bv parameter is only available starting
+           with API version 1.2.  A plugin m\bmu\bus\bst\bt check the API version
+           specified by the s\bsu\bud\bdo\bo front end before using _\bu_\bs_\be_\br_\b__\be_\bn_\bv.  Failure to
+           do so may result in a crash.
+
            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 SUDO_CONF_ERROR_MSG to present additional error
            information to the user.
 
-       _\bV_\be_\br_\bs_\bi_\bo_\bn _\bm_\ba_\bc_\br_\bo_\bs
+       register_hooks
+            void (*register_hooks)(int version,
+               int (*register_hook)(struct sudo_hook *hook));
+
+           The register_hooks function is called by the sudo front end to
+           register any hooks the plugin needs.  If the plugin does not
+           support hooks, register_hooks should be set to the NULL pointer.
+
+           The _\bv_\be_\br_\bs_\bi_\bo_\bn argument describes the version of the hooks API
+           supported by the s\bsu\bud\bdo\bo front end.
+
+           The register_hook 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 struct hook
+           does not match the front end's major hook API version.
+
+           See the "Hook Function API" section below for more information
+           about hooks.
+
+           NOTE: the register_hooks function is only available starting with
+           API version 1.2.  If the s\bsu\bud\bdo\bo front end doesn't support API version
+           1.2 or higher, register_hooks will not be called.
+
+       deregister_hooks
+            void (*deregister_hooks)(int version,
+               int (*deregister_hook)(struct sudo_hook *hook));
+
+           The 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, deregister_hooks should be set to the NULL
+           pointer.
+
+           The _\bv_\be_\br_\bs_\bi_\bo_\bn argument describes the version of the hooks API
+           supported by the s\bsu\bud\bdo\bo front end.
+
+           The deregister_hook function should be used to deregister any hooks
+           that were put in place by the register_hook function.  If the
+           plugin tries to deregister a hook that the front end does not
+           support, deregister_hook will return an error.
+
+           See the "Hook Function API" section below for more information
+           about hooks.
+
+           NOTE: the deregister_hooks function is only available starting with
+           API version 1.2.  If the s\bsu\bud\bdo\bo front end doesn't support API version
+           1.2 or higher, deregister_hooks will not be called.
+
+       _\bP_\bo_\bl_\bi_\bc_\by _\bP_\bl_\bu_\bg_\bi_\bn _\bV_\be_\br_\bs_\bi_\bo_\bn _\bM_\ba_\bc_\br_\bo_\bs
+
+        /* 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_MINOR(v) ((v) & 0xffff)
         #define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \
@@ -611,11 +752,6 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
             *(vp) = (*(vp) & 0xffff0000) | (n); \
         } 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)
-
    I\bI/\b/O\bO P\bPl\blu\bug\bgi\bin\bn A\bAP\bPI\bI
         struct io_plugin {
         #define SUDO_IO_PLUGIN         2
@@ -624,7 +760,7 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
             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);
@@ -632,6 +768,10 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
             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));
         };
 
        When an I/O plugin is loaded, s\bsu\bud\bdo\bo runs the command in a pseudo-tty.
@@ -667,7 +807,7 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
             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[]);
 
            The _\bo_\bp_\be_\bn function is run before the _\bl_\bo_\bg_\b__\bi_\bn_\bp_\bu_\bt, _\bl_\bo_\bg_\b__\bo_\bu_\bt_\bp_\bu_\bt or
            _\bs_\bh_\bo_\bw_\b__\bv_\be_\br_\bs_\bi_\bo_\bn functions are called.  It is only called if the
@@ -744,6 +884,18 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
                equal sign ('=') since the _\bn_\ba_\bm_\be field will never include one
                itself but the _\bv_\ba_\bl_\bu_\be might.
 
+           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 NULL-terminated array of strings.  If no arguments
+               were specified, _\bp_\bl_\bu_\bg_\bi_\bn_\b__\bo_\bp_\bt_\bi_\bo_\bn_\bs will be the NULL pointer.
+
+               NOTE: the _\bp_\bl_\bu_\bg_\bi_\bn_\b__\bo_\bp_\bt_\bi_\bo_\bn_\bs parameter is only available starting
+               with API version 1.2.  A plugin m\bmu\bus\bst\bt check the API version
+               specified by the s\bsu\bud\bdo\bo front end before using _\bp_\bl_\bu_\bg_\bi_\bn_\b__\bo_\bp_\bt_\bi_\bo_\bn_\bs.
+               Failure to do so may result in a crash.
+
        close
             void (*close)(int exit_status, int error);
 
@@ -854,10 +1006,153 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 
            len The length of _\bb_\bu_\bf in bytes.
 
-       _\bV_\be_\br_\bs_\bi_\bo_\bn _\bm_\ba_\bc_\br_\bo_\bs
+       register_hooks
+           See the "Policy Plugin API" section for a description of
+           register_hooks.
+
+       deregister_hooks
+           See the "Policy Plugin API" section for a description of
+           deregister_hooks.
+
+       _\bI_\b/_\bO _\bP_\bl_\bu_\bg_\bi_\bn _\bV_\be_\br_\bs_\bi_\bo_\bn _\bM_\ba_\bc_\br_\bo_\bs
 
        Same as for the "Policy Plugin API".
 
+   H\bHo\boo\bok\bk F\bFu\bun\bnc\bct\bti\bio\bon\bn A\bAP\bPI\bI
+       Beginning with plugin API version 1.2, it is possible to install hooks
+       for certain functions called by the s\bsu\bud\bdo\bo 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
+       s\bsu\bud\bdo\bo front end functions as well.
+
+       _\bH_\bo_\bo_\bk _\bs_\bt_\br_\bu_\bc_\bt_\bu_\br_\be
+
+       Hooks in s\bsu\bud\bdo\bo 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 sudo_hook structure has the following fields:
+
+       hook_version
+           The hook_version field should be set to SUDO_HOOK_VERSION.
+
+       hook_type
+           The hook_type field may be one of the following supported hook
+           types:
+
+           SUDO_HOOK_SETENV
+               The C library setenv() function.  Any registered hooks will run
+               before the C library implementation.  The 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.
+
+           SUDO_HOOK_UNSETENV
+               The C library unsetenv() function.  Any registered hooks will
+               run before the C library implementation.  The hook_fn field
+               should be a function that matches the following typedef:
+
+                typedef int (*sudo_hook_fn_unsetenv_t)(const char *name,
+                   void *closure);
+
+           SUDO_HOOK_GETENV
+               The C library getenv() function.  Any registered hooks will run
+               before the C library implementation.  The 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.
+
+           SUDO_HOOK_PUTENV
+               The C library putenv() function.  Any registered hooks will run
+               before the C library implementation.  The 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.
+
+       hook_fn
+            sudo_hook_fn_t hook_fn;
+
+           The hook_fn field should be set to the plugin's hook
+           implementation.  The actual function arguments will vary depending
+           on the hook_type (see hook_type above).  In all cases, the closure
+           field of 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:
+
+           SUDO_HOOK_RET_ERROR
+               The hook function encountered an error.
+
+           SUDO_HOOK_RET_NEXT
+               The hook completed without error, go on to the next hook
+               (including the native implementation if applicable).  For
+               example, a getenv hook might return SUDO_HOOK_RET_NEXT if the
+               specified variable was not found in the private copy of the
+               environment.
+
+           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 setenv hook that operates on a
+               private copy of the environment but leaves environ unchanged.
+
+       Note that it is very easy to create an infinite loop when hooking C
+       library functions.  For example, a getenv hook that calls the snprintf
+       function may create a loop if the snprintf implementation calls 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;
+
+       _\bH_\bo_\bo_\bk _\bA_\bP_\bI _\bV_\be_\br_\bs_\bi_\bo_\bn _\bM_\ba_\bc_\br_\bo_\bs
+
+        /* 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)
+
    C\bCo\bon\bnv\bve\ber\brs\bsa\bat\bti\bio\bon\bn A\bAP\bPI\bI
        If the plugin needs to interact with the user, it may do so via the
        conversation function.  A plugin should not attempt to read directly
@@ -875,6 +1170,7 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
         #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;
@@ -901,10 +1197,17 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
        buffer filled in to the struct sudo_conv_reply, if any.
 
        The printf-style function uses the same underlying mechanism as the
-       conversation function but only supports SUDO_CONV_INFO_MSG and
-       SUDO_CONV_ERROR_MSG for the _\bm_\bs_\bg_\b__\bt_\by_\bp_\be parameter.  It can be more
-       convenient than using the conversation function if no user reply is
-       needed and supports standard _\bp_\br_\bi_\bn_\bt_\bf_\b(_\b) escape sequences.
+       conversation function but only supports SUDO_CONV_INFO_MSG,
+       SUDO_CONV_ERROR_MSG and SUDO_CONV_DEBUG_MSG for the _\bm_\bs_\bg_\b__\bt_\by_\bp_\be parameter.
+       It can be more convenient than using the conversation function if no
+       user reply is needed and supports standard _\bp_\br_\bi_\bn_\bt_\bf_\b(_\b) escape sequences.
+
+       Unlike, SUDO_CONV_INFO_MSG and SUDO_CONV_ERROR_MSG, messages sent with
+       the <SUDO_CONV_DEBUG_MSG> _\bm_\bs_\bg_\b__\bt_\by_\bp_\be are not directly user-visible.
+       Instead, they are logged to the file specified in the Debug statement
+       (if any) in the _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b._\bc_\bo_\bn_\bf file.  This allows a plugin to log
+       debugging information and is intended to be used in conjunction with
+       the _\bd_\be_\bb_\bu_\bg_\b__\bf_\bl_\ba_\bg_\bs setting.
 
        See the sample plugin for an example of the conversation function
        usage.
@@ -991,7 +1294,7 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
            pwd The password database entry for _\bu_\bs_\be_\br, if any.  If _\bu_\bs_\be_\br is not
                present in the password database, _\bp_\bw_\bd will be NULL.
 
-       _\bV_\be_\br_\bs_\bi_\bo_\bn _\bM_\ba_\bc_\br_\bo_\bs
+       _\bG_\br_\bo_\bu_\bp _\bA_\bP_\bI _\bV_\be_\br_\bs_\bi_\bo_\bn _\bM_\ba_\bc_\br_\bo_\bs
 
         /* Sudoers group plugin version major/minor */
         #define GROUP_API_VERSION_MAJOR 1
@@ -1009,6 +1312,28 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
             *(vp) = (*(vp) & 0xffff0000) | (n); \
         } while(0)
 
+P\bPL\bLU\bUG\bGI\bIN\bN A\bAP\bPI\bI C\bCH\bHA\bAN\bNG\bGE\bEL\bLO\bOG\bG
+       The following revisions have been made to the Sudo Plugin API.
+
+       Version 1.0
+           Initial API version.
+
+       Version 1.1
+           The I/O logging plugin's open function was modified to take the
+           command_info list as an argument.
+
+       Version 1.2
+           The Policy and I/O logging plugins' open functions are now passed a
+           list of plugin options if any are specified in _\b/_\be_\bt_\bc_\b/_\bs_\bu_\bd_\bo_\b._\bc_\bo_\bn_\bf.
+
+           A simple hooks API has been introduced to allow plugins to hook in
+           to the system's environment handling functions.
+
+           The init_session 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 PAM handle
+           before a command is run.
+
 S\bSE\bEE\bE A\bAL\bLS\bSO\bO
        _\bs_\bu_\bd_\bo_\be_\br_\bs(4), _\bs_\bu_\bd_\bo(1m)
 
@@ -1030,4 +1355,4 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
 
 
 
-1.8.2                            May 22, 2011                  SUDO_PLUGIN(1m)
+1.8.5                           April 23, 2012                 SUDO_PLUGIN(1m)