URL: https://github.com/SSSD/sssd/pull/187 Author: fidencio Title: #187: Add support to lookup for users/groups in subdomains just by the user shortname Action: synchronized
To pull the PR as Git branch: git remote add ghsssd https://github.com/SSSD/sssd git fetch ghsssd pull/187/head:pr187 git checkout pr187
From bb88a6e449d5b737bebf86ecf15d570ce5cc8315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fiden...@redhat.com> Date: Wed, 1 Mar 2017 08:34:57 +0000 Subject: [PATCH 1/7] CACHE_REQ: Descend into subdomains on lookups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's make all plugins, but the "host_by_name", to descend into the subdomains on lookups. This patch basically prepares the field for the coming up patches that will allow group/user resolution in all domains (or a subset of the domains) to be possible by only using the short names without the domain component. The "host_by_name" plugin was not changed as it's a specific IPA plugin and won't find anything on its subdomains. Related: https://pagure.io/SSSD/sssd/issue/3001 Signed-off-by: Fabiano Fidêncio <fiden...@redhat.com> --- src/responder/common/cache_req/plugins/cache_req_enum_svc.c | 2 +- src/responder/common/cache_req/plugins/cache_req_group_by_filter.c | 2 +- src/responder/common/cache_req/plugins/cache_req_group_by_name.c | 2 +- src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c | 2 +- src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c | 2 +- src/responder/common/cache_req/plugins/cache_req_object_by_name.c | 2 +- src/responder/common/cache_req/plugins/cache_req_svc_by_name.c | 2 +- src/responder/common/cache_req/plugins/cache_req_svc_by_port.c | 2 +- src/responder/common/cache_req/plugins/cache_req_user_by_filter.c | 2 +- src/responder/common/cache_req/plugins/cache_req_user_by_name.c | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c index 2c4917c..28dea33 100644 --- a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c +++ b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c @@ -68,7 +68,7 @@ const struct cache_req_plugin cache_req_enum_svc = { .allow_missing_fqn = true, .allow_switch_to_upn = false, .upn_equivalent = CACHE_REQ_SENTINEL, - .get_next_domain_flags = 0, + .get_next_domain_flags = SSS_GND_DESCEND, .is_well_known_fn = NULL, .prepare_domain_data_fn = NULL, diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c index 88e1137..6ce6ae0 100644 --- a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c +++ b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c @@ -123,7 +123,7 @@ const struct cache_req_plugin cache_req_group_by_filter = { .allow_missing_fqn = false, .allow_switch_to_upn = false, .upn_equivalent = CACHE_REQ_SENTINEL, - .get_next_domain_flags = 0, + .get_next_domain_flags = SSS_GND_DESCEND, .is_well_known_fn = NULL, .prepare_domain_data_fn = cache_req_group_by_filter_prepare_domain_data, diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c index be1eb9b..af6f23c 100644 --- a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c +++ b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c @@ -186,7 +186,7 @@ const struct cache_req_plugin cache_req_group_by_name = { .allow_missing_fqn = false, .allow_switch_to_upn = false, .upn_equivalent = CACHE_REQ_SENTINEL, - .get_next_domain_flags = 0, + .get_next_domain_flags = SSS_GND_DESCEND, .is_well_known_fn = NULL, .prepare_domain_data_fn = cache_req_group_by_name_prepare_domain_data, diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c index 10fb67c..307b65a 100644 --- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c +++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c @@ -201,7 +201,7 @@ const struct cache_req_plugin cache_req_initgroups_by_name = { .allow_missing_fqn = false, .allow_switch_to_upn = true, .upn_equivalent = CACHE_REQ_INITGROUPS_BY_UPN, - .get_next_domain_flags = 0, + .get_next_domain_flags = SSS_GND_DESCEND, .is_well_known_fn = NULL, .prepare_domain_data_fn = cache_req_initgroups_by_name_prepare_domain_data, diff --git a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c index bc6fc9a..e49d6d8 100644 --- a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c +++ b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c @@ -120,7 +120,7 @@ const struct cache_req_plugin cache_req_netgroup_by_name = { .allow_missing_fqn = true, .allow_switch_to_upn = false, .upn_equivalent = CACHE_REQ_SENTINEL, - .get_next_domain_flags = 0, + .get_next_domain_flags = SSS_GND_DESCEND, .is_well_known_fn = NULL, .prepare_domain_data_fn = cache_req_netgroup_by_name_prepare_domain_data, diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c index 2b2caee..74d2b3d 100644 --- a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c +++ b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c @@ -196,7 +196,7 @@ const struct cache_req_plugin cache_req_object_by_name = { .allow_missing_fqn = false, .allow_switch_to_upn = true, .upn_equivalent = CACHE_REQ_USER_BY_UPN, - .get_next_domain_flags = 0, + .get_next_domain_flags = SSS_GND_DESCEND, .is_well_known_fn = cache_req_object_by_name_well_known, .prepare_domain_data_fn = cache_req_object_by_name_prepare_domain_data, diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c index cbb186d..ef13f09 100644 --- a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c +++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c @@ -144,7 +144,7 @@ const struct cache_req_plugin cache_req_svc_by_name = { .allow_missing_fqn = false, .allow_switch_to_upn = false, .upn_equivalent = CACHE_REQ_SENTINEL, - .get_next_domain_flags = 0, + .get_next_domain_flags = SSS_GND_DESCEND, .is_well_known_fn = NULL, .prepare_domain_data_fn = cache_req_svc_by_name_prepare_domain_data, diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c index 1da23d4..afa2eee 100644 --- a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c +++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c @@ -117,7 +117,7 @@ const struct cache_req_plugin cache_req_svc_by_port = { .allow_missing_fqn = false, .allow_switch_to_upn = false, .upn_equivalent = CACHE_REQ_SENTINEL, - .get_next_domain_flags = 0, + .get_next_domain_flags = SSS_GND_DESCEND, .is_well_known_fn = NULL, .prepare_domain_data_fn = cache_req_svc_by_port_prepare_domain_data, diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c index ee7e693..eb71b42 100644 --- a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c +++ b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c @@ -123,7 +123,7 @@ const struct cache_req_plugin cache_req_user_by_filter = { .allow_missing_fqn = false, .allow_switch_to_upn = false, .upn_equivalent = CACHE_REQ_SENTINEL, - .get_next_domain_flags = 0, + .get_next_domain_flags = SSS_GND_DESCEND, .is_well_known_fn = NULL, .prepare_domain_data_fn = cache_req_user_by_filter_prepare_domain_data, diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c index 4289f5f..0670feb 100644 --- a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c +++ b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c @@ -191,7 +191,7 @@ const struct cache_req_plugin cache_req_user_by_name = { .allow_missing_fqn = false, .allow_switch_to_upn = true, .upn_equivalent = CACHE_REQ_USER_BY_UPN, - .get_next_domain_flags = 0, + .get_next_domain_flags = SSS_GND_DESCEND, .is_well_known_fn = NULL, .prepare_domain_data_fn = cache_req_user_by_name_prepare_domain_data, From 5645f102e5773a719d40d19310d942ef84b40198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fiden...@redhat.com> Date: Mon, 27 Feb 2017 16:50:41 +0000 Subject: [PATCH 2/7] Allow subdomains to inherit "use_fully_qualified_names" option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces the possibility to have subdomains inheriting the "use_fully_qualified_names" option from its parent domain. The intention behind this change is to allow user and group resolution and user authentication in all the domains or a subset of the domains to be possible by using only the short names without the domain component. Related: https://pagure.io/SSSD/sssd/issue/3001 Signed-off-by: Fabiano Fidêncio <fiden...@redhat.com> --- src/db/sysdb_subdomains.c | 7 ++++++- src/man/sssd.conf.5.xml | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c index 01f4976..6b501e8 100644 --- a/src/db/sysdb_subdomains.c +++ b/src/db/sysdb_subdomains.c @@ -118,7 +118,6 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, } dom->enumerate = enumerate; - dom->fqnames = true; dom->mpg = mpg; dom->state = DOM_ACTIVE; @@ -147,6 +146,12 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, dom->service_timeout = parent->service_timeout; dom->names = parent->names; + /* If the parent domain requires fully-qualified names, the subdomain should + * do as well */ + inherit_option = string_in_list(CONFDB_DOMAIN_FQ, + parent->sd_inherit, false); + dom->fqnames = inherit_option ? parent->fqnames : true; + dom->override_homedir = parent->override_homedir; dom->fallback_homedir = parent->fallback_homedir; dom->subdomain_homedir = parent->subdomain_homedir; diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index 284402b..a3e7c69 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -2491,6 +2491,9 @@ pam_account_locked_message = Account locked, please contact help desk. ldap_user_principal </para> <para> + use_fully_qualified_names + </para> + <para> ldap_krb5_keytab (the value of krb5_keytab will be used if ldap_krb5_keytab is not set explicitly) </para> From 8d1c7cce75e1aa93dae4ac230e7c5dca896676da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com> Date: Wed, 1 Mar 2017 13:21:19 +0000 Subject: [PATCH 3/7] NSS/TESTS: Fix subdomains attribution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related: https://pagure.io/SSSD/sssd/issue/3001 Reviewed-by: Fabiano Fidêncio <fiden...@redhat.com> --- src/tests/cmocka/test_nss_srv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c index 72bbaf9..d06326e 100644 --- a/src/tests/cmocka/test_nss_srv.c +++ b/src/tests/cmocka/test_nss_srv.c @@ -3217,7 +3217,7 @@ static int nss_subdom_test_setup(void **state) ret = sysdb_update_subdomains(nss_test_ctx->tctx->dom); assert_int_equal(ret, EOK); - nss_test_ctx->subdom = subdomain; + nss_test_ctx->subdom = nss_test_ctx->tctx->dom->subdomains; return 0; } From 752a23e22ea0e84296d09dc7ce729f5c563f8876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fiden...@redhat.com> Date: Wed, 1 Mar 2017 20:46:10 +0000 Subject: [PATCH 4/7] NSS/TESTS: Improve setup/teardown for subdomains tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch basically makes the getgrnam_members_subdom(), getgrnam_mix_dom(), getgrnam_mix_dom_fqdn() and getgrnam_mix_subdom() more independent of each other. Related: https://pagure.io/SSSD/sssd/issue/3001 Signed-off-by: Fabiano Fidêncio <fiden...@redhat.com> --- src/tests/cmocka/test_nss_srv.c | 182 +++++++++++++++++++++++++++++++++------- 1 file changed, 150 insertions(+), 32 deletions(-) diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c index d06326e..ff740c7 100644 --- a/src/tests/cmocka/test_nss_srv.c +++ b/src/tests/cmocka/test_nss_srv.c @@ -418,6 +418,26 @@ static errno_t store_user(struct nss_test_ctx *ctx, return ret; } +static errno_t delete_user(struct nss_test_ctx *ctx, + struct sss_domain_info *dom, + struct passwd *user) +{ + errno_t ret; + char *fqname; + + fqname = sss_create_internal_fqname(ctx, + user->pw_name, + dom->name); + if (fqname == NULL) { + return ENOMEM; + } + + ret = sysdb_delete_user(dom, fqname, user->pw_uid); + + talloc_free(fqname); + return ret; +} + static errno_t set_user_attr(struct nss_test_ctx *ctx, struct sss_domain_info *dom, struct passwd *user, @@ -491,6 +511,27 @@ static errno_t store_group(struct nss_test_ctx *ctx, return ret; } +static errno_t delete_group(struct nss_test_ctx *ctx, + struct sss_domain_info *dom, + struct group *group) +{ + errno_t ret; + char *fqname; + + fqname = sss_create_internal_fqname(ctx, + group->gr_name, + dom->name); + + if (fqname == NULL) { + return ENOMEM; + } + + ret = sysdb_delete_group(dom, fqname, group->gr_gid); + + talloc_free(fqname); + return ret; +} + static void assert_groups_equal(struct group *expected, struct group *gr, const int nmem) { @@ -540,6 +581,42 @@ static errno_t store_group_member(struct nss_test_ctx *ctx, return ret; } +static errno_t remove_group_member(struct nss_test_ctx *ctx, + const char *shortname_group, + struct sss_domain_info *group_dom, + const char *shortname_member, + struct sss_domain_info *member_dom, + enum sysdb_member_type type) +{ + errno_t ret; + char *group_fqname = NULL; + char *member_fqname = NULL; + + group_fqname = sss_create_internal_fqname(ctx, + shortname_group, + group_dom->name); + if (group_fqname == NULL) { + return ENOMEM; + } + + member_fqname = sss_create_internal_fqname(ctx, + shortname_member, + member_dom->name); + if (member_fqname == NULL) { + talloc_free(group_fqname); + return ENOMEM; + } + + ret = sysdb_remove_group_member(group_dom, + group_fqname, + member_fqname, + type, + false); + + talloc_free(group_fqname); + talloc_free(member_fqname); + return ret; +} /* ====================== The tests =============================== */ struct passwd getpwnam_usr = { @@ -1599,34 +1676,6 @@ void test_nss_getgrnam_members_subdom(void **state) { errno_t ret; - ret = store_group(nss_test_ctx, nss_test_ctx->subdom, - &testsubdomgroup, 0); - assert_int_equal(ret, EOK); - - ret = store_user(nss_test_ctx, nss_test_ctx->subdom, - &submember1, NULL, 0); - assert_int_equal(ret, EOK); - - ret = store_user(nss_test_ctx, nss_test_ctx->subdom, - &submember2, NULL, 0); - assert_int_equal(ret, EOK); - - ret = store_group_member(nss_test_ctx, - testsubdomgroup.gr_name, - nss_test_ctx->subdom, - submember1.pw_name, - nss_test_ctx->subdom, - SYSDB_MEMBER_USER); - assert_int_equal(ret, EOK); - - ret = store_group_member(nss_test_ctx, - testsubdomgroup.gr_name, - nss_test_ctx->subdom, - submember2.pw_name, - nss_test_ctx->subdom, - SYSDB_MEMBER_USER); - assert_int_equal(ret, EOK); - mock_input_user_or_group("testsubdomgroup@"TEST_SUBDOM_NAME); will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL); @@ -1757,6 +1806,14 @@ void test_nss_getgrnam_mix_dom_fqdn(void **state) { errno_t ret; + ret = store_group_member(nss_test_ctx, + testgroup_members.gr_name, + nss_test_ctx->tctx->dom, + submember1.pw_name, + nss_test_ctx->subdom, + SYSDB_MEMBER_USER); + assert_int_equal(ret, EOK); + nss_test_ctx->tctx->dom->fqnames = true; mock_input_user_or_group("testgroup_members@"TEST_DOM_NAME); @@ -3218,6 +3275,35 @@ static int nss_subdom_test_setup(void **state) assert_int_equal(ret, EOK); nss_test_ctx->subdom = nss_test_ctx->tctx->dom->subdomains; + + ret = store_group(nss_test_ctx, nss_test_ctx->subdom, + &testsubdomgroup, 0); + assert_int_equal(ret, EOK); + + ret = store_user(nss_test_ctx, nss_test_ctx->subdom, + &submember1, NULL, 0); + assert_int_equal(ret, EOK); + + ret = store_user(nss_test_ctx, nss_test_ctx->subdom, + &submember2, NULL, 0); + assert_int_equal(ret, EOK); + + ret = store_group_member(nss_test_ctx, + testsubdomgroup.gr_name, + nss_test_ctx->subdom, + submember1.pw_name, + nss_test_ctx->subdom, + SYSDB_MEMBER_USER); + assert_int_equal(ret, EOK); + + ret = store_group_member(nss_test_ctx, + testsubdomgroup.gr_name, + nss_test_ctx->subdom, + submember2.pw_name, + nss_test_ctx->subdom, + SYSDB_MEMBER_USER); + assert_int_equal(ret, EOK); + return 0; } @@ -3239,6 +3325,38 @@ static int nss_test_teardown(void **state) return 0; } +static int nss_subdom_test_teardown(void **state) +{ + errno_t ret; + + ret = remove_group_member(nss_test_ctx, + testsubdomgroup.gr_name, + nss_test_ctx->subdom, + submember2.pw_name, + nss_test_ctx->subdom, + SYSDB_MEMBER_USER); + assert_int_equal(ret, EOK); + + ret = remove_group_member(nss_test_ctx, + testsubdomgroup.gr_name, + nss_test_ctx->subdom, + submember1.pw_name, + nss_test_ctx->subdom, + SYSDB_MEMBER_USER); + assert_int_equal(ret, EOK); + + ret = delete_user(nss_test_ctx, nss_test_ctx->subdom, &submember2); + assert_int_equal(ret, EOK); + + ret = delete_user(nss_test_ctx, nss_test_ctx->subdom, &submember1); + assert_int_equal(ret, EOK); + + ret = delete_group(nss_test_ctx, nss_test_ctx->subdom, &testsubdomgroup); + assert_int_equal(ret, EOK); + + return nss_test_teardown(state); +} + struct passwd testbysid = { .pw_name = discard_const("testsiduser"), .pw_uid = 12345, @@ -3748,16 +3866,16 @@ int main(int argc, const char *argv[]) nss_fqdn_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_members_subdom, nss_subdom_test_setup, - nss_test_teardown), + nss_subdom_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom, nss_subdom_test_setup, - nss_test_teardown), + nss_subdom_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_fqdn, nss_subdom_test_setup, - nss_test_teardown), + nss_subdom_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_subdom, nss_subdom_test_setup, - nss_test_teardown), + nss_subdom_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_space, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_space_sub, From 95407fb37e0eb0b060bd5a6a8907bbca4598a6f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fiden...@redhat.com> Date: Wed, 1 Mar 2017 08:33:06 +0000 Subject: [PATCH 5/7] NSS/TESTS: Include searches for non-fqnames members of a subdomain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's extend the NSS tests in order to also test looking up users, from a subdomain, by their short names (non fully qualified names). Related: https://pagure.io/SSSD/sssd/issue/3001 Signed-off-by: Fabiano Fidêncio <fiden...@redhat.com> --- src/tests/cmocka/test_nss_srv.c | 250 ++++++++++++++++++++++++++++++++++------ 1 file changed, 213 insertions(+), 37 deletions(-) diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c index ff740c7..f065ac3 100644 --- a/src/tests/cmocka/test_nss_srv.c +++ b/src/tests/cmocka/test_nss_srv.c @@ -1648,16 +1648,29 @@ static int test_nss_getgrnam_members_check_subdom(uint32_t status, tmp_ctx = talloc_new(nss_test_ctx); assert_non_null(tmp_ctx); - exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, - nss_test_ctx->subdom, submember1.pw_name); - assert_non_null(exp_members[0]); - exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, - nss_test_ctx->subdom, submember2.pw_name); - assert_non_null(exp_members[1]); - - expected.gr_name = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, - nss_test_ctx->subdom, testsubdomgroup.gr_name); - assert_non_null(expected.gr_name); + if (nss_test_ctx->subdom->fqnames) { + exp_members[0] = sss_tc_fqname(tmp_ctx, + nss_test_ctx->subdom->names, + nss_test_ctx->subdom, + submember1.pw_name); + assert_non_null(exp_members[0]); + + exp_members[1] = sss_tc_fqname(tmp_ctx, + nss_test_ctx->subdom->names, + nss_test_ctx->subdom, + submember2.pw_name); + assert_non_null(exp_members[1]); + + expected.gr_name = sss_tc_fqname(tmp_ctx, + nss_test_ctx->subdom->names, + nss_test_ctx->subdom, + testsubdomgroup.gr_name); + assert_non_null(expected.gr_name); + } else { + exp_members[0] = submember1.pw_name; + exp_members[1] = submember2.pw_name; + expected.gr_name = testsubdomgroup.gr_name; + } assert_int_equal(status, EOK); @@ -1692,6 +1705,29 @@ void test_nss_getgrnam_members_subdom(void **state) assert_int_equal(ret, EOK); } +void test_nss_getgrnam_members_subdom_nonfqnames(void **state) +{ + errno_t ret; + + nss_test_ctx->subdom->fqnames = false; + + mock_input_user_or_group("testsubdomgroup"); + mock_account_recv_simple(); + will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); + will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + + /* Query for that group, call a callback when command finishes */ + set_cmd_cb(test_nss_getgrnam_members_check_subdom); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, + nss_test_ctx->nss_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(nss_test_ctx->tctx); + + assert_int_equal(ret, EOK); +} + static int test_nss_getgrnam_check_mix_dom(uint32_t status, uint8_t *body, size_t blen) { @@ -1710,9 +1746,15 @@ static int test_nss_getgrnam_check_mix_dom(uint32_t status, tmp_ctx = talloc_new(nss_test_ctx); assert_non_null(tmp_ctx); - exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, - nss_test_ctx->subdom, submember1.pw_name); - assert_non_null(exp_members[0]); + if (nss_test_ctx->subdom->fqnames) { + exp_members[0] = sss_tc_fqname(tmp_ctx, + nss_test_ctx->subdom->names, + nss_test_ctx->subdom, + submember1.pw_name); + assert_non_null(exp_members[0]); + } else { + exp_members[0] = submember1.pw_name; + } exp_members[1] = testmember1.pw_name; exp_members[2] = testmember2.pw_name; @@ -1756,6 +1798,35 @@ void test_nss_getgrnam_mix_dom(void **state) assert_int_equal(ret, EOK); } +void test_nss_getgrnam_mix_dom_nonfqnames(void **state) +{ + errno_t ret; + + nss_test_ctx->subdom->fqnames = false; + + ret = store_group_member(nss_test_ctx, + testgroup_members.gr_name, + nss_test_ctx->tctx->dom, + submember1.pw_name, + nss_test_ctx->subdom, + SYSDB_MEMBER_USER); + assert_int_equal(ret, EOK); + + mock_input_user_or_group("testgroup_members"); + will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); + will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + + /* Query for that group, call a callback when command finishes */ + set_cmd_cb(test_nss_getgrnam_check_mix_dom); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, + nss_test_ctx->nss_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(nss_test_ctx->tctx); + assert_int_equal(ret, EOK); +} + static int test_nss_getgrnam_check_mix_dom_fqdn(uint32_t status, uint8_t *body, size_t blen) { @@ -1773,21 +1844,33 @@ static int test_nss_getgrnam_check_mix_dom_fqdn(uint32_t status, tmp_ctx = talloc_new(nss_test_ctx); assert_non_null(tmp_ctx); - exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, - nss_test_ctx->subdom, submember1.pw_name); - assert_non_null(exp_members[0]); - exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, - nss_test_ctx->tctx->dom, testmember1.pw_name); - assert_non_null(exp_members[1]); - exp_members[2] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, - nss_test_ctx->tctx->dom, testmember2.pw_name); - assert_non_null(exp_members[2]); - - expected.gr_name = sss_tc_fqname(tmp_ctx, - nss_test_ctx->tctx->dom->names, - nss_test_ctx->tctx->dom, - testgroup_members.gr_name); - assert_non_null(expected.gr_name); + if (nss_test_ctx->subdom->fqnames) { + exp_members[0] = sss_tc_fqname(tmp_ctx, + nss_test_ctx->subdom->names, + nss_test_ctx->subdom, + submember1.pw_name); + assert_non_null(exp_members[0]); + } else { + exp_members[0] = submember1.pw_name; + } + if (nss_test_ctx->tctx->dom->fqnames) { + exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, + nss_test_ctx->tctx->dom, testmember1.pw_name); + assert_non_null(exp_members[1]); + exp_members[2] = sss_tc_fqname(tmp_ctx, nss_test_ctx->tctx->dom->names, + nss_test_ctx->tctx->dom, testmember2.pw_name); + assert_non_null(exp_members[2]); + + expected.gr_name = sss_tc_fqname(tmp_ctx, + nss_test_ctx->tctx->dom->names, + nss_test_ctx->tctx->dom, + testgroup_members.gr_name); + assert_non_null(expected.gr_name); + } else { + exp_members[1] = testmember1.pw_name; + exp_members[2] = testmember2.pw_name; + expected.gr_name = testgroup_members.gr_name; + } assert_int_equal(status, EOK); @@ -1834,6 +1917,40 @@ void test_nss_getgrnam_mix_dom_fqdn(void **state) assert_int_equal(ret, EOK); } +void test_nss_getgrnam_mix_dom_fqdn_nonfqnames(void **state) +{ + errno_t ret; + + ret = store_group_member(nss_test_ctx, + testgroup_members.gr_name, + nss_test_ctx->tctx->dom, + submember1.pw_name, + nss_test_ctx->subdom, + SYSDB_MEMBER_USER); + assert_int_equal(ret, EOK); + + nss_test_ctx->tctx->dom->fqnames = false; + nss_test_ctx->subdom->fqnames = false; + + + mock_input_user_or_group("testgroup_members"); + will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); + will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + + /* Query for that group, call a callback when command finishes */ + set_cmd_cb(test_nss_getgrnam_check_mix_dom_fqdn); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, + nss_test_ctx->nss_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(nss_test_ctx->tctx); + + /* Restore FQDN settings */ + nss_test_ctx->tctx->dom->fqnames = false; + assert_int_equal(ret, EOK); +} + static int test_nss_getgrnam_check_mix_subdom(uint32_t status, uint8_t *body, size_t blen) { @@ -1851,20 +1968,37 @@ static int test_nss_getgrnam_check_mix_subdom(uint32_t status, tmp_ctx = talloc_new(nss_test_ctx); assert_non_null(tmp_ctx); - exp_members[0] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, - nss_test_ctx->subdom, submember1.pw_name); - assert_non_null(exp_members[0]); - exp_members[1] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, - nss_test_ctx->subdom, submember2.pw_name); - assert_non_null(exp_members[1]); + if (nss_test_ctx->subdom->fqnames) { + exp_members[0] = sss_tc_fqname(tmp_ctx, + nss_test_ctx->subdom->names, + nss_test_ctx->subdom, + submember1.pw_name); + assert_non_null(exp_members[0]); + + exp_members[1] = sss_tc_fqname(tmp_ctx, + nss_test_ctx->subdom->names, + nss_test_ctx->subdom, + submember2.pw_name); + assert_non_null(exp_members[1]); + } else { + exp_members[0] = submember1.pw_name; + exp_members[1] = submember2.pw_name; + } + /* Important: this member is from a non-qualified domain, so his name will * not be qualified either */ exp_members[2] = testmember1.pw_name; - expected.gr_name = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, - nss_test_ctx->subdom, testsubdomgroup.gr_name); - assert_non_null(expected.gr_name); + if (nss_test_ctx->subdom->fqnames) { + expected.gr_name = sss_tc_fqname(tmp_ctx, + nss_test_ctx->subdom->names, + nss_test_ctx->subdom, + testsubdomgroup.gr_name); + assert_non_null(expected.gr_name); + } else { + expected.gr_name = testsubdomgroup.gr_name; + } assert_int_equal(status, EOK); @@ -1906,6 +2040,36 @@ void test_nss_getgrnam_mix_subdom(void **state) assert_int_equal(ret, EOK); } +void test_nss_getgrnam_mix_subdom_nonfqnames(void **state) +{ + errno_t ret; + + nss_test_ctx->subdom->fqnames = false; + + ret = store_group_member(nss_test_ctx, + testsubdomgroup.gr_name, + nss_test_ctx->subdom, + testmember1.pw_name, + nss_test_ctx->tctx->dom, + SYSDB_MEMBER_USER); + assert_int_equal(ret, EOK); + + mock_input_user_or_group("testsubdomgroup"); + mock_account_recv_simple(); + will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM); + will_return_always(__wrap_sss_packet_get_body, WRAP_CALL_REAL); + + /* Query for that group, call a callback when command finishes */ + set_cmd_cb(test_nss_getgrnam_check_mix_subdom); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM, + nss_test_ctx->nss_cmds); + assert_int_equal(ret, EOK); + + /* Wait until the test finishes with EOK */ + ret = test_ev_loop(nss_test_ctx->tctx); + assert_int_equal(ret, EOK); +} + struct group space_group = { .gr_gid = 2123, .gr_name = discard_const("space group"), @@ -3867,15 +4031,27 @@ int main(int argc, const char *argv[]) cmocka_unit_test_setup_teardown(test_nss_getgrnam_members_subdom, nss_subdom_test_setup, nss_subdom_test_teardown), + cmocka_unit_test_setup_teardown(test_nss_getgrnam_members_subdom_nonfqnames, + nss_subdom_test_setup, + nss_subdom_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom, nss_subdom_test_setup, nss_subdom_test_teardown), + cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_nonfqnames, + nss_subdom_test_setup, + nss_subdom_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_fqdn, nss_subdom_test_setup, nss_subdom_test_teardown), + cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_dom_fqdn_nonfqnames, + nss_subdom_test_setup, + nss_subdom_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_subdom, nss_subdom_test_setup, nss_subdom_test_teardown), + cmocka_unit_test_setup_teardown(test_nss_getgrnam_mix_subdom_nonfqnames, + nss_subdom_test_setup, + nss_subdom_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_space, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getgrnam_space_sub, From 1538eddf79b9d99217e52e8618f9e7cd7fcbc4e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fiden...@redhat.com> Date: Thu, 16 Mar 2017 12:44:19 +0100 Subject: [PATCH 6/7] Add domains' lookup order config option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This option will be used to define a specific lookup order to be followed. The list should contain the domain with the given name and no expansion magic will be done from our side. It means that if 'example.com' is set it doesn't stand for all sub-domains DNS wise like 'a.example.com', 'b.example.com', etc. In case the admin has several domains but not all of them are part of the domains' lookup order, the domains which were not explicitly set up will be appended to the final lookup ordered list in the very same order they're presented in the "domains" option of [sssd] section in the config file. Related: https://pagure.io/SSSD/sssd/issue/3001 Signed-off-by: Fabiano Fidêncio <fiden...@redhat.com> --- src/confdb/confdb.h | 1 + src/config/SSSDConfig/__init__.py.in | 1 + src/config/SSSDConfigTest.py | 7 ++- src/config/cfg_rules.ini | 1 + src/config/etc/sssd.api.conf | 1 + src/man/sssd.conf.5.xml | 20 ++++++++ src/responder/common/cache_req/cache_req.c | 7 ++- src/responder/common/responder.h | 3 ++ src/responder/common/responder_common.c | 11 +++++ src/responder/common/responder_get_domains.c | 70 ++++++++++++++++++++++++++++ 10 files changed, 119 insertions(+), 3 deletions(-) diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index c05b1ce..51ea7e1 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -74,6 +74,7 @@ #define CONFDB_MONITOR_CERT_VERIFICATION "certificate_verification" #define CONFDB_MONITOR_DISABLE_NETLINK "disable_netlink" #define CONFDB_MONITOR_ENABLE_FILES_DOM "enable_files_domain" +#define CONFDB_MONITOR_LOOKUP_ORDER "lookup_order" /* Both monitor and domains */ #define CONFDB_NAME_REGEX "re_expression" diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in index 03a1a43..791fcca 100644 --- a/src/config/SSSDConfig/__init__.py.in +++ b/src/config/SSSDConfig/__init__.py.in @@ -66,6 +66,7 @@ option_strings = { 'override_space': _('All spaces in group or user names will be replaced with this character'), 'disable_netlink' : _('Tune sssd to honor or ignore netlink state changes'), 'enable_files_domain' : _('Enable or disable the implicit files domain'), + 'lookup_order': _('A specific order of the domains to be looked up'), # [nss] 'enum_cache_timeout' : _('Enumeration cache timeout length (seconds)'), diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py index 457a6f0..f64f7c7 100755 --- a/src/config/SSSDConfigTest.py +++ b/src/config/SSSDConfigTest.py @@ -94,6 +94,10 @@ def testServices(self): self.assertTrue('default_domain_suffix' in new_options) self.assertEquals(new_options['default_domain_suffix'][0], str) + self.assertTrue('lookup_order' in new_options) + self.assertEquals(new_options['lookup_order'][0], list) + self.assertEquals(new_options['lookup_order'][1], str) + del sssdconfig def testDomains(self): @@ -314,7 +318,8 @@ def testListOptions(self): 'certificate_verification', 'override_space', 'disable_netlink', - 'enable_files_domain'] + 'enable_files_domain', + 'lookup_order'] self.assertTrue(type(options) == dict, "Options should be a dictionary") diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini index c287328..675197e 100644 --- a/src/config/cfg_rules.ini +++ b/src/config/cfg_rules.ini @@ -42,6 +42,7 @@ option = override_space option = config_file_version option = disable_netlink option = enable_files_domain +option = lookup_order [rule/allowed_nss_options] validator = ini_allowed_options diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf index 08cecf0..1b5ec5f 100644 --- a/src/config/etc/sssd.api.conf +++ b/src/config/etc/sssd.api.conf @@ -32,6 +32,7 @@ certificate_verification = str, None, false override_space = str, None, false disable_netlink = bool, None, false enable_files_domain = str, None, false +lookup_order = list, str, false [nss] # Name service diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index a3e7c69..bb8a942 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -542,6 +542,26 @@ </para> </listitem> </varlistentry> + <varlistentry> + <term>lookup_order</term> + <listitem> + <para> + Comma separated list of domains and subdomains + representing the lookup order that will be + followed. + The list doesn't have to include all possible + domains as the missing domains will be looked + up based on the order they're presented in the + <quote>domains</quote> configuration option. + The subdomains which are not listed as part of + <quote>lookup_order</quote> will be looked up + in a random order for each parent domain. + </para> + <para> + Default: Not set + </para> + </listitem> + </varlistentry> </variablelist> </para> </refsect2> diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c index aca150d..26d40c0 100644 --- a/src/responder/common/cache_req/cache_req.c +++ b/src/responder/common/cache_req/cache_req.c @@ -779,6 +779,7 @@ static errno_t cache_req_select_domains(struct tevent_req *req, { struct cache_req_state *state = NULL; struct sss_domain_info *domain; + struct resp_ctx *rctx; bool check_next; bool bypass_cache; bool bypass_dp; @@ -794,11 +795,12 @@ static errno_t cache_req_select_domains(struct tevent_req *req, return EOK; } + rctx = state->cr->rctx; if (domain_name != NULL) { CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, "Performing a single domain search\n"); - domain = responder_get_domain(state->cr->rctx, domain_name); + domain = responder_get_domain(rctx, domain_name); if (domain == NULL) { return ERR_DOMAIN_NOT_FOUND; } @@ -808,7 +810,8 @@ static errno_t cache_req_select_domains(struct tevent_req *req, CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, "Performing a multi-domain search\n"); - domain = state->cr->rctx->domains; + domain = rctx->lookup_order != NULL ? rctx->lookup_order : + rctx->domains; check_next = true; } diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h index 4d1048a..a85f4d1 100644 --- a/src/responder/common/responder.h +++ b/src/responder/common/responder.h @@ -139,6 +139,9 @@ struct resp_ctx { bool socket_activated; bool dbus_activated; bool cache_first; + + struct sss_domain_info *lookup_order; + char **lookup_order_list; }; struct cli_creds; diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c index 76f4360..f70fcd0 100644 --- a/src/responder/common/responder_common.c +++ b/src/responder/common/responder_common.c @@ -1194,6 +1194,17 @@ int sss_process_init(TALLOC_CTX *mem_ctx, } } + ret = confdb_get_string_as_list(rctx->cdb, rctx, + CONFDB_MONITOR_CONF_ENTRY, + CONFDB_MONITOR_LOOKUP_ORDER, + &rctx->lookup_order_list); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Cannot get the \"lookup_order\" option.\n" + "The set up lookup_order won't be followed [%d]: %s.\n", + ret, sss_strerror(ret)); + } + ret = sysdb_init(rctx, rctx->domains); if (ret != EOK) { SYSDB_VERSION_ERROR_DAEMON(ret); diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c index 0f39d10..87159a6 100644 --- a/src/responder/common/responder_get_domains.c +++ b/src/responder/common/responder_get_domains.c @@ -364,6 +364,74 @@ static errno_t check_last_request(struct resp_ctx *rctx, const char *hint) return EOK; } +static errno_t +add_domain_to_lookup_order_list(TALLOC_CTX *mem_ctx, + struct sss_domain_info **lookup_order, + struct sss_domain_info *domain) +{ + struct sss_domain_info *new; + + new = talloc_memdup(mem_ctx, domain, sizeof(struct sss_domain_info)); + if (new == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_memdup() failed!\n"); + return ENOMEM; + } + new->prev = NULL; + new->next = NULL; + new->parent = NULL; + new->subdomains = NULL; + + DLIST_ADD_END(*lookup_order, new, struct sss_domain_info *); + + return EOK; +} + +static void create_domains_lookup_order_list(struct resp_ctx *rctx) +{ + struct sss_domain_info *dom; + char *domain_name; + errno_t ret; + int i; + + if (rctx->lookup_order_list == NULL) { + return; + } + + for (i = 0; rctx->lookup_order_list[i] != NULL; i++) { + domain_name = rctx->lookup_order_list[i]; + for (dom = rctx->domains; + dom != NULL; + dom = get_next_domain(dom, SSS_GND_DESCEND)) { + if (strcmp(domain_name, dom->name) == 0) { + ret = add_domain_to_lookup_order_list(rctx, &rctx->lookup_order, + dom); + if (ret != EOK) { + goto fail; + } + + break; + } + } + } + + for (dom = rctx->domains; + dom != NULL; + dom = get_next_domain(dom, SSS_GND_DESCEND)) { + if (!string_in_list(dom->name, rctx->lookup_order_list, false)) { + ret = add_domain_to_lookup_order_list(rctx, &rctx->lookup_order, + dom); + if (ret != EOK) { + goto fail; + } + } + } + + return; + +fail: + talloc_zfree(rctx->lookup_order); +} + struct get_domains_state { struct resp_ctx *rctx; struct sss_nc_ctx *optional_ncache; @@ -390,6 +458,8 @@ static void get_domains_at_startup_done(struct tevent_req *req) } } + create_domains_lookup_order_list(state->rctx); + talloc_free(state); return; } From 43df99f22e4db0e307bac6fa463f53a7577c5905 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fiden...@redhat.com> Date: Wed, 8 Mar 2017 03:01:49 +0100 Subject: [PATCH 7/7] UTIL: Avoid duplication when creating a list from a string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When parsing a string as a list, let's ensure there's no duplicated entries in the resulting list. As far as I understsand, there's no place where a duplicated string actually makes sense in our code and it can avoid creating twice some object, at least, in when using the domain's lookup order config option, in case the admin, by mistake, adds the same domain twice. Related: https://pagure.io/SSSD/sssd/issue/3001 Signed-off-by: Fabiano Fidêncio <fiden...@redhat.com> --- src/tests/util-tests.c | 6 +++--- src/util/util.c | 19 ++++++++++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/tests/util-tests.c b/src/tests/util-tests.c index ae2577f..b456a68 100644 --- a/src/tests/util-tests.c +++ b/src/tests/util-tests.c @@ -832,13 +832,13 @@ START_TEST(test_split_on_separator) { /* If skip empty is false, single comma means "empty,empty" */ ",", - (const char*[]){"", "", NULL, NULL}, + (const char*[]){"", NULL}, false, false, - 2, 0 + 1, 0 }, { "one, ,", - (const char*[]){"one", " ", "NULL", "NULL"}, + (const char*[]){"one", " ", NULL}, false, true, 2, 0 }, diff --git a/src/util/util.c b/src/util/util.c index a528f0c..967f81b 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -43,6 +43,7 @@ int split_on_separator(TALLOC_CTX *mem_ctx, const char *str, const char *substr_end = str; const char *substr_begin = str; const char *sep_pos = NULL; + char *string; size_t substr_len; char **list = NULL; int num_strings = 0; @@ -90,19 +91,27 @@ int split_on_separator(TALLOC_CTX *mem_ctx, const char *str, /* Copy the substring to the output list of strings */ if (skip_empty == false || substr_len > 0) { - list = talloc_realloc(tmp_ctx, list, char*, num_strings + 2); - if (list == NULL) { + string = talloc_strndup(list, substr_begin, substr_len); + if (string == NULL) { ret = ENOMEM; goto done; } - /* empty string is stored for substr_len == 0 */ - list[num_strings] = talloc_strndup(list, substr_begin, substr_len); - if (list[num_strings] == NULL) { + if (string_in_list(string, list, false)) { + talloc_free(string); + continue; + } + + list = talloc_realloc(tmp_ctx, list, char*, num_strings + 2); + if (list == NULL) { ret = ENOMEM; goto done; } + + /* empty string is stored for substr_len == 0 */ + list[num_strings] = string; num_strings++; + list[num_strings] = NULL; } } while (*sep_pos != '\0');
_______________________________________________ sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org