From c0d53d75eb9c738e9e241b0789a4d6d9345aee9a Mon Sep 17 00:00:00 2001 From: Robert Manner Date: Tue, 10 Dec 2019 12:30:15 +0100 Subject: [PATCH] src/load_plugins, plugins/sudoers: added developer_mode sudo.conf option It can be used to disable the enforcement that a plugin (shared object or an imported python module) must be owned by root and not modifiable by others. This can make plugin development easier. --- include/sudo_conf.h | 2 ++ lib/util/regress/sudo_conf/conf_test.c | 2 ++ lib/util/regress/sudo_conf/test1.in | 9 +++++++++ lib/util/regress/sudo_conf/test1.out.ok | 1 + lib/util/regress/sudo_conf/test2.out.ok | 1 + lib/util/regress/sudo_conf/test3.out.ok | 1 + lib/util/regress/sudo_conf/test4.out.ok | 1 + lib/util/regress/sudo_conf/test5.out.ok | 1 + lib/util/regress/sudo_conf/test6.out.ok | 1 + lib/util/regress/sudo_conf/test7.out.ok | 1 + lib/util/regress/sudo_conf/test8.err.ok | 1 + lib/util/regress/sudo_conf/test8.in | 1 + lib/util/regress/sudo_conf/test8.out.ok | 4 ++++ lib/util/sudo_conf.c | 26 +++++++++++++++++++++++++ lib/util/util.exp.in | 1 + plugins/sudoers/group_plugin.c | 16 ++++++++------- src/load_plugins.c | 25 +++++++++++++----------- 17 files changed, 76 insertions(+), 18 deletions(-) create mode 100644 lib/util/regress/sudo_conf/test8.err.ok create mode 100644 lib/util/regress/sudo_conf/test8.in create mode 100644 lib/util/regress/sudo_conf/test8.out.ok diff --git a/include/sudo_conf.h b/include/sudo_conf.h index a8b72beb1..c3cf556e2 100644 --- a/include/sudo_conf.h +++ b/include/sudo_conf.h @@ -66,6 +66,7 @@ __dso_public struct sudo_conf_debug_list *sudo_conf_debugging_v1(void); __dso_public struct sudo_conf_debug_file_list *sudo_conf_debug_files_v1(const char *progname); __dso_public struct plugin_info_list *sudo_conf_plugins_v1(void); __dso_public bool sudo_conf_disable_coredump_v1(void); +__dso_public bool sudo_conf_developer_mode_v1(void); __dso_public bool sudo_conf_probe_interfaces_v1(void); __dso_public int sudo_conf_group_source_v1(void); __dso_public int sudo_conf_max_groups_v1(void); @@ -79,6 +80,7 @@ __dso_public void sudo_conf_clear_paths_v1(void); #define sudo_conf_debug_files(_a) sudo_conf_debug_files_v1((_a)) #define sudo_conf_plugins() sudo_conf_plugins_v1() #define sudo_conf_disable_coredump() sudo_conf_disable_coredump_v1() +#define sudo_conf_developer_mode() sudo_conf_developer_mode_v1() #define sudo_conf_probe_interfaces() sudo_conf_probe_interfaces_v1() #define sudo_conf_group_source() sudo_conf_group_source_v1() #define sudo_conf_max_groups() sudo_conf_max_groups_v1() diff --git a/lib/util/regress/sudo_conf/conf_test.c b/lib/util/regress/sudo_conf/conf_test.c index e7539ddd1..93ca67150 100644 --- a/lib/util/regress/sudo_conf/conf_test.c +++ b/lib/util/regress/sudo_conf/conf_test.c @@ -72,6 +72,8 @@ sudo_conf_dump(void) struct sudo_debug_file *debug_file; struct plugin_info *info; + printf("Set developer_mode %s\n", + sudo_conf_developer_mode() ? "true" : "false"); printf("Set disable_coredump %s\n", sudo_conf_disable_coredump() ? "true" : "false"); printf("Set group_source %s\n", diff --git a/lib/util/regress/sudo_conf/test1.in b/lib/util/regress/sudo_conf/test1.in index 41282d7da..b203d8a16 100644 --- a/lib/util/regress/sudo_conf/test1.in +++ b/lib/util/regress/sudo_conf/test1.in @@ -55,6 +55,15 @@ Path noexec /usr/libexec/sudo_noexec.so # Set disable_coredump false +# +# Developer mode: +# +# By default, sudo enforces that each plugin it loads is only modifiable as +# non root user. This might not be very convenient for plugin development, +# so this can be disabled by setting "developer_mode" to true. +# +Set developer_mode true + # # User groups: # diff --git a/lib/util/regress/sudo_conf/test1.out.ok b/lib/util/regress/sudo_conf/test1.out.ok index 18807483d..47584e9f9 100644 --- a/lib/util/regress/sudo_conf/test1.out.ok +++ b/lib/util/regress/sudo_conf/test1.out.ok @@ -1,3 +1,4 @@ +Set developer_mode true Set disable_coredump false Set group_source static Set max_groups -1 diff --git a/lib/util/regress/sudo_conf/test2.out.ok b/lib/util/regress/sudo_conf/test2.out.ok index af42145e2..d7c595e33 100644 --- a/lib/util/regress/sudo_conf/test2.out.ok +++ b/lib/util/regress/sudo_conf/test2.out.ok @@ -1,3 +1,4 @@ +Set developer_mode false Set disable_coredump true Set group_source adaptive Set max_groups -1 diff --git a/lib/util/regress/sudo_conf/test3.out.ok b/lib/util/regress/sudo_conf/test3.out.ok index 819d638f8..828166651 100644 --- a/lib/util/regress/sudo_conf/test3.out.ok +++ b/lib/util/regress/sudo_conf/test3.out.ok @@ -1,3 +1,4 @@ +Set developer_mode false Set disable_coredump true Set group_source adaptive Set max_groups -1 diff --git a/lib/util/regress/sudo_conf/test4.out.ok b/lib/util/regress/sudo_conf/test4.out.ok index af42145e2..d7c595e33 100644 --- a/lib/util/regress/sudo_conf/test4.out.ok +++ b/lib/util/regress/sudo_conf/test4.out.ok @@ -1,3 +1,4 @@ +Set developer_mode false Set disable_coredump true Set group_source adaptive Set max_groups -1 diff --git a/lib/util/regress/sudo_conf/test5.out.ok b/lib/util/regress/sudo_conf/test5.out.ok index af42145e2..d7c595e33 100644 --- a/lib/util/regress/sudo_conf/test5.out.ok +++ b/lib/util/regress/sudo_conf/test5.out.ok @@ -1,3 +1,4 @@ +Set developer_mode false Set disable_coredump true Set group_source adaptive Set max_groups -1 diff --git a/lib/util/regress/sudo_conf/test6.out.ok b/lib/util/regress/sudo_conf/test6.out.ok index 1f62f844a..d6e938ae2 100644 --- a/lib/util/regress/sudo_conf/test6.out.ok +++ b/lib/util/regress/sudo_conf/test6.out.ok @@ -1,3 +1,4 @@ +Set developer_mode false Set disable_coredump true Set group_source adaptive Set max_groups 16 diff --git a/lib/util/regress/sudo_conf/test7.out.ok b/lib/util/regress/sudo_conf/test7.out.ok index 56441093d..fedef8bab 100644 --- a/lib/util/regress/sudo_conf/test7.out.ok +++ b/lib/util/regress/sudo_conf/test7.out.ok @@ -1,3 +1,4 @@ +Set developer_mode false Set disable_coredump true Set group_source adaptive Set max_groups -1 diff --git a/lib/util/regress/sudo_conf/test8.err.ok b/lib/util/regress/sudo_conf/test8.err.ok new file mode 100644 index 000000000..2ff67737b --- /dev/null +++ b/lib/util/regress/sudo_conf/test8.err.ok @@ -0,0 +1 @@ +conf_test: invalid value for developer_mode "foo" in regress/sudo_conf/test8.in, line 1 diff --git a/lib/util/regress/sudo_conf/test8.in b/lib/util/regress/sudo_conf/test8.in new file mode 100644 index 000000000..e9a677369 --- /dev/null +++ b/lib/util/regress/sudo_conf/test8.in @@ -0,0 +1 @@ +Set developer_mode foo diff --git a/lib/util/regress/sudo_conf/test8.out.ok b/lib/util/regress/sudo_conf/test8.out.ok new file mode 100644 index 000000000..d7c595e33 --- /dev/null +++ b/lib/util/regress/sudo_conf/test8.out.ok @@ -0,0 +1,4 @@ +Set developer_mode false +Set disable_coredump true +Set group_source adaptive +Set max_groups -1 diff --git a/lib/util/sudo_conf.c b/lib/util/sudo_conf.c index 0538a1b3b..a8fca8776 100644 --- a/lib/util/sudo_conf.c +++ b/lib/util/sudo_conf.c @@ -82,12 +82,14 @@ static struct sudo_conf_table sudo_conf_table[] = { { NULL } }; +static int set_var_developer_mode(const char *entry, const char *conf_file, unsigned int); static int set_var_disable_coredump(const char *entry, const char *conf_file, unsigned int); static int set_var_group_source(const char *entry, const char *conf_file, unsigned int); static int set_var_max_groups(const char *entry, const char *conf_file, unsigned int); static int set_var_probe_interfaces(const char *entry, const char *conf_file, unsigned int); static struct sudo_conf_table sudo_conf_var_table[] = { + { "developer_mode", sizeof("developer_mode") - 1, set_var_developer_mode }, { "disable_coredump", sizeof("disable_coredump") - 1, set_var_disable_coredump }, { "group_source", sizeof("group_source") - 1, set_var_group_source }, { "max_groups", sizeof("max_groups") - 1, set_var_max_groups }, @@ -103,6 +105,7 @@ static struct sudo_conf_table sudo_conf_var_table[] = { #define SUDO_CONF_PATH_DEVSEARCH 4 static struct sudo_conf_data { + bool developer_mode; bool disable_coredump; bool probe_interfaces; int group_source; @@ -111,6 +114,7 @@ static struct sudo_conf_data { struct plugin_info_list plugins; struct sudo_conf_path_table path_table[6]; } sudo_conf_data = { + false, true, true, GROUP_SOURCE_ADAPTIVE, @@ -361,6 +365,22 @@ oom: debug_return_int(-1); } +static int +set_var_developer_mode(const char *strval, const char *conf_file, + unsigned int lineno) +{ + int val = sudo_strtobool(strval); + debug_decl(set_var_developer_mode, SUDO_DEBUG_UTIL) + + if (val == -1) { + sudo_warnx(U_("invalid value for %s \"%s\" in %s, line %u"), + "developer_mode", strval, conf_file, lineno); + debug_return_bool(false); + } + sudo_conf_data.developer_mode = val; + debug_return_bool(true); +} + static int set_var_disable_coredump(const char *strval, const char *conf_file, unsigned int lineno) @@ -520,6 +540,12 @@ sudo_conf_debug_files_v1(const char *progname) debug_return_ptr(NULL); } +bool +sudo_conf_developer_mode_v1(void) +{ + return sudo_conf_data.developer_mode; +} + bool sudo_conf_disable_coredump_v1(void) { diff --git a/lib/util/util.exp.in b/lib/util/util.exp.in index ebbae5119..6a10b6a82 100644 --- a/lib/util/util.exp.in +++ b/lib/util/util.exp.in @@ -4,6 +4,7 @@ sudo_conf_clear_paths_v1 sudo_conf_debug_files_v1 sudo_conf_debugging_v1 sudo_conf_devsearch_path_v1 +sudo_conf_developer_mode_v1 sudo_conf_disable_coredump_v1 sudo_conf_group_source_v1 sudo_conf_max_groups_v1 diff --git a/plugins/sudoers/group_plugin.c b/plugins/sudoers/group_plugin.c index 3a958afa3..6f2957891 100644 --- a/plugins/sudoers/group_plugin.c +++ b/plugins/sudoers/group_plugin.c @@ -86,13 +86,15 @@ group_plugin_load(char *plugin_info) sudo_warn("%s", path); goto done; } - if (sb.st_uid != ROOT_UID) { - sudo_warnx(U_("%s must be owned by uid %d"), path, ROOT_UID); - goto done; - } - if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - sudo_warnx(U_("%s must only be writable by owner"), path); - goto done; + if (!sudo_conf_developer_mode()) { + if (sb.st_uid != ROOT_UID) { + sudo_warnx(U_("%s must be owned by uid %d"), path, ROOT_UID); + goto done; + } + if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) { + sudo_warnx(U_("%s must only be writable by owner"), path); + goto done; + } } /* Open plugin and map in symbol. */ diff --git a/src/load_plugins.c b/src/load_plugins.c index 757a28c4a..14a2ae539 100644 --- a/src/load_plugins.c +++ b/src/load_plugins.c @@ -130,17 +130,20 @@ sudo_check_plugin(struct plugin_info *info, char *fullpath, size_t pathsize) } goto done; } - if (sb.st_uid != ROOT_UID) { - sudo_warnx(U_("error in %s, line %d while loading plugin \"%s\""), - _PATH_SUDO_CONF, info->lineno, info->symbol_name); - sudo_warnx(U_("%s must be owned by uid %d"), fullpath, ROOT_UID); - goto done; - } - if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - sudo_warnx(U_("error in %s, line %d while loading plugin \"%s\""), - _PATH_SUDO_CONF, info->lineno, info->symbol_name); - sudo_warnx(U_("%s must be only be writable by owner"), fullpath); - goto done; + + if (!sudo_conf_developer_mode()) { + if (sb.st_uid != ROOT_UID) { + sudo_warnx(U_("error in %s, line %d while loading plugin \"%s\""), + _PATH_SUDO_CONF, info->lineno, info->symbol_name); + sudo_warnx(U_("%s must be owned by uid %d"), fullpath, ROOT_UID); + goto done; + } + if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) { + sudo_warnx(U_("error in %s, line %d while loading plugin \"%s\""), + _PATH_SUDO_CONF, info->lineno, info->symbol_name); + sudo_warnx(U_("%s must be only be writable by owner"), fullpath); + goto done; + } } ret = true;