diff --git a/0022-CONFDB-Add-passwd_files-and-group_files-options.patch b/0022-CONFDB-Add-passwd_files-and-group_files-options.patch new file mode 100644 index 0000000..70694a2 --- /dev/null +++ b/0022-CONFDB-Add-passwd_files-and-group_files-options.patch @@ -0,0 +1,165 @@ +From a40215878688cf10e35e6ba27893201c686395b3 Mon Sep 17 00:00:00 2001 +From: Justin Stephenson +Date: Fri, 14 Jul 2017 16:08:37 -0400 +Subject: [PATCH] CONFDB: Add passwd_files and group_files options +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add new options to the files provider allowing an administrator to +configure the files provider to read and monitor multiple or +non-standard passwd and group file sources. These options default to +/etc/passwd and /etc/group when unset. + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +(cherry picked from commit c1208b485924964a7a4fcf19562964acb47fc214) +--- + Makefile.am | 3 ++- + src/confdb/confdb.h | 4 ++++ + src/config/SSSDConfig/__init__.py.in | 6 +++++- + src/config/cfg_rules.ini | 4 ++++ + src/config/etc/sssd.api.d/sssd-files.conf | 3 +++ + src/man/sssd-files.5.xml | 36 +++++++++++++++++++++++++++++-- + src/providers/files/files_init.c | 1 + + 7 files changed, 53 insertions(+), 4 deletions(-) + create mode 100644 src/config/etc/sssd.api.d/sssd-files.conf + +diff --git a/Makefile.am b/Makefile.am +index 25e996d2d..d52fe0670 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -4577,7 +4577,8 @@ dist_sssdapiplugin_DATA = \ + src/config/etc/sssd.api.d/sssd-ldap.conf \ + src/config/etc/sssd.api.d/sssd-local.conf \ + src/config/etc/sssd.api.d/sssd-proxy.conf \ +- src/config/etc/sssd.api.d/sssd-simple.conf ++ src/config/etc/sssd.api.d/sssd-simple.conf \ ++ src/config/etc/sssd.api.d/sssd-files.conf + + edit_cmd = $(SED) \ + -e 's|@sbindir[@]|$(sbindir)|g' \ +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index c97a9b804..1d322aaac 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -242,6 +242,10 @@ + #define CONFDB_PROXY_FAST_ALIAS "proxy_fast_alias" + #define CONFDB_PROXY_MAX_CHILDREN "proxy_max_children" + ++/* Files Provider */ ++#define CONFDB_FILES_PASSWD "passwd_files" ++#define CONFDB_FILES_GROUP "group_files" ++ + /* Secrets Service */ + #define CONFDB_SEC_CONF_ENTRY "config/secrets" + #define CONFDB_SEC_CONTAINERS_NEST_LEVEL "containers_nest_level" +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index 857d56cb5..32b74e4c7 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -473,7 +473,11 @@ option_strings = { + 'proxy_fast_alias' : _('Whether to look up canonical group name from cache if possible'), + + # [provider/proxy/auth] +- 'proxy_pam_target' : _('PAM stack to use') ++ 'proxy_pam_target' : _('PAM stack to use'), ++ ++ # [provider/files] ++ 'passwd_files' : _('Path of passwd file sources.'), ++ 'group_files' : _('Path of group file sources.') + } + + def striplist(l): +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 4e70bf7b6..551322780 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -404,6 +404,10 @@ option = dyndns_force_tcp + option = dyndns_auth + option = dyndns_server + ++# files provider specific options ++option = passwd_files ++option = group_files ++ + # local provider specific options + option = create_homedir + option = remove_homedir +diff --git a/src/config/etc/sssd.api.d/sssd-files.conf b/src/config/etc/sssd.api.d/sssd-files.conf +new file mode 100644 +index 000000000..2444d4924 +--- /dev/null ++++ b/src/config/etc/sssd.api.d/sssd-files.conf +@@ -0,0 +1,3 @@ ++[provider/files] ++passwd_files = str, None, false ++group_files = str, None, false +diff --git a/src/man/sssd-files.5.xml b/src/man/sssd-files.5.xml +index d44fffc03..59e1b6523 100644 +--- a/src/man/sssd-files.5.xml ++++ b/src/man/sssd-files.5.xml +@@ -56,14 +56,46 @@ + + CONFIGURATION OPTIONS + +- The files provider has no specific options of its own, however, +- generic SSSD domain options can be set where applicable. ++ In addition to the options listed below, generic SSSD domain options ++ can be set where applicable. + Refer to the section DOMAIN SECTIONS of the + + sssd.conf + 5 + manual page for details on the configuration + of an SSSD domain. ++ ++ ++ passwd_files (string) ++ ++ ++ Comma-separated list of one or multiple password ++ filenames to be read and enumerated by the files ++ provider, inotify monitor watches will be set on ++ each file to detect changes dynamically. ++ ++ ++ Default: /etc/passwd ++ ++ ++ ++ ++ ++ group_files (string) ++ ++ ++ Comma-separated list of one or multiple group ++ filenames to be read and enumerated by the files ++ provider, inotify monitor watches will be set on ++ each file to detect changes dynamically. ++ ++ ++ Default: /etc/group ++ ++ ++ ++ ++ + + + +diff --git a/src/providers/files/files_init.c b/src/providers/files/files_init.c +index 8e5cd4cf9..b8a051c34 100644 +--- a/src/providers/files/files_init.c ++++ b/src/providers/files/files_init.c +@@ -21,6 +21,7 @@ + + #include "providers/data_provider/dp.h" + #include "providers/files/files_private.h" ++#include "util/util.h" + + int sssm_files_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, +-- +2.14.3 + diff --git a/0023-FILES-Handle-files-provider-sources.patch b/0023-FILES-Handle-files-provider-sources.patch new file mode 100644 index 0000000..6565fb7 --- /dev/null +++ b/0023-FILES-Handle-files-provider-sources.patch @@ -0,0 +1,721 @@ +From 2eb09d21d486e83a3a844fda0a504bbc479c9b3a Mon Sep 17 00:00:00 2001 +From: Justin Stephenson +Date: Mon, 17 Jul 2017 15:01:36 -0400 +Subject: [PATCH] FILES: Handle files provider sources +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Setup watches on passwd and group files provided with the files provider +options passwd_files and group_files lists + +Resolves: +https://pagure.io/SSSD/sssd/issue/3402 + +Reviewed-by: Pavel Březina +Reviewed-by: Jakub Hrozek +(cherry picked from commit 0d6d493f68bb83a046d351cb3035b08ef5456b50) +--- + src/providers/files/files_init.c | 161 +++++++++++++++++--- + src/providers/files/files_ops.c | 285 ++++++++++++++++++++++-------------- + src/providers/files/files_private.h | 8 +- + 3 files changed, 327 insertions(+), 127 deletions(-) + +diff --git a/src/providers/files/files_init.c b/src/providers/files/files_init.c +index b8a051c34..746c04af1 100644 +--- a/src/providers/files/files_init.c ++++ b/src/providers/files/files_init.c +@@ -23,6 +23,138 @@ + #include "providers/files/files_private.h" + #include "util/util.h" + ++#define DEFAULT_PASSWD_FILE "/etc/passwd" ++#define DEFAULT_GROUP_FILE "/etc/group" ++ ++static errno_t files_init_file_sources(TALLOC_CTX *mem_ctx, ++ struct be_ctx *be_ctx, ++ const char ***_passwd_files, ++ const char ***_group_files) ++{ ++ TALLOC_CTX *tmp_ctx = NULL; ++ char *conf_passwd_files; ++ char *conf_group_files; ++ char **passwd_list = NULL; ++ char **group_list = NULL; ++ int num_passwd_files = 0; ++ int num_group_files = 0; ++ const char **passwd_files = NULL; ++ const char **group_files = NULL; ++ const char *dfl_passwd_files = NULL; ++ const char *env_group_files = NULL; ++ int i; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ dfl_passwd_files = getenv("SSS_FILES_PASSWD"); ++ if (dfl_passwd_files) { ++ sss_log(SSS_LOG_ALERT, ++ "Defaulting to %s for the passwd file, " ++ "this should only be used for testing!\n", ++ dfl_passwd_files); ++ } else { ++ dfl_passwd_files = DEFAULT_PASSWD_FILE; ++ } ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Using default passwd file: [%s].\n", dfl_passwd_files); ++ ++ env_group_files = getenv("SSS_FILES_GROUP"); ++ if (env_group_files) { ++ sss_log(SSS_LOG_ALERT, ++ "Defaulting to %s for the group file, " ++ "this should only be used for testing!\n", ++ env_group_files); ++ } else { ++ env_group_files = DEFAULT_GROUP_FILE; ++ } ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Using default group file: [%s].\n", DEFAULT_GROUP_FILE); ++ ++ ret = confdb_get_string(be_ctx->cdb, tmp_ctx, be_ctx->conf_path, ++ CONFDB_FILES_PASSWD, dfl_passwd_files, ++ &conf_passwd_files); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to retrieve confdb passwd files!\n"); ++ goto done; ++ } ++ ++ ret = confdb_get_string(be_ctx->cdb, tmp_ctx, be_ctx->conf_path, ++ CONFDB_FILES_GROUP, env_group_files, ++ &conf_group_files); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to retrieve confdb group files!\n"); ++ goto done; ++ } ++ ++ ret = split_on_separator(tmp_ctx, conf_passwd_files, ',', true, true, ++ &passwd_list, &num_passwd_files); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to parse passwd list!\n"); ++ goto done; ++ } ++ ++ passwd_files = talloc_zero_array(tmp_ctx, const char *, ++ num_passwd_files + 1); ++ if (passwd_files == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (i = 0; i < num_passwd_files; i++) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Using passwd file: [%s].\n", passwd_list[i]); ++ ++ passwd_files[i] = talloc_strdup(passwd_files, passwd_list[i]); ++ if (passwd_files[i] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ /* Retrieve list of group files */ ++ ret = split_on_separator(tmp_ctx, conf_group_files, ',', true, true, ++ &group_list, &num_group_files); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to parse group files!\n"); ++ goto done; ++ } ++ ++ group_files = talloc_zero_array(tmp_ctx, const char *, ++ num_group_files + 1); ++ if (group_files == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (i = 0; i < num_group_files; i++) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Using group file: [%s].\n", group_list[i]); ++ group_files[i] = talloc_strdup(group_files, group_list[i]); ++ if (group_files[i] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ *_passwd_files = talloc_steal(mem_ctx, passwd_files); ++ *_group_files = talloc_steal(mem_ctx, group_files); ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + int sssm_files_init(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct data_provider *provider, +@@ -30,32 +162,27 @@ int sssm_files_init(TALLOC_CTX *mem_ctx, + void **_module_data) + { + struct files_id_ctx *ctx; +- int ret; +- const char *passwd_file = NULL; +- const char *group_file = NULL; +- +- /* So far this is mostly useful for tests */ +- passwd_file = getenv("SSS_FILES_PASSWD"); +- if (passwd_file == NULL) { +- passwd_file = "/etc/passwd"; +- } +- +- group_file = getenv("SSS_FILES_GROUP"); +- if (group_file == NULL) { +- group_file = "/etc/group"; +- } ++ errno_t ret; + + ctx = talloc_zero(mem_ctx, struct files_id_ctx); + if (ctx == NULL) { + return ENOMEM; + } ++ + ctx->be = be_ctx; + ctx->domain = be_ctx->domain; +- ctx->passwd_file = passwd_file; +- ctx->group_file = group_file; ++ ++ ret = files_init_file_sources(ctx, be_ctx, ++ &ctx->passwd_files, ++ &ctx->group_files); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize the passwd/group source files\n"); ++ goto done; ++ } + + ctx->fctx = sf_init(ctx, be_ctx->ev, +- ctx->passwd_file, ctx->group_file, ++ ctx->passwd_files, ++ ctx->group_files, + ctx); + if (ctx->fctx == NULL) { + ret = ENOMEM; +diff --git a/src/providers/files/files_ops.c b/src/providers/files/files_ops.c +index b59a94252..a2a2798d3 100644 +--- a/src/providers/files/files_ops.c ++++ b/src/providers/files/files_ops.c +@@ -44,6 +44,7 @@ struct files_ctx { + + static errno_t enum_files_users(TALLOC_CTX *mem_ctx, + struct files_id_ctx *id_ctx, ++ const char *passwd_file, + struct passwd ***_users) + { + errno_t ret, close_ret; +@@ -53,12 +54,12 @@ static errno_t enum_files_users(TALLOC_CTX *mem_ctx, + FILE *pwd_handle = NULL; + size_t n_users = 0; + +- pwd_handle = fopen(id_ctx->passwd_file, "r"); ++ pwd_handle = fopen(passwd_file, "r"); + if (pwd_handle == NULL) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot open passwd file %s [%d]\n", +- id_ctx->passwd_file, ret); ++ passwd_file, ret); + goto done; + } + +@@ -133,7 +134,7 @@ done: + close_ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot close passwd file %s [%d]\n", +- id_ctx->passwd_file, close_ret); ++ passwd_file, close_ret); + } + } + return ret; +@@ -141,6 +142,7 @@ done: + + static errno_t enum_files_groups(TALLOC_CTX *mem_ctx, + struct files_id_ctx *id_ctx, ++ const char *group_file, + struct group ***_groups) + { + errno_t ret, close_ret; +@@ -150,12 +152,12 @@ static errno_t enum_files_groups(TALLOC_CTX *mem_ctx, + size_t n_groups = 0; + FILE *grp_handle = NULL; + +- grp_handle = fopen(id_ctx->group_file, "r"); ++ grp_handle = fopen(group_file, "r"); + if (grp_handle == NULL) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot open group file %s [%d]\n", +- id_ctx->group_file, ret); ++ group_file, ret); + goto done; + } + +@@ -237,7 +239,7 @@ done: + close_ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot close group file %s [%d]\n", +- id_ctx->group_file, close_ret); ++ group_file, close_ret); + } + } + return ret; +@@ -446,35 +448,23 @@ done: + return ret; + } + +-static errno_t sf_enum_groups(struct files_id_ctx *id_ctx); ++static errno_t sf_enum_groups(struct files_id_ctx *id_ctx, ++ const char *group_file); + +-errno_t sf_enum_users(struct files_id_ctx *id_ctx) ++errno_t sf_enum_users(struct files_id_ctx *id_ctx, ++ const char *passwd_file) + { + errno_t ret; +- errno_t tret; + TALLOC_CTX *tmp_ctx = NULL; + struct passwd **users = NULL; +- bool in_transaction = false; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + +- ret = enum_files_users(tmp_ctx, id_ctx, &users); +- if (ret != EOK) { +- goto done; +- } +- +- ret = sysdb_transaction_start(id_ctx->domain->sysdb); +- if (ret != EOK) { +- goto done; +- } +- in_transaction = true; +- +- /* remove previous cache contents */ +- /* FIXME - this is terribly inefficient */ +- ret = delete_all_users(id_ctx->domain); ++ ret = enum_files_users(tmp_ctx, id_ctx, passwd_file, ++ &users); + if (ret != EOK) { + goto done; + } +@@ -496,31 +486,8 @@ errno_t sf_enum_users(struct files_id_ctx *id_ctx) + "override values might not be available.\n"); + } + +- ret = sysdb_transaction_commit(id_ctx->domain->sysdb); +- if (ret != EOK) { +- goto done; +- } +- in_transaction = false; +- +- /* Covers the case when someone edits /etc/group, adds a group member and +- * only then edits passwd and adds the user. The reverse is not needed, +- * because member/memberof links are established when groups are saved. +- */ +- ret = sf_enum_groups(id_ctx); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Cannot refresh groups\n"); +- goto done; +- } +- + ret = EOK; + done: +- if (in_transaction) { +- tret = sysdb_transaction_cancel(id_ctx->domain->sysdb); +- if (tret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Cannot cancel transaction: %d\n", ret); +- } +- } + talloc_free(tmp_ctx); + return ret; + } +@@ -698,13 +665,12 @@ done: + return ret; + } + +-static errno_t sf_enum_groups(struct files_id_ctx *id_ctx) ++static errno_t sf_enum_groups(struct files_id_ctx *id_ctx, ++ const char *group_file) + { + errno_t ret; +- errno_t tret; + TALLOC_CTX *tmp_ctx = NULL; + struct group **groups = NULL; +- bool in_transaction = false; + const char **cached_users = NULL; + + tmp_ctx = talloc_new(NULL); +@@ -712,7 +678,8 @@ static errno_t sf_enum_groups(struct files_id_ctx *id_ctx) + return ENOMEM; + } + +- ret = enum_files_groups(tmp_ctx, id_ctx, &groups); ++ ret = enum_files_groups(tmp_ctx, id_ctx, group_file, ++ &groups); + if (ret != EOK) { + goto done; + } +@@ -722,18 +689,6 @@ static errno_t sf_enum_groups(struct files_id_ctx *id_ctx) + goto done; + } + +- ret = sysdb_transaction_start(id_ctx->domain->sysdb); +- if (ret != EOK) { +- goto done; +- } +- in_transaction = true; +- +- /* remove previous cache contents */ +- ret = delete_all_groups(id_ctx->domain); +- if (ret != EOK) { +- goto done; +- } +- + for (size_t i = 0; groups[i]; i++) { + ret = save_file_group(id_ctx, groups[i], cached_users); + if (ret != EOK) { +@@ -750,21 +705,8 @@ static errno_t sf_enum_groups(struct files_id_ctx *id_ctx) + "override values might not be available.\n"); + } + +- ret = sysdb_transaction_commit(id_ctx->domain->sysdb); +- if (ret != EOK) { +- goto done; +- } +- in_transaction = false; +- + ret = EOK; + done: +- if (in_transaction) { +- tret = sysdb_transaction_cancel(id_ctx->domain->sysdb); +- if (tret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Cannot cancel transaction: %d\n", ret); +- } +- } + talloc_free(tmp_ctx); + return ret; + } +@@ -783,21 +725,17 @@ static int sf_passwd_cb(const char *filename, uint32_t flags, void *pvt) + { + struct files_id_ctx *id_ctx; + errno_t ret; ++ errno_t tret; ++ bool in_transaction = false; + + id_ctx = talloc_get_type(pvt, struct files_id_ctx); + if (id_ctx == NULL) { +- return EINVAL; ++ ret = EINVAL; ++ goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "passwd notification\n"); + +- if (strcmp(filename, id_ctx->passwd_file) != 0) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Wrong file, expected %s, got %s\n", +- id_ctx->passwd_file, filename); +- return EINVAL; +- } +- + id_ctx->updating_passwd = true; + dp_sbus_domain_inconsistent(id_ctx->be->provider, id_ctx->domain); + +@@ -805,11 +743,64 @@ static int sf_passwd_cb(const char *filename, uint32_t flags, void *pvt) + dp_sbus_reset_users_memcache(id_ctx->be->provider); + dp_sbus_reset_initgr_memcache(id_ctx->be->provider); + +- ret = sf_enum_users(id_ctx); ++ ret = sysdb_transaction_start(id_ctx->domain->sysdb); ++ if (ret != EOK) { ++ goto done; ++ } ++ in_transaction = true; ++ ++ ret = delete_all_users(id_ctx->domain); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ /* All users were deleted, therefore we need to enumerate each file again */ ++ for (size_t i = 0; id_ctx->passwd_files[i] != NULL; i++) { ++ ret = sf_enum_users(id_ctx, id_ctx->passwd_files[i]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Cannot enumerate users\n"); ++ goto done; ++ } ++ } ++ ++ /* Covers the case when someone edits /etc/group, adds a group member and ++ * only then edits passwd and adds the user. The reverse is not needed, ++ * because member/memberof links are established when groups are saved. ++ */ ++ ret = delete_all_groups(id_ctx->domain); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ /* All groups were deleted, therefore we need to enumerate each file again */ ++ for (size_t i = 0; id_ctx->group_files[i] != NULL; i++) { ++ ret = sf_enum_groups(id_ctx, id_ctx->group_files[i]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Cannot enumerate groups\n"); ++ goto done; ++ } ++ } ++ ++ ret = sysdb_transaction_commit(id_ctx->domain->sysdb); ++ if (ret != EOK) { ++ goto done; ++ } ++ in_transaction = false; + + id_ctx->updating_passwd = false; + sf_cb_done(id_ctx); + files_account_info_finished(id_ctx, BE_REQ_USER, ret); ++ ++ ret = EOK; ++done: ++ if (in_transaction) { ++ tret = sysdb_transaction_cancel(id_ctx->domain->sysdb); ++ if (tret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot cancel transaction: %d\n", ret); ++ } ++ } ++ + return ret; + } + +@@ -817,21 +808,17 @@ static int sf_group_cb(const char *filename, uint32_t flags, void *pvt) + { + struct files_id_ctx *id_ctx; + errno_t ret; ++ errno_t tret; ++ bool in_transaction = false; + + id_ctx = talloc_get_type(pvt, struct files_id_ctx); + if (id_ctx == NULL) { +- return EINVAL; ++ ret = EINVAL; ++ goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "group notification\n"); + +- if (strcmp(filename, id_ctx->group_file) != 0) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Wrong file, expected %s, got %s\n", +- id_ctx->group_file, filename); +- return EINVAL; +- } +- + id_ctx->updating_groups = true; + dp_sbus_domain_inconsistent(id_ctx->be->provider, id_ctx->domain); + +@@ -839,11 +826,47 @@ static int sf_group_cb(const char *filename, uint32_t flags, void *pvt) + dp_sbus_reset_groups_memcache(id_ctx->be->provider); + dp_sbus_reset_initgr_memcache(id_ctx->be->provider); + +- ret = sf_enum_groups(id_ctx); ++ ret = sysdb_transaction_start(id_ctx->domain->sysdb); ++ if (ret != EOK) { ++ goto done; ++ } ++ in_transaction = true; ++ ++ ret = delete_all_groups(id_ctx->domain); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ /* All groups were deleted, therefore we need to enumerate each file again */ ++ for (size_t i = 0; id_ctx->group_files[i] != NULL; i++) { ++ ret = sf_enum_groups(id_ctx, id_ctx->group_files[i]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Cannot enumerate groups\n"); ++ goto done; ++ } ++ } ++ ++ ret = sysdb_transaction_commit(id_ctx->domain->sysdb); ++ if (ret != EOK) { ++ goto done; ++ } ++ in_transaction = false; + + id_ctx->updating_groups = false; + sf_cb_done(id_ctx); + files_account_info_finished(id_ctx, BE_REQ_GROUP, ret); ++ ++ ret = EOK; ++ ++done: ++ if (in_transaction) { ++ tret = sysdb_transaction_cancel(id_ctx->domain->sysdb); ++ if (tret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot cancel transaction: %d\n", ret); ++ } ++ } ++ + return ret; + } + +@@ -853,19 +876,62 @@ static void startup_enum_files(struct tevent_context *ev, + { + struct files_id_ctx *id_ctx = talloc_get_type(pvt, struct files_id_ctx); + errno_t ret; ++ errno_t tret; ++ bool in_transaction = false; + + talloc_zfree(imm); + +- ret = sf_enum_users(id_ctx); ++ ret = sysdb_transaction_start(id_ctx->domain->sysdb); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Enumerating users failed, data might be inconsistent!\n"); ++ goto done; + } ++ in_transaction = true; + +- ret = sf_enum_groups(id_ctx); ++ ret = delete_all_users(id_ctx->domain); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Enumerating groups failed, data might be inconsistent!\n"); ++ goto done; ++ } ++ ++ ret = delete_all_groups(id_ctx->domain); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ for (size_t i = 0; id_ctx->passwd_files[i] != NULL; i++) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Startup user enumeration of [%s]\n", id_ctx->passwd_files[i]); ++ ret = sf_enum_users(id_ctx, id_ctx->passwd_files[i]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Enumerating users failed, data might be inconsistent!\n"); ++ goto done; ++ } ++ } ++ ++ for (size_t i = 0; id_ctx->group_files[i] != NULL; i++) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Startup group enumeration of [%s]\n", id_ctx->group_files[i]); ++ ret = sf_enum_groups(id_ctx, id_ctx->group_files[i]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Enumerating groups failed, data might be inconsistent!\n"); ++ goto done; ++ } ++ } ++ ++ ret = sysdb_transaction_commit(id_ctx->domain->sysdb); ++ if (ret != EOK) { ++ goto done; ++ } ++ in_transaction = false; ++ ++done: ++ if (in_transaction) { ++ tret = sysdb_transaction_cancel(id_ctx->domain->sysdb); ++ if (tret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot cancel transaction: %d\n", ret); ++ } + } + } + +@@ -884,22 +950,29 @@ static struct snotify_ctx *sf_setup_watch(TALLOC_CTX *mem_ctx, + + struct files_ctx *sf_init(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +- const char *passwd_file, +- const char *group_file, ++ const char **passwd_files, ++ const char **group_files, + struct files_id_ctx *id_ctx) + { + struct files_ctx *fctx; + struct tevent_immediate *imm; ++ int i; + + fctx = talloc(mem_ctx, struct files_ctx); + if (fctx == NULL) { + return NULL; + } + +- fctx->pwd_watch = sf_setup_watch(fctx, ev, passwd_file, +- sf_passwd_cb, id_ctx); +- fctx->grp_watch = sf_setup_watch(fctx, ev, group_file, +- sf_group_cb, id_ctx); ++ for (i = 0; passwd_files[i]; i++) { ++ fctx->pwd_watch = sf_setup_watch(fctx, ev, passwd_files[i], ++ sf_passwd_cb, id_ctx); ++ } ++ ++ for (i = 0; group_files[i]; i++) { ++ fctx->grp_watch = sf_setup_watch(fctx, ev, group_files[i], ++ sf_group_cb, id_ctx); ++ } ++ + if (fctx->pwd_watch == NULL || fctx->grp_watch == NULL) { + talloc_free(fctx); + return NULL; +diff --git a/src/providers/files/files_private.h b/src/providers/files/files_private.h +index a7d195c90..f44e6d458 100644 +--- a/src/providers/files/files_private.h ++++ b/src/providers/files/files_private.h +@@ -39,8 +39,8 @@ struct files_id_ctx { + struct sss_domain_info *domain; + struct files_ctx *fctx; + +- const char *passwd_file; +- const char *group_file; ++ const char **passwd_files; ++ const char **group_files; + + bool updating_passwd; + bool updating_groups; +@@ -53,8 +53,8 @@ struct files_id_ctx { + /* files_ops.c */ + struct files_ctx *sf_init(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +- const char *passwd_file, +- const char *group_file, ++ const char **passwd_files, ++ const char **group_files, + struct files_id_ctx *id_ctx); + + /* files_id.c */ +-- +2.14.3 + diff --git a/0024-TESTS-Add-a-test-for-the-multiple-files-feature.patch b/0024-TESTS-Add-a-test-for-the-multiple-files-feature.patch new file mode 100644 index 0000000..a21c0b3 --- /dev/null +++ b/0024-TESTS-Add-a-test-for-the-multiple-files-feature.patch @@ -0,0 +1,123 @@ +From bb1455ce8d45d026f173f402bce29bf97af8c44d Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 26 Mar 2018 17:30:14 +0200 +Subject: [PATCH] TESTS: Add a test for the multiple files feature +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Adds an integration test for the new feature. + +Reviewed-by: Pavel Březina +(cherry picked from commit 4a9100a588ade253cecb2224b95bd8caa8136109) +--- + src/tests/intg/test_files_provider.py | 61 ++++++++++++++++++++++++++++++++++- + 1 file changed, 60 insertions(+), 1 deletion(-) + +diff --git a/src/tests/intg/test_files_provider.py b/src/tests/intg/test_files_provider.py +index 41bfd8844..ce5c7b774 100644 +--- a/src/tests/intg/test_files_provider.py ++++ b/src/tests/intg/test_files_provider.py +@@ -25,6 +25,7 @@ import subprocess + import pwd + import grp + import pytest ++import tempfile + + import ent + import sssd_id +@@ -33,7 +34,7 @@ from sssd_passwd import (call_sssd_getpwnam, + call_sssd_enumeration, + call_sssd_getpwuid) + from sssd_group import call_sssd_getgrnam, call_sssd_getgrgid +-from files_ops import passwd_ops_setup, group_ops_setup ++from files_ops import passwd_ops_setup, group_ops_setup, PasswdOps, GroupOps + from util import unindent + + # Sync this with files_ops.c +@@ -59,6 +60,11 @@ OV_USER1 = dict(name='ov_user1', passwd='x', uid=10010, gid=20010, + dir='/home/ov/user1', + shell='/bin/ov_user1_shell') + ++ALT_USER1 = dict(name='altuser1', passwd='x', uid=60001, gid=70001, ++ gecos='User for tests from alt files', ++ dir='/home/altuser1', ++ shell='/bin/bash') ++ + CANARY_GR = dict(name='canary', + gid=300001, + mem=[]) +@@ -79,6 +85,10 @@ GROUP_NOMEM = dict(name='group_nomem', + gid=40000, + mem=[]) + ++ALT_GROUP1 = dict(name='alt_group1', ++ gid=80001, ++ mem=['alt_user1']) ++ + + def start_sssd(): + """Start sssd and add teardown for stopping it and removing state""" +@@ -145,6 +155,38 @@ def files_domain_only(request): + return None + + ++@pytest.fixture ++def files_multiple_sources(request): ++ _, alt_passwd_path = tempfile.mkstemp(prefix='altpasswd') ++ request.addfinalizer(lambda: os.unlink(alt_passwd_path)) ++ alt_pwops = PasswdOps(alt_passwd_path) ++ ++ _, alt_group_path = tempfile.mkstemp(prefix='altgroup') ++ request.addfinalizer(lambda: os.unlink(alt_group_path)) ++ alt_grops = GroupOps(alt_group_path) ++ ++ passwd_list = ",".join([os.environ["NSS_WRAPPER_PASSWD"], alt_passwd_path]) ++ group_list = ",".join([os.environ["NSS_WRAPPER_GROUP"], alt_group_path]) ++ ++ conf = unindent("""\ ++ [sssd] ++ domains = files ++ services = nss ++ ++ [nss] ++ debug_level = 10 ++ ++ [domain/files] ++ id_provider = files ++ passwd_files = {passwd_list} ++ group_files = {group_list} ++ debug_level = 10 ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ return alt_pwops, alt_grops ++ ++ + @pytest.fixture + def proxy_to_files_domain_only(request): + conf = unindent("""\ +@@ -1054,3 +1096,20 @@ def test_no_sssd_conf(add_user_with_canary, no_sssd_conf): + res, user = sssd_getpwnam_sync(USER1["name"]) + assert res == NssReturnCode.SUCCESS + assert user == USER1 ++ ++ ++def test_multiple_passwd_group_files(add_user_with_canary, ++ add_group_with_canary, ++ files_multiple_sources): ++ """ ++ Test that users and groups can be mirrored from multiple files ++ """ ++ alt_pwops, alt_grops = files_multiple_sources ++ alt_pwops.useradd(**ALT_USER1) ++ alt_grops.groupadd(**ALT_GROUP1) ++ ++ check_user(USER1) ++ check_user(ALT_USER1) ++ ++ check_group(GROUP1) ++ check_group(ALT_GROUP1) +-- +2.14.3 + diff --git a/sssd.spec b/sssd.spec index 944ba2f..9f1e083 100644 --- a/sssd.spec +++ b/sssd.spec @@ -62,6 +62,9 @@ Patch0018: 0018-sysdb-custom-completely-replace-old-object-instead-o.patch Patch0019: 0019-SERVER-Tone-down-shutdown-messages-for-socket-activa.patch Patch0020: 0020-IPA-Qualify-the-externalUser-sudo-attribute.patch Patch0021: 0021-NSS-Adjust-netgroup-setnetgrent-cache-lifetime-if-mi.patch +Patch0022: 0022-CONFDB-Add-passwd_files-and-group_files-options.patch +Patch0023: 0023-FILES-Handle-files-provider-sources.patch +Patch0024: 0024-TESTS-Add-a-test-for-the-multiple-files-feature.patch Patch0500: 0500-Revert-libwbclient-sssd-update-interface-to-version-.patch Patch0502: 0502-SYSTEMD-Use-capabilities.patch @@ -1266,6 +1269,7 @@ fi - IPA: Qualify the externalUser sudo attribute - Resolves: upstream#3550 - refresh_expired_interval does not work with netgrous in 1.15 +- Resolves: upstream#3402 - Support alternative sources for the files provider * Fri Mar 30 2018 Fabiano Fidêncio - 1.16.1-2 - Resolves: upstream#3573 - sssd won't show netgroups with blank domain