--- embedaddon/sudo/doc/sudo_plugin.pod 2012/02/21 16:23:02 1.1.1.1 +++ embedaddon/sudo/doc/sudo_plugin.pod 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 @@ -48,8 +48,9 @@ plugin. The I is the name of the C in the plugin shared object. The I may be fully qualified or relative. If not fully qualified it is relative to the F<@prefix@/libexec> directory. Any additional -parameters after the I are ignored. Lines that don't begin -with C or C are silently ignored. +parameters after the I are passed as options to the plugin's +I function. Lines that don't begin with C, C, +C or C 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 @@ -61,13 +62,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 @@ -85,8 +90,9 @@ so that B can load it. unsigned int type; /* always SUDO_POLICY_PLUGIN */ 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[]); + sudo_printf_t plugin_printf, char * const settings[], + 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[], @@ -96,7 +102,11 @@ so that B 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)); }; The policy_plugin struct has the following fields: @@ -118,7 +128,8 @@ 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 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, B will @@ -163,9 +174,31 @@ itself but the I might. =over 4 +=item debug_flags=string + +A comma-separated list of debug flags that correspond to B's +C entry in F<@sysconfdir@/sudo.conf>, if there is one. The +flags are passed to the plugin as they appear in F<@sysconfdir@/sudo.conf>. +The syntax used by B and the I plugin is +I@I but the plugin is free to use a different +format so long as it does not include a command C<,>. + +For reference, the priorities supported by the B front end and +I are: I, I, I, I, I, +I, I and I. + +The following subsystems are defined: I
, I, I, +I, I, I, I, I, I, I, +I, I, I, I, I, I, I, +I, I, I, I, I, I, I, +I, I. The subsystem I 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 B and the plugin. + =item debug_level=number -A numeric debug level, from 1-9, if specified via the C<-D> flag. +This setting has been deprecated in favor of I. =item runas_user=string @@ -294,14 +327,51 @@ itself but the I might. =over 4 +=item pid=int + +The process ID of the running B process. +Only available starting with API version 1.2 + +=item ppid=int + +The parent process ID of the running B process. +Only available starting with API version 1.2 + +=item sid=int + +The session ID of the running B process or 0 if B is +not part of a POSIX job control session. +Only available starting with API version 1.2 + +=item pgid=int + +The ID of the process group that the running B process belongs +to. +Only available starting with API version 1.2 + +=item tcpgid=int + +The ID of the forground process group associated with the terminal +device associcated with the B process or -1 if there is no +terminal present. +Only available starting with API version 1.2 + =item user=string The name of the user invoking B. +=item euid=uid_t + +The effective user ID of the user invoking B. + =item uid=uid_t The real user ID of the user invoking B. +=item egid=gid_t + +The effective group ID of the user invoking B. + =item gid=gid_t The real group ID of the user invoking B. @@ -347,6 +417,19 @@ When parsing I, the plugin should split on t equal sign ('=') since the I field will never include one itself but the I might. +=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 C-terminated array of strings. If no arguments were +specified, I will be the NULL pointer. + +NOTE: the I parameter is only available starting with +API version 1.2. A plugin B check the API version specified +by the B front end before using I. Failure to +do so may result in a crash. + =back =item close @@ -696,27 +779,97 @@ support credential caching. =item init_session - int (*init_session)(struct passwd *pwd); + int (*init_session)(struct passwd *pwd, char **user_envp[); -The C function is called when B sets up the -execution environment for the command, immediately before the -contents of the I list are applied (before the uid -changes). This can be used to do session setup that is not supported -by I, such as opening the PAM session. +The C function is called before B sets up the +execution environment for the command. It is run in the parent +B process and before any uid or gid changes. This can be used +to perform session setup that is not supported by I, +such as opening the PAM session. The C function can be +used to tear down the session that was opened by C. The I 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 I argument points to the environment the command will +run in, in the form of a C-terminated vector of "name=value" +strings. This is the same string passed back to the front end via +the Policy Plugin's I parameter. If the C +function needs to modify the user environment, it should update the +pointer stored in I. The expected use case is to merge +the contents of the PAM environment (if any) with the contents of +I. NOTE: the I parameter is only available +starting with API version 1.2. A plugin B check the API +version specified by the B front end before using I. +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 C to present additional error information to the user. +=item register_hooks + + void (*register_hooks)(int version, + int (*register_hook)(struct sudo_hook *hook)); + +The C function is called by the sudo front end to +register any hooks the plugin needs. If the plugin does not support +hooks, C should be set to the NULL pointer. + +The I argument describes the version of the hooks API +supported by the B front end. + +The C 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 C +does not match the front end's major hook API version. + +See the L section below for more information +about hooks. + +NOTE: the C function is only available starting +with API version 1.2. If the B front end doesn't support API +version 1.2 or higher, C will not be called. + +=item deregister_hooks + + void (*deregister_hooks)(int version, + int (*deregister_hook)(struct sudo_hook *hook)); + +The C function is called by the sudo front end +to deregister any hooks the plugin has registered. If the plugin +does not support hooks, C should be set to the +NULL pointer. + +The I argument describes the version of the hooks API +supported by the B front end. + +The C function should be used to deregister any +hooks that were put in place by the C function. If +the plugin tries to deregister a hook that the front end does not +support, C will return an error. + +See the L section below for more information +about hooks. + +NOTE: the C function is only available starting +with API version 1.2. If the B front end doesn't support API +version 1.2 or higher, C will not be called. + =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_MINOR(v) ((v) & 0xffff) #define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \ @@ -726,11 +879,6 @@ error information to the user. *(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) - =head2 I/O Plugin API struct io_plugin { @@ -740,7 +888,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); @@ -748,6 +896,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)); }; When an I/O plugin is loaded, B runs the command in a pseudo-tty. @@ -789,7 +941,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[]); The I function is run before the I, I or I functions are called. It is only called if the @@ -873,6 +1025,19 @@ When parsing I, the plugin should split on t equal sign ('=') since the I field will never include one itself but the I might. +=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 C-terminated array of strings. If no arguments were +specified, I will be the NULL pointer. + +NOTE: the I parameter is only available starting with +API version 1.2. A plugin B check the API version specified +by the B front end before using I. Failure to +do so may result in a crash. + =back =item close @@ -1040,12 +1205,178 @@ The length of I in bytes. =back +=item register_hooks + +See the L section for a description of +C. + +=item deregister_hooks + +See the L section for a description of +C. + =back -=head3 Version macros +=head3 I/O Plugin Version Macros Same as for the L. +=head2 Hook Function API + +Beginning with plugin API version 1.2, it is possible to install +hooks for certain functions called by the B 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 front end functions as well. + +=head3 Hook structure + +Hooks in B 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 structure has the following fields: + +=over 4 + +=item hook_version + +The C field should be set to SUDO_HOOK_VERSION. + +=item hook_type + +The C field may be one of the following supported hook types: + +=over 4 + +=item SUDO_HOOK_SETENV + +The C library C function. Any registered hooks will run +before the C library implementation. The C 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 function. Any registered hooks will run +before the C library implementation. The C 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 function. Any registered hooks will run +before the C library implementation. The C 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 function. Any registered hooks will run +before the C library implementation. The C 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 field should be set to the plugin's hook implementation. +The actual function arguments will vary depending on the C +(see C above). In all cases, the C field of +C 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 +hook might return C 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 hook that operates on a private copy of +the environment but leaves C unchanged. + +=back + +=back + +Note that it is very easy to create an infinite loop when hooking +C library functions. For example, a C hook that calls the +C function may create a loop if the C implementation +calls C 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 If the plugin needs to interact with the user, it may do so via the @@ -1064,6 +1395,7 @@ convenient for simple messages where no use input is r #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; @@ -1091,11 +1423,19 @@ freeing the reply buffer filled in to the C and -C for the I parameter. It can be -more convenient than using the conversation function if no user -reply is needed and supports standard printf() escape sequences. +conversation function but only supports C, +C and C for the I +parameter. It can be more convenient than using the conversation +function if no user reply is needed and supports standard printf() +escape sequences. +Unlike, C and C, messages +sent with the I are not directly +user-visible. Instead, they are logged to the file specified in +the C statement (if any) in the F<@sysconfdir@/sudo.conf> +file. This allows a plugin to log debugging information and is +intended to be used in conjunction with the I setting. + See the sample plugin for an example of the conversation function usage. =head2 Sudoers Group Plugin API @@ -1204,7 +1544,7 @@ present in the password database, I will be C will be C function was modified to take the +C list as an argument. + +=item Version 1.2 + +The Policy and I/O logging plugins' C functions are now passed +a list of plugin options if any are specified in F<@sysconfdir@/sudo.conf>. + +A simple hooks API has been introduced to allow plugins to hook in to the +system's environment handling functions. + +The C 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. + +=back + =head1 SEE ALSO