From: Todd C. Miller Date: Fri, 2 Mar 2012 16:04:09 +0000 (-0500) Subject: Add support for plugin args at the end of a Plugin line in sudo.conf. X-Git-Tag: SUDO_1_8_5~1^2~177 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a16dee915bbb94384445eb8f6544ebc0ceff8848;p=sudo Add support for plugin args at the end of a Plugin line in sudo.conf. Bump the minor number accordingly and update the documentation. A plugin must check the sudo front end's version before using the plugin_args parameter since it is only supported for API version 1.2 and higher. --- diff --git a/common/sudo_conf.c b/common/sudo_conf.c index 74b90407d..3cdf9056a 100644 --- a/common/sudo_conf.c +++ b/common/sudo_conf.c @@ -204,8 +204,10 @@ static bool set_plugin(const char *entry) { struct plugin_info *info; - const char *name, *path; - size_t namelen; + const char *name, *path, *cp, *ep; + char **args = NULL; + size_t namelen, pathlen; + unsigned int nargs; /* Parse Plugin line */ name = entry; @@ -215,10 +217,35 @@ set_plugin(const char *entry) namelen = (size_t)(path - name); while (isblank((unsigned char)*path)) path++; + if ((cp = strpbrk(path, " \t")) != NULL) { + /* Convert extra args to an array. */ + pathlen = (size_t)(cp - path); + while (isblank((unsigned char)*cp)) + cp++; + /* Count number of args and allocate array. */ + for (ep = cp, nargs = 1; (ep = strpbrk(ep, " \t")) != NULL; nargs++) { + while (isblank((unsigned char)*ep)) + ep++; + } + args = emalloc2(nargs + 1, sizeof(*args)); + /* Fill in args array, there is at least one element. */ + for (nargs = 0; (ep = strpbrk(cp, " \t")) != NULL; ) { + args[nargs++] = estrndup(cp, (size_t)(ep - cp)); + while (isblank((unsigned char)*ep)) + ep++; + cp = ep; + } + args[nargs++] = estrdup(cp); + args[nargs] = NULL; + } else { + /* No extra args. */ + pathlen = strlen(path); + } info = emalloc(sizeof(*info)); info->symbol_name = estrndup(name, namelen); - info->path = estrdup(path); + info->path = estrndup(path, pathlen); + info->args = args; info->prev = info; info->next = NULL; tq_append(&sudo_conf_data.plugins, info); diff --git a/doc/sample.sudo.conf b/doc/sample.sudo.conf index 529602fb1..c6b2d38cf 100644 --- a/doc/sample.sudo.conf +++ b/doc/sample.sudo.conf @@ -2,7 +2,7 @@ # Sample /etc/sudo.conf file # # Format: -# Plugin plugin_name plugin_path +# Plugin plugin_name plugin_path plugin_args ... # Path askpass /path/to/askpass # Path noexec /path/to/noexec.so # Debug sudo /var/log/sudo_debug all@warn @@ -13,6 +13,7 @@ # 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_args are optional. # # The sudoers plugin is used by default if no Plugin lines are present. Plugin sudoers_policy sudoers.so diff --git a/doc/sudo.pod b/doc/sudo.pod index 13b1b84af..d69b5b6d9 100644 --- a/doc/sudo.pod +++ b/doc/sudo.pod @@ -421,7 +421,7 @@ which corresponds to the following F<@sysconfdir@/sudo.conf> file. # Default @sysconfdir@/sudo.conf file # # Format: - # Plugin plugin_name plugin_path + # Plugin plugin_name plugin_path plugin_args ... # Path askpass /path/to/askpass # Path noexec /path/to/noexec.so # Debug sudo /var/log/sudo_debug all@warn @@ -431,6 +431,7 @@ which corresponds to the following F<@sysconfdir@/sudo.conf> file. # fully qualified. # The plugin_name corresponds to a global symbol in the plugin # that contains the plugin interface structure. + # The plugin_args are optional. # Plugin policy_plugin sudoers.so Plugin io_plugin sudoers.so @@ -441,8 +442,9 @@ plugin. The I is the name of the C or 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 arguments to the plugin's +I function. Lines that don't begin with C, C, +C or C are silently ignored. For more information, see the L manual. diff --git a/doc/sudo_plugin.pod b/doc/sudo_plugin.pod index 3513cae0a..8627556d7 100644 --- a/doc/sudo_plugin.pod +++ b/doc/sudo_plugin.pod @@ -48,8 +48,9 @@ plugin. The I is the name of the C or 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 arguments 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 optional_args # Path askpass /path/to/askpass + # Path noexec /path/to/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_args 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_args[]); void (*close)(int exit_status, int error); int (*show_version)(int verbose); int (*check_policy)(int argc, char * const argv[], @@ -118,7 +124,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_args[]); 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 @@ -369,6 +376,19 @@ When parsing I, the plugin should split on the B equal sign ('=') since the I field will never include one itself but the I might. +=item plugin_args + +Any (non-comment) strings immediately after the plugin path are +treated as arguments to the plugin. These arguments are split on +a whitespace 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 @@ -762,7 +782,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_args[]); 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); @@ -811,7 +831,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_args[]); The I function is run before the I, I or I functions are called. It is only called if the @@ -895,6 +915,19 @@ When parsing I, the plugin should split on the B equal sign ('=') since the I field will never include one itself but the I might. +=item plugin_args + +Any (non-comment) strings immediately after the plugin path are +treated as arguments to the plugin. These arguments are split on +a whitespace 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 diff --git a/doc/sudoers.pod b/doc/sudoers.pod index 32c39bce2..144c8f8a1 100644 --- a/doc/sudoers.pod +++ b/doc/sudoers.pod @@ -540,7 +540,7 @@ and F but shell escapes will be disabled. aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi -See the L section below for more details +See the L section below for more details on how C works and whether or not it will work on your system. =head3 SETENV and NOSETENV @@ -940,8 +940,8 @@ by default. If set, all commands run via B will behave as if the C tag has been set, unless overridden by a C tag. See the -description of I below as well as the L section at the end of this manual. This flag is I by default. +description of I below as well as the L section at the end of this manual. This flag is I by default. =item path_info @@ -1594,10 +1594,166 @@ is displayed when B is run by root with the I<-V> option. =back +=head1 SUDO.CONF + +The F<@sysconfdir@/sudo.conf> file determines which plugins the +B front end will load. If no F<@sysconfdir@/sudo.conf> file +is present, or it contains no C lines, B will use the +I security policy and I/O logging, which corresponds to +the following F<@sysconfdir@/sudo.conf> file. + + # + # Default @sysconfdir@/sudo.conf file + # + # Format: + # Plugin plugin_name plugin_path plugin_args ... + # Path askpass /path/to/askpass + # Path noexec /path/to/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_args are optional. + # + Plugin policy_plugin sudoers.so + Plugin io_plugin sudoers.so + +=head2 PLUGIN OPTIONS + +Starting with B 1.8.5 it is possible to pass options to the +I plugin. Options may be listed after the path to the +plugin (i.e. after F); multiple options should be +space-separated. For example: + + Plugin sudoers_policy sudoers.so sudoers_file=/etc/sudoers sudoers_uid=0 sudoers_gid=0 sudoers_mode=0440 + +The following plugin options are supported: + +=over 10 + +=item sudoers_file=pathname + +The I option can be used to override the default path +to the I file. + +=item sudoers_uid=uid + +The I option can be used to override the default owner +of the sudoers file. It should be specified as a numeric user ID. + +=item sudoers_gid=gid + +The I option can be used to override the default group +of the sudoers file. It should be specified as a numeric group ID. + +=item sudoers_mode=mode + +The I option can be used to override the default file +mode for the sudoers file. It should be specified as an octal value. + +=back + +=head2 DEBUG FLAGS + +Versions 1.8.4 and higher of the I plugin supports a +debugging framework that can help track down what the plugin is +doing internally if there is a problem. This can be configured in +the F<@sysconfdir@/sudo.conf> file as described in L. + +The I plugin uses the same debug flag format as B +itself: I@I. + +The priorities used by I, in order of decreasing severity, +are: I, I, I, I, I, I, I +and I. Each priority, when specified, also includes all +priorities higher than it. For example, a priority of I +would include debug messages logged at I and higher. + +The following subsystems are used by I: + +=over 10 + +=item I + +C, C, C and C processing + +=item I + +matches every subsystem + +=item I + +BSM and Linux audit code + +=item I + +user authentication + +=item I + +I I settings + +=item I + +environment handling + +=item I + +LDAP-based sudoers + +=item I + +logging support + +=item I + +matching of users, groups, hosts and netgroups in I + +=item I + +network interface handling + +=item I + +network service switch handling in I + +=item I + +I file parsing + +=item I + +permission setting + +=item I + +The equivalent of I
for the plugin. + +=item I + +pseudo-tty related code + +=item I + +redblack tree internals + +=item I + +utility functions + +=back + =head1 FILES =over 24 +=item F<@sysconfdir@/sudo.conf> + +Sudo front end configuration + =item F<@sysconfdir@/sudoers> List of who can run what @@ -1810,6 +1966,8 @@ for encapsulating in a shell script. =head1 SECURITY NOTES +=head2 Limitations of the '!' operator + It is generally not effective to "subtract" commands from C using the '!' operator. A user can trivially circumvent this by copying the desired command to a different name and then @@ -1823,7 +1981,14 @@ different name, or use a shell escape from an editor or other program. Therefore, these kind of restrictions should be considered advisory at best (and reinforced by policy). -Furthermore, if the I option is in use, it is not possible +In general, if a user has sudo C there is nothing to prevent +them from creating their own program that gives them a root shell +(or making their own copy of a shell) regardless of any '!' elements +in the user specification. + +=head2 Security implications of I + +If the I option is in use, it is not possible to reliably negate commands where the path name includes globbing (aka wildcard) characters. This is because the C library's L function cannot resolve relative paths. While this @@ -1839,7 +2004,7 @@ For example, given the following I entry: User B can still run C if I is enabled by changing to F and running C<./passwd root> instead. -=head1 PREVENTING SHELL ESCAPES +=head2 Preventing Shell Escapes Once B executes a program, that program is free to do whatever it pleases, including run other programs. This can be a security @@ -1903,97 +2068,7 @@ to unintended privilege escalation. In the specific case of an editor, a safer approach is to give the user permission to run B. -=head1 DEBUG FLAGS - -Versions 1.8.4 and higher of the I plugin supports a -debugging framework that can help track down what the plugin is -doing internally if there is a problem. This can be configured in -the F<@sysconfdir@/sudo.conf> file as described in L. - -The I plugin uses the same debug flag format as B -itself: I@I. - -The priorities used by I, in order of decreasing severity, -are: I, I, I, I, I, I, I -and I. Each priority, when specified, also includes all -priorities higher than it. For example, a priority of I -would include debug messages logged at I and higher. - -The following subsystems are used by I: - -=over 10 - -=item I - -C, C, C and C processing - -=item I - -matches every subsystem - -=item I - -BSM and Linux audit code - -=item I - -user authentication - -=item I - -I I settings - -=item I - -environment handling - -=item I - -LDAP-based sudoers - -=item I - -logging support - -=item I - -matching of users, groups, hosts and netgroups in I - -=item I - -network interface handling - -=item I - -network service switch handling in I - -=item I - -I file parsing - -=item I - -permission setting - -=item I - -The equivalent of I
for the plugin. - -=item I - -pseudo-tty related code - -=item I - -redblack tree internals - -=item I - -utility functions - -=back - -=head1 SECURITY NOTES +=head2 Time stamp file checks I will check the ownership of its time stamp directory (F<@timedir@> by default) and ignore the directory's contents if @@ -2034,11 +2109,6 @@ created (such as Mac OS X), I is able to determine when a tty-based time stamp file is stale and will ignore it. Administrators should not rely on this feature as it is not universally available. -If users have sudo C there is nothing to prevent them from -creating their own program that gives them a root shell (or making -their own copy of a shell) regardless of any '!' elements in the -user specification. - =head1 SEE ALSO L, L, L, L, L, L, diff --git a/include/sudo_conf.h b/include/sudo_conf.h index 6efc302f8..9e0ea14bb 100644 --- a/include/sudo_conf.h +++ b/include/sudo_conf.h @@ -24,6 +24,7 @@ struct plugin_info { struct plugin_info *next; /* required */ const char *path; const char *symbol_name; + char * const * args; }; TQ_DECLARE(plugin_info) diff --git a/include/sudo_plugin.h b/include/sudo_plugin.h index 6fd3e6794..1eed2a294 100644 --- a/include/sudo_plugin.h +++ b/include/sudo_plugin.h @@ -19,7 +19,7 @@ /* API version major/minor */ #define SUDO_API_VERSION_MAJOR 1 -#define SUDO_API_VERSION_MINOR 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) @@ -63,7 +63,8 @@ struct policy_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[], char * const user_env[]); + char * const user_info[], char * const user_env[], + char * const plugin_args[]); void (*close)(int exit_status, int error); /* wait status or error */ int (*show_version)(int verbose); int (*check_policy)(int argc, char * const argv[], @@ -84,7 +85,8 @@ struct io_plugin { int (*open)(unsigned int version, sudo_conv_t conversation, 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[]); + int argc, char * const argv[], char * const user_env[], + char * const plugin_args[]); 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); diff --git a/plugins/sample/sample_plugin.c b/plugins/sample/sample_plugin.c index 51ec2451a..c95ffd60e 100644 --- a/plugins/sample/sample_plugin.c +++ b/plugins/sample/sample_plugin.c @@ -111,7 +111,7 @@ fmt_string(const char *var, const char *val) static int policy_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 user_info[], char * const user_env[], char * const args[]) { char * const *ui; struct passwd *pw; @@ -422,7 +422,7 @@ static int io_open(unsigned int version, sudo_conv_t conversation, 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[]) + int argc, char * const argv[], char * const user_env[], char * const args[]) { int fd; char path[PATH_MAX]; diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c index 11622cb5e..1f591e924 100644 --- a/plugins/sudoers/iolog.c +++ b/plugins/sudoers/iolog.c @@ -417,7 +417,7 @@ static int sudoers_io_open(unsigned int version, sudo_conv_t conversation, 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[]) + int argc, char * const argv[], char * const user_env[], char * const args[]) { struct iolog_details details; char pathbuf[PATH_MAX], sessid[7]; diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 28707ab50..936298990 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -96,7 +96,8 @@ static void set_runaspw(const char *); static void set_runasgr(const char *); static int cb_runas_default(const char *); static int sudoers_policy_version(int verbose); -static int deserialize_info(char * const settings[], char * const user_info[]); +static int deserialize_info(char * const args[], char * const settings[], + char * const user_info[]); static char *find_editor(int nfiles, char **files, char ***argv_out); static void create_admin_success_flag(void); @@ -135,13 +136,17 @@ sigjmp_buf error_jmp; static int sudoers_policy_open(unsigned int version, sudo_conv_t conversation, sudo_printf_t plugin_printf, char * const settings[], - char * const user_info[], char * const envp[]) + char * const user_info[], char * const envp[], char * const args[]) { volatile int sources = 0; sigaction_t sa; struct sudo_nss *nss; debug_decl(sudoers_policy_open, SUDO_DEBUG_PLUGIN) + /* Plugin args are only specified for API version 1.2 and higher. */ + if (version < SUDO_API_MKVERSION(1, 2)) + args = NULL; + if (!sudo_conv) sudo_conv = conversation; if (!sudo_printf) @@ -178,8 +183,8 @@ sudoers_policy_open(unsigned int version, sudo_conv_t conversation, /* Setup defaults data structures. */ init_defaults(); - /* Parse settings and user_info */ - sudo_mode = deserialize_info(settings, user_info); + /* Parse args, settings and user_info */ + sudo_mode = deserialize_info(args, settings, user_info); init_vars(envp); /* XXX - move this later? */ @@ -1181,7 +1186,7 @@ sudoers_policy_version(int verbose) } static int -deserialize_info(char * const settings[], char * const user_info[]) +deserialize_info(char * const args[], char * const settings[], char * const user_info[]) { char * const *cur; const char *p, *groups = NULL; @@ -1191,6 +1196,29 @@ deserialize_info(char * const settings[], char * const user_info[]) #define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0) + /* Parse sudo.conf plugin args. */ + if (args != NULL) { + for (cur = args; *cur != NULL; cur++) { + if (MATCHES(*cur, "sudoers_file=")) { + sudoers_file = *cur + sizeof("sudoers_file=") - 1; + continue; + } + if (MATCHES(*cur, "sudoers_uid=")) { + sudoers_uid = (uid_t) atoi(*cur + sizeof("sudoers_uid=") - 1); + continue; + } + if (MATCHES(*cur, "sudoers_gid=")) { + sudoers_gid = (gid_t) atoi(*cur + sizeof("sudoers_gid=") - 1); + continue; + } + if (MATCHES(*cur, "sudoers_mode=")) { + sudoers_mode = (mode_t) strtol(*cur + sizeof("sudoers_mode=") - 1, + NULL, 8); + continue; + } + } + } + /* Parse command line settings. */ user_closefrom = -1; for (cur = settings; *cur != NULL; cur++) { @@ -1294,23 +1322,6 @@ deserialize_info(char * const settings[], char * const user_info[]) set_interfaces(interfaces_string); continue; } - if (MATCHES(*cur, "sudoers_file=")) { - sudoers_file = *cur + sizeof("sudoers_file=") - 1; - continue; - } - if (MATCHES(*cur, "sudoers_uid=")) { - sudoers_uid = (uid_t) atoi(*cur + sizeof("sudoers_uid=") - 1); - continue; - } - if (MATCHES(*cur, "sudoers_gid=")) { - sudoers_gid = (gid_t) atoi(*cur + sizeof("sudoers_gid=") - 1); - continue; - } - if (MATCHES(*cur, "sudoers_mode=")) { - sudoers_mode = (mode_t) strtol(*cur + sizeof("sudoers_mode=") - 1, - NULL, 8); - continue; - } } for (cur = user_info; *cur != NULL; cur++) { diff --git a/plugins/sudoers/toke.l b/plugins/sudoers/toke.l index f48fb2842..967de07fd 100644 --- a/plugins/sudoers/toke.l +++ b/plugins/sudoers/toke.l @@ -81,7 +81,7 @@ int sudolineno; int last_token; char *sudoers; -/* Default sudoers path, mode and owner */ +/* Default sudoers path, mode and owner (may be set via sudo.conf) */ const char *sudoers_file = _PATH_SUDOERS; mode_t sudoers_mode = SUDOERS_MODE; uid_t sudoers_uid = SUDOERS_UID; diff --git a/src/load_plugins.c b/src/load_plugins.c index e86c1432c..7b0f5e50e 100644 --- a/src/load_plugins.c +++ b/src/load_plugins.c @@ -131,6 +131,7 @@ sudo_load_plugins(struct plugin_container *policy_plugin, } policy_plugin->handle = handle; policy_plugin->name = info->symbol_name; + policy_plugin->args = info->args; policy_plugin->u.generic = plugin; } else if (plugin->type == SUDO_IO_PLUGIN) { container = emalloc(sizeof(*container)); @@ -138,6 +139,7 @@ sudo_load_plugins(struct plugin_container *policy_plugin, container->next = NULL; container->handle = handle; container->name = info->symbol_name; + container->args = info->args; container->u.generic = plugin; tq_append(io_plugins, container); } diff --git a/src/sudo.c b/src/sudo.c index eb006a088..7721f4aa7 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -1056,9 +1056,24 @@ static int policy_open(struct plugin_container *plugin, char * const settings[], char * const user_info[], char * const user_env[]) { + int rval; debug_decl(policy_open, SUDO_DEBUG_PCOMM) - debug_return_bool(plugin->u.policy->open(SUDO_API_VERSION, - sudo_conversation, _sudo_printf, settings, user_info, user_env)); + + /* + * Backwards compatibility for older API versions + */ + switch (plugin->u.generic->version) { + case SUDO_API_MKVERSION(1, 0): + case SUDO_API_MKVERSION(1, 1): + rval = plugin->u.policy_1_0->open(plugin->u.io_1_0->version, + sudo_conversation, _sudo_printf, settings, user_info, user_env); + break; + default: + rval = plugin->u.policy->open(SUDO_API_VERSION, sudo_conversation, + _sudo_printf, settings, user_info, user_env, plugin->args); + } + + debug_return_bool(rval); } static void @@ -1141,7 +1156,7 @@ iolog_open(struct plugin_container *plugin, char * const settings[], debug_decl(iolog_open, SUDO_DEBUG_PCOMM) /* - * Backwards compatibility for API major 1, minor 0 + * Backwards compatibility for older API versions */ switch (plugin->u.generic->version) { case SUDO_API_MKVERSION(1, 0): @@ -1149,10 +1164,15 @@ iolog_open(struct plugin_container *plugin, char * const settings[], sudo_conversation, _sudo_printf, settings, user_info, argc, argv, user_env); break; + case SUDO_API_MKVERSION(1, 1): + rval = plugin->u.io_1_1->open(plugin->u.io_1_1->version, + sudo_conversation, _sudo_printf, settings, user_info, + command_info, argc, argv, user_env); + break; default: rval = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation, - _sudo_printf, settings, user_info, command_info, argc, argv, - user_env); + _sudo_printf, settings, user_info, command_info, + argc, argv, user_env, plugin->args); } debug_return_bool(rval); } diff --git a/src/sudo_plugin_int.h b/src/sudo_plugin_int.h index 135c12344..a3c77313c 100644 --- a/src/sudo_plugin_int.h +++ b/src/sudo_plugin_int.h @@ -29,6 +29,23 @@ struct generic_plugin { /* * Backwards-compatible structures for API bumps. */ +struct policy_plugin_1_0 { + unsigned int type; + unsigned int version; + 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[]); + 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[]); + int (*list)(int argc, char * const argv[], int verbose, + const char *list_user); + int (*validate)(void); + void (*invalidate)(int remove); + int (*init_session)(struct passwd *pwd); +}; struct io_plugin_1_0 { unsigned int type; unsigned int version; @@ -44,6 +61,21 @@ struct io_plugin_1_0 { int (*log_stdout)(const char *buf, unsigned int len); int (*log_stderr)(const char *buf, unsigned int len); }; +struct io_plugin_1_1 { + unsigned int type; + unsigned int version; + int (*open)(unsigned int version, sudo_conv_t conversation, + 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[]); + 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); +}; /* * Sudo plugin internals. @@ -52,12 +84,15 @@ struct plugin_container { struct plugin_container *prev; /* required */ struct plugin_container *next; /* required */ const char *name; + char * const *args; void *handle; union { struct generic_plugin *generic; struct policy_plugin *policy; + struct policy_plugin_1_0 *policy_1_0; struct io_plugin *io; struct io_plugin_1_0 *io_1_0; + struct io_plugin_1_1 *io_1_1; } u; }; TQ_DECLARE(plugin_container)