[sssd/f17] Rebase to 1.9.4
Jakub Hrozek
jhrozek at fedoraproject.org
Mon Mar 25 13:45:08 UTC 2013
commit 40c3ae988fbeb03f3ae1b9b31d6288ae3d8f3a39
Author: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon Mar 25 13:20:29 2013 +0100
Rebase to 1.9.4
.gitignore | 1 +
0001-krb-recreate-ccache-if-it-was-deleted.patch | 39 +
...replace-invalid-characters-with-underscor.patch | 69 +
...-Fix-the-krb5-password-expiration-warning.patch | 39 +
...it-tests-for-simple-access-test-by-groups.patch | 412 +++++
...ile-main-in-DP-if-UNIT_TESTING-is-defined.patch | 40 +
...ovide-a-be_get_account_info_send-function.patch | 236 +++
...esolve-GIDs-in-the-simple-access-provider.patch | 1622 ++++++++++++++++++++
sources | 2 +-
sssd.spec | 117 ++-
10 files changed, 2557 insertions(+), 20 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index e99f7d2..9f0a81c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,4 @@ sssd-1.2.91.tar.gz
/sssd-1.8.4.tar.gz
/sssd-1.8.5.tar.gz
/sssd-1.8.6.tar.gz
+/sssd-1.9.4.tar.gz
diff --git a/0001-krb-recreate-ccache-if-it-was-deleted.patch b/0001-krb-recreate-ccache-if-it-was-deleted.patch
new file mode 100644
index 0000000..51f8634
--- /dev/null
+++ b/0001-krb-recreate-ccache-if-it-was-deleted.patch
@@ -0,0 +1,39 @@
+From cae3bf6af22855adc8dd7b270e11207f0a33c385 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina at redhat.com>
+Date: Wed, 30 Jan 2013 13:45:27 +0100
+Subject: [PATCH] krb: recreate ccache if it was deleted
+
+https://fedorahosted.org/sssd/ticket/1512
+
+If directory where a ccache file was stored was missing and user
+was still logged in, we erroneously considered the ccache file
+still active. Thus the ccache file was not recreated and user was
+unable to login.
+---
+ src/providers/krb5/krb5_utils.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
+index b770714be030076203b6578f90ef726226cb72f8..7b56be52497ae66fa536b76ca0561ec3cc3208ce 100644
+--- a/src/providers/krb5/krb5_utils.c
++++ b/src/providers/krb5/krb5_utils.c
+@@ -770,8 +770,15 @@ cc_residual_is_used(uid_t uid, const char *ccname,
+
+ ret = lstat(ccname, &stat_buf);
+
+- if (ret == -1 && errno != ENOENT) {
++ if (ret == -1) {
+ ret = errno;
++ if (ret == ENOENT) {
++ DEBUG(SSSDBG_FUNC_DATA, ("Cache file [%s] does not exists, "
++ "it will be recreated\n", ccname));
++ *result = false;
++ return EOK;
++ }
++
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("stat failed [%d][%s].\n", ret, strerror(ret)));
+ return ret;
+--
+1.7.11.7
+
diff --git a/0002-subdomains-replace-invalid-characters-with-underscor.patch b/0002-subdomains-replace-invalid-characters-with-underscor.patch
new file mode 100644
index 0000000..c2564cc
--- /dev/null
+++ b/0002-subdomains-replace-invalid-characters-with-underscor.patch
@@ -0,0 +1,69 @@
+From a0388dc52f5461f72f8221c9bb7c92008e1fe2c5 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina at redhat.com>
+Date: Fri, 1 Feb 2013 12:17:47 +0100
+Subject: [PATCH] subdomains: replace invalid characters with underscore in
+ krb5 mapping file name
+
+https://fedorahosted.org/sssd/ticket/1795
+
+Only alpha-numeric chars, dashes and underscores are allowed in
+krb5 include directory.
+---
+ src/providers/ipa/ipa_subdomains.c | 26 +++++++++++++++++++++++++-
+ 1 file changed, 25 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index ef6195d19de72be7fd2b12a309b33fcf20e0e3a1..f959c4e6eb1d830e3990f552c9f4cf962298ef48 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -287,22 +287,46 @@ ipa_subdomains_write_mappings(struct sss_domain_info *domain,
+ errno_t err;
+ TALLOC_CTX *tmp_ctx;
+ const char *mapping_file;
++ char *sanitized_domain;
+ char *tmp_file = NULL;
+ int fd = -1;
+ mode_t old_mode;
+ FILE *fstream = NULL;
+ size_t i;
+
++ if (domain == NULL || domain->name == NULL) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("No domain name provided\n"));
++ return EINVAL;
++ }
++
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) return ENOMEM;
+
++ sanitized_domain = talloc_strdup(tmp_ctx, domain->name);
++ if (sanitized_domain == NULL) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strdup() failed\n"));
++ return ENOMEM;
++ }
++
++ /* only alpha-numeric chars, dashes and underscores are allowed in
++ * krb5 include directory */
++ for (i = 0; sanitized_domain[i] != '\0'; i++) {
++ if (!isalnum(sanitized_domain[i])
++ && sanitized_domain[i] != '-' && sanitized_domain[i] != '_') {
++ sanitized_domain[i] = '_';
++ }
++ }
++
+ mapping_file = talloc_asprintf(tmp_ctx, "%s/domain_realm_%s",
+- IPA_SUBDOMAIN_MAPPING_DIR, domain->name);
++ IPA_SUBDOMAIN_MAPPING_DIR, sanitized_domain);
+ if (!mapping_file) {
+ ret = ENOMEM;
+ goto done;
+ }
+
++ DEBUG(SSSDBG_FUNC_DATA, ("Mapping file for domain [%s] is [%s]\n",
++ domain->name, mapping_file));
++
+ tmp_file = talloc_asprintf(tmp_ctx, "%sXXXXXX", mapping_file);
+ if (tmp_file == NULL) {
+ ret = ENOMEM;
+--
+1.7.11.7
+
diff --git a/0003-Fix-the-krb5-password-expiration-warning.patch b/0003-Fix-the-krb5-password-expiration-warning.patch
new file mode 100644
index 0000000..3996494
--- /dev/null
+++ b/0003-Fix-the-krb5-password-expiration-warning.patch
@@ -0,0 +1,39 @@
+From e354a96bbca5da8525ee51f91907e75af897b856 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek at redhat.com>
+Date: Thu, 14 Feb 2013 10:13:59 +0100
+Subject: [PATCH] Fix the krb5 password expiration warning
+
+https://fedorahosted.org/sssd/ticket/1808
+---
+ src/confdb/confdb.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
+index 31efd9443be8490715961c8a45f9352bd1ade653..31c48bd28aee37008687e7e255ebf2ef2d79798a 100644
+--- a/src/confdb/confdb.c
++++ b/src/confdb/confdb.c
+@@ -1020,7 +1020,11 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
+ goto done;
+ }
+
+- /* Set the PAM warning time, if specified */
++ /* Set the PAM warning time, if specified. If not specified, pass on
++ * the "not set" value of "-1" which means "use provider default". The
++ * value 0 means "always display the warning if server sends one" */
++ domain->pwd_expiration_warning = -1;
++
+ val = ldb_msg_find_attr_as_int(res->msgs[0],
+ CONFDB_DOMAIN_PWD_EXPIRATION_WARNING,
+ -1);
+@@ -1035,6 +1039,8 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
+ }
+
+ if (val > 0) {
++ DEBUG(SSSDBG_CONF_SETTINGS,
++ ("Setting domain password expiration warning to %d days\n", val));
+ /* The value is in days, transform it to seconds */
+ domain->pwd_expiration_warning = val * 24 * 3600;
+ }
+--
+1.8.1.2
+
diff --git a/0004-Add-unit-tests-for-simple-access-test-by-groups.patch b/0004-Add-unit-tests-for-simple-access-test-by-groups.patch
new file mode 100644
index 0000000..a219fb0
--- /dev/null
+++ b/0004-Add-unit-tests-for-simple-access-test-by-groups.patch
@@ -0,0 +1,412 @@
+From 754b09b5444e6da88ed58d6deaed8b815e268b6b Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek at redhat.com>
+Date: Sun, 3 Mar 2013 21:43:44 +0100
+Subject: [PATCH 2/4] Add unit tests for simple access test by groups
+
+I realized that the current unit tests for the simple access provider
+only tested the user directives. To have a baseline and be able to
+detect new bugs in the upcoming patch, I implemented unit tests for the
+group lists, too.
+---
+ src/tests/simple_access-tests.c | 283 +++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 252 insertions(+), 31 deletions(-)
+
+diff --git a/src/tests/simple_access-tests.c b/src/tests/simple_access-tests.c
+index c61814eb54c1aa5138a1b45653f9384228c5456a..577c6d334edda513fd0f1e42a859ea333ba5ba23 100644
+--- a/src/tests/simple_access-tests.c
++++ b/src/tests/simple_access-tests.c
+@@ -30,39 +30,152 @@
+ #include "providers/simple/simple_access.h"
+ #include "tests/common.h"
+
++#define TESTS_PATH "tests_simple_access"
++#define TEST_CONF_FILE "tests_conf.ldb"
++
+ const char *ulist_1[] = {"u1", "u2", NULL};
++const char *glist_1[] = {"g1", "g2", NULL};
+
+-struct simple_ctx *ctx = NULL;
++struct simple_test_ctx *test_ctx = NULL;
++
++struct simple_test_ctx {
++ struct sysdb_ctx *sysdb;
++ struct confdb_ctx *confdb;
++
++ struct simple_ctx *ctx;
++};
+
+ void setup_simple(void)
+ {
+- fail_unless(ctx == NULL, "Simple context already initialized.");
+- ctx = talloc_zero(NULL, struct simple_ctx);
+- fail_unless(ctx != NULL, "Cannot create simple context.");
++ errno_t ret;
++ char *conf_db;
++ const char *val[2];
++ val[1] = NULL;
+
+- ctx->domain = talloc_zero(ctx, struct sss_domain_info);
+- fail_unless(ctx != NULL, "Cannot create domain in simple context.");
+- ctx->domain->case_sensitive = true;
++ /* Create tests directory if it doesn't exist */
++ /* (relative to current dir) */
++ ret = mkdir(TESTS_PATH, 0775);
++ fail_if(ret == -1 && errno != EEXIST,
++ "Could not create %s directory", TESTS_PATH);
++
++ fail_unless(test_ctx == NULL, "Simple context already initialized.");
++ test_ctx = talloc_zero(NULL, struct simple_test_ctx);
++ fail_unless(test_ctx != NULL, "Cannot create simple test context.");
++
++ test_ctx->ctx = talloc_zero(test_ctx, struct simple_ctx);
++ fail_unless(test_ctx->ctx != NULL, "Cannot create simple context.");
++
++ conf_db = talloc_asprintf(test_ctx, "%s/%s", TESTS_PATH, TEST_CONF_FILE);
++ fail_if(conf_db == NULL, "Out of memory, aborting!");
++ DEBUG(SSSDBG_TRACE_LIBS, ("CONFDB: %s\n", conf_db));
++
++ /* Connect to the conf db */
++ ret = confdb_init(test_ctx, &test_ctx->confdb, conf_db);
++ fail_if(ret != EOK, "Could not initialize connection to the confdb");
++
++ val[0] = "LOCAL";
++ ret = confdb_add_param(test_ctx->confdb, true,
++ "config/sssd", "domains", val);
++ fail_if(ret != EOK, "Could not initialize domains placeholder");
++
++ val[0] = "local";
++ ret = confdb_add_param(test_ctx->confdb, true,
++ "config/domain/LOCAL", "id_provider", val);
++ fail_if(ret != EOK, "Could not initialize provider");
++
++ val[0] = "TRUE";
++ ret = confdb_add_param(test_ctx->confdb, true,
++ "config/domain/LOCAL", "enumerate", val);
++ fail_if(ret != EOK, "Could not initialize LOCAL domain");
++
++ val[0] = "TRUE";
++ ret = confdb_add_param(test_ctx->confdb, true,
++ "config/domain/LOCAL", "cache_credentials", val);
++ fail_if(ret != EOK, "Could not initialize LOCAL domain");
++
++ ret = sysdb_init_domain_and_sysdb(test_ctx, test_ctx->confdb, "local",
++ TESTS_PATH,
++ &test_ctx->ctx->domain, &test_ctx->ctx->sysdb);
++ fail_if(ret != EOK, "Could not initialize connection to the sysdb (%d)", ret);
++ test_ctx->ctx->domain->case_sensitive = true;
+ }
+
+ void teardown_simple(void)
+ {
+ int ret;
+- fail_unless(ctx != NULL, "Simple context already freed.");
+- ret = talloc_free(ctx);
+- ctx = NULL;
++ fail_unless(test_ctx != NULL, "Simple context already freed.");
++ ret = talloc_free(test_ctx);
++ test_ctx = NULL;
+ fail_unless(ret == 0, "Connot free simple context.");
+ }
+
++void setup_simple_group(void)
++{
++ errno_t ret;
++
++ setup_simple();
++
++ /* Add test users u1 and u2 that would be members of test groups
++ * g1 and g2 respectively */
++ ret = sysdb_store_user(test_ctx->ctx->sysdb,
++ "u1", NULL, 123, 0, "u1", "/home/u1",
++ "/bin/bash", NULL, NULL, NULL, -1, 0);
++ fail_if(ret != EOK, "Could not add u1");
++
++ ret = sysdb_store_user(test_ctx->ctx->sysdb,
++ "u2", NULL, 456, 0, "u1", "/home/u1",
++ "/bin/bash", NULL, NULL, NULL, -1, 0);
++ fail_if(ret != EOK, "Could not add u2");
++
++ ret = sysdb_store_user(test_ctx->ctx->sysdb,
++ "u3", NULL, 789, 0, "u1", "/home/u1",
++ "/bin/bash", NULL, NULL, NULL, -1, 0);
++ fail_if(ret != EOK, "Could not add u3");
++
++ ret = sysdb_add_group(test_ctx->ctx->sysdb,
++ "g1", 321, NULL, 0, 0);
++ fail_if(ret != EOK, "Could not add g1");
++
++ ret = sysdb_add_group(test_ctx->ctx->sysdb,
++ "g2", 654, NULL, 0, 0);
++ fail_if(ret != EOK, "Could not add g2");
++
++ ret = sysdb_add_group_member(test_ctx->ctx->sysdb,
++ "g1", "u1", SYSDB_MEMBER_USER);
++ fail_if(ret != EOK, "Could not add u1 to g1");
++
++ ret = sysdb_add_group_member(test_ctx->ctx->sysdb,
++ "g2", "u2", SYSDB_MEMBER_USER);
++ fail_if(ret != EOK, "Could not add u2 to g2");
++}
++
++void teardown_simple_group(void)
++{
++ errno_t ret;
++
++ ret = sysdb_delete_user(test_ctx->ctx->sysdb, "u1", 0);
++ fail_if(ret != EOK, "Could not delete u1");
++ ret = sysdb_delete_user(test_ctx->ctx->sysdb, "u2", 0);
++ fail_if(ret != EOK, "Could not delete u2");
++ ret = sysdb_delete_user(test_ctx->ctx->sysdb, "u3", 0);
++ fail_if(ret != EOK, "Could not delete u3");
++ ret = sysdb_delete_group(test_ctx->ctx->sysdb, "g1", 0);
++ fail_if(ret != EOK, "Could not delete g1");
++ ret = sysdb_delete_group(test_ctx->ctx->sysdb, "g2", 0);
++ fail_if(ret != EOK, "Could not delete g2");
++
++ teardown_simple();
++}
++
+ START_TEST(test_both_empty)
+ {
+ int ret;
+ bool access_granted = false;
+
+- ctx->allow_users = NULL;
+- ctx->deny_users = NULL;
++ test_ctx->ctx->allow_users = NULL;
++ test_ctx->ctx->deny_users = NULL;
+
+- ret = simple_access_check(ctx, "u1", &access_granted);
++ ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+ fail_unless(ret == EOK, "access_simple_check failed.");
+ fail_unless(access_granted == true, "Access denied "
+ "while both lists are empty.");
+@@ -74,15 +187,15 @@ START_TEST(test_allow_empty)
+ int ret;
+ bool access_granted = true;
+
+- ctx->allow_users = NULL;
+- ctx->deny_users = discard_const(ulist_1);
++ test_ctx->ctx->allow_users = NULL;
++ test_ctx->ctx->deny_users = discard_const(ulist_1);
+
+- ret = simple_access_check(ctx, "u1", &access_granted);
++ ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+ fail_unless(ret == EOK, "access_simple_check failed.");
+ fail_unless(access_granted == false, "Access granted "
+ "while user is in deny list.");
+
+- ret = simple_access_check(ctx, "u3", &access_granted);
++ ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
+ fail_unless(ret == EOK, "access_simple_check failed.");
+ fail_unless(access_granted == true, "Access denied "
+ "while user is not in deny list.");
+@@ -94,15 +207,15 @@ START_TEST(test_deny_empty)
+ int ret;
+ bool access_granted = false;
+
+- ctx->allow_users = discard_const(ulist_1);
+- ctx->deny_users = NULL;
++ test_ctx->ctx->allow_users = discard_const(ulist_1);
++ test_ctx->ctx->deny_users = NULL;
+
+- ret = simple_access_check(ctx, "u1", &access_granted);
++ ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+ fail_unless(ret == EOK, "access_simple_check failed.");
+ fail_unless(access_granted == true, "Access denied "
+ "while user is in allow list.");
+
+- ret = simple_access_check(ctx, "u3", &access_granted);
++ ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
+ fail_unless(ret == EOK, "access_simple_check failed.");
+ fail_unless(access_granted == false, "Access granted "
+ "while user is not in allow list.");
+@@ -114,15 +227,15 @@ START_TEST(test_both_set)
+ int ret;
+ bool access_granted = false;
+
+- ctx->allow_users = discard_const(ulist_1);
+- ctx->deny_users = discard_const(ulist_1);
++ test_ctx->ctx->allow_users = discard_const(ulist_1);
++ test_ctx->ctx->deny_users = discard_const(ulist_1);
+
+- ret = simple_access_check(ctx, "u1", &access_granted);
++ ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+ fail_unless(ret == EOK, "access_simple_check failed.");
+ fail_unless(access_granted == false, "Access granted "
+ "while user is in deny list.");
+
+- ret = simple_access_check(ctx, "u3", &access_granted);
++ ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
+ fail_unless(ret == EOK, "access_simple_check failed.");
+ fail_unless(access_granted == false, "Access granted "
+ "while user is not in allow list.");
+@@ -134,18 +247,18 @@ START_TEST(test_case)
+ int ret;
+ bool access_granted = false;
+
+- ctx->allow_users = discard_const(ulist_1);
+- ctx->deny_users = NULL;
++ test_ctx->ctx->allow_users = discard_const(ulist_1);
++ test_ctx->ctx->deny_users = NULL;
+
+- ret = simple_access_check(ctx, "U1", &access_granted);
++ ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
+ fail_unless(ret == EOK, "access_simple_check failed.");
+ fail_unless(access_granted == false, "Access granted "
+ "for user with different case "
+ "in case-sensitive domain");
+
+- ctx->domain->case_sensitive = false;
++ test_ctx->ctx->domain->case_sensitive = false;
+
+- ret = simple_access_check(ctx, "U1", &access_granted);
++ ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
+ fail_unless(ret == EOK, "access_simple_check failed.");
+ fail_unless(access_granted == true, "Access denied "
+ "for user with different case "
+@@ -153,11 +266,95 @@ START_TEST(test_case)
+ }
+ END_TEST
+
++START_TEST(test_group_allow_empty)
++{
++ int ret;
++ bool access_granted = true;
++
++ test_ctx->ctx->allow_groups = NULL;
++ test_ctx->ctx->deny_groups = discard_const(glist_1);
++
++ ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
++ fail_unless(ret == EOK, "access_simple_check failed.");
++ fail_unless(access_granted == false, "Access granted "
++ "while group is in deny list.");
++
++ ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
++ fail_unless(ret == EOK, "access_simple_check failed.");
++ fail_unless(access_granted == true, "Access denied "
++ "while group is not in deny list.");
++}
++END_TEST
++
++START_TEST(test_group_deny_empty)
++{
++ int ret;
++ bool access_granted = false;
++
++ test_ctx->ctx->allow_groups = discard_const(glist_1);
++ test_ctx->ctx->deny_groups = NULL;
++
++ ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
++ fail_unless(ret == EOK, "access_simple_check failed.");
++ fail_unless(access_granted == true, "Access denied "
++ "while group is in allow list.");
++
++ ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
++ fail_unless(ret == EOK, "access_simple_check failed.");
++ fail_unless(access_granted == false, "Access granted "
++ "while group is not in allow list.");
++}
++END_TEST
++
++START_TEST(test_group_both_set)
++{
++ int ret;
++ bool access_granted = false;
++
++ test_ctx->ctx->allow_groups = discard_const(ulist_1);
++ test_ctx->ctx->deny_groups = discard_const(ulist_1);
++
++ ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
++ fail_unless(ret == EOK, "access_simple_check failed.");
++ fail_unless(access_granted == false, "Access granted "
++ "while group is in deny list.");
++
++ ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
++ fail_unless(ret == EOK, "access_simple_check failed.");
++ fail_unless(access_granted == false, "Access granted "
++ "while group is not in allow list.");
++}
++END_TEST
++
++START_TEST(test_group_case)
++{
++ int ret;
++ bool access_granted = false;
++
++ test_ctx->ctx->allow_groups = discard_const(ulist_1);
++ test_ctx->ctx->deny_groups = NULL;
++
++ ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
++ fail_unless(ret == EOK, "access_simple_check failed.");
++ fail_unless(access_granted == false, "Access granted "
++ "for group with different case "
++ "in case-sensitive domain");
++
++ test_ctx->ctx->domain->case_sensitive = false;
++
++ ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
++ fail_unless(ret == EOK, "access_simple_check failed.");
++ fail_unless(access_granted == true, "Access denied "
++ "for group with different case "
++ "in case-insensitive domain");
++}
++END_TEST
++
+ Suite *access_simple_suite (void)
+ {
+ Suite *s = suite_create("access_simple");
+
+- TCase *tc_allow_deny = tcase_create("allow/deny");
++ TCase *tc_allow_deny = tcase_create("user allow/deny");
+ tcase_add_checked_fixture(tc_allow_deny, setup_simple, teardown_simple);
+ tcase_add_test(tc_allow_deny, test_both_empty);
+ tcase_add_test(tc_allow_deny, test_allow_empty);
+@@ -166,6 +363,15 @@ Suite *access_simple_suite (void)
+ tcase_add_test(tc_allow_deny, test_case);
+ suite_add_tcase(s, tc_allow_deny);
+
++ TCase *tc_grp_allow_deny = tcase_create("group allow/deny");
++ tcase_add_checked_fixture(tc_grp_allow_deny,
++ setup_simple_group, teardown_simple_group);
++ tcase_add_test(tc_grp_allow_deny, test_group_allow_empty);
++ tcase_add_test(tc_grp_allow_deny, test_group_deny_empty);
++ tcase_add_test(tc_grp_allow_deny, test_group_both_set);
++ tcase_add_test(tc_grp_allow_deny, test_group_case);
++ suite_add_tcase(s, tc_grp_allow_deny);
++
+ return s;
+ }
+
+@@ -174,6 +380,7 @@ int main(int argc, const char *argv[])
+ int opt;
+ poptContext pc;
+ int number_failed;
++ int ret;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+@@ -205,6 +412,20 @@ int main(int argc, const char *argv[])
+ srunner_run_all(sr, CK_ENV);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
++
++ ret = unlink(TESTS_PATH"/"TEST_CONF_FILE);
++ if (ret != EOK) {
++ fprintf(stderr, "Could not delete the test config ldb file (%d) (%s)\n",
++ errno, strerror(errno));
++ return EXIT_FAILURE;
++ }
++ ret = unlink(TESTS_PATH"/"LOCAL_SYSDB_FILE);
++ if (ret != EOK) {
++ fprintf(stderr, "Could not delete the test config ldb file (%d) (%s)\n",
++ errno, strerror(errno));
++ return EXIT_FAILURE;
++ }
++
+ return (number_failed==0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ }
+
+--
+1.8.1.4
+
diff --git a/0005-Do-not-compile-main-in-DP-if-UNIT_TESTING-is-defined.patch b/0005-Do-not-compile-main-in-DP-if-UNIT_TESTING-is-defined.patch
new file mode 100644
index 0000000..73d5b84
--- /dev/null
+++ b/0005-Do-not-compile-main-in-DP-if-UNIT_TESTING-is-defined.patch
@@ -0,0 +1,40 @@
+From 26590d31f492dbbd36be6d0bde46a4bd3b221edb Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek at redhat.com>
+Date: Mon, 4 Mar 2013 16:37:04 +0100
+Subject: [PATCH 3/4] Do not compile main() in DP if UNIT_TESTING is defined
+
+The simple access provider unit tests now need to link against the Data
+Provider when they start using the be_file_account_request() function.
+But then we would start having conflicts as at least the main()
+functions would clash.
+
+If UNIT_TESTING is defined, then the data_provider_be.c module does not
+contain the main() function and can be linked against directly from
+another module that contains its own main() function
+---
+ src/providers/data_provider_be.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index f85a04d09b5b41b17be611c333324f7207242979..33590aeef0231427642916c6a2f9bc391c165c21 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -2651,6 +2651,7 @@ fail:
+ return ret;
+ }
+
++#ifndef UNIT_TESTING
+ int main(int argc, const char *argv[])
+ {
+ int opt;
+@@ -2732,6 +2733,7 @@ int main(int argc, const char *argv[])
+
+ return 0;
+ }
++#endif
+
+ static int data_provider_res_init(DBusMessage *message,
+ struct sbus_connection *conn)
+--
+1.8.1.4
+
diff --git a/0006-Provide-a-be_get_account_info_send-function.patch b/0006-Provide-a-be_get_account_info_send-function.patch
new file mode 100644
index 0000000..766e21c
--- /dev/null
+++ b/0006-Provide-a-be_get_account_info_send-function.patch
@@ -0,0 +1,236 @@
+From b63830b142053f99bfe954d4be5a2b0f68ce3a93 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek at redhat.com>
+Date: Fri, 22 Feb 2013 11:01:38 +0100
+Subject: [PATCH 1/4] Provide a be_get_account_info_send function
+
+In order to resolve group names in the simple access provider we need to
+contact the Data Provider in a generic fashion from the access provider.
+We can't call any particular implementation (like sdap_generic_send())
+because we have no idea what kind of provider is configured as the
+id_provider.
+
+This patch splits introduces the be_file_account_request() function into
+the data_provider_be module and makes it public.
+
+A future patch should make the be_get_account_info function use the
+be_get_account_info_send function.
+---
+ src/providers/data_provider_be.c | 153 ++++++++++++++++++++++++++++++++++-----
+ src/providers/dp_backend.h | 15 ++++
+ 2 files changed, 149 insertions(+), 19 deletions(-)
+
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index b261bf8d456829a513ec352c8290d2011bd3526a..f85a04d09b5b41b17be611c333324f7207242979 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -717,6 +717,34 @@ static errno_t be_initgroups_prereq(struct be_req *be_req)
+ }
+
+ static errno_t
++be_file_account_request(struct be_req *be_req, struct be_acct_req *ar)
++{
++ errno_t ret;
++ struct be_ctx *be_ctx = be_req->be_ctx;
++
++ be_req->req_data = ar;
++
++ /* see if we need a pre request call, only done for initgroups for now */
++ if ((ar->entry_type & 0xFF) == BE_REQ_INITGROUPS) {
++ ret = be_initgroups_prereq(be_req);
++ if (ret) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("Prerequest failed"));
++ return ret;
++ }
++ }
++
++ /* process request */
++ ret = be_file_request(be_ctx, be_req,
++ be_ctx->bet_info[BET_ID].bet_ops->handler);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to file request"));
++ return ret;
++ }
++
++ return EOK;
++}
++
++static errno_t
+ split_name_extended(TALLOC_CTX *mem_ctx,
+ const char *filter,
+ char **name,
+@@ -742,6 +770,110 @@ split_name_extended(TALLOC_CTX *mem_ctx,
+ return EOK;
+ }
+
++static void
++be_get_account_info_done(struct be_req *be_req,
++ int dp_err, int dp_ret,
++ const char *errstr);
++
++struct be_get_account_info_state {
++ int err_maj;
++ int err_min;
++ const char *err_msg;
++};
++
++struct tevent_req *
++be_get_account_info_send(TALLOC_CTX *mem_ctx,
++ struct tevent_context *ev,
++ struct be_client *becli,
++ struct be_ctx *be_ctx,
++ struct be_acct_req *ar)
++{
++ struct tevent_req *req;
++ struct be_get_account_info_state *state;
++ struct be_req *be_req;
++ errno_t ret;
++
++ req = tevent_req_create(mem_ctx, &state,
++ struct be_get_account_info_state);
++ if (!req) return NULL;
++
++ be_req = talloc_zero(mem_ctx, struct be_req);
++ if (be_req == NULL) {
++ ret = ENOMEM;
++ goto done;
++ }
++
++ be_req->becli = becli;
++ be_req->be_ctx = be_ctx;
++ be_req->fn = be_get_account_info_done;
++ be_req->pvt = req;
++
++ ret = be_file_account_request(be_req, ar);
++ if (ret != EOK) {
++ goto done;
++ }
++
++ return req;
++
++done:
++ tevent_req_error(req, ret);
++ tevent_req_post(req, ev);
++ return req;
++}
++
++static void
++be_get_account_info_done(struct be_req *be_req,
++ int dp_err, int dp_ret,
++ const char *errstr)
++{
++ struct tevent_req *req;
++ struct be_get_account_info_state *state;
++
++ req = talloc_get_type(be_req->pvt, struct tevent_req);
++ state = tevent_req_data(req, struct be_get_account_info_state);
++
++ state->err_maj = dp_err;
++ state->err_min = dp_ret;
++ if (errstr) {
++ state->err_msg = talloc_strdup(state, errstr);
++ if (state->err_msg == NULL) {
++ talloc_free(be_req);
++ tevent_req_error(req, ENOMEM);
++ return;
++ }
++ }
++
++ talloc_free(be_req);
++ tevent_req_done(req);
++}
++
++errno_t be_get_account_info_recv(struct tevent_req *req,
++ TALLOC_CTX *mem_ctx,
++ int *_err_maj,
++ int *_err_min,
++ const char **_err_msg)
++{
++ struct be_get_account_info_state *state;
++
++ state = tevent_req_data(req, struct be_get_account_info_state);
++
++ TEVENT_REQ_RETURN_ON_ERROR(req);
++
++ if (_err_maj) {
++ *_err_maj = state->err_maj;
++ }
++
++ if (_err_min) {
++ *_err_min = state->err_min;
++ }
++
++ if (_err_msg) {
++ *_err_msg = talloc_steal(mem_ctx, state->err_msg);
++ }
++
++ return EOK;
++}
++
+ static int be_get_account_info(DBusMessage *message, struct sbus_connection *conn)
+ {
+ struct be_acct_req *req;
+@@ -845,8 +977,6 @@ static int be_get_account_info(DBusMessage *message, struct sbus_connection *con
+ goto done;
+ }
+
+- be_req->req_data = req;
+-
+ if ((attr_type != BE_ATTR_CORE) &&
+ (attr_type != BE_ATTR_MEM) &&
+ (attr_type != BE_ATTR_ALL)) {
+@@ -893,26 +1023,11 @@ static int be_get_account_info(DBusMessage *message, struct sbus_connection *con
+ goto done;
+ }
+
+- /* see if we need a pre request call, only done for initgroups for now */
+- if ((type & 0xFF) == BE_REQ_INITGROUPS) {
+- ret = be_initgroups_prereq(be_req);
+- if (ret) {
+- err_maj = DP_ERR_FATAL;
+- err_min = ret;
+- err_msg = "Prerequest failed";
+- goto done;
+- }
+- }
+-
+- /* process request */
+-
+- ret = be_file_request(becli->bectx->bet_info[BET_ID].pvt_bet_data,
+- be_req,
+- becli->bectx->bet_info[BET_ID].bet_ops->handler);
++ ret = be_file_account_request(be_req, req);
+ if (ret != EOK) {
+ err_maj = DP_ERR_FATAL;
+ err_min = ret;
+- err_msg = "Failed to file request";
++ err_msg = "Cannot file account request";
+ goto done;
+ }
+
+diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
+index 58a9b7490df8aab06a2a15f8c0fed9ac5ed33600..743b6f4ffe73fe9ec7404218184a7133aba054c6 100644
+--- a/src/providers/dp_backend.h
++++ b/src/providers/dp_backend.h
+@@ -258,4 +258,19 @@ int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx,
+ const char *service_name);
+
+ void reset_fo(struct be_ctx *be_ctx);
++
++/* Request account information */
++struct tevent_req *
++be_get_account_info_send(TALLOC_CTX *mem_ctx,
++ struct tevent_context *ev,
++ struct be_client *becli,
++ struct be_ctx *be_ctx,
++ struct be_acct_req *ar);
++
++errno_t be_get_account_info_recv(struct tevent_req *req,
++ TALLOC_CTX *mem_ctx,
++ int *_err_maj,
++ int *_err_min,
++ const char **_err_msg);
++
+ #endif /* __DP_BACKEND_H___ */
+--
+1.8.1.4
+
diff --git a/0007-Resolve-GIDs-in-the-simple-access-provider.patch b/0007-Resolve-GIDs-in-the-simple-access-provider.patch
new file mode 100644
index 0000000..c06f900
--- /dev/null
+++ b/0007-Resolve-GIDs-in-the-simple-access-provider.patch
@@ -0,0 +1,1622 @@
+From 8b8019fe3dd1564fba657e219ec20ff816c7ffdb Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek at redhat.com>
+Date: Sat, 23 Feb 2013 10:44:54 +0100
+Subject: [PATCH 4/4] Resolve GIDs in the simple access provider
+
+Changes the simple access provider's interface to be asynchronous. When
+the simple access provider encounters a group that has gid, but no
+meaningful name, it attempts to resolve the name using the
+be_file_account_request function.
+
+Some providers (like the AD provider) might perform initgroups
+without resolving the group names. In order for the simple access
+provider to work correctly, we need to resolve the groups before
+performing the access check. In AD provider, the situation is
+even more tricky b/c the groups HAVE name, but their name
+attribute is set to SID and they are set as non-POSIX
+---
+ Makefile.am | 17 +-
+ src/providers/simple/simple_access.c | 230 ++-------
+ src/providers/simple/simple_access.h | 11 +-
+ src/providers/simple/simple_access_check.c | 723 +++++++++++++++++++++++++++++
+ src/tests/simple_access-tests.c | 373 ++++++++++-----
+ 5 files changed, 1040 insertions(+), 314 deletions(-)
+ create mode 100644 src/providers/simple/simple_access_check.c
+
+diff --git a/Makefile.am b/Makefile.am
+index dc0465a8cb6b441cfc810a5da8c448b034cc4b7a..eea535e81ac572713810f8b97dacc58ed221b440 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1008,14 +1008,22 @@ ad_ldap_opt_tests_LDADD = \
+ simple_access_tests_SOURCES = \
+ src/tests/simple_access-tests.c \
+ src/tests/common.c \
+- src/providers/simple/simple_access.c
++ src/providers/simple/simple_access_check.c \
++ src/providers/data_provider_be.c \
++ src/providers/data_provider_fo.c \
++ src/providers/data_provider_callbacks.c \
++ $(SSSD_FAILOVER_OBJ)
+ simple_access_tests_CFLAGS = \
+ $(AM_CFLAGS) \
+- $(CHECK_CFLAGS)
++ $(CHECK_CFLAGS) \
++ -DUNIT_TESTING
+ simple_access_tests_LDADD = \
+ $(SSSD_LIBS) \
++ $(CARES_LIBS) \
+ $(CHECK_LIBS) \
+- libsss_util.la
++ $(PAM_LIBS) \
++ libsss_util.la \
++ libsss_test_common.la
+
+ util_tests_SOURCES = \
+ src/tests/util-tests.c
+@@ -1347,7 +1355,8 @@ libsss_proxy_la_LDFLAGS = \
+ -module
+
+ libsss_simple_la_SOURCES = \
+- src/providers/simple/simple_access.c
++ src/providers/simple/simple_access.c \
++ src/providers/simple/simple_access_check.c
+ libsss_simple_la_CFLAGS = \
+ $(AM_CFLAGS)
+ libsss_simple_la_LIBADD = \
+diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c
+index 70d1f07282d472089a2c6eac05479c39eb03c606..d53a04b4d73bfa4fae23b4522d01cf1e947e7d64 100644
+--- a/src/providers/simple/simple_access.c
++++ b/src/providers/simple/simple_access.c
+@@ -35,211 +35,13 @@
+ #define CONFDB_SIMPLE_ALLOW_GROUPS "simple_allow_groups"
+ #define CONFDB_SIMPLE_DENY_GROUPS "simple_deny_groups"
+
+-errno_t simple_access_check(struct simple_ctx *ctx, const char *username,
+- bool *access_granted)
+-{
+- int i, j;
+- errno_t ret;
+- TALLOC_CTX *tmp_ctx = NULL;
+- const char *user_attrs[] = { SYSDB_MEMBEROF,
+- SYSDB_GIDNUM,
+- NULL };
+- const char *group_attrs[] = { SYSDB_NAME,
+- NULL };
+- struct ldb_message *msg;
+- struct ldb_message_element *el;
+- char **groups;
+- const char *primary_group;
+- gid_t gid;
+- bool matched;
+- bool cs = ctx->domain->case_sensitive;
+-
+- *access_granted = false;
+-
+- /* First, check whether the user is in the allowed users list */
+- if (ctx->allow_users != NULL) {
+- for(i = 0; ctx->allow_users[i] != NULL; i++) {
+- if (sss_string_equal(cs, username, ctx->allow_users[i])) {
+- DEBUG(9, ("User [%s] found in allow list, access granted.\n",
+- username));
+-
+- /* Do not return immediately on explicit allow
+- * We need to make sure none of the user's groups
+- * are denied.
+- */
+- *access_granted = true;
+- }
+- }
+- } else if (!ctx->allow_groups) {
+- /* If neither allow rule is in place, we'll assume allowed
+- * unless a deny rule disables us below.
+- */
+- *access_granted = true;
+- }
+-
+- /* Next check whether this user has been specifically denied */
+- if (ctx->deny_users != NULL) {
+- for(i = 0; ctx->deny_users[i] != NULL; i++) {
+- if (sss_string_equal(cs, username, ctx->deny_users[i])) {
+- DEBUG(9, ("User [%s] found in deny list, access denied.\n",
+- username));
+-
+- /* Return immediately on explicit denial */
+- *access_granted = false;
+- return EOK;
+- }
+- }
+- }
+-
+- if (!ctx->allow_groups && !ctx->deny_groups) {
+- /* There are no group restrictions, so just return
+- * here with whatever we've decided.
+- */
+- return EOK;
+- }
+-
+- /* Now get a list of this user's groups and check those against the
+- * simple_allow_groups list.
+- */
+- tmp_ctx = talloc_new(NULL);
+- if (!tmp_ctx) {
+- ret = ENOMEM;
+- goto done;
+- }
+-
+- ret = sysdb_search_user_by_name(tmp_ctx, ctx->sysdb,
+- username, user_attrs, &msg);
+- if (ret != EOK) {
+- DEBUG(1, ("Could not look up username [%s]: [%d][%s]\n",
+- username, ret, strerror(ret)));
+- goto done;
+- }
+-
+- /* Construct a list of the user's groups */
+- el = ldb_msg_find_element(msg, SYSDB_MEMBEROF);
+- if (el && el->num_values) {
+- /* Get the groups from the memberOf entries
+- * Allocate the array with room for both the NULL
+- * terminator and the primary group
+- */
+- groups = talloc_array(tmp_ctx, char *, el->num_values + 2);
+- if (!groups) {
+- ret = ENOMEM;
+- goto done;
+- }
+-
+- for (j = 0; j < el->num_values; j++) {
+- ret = sysdb_group_dn_name(
+- ctx->sysdb, tmp_ctx,
+- (char *)el->values[j].data,
+- &groups[j]);
+- if (ret != EOK) {
+- goto done;
+- }
+- }
+- } else {
+- /* User is not a member of any groups except primary */
+- groups = talloc_array(tmp_ctx, char *, 2);
+- if (!groups) {
+- ret = ENOMEM;
+- goto done;
+- }
+- j = 0;
+- }
+-
+- /* Get the user's primary group */
+- gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
+- if (!gid) {
+- ret = EINVAL;
+- goto done;
+- }
+- talloc_zfree(msg);
+-
+- ret = sysdb_search_group_by_gid(tmp_ctx, ctx->sysdb,
+- gid, group_attrs, &msg);
+- if (ret != EOK) {
+- DEBUG(1, ("Could not look up primary group [%lu]: [%d][%s]\n",
+- gid, ret, strerror(ret)));
+- /* We have to treat this as non-fatal, because the primary
+- * group may be local to the machine and not available in
+- * our ID provider.
+- */
+- } else {
+- primary_group = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
+- if (!primary_group) {
+- ret = EINVAL;
+- goto done;
+- }
+-
+- groups[j] = talloc_strdup(tmp_ctx, primary_group);
+- if (!groups[j]) {
+- ret = ENOMEM;
+- goto done;
+- }
+- j++;
+-
+- talloc_zfree(msg);
+- }
+-
+- groups[j] = NULL;
+-
+- /* Now process allow and deny group rules
+- * If access was already granted above, we'll skip
+- * this redundant rule check
+- */
+- if (ctx->allow_groups && !*access_granted) {
+- matched = false;
+- for (i = 0; ctx->allow_groups[i]; i++) {
+- for(j = 0; groups[j]; j++) {
+- if (sss_string_equal(cs, groups[j], ctx->allow_groups[i])) {
+- matched = true;
+- break;
+- }
+- }
+-
+- /* If any group has matched, we can skip out on the
+- * processing early
+- */
+- if (matched) {
+- *access_granted = true;
+- break;
+- }
+- }
+- }
+-
+- /* Finally, process the deny group rules */
+- if (ctx->deny_groups) {
+- matched = false;
+- for (i = 0; ctx->deny_groups[i]; i++) {
+- for(j = 0; groups[j]; j++) {
+- if (sss_string_equal(cs, groups[j], ctx->deny_groups[i])) {
+- matched = true;
+- break;
+- }
+- }
+-
+- /* If any group has matched, we can skip out on the
+- * processing early
+- */
+- if (matched) {
+- *access_granted = false;
+- break;
+- }
+- }
+- }
+-
+- ret = EOK;
+-
+-done:
+- talloc_free(tmp_ctx);
+- return ret;
+-}
++static void simple_access_check(struct tevent_req *req);
+
+ void simple_access_handler(struct be_req *be_req)
+ {
+- int ret;
+- bool access_granted = false;
++ struct be_ctx *be_ctx = be_req->be_ctx;
+ struct pam_data *pd;
++ struct tevent_req *req;
+ struct simple_ctx *ctx;
+
+ pd = talloc_get_type(be_req->req_data, struct pam_data);
+@@ -255,7 +57,30 @@ void simple_access_handler(struct be_req *be_req)
+ ctx = talloc_get_type(be_req->be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
+ struct simple_ctx);
+
+- ret = simple_access_check(ctx, pd->user, &access_granted);
++ req = simple_access_check_send(be_req, be_ctx->ev, ctx, pd->user);
++ if (!req) {
++ pd->pam_status = PAM_SYSTEM_ERR;
++ goto done;
++ }
++ tevent_req_set_callback(req, simple_access_check, be_req);
++ return;
++
++done:
++ be_req->fn(be_req, DP_ERR_OK, pd->pam_status, NULL);
++}
++
++static void simple_access_check(struct tevent_req *req)
++{
++ bool access_granted = false;
++ errno_t ret;
++ struct pam_data *pd;
++ struct be_req *be_req;
++
++ be_req = tevent_req_callback_data(req, struct be_req);
++ pd = talloc_get_type(be_req->req_data, struct pam_data);
++
++ ret = simple_access_check_recv(req, &access_granted);
++ talloc_free(req);
+ if (ret != EOK) {
+ pd->pam_status = PAM_SYSTEM_ERR;
+ goto done;
+@@ -290,6 +115,7 @@ int sssm_simple_access_init(struct be_ctx *bectx, struct bet_ops **ops,
+
+ ctx->sysdb = bectx->sysdb;
+ ctx->domain = bectx->domain;
++ ctx->be_ctx = bectx;
+
+ /* Users */
+ ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path,
+diff --git a/src/providers/simple/simple_access.h b/src/providers/simple/simple_access.h
+index abcf61ac29f31b3e424dd12340759ee6cc8c9489..1de9d898bdc3a58bbce2e2c74a02796fa5c3c609 100644
+--- a/src/providers/simple/simple_access.h
++++ b/src/providers/simple/simple_access.h
+@@ -29,6 +29,7 @@
+ struct simple_ctx {
+ struct sysdb_ctx *sysdb;
+ struct sss_domain_info *domain;
++ struct be_ctx *be_ctx;
+
+ char **allow_users;
+ char **deny_users;
+@@ -36,6 +37,12 @@ struct simple_ctx {
+ char **deny_groups;
+ };
+
+-errno_t simple_access_check(struct simple_ctx *ctx, const char *username,
+- bool *access_granted);
++struct tevent_req *simple_access_check_send(TALLOC_CTX *mem_ctx,
++ struct tevent_context *ev,
++ struct simple_ctx *ctx,
++ const char *username);
++
++errno_t simple_access_check_recv(struct tevent_req *req,
++ bool *access_granted);
++
+ #endif /* __SIMPLE_ACCESS_H__ */
+diff --git a/src/providers/simple/simple_access_check.c b/src/providers/simple/simple_access_check.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..a9e8f632e8af6aae467571db6f093a5b07b5ed91
+--- /dev/null
++++ b/src/providers/simple/simple_access_check.c
+@@ -0,0 +1,723 @@
++/*
++ SSSD
++
++ Simple access control
++
++ Copyright (C) Sumit Bose <sbose at redhat.com> 2010
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include "providers/dp_backend.h"
++#include "providers/simple/simple_access.h"
++#include "util/sss_utf8.h"
++#include "db/sysdb.h"
++
++static bool
++is_posix(const struct ldb_message *group)
++{
++ const char *val;
++
++ val = ldb_msg_find_attr_as_string(group, SYSDB_POSIX, NULL);
++ if (!val || /* Groups are posix by default */
++ strcasecmp(val, "TRUE") == 0) {
++ return true;
++ }
++
++ return false;
++}
++
++/* Returns EOK if the result is definitive, EAGAIN if only partial result
++ */
++static errno_t
++simple_check_users(struct simple_ctx *ctx, const char *username,
++ bool *access_granted)
++{
++ int i;
++ bool cs = ctx->domain->case_sensitive;
++
++ /* First, check whether the user is in the allowed users list */
++ if (ctx->allow_users != NULL) {
++ for(i = 0; ctx->allow_users[i] != NULL; i++) {
++ if (sss_string_equal(cs, username, ctx->allow_users[i])) {
++ DEBUG(SSSDBG_TRACE_LIBS,
++ ("User [%s] found in allow list, access granted.\n",
++ username));
++
++ /* Do not return immediately on explicit allow
++ * We need to make sure none of the user's groups
++ * are denied.
++ */
++ *access_granted = true;
++ }
++ }
++ } else if (!ctx->allow_groups) {
++ /* If neither allow rule is in place, we'll assume allowed
++ * unless a deny rule disables us below.
++ */
++ DEBUG(SSSDBG_TRACE_LIBS,
++ ("No allow rule, assumuing allow unless explicitly denied\n"));
++ *access_granted = true;
++ }
++
++ /* Next check whether this user has been specifically denied */
++ if (ctx->deny_users != NULL) {
++ for(i = 0; ctx->deny_users[i] != NULL; i++) {
++ if (sss_string_equal(cs, username, ctx->deny_users[i])) {
++ DEBUG(SSSDBG_TRACE_LIBS,
++ ("User [%s] found in deny list, access denied.\n",
++ username));
++
++ /* Return immediately on explicit denial */
++ *access_granted = false;
++ return EOK;
++ }
++ }
++ }
++
++ return EAGAIN;
++}
++
++static errno_t
++simple_check_groups(struct simple_ctx *ctx, const char *username,
++ const char **group_names, bool *access_granted)
++{
++ bool matched;
++ int i, j;
++ bool cs = ctx->domain->case_sensitive;
++
++ /* Now process allow and deny group rules
++ * If access was already granted above, we'll skip
++ * this redundant rule check
++ */
++ if (ctx->allow_groups && !*access_granted) {
++ matched = false;
++ for (i = 0; ctx->allow_groups[i]; i++) {
++ for(j = 0; group_names[j]; j++) {
++ if (sss_string_equal(cs, group_names[j], ctx->allow_groups[i])) {
++ matched = true;
++ break;
++ }
++ }
++
++ /* If any group has matched, we can skip out on the
++ * processing early
++ */
++ if (matched) {
++ DEBUG(SSSDBG_TRACE_LIBS,
++ ("Group [%s] found in allow list, access granted.\n",
++ group_names[j]));
++ *access_granted = true;
++ break;
++ }
++ }
++ }
++
++ /* Finally, process the deny group rules */
++ if (ctx->deny_groups) {
++ matched = false;
++ for (i = 0; ctx->deny_groups[i]; i++) {
++ for(j = 0; group_names[j]; j++) {
++ if (sss_string_equal(cs, group_names[j], ctx->deny_groups[i])) {
++ matched = true;
++ break;
++ }
++ }
++
++ /* If any group has matched, we can skip out on the
++ * processing early
++ */
++ if (matched) {
++ DEBUG(SSSDBG_TRACE_LIBS,
++ ("Group [%s] found in deny list, access denied.\n",
++ group_names[j]));
++ *access_granted = false;
++ break;
++ }
++ }
++ }
++
++ return EOK;
++}
++
++struct simple_resolve_group_state {
++ gid_t gid;
++ struct simple_ctx *ctx;
++
++ const char *name;
++};
++
++static errno_t
++simple_resolve_group_check(struct simple_resolve_group_state *state);
++static void simple_resolve_group_done(struct tevent_req *subreq);
++
++static struct tevent_req *
++simple_resolve_group_send(TALLOC_CTX *mem_ctx,
++ struct tevent_context *ev,
++ struct simple_ctx *ctx,
++ gid_t gid)
++{
++ errno_t ret;
++ struct tevent_req *req;
++ struct tevent_req *subreq;
++ struct simple_resolve_group_state *state;
++ struct be_acct_req *ar;
++
++ req = tevent_req_create(mem_ctx, &state,
++ struct simple_resolve_group_state);
++ if (!req) return NULL;
++
++ state->gid = gid;
++ state->ctx = ctx;
++
++ /* First check if the group was updated already. If it was (maybe its
++ * parent was updated first), then just shortcut */
++ ret = simple_resolve_group_check(state);
++ if (ret == EOK) {
++ DEBUG(SSSDBG_TRACE_LIBS, ("Group already updated\n"));
++ ret = EOK;
++ goto done;
++ } else if (ret != EAGAIN) {
++ DEBUG(SSSDBG_OP_FAILURE,
++ ("Cannot check if group was already updated\n"));
++ goto done;
++ }
++ /* EAGAIN - still needs update */
++
++ ar = talloc(state, struct be_acct_req);
++ if (!ar) {
++ ret = ENOMEM;
++ goto done;
++ }
++
++ ar->entry_type = BE_REQ_GROUP;
++ ar->attr_type = BE_ATTR_CORE;
++ ar->filter_type = BE_FILTER_IDNUM;
++ ar->filter_value = talloc_asprintf(ar, "%llu", (unsigned long long) gid);
++ ar->domain = talloc_strdup(ar, ctx->domain->name);
++ if (!ar->domain || !ar->filter_value) {
++ ret = ENOMEM;
++ goto done;
++ }
++
++ subreq = be_get_account_info_send(state, ev, NULL, ctx->be_ctx, ar);
++ if (!subreq) {
++ ret = ENOMEM;
++ goto done;
++ }
++ tevent_req_set_callback(subreq, simple_resolve_group_done, req);
++
++ return req;
++
++done:
++ if (ret == EOK) {
++ tevent_req_done(req);
++ } else {
++ tevent_req_error(req, ret);
++ }
++ tevent_req_post(req, ev);
++ return req;
++}
++
++static errno_t
++simple_resolve_group_check(struct simple_resolve_group_state *state)
++{
++ errno_t ret;
++ struct ldb_message *group;
++ const char *group_attrs[] = { SYSDB_NAME, SYSDB_POSIX,
++ SYSDB_GIDNUM, NULL };
++
++ /* Check the cache by GID again and fetch the name */
++ ret = sysdb_search_group_by_gid(state, state->ctx->domain->sysdb,
++ state->gid, group_attrs, &group);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE,
++ ("Could not look up group by gid [%lu]: [%d][%s]\n",
++ state->gid, ret, strerror(ret)));
++ return ret;
++ }
++
++ state->name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
++ if (!state->name) {
++ DEBUG(SSSDBG_OP_FAILURE, ("No group name\n"));
++ return ENOENT;
++ }
++
++ if (is_posix(group) == false) {
++ DEBUG(SSSDBG_TRACE_LIBS,
++ ("The group is still non-POSIX\n"));
++ return EAGAIN;
++ }
++
++ DEBUG(SSSDBG_TRACE_LIBS, ("Got POSIX group\n"));
++ return EOK;
++}
++
++static void simple_resolve_group_done(struct tevent_req *subreq)
++{
++ struct tevent_req *req;
++ struct simple_resolve_group_state *state;
++ int err_maj;
++ int err_min;
++ errno_t ret;
++ const char *err_msg;
++
++ req = tevent_req_callback_data(subreq, struct tevent_req);
++ state = tevent_req_data(req, struct simple_resolve_group_state);
++
++ ret = be_get_account_info_recv(subreq, state,
++ &err_maj, &err_min, &err_msg);
++ talloc_zfree(subreq);
++ if (ret) {
++ DEBUG(SSSDBG_OP_FAILURE, ("be_get_account_info_recv failed\n"));
++ tevent_req_error(req, ret);
++ return;
++ }
++
++ if (err_maj) {
++ DEBUG(SSSDBG_MINOR_FAILURE,
++ ("Cannot refresh data from DP: %u,%u: %s\n",
++ err_maj, err_min, err_msg));
++ tevent_req_error(req, EIO);
++ return;
++ }
++
++ /* Check the cache by GID again and fetch the name */
++ ret = simple_resolve_group_check(state);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE, ("Refresh failed\n"));
++ tevent_req_error(req, ret);
++ return;
++ }
++
++ tevent_req_done(req);
++}
++
++static errno_t
++simple_resolve_group_recv(struct tevent_req *req,
++ TALLOC_CTX *mem_ctx,
++ const char **name)
++{
++ struct simple_resolve_group_state *state;
++
++ state = tevent_req_data(req, struct simple_resolve_group_state);
++
++ TEVENT_REQ_RETURN_ON_ERROR(req);
++
++ *name = talloc_strdup(mem_ctx, state->name);
++ return EOK;
++}
++
++struct simple_check_groups_state {
++ struct tevent_context *ev;
++ struct simple_ctx *ctx;
++
++ gid_t *lookup_gids;
++ size_t num_gids;
++ size_t giter;
++
++ const char **group_names;
++ size_t num_names;
++};
++
++static void simple_check_get_groups_next(struct tevent_req *subreq);
++
++static errno_t
++simple_check_get_groups_primary(struct simple_check_groups_state *state,
++ gid_t gid);
++static errno_t
++simple_check_process_group(struct simple_check_groups_state *state,
++ struct ldb_message *group);
++
++static struct tevent_req *
++simple_check_get_groups_send(TALLOC_CTX *mem_ctx,
++ struct tevent_context *ev,
++ struct simple_ctx *ctx,
++ const char *username)
++{
++ errno_t ret;
++ struct tevent_req *req;
++ struct tevent_req *subreq;
++ struct simple_check_groups_state *state;
++ const char *attrs[] = { SYSDB_NAME, SYSDB_POSIX, SYSDB_GIDNUM, NULL };
++ size_t group_count;
++ struct ldb_message *user;
++ struct ldb_message **groups;
++ int i;
++ gid_t gid;
++ char *cname;
++
++ req = tevent_req_create(mem_ctx, &state,
++ struct simple_check_groups_state);
++ if (!req) return NULL;
++
++ state->ev = ev;
++ state->ctx = ctx;
++
++ cname = sss_get_cased_name(state, username, ctx->domain->case_sensitive);
++ if (!cname) {
++ ret = ENOMEM;
++ goto done;
++ }
++
++ DEBUG(SSSDBG_TRACE_LIBS, ("Looking up groups for user %s\n", cname));
++
++ ret = sysdb_search_user_by_name(state, ctx->domain->sysdb,
++ cname, attrs, &user);
++ if (ret == ENOENT) {
++ DEBUG(SSSDBG_MINOR_FAILURE, ("No such user %s\n", cname));
++ goto done;
++ } else if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE,
++ ("Could not look up username [%s]: [%d][%s]\n",
++ username, ret, strerror(ret)));
++ goto done;
++ }
++
++ ret = sysdb_asq_search(state, ctx->domain->sysdb,
++ user->dn, NULL, SYSDB_MEMBEROF,
++ attrs, &group_count, &groups);
++ if (ret != EOK) {
++ goto done;
++ }
++
++ DEBUG(SSSDBG_TRACE_FUNC,
++ ("User %s is a member of %d supplemental groups\n",
++ cname, group_count));
++
++ /* One extra space for terminator, one extra space for private group */
++ state->group_names = talloc_zero_array(state, const char *, group_count + 2);
++ state->lookup_gids = talloc_zero_array(state, gid_t, group_count + 2);
++ if (!state->group_names || !state->lookup_gids) {
++ ret = ENOMEM;
++ goto done;
++ }
++
++ for (i=0; i < group_count; i++) {
++ /* Some providers (like the AD provider) might perform initgroups
++ * without resolving the group names. In order for the simple access
++ * provider to work correctly, we need to resolve the groups before
++ * performing the access check. In AD provider, the situation is
++ * even more tricky b/c the groups HAVE name, but their name
++ * attribute is set to SID and they are set as non-POSIX
++ */
++ ret = simple_check_process_group(state, groups[i]);
++ if (ret != EOK) {
++ goto done;
++ }
++ }
++
++ gid = ldb_msg_find_attr_as_uint64(user, SYSDB_GIDNUM, 0);
++ if (!gid) {
++ DEBUG(SSSDBG_MINOR_FAILURE, ("User %s has no gid?\n", cname));
++ ret = EINVAL;
++ goto done;
++ }
++
++ ret = simple_check_get_groups_primary(state, gid);
++ if (ret != EOK) {
++ goto done;
++ }
++
++ if (state->num_gids == 0) {
++ /* If all groups could have been resolved by name, we are
++ * done
++ */
++ DEBUG(SSSDBG_TRACE_FUNC, ("All groups had name attribute\n"));
++ ret = EOK;
++ goto done;
++ }
++
++ DEBUG(SSSDBG_TRACE_FUNC, ("Need to resolve %d groups\n", state->num_gids));
++ state->giter = 0;
++ subreq = simple_resolve_group_send(req, state->ev, state->ctx,
++ state->lookup_gids[state->giter]);
++ if (!subreq) {
++ ret = ENOMEM;
++ goto done;
++ }
++ tevent_req_set_callback(subreq, simple_check_get_groups_next, req);
++
++ return req;
++
++done:
++ if (ret == EOK) {
++ tevent_req_done(req);
++ } else {
++ tevent_req_error(req, ret);
++ }
++ tevent_req_post(req, ev);
++ return req;
++}
++
++static void simple_check_get_groups_next(struct tevent_req *subreq)
++{
++ struct tevent_req *req =
++ tevent_req_callback_data(subreq, struct tevent_req);
++ struct simple_check_groups_state *state =
++ tevent_req_data(req, struct simple_check_groups_state);
++ errno_t ret;
++
++ ret = simple_resolve_group_recv(subreq, state->group_names,
++ &state->group_names[state->num_names]);
++ talloc_zfree(subreq);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE,
++ ("Could not resolve name of group with GID %llu\n",
++ state->lookup_gids[state->giter]));
++ tevent_req_error(req, ret);
++ return;
++ }
++
++ state->num_names++;
++ state->giter++;
++
++ if (state->giter < state->num_gids) {
++ subreq = simple_resolve_group_send(req, state->ev, state->ctx,
++ state->lookup_gids[state->giter]);
++ if (!subreq) {
++ tevent_req_error(req, ENOMEM);
++ return;
++ }
++ tevent_req_set_callback(subreq, simple_check_get_groups_next, req);
++ return;
++ }
++
++ DEBUG(SSSDBG_TRACE_INTERNAL, ("All groups resolved. Done.\n"));
++ tevent_req_done(req);
++}
++
++static errno_t
++simple_check_process_group(struct simple_check_groups_state *state,
++ struct ldb_message *group)
++{
++ const char *name;
++ gid_t gid;
++ bool posix;
++
++ posix = is_posix(group);
++ name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
++ gid = ldb_msg_find_attr_as_uint64(group, SYSDB_GIDNUM, 0);
++
++ /* With the current sysdb layout, every group has a name */
++ if (name == NULL) {
++ return EINVAL;
++ }
++
++ if (gid == 0) {
++ if (posix == true) {
++ DEBUG(SSSDBG_CRIT_FAILURE, ("POSIX group without GID\n"));
++ return EINVAL;
++ }
++
++ /* Non-posix group with a name. Still can be used for access
++ * control as the name should point to the real name, no SID
++ */
++ state->group_names[state->num_names] = talloc_strdup(state->group_names,
++ name);
++ if (!state->group_names[state->num_names]) {
++ return ENOMEM;
++ }
++ DEBUG(SSSDBG_TRACE_INTERNAL, ("Adding group %s\n", name));
++ state->num_names++;
++ return EOK;
++ }
++
++ /* Here are only groups with a name and gid. POSIX group can already
++ * be used, non-POSIX groups can be resolved */
++ if (posix) {
++ state->group_names[state->num_names] = talloc_strdup(state->group_names,
++ name);
++ if (!state->group_names[state->num_names]) {
++ return ENOMEM;
++ }
++ DEBUG(SSSDBG_TRACE_INTERNAL, ("Adding group %s\n", name));
++ state->num_names++;
++ return EOK;
++ }
++
++ /* Non-posix group with a GID. Needs resolving */
++ state->lookup_gids[state->num_gids] = gid;
++ DEBUG(SSSDBG_TRACE_INTERNAL, ("Adding GID %llu\n", gid));
++ state->num_gids++;
++ return EOK;
++}
++
++static errno_t
++simple_check_get_groups_primary(struct simple_check_groups_state *state,
++ gid_t gid)
++{
++ errno_t ret;
++ const char *group_attrs[] = { SYSDB_NAME, SYSDB_POSIX,
++ SYSDB_GIDNUM, NULL };
++ struct ldb_message *msg;
++
++ ret = sysdb_search_group_by_gid(state, state->ctx->domain->sysdb,
++ gid, group_attrs, &msg);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE,
++ ("Could not look up primary group [%lu]: [%d][%s]\n",
++ gid, ret, strerror(ret)));
++ /* We have to treat this as non-fatal, because the primary
++ * group may be local to the machine and not available in
++ * our ID provider.
++ */
++ } else {
++ ret = simple_check_process_group(state, msg);
++ if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE, ("Cannot process primary group\n"));
++ return ret;
++ }
++ }
++
++ return EOK;
++}
++
++static errno_t
++simple_check_get_groups_recv(struct tevent_req *req,
++ TALLOC_CTX *mem_ctx,
++ const char ***_group_names)
++{
++ struct simple_check_groups_state *state;
++
++ state = tevent_req_data(req, struct simple_check_groups_state);
++
++ TEVENT_REQ_RETURN_ON_ERROR(req);
++
++ *_group_names = talloc_steal(mem_ctx, state->group_names);
++ return EOK;
++}
++
++struct simple_access_check_state {
++ bool access_granted;
++ struct simple_ctx *ctx;
++ const char *username;
++
++ const char **group_names;
++};
++
++static void simple_access_check_done(struct tevent_req *subreq);
++
++struct tevent_req *simple_access_check_send(TALLOC_CTX *mem_ctx,
++ struct tevent_context *ev,
++ struct simple_ctx *ctx,
++ const char *username)
++{
++ errno_t ret;
++ struct tevent_req *req;
++ struct tevent_req *subreq;
++ struct simple_access_check_state *state;
++
++ req = tevent_req_create(mem_ctx, &state,
++ struct simple_access_check_state);
++ if (!req) return NULL;
++
++ state->access_granted = false;
++ state->ctx = ctx;
++ state->username = talloc_strdup(state, username);
++ if (!state->username) {
++ ret = ENOMEM;
++ goto immediate;
++ }
++
++ DEBUG(SSSDBG_FUNC_DATA, ("Simple access check for %s\n", username));
++
++ ret = simple_check_users(ctx, username, &state->access_granted);
++ if (ret != EAGAIN) {
++ /* Both access denied and an error */
++ goto immediate;
++ }
++
++ if (!ctx->allow_groups && !ctx->deny_groups) {
++ /* There are no group restrictions, so just return
++ * here with whatever we've decided.
++ */
++ DEBUG(SSSDBG_TRACE_LIBS, ("No group restrictions, end request\n"));
++ ret = EOK;
++ goto immediate;
++ }
++
++ /* The group names might not be available. Fire a request to
++ * gather them. In most cases, the request will just shortcut
++ */
++ subreq = simple_check_get_groups_send(state, ev, ctx, username);
++ if (!subreq) {
++ ret = EIO;
++ goto immediate;
++ }
++ tevent_req_set_callback(subreq, simple_access_check_done, req);
++
++ return req;
++
++immediate:
++ if (ret == EOK) {
++ tevent_req_done(req);
++ } else {
++ tevent_req_error(req, ret);
++ }
++ tevent_req_post(req, ev);
++ return req;
++}
++
++
++static void simple_access_check_done(struct tevent_req *subreq)
++{
++ struct tevent_req *req =
++ tevent_req_callback_data(subreq, struct tevent_req);
++ struct simple_access_check_state *state =
++ tevent_req_data(req, struct simple_access_check_state);
++ errno_t ret;
++
++ /* We know the names now. Run the check. */
++ ret = simple_check_get_groups_recv(subreq, state, &state->group_names);
++ talloc_zfree(subreq);
++ if (ret == ENOENT) {
++ /* If the user wasn't found, just shortcut */
++ state->access_granted = false;
++ tevent_req_done(req);
++ return;
++ } else if (ret != EOK) {
++ DEBUG(SSSDBG_OP_FAILURE,
++ ("Could not collect groups of user %s\n", state->username));
++ tevent_req_error(req, ret);
++ return;
++ }
++
++ ret = simple_check_groups(state->ctx, state->username,
++ state->group_names, &state->access_granted);
++ if (ret != EOK) {
++ tevent_req_error(req, ret);
++ return;
++ }
++
++ /* Now just return whatever we decided */
++ DEBUG(SSSDBG_TRACE_INTERNAL, ("Group check done\n"));
++ tevent_req_done(req);
++}
++
++errno_t simple_access_check_recv(struct tevent_req *req, bool *access_granted)
++{
++ struct simple_access_check_state *state =
++ tevent_req_data(req, struct simple_access_check_state);
++
++ TEVENT_REQ_RETURN_ON_ERROR(req);
++
++ DEBUG(SSSDBG_TRACE_LIBS,
++ ("Access %sgranted\n", state->access_granted ? "" : "not "));
++ if (access_granted) {
++ *access_granted = state->access_granted;
++ }
++
++ return EOK;
++}
+diff --git a/src/tests/simple_access-tests.c b/src/tests/simple_access-tests.c
+index 577c6d334edda513fd0f1e42a859ea333ba5ba23..ab2612db85b6cfe46c87a1fc8b17655dc7a795bb 100644
+--- a/src/tests/simple_access-tests.c
++++ b/src/tests/simple_access-tests.c
+@@ -27,6 +27,7 @@
+ #include <check.h>
+
+ #include "confdb/confdb.h"
++#include "db/sysdb_private.h"
+ #include "providers/simple/simple_access.h"
+ #include "tests/common.h"
+
+@@ -35,16 +36,40 @@
+
+ const char *ulist_1[] = {"u1", "u2", NULL};
+ const char *glist_1[] = {"g1", "g2", NULL};
++const char *glist_1_case[] = {"G1", "G2", NULL};
+
+ struct simple_test_ctx *test_ctx = NULL;
+
+ struct simple_test_ctx {
+ struct sysdb_ctx *sysdb;
+ struct confdb_ctx *confdb;
++ struct tevent_context *ev;
++ bool done;
++ int error;
+
++ bool access_granted;
+ struct simple_ctx *ctx;
+ };
+
++static int test_loop(struct simple_test_ctx *tctx)
++{
++ while (!tctx->done)
++ tevent_loop_once(tctx->ev);
++
++ return tctx->error;
++}
++
++static void simple_access_check_done(struct tevent_req *req)
++{
++ struct simple_test_ctx *tctx =
++ tevent_req_callback_data(req, struct simple_test_ctx);
++
++
++ tctx->error = simple_access_check_recv(req, &tctx->access_granted);
++ talloc_free(req);
++ tctx->done = true;
++}
++
+ void setup_simple(void)
+ {
+ errno_t ret;
+@@ -52,19 +77,22 @@ void setup_simple(void)
+ const char *val[2];
+ val[1] = NULL;
+
+- /* Create tests directory if it doesn't exist */
+- /* (relative to current dir) */
+- ret = mkdir(TESTS_PATH, 0775);
+- fail_if(ret == -1 && errno != EEXIST,
+- "Could not create %s directory", TESTS_PATH);
+-
+ fail_unless(test_ctx == NULL, "Simple context already initialized.");
+ test_ctx = talloc_zero(NULL, struct simple_test_ctx);
+ fail_unless(test_ctx != NULL, "Cannot create simple test context.");
+
++ test_ctx->ev = tevent_context_init(test_ctx);
++ fail_unless(test_ctx->ev != NULL, "Cannot create tevent context.");
++
+ test_ctx->ctx = talloc_zero(test_ctx, struct simple_ctx);
+ fail_unless(test_ctx->ctx != NULL, "Cannot create simple context.");
+
++ /* Create tests directory if it doesn't exist */
++ /* (relative to current dir) */
++ ret = mkdir(TESTS_PATH, 0775);
++ fail_if(ret == -1 && errno != EEXIST,
++ "Could not create %s directory", TESTS_PATH);
++
+ conf_db = talloc_asprintf(test_ctx, "%s/%s", TESTS_PATH, TEST_CONF_FILE);
+ fail_if(conf_db == NULL, "Out of memory, aborting!");
+ DEBUG(SSSDBG_TRACE_LIBS, ("CONFDB: %s\n", conf_db));
+@@ -98,6 +126,7 @@ void setup_simple(void)
+ &test_ctx->ctx->domain, &test_ctx->ctx->sysdb);
+ fail_if(ret != EOK, "Could not initialize connection to the sysdb (%d)", ret);
+ test_ctx->ctx->domain->case_sensitive = true;
++ test_ctx->ctx->sysdb->mpg = false; /* Simulate an LDAP domain better */
+ }
+
+ void teardown_simple(void)
+@@ -117,18 +146,22 @@ void setup_simple_group(void)
+
+ /* Add test users u1 and u2 that would be members of test groups
+ * g1 and g2 respectively */
++ ret = sysdb_add_group(test_ctx->ctx->sysdb,
++ "pvt", 999, NULL, 0, 0);
++ fail_if(ret != EOK, "Could not add private group");
++
+ ret = sysdb_store_user(test_ctx->ctx->sysdb,
+- "u1", NULL, 123, 0, "u1", "/home/u1",
++ "u1", NULL, 123, 999, "u1", "/home/u1",
+ "/bin/bash", NULL, NULL, NULL, -1, 0);
+ fail_if(ret != EOK, "Could not add u1");
+
+ ret = sysdb_store_user(test_ctx->ctx->sysdb,
+- "u2", NULL, 456, 0, "u1", "/home/u1",
++ "u2", NULL, 456, 999, "u1", "/home/u1",
+ "/bin/bash", NULL, NULL, NULL, -1, 0);
+ fail_if(ret != EOK, "Could not add u2");
+
+ ret = sysdb_store_user(test_ctx->ctx->sysdb,
+- "u3", NULL, 789, 0, "u1", "/home/u1",
++ "u3", NULL, 789, 999, "u1", "/home/u1",
+ "/bin/bash", NULL, NULL, NULL, -1, 0);
+ fail_if(ret != EOK, "Could not add u3");
+
+@@ -163,190 +196,317 @@ void teardown_simple_group(void)
+ fail_if(ret != EOK, "Could not delete g1");
+ ret = sysdb_delete_group(test_ctx->ctx->sysdb, "g2", 0);
+ fail_if(ret != EOK, "Could not delete g2");
++ ret = sysdb_delete_group(test_ctx->ctx->sysdb, "pvt", 0);
++ fail_if(ret != EOK, "Could not delete pvt");
+
+ teardown_simple();
+ }
+
+ START_TEST(test_both_empty)
+ {
+- int ret;
+- bool access_granted = false;
++ struct tevent_req *req;
+
+ test_ctx->ctx->allow_users = NULL;
+ test_ctx->ctx->deny_users = NULL;
+
+- ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == true, "Access denied "
+- "while both lists are empty.");
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "u1");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == true,
++ "Access denied while both lists are empty.");
+ }
+ END_TEST
+
+ START_TEST(test_allow_empty)
+ {
+- int ret;
+- bool access_granted = true;
++ struct tevent_req *req;
+
+ test_ctx->ctx->allow_users = NULL;
+ test_ctx->ctx->deny_users = discard_const(ulist_1);
+
+- ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == false, "Access granted "
+- "while user is in deny list.");
+-
+- ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == true, "Access denied "
+- "while user is not in deny list.");
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "u1");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++ test_ctx->done = false;
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == false,
++ "Access granted while user is in deny list.");
++
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "u3");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == true,
++ "Access denied while user is not in deny list.");
+ }
+ END_TEST
+
+ START_TEST(test_deny_empty)
+ {
+- int ret;
+- bool access_granted = false;
++ struct tevent_req *req;
+
+ test_ctx->ctx->allow_users = discard_const(ulist_1);
+ test_ctx->ctx->deny_users = NULL;
+
+- ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == true, "Access denied "
+- "while user is in allow list.");
+-
+- ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == false, "Access granted "
+- "while user is not in allow list.");
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "u1");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++ test_ctx->done = false;
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == true,
++ "Access denied while user is in allow list.");
++
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "u3");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == false,
++ "Access granted while user is not in allow list.");
+ }
+ END_TEST
+
+ START_TEST(test_both_set)
+ {
+- int ret;
+- bool access_granted = false;
++ struct tevent_req *req;
+
+ test_ctx->ctx->allow_users = discard_const(ulist_1);
+ test_ctx->ctx->deny_users = discard_const(ulist_1);
+
+- ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == false, "Access granted "
+- "while user is in deny list.");
+-
+- ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == false, "Access granted "
+- "while user is not in allow list.");
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "u1");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++ test_ctx->done = false;
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == false,
++ "Access granted while user is in deny list.");
++
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "u3");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == false,
++ "Access granted while user is not in allow list.");
+ }
+ END_TEST
+
+ START_TEST(test_case)
+ {
+- int ret;
+- bool access_granted = false;
++ struct tevent_req *req;
+
+ test_ctx->ctx->allow_users = discard_const(ulist_1);
+ test_ctx->ctx->deny_users = NULL;
+
+- ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == false, "Access granted "
+- "for user with different case "
+- "in case-sensitive domain");
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "U1");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++ test_ctx->done = false;
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == false,
++ "Access granted for user with different case "
++ "in case-sensitive domain");
+
+ test_ctx->ctx->domain->case_sensitive = false;
+
+- ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == true, "Access denied "
+- "for user with different case "
+- "in case-insensitive domain");
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "U1");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++ test_ctx->done = false;
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == true,
++ "Access denied for user with different case "
++ "in case-sensitive domain");
+ }
+ END_TEST
+
++START_TEST(test_unknown_user)
++{
++ struct tevent_req *req;
++
++ test_ctx->ctx->allow_users = discard_const(ulist_1);
++ test_ctx->ctx->deny_users = NULL;
++
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "foo");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++ test_ctx->done = false;
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == false,
++ "Access granted for user not present in domain");
++}
++END_TEST
++
++
+ START_TEST(test_group_allow_empty)
+ {
+- int ret;
+- bool access_granted = true;
++ struct tevent_req *req;
+
+ test_ctx->ctx->allow_groups = NULL;
+ test_ctx->ctx->deny_groups = discard_const(glist_1);
+
+- ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == false, "Access granted "
+- "while group is in deny list.");
+-
+- ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == true, "Access denied "
+- "while group is not in deny list.");
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "u1");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++ test_ctx->done = false;
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == false,
++ "Access granted while group is in deny list.");
++
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "u3");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == true,
++ "Access denied while group is not in deny list.");
+ }
+ END_TEST
+
+ START_TEST(test_group_deny_empty)
+ {
+- int ret;
+- bool access_granted = false;
++ struct tevent_req *req;
+
+ test_ctx->ctx->allow_groups = discard_const(glist_1);
+ test_ctx->ctx->deny_groups = NULL;
+
+- ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == true, "Access denied "
+- "while group is in allow list.");
+-
+- ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == false, "Access granted "
+- "while group is not in allow list.");
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "u1");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++ test_ctx->done = false;
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == true,
++ "Access denied while user is in allow list.");
++
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "u3");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == false,
++ "Access granted while user is not in allow list.");
+ }
+ END_TEST
+
+ START_TEST(test_group_both_set)
+ {
+- int ret;
+- bool access_granted = false;
++ struct tevent_req *req;
+
+ test_ctx->ctx->allow_groups = discard_const(ulist_1);
+ test_ctx->ctx->deny_groups = discard_const(ulist_1);
+
+- ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == false, "Access granted "
+- "while group is in deny list.");
+-
+- ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == false, "Access granted "
+- "while group is not in allow list.");
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "u1");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++ test_ctx->done = false;
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == false,
++ "Access granted while user is in deny list.");
++
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "u3");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == false,
++ "Access granted while user is not in allow list.");
+ }
+ END_TEST
+
+ START_TEST(test_group_case)
+ {
+- int ret;
+- bool access_granted = false;
++ struct tevent_req *req;
+
+- test_ctx->ctx->allow_groups = discard_const(ulist_1);
++ test_ctx->ctx->allow_groups = discard_const(glist_1_case);
+ test_ctx->ctx->deny_groups = NULL;
+
+- ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == false, "Access granted "
+- "for group with different case "
+- "in case-sensitive domain");
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "U1");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++ test_ctx->done = false;
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == false,
++ "Access granted for user with different case "
++ "in case-sensitive domain");
+
+ test_ctx->ctx->domain->case_sensitive = false;
+
+- ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
+- fail_unless(ret == EOK, "access_simple_check failed.");
+- fail_unless(access_granted == true, "Access denied "
+- "for group with different case "
+- "in case-insensitive domain");
++ req = simple_access_check_send(test_ctx, test_ctx->ev,
++ test_ctx->ctx, "U1");
++ fail_unless(test_ctx != NULL, "Cannot create request\n");
++ tevent_req_set_callback(req, simple_access_check_done, test_ctx);
++
++ test_loop(test_ctx);
++ test_ctx->done = false;
++
++ fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
++ fail_unless(test_ctx->access_granted == true,
++ "Access denied for user with different case "
++ "in case-sensitive domain");
+ }
+ END_TEST
+
+@@ -361,6 +521,7 @@ Suite *access_simple_suite (void)
+ tcase_add_test(tc_allow_deny, test_deny_empty);
+ tcase_add_test(tc_allow_deny, test_both_set);
+ tcase_add_test(tc_allow_deny, test_case);
++ tcase_add_test(tc_allow_deny, test_unknown_user);
+ suite_add_tcase(s, tc_allow_deny);
+
+ TCase *tc_grp_allow_deny = tcase_create("group allow/deny");
+--
+1.8.1.4
+
diff --git a/sources b/sources
index 27b29fb..a070340 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-af1854a392114b26f9bd7dfa6cad9943 sssd-1.8.6.tar.gz
+a72cda079a287e62a4beaa4d4f48fa89 sssd-1.9.4.tar.gz
diff --git a/sssd.spec b/sssd.spec
index d9e0c3c..c555385 100644
--- a/sssd.spec
+++ b/sssd.spec
@@ -15,7 +15,7 @@
%global ldb_version 1.1.6
Name: sssd
-Version: 1.8.6
+Version: 1.9.4
Release: 1%{?dist}
Group: Applications/System
Summary: System Security Services Daemon
@@ -25,6 +25,13 @@ Source0: https://fedorahosted.org/released/sssd/%{name}-%{version}.tar.gz
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
### Patches ###
+Patch0001: 0001-krb-recreate-ccache-if-it-was-deleted.patch
+Patch0002: 0002-subdomains-replace-invalid-characters-with-underscor.patch
+Patch0003: 0003-Fix-the-krb5-password-expiration-warning.patch
+Patch0004: 0004-Add-unit-tests-for-simple-access-test-by-groups.patch
+Patch0005: 0005-Do-not-compile-main-in-DP-if-UNIT_TESTING-is-defined.patch
+Patch0006: 0006-Provide-a-be_get_account_info_send-function.patch
+Patch0007: 0007-Resolve-GIDs-in-the-simple-access-provider.patch
### Dependencies ###
@@ -34,15 +41,17 @@ Requires: libtdb%{?_isa} >= 1.1.3
Requires: sssd-client%{?_isa} = %{version}-%{release}
Requires: cyrus-sasl-gssapi%{?_isa}
Requires: libipa_hbac%{?_isa} = %{version}-%{release}
+Requires: libsss_idmap%{?_isa} = %{version}-%{release}
Requires: krb5-libs%{?_isa} >= 1.10
-Requires(post): systemd-units initscripts chkconfig /sbin/ldconfig
+Requires(post): systemd-units initscripts chkconfig
Requires(preun): systemd-units initscripts chkconfig
-Requires(postun): systemd-units initscripts chkconfig /sbin/ldconfig
+Requires(postun): systemd-units initscripts chkconfig
%global servicename sssd
%global sssdstatedir %{_localstatedir}/lib/sss
%global dbpath %{sssdstatedir}/db
%global pipepath %{sssdstatedir}/pipes
+%global mcpath %{sssdstatedir}/mc
%global pubconfpath %{sssdstatedir}/pubconf
### Build Dependencies ###
@@ -88,7 +97,10 @@ BuildRequires: libnl-devel
BuildRequires: gettext-devel
BuildRequires: pkgconfig
BuildRequires: glib2-devel
+BuildRequires: diffstat
BuildRequires: findutils
+BuildRequires: samba4-devel >= samba4-4.0.0-59beta2
+BuildRequires: selinux-policy-targeted
%description
Provides a set of daemons to manage access to remote directories and
@@ -101,6 +113,8 @@ services for projects like FreeIPA.
Summary: SSSD Client libraries for NSS and PAM
Group: Applications/System
License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
%description client
Provides the libraries needed by the PAM and NSS stacks to connect to the SSSD
@@ -110,19 +124,43 @@ service.
Summary: Userspace tools for use with the SSSD
Group: Applications/System
License: GPLv3+
-Requires: sssd%{?_isa} = %{version}-%{release}
+Requires: sssd = %{version}-%{release}
%description tools
Provides userspace tools for manipulating users, groups, and nested groups in
SSSD when using id_provider = local in /etc/sssd/sssd.conf.
-Also provides a userspace tool for generating an obfuscated LDAP password for
-use with ldap_default_authtok_type = obfuscated_password.
+Also provides several other administrative tools:
+ * sss_cache to expire cached entries
+ * sss_debuglevel to change the debug level on the fly
+ * sss_seed which pre-creates a user entry for use in kickstarts
+ * sss_obfuscate for generating an obfuscated LDAP password
+
+%package -n libsss_idmap
+Summary: FreeIPA Idmap library
+Group: Development/Libraries
+License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n libsss_idmap
+Utility library to convert SIDs to Unix uids and gids
+
+%package -n libsss_idmap-devel
+Summary: FreeIPA Idmap library
+Group: Development/Libraries
+License: LGPLv3+
+Requires: libsss_idmap = %{version}-%{release}
+
+%description -n libsss_idmap-devel
+Utility library to SIDs to Unix uids and gids
%package -n libipa_hbac
Summary: FreeIPA HBAC Evaluator library
Group: Development/Libraries
License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
%description -n libipa_hbac
Utility library to validate FreeIPA HBAC rules for authorization requests
@@ -131,7 +169,7 @@ Utility library to validate FreeIPA HBAC rules for authorization requests
Summary: FreeIPA HBAC Evaluator library
Group: Development/Libraries
License: LGPLv3+
-Requires: libipa_hbac%{?_isa} = %{version}-%{release}
+Requires: libipa_hbac = %{version}-%{release}
%description -n libipa_hbac-devel
Utility library to validate FreeIPA HBAC rules for authorization requests
@@ -140,7 +178,7 @@ Utility library to validate FreeIPA HBAC rules for authorization requests
Summary: Python bindings for the FreeIPA HBAC Evaluator library
Group: Development/Libraries
License: LGPLv3+
-Requires: libipa_hbac%{?_isa} = %{version}-%{release}
+Requires: libipa_hbac = %{version}-%{release}
%description -n libipa_hbac-python
The libipa_hbac-python contains the bindings so that libipa_hbac can be
@@ -150,6 +188,9 @@ used by Python applications.
Summary: A library to allow communication between SUDO and SSSD
Group: Development/Libraries
License: LGPLv3+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+Requires: sssd = %{version}-%{release}
%description -n libsss_sudo
A utility library to allow communication between SUDO and SSSD
@@ -158,7 +199,7 @@ A utility library to allow communication between SUDO and SSSD
Summary: A library to allow communication between SUDO and SSSD
Group: Development/Libraries
License: LGPLv3+
-Requires: libsss_sudo%{?_isa} = %{version}-%{release}
+Requires: libsss_sudo = %{version}-%{release}
%description -n libsss_sudo-devel
A utility library to allow communication between SUDO and SSSD
@@ -192,6 +233,7 @@ autoreconf -ivf
--with-db-path=%{dbpath} \
--with-pipe-path=%{pipepath} \
--with-pubconf-path=%{pubconfpath} \
+ --with-mcache-path=%{mcpath} \
--with-init-dir=%{_initrddir} \
--with-krb5-rcache-dir=%{_localstatedir}/cache/krb5rcache \
--enable-nsslibdir=/%{_lib} \
@@ -251,6 +293,7 @@ do
done
touch sssd_tools.lang
+touch sssd_client.lang
for man in `find $RPM_BUILD_ROOT/%{_mandir}/??/man?/ -type f | sed -e "s#$RPM_BUILD_ROOT/%{_mandir}/##"`
do
lang=`echo $man | cut -c 1-2`
@@ -258,6 +301,9 @@ do
sss_*)
echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_tools.lang
;;
+ sssd_krb5_*)
+ echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_client.lang
+ ;;
pam_sss*)
echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_client.lang
;;
@@ -291,6 +337,7 @@ rm -rf $RPM_BUILD_ROOT
%{_unitdir}/sssd.service
%{_sbindir}/sssd
+%dir %{_libexecdir}/%{servicename}
%{_libexecdir}/%{servicename}/krb5_child
%{_libexecdir}/%{servicename}/ldap_child
%{_libexecdir}/%{servicename}/proxy_child
@@ -300,12 +347,15 @@ rm -rf $RPM_BUILD_ROOT
%{_libexecdir}/%{servicename}/sssd_autofs
%{_libexecdir}/%{servicename}/sssd_ssh
%{_libexecdir}/%{servicename}/sssd_sudo
+%{_libexecdir}/%{servicename}/sssd_pac
+%dir %{_libdir}/%{name}
%{_libdir}/%{name}/libsss_ipa.so
%{_libdir}/%{name}/libsss_krb5.so
%{_libdir}/%{name}/libsss_ldap.so
%{_libdir}/%{name}/libsss_proxy.so
%{_libdir}/%{name}/libsss_simple.so
+%{_libdir}/%{name}/libsss_ad.so
%{ldb_modulesdir}/memberof.so
%{_bindir}/sss_ssh_authorizedkeys
@@ -314,14 +364,19 @@ rm -rf $RPM_BUILD_ROOT
%dir %{sssdstatedir}
%dir %{_localstatedir}/cache/krb5rcache
%attr(700,root,root) %dir %{dbpath}
+%attr(755,root,root) %dir %{mcpath}
+%ghost %attr(0644,root,root) %verify(not md5 size mtime) %{mcpath}/passwd
+%ghost %attr(0644,root,root) %verify(not md5 size mtime) %{mcpath}/group
%attr(755,root,root) %dir %{pipepath}
%attr(755,root,root) %dir %{pubconfpath}
+%attr(755,root,root) %dir %{pubconfpath}/krb5.include.d
%attr(700,root,root) %dir %{pipepath}/private
%attr(750,root,root) %dir %{_var}/log/%{name}
%attr(700,root,root) %dir %{_sysconfdir}/sssd
%ghost %attr(0600,root,root) %config(noreplace) %{_sysconfdir}/sssd/sssd.conf
%config(noreplace) %{_sysconfdir}/logrotate.d/sssd
%config(noreplace) %{_sysconfdir}/rwtab.d/sssd
+%dir %{_datadir}/sssd
%{_datadir}/sssd/sssd.api.conf
%{_datadir}/sssd/sssd.api.d
%{_mandir}/man1/sss_ssh_authorizedkeys.1*
@@ -331,9 +386,13 @@ rm -rf $RPM_BUILD_ROOT
%{_mandir}/man5/sssd-krb5.5*
%{_mandir}/man5/sssd-ldap.5*
%{_mandir}/man5/sssd-simple.5*
+%{_mandir}/man5/sssd-ad.5*
+%{_mandir}/man5/sssd-sudo.5*
%{_mandir}/man8/sssd.8*
%{python_sitearch}/pysss.so
-%{python_sitelib}/*.py*
+%{python_sitearch}/pysss_murmur.so
+%dir %{python_sitelib}/SSSDConfig
+%{python_sitelib}/SSSDConfig/*.py*
%files client -f sssd_client.lang
%defattr(-,root,root,-)
@@ -341,6 +400,7 @@ rm -rf $RPM_BUILD_ROOT
/%{_lib}/libnss_sss.so.2
/%{_lib}/security/pam_sss.so
%{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so
+%{_libdir}/krb5/plugins/authdata/sssd_pac_plugin.so
%{_mandir}/man8/pam_sss.8*
%{_mandir}/man8/sssd_krb5_locator_plugin.8*
@@ -357,6 +417,7 @@ rm -rf $RPM_BUILD_ROOT
%{_sbindir}/sss_obfuscate
%{_sbindir}/sss_cache
%{_sbindir}/sss_debuglevel
+%{_sbindir}/sss_seed
%{_mandir}/man8/sss_groupadd.8*
%{_mandir}/man8/sss_groupdel.8*
%{_mandir}/man8/sss_groupmod.8*
@@ -367,6 +428,19 @@ rm -rf $RPM_BUILD_ROOT
%{_mandir}/man8/sss_obfuscate.8*
%{_mandir}/man8/sss_cache.8*
%{_mandir}/man8/sss_debuglevel.8*
+%{_mandir}/man8/sss_seed.8*
+
+%files -n libsss_idmap
+%defattr(-,root,root,-)
+%doc src/sss_client/COPYING src/sss_client/COPYING.LESSER
+%{_libdir}/libsss_idmap.so.*
+
+%files -n libsss_idmap-devel
+%defattr(-,root,root,-)
+%doc idmap_doc/html
+%{_includedir}/sss_idmap.h
+%{_libdir}/libsss_idmap.so
+%{_libdir}/pkgconfig/sss_idmap.pc
%files -n libipa_hbac
%defattr(-,root,root,-)
@@ -395,13 +469,11 @@ A utility library to allow communication between Autofs and SSSD
%files -n libsss_sudo
%defattr(-,root,root,-)
%doc src/sss_client/COPYING src/sss_client/COPYING.LESSER
-%{_libdir}/libsss_sudo.so.*
+%{_libdir}/libsss_sudo.so*
%files -n libsss_sudo-devel
%doc libsss_sudo_doc/html
%{_includedir}/sss_sudo.h
-%{_libdir}/libsss_sudo.so
-%{_libdir}/pkgconfig/libsss_sudo.pc
%files -n libsss_autofs
%defattr(-,root,root,-)
@@ -409,15 +481,13 @@ A utility library to allow communication between Autofs and SSSD
%{_libdir}/sssd/modules/libsss_autofs.so*
%post
-/sbin/ldconfig
-
if [ $1 -ge 1 ] ; then
# Initial installation
/bin/systemctl daemon-reload >/dev/null 2>&1 || :
fi
%preun
-if [ $1 = 0 ]; then
+if [ $1 -eq 0 ]; then
# Package removal, not upgrade
/bin/systemctl --no-reload disable sssd.service > /dev/null 2>&1 || :
/bin/systemctl stop sssd.service > /dev/null 2>&1 || :
@@ -437,11 +507,8 @@ fi
%postun
-/sbin/ldconfig
/bin/systemctl daemon-reload >/dev/null 2>&1 || :
if [ $1 -ge 1 ] ; then
- # On upgrade, reload init system configuration if we changed unit files
- /bin/systemctl daemon-reload >/dev/null 2>&1 || :
/bin/systemctl try-restart sssd.service >/dev/null 2>&1 || :
fi
@@ -453,7 +520,19 @@ fi
%postun -n libipa_hbac -p /sbin/ldconfig
+%post -n libsss_idmap -p /sbin/ldconfig
+
+%postun -n libsss_idmap -p /sbin/ldconfig
+
+%post -n libsss_sudo -p /sbin/ldconfig
+
+%postun -n libsss_sudo -p /sbin/ldconfig
+
%changelog
+* Mon Mar 25 2013 Jakub Hrozek <jhrozek at redhat.com> - 1.9.4-1
+- New upstream release 1.9.4
+- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.9.4
+
* Tue Jan 29 2013 Jakub Hrozek <jhrozek at redhat.com> - 1.8.6-1
- New upstream release 1.8.6
- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.8.6
More information about the scm-commits
mailing list