From bb7cd1535b208c22ad8c1541bee2b4b1f279474a Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Aug 01 2017 03:49:14 +0000 Subject: import sssd-1.15.2-50.el7 --- diff --git a/.gitignore b/.gitignore index f71df95..bae0ba3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/sssd-1.14.0.tar.gz +SOURCES/sssd-1.15.2.tar.gz diff --git a/.sssd.metadata b/.sssd.metadata index 26fd024..bc1073e 100644 --- a/.sssd.metadata +++ b/.sssd.metadata @@ -1 +1 @@ -4ddb4403b07125f413181c43d8d2208c3128924d SOURCES/sssd-1.14.0.tar.gz +f94298ac05169cdf5a9082c3aba9f6a18513720a SOURCES/sssd-1.15.2.tar.gz diff --git a/SOURCES/0001-MAN-Mention-sssd-secrets-in-SEE-ALSO-section.patch b/SOURCES/0001-MAN-Mention-sssd-secrets-in-SEE-ALSO-section.patch new file mode 100644 index 0000000..e405016 --- /dev/null +++ b/SOURCES/0001-MAN-Mention-sssd-secrets-in-SEE-ALSO-section.patch @@ -0,0 +1,36 @@ +From 1bf225166db64e81fe94cbee0fd3b1dc124717f4 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 21 Mar 2017 12:27:16 +0100 +Subject: [PATCH 01/15] MAN: Mention sssd-secrets in "SEE ALSO" section +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves: +https://pagure.io/SSSD/sssd/issue/3344 + +Reviewed-by: Fabiano Fidêncio +--- + src/man/include/seealso.xml | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/man/include/seealso.xml b/src/man/include/seealso.xml +index 25b421748fb19881552de8b6384af2c794063e11..2e9c646c475887bce3612472975ade375edbd819 100644 +--- a/src/man/include/seealso.xml ++++ b/src/man/include/seealso.xml +@@ -28,6 +28,12 @@ + 5 + , + ++ ++ ++ sssd-secrets ++ 5 ++ , ++ + + sss_cache8 + , +-- +2.9.3 + diff --git a/SOURCES/0001-SYSDB-Fixing-DB-update.patch b/SOURCES/0001-SYSDB-Fixing-DB-update.patch deleted file mode 100644 index f4df02a..0000000 --- a/SOURCES/0001-SYSDB-Fixing-DB-update.patch +++ /dev/null @@ -1,71 +0,0 @@ -From dc8e4131f73d62f23a4be7148e24315adbc550e4 Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Mon, 20 Jun 2016 09:19:03 -0300 -Subject: [PATCH 01/18] SYSDB: Fixing DB update -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Functions sysdb_user_base_dn() and sysdb_group_base_dn() expect -that struct sss_domain_info contains pointer to struct sysdb_ctx. -This is not true in case of sysdb_upgrade functions. -This patch fixes the situation and revert code to the state before -12a000c8c7c07259e438fb1e992134bdd07d9a30 commit. - -Resolves: -https://fedorahosted.org/sssd/ticket/3023 - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Sumit Bose -(cherry picked from commit 311836214245600566f881ff6253594e0999008e) ---- - src/db/sysdb_upgrade.c | 22 +++++++++++++++++++--- - 1 file changed, 19 insertions(+), 3 deletions(-) - -diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c -index 1d2978caee4512856fb64c4798a4b031bf6a3af1..4ca8433f9d5430b038f90563c34cede02393b0b0 100644 ---- a/src/db/sysdb_upgrade.c -+++ b/src/db/sysdb_upgrade.c -@@ -443,12 +443,23 @@ int sysdb_check_upgrade_02(struct sss_domain_info *domains, - goto done; - } - -- users_dn = sysdb_user_base_dn(tmp_ctx, dom); -+ /* -+ * dom->sysdb->ldb is not initialized, -+ * so ldb_dn_new_fmt() shouldn't be changed to sysdb_*_base_dn() -+ */ -+ users_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, -+ SYSDB_TMPL_USER_BASE, dom->name); - if (!users_dn) { - ret = ENOMEM; - goto done; - } -- groups_dn = sysdb_group_base_dn(tmp_ctx, dom); -+ -+ /* -+ * dom->sysdb->ldb is not initialized, -+ * so ldb_dn_new_fmt() shouldn't be changed to sysdb_*_base_dn() -+ */ -+ groups_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, -+ SYSDB_TMPL_GROUP_BASE, dom->name); - if (!groups_dn) { - ret = ENOMEM; - goto done; -@@ -1045,7 +1056,12 @@ int sysdb_upgrade_10(struct sysdb_ctx *sysdb, struct sss_domain_info *domain, - return ret; - } - -- basedn = sysdb_user_base_dn(tmp_ctx, domain); -+ /* -+ * dom->sysdb->ldb is not initialized, -+ * so ldb_dn_new_fmt() shouldn't be changed to sysdb_*_base_dn() -+ */ -+ basedn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, -+ SYSDB_TMPL_USER_BASE, domain->name); - if (basedn == NULL) { - ret = EIO; - goto done; --- -2.4.11 - diff --git a/SOURCES/0002-split_on_separator-move-to-a-separate-file.patch b/SOURCES/0002-split_on_separator-move-to-a-separate-file.patch new file mode 100644 index 0000000..24961c7 --- /dev/null +++ b/SOURCES/0002-split_on_separator-move-to-a-separate-file.patch @@ -0,0 +1,369 @@ +From 4f98b36562fb02f95c9af7af6fde548334ce9c34 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 8 Feb 2017 14:28:28 +0100 +Subject: [PATCH 02/15] split_on_separator: move to a separate file +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To be able to include split_on_separator() without additional +dependencies (only talloc), it is moved into a separate file. + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +--- + Makefile.am | 30 ++++++++++--- + src/util/util.c | 93 ---------------------------------------- + src/util/util_ext.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 144 insertions(+), 100 deletions(-) + create mode 100644 src/util/util_ext.c + +diff --git a/Makefile.am b/Makefile.am +index 45b04de2638a745a189c0b4e5794ccd29913b10d..6dae4f2dd7f2dee501add82c7ab4f15fcbcc59ac 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -987,6 +987,7 @@ libsss_util_la_SOURCES = \ + src/sbus/sssd_dbus_common_signals.c \ + src/sbus/sssd_dbus_utils.c \ + src/util/util.c \ ++ src/util/util_ext.c \ + src/util/memory.c \ + src/util/safe-format-string.c \ + src/util/server.c \ +@@ -2355,19 +2356,23 @@ test_authtok_SOURCES = \ + src/tests/cmocka/test_authtok.c \ + src/util/authtok.c \ + src/util/authtok-utils.c \ +- src/util/util.c ++ src/util/util.c \ ++ src/util/util_ext.c \ ++ $(NULL) + test_authtok_CFLAGS = \ + $(AM_CFLAGS) \ + $(TALLOC_CFLAGS) \ + $(POPT_CFLAGS) \ +- $(DHASH_CFLAGS) ++ $(DHASH_CFLAGS) \ ++ $(NULL) + test_authtok_LDADD = \ + $(TALLOC_LIBS) \ + $(CMOCKA_LIBS) \ + $(DHASH_LIBS) \ + $(POPT_LIBS) \ + libsss_test_common.la \ +- libsss_debug.la ++ libsss_debug.la \ ++ $(NULL) + + sss_nss_idmap_tests_SOURCES = \ + src/tests/cmocka/sss_nss_idmap-tests.c +@@ -2839,6 +2844,7 @@ test_child_common_SOURCES = \ + src/util/atomic_io.c \ + src/util/util_errors.c \ + src/util/util.c \ ++ src/util/util_ext.c \ + $(NULL) + test_child_common_CFLAGS = \ + $(AM_CFLAGS) \ +@@ -3774,6 +3780,7 @@ krb5_child_SOURCES = \ + src/util/authtok.c \ + src/util/authtok-utils.c \ + src/util/util.c \ ++ src/util/util_ext.c \ + src/util/signal.c \ + src/util/strtonum.c \ + src/util/become_user.c \ +@@ -3807,6 +3814,7 @@ ldap_child_SOURCES = \ + src/util/authtok.c \ + src/util/authtok-utils.c \ + src/util/util.c \ ++ src/util/util_ext.c \ + src/util/signal.c \ + src/util/become_user.c \ + $(NULL) +@@ -3827,6 +3835,7 @@ selinux_child_SOURCES = \ + src/util/sss_semanage.c \ + src/util/atomic_io.c \ + src/util/util.c \ ++ src/util/util_ext.c \ + $(NULL) + selinux_child_CFLAGS = \ + $(AM_CFLAGS) \ +@@ -3845,6 +3854,7 @@ gpo_child_SOURCES = \ + src/providers/ad/ad_gpo_child.c \ + src/util/atomic_io.c \ + src/util/util.c \ ++ src/util/util_ext.c \ + src/util/signal.c + gpo_child_CFLAGS = \ + $(AM_CFLAGS) \ +@@ -3876,6 +3886,7 @@ p11_child_SOURCES = \ + src/p11_child/p11_child_nss.c \ + src/util/atomic_io.c \ + src/util/util.c \ ++ src/util/util_ext.c \ + $(NULL) + p11_child_CFLAGS = \ + $(AM_CFLAGS) \ +@@ -3893,16 +3904,21 @@ p11_child_LDADD = \ + + memberof_la_SOURCES = \ + src/ldb_modules/memberof.c \ +- src/util/util.c ++ src/util/util.c \ ++ src/util/util_ext.c \ ++ $(NULL) + memberof_la_CFLAGS = \ +- $(AM_CFLAGS) ++ $(AM_CFLAGS) \ ++ $(NULL) + memberof_la_LIBADD = \ + libsss_debug.la \ + $(LDB_LIBS) \ +- $(DHASH_LIBS) ++ $(DHASH_LIBS) \ ++ $(NULL) + memberof_la_LDFLAGS = \ + -avoid-version \ +- -module ++ -module \ ++ $(NULL) + + if BUILD_KRB5_LOCATOR_PLUGIN + sssd_krb5_locator_plugin_la_SOURCES = \ +diff --git a/src/util/util.c b/src/util/util.c +index a528f0c0249c33bfc3d3275250e74d5edcef2e6f..9d6202f695d516f20d648621da81a2d5e746daa5 100644 +--- a/src/util/util.c ++++ b/src/util/util.c +@@ -35,99 +35,6 @@ + int socket_activated = 0; + int dbus_activated = 0; + +-int split_on_separator(TALLOC_CTX *mem_ctx, const char *str, +- const char sep, bool trim, bool skip_empty, +- char ***_list, int *size) +-{ +- int ret; +- const char *substr_end = str; +- const char *substr_begin = str; +- const char *sep_pos = NULL; +- size_t substr_len; +- char **list = NULL; +- int num_strings = 0; +- TALLOC_CTX *tmp_ctx = NULL; +- +- if (str == NULL || *str == '\0' || _list == NULL) { +- return EINVAL; +- } +- +- tmp_ctx = talloc_new(NULL); +- if (tmp_ctx == NULL) { +- return ENOMEM; +- } +- +- do { +- substr_len = 0; +- +- /* If this is not the first substring, then move from the separator. */ +- if (sep_pos != NULL) { +- substr_end = sep_pos + 1; +- substr_begin = sep_pos + 1; +- } +- +- /* Find end of the first substring */ +- while (*substr_end != sep && *substr_end != '\0') { +- substr_end++; +- substr_len++; +- } +- +- sep_pos = substr_end; +- +- if (trim) { +- /* Trim leading whitespace */ +- while (isspace(*substr_begin) && substr_begin < substr_end) { +- substr_begin++; +- substr_len--; +- } +- +- /* Trim trailing whitespace */ +- while (substr_end - 1 > substr_begin && isspace(*(substr_end-1))) { +- substr_end--; +- substr_len--; +- } +- } +- +- /* 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) { +- 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) { +- ret = ENOMEM; +- goto done; +- } +- num_strings++; +- } +- +- } while (*sep_pos != '\0'); +- +- if (list == NULL) { +- /* No allocations were done, make space for the NULL */ +- list = talloc(tmp_ctx, char *); +- if (list == NULL) { +- ret = ENOMEM; +- goto done; +- } +- } +- list[num_strings] = NULL; +- +- if (size) { +- *size = num_strings; +- } +- +- *_list = talloc_steal(mem_ctx, list); +- ret = EOK; +-done: +- talloc_free(tmp_ctx); +- return ret; +-} +- + static void free_args(char **args) + { + int i; +diff --git a/src/util/util_ext.c b/src/util/util_ext.c +new file mode 100644 +index 0000000000000000000000000000000000000000..fceb8c873a26471d476b39d5d4e567c445ed8d0b +--- /dev/null ++++ b/src/util/util_ext.c +@@ -0,0 +1,121 @@ ++/* ++ SSSD helper calls - can be used by libraries for external use as well ++ ++ Authors: ++ Simo Sorce ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++#include ++#include ++#include ++#include ++ ++#define EOK 0 ++ ++int split_on_separator(TALLOC_CTX *mem_ctx, const char *str, ++ const char sep, bool trim, bool skip_empty, ++ char ***_list, int *size) ++{ ++ int ret; ++ const char *substr_end = str; ++ const char *substr_begin = str; ++ const char *sep_pos = NULL; ++ size_t substr_len; ++ char **list = NULL; ++ int num_strings = 0; ++ TALLOC_CTX *tmp_ctx = NULL; ++ ++ if (str == NULL || *str == '\0' || _list == NULL) { ++ return EINVAL; ++ } ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ do { ++ substr_len = 0; ++ ++ /* If this is not the first substring, then move from the separator. */ ++ if (sep_pos != NULL) { ++ substr_end = sep_pos + 1; ++ substr_begin = sep_pos + 1; ++ } ++ ++ /* Find end of the first substring */ ++ while (*substr_end != sep && *substr_end != '\0') { ++ substr_end++; ++ substr_len++; ++ } ++ ++ sep_pos = substr_end; ++ ++ if (trim) { ++ /* Trim leading whitespace */ ++ while (isspace(*substr_begin) && substr_begin < substr_end) { ++ substr_begin++; ++ substr_len--; ++ } ++ ++ /* Trim trailing whitespace */ ++ while (substr_end - 1 > substr_begin && isspace(*(substr_end-1))) { ++ substr_end--; ++ substr_len--; ++ } ++ } ++ ++ /* 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) { ++ 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) { ++ ret = ENOMEM; ++ goto done; ++ } ++ num_strings++; ++ } ++ ++ } while (*sep_pos != '\0'); ++ ++ if (list == NULL) { ++ /* No allocations were done, make space for the NULL */ ++ list = talloc(tmp_ctx, char *); ++ if (list == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ list[num_strings] = NULL; ++ ++ if (size) { ++ *size = num_strings; ++ } ++ ++ *_list = talloc_steal(mem_ctx, list); ++ ret = EOK; ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} +-- +2.9.3 + diff --git a/SOURCES/0002-sssctl-Fix-error-handling-after-memory-allocation-fa.patch b/SOURCES/0002-sssctl-Fix-error-handling-after-memory-allocation-fa.patch deleted file mode 100644 index 4590e63..0000000 --- a/SOURCES/0002-sssctl-Fix-error-handling-after-memory-allocation-fa.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 36adb8fdc1e0ec14d394a2c51be16c90f4fa1acd Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Fri, 8 Jul 2016 12:16:47 +0200 -Subject: [PATCH 02/18] sssctl: Fix error handling after memory allocation - failure -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Pavel Březina -(cherry picked from commit 4b18d0c25471150940c1a552bc2504ff9debb703) ---- - src/tools/sssctl/sssctl_cache.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c -index 9f626d983a4672cf00fba6b3171b822e8f6e02bd..28de6c139d844f98f9b06844492c935696e19643 100644 ---- a/src/tools/sssctl/sssctl_cache.c -+++ b/src/tools/sssctl/sssctl_cache.c -@@ -364,8 +364,9 @@ static errno_t sssctl_find_object(TALLOC_CTX *mem_ctx, - filter = talloc_asprintf(tmp_ctx, "(&(objectClass=%s)(%s=%s))", - class, attr_name, filter_value); - talloc_free(filter_value); -- if (filter_value == NULL) { -+ if (filter == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n"); -+ ret = ENOMEM; - goto done; - } - --- -2.4.11 - diff --git a/SOURCES/0003-sssctl-config-check-access-check-report.patch b/SOURCES/0003-sssctl-config-check-access-check-report.patch deleted file mode 100644 index 3a564f8..0000000 --- a/SOURCES/0003-sssctl-config-check-access-check-report.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0df858e26420bc6fb49819572694fced6791d414 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Thu, 7 Jul 2016 15:43:11 +0200 -Subject: [PATCH 03/18] sssctl: config-check access check report -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Improve output when access check error -is detected by sssctl config-check command. - -Reviewed-by: Pavel Březina -(cherry picked from commit 9dc66cb6b96a885f7272a3c4aa6a44d60cdce82c) ---- - src/tools/sssctl/sssctl_config.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/tools/sssctl/sssctl_config.c b/src/tools/sssctl/sssctl_config.c -index fc13582accd63f58c9d8bce59c4d6e898a96b170..4f6dbcdd7d04183c65b6613efbe5ab95df19e2c7 100644 ---- a/src/tools/sssctl/sssctl_config.c -+++ b/src/tools/sssctl/sssctl_config.c -@@ -68,7 +68,8 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline, - /* Check the file permissions */ - ret = sss_ini_config_access_check(init_data); - if (ret != EOK) { -- printf(_("Access check on sssd.conf file failed.\n")); -+ printf(_("File ownership and permissions check failed. " -+ "Expected root:root and 0600.\n")); - ret = EPERM; - goto done; - } --- -2.4.11 - diff --git a/SOURCES/0003-util-move-string_in_list-to-util_ext.patch b/SOURCES/0003-util-move-string_in_list-to-util_ext.patch new file mode 100644 index 0000000..f21cb03 --- /dev/null +++ b/SOURCES/0003-util-move-string_in_list-to-util_ext.patch @@ -0,0 +1,91 @@ +From 7bf6cf5632fbdf83a37c52c40b7b982094b5c668 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 20 Feb 2017 17:28:51 +0100 +Subject: [PATCH 03/15] util: move string_in_list to util_ext +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To be able to include string_in_list() without additional +dependencies it is moved into a separate file. + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +--- + src/util/util.c | 20 -------------------- + src/util/util_ext.c | 22 ++++++++++++++++++++++ + 2 files changed, 22 insertions(+), 20 deletions(-) + +diff --git a/src/util/util.c b/src/util/util.c +index 9d6202f695d516f20d648621da81a2d5e746daa5..f0e8f9dd6a4bceed6befb74c57aa066b19a72bb7 100644 +--- a/src/util/util.c ++++ b/src/util/util.c +@@ -617,26 +617,6 @@ errno_t add_string_to_list(TALLOC_CTX *mem_ctx, const char *string, + return EOK; + } + +-bool string_in_list(const char *string, char **list, bool case_sensitive) +-{ +- size_t c; +- int(*compare)(const char *s1, const char *s2); +- +- if (string == NULL || list == NULL || *list == NULL) { +- return false; +- } +- +- compare = case_sensitive ? strcmp : strcasecmp; +- +- for (c = 0; list[c] != NULL; c++) { +- if (compare(string, list[c]) == 0) { +- return true; +- } +- } +- +- return false; +-} +- + void safezero(void *data, size_t size) + { + volatile uint8_t *p = data; +diff --git a/src/util/util_ext.c b/src/util/util_ext.c +index fceb8c873a26471d476b39d5d4e567c445ed8d0b..04dc02a8adf32bd0590fe6eba230658e67d0a362 100644 +--- a/src/util/util_ext.c ++++ b/src/util/util_ext.c +@@ -24,6 +24,8 @@ + #include + #include + #include ++#include ++#include + + #define EOK 0 + +@@ -119,3 +121,23 @@ done: + talloc_free(tmp_ctx); + return ret; + } ++ ++bool string_in_list(const char *string, char **list, bool case_sensitive) ++{ ++ size_t c; ++ int(*compare)(const char *s1, const char *s2); ++ ++ if (string == NULL || list == NULL || *list == NULL) { ++ return false; ++ } ++ ++ compare = case_sensitive ? strcmp : strcasecmp; ++ ++ for (c = 0; list[c] != NULL; c++) { ++ if (compare(string, list[c]) == 0) { ++ return true; ++ } ++ } ++ ++ return false; ++} +-- +2.9.3 + diff --git a/SOURCES/0004-FO-Set-port-to-NOT_WORKING-when-trying-a-next-server.patch b/SOURCES/0004-FO-Set-port-to-NOT_WORKING-when-trying-a-next-server.patch deleted file mode 100644 index e7bf9c3..0000000 --- a/SOURCES/0004-FO-Set-port-to-NOT_WORKING-when-trying-a-next-server.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 95939e9831fb3d9a8f464ecff3377dd6027e0321 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 10 May 2016 14:11:36 +0200 -Subject: [PATCH 04/18] FO: Set port to NOT_WORKING when trying a next server -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: https://fedorahosted.org/sssd/ticket/3009 - -Reviewed-by: Pavel Březina -(cherry picked from commit c420ce830ac0b0b288a2a887ec2cfce5c748018c) ---- - src/providers/fail_over.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c -index e945c9924597c7addeeb11090e1c1aee5596cb71..1d88d2aa54bfdebd4b648e2b13fa8d03e2be3973 100644 ---- a/src/providers/fail_over.c -+++ b/src/providers/fail_over.c -@@ -1546,7 +1546,7 @@ void fo_try_next_server(struct fo_service *service) - service->active_server = 0; - - if (server->port_status == PORT_WORKING) { -- server->port_status = PORT_NEUTRAL; -+ server->port_status = PORT_NOT_WORKING; - } - } - --- -2.4.11 - diff --git a/SOURCES/0004-certmap-add-new-library-libsss_certmap.patch b/SOURCES/0004-certmap-add-new-library-libsss_certmap.patch new file mode 100644 index 0000000..1a04fe7 --- /dev/null +++ b/SOURCES/0004-certmap-add-new-library-libsss_certmap.patch @@ -0,0 +1,5787 @@ +From 64d74f65ca66fafd67c99ac17c5e45e584f59d83 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 2 Feb 2017 11:24:02 +0100 +Subject: [PATCH 04/15] certmap: add new library libsss_certmap +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With this library it would be possible to map certificates and users not +only by adding the full certificate to the user's LDAP object but by +adding e.g. only parts like the issuer and subject name. Additionally +the library is also able to flexible select/match certificates based on +values in the certificate. + +Details about mapping and matching rules can be found in the included +man page. + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +--- + Makefile.am | 55 ++ + configure.ac | 1 + + contrib/sssd.spec.in | 32 + + src/lib/certmap/sss_cert_content_nss.c | 1014 +++++++++++++++++++ + src/lib/certmap/sss_certmap.c | 993 +++++++++++++++++++ + src/lib/certmap/sss_certmap.doxy.in | 3 + + src/lib/certmap/sss_certmap.exports | 13 + + src/lib/certmap/sss_certmap.h | 155 +++ + src/lib/certmap/sss_certmap.pc.in | 11 + + src/lib/certmap/sss_certmap_attr_names.c | 107 +++ + src/lib/certmap/sss_certmap_int.h | 187 ++++ + src/lib/certmap/sss_certmap_krb5_match.c | 558 +++++++++++ + src/lib/certmap/sss_certmap_ldap_mapping.c | 367 +++++++ + src/man/Makefile.am | 2 +- + src/man/po/po4a.cfg | 1 + + src/man/sss-certmap.5.xml | 600 ++++++++++++ + src/tests/cmocka/test_certmap.c | 1443 ++++++++++++++++++++++++++++ + src/tests/dlopen-tests.c | 1 + + 18 files changed, 5542 insertions(+), 1 deletion(-) + create mode 100644 src/lib/certmap/sss_cert_content_nss.c + create mode 100644 src/lib/certmap/sss_certmap.c + create mode 100644 src/lib/certmap/sss_certmap.doxy.in + create mode 100644 src/lib/certmap/sss_certmap.exports + create mode 100644 src/lib/certmap/sss_certmap.h + create mode 100644 src/lib/certmap/sss_certmap.pc.in + create mode 100644 src/lib/certmap/sss_certmap_attr_names.c + create mode 100644 src/lib/certmap/sss_certmap_int.h + create mode 100644 src/lib/certmap/sss_certmap_krb5_match.c + create mode 100644 src/lib/certmap/sss_certmap_ldap_mapping.c + create mode 100644 src/man/sss-certmap.5.xml + create mode 100644 src/tests/cmocka/test_certmap.c + +diff --git a/Makefile.am b/Makefile.am +index 6dae4f2dd7f2dee501add82c7ab4f15fcbcc59ac..8ca12c10d2713b6a72361d84b25486500c79f407 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -278,6 +278,7 @@ if HAVE_CMOCKA + simple-access-tests \ + krb5_common_test \ + test_iobuf \ ++ sss_certmap_test \ + $(NULL) + + if HAVE_LIBRESOLV +@@ -1074,6 +1075,7 @@ SSSD_INTERNAL_LTLIBS = \ + lib_LTLIBRARIES = libipa_hbac.la \ + libsss_idmap.la \ + libsss_nss_idmap.la \ ++ libsss_certmap.la \ + $(NULL) + + pkgconfig_DATA += src/lib/ipa_hbac/ipa_hbac.pc +@@ -1128,6 +1130,7 @@ include_HEADERS = \ + src/lib/ipa_hbac/ipa_hbac.h \ + src/lib/idmap/sss_idmap.h \ + src/sss_client/idmap/sss_nss_idmap.h \ ++ src/lib/certmap/sss_certmap.h \ + $(NULL) + + if BUILD_LIBWBCLIENT +@@ -1712,6 +1715,38 @@ sssd_check_socket_activated_responders_LDADD = \ + $(NULL) + endif + ++if HAVE_NSS ++pkgconfig_DATA += src/lib/certmap/sss_certmap.pc ++libsss_certmap_la_DEPENDENCIES = src/lib/certmap/sss_certmap.exports ++libsss_certmap_la_SOURCES = \ ++ src/lib/certmap/sss_certmap.c \ ++ src/lib/certmap/sss_certmap_attr_names.c \ ++ src/lib/certmap/sss_cert_content_nss.c \ ++ src/lib/certmap/sss_certmap_krb5_match.c \ ++ src/lib/certmap/sss_certmap_ldap_mapping.c \ ++ src/util/util_ext.c \ ++ src/util/cert/cert_common.c \ ++ src/util/crypto/nss/nss_base64.c \ ++ src/util/cert/nss/cert.c \ ++ src/util/crypto/nss/nss_util.c \ ++ $(NULL) ++libsss_certmap_la_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(TALLOC_CFLAGS) \ ++ $(NSS_CFLAGS) \ ++ $(NULL) ++libsss_certmap_la_LIBADD = \ ++ $(TALLOC_LIBS) \ ++ $(NSS_LIBS) \ ++ $(NULL) ++libsss_certmap_la_LDFLAGS = \ ++ -Wl,--version-script,$(srcdir)/src/lib/certmap/sss_certmap.exports \ ++ -version-info 0:0:0 ++ ++dist_noinst_DATA += src/lib/certmap/sss_certmap.exports ++dist_noinst_HEADERS += src/lib/certmap/sss_certmap_int.h ++endif ++ + ################# + # Feature Tests # + ################# +@@ -3245,6 +3280,25 @@ test_inotify_LDADD = \ + libsss_test_common.la \ + $(NULL) + ++if HAVE_NSS ++sss_certmap_test_SOURCES = \ ++ src/tests/cmocka/test_certmap.c \ ++ src/lib/certmap/sss_certmap_attr_names.c \ ++ $(NULL) ++sss_certmap_test_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(NSS_CFLAGS) \ ++ $(NULL) ++sss_certmap_test_LDADD = \ ++ $(CMOCKA_LIBS) \ ++ $(POPT_LIBS) \ ++ $(TALLOC_LIBS) \ ++ $(NSS_LIBS) \ ++ $(SSSD_INTERNAL_LTLIBS) \ ++ libsss_test_common.la \ ++ libsss_certmap.la \ ++ $(NULL) ++endif + endif # HAVE_CMOCKA + + noinst_PROGRAMS = pam_test_client +@@ -4404,6 +4458,7 @@ docs: + $(DOXYGEN) src/lib/ipa_hbac/ipa_hbac.doxy + $(DOXYGEN) src/lib/idmap/sss_idmap.doxy + $(DOXYGEN) src/sss_client/idmap/sss_nss_idmap.doxy ++ $(DOXYGEN) src/lib/certmap/sss_certmap.doxy + if BUILD_IFP + $(DOXYGEN) src/lib/sifp/sss_simpleifp.doxy + endif +diff --git a/configure.ac b/configure.ac +index e6a3b4e857bcbec16873f54008e6b42aeb9b7cd7..dd1012015a5fea9f25e5b5199b4868fbc0bc14c4 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -483,6 +483,7 @@ AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config + src/tests/intg/Makefile + src/lib/ipa_hbac/ipa_hbac.pc src/lib/ipa_hbac/ipa_hbac.doxy + src/lib/idmap/sss_idmap.pc src/lib/idmap/sss_idmap.doxy ++ src/lib/certmap/sss_certmap.pc src/lib/certmap/sss_certmap.doxy + src/sss_client/idmap/sss_nss_idmap.pc + src/sss_client/idmap/sss_nss_idmap.doxy + src/sss_client/libwbclient/wbclient_sssd.pc +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index 5bd2beb89014ba7c86b4231f0357a7a6e10a18a8..28ebe07a26a3112210b092b7831e7f6aae061c8d 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -658,6 +658,25 @@ The libnfsidmap sssd module provides a way for rpc.idmapd to call SSSD to map + UIDs/GIDs to names and vice versa. It can be also used for mapping principal + (user) name to IDs(UID or GID) or to obtain groups which user are member of. + ++%package -n libsss_certmap ++Summary: SSSD Certficate Mapping Library ++Group: Development/Libraries ++License: LGPLv3+ ++Requires(post): /sbin/ldconfig ++Requires(postun): /sbin/ldconfig ++ ++%description -n libsss_certmap ++Library to map certificates to users based on rules ++ ++%package -n libsss_certmap-devel ++Summary: SSSD Certficate Mapping Library ++Group: Development/Libraries ++License: LGPLv3+ ++Requires: libsss_certmap = %{version}-%{release} ++ ++%description -n libsss_certmap-devel ++Library to map certificates to users based on rules ++ + %prep + %setup -q -n %{name}-%{version} + +@@ -888,6 +907,7 @@ done + %{_datadir}/sssd/sssd.api.d + %{_mandir}/man1/sss_ssh_authorizedkeys.1* + %{_mandir}/man1/sss_ssh_knownhostsproxy.1* ++%{_mandir}/man5/sss-certmap.5* + %{_mandir}/man5/sssd.conf.5* + %{_mandir}/man5/sssd-simple.5* + %{_mandir}/man5/sssd-sudo.5* +@@ -1146,6 +1166,18 @@ done + %files nfs-idmap + %{_libdir}/libnfsidmap/sss.so + ++%files -n libsss_certmap ++%defattr(-,root,root,-) ++%doc src/sss_client/COPYING src/sss_client/COPYING.LESSER ++%{_libdir}/libsss_certmap.so.* ++ ++%files -n libsss_certmap-devel ++%defattr(-,root,root,-) ++%doc certmap_doc/html ++%{_includedir}/sss_certmap.h ++%{_libdir}/libsss_certmap.so ++%{_libdir}/pkgconfig/sss_certmap.pc ++ + %pre common + getent group sssd >/dev/null || groupadd -r sssd + getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd +diff --git a/src/lib/certmap/sss_cert_content_nss.c b/src/lib/certmap/sss_cert_content_nss.c +new file mode 100644 +index 0000000000000000000000000000000000000000..d3182895465706c87503b8abb0cea49b7677625d +--- /dev/null ++++ b/src/lib/certmap/sss_cert_content_nss.c +@@ -0,0 +1,1014 @@ ++/* ++ SSSD - certificate handling utils - NSS version ++ The calls defined here should be useable outside of SSSD as well, e.g. in ++ libsss_certmap. ++ ++ Copyright (C) Sumit Bose 2017 ++ ++ 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 . ++*/ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "util/crypto/sss_crypto.h" ++#include "util/crypto/nss/nss_util.h" ++#include "util/cert.h" ++#include "lib/certmap/sss_certmap.h" ++#include "lib/certmap/sss_certmap_int.h" ++ ++ ++/* The following two functions are copied from NSS's lib/certdb/secname.c ++ * becasue CERT_AddAVA is not exported. I just renamed it and made it static ++ * to avoid issues if the call gets exported some time in future. */ ++ ++static void ** ++AddToArray(PLArenaPool *arena, void **array, void *element) ++{ ++ unsigned count; ++ void **ap; ++ ++ /* Count up number of slots already in use in the array */ ++ count = 0; ++ ap = array; ++ if (ap) { ++ while (*ap++) { ++ count++; ++ } ++ } ++ ++ if (array) { ++ array = (void**) PORT_ArenaGrow(arena, array, ++ (count + 1) * sizeof(void *), ++ (count + 2) * sizeof(void *)); ++ } else { ++ array = (void**) PORT_ArenaAlloc(arena, (count + 2) * sizeof(void *)); ++ } ++ if (array) { ++ array[count] = element; ++ array[count+1] = 0; ++ } ++ return array; ++} ++ ++ ++static SECStatus ++sss_CERT_AddAVA(PLArenaPool *arena, CERTRDN *rdn, CERTAVA *ava) ++{ ++ rdn->avas = (CERTAVA**) AddToArray(arena, (void**) rdn->avas, ava); ++ return rdn->avas ? SECSuccess : SECFailure; ++} ++ ++static SECItem * ++cert_get_ext_by_tag(CERTCertificate *cert, SECOidTag tag) ++{ ++ SECOidData *oid; ++ int i; ++ ++ oid = SECOID_FindOIDByTag(tag); ++ for (i = 0; ++ (cert->extensions != NULL) && (cert->extensions[i] != NULL); ++ i++) ++ if (SECITEM_ItemsAreEqual(&cert->extensions[i]->id, &oid->oid)) ++ return &cert->extensions[i]->value; ++ return NULL; ++} ++ ++static int get_extended_key_usage_oids(TALLOC_CTX *mem_ctx, ++ CERTCertificate *cert, ++ const char ***_oids) ++{ ++ PLArenaPool *pool; ++ SECItem *ext; ++ SECItem **oids = NULL; ++ const char **oids_list = NULL; ++ size_t c; ++ SECStatus rv; ++ char *tmp_str; ++ int ret; ++ ++ pool = PORT_NewArena(sizeof(double)); ++ ext = cert_get_ext_by_tag(cert, SEC_OID_X509_EXT_KEY_USAGE); ++ if (ext != NULL) { ++ rv = SEC_ASN1DecodeItem(pool, &oids, ++ SEC_ASN1_GET(SEC_SequenceOfObjectIDTemplate), ++ ext); ++ if (rv != SECSuccess) { ++ ret = EINVAL; ++ goto done; ++ } ++ } ++ ++ for (c = 0; (oids != NULL && oids[c] != NULL); c++); ++ oids_list = talloc_zero_array(mem_ctx, const char *, c + 1); ++ if (oids_list == NULL) { ++ return ENOMEM; ++ } ++ ++ for (c = 0; (oids != NULL && oids[c] != NULL); c++) { ++ tmp_str = CERT_GetOidString(oids[c]); ++ /* is it expexted that NSS OID strings start with "OID." but we ++ * prefer the plain dotted-decimal version so the prefix is skipped */ ++ if (tmp_str == NULL || strncmp(tmp_str, "OID.", 4) != 0) { ++ PR_smprintf_free(tmp_str); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ oids_list[c] = talloc_strdup(oids_list, tmp_str + 4); ++ PR_smprintf_free(tmp_str); ++ if(oids_list[c] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ ret = 0; ++ ++done: ++ PORT_FreeArena(pool, PR_TRUE); ++ if (ret == 0) { ++ *_oids = oids_list; ++ } else { ++ talloc_free(oids_list); ++ } ++ ++ return ret; ++ ++} ++ ++static int get_rdn_str(TALLOC_CTX *mem_ctx, CERTAVA **avas, ++ const char **rdn_str) ++{ ++ size_t c; ++ char *tmp_name = NULL; ++ const char *tmp_str = NULL; ++ int ret; ++ SECStatus rv; ++ CERTRDN rdn = { 0 }; ++ CERTName *name = NULL; ++ PLArenaPool *arena = NULL; ++ ++ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); ++ if (arena == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ++ /* Multiple AVAs should be avoided becasue there is no general ordering ++ * rule and the RDN strings are not reproducible */ ++ for (c = 0; avas[c] != NULL; c++) { ++ rv = sss_CERT_AddAVA(arena, &rdn, avas[c]); ++ if (rv != SECSuccess) { ++ ret = EIO; ++ goto done; ++ } ++ } ++ ++ name = CERT_CreateName(&rdn, NULL); ++ if (name == NULL) { ++ ret = EIO; ++ goto done; ++ } ++ ++ tmp_name = CERT_NameToAscii(name); ++ CERT_DestroyName(name); ++ if (tmp_name == NULL) { ++ ret = EIO; ++ goto done; ++ } ++ ++ tmp_str = talloc_strdup(mem_ctx, tmp_name); ++ PORT_Free(tmp_name); ++ if (tmp_str == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *rdn_str = tmp_str; ++ } else { ++ talloc_free(discard_const(tmp_str)); ++ } ++ PORT_FreeArena(arena, PR_FALSE); ++ ++ return ret; ++} ++ ++static int get_rdn_list(TALLOC_CTX *mem_ctx, CERTRDN **rdns, ++ const char ***rdn_list) ++{ ++ int ret; ++ size_t c; ++ const char **list = NULL; ++ ++ for (c = 0; rdns[c] != NULL; c++); ++ list = talloc_zero_array(mem_ctx, const char *, c + 1); ++ if (list == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ for (c = 0; rdns[c] != NULL; c++) { ++ ret = get_rdn_str(list, rdns[c]->avas, ++ &(list[c])); ++ if (ret != 0) { ++ goto done; ++ } ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *rdn_list = list; ++ } else { ++ talloc_free(list); ++ } ++ ++ return ret; ++} ++ ++enum san_opt nss_name_type_to_san_opt(CERTGeneralNameType type) ++{ ++ switch (type) { ++ case certOtherName: ++ return SAN_OTHER_NAME; ++ case certRFC822Name: ++ return SAN_RFC822_NAME; ++ case certDNSName: ++ return SAN_DNS_NAME; ++ case certX400Address: ++ return SAN_X400_ADDRESS; ++ case certDirectoryName: ++ return SAN_DIRECTORY_NAME; ++ case certEDIPartyName: ++ return SAN_EDIPART_NAME; ++ case certURI: ++ return SAN_URI; ++ case certIPAddress: ++ return SAN_IP_ADDRESS; ++ case certRegisterID: ++ return SAN_REGISTERED_ID; ++ default: ++ return SAN_INVALID; ++ } ++} ++ ++static int add_to_san_list(TALLOC_CTX *mem_ctx, bool is_bin, ++ enum san_opt san_opt, uint8_t *data, size_t len, ++ struct san_list **item) ++{ ++ struct san_list *i; ++ ++ if (data == NULL || len == 0 || san_opt == SAN_INVALID) { ++ return EINVAL; ++ } ++ ++ i = talloc_zero(mem_ctx, struct san_list); ++ if (i == NULL) { ++ return ENOMEM; ++ } ++ ++ i->san_opt = san_opt; ++ if (is_bin) { ++ i->bin_val = talloc_memdup(i, data, len); ++ i->bin_val_len = len; ++ } else { ++ i->val = talloc_strndup(i, (char *) data, len); ++ } ++ if (i->val == NULL) { ++ talloc_free(i); ++ return ENOMEM; ++ } ++ ++ *item = i; ++ ++ return 0; ++} ++ ++/* taken from pkinit_crypto_nss.c of MIT Kerberos */ ++/* KerberosString: RFC 4120, 5.2.1. */ ++static const SEC_ASN1Template kerberos_string_template[] = { ++ { ++ SEC_ASN1_GENERAL_STRING, ++ 0, ++ NULL, ++ sizeof(SECItem), ++ } ++}; ++ ++/* Realm: RFC 4120, 5.2.2. */ ++struct realm { ++ SECItem name; ++}; ++static const SEC_ASN1Template realm_template[] = { ++ { ++ SEC_ASN1_GENERAL_STRING, ++ 0, ++ NULL, ++ sizeof(SECItem), ++ } ++}; ++ ++/* PrincipalName: RFC 4120, 5.2.2. */ ++static const SEC_ASN1Template sequence_of_kerberos_string_template[] = { ++ { ++ SEC_ASN1_SEQUENCE_OF, ++ 0, ++ &kerberos_string_template, ++ 0, ++ } ++}; ++ ++struct principal_name { ++ SECItem name_type; ++ SECItem **name_string; ++}; ++static const SEC_ASN1Template principal_name_template[] = { ++ { ++ SEC_ASN1_SEQUENCE, ++ 0, ++ NULL, ++ sizeof(struct principal_name), ++ }, ++ { ++ SEC_ASN1_CONTEXT_SPECIFIC | 0 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT, ++ offsetof(struct principal_name, name_type), ++ &SEC_IntegerTemplate, ++ sizeof(SECItem), ++ }, ++ { ++ SEC_ASN1_CONTEXT_SPECIFIC | 1 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT, ++ offsetof(struct principal_name, name_string), ++ sequence_of_kerberos_string_template, ++ sizeof(struct SECItem **), ++ }, ++ {0, 0, NULL, 0}, ++}; ++ ++/* KRB5PrincipalName: RFC 4556, 3.2.2. */ ++struct kerberos_principal_name { ++ SECItem realm; ++ struct principal_name principal_name; ++}; ++static const SEC_ASN1Template kerberos_principal_name_template[] = { ++ { ++ SEC_ASN1_SEQUENCE, ++ 0, ++ NULL, ++ sizeof(struct kerberos_principal_name), ++ }, ++ { ++ SEC_ASN1_CONTEXT_SPECIFIC | 0 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT, ++ offsetof(struct kerberos_principal_name, realm), ++ &realm_template, ++ sizeof(struct realm), ++ }, ++ { ++ SEC_ASN1_CONTEXT_SPECIFIC | 1 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT, ++ offsetof(struct kerberos_principal_name, principal_name), ++ &principal_name_template, ++ sizeof(struct principal_name), ++ }, ++ {0, 0, NULL, 0} ++}; ++ ++#define PKINIT_OID "1.3.6.1.5.2.2" ++#define NT_PRINCIPAL_OID "1.3.6.1.4.1.311.20.2.3" ++ ++static int add_string_other_name_to_san_list(TALLOC_CTX *mem_ctx, ++ enum san_opt san_opt, ++ CERTGeneralName *current, ++ struct san_list **item) ++{ ++ struct san_list *i = NULL; ++ int ret; ++ char *tmp_str; ++ ++ tmp_str = CERT_GetOidString(&(current->name.OthName.oid)); ++ /* is it expexted that NSS OID strings start with "OID." but we ++ * prefer the plain dotted-decimal version so the prefix is skipped */ ++ if (tmp_str == NULL || strncmp(tmp_str, "OID.", 4) != 0) { ++ PR_smprintf_free(tmp_str); ++ return EINVAL; ++ } ++ ++ i = talloc_zero(mem_ctx, struct san_list); ++ if (i == NULL) { ++ PR_smprintf_free(tmp_str); ++ return ENOMEM; ++ } ++ i->san_opt = san_opt; ++ ++ i->other_name_oid = talloc_strdup(i, tmp_str + 4); ++ PR_smprintf_free(tmp_str); ++ if (i->other_name_oid == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ i->bin_val = talloc_memdup(i, current->name.OthName.name.data, ++ current->name.OthName.name.len); ++ if (i->bin_val == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ i->bin_val_len = current->name.OthName.name.len; ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *item = i; ++ } else { ++ talloc_free(i); ++ } ++ ++ return ret; ++} ++ ++static int get_short_name(TALLOC_CTX *mem_ctx, const char *full_name, ++ char delim, char **short_name) ++{ ++ char *at; ++ char *s; ++ ++ if (full_name == NULL || delim == '\0' || short_name == NULL) { ++ return EINVAL; ++ } ++ ++ at = strchr(full_name, delim); ++ if (at != NULL) { ++ s = talloc_strndup(mem_ctx, full_name, (at - full_name)); ++ } else { ++ s = talloc_strdup(mem_ctx, full_name); ++ } ++ if (s == NULL) { ++ return ENOMEM; ++ } ++ ++ *short_name = s; ++ ++ return 0; ++} ++ ++static int add_nt_princ_to_san_list(TALLOC_CTX *mem_ctx, ++ PLArenaPool *pool, ++ enum san_opt san_opt, ++ CERTGeneralName *current, ++ struct san_list **item) ++{ ++ struct san_list *i = NULL; ++ SECStatus rv; ++ SECItem tmp_secitem = { 0 }; ++ int ret; ++ ++ rv = SEC_ASN1DecodeItem(pool, &tmp_secitem, ++ SEC_ASN1_GET(SEC_UTF8StringTemplate), ++ &(current->name.OthName.name)); ++ if (rv != SECSuccess) { ++ return EINVAL; ++ } ++ ++ i = talloc_zero(mem_ctx, struct san_list); ++ if (i == NULL) { ++ return ENOMEM; ++ } ++ i->san_opt = san_opt; ++ ++ i->val = talloc_strndup(i, (char *) tmp_secitem.data, ++ tmp_secitem.len); ++ if (i->val == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = get_short_name(i, i->val, '@', &(i->short_name)); ++ if (ret != 0) { ++ goto done; ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *item = i; ++ } else { ++ talloc_free(i); ++ } ++ ++ return ret; ++} ++ ++static int add_pkinit_princ_to_san_list(TALLOC_CTX *mem_ctx, ++ PLArenaPool *pool, ++ enum san_opt san_opt, ++ CERTGeneralName *current, ++ struct san_list **item) ++{ ++ struct san_list *i = NULL; ++ SECStatus rv; ++ struct kerberos_principal_name kname; ++ int ret; ++ size_t c; ++ ++ rv = SEC_ASN1DecodeItem(pool, &kname, ++ kerberos_principal_name_template, ++ &(current->name.OthName.name)); ++ if (rv != SECSuccess) { ++ return EINVAL; ++ } ++ ++ i = talloc_zero(mem_ctx, struct san_list); ++ if (i == NULL) { ++ return ENOMEM; ++ } ++ i->san_opt = san_opt; ++ ++ if (kname.principal_name.name_string != NULL) { ++ i->val = talloc_strdup(i, ""); ++ if (i->val == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ for (c = 0; kname.principal_name.name_string[c] != NULL; c++) { ++ if (c > 0) { ++ i->val = talloc_strdup_append(i->val, "/"); ++ if (i->val == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ i->val = talloc_strndup_append(i->val, ++ (char *) kname.principal_name.name_string[c]->data, ++ kname.principal_name.name_string[c]->len); ++ if (i->val == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ i->val = talloc_strndup_append(i->val, ++ (char *) kname.realm.data, ++ kname.realm.len); ++ if (i->val == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = get_short_name(i, i->val, '@', &(i->short_name)); ++ if (ret != 0) { ++ goto done; ++ } ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *item = i; ++ } else { ++ talloc_free(i); ++ } ++ ++ return ret; ++} ++ ++static int add_oid_to_san_list(TALLOC_CTX *mem_ctx, ++ enum san_opt san_opt, ++ SECItem oid, ++ struct san_list **item) ++{ ++ struct san_list *i = NULL; ++ char *tmp_str; ++ ++ tmp_str = CERT_GetOidString(&oid); ++ /* is it expexted that NSS OID strings start with "OID." but we ++ * prefer the plain dotted-decimal version so the prefix is skipped */ ++ if (tmp_str == NULL || strncmp(tmp_str, "OID.", 4) != 0) { ++ PR_smprintf_free(tmp_str); ++ return EINVAL; ++ } ++ ++ i = talloc_zero(mem_ctx, struct san_list); ++ if (i == NULL) { ++ PR_smprintf_free(tmp_str); ++ return ENOMEM; ++ } ++ i->san_opt = san_opt; ++ ++ i->val = talloc_strdup(i, tmp_str + 4); ++ PR_smprintf_free(tmp_str); ++ if (i->val == NULL) { ++ talloc_free(i); ++ return ENOMEM; ++ } ++ ++ *item = i; ++ return 0; ++} ++ ++static int add_rdn_list_to_san_list(TALLOC_CTX *mem_ctx, ++ enum san_opt san_opt, ++ CERTName name, ++ struct san_list **item) ++{ ++ struct san_list *i = NULL; ++ int ret; ++ ++ i = talloc_zero(mem_ctx, struct san_list); ++ if (i == NULL) { ++ return ENOMEM; ++ } ++ i->san_opt = san_opt; ++ ++ ret = get_rdn_list(i, name.rdns, &(i->rdn_list)); ++ if (ret != 0) { ++ talloc_free(i); ++ return ret; ++ } ++ ++ *item = i; ++ return 0; ++} ++ ++static int add_ip_to_san_list(TALLOC_CTX *mem_ctx, enum san_opt san_opt, ++ uint8_t *data, size_t len, ++ struct san_list **item) ++{ ++ struct san_list *i; ++ PRStatus st; ++ PRNetAddr addr; ++ char addrBuf[80]; ++ ++ if (data == NULL || len == 0 || san_opt == SAN_INVALID) { ++ return EINVAL; ++ } ++ ++ /* taken from secu_PrintIPAddress() */ ++ memset(&addr, 0, sizeof addr); ++ if (len == 4) { ++ addr.inet.family = PR_AF_INET; ++ memcpy(&addr.inet.ip, data, len); ++ } else if (len == 16) { ++ addr.ipv6.family = PR_AF_INET6; ++ memcpy(addr.ipv6.ip.pr_s6_addr, data, len); ++ if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) { ++ /* convert to IPv4. */ ++ addr.inet.family = PR_AF_INET; ++ memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4); ++ memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad); ++ } ++ } else { ++ return EINVAL; ++ } ++ ++ st = PR_NetAddrToString(&addr, addrBuf, sizeof addrBuf); ++ if (st != PR_SUCCESS) { ++ return EIO; ++ } ++ ++ i = talloc_zero(mem_ctx, struct san_list); ++ if (i == NULL) { ++ return ENOMEM; ++ } ++ ++ i->san_opt = san_opt; ++ i->val = talloc_strdup(i, addrBuf); ++ if (i->val == NULL) { ++ talloc_free(i); ++ return ENOMEM; ++ } ++ ++ *item = i; ++ return 0; ++} ++static int add_principal_to_san_list(TALLOC_CTX *mem_ctx, ++ enum san_opt san_opt, ++ const char *princ, ++ struct san_list **item) ++{ ++ struct san_list *i = NULL; ++ int ret; ++ ++ i = talloc_zero(mem_ctx, struct san_list); ++ if (i == NULL) { ++ return ENOMEM; ++ } ++ i->san_opt = san_opt; ++ ++ i->val = talloc_strdup(i, princ); ++ if (i->val == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = get_short_name(i, i->val, '@', &(i->short_name)); ++ if (ret != 0) { ++ goto done; ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *item = i; ++ } else { ++ talloc_free(i); ++ } ++ ++ return ret; ++} ++ ++static int get_san(TALLOC_CTX *mem_ctx, CERTCertificate *cert, ++ struct san_list **san_list) ++{ ++ ++ SECItem subAltName = { 0 }; ++ SECStatus rv; ++ CERTGeneralName *name_list = NULL; ++ CERTGeneralName *current; ++ PLArenaPool *pool = NULL; ++ int ret; ++ struct san_list *list = NULL; ++ struct san_list *item = NULL; ++ struct san_list *item_s = NULL; ++ struct san_list *item_p = NULL; ++ struct san_list *item_pb = NULL; ++ ++ rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, ++ &subAltName); ++ if (rv != SECSuccess) { ++ if (rv == SECFailure ++ && PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) { ++ ret = EOK; ++ } else { ++ ret = EIO; ++ } ++ goto done; ++ } ++ ++ pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); ++ if (pool == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ name_list = CERT_DecodeAltNameExtension(pool, &subAltName); ++ if (name_list == NULL ) { ++ ret = EIO; ++ goto done; ++ } ++ ++ current = name_list; ++ do { ++ switch (current->type) { ++ case certOtherName: ++ ret = add_string_other_name_to_san_list(mem_ctx, ++ SAN_STRING_OTHER_NAME, ++ current, &item_s); ++ if (ret != 0) { ++ goto done; ++ } ++ DLIST_ADD(list, item_s); ++ ++ item_p = NULL; ++ if (strcmp(item_s->other_name_oid, NT_PRINCIPAL_OID) == 0) { ++ ret = add_nt_princ_to_san_list(mem_ctx, pool, SAN_NT, current, ++ &item_p); ++ if (ret != 0) { ++ goto done; ++ } ++ DLIST_ADD(list, item_p); ++ } else if (strcmp(item_s->other_name_oid, PKINIT_OID) == 0) { ++ ret = add_pkinit_princ_to_san_list(mem_ctx, pool, SAN_PKINIT, ++ current, &item_p); ++ if (ret != 0) { ++ goto done; ++ } ++ DLIST_ADD(list, item_p); ++ } ++ ++ if (item_p != NULL) { ++ ret = add_principal_to_san_list(mem_ctx, SAN_PRINCIPAL, ++ item_p->val, &item_pb); ++ if (ret != 0) { ++ goto done; ++ } ++ DLIST_ADD(list, item_pb); ++ } ++ ++ break; ++ case certRFC822Name: ++ case certDNSName: ++ case certURI: ++ ret = add_to_san_list(mem_ctx, false, ++ nss_name_type_to_san_opt(current->type), ++ current->name.other.data, ++ current->name.other.len, &item); ++ if (ret != 0) { ++ goto done; ++ } ++ ++ if (current->type == certRFC822Name ++ || current->type == certDNSName) { ++ ret = get_short_name(item, item->val, ++ (current->type == certRFC822Name ++ ? '@' : '.'), ++ &(item->short_name)); ++ if (ret != 0) { ++ goto done; ++ } ++ } ++ ++ DLIST_ADD(list, item); ++ break; ++ case certIPAddress: ++ ret = add_ip_to_san_list(mem_ctx, ++ nss_name_type_to_san_opt(current->type), ++ current->name.other.data, ++ current->name.other.len, &item); ++ if (ret != 0) { ++ goto done; ++ } ++ DLIST_ADD(list, item); ++ break; ++ case certDirectoryName: ++ ret = add_rdn_list_to_san_list(mem_ctx, ++ nss_name_type_to_san_opt(current->type), ++ current->name.directoryName, &item); ++ if (ret != 0) { ++ goto done; ++ } ++ DLIST_ADD(list, item); ++ break; ++ case certRegisterID: ++ ret = add_oid_to_san_list(mem_ctx, ++ nss_name_type_to_san_opt(current->type), ++ current->name.other, &item); ++ if (ret != 0) { ++ goto done; ++ } ++ DLIST_ADD(list, item); ++ break; ++ case certX400Address: ++ case certEDIPartyName: ++ ret = add_to_san_list(mem_ctx, true, ++ nss_name_type_to_san_opt(current->type), ++ current->name.other.data, ++ current->name.other.len, &item); ++ if (ret != 0) { ++ goto done; ++ } ++ DLIST_ADD(list, item); ++ break; ++ default: ++ ret = EINVAL; ++ } ++ ++ current = CERT_GetNextGeneralName(current); ++ if (current == NULL) { ++ ret = EIO; ++ goto done; ++ } ++ } while (current != name_list); ++ ++done: ++ ++ /* Don't free nameList, it's part of the arena. */ ++ ++ if (pool != NULL) { ++ PORT_FreeArena(pool, PR_FALSE); ++ } ++ ++ if (subAltName.data != NULL) { ++ SECITEM_FreeItem(&subAltName, PR_FALSE); ++ } ++ ++ if (ret == EOK) { ++ *san_list = list; ++ } ++ return ret; ++} ++ ++int sss_cert_get_content(TALLOC_CTX *mem_ctx, ++ const uint8_t *der_blob, size_t der_size, ++ struct sss_cert_content **content) ++{ ++ int ret; ++ struct sss_cert_content *cont = NULL; ++ CERTCertDBHandle *handle; ++ CERTCertificate *cert = NULL; ++ SECItem der_item; ++ NSSInitContext *nss_ctx; ++ ++ if (der_blob == NULL || der_size == 0) { ++ return EINVAL; ++ } ++ ++ nss_ctx = NSS_InitContext("", "", "", "", NULL, NSS_INIT_READONLY ++ | NSS_INIT_NOCERTDB ++ | NSS_INIT_NOMODDB ++ | NSS_INIT_FORCEOPEN ++ | NSS_INIT_NOROOTINIT ++ | NSS_INIT_OPTIMIZESPACE); ++ if (nss_ctx == NULL) { ++ return EIO; ++ } ++ ++ cont = talloc_zero(mem_ctx, struct sss_cert_content); ++ if (cont == NULL) { ++ return ENOMEM; ++ } ++ ++ handle = CERT_GetDefaultCertDB(); ++ der_item.len = der_size; ++ der_item.data = discard_const(der_blob); ++ ++ cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE); ++ if (cert == NULL) { ++ ret = EINVAL; ++ goto done; ++ } ++ ++ cont->issuer_str = talloc_strdup(cont, cert->issuerName); ++ if (cont->issuer_str == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = get_rdn_list(cont, cert->issuer.rdns, &cont->issuer_rdn_list); ++ if (ret != 0) { ++ goto done; ++ } ++ ++ cont->subject_str = talloc_strdup(cont, cert->subjectName); ++ if (cont->subject_str == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = get_rdn_list(cont, cert->subject.rdns, &cont->subject_rdn_list); ++ if (ret != 0) { ++ goto done; ++ } ++ ++ ++ cont->key_usage = cert->keyUsage; ++ ++ ret = get_extended_key_usage_oids(cont, cert, ++ &(cont->extended_key_usage_oids)); ++ if (ret != 0) { ++ goto done; ++ } ++ ++ ret = get_san(cont, cert, &(cont->san_list)); ++ if (ret != 0) { ++ goto done; ++ } ++ ++ cont->cert_der = talloc_memdup(cont, der_blob, der_size); ++ if (cont->cert_der == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ cont->cert_der_size = der_size; ++ ret = EOK; ++ ++done: ++ ++ CERT_DestroyCertificate(cert); ++ NSS_ShutdownContext(nss_ctx); ++ ++ if (ret == EOK) { ++ *content = cont; ++ } else { ++ talloc_free(cont); ++ } ++ ++ return ret; ++} +diff --git a/src/lib/certmap/sss_certmap.c b/src/lib/certmap/sss_certmap.c +new file mode 100644 +index 0000000000000000000000000000000000000000..080cab8ab585ce64a88c352a23a8062887fa720a +--- /dev/null ++++ b/src/lib/certmap/sss_certmap.c +@@ -0,0 +1,993 @@ ++/* ++ SSSD ++ ++ Library for rule based certificate to user mapping ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++#include "util/util.h" ++#include "util/cert.h" ++#include "util/crypto/sss_crypto.h" ++#include "lib/certmap/sss_certmap.h" ++#include "lib/certmap/sss_certmap_int.h" ++ ++int debug_level; ++void sss_debug_fn(const char *file, ++ long line, ++ const char *function, ++ int level, ++ const char *format, ...) ++{ ++ return; ++} ++ ++static int get_type_prefix(TALLOC_CTX *mem_ctx, const char *match_rule, ++ char **type, const char **rule_start) ++{ ++ const char *c; ++ char *delim; ++ ++ *type = NULL; ++ *rule_start = match_rule; ++ ++ delim = strchr(match_rule, ':'); ++ if (delim == NULL) { ++ /* no type prefix found */ ++ return 0; ++ } ++ ++ /* rule starts with ':', empty type */ ++ if (delim == match_rule) { ++ *rule_start = delim + 1; ++ return EOK; ++ } ++ ++ for (c = match_rule; c < delim; c++) { ++ /* type prefix may only contain digits and upper-case ASCII characters */ ++ if (!(isascii(*c) && (isdigit(*c) || isupper(*c)))) { ++ /* no type prefix found */ ++ return 0; ++ } ++ } ++ ++ *rule_start = delim + 1; ++ *type = talloc_strndup(mem_ctx, match_rule, (delim - match_rule)); ++ if (*type == NULL) { ++ return ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int parse_match_rule(struct sss_certmap_ctx *ctx, const char *match_rule, ++ struct krb5_match_rule **parsed_match_rule) ++{ ++ int ret; ++ char *type; ++ const char *rule_start; ++ ++ ret = get_type_prefix(ctx, match_rule, &type, &rule_start); ++ if (ret != EOK) { ++ CM_DEBUG(ctx, "Failed to read rule type."); ++ goto done; ++ } ++ ++ if (type == NULL || strcmp(type, "KRB5") == 0) { ++ ret = parse_krb5_match_rule(ctx, rule_start, parsed_match_rule); ++ if (ret != EOK) { ++ CM_DEBUG(ctx, "Failed to parse KRB5 matching rule."); ++ goto done; ++ } ++ } else { ++ CM_DEBUG(ctx, "Unsupported matching rule type."); ++ ret = ESRCH; ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(type); ++ ++ return ret; ++} ++ ++static int parse_mapping_rule(struct sss_certmap_ctx *ctx, ++ const char *mapping_rule, ++ struct ldap_mapping_rule **parsed_mapping_rule) ++{ ++ int ret; ++ char *type; ++ const char *rule_start; ++ ++ ret = get_type_prefix(ctx, mapping_rule, &type, &rule_start); ++ if (ret != EOK) { ++ CM_DEBUG(ctx, "Failed to read rule type."); ++ goto done; ++ } ++ ++ if (type == NULL || strcmp(type, "LDAP") == 0) { ++ ret = parse_ldap_mapping_rule(ctx, rule_start, parsed_mapping_rule); ++ if (ret != EOK) { ++ CM_DEBUG(ctx, "Failed to parse LDAP mapping rule."); ++ goto done; ++ } ++ } else { ++ CM_DEBUG(ctx, "Unsupported mapping rule type."); ++ ret = ESRCH; ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(type); ++ ++ return ret; ++} ++ ++int sss_certmap_add_rule(struct sss_certmap_ctx *ctx, ++ uint32_t priority, const char *match_rule, ++ const char *map_rule, const char **domains) ++{ ++ size_t c; ++ int ret; ++ struct match_map_rule *rule; ++ struct TALLOC_CTX *tmp_ctx; ++ struct priority_list *p; ++ struct priority_list *p_new; ++ struct krb5_match_rule *parsed_match_rule; ++ struct ldap_mapping_rule *parsed_mapping_rule; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ rule = talloc_zero(tmp_ctx, struct match_map_rule); ++ if (rule == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ rule->priority = priority; ++ ++ if (match_rule == NULL) { ++ match_rule = DEFAULT_MATCH_RULE; ++ } ++ ret = parse_match_rule(ctx, match_rule, &parsed_match_rule); ++ if (ret == 0) { ++ rule->parsed_match_rule = talloc_steal(rule, parsed_match_rule); ++ rule->match_rule = talloc_strdup(rule, match_rule); ++ if (rule->match_rule == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } else if (ret == ESRCH) { ++ /* report unsupported rules */ ++ goto done; ++ } else { ++ goto done; ++ } ++ ++ if (map_rule == NULL) { ++ map_rule = DEFAULT_MAP_RULE; ++ } ++ ret = parse_mapping_rule(ctx, map_rule, &parsed_mapping_rule); ++ if (ret == 0) { ++ rule->parsed_mapping_rule = talloc_steal(rule, parsed_mapping_rule); ++ rule->map_rule = talloc_strdup(rule, map_rule); ++ if (rule->map_rule == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } else if (ret == ESRCH) { ++ /* report unsupported rules */ ++ goto done; ++ } else { ++ goto done; ++ } ++ ++ if (domains != NULL && *domains != NULL) { ++ for (c = 0; domains[c] != NULL; c++); ++ rule->domains = talloc_zero_array(rule, char *, c + 1); ++ if (rule->domains == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ for (c = 0; domains[c] != NULL; c++) { ++ rule->domains[c] = talloc_strdup(rule->domains, domains[c]); ++ if (rule->domains[c] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ } ++ ++ if (ctx->prio_list == NULL) { ++ ctx->prio_list = talloc_zero(ctx, struct priority_list); ++ if (ctx->prio_list == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ctx->prio_list->priority = rule->priority; ++ ctx->prio_list->rule_list = rule; ++ } else { ++ for (p = ctx->prio_list; p != NULL && p->priority < rule->priority; ++ p = p->next); ++ if (p != NULL && p->priority == priority) { ++ DLIST_ADD(p->rule_list, rule); ++ } else { ++ p_new = talloc_zero(ctx, struct priority_list); ++ if (p_new == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ p_new->priority = rule->priority; ++ p_new->rule_list = rule; ++ ++ if (p == NULL) { ++ DLIST_ADD_END(ctx->prio_list, p_new, struct priority_list *); ++ } else if (p->prev == NULL) { ++ DLIST_ADD(ctx->prio_list, p_new); ++ } else { ++ DLIST_ADD_AFTER(ctx->prio_list, p_new, p->prev); ++ } ++ } ++ } ++ ++ talloc_steal(ctx, rule); ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ ++ return ret; ++} ++ ++static int expand_cert(struct sss_certmap_ctx *ctx, ++ struct parsed_template *parsed_template, ++ struct sss_cert_content *cert_content, ++ char **expanded) ++{ ++ int ret; ++ char *tmp_str = NULL; ++ ++ if (parsed_template->conversion == NULL ++ || strcmp(parsed_template->conversion, "bin") == 0) { ++ ret = bin_to_ldap_filter_value(ctx, cert_content->cert_der, ++ cert_content->cert_der_size, &tmp_str); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "bin conversion failed."); ++ goto done; ++ } ++ } else if (strcmp(parsed_template->conversion, "base64") == 0) { ++ tmp_str = sss_base64_encode(ctx, cert_content->cert_der, ++ cert_content->cert_der_size); ++ if (tmp_str == NULL) { ++ CM_DEBUG(ctx, "base64 conversion failed."); ++ ret = ENOMEM; ++ goto done; ++ } ++ } else { ++ CM_DEBUG(ctx, "Unsupported conversion."); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *expanded = tmp_str; ++ } else { ++ talloc_free(tmp_str); ++ } ++ ++ return ret; ++} ++ ++static int get_dn_str(struct sss_certmap_ctx *ctx, const char *conversion, ++ const char **rdn_list, char **result) ++{ ++ char *str = NULL; ++ size_t c; ++ int ret; ++ char *conv = NULL; ++ ++ str = talloc_strdup(ctx, ""); ++ if (str == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ if (conversion == NULL || strcmp(conversion, "nss_ldap") == 0 ++ || strcmp(conversion, "nss") == 0) { ++ for (c = 0; rdn_list[c] != NULL; c++); ++ while (c != 0) { ++ c--; ++ str = talloc_asprintf_append(str, "%s%s", ++ (rdn_list[c + 1] == NULL) ? "" : ",", ++ rdn_list[c]); ++ if (str == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ }; ++ } else if (strcmp(conversion, "ad_ldap") == 0) { ++ for (c = 0; rdn_list[c] != NULL; c++); ++ while (c != 0) { ++ c--; ++ conv = check_ad_attr_name(str, rdn_list[c]); ++ str = talloc_asprintf_append(str, "%s%s", ++ (rdn_list[c + 1] == NULL) ? "" : ",", ++ conv == NULL ? rdn_list[c] : conv); ++ talloc_free(conv); ++ conv = NULL; ++ if (str == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ }; ++ } else if (strcmp(conversion, "nss_x500") == 0) { ++ for (c = 0; rdn_list[c] != NULL; c++) { ++ str = talloc_asprintf_append(str, "%s%s", (c == 0) ? "" : ",", ++ rdn_list[c]); ++ if (str == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ } else if (strcmp(conversion, "ad_x500") == 0 ++ || strcmp(conversion, "ad") == 0) { ++ for (c = 0; rdn_list[c] != NULL; c++) { ++ conv = check_ad_attr_name(str, rdn_list[c]); ++ str = talloc_asprintf_append(str, "%s%s", ++ (c == 0) ? "" : ",", ++ conv == NULL ? rdn_list[c] : conv); ++ talloc_free(conv); ++ conv = NULL; ++ if (str == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ } else { ++ ret = EINVAL; ++ goto done; ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *result = str; ++ } else { ++ talloc_free(str); ++ } ++ ++ return ret; ++} ++ ++static int expand_san_blob(struct sss_certmap_ctx *ctx, enum san_opt san_opt, ++ struct san_list *san_list, char **expanded) ++{ ++ struct san_list *item; ++ char *exp; ++ int ret; ++ ++ DLIST_FOR_EACH(item, san_list) { ++ if (item->san_opt == san_opt) { ++ ret = bin_to_ldap_filter_value(ctx, item->bin_val, ++ item->bin_val_len, &exp); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "bin conversion failed."); ++ return ret; ++ } ++ ++ *expanded = exp; ++ return 0; ++ } ++ } ++ ++ return ENOENT; ++} ++ ++static int expand_san_string(struct sss_certmap_ctx *ctx, enum san_opt san_opt, ++ struct san_list *san_list, const char *attr_name, ++ char **expanded) ++{ ++ struct san_list *item; ++ char *exp; ++ ++ DLIST_FOR_EACH(item, san_list) { ++ if (item->san_opt == san_opt) { ++ if (attr_name == NULL) { ++ exp = talloc_strdup(ctx, item->val); ++ } else if (strcasecmp(attr_name, "short_name") == 0) { ++ exp = talloc_strdup(ctx, item->short_name); ++ } else { ++ CM_DEBUG(ctx, "Unsupported attribute name [%s].", attr_name); ++ return EINVAL; ++ } ++ ++ if (exp == NULL) { ++ return ENOMEM; ++ } ++ ++ *expanded = exp; ++ return 0; ++ } ++ } ++ ++ return ENOENT; ++} ++ ++static int expand_san_rdn_list(struct sss_certmap_ctx *ctx, ++ enum san_opt san_opt, ++ struct san_list *san_list, ++ const char *conversion, ++ char **expanded) ++{ ++ struct san_list *item; ++ char *exp; ++ int ret; ++ ++ DLIST_FOR_EACH(item, san_list) { ++ if (item->san_opt == san_opt) { ++ ret = get_dn_str(ctx, conversion, item->rdn_list, &exp); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ *expanded = exp; ++ return 0; ++ } ++ } ++ ++ return ENOENT; ++} ++ ++ ++static int expand_san(struct sss_certmap_ctx *ctx, ++ struct parsed_template *parsed_template, ++ struct san_list *san_list, ++ char **expanded) ++{ ++ int ret; ++ ++ if (strcmp("subject_rfc822_name", parsed_template->name) == 0) { ++ ret = expand_san_string(ctx, SAN_RFC822_NAME, san_list, ++ parsed_template->attr_name, expanded); ++ } else if (strcmp("subject_dns_name", parsed_template->name) == 0) { ++ ret = expand_san_string(ctx, SAN_DNS_NAME, san_list, ++ parsed_template->attr_name, expanded); ++ } else if (strcmp("subject_x400_address", parsed_template->name) == 0) { ++ ret = expand_san_blob(ctx, SAN_X400_ADDRESS, san_list, expanded); ++ } else if (strcmp("subject_directory_name", parsed_template->name) == 0) { ++ ret = expand_san_rdn_list(ctx, SAN_DIRECTORY_NAME, san_list, ++ parsed_template->conversion, expanded); ++ } else if (strcmp("subject_ediparty_name", parsed_template->name) == 0) { ++ ret = expand_san_blob(ctx, SAN_EDIPART_NAME, san_list, expanded); ++ } else if (strcmp("subject_uri", parsed_template->name) == 0) { ++ ret = expand_san_string(ctx, SAN_URI, san_list, ++ parsed_template->attr_name, expanded); ++ } else if (strcmp("subject_ip_address", parsed_template->name) == 0) { ++ ret = expand_san_string(ctx, SAN_IP_ADDRESS, san_list, ++ parsed_template->attr_name, expanded); ++ } else if (strcmp("subject_registered_id", parsed_template->name) == 0) { ++ ret = expand_san_string(ctx, SAN_REGISTERED_ID, san_list, ++ parsed_template->attr_name, expanded); ++ } else if (strcmp("subject_pkinit_principal", parsed_template->name) == 0) { ++ ret = expand_san_string(ctx, SAN_PKINIT, san_list, ++ parsed_template->attr_name, expanded); ++ } else if (strcmp("subject_nt_principal", parsed_template->name) == 0) { ++ ret = expand_san_string(ctx, SAN_NT, san_list, ++ parsed_template->attr_name, expanded); ++ } else if (strcmp("subject_principal", parsed_template->name) == 0) { ++ ret = expand_san_string(ctx, SAN_PRINCIPAL, san_list, ++ parsed_template->attr_name, expanded); ++ } else { ++ CM_DEBUG(ctx, "Unsupported template name [%s].n", ++ parsed_template->name); ++ ret = EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int expand_template(struct sss_certmap_ctx *ctx, ++ struct parsed_template *parsed_template, ++ struct sss_cert_content *cert_content, ++ char **expanded) ++{ ++ int ret; ++ char *exp = NULL; ++ ++ if (strcmp("issuer_dn", parsed_template->name) == 0) { ++ ret = get_dn_str(ctx, parsed_template->conversion, ++ cert_content->issuer_rdn_list, &exp); ++ } else if (strcmp("subject_dn", parsed_template->name) == 0) { ++ ret = get_dn_str(ctx, parsed_template->conversion, ++ cert_content->subject_rdn_list, &exp); ++ } else if (strncmp("subject_", parsed_template->name, 8) == 0) { ++ ret = expand_san(ctx, parsed_template, cert_content->san_list, &exp); ++ } else if (strcmp("cert", parsed_template->name) == 0) { ++ ret = expand_cert(ctx, parsed_template, cert_content, &exp); ++ } else { ++ CM_DEBUG(ctx, "Unsupported template name."); ++ ret = EINVAL; ++ goto done; ++ } ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to expand [%s] template.", parsed_template->name); ++ goto done; ++ } ++ ++ if (exp == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *expanded = exp; ++ } else { ++ talloc_free(exp); ++ } ++ ++ return ret; ++} ++ ++static int get_filter(struct sss_certmap_ctx *ctx, ++ struct ldap_mapping_rule *parsed_mapping_rule, ++ struct sss_cert_content *cert_content, ++ char **filter) ++{ ++ struct ldap_mapping_rule_comp *comp; ++ char *result = NULL; ++ char *expanded = NULL; ++ int ret; ++ ++ result = talloc_strdup(ctx, ""); ++ if (result == NULL) { ++ return ENOMEM; ++ } ++ ++ for (comp = parsed_mapping_rule->list; comp != NULL; comp = comp->next) { ++ if (comp->type == comp_string) { ++ result = talloc_strdup_append(result, comp->val); ++ } else if (comp->type == comp_template) { ++ ret = expand_template(ctx, comp->parsed_template, cert_content, ++ &expanded); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to expanded template."); ++ goto done; ++ } ++ ++ result = talloc_strdup_append(result, expanded); ++ talloc_free(expanded); ++ expanded = NULL; ++ if (result == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } else { ++ ret = EINVAL; ++ CM_DEBUG(ctx, "Unsupported component type."); ++ goto done; ++ } ++ } ++ ++ ret = 0; ++done: ++ talloc_free(expanded); ++ if (ret == 0) { ++ *filter = result; ++ } else { ++ talloc_free(result); ++ } ++ ++ return ret; ++} ++ ++static bool check_san_regexp(struct sss_certmap_ctx *ctx, ++ enum san_opt san_opt, regex_t regexp, ++ struct san_list *san_list) ++{ ++ struct san_list *item; ++ bool match = false; ++ int ret; ++ char *tmp_str = NULL; ++ ++ DLIST_FOR_EACH(item, san_list) { ++ if (item->san_opt == san_opt) { ++ if (item->san_opt == SAN_DIRECTORY_NAME) { ++ /* use LDAP order for matching */ ++ ret = get_dn_str(ctx, NULL, item->rdn_list, &tmp_str); ++ if (ret != 0 || tmp_str == NULL) { ++ return false; ++ } ++ match = (regexec(®exp, tmp_str, 0, NULL, 0) == 0); ++ talloc_free(tmp_str); ++ } else { ++ match = (item->val != NULL ++ && regexec(®exp, item->val, 0, NULL, 0) == 0); ++ } ++ if (!match) { ++ return false; ++ } ++ } ++ } ++ ++ return match; ++} ++ ++static bool check_san_blob(enum san_opt san_opt, ++ uint8_t *bin_val, size_t bin_val_len, ++ struct san_list *san_list) ++{ ++ struct san_list *item; ++ bool match = false; ++ ++ if (bin_val == NULL || bin_val_len == 0) { ++ return false; ++ } ++ ++ DLIST_FOR_EACH(item, san_list) { ++ if (item->san_opt == san_opt) { ++ match = (item->bin_val != NULL && item->bin_val_len != 0 ++ && memmem(item->bin_val, item->bin_val_len, ++ bin_val, bin_val_len) != NULL); ++ if (!match) { ++ return false; ++ } ++ } ++ } ++ ++ return match; ++} ++ ++static bool check_san_str_other_name(enum san_opt san_opt, ++ const char *str_other_name_oid, ++ regex_t regexp, ++ struct san_list *san_list) ++{ ++ struct san_list *item; ++ bool match = false; ++ char *tmp_str; ++ ++ if (str_other_name_oid == NULL) { ++ return false; ++ } ++ ++ DLIST_FOR_EACH(item, san_list) { ++ if (item->san_opt == san_opt ++ && strcmp(item->other_name_oid, str_other_name_oid) == 0) { ++ match = false; ++ if (item->bin_val != NULL && item->bin_val_len != 0) { ++ tmp_str = talloc_strndup(item, (char *) item->bin_val, ++ item->bin_val_len); ++ if (tmp_str != NULL) { ++ match = (regexec(®exp, tmp_str, 0, NULL, 0) == 0); ++ } ++ talloc_free(tmp_str); ++ } ++ if (!match) { ++ return false; ++ } ++ } ++ } ++ ++ return match; ++} ++ ++static bool do_san_match(struct sss_certmap_ctx *ctx, ++ struct component_list *comp, ++ struct san_list *san_list) ++{ ++ switch (comp->san_opt) { ++ case SAN_OTHER_NAME: ++ return check_san_blob(SAN_STRING_OTHER_NAME, ++ comp->bin_val, comp->bin_val_len, ++ san_list); ++ break; ++ case SAN_X400_ADDRESS: ++ case SAN_EDIPART_NAME: ++ return check_san_blob(comp->san_opt, comp->bin_val, comp->bin_val_len, ++ san_list); ++ break; ++ case SAN_RFC822_NAME: ++ case SAN_DNS_NAME: ++ case SAN_DIRECTORY_NAME: ++ case SAN_URI: ++ case SAN_IP_ADDRESS: ++ case SAN_REGISTERED_ID: ++ case SAN_PKINIT: ++ case SAN_NT: ++ case SAN_PRINCIPAL: ++ return check_san_regexp(ctx, comp->san_opt, comp->regexp, san_list); ++ break; ++ case SAN_STRING_OTHER_NAME: ++ return check_san_str_other_name(comp->san_opt, comp->str_other_name_oid, ++ comp->regexp, san_list); ++ break; ++ default: ++ CM_DEBUG(ctx, "Unsupported SAN option [%d].", comp->san_opt); ++ return false; ++ } ++} ++ ++static int do_match(struct sss_certmap_ctx *ctx, ++ struct krb5_match_rule *parsed_match_rule, ++ struct sss_cert_content *cert_content) ++{ ++ struct component_list *comp; ++ bool match = false; ++ size_t c; ++ ++ if (parsed_match_rule == NULL || cert_content == NULL) { ++ return EINVAL; ++ } ++ ++ /* Issuer */ ++ for (comp = parsed_match_rule->issuer; comp != NULL; comp = comp->next) { ++ match = (cert_content->issuer_str != NULL ++ && regexec(&(comp->regexp), cert_content->issuer_str, ++ 0, NULL, 0) == 0); ++ if (match && parsed_match_rule->r == relation_or) { ++ /* match */ ++ return 0; ++ } else if (!match && parsed_match_rule->r == relation_and) { ++ /* no match */ ++ return ENOENT; ++ } ++ ++ } ++ ++ /* Subject */ ++ for (comp = parsed_match_rule->subject; comp != NULL; comp = comp->next) { ++ match = (cert_content->subject_str != NULL ++ && regexec(&(comp->regexp), cert_content->subject_str, ++ 0, NULL, 0) == 0); ++ if (match && parsed_match_rule->r == relation_or) { ++ /* match */ ++ return 0; ++ } else if (!match && parsed_match_rule->r == relation_and) { ++ /* no match */ ++ return ENOENT; ++ } ++ ++ } ++ ++ /* Key Usage */ ++ for (comp = parsed_match_rule->ku; comp != NULL; comp = comp->next) { ++ match = ((cert_content->key_usage & comp->ku) == comp->ku); ++ if (match && parsed_match_rule->r == relation_or) { ++ /* match */ ++ return 0; ++ } else if (!match && parsed_match_rule->r == relation_and) { ++ /* no match */ ++ return ENOENT; ++ } ++ } ++ ++ /* Extended Key Usage */ ++ for (comp = parsed_match_rule->eku; comp != NULL; comp = comp->next) { ++ for (c = 0; comp->eku_oid_list[c] != NULL; c++) { ++ match = string_in_list(comp->eku_oid_list[c], ++ discard_const( ++ cert_content->extended_key_usage_oids), ++ true); ++ if (match && parsed_match_rule->r == relation_or) { ++ /* match */ ++ return 0; ++ } else if (!match && parsed_match_rule->r == relation_and) { ++ /* no match */ ++ return ENOENT; ++ } ++ } ++ } ++ ++ /* SAN */ ++ for (comp = parsed_match_rule->san; comp != NULL; comp = comp->next) { ++ match = do_san_match(ctx, comp, cert_content->san_list); ++ if (match && parsed_match_rule->r == relation_or) { ++ /* match */ ++ return 0; ++ } else if (!match && parsed_match_rule->r == relation_and) { ++ /* no match */ ++ return ENOENT; ++ } ++ } ++ ++ if (match) { ++ /* match */ ++ return 0; ++ } ++ ++ /* no match */ ++ return ENOENT; ++} ++ ++int sss_certmap_match_cert(struct sss_certmap_ctx *ctx, ++ const uint8_t *der_cert, size_t der_size) ++{ ++ int ret; ++ struct match_map_rule *r; ++ struct priority_list *p; ++ struct sss_cert_content *cert_content = NULL; ++ ++ ret = sss_cert_get_content(ctx, der_cert, der_size, &cert_content); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to get certificate content."); ++ return ret; ++ } ++ ++ if (ctx->prio_list == NULL) { ++ /* Match all certificates if there are no rules applied */ ++ ret = 0; ++ goto done; ++ } ++ ++ for (p = ctx->prio_list; p != NULL; p = p->next) { ++ for (r = p->rule_list; r != NULL; r = r->next) { ++ ret = do_match(ctx, r->parsed_match_rule, cert_content); ++ if (ret == 0) { ++ /* match */ ++ goto done; ++ } ++ } ++ } ++ ++ ret = ENOENT; ++done: ++ talloc_free(cert_content); ++ ++ return ret; ++} ++ ++int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx, ++ const uint8_t *der_cert, size_t der_size, ++ char **_filter, char ***_domains) ++{ ++ int ret; ++ struct match_map_rule *r; ++ struct priority_list *p; ++ struct sss_cert_content *cert_content = NULL; ++ char *filter = NULL; ++ char **domains = NULL; ++ size_t c; ++ ++ if (_filter == NULL || _domains == NULL) { ++ return EINVAL; ++ } ++ ++ ret = sss_cert_get_content(ctx, der_cert, der_size, &cert_content); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to get certificate content [%d].", ret); ++ return ret; ++ } ++ ++ if (ctx->prio_list == NULL) { ++ if (ctx->default_mapping_rule == NULL) { ++ CM_DEBUG(ctx, "No matching or mapping rules available."); ++ return EINVAL; ++ } ++ ++ ret = get_filter(ctx, ctx->default_mapping_rule, cert_content, &filter); ++ goto done; ++ } ++ ++ for (p = ctx->prio_list; p != NULL; p = p->next) { ++ for (r = p->rule_list; r != NULL; r = r->next) { ++ ret = do_match(ctx, r->parsed_match_rule, cert_content); ++ if (ret == 0) { ++ /* match */ ++ ret = get_filter(ctx, r->parsed_mapping_rule, cert_content, ++ &filter); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to get filter"); ++ goto done; ++ } ++ ++ if (r->domains != NULL) { ++ for (c = 0; r->domains[c] != NULL; c++); ++ domains = talloc_zero_array(ctx, char *, c + 1); ++ if (domains == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (c = 0; r->domains[c] != NULL; c++) { ++ domains[c] = talloc_strdup(domains, r->domains[c]); ++ if (domains[c] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ } ++ ++ ret = 0; ++ goto done; ++ } ++ } ++ } ++ ++ ret = ENOENT; ++ ++done: ++ talloc_free(cert_content); ++ if (ret == 0) { ++ *_filter = filter; ++ *_domains = domains; ++ } else { ++ talloc_free(filter); ++ talloc_free(domains); ++ } ++ ++ return ret; ++} ++ ++int sss_certmap_init(TALLOC_CTX *mem_ctx, ++ sss_certmap_ext_debug *debug, void *debug_priv, ++ struct sss_certmap_ctx **ctx) ++{ ++ int ret; ++ ++ if (ctx == NULL) { ++ return EINVAL; ++ } ++ ++ *ctx = talloc_zero(mem_ctx, struct sss_certmap_ctx); ++ if (*ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ (*ctx)->debug = debug; ++ (*ctx)->debug_priv = debug_priv; ++ ++ ret = parse_mapping_rule(*ctx, DEFAULT_MAP_RULE, ++ &((*ctx)->default_mapping_rule)); ++ if (ret != 0) { ++ CM_DEBUG((*ctx), "Failed to parse default mapping rule."); ++ talloc_free(*ctx); ++ *ctx = NULL; ++ return ret; ++ } ++ ++ CM_DEBUG((*ctx), "sss_certmap initialized."); ++ return EOK; ++} ++ ++void sss_certmap_free_ctx(struct sss_certmap_ctx *ctx) ++{ ++ talloc_free(ctx); ++} ++ ++void sss_certmap_free_filter_and_domains(char *filter, char **domains) ++{ ++ talloc_free(filter); ++ talloc_free(domains); ++} +diff --git a/src/lib/certmap/sss_certmap.doxy.in b/src/lib/certmap/sss_certmap.doxy.in +new file mode 100644 +index 0000000000000000000000000000000000000000..e8959e2099a0f517c314833e47d410306fb02702 +--- /dev/null ++++ b/src/lib/certmap/sss_certmap.doxy.in +@@ -0,0 +1,3 @@ ++PROJECT_NAME = sss_certmap ++OUTPUT_DIRECTORY = certmap_doc ++INPUT = @abs_top_srcdir@/src/lib/certmap/sss_certmap.h +diff --git a/src/lib/certmap/sss_certmap.exports b/src/lib/certmap/sss_certmap.exports +new file mode 100644 +index 0000000000000000000000000000000000000000..8b5d5366697401649547c09c6b6f3db571c2b518 +--- /dev/null ++++ b/src/lib/certmap/sss_certmap.exports +@@ -0,0 +1,13 @@ ++SSS_CERTMAP_0.0 { ++ global: ++ sss_certmap_init; ++ sss_certmap_free_ctx; ++ sss_certmap_err_msg; ++ sss_certmap_add_rule; ++ sss_certmap_match_cert; ++ sss_certmap_get_search_filter; ++ sss_cert_get_content; ++ sss_certmap_free_filter_and_domains; ++ local: ++ *; ++}; +diff --git a/src/lib/certmap/sss_certmap.h b/src/lib/certmap/sss_certmap.h +new file mode 100644 +index 0000000000000000000000000000000000000000..55485cc35e8bd7cf2cb2b0c5a06a7521025e3c43 +--- /dev/null ++++ b/src/lib/certmap/sss_certmap.h +@@ -0,0 +1,155 @@ ++/* ++ SSSD ++ ++ Library for rule based certificate to user mapping ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++#ifndef _SSS_CERTMAP_H_ ++#define _SSS_CERTMAP_H_ ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++/** ++ * @defgroup sss_certmap Allow rule-based mapping of certificates to users ++ * Libsss_certmap provides a mechanism to map X509 certificate to users based ++ * on rules. ++ * @{ ++ */ ++ ++/** ++ * Opaque type for the idmap context ++ */ ++struct sss_certmap_ctx; ++ ++/** ++ * Lowest priority of a rule ++ */ ++#define SSS_CERTMAP_MIN_PRIO UINT32_MAX ++ ++/** ++ * Typedef for external debug callback ++ */ ++typedef void (sss_certmap_ext_debug)(void *pvt, ++ const char *file, long line, ++ const char *function, ++ const char *format, ...); ++/** ++ * @brief Initialize certmap context ++ * ++ * @param[in] mem_ctx Talloc memory context, may be NULL ++ * @param[in] debug Callback to handle debug output, may be NULL ++ * @param[in] debug_priv Private data for debugging callback, may be NULL ++ * @param[out] ctx New certmap context ++ * ++ * @return ++ * - 0: success ++ * - ENOMEM: failed to allocate internal Talloc context ++ * - EINVAL: ctx is NULL ++ */ ++int sss_certmap_init(TALLOC_CTX *mem_ctx, ++ sss_certmap_ext_debug *debug, void *debug_priv, ++ struct sss_certmap_ctx **ctx); ++ ++/** ++ * @brief Free certmap context ++ * ++ * @param[in] ctx certmap context previously initialized with ++ * @ref sss_certmap_init, may be NULL ++ */ ++void sss_certmap_free_ctx(struct sss_certmap_ctx *ctx); ++ ++/** ++ * @brief Add a rule to the certmap context ++ * ++ * @param[in] ctx certmap context previously initialized with ++ * @ref sss_certmap_init ++ * @param[in] priority priority of the rule, 0 is the hightest priority, the ++ * lowest is SSS_CERTMAP_MIN_PRIO ++ * @param[in] match_rule String with the matching rule ++ * @param[in] map_rule String with the mapping rule ++ * @param[in] domains NULL-terminated string array with a list of domains ++ * the rule should be valid for, i.e. only this domains ++ * should be searched for matching users ++ * ++ * @return ++ * - 0: success ++ */ ++int sss_certmap_add_rule(struct sss_certmap_ctx *ctx, ++ uint32_t priority, const char *match_rule, ++ const char *map_rule, const char **domains); ++ ++/** ++ * @brief Check if a certificate matches any of the applied rules ++ * ++ * @param[in] ctx certmap context previously initialized with ++ * @ref sss_certmap_init ++ * @param[in] der_cert binary blog with the DER encoded certificate ++ * @param[in] der_size size of the certificate blob ++ * ++ * @return ++ * - 0: certificate matches a rule ++ * - ENOENT: certificate does not match ++ * - EINVAL: internal error ++ */ ++int sss_certmap_match_cert(struct sss_certmap_ctx *ctx, ++ const uint8_t *der_cert, size_t der_size); ++ ++/** ++ * @brief Get the LDAP filter string for a certificate ++ * ++ * @param[in] ctx certmap context previously initialized with ++ * @ref sss_certmap_init ++ * @param[in] der_cert binary blog with the DER encoded certificate ++ * @param[in] der_size size of the certificate blob ++ * @param[out] filter LDAP filter string, caller should free the data by ++ * calling sss_certmap_free_filter_and_domains ++ * @param[out] domains NULL-terminated array of strings with the domains the ++ * rule applies, caller should free the data by calling ++ * sss_certmap_free_filter_and_domains ++ * ++ * @return ++ * - 0: certificate matches a rule ++ * - ENOENT: certificate does not match ++ * - EINVAL: internal error ++ */ ++int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx, ++ const uint8_t *der_cert, size_t der_size, ++ char **filter, char ***domains); ++ ++/** ++ * @brief Free data returned by @ref sss_certmap_get_search_filter ++ * ++ * @param[in] filter LDAP filter strings returned by ++ * sss_certmap_get_search_filter ++ * @param[in] domains string array of domains returned by ++ * sss_certmap_get_search_filter ++ */ ++void sss_certmap_free_filter_and_domains(char *filter, char **domains); ++ ++/** ++ * @} ++ */ ++#endif /* _SSS_CERTMAP_H_ */ +diff --git a/src/lib/certmap/sss_certmap.pc.in b/src/lib/certmap/sss_certmap.pc.in +new file mode 100644 +index 0000000000000000000000000000000000000000..f1a4432fce8ccd5642a622ca6a8d3a7954fc7ba3 +--- /dev/null ++++ b/src/lib/certmap/sss_certmap.pc.in +@@ -0,0 +1,11 @@ ++prefix=@prefix@ ++exec_prefix=@exec_prefix@ ++libdir=@libdir@ ++includedir=@includedir@ ++ ++Name: sss_certmap ++Description: SSS certificate mapping library ++Version: @VERSION@ ++Libs: -L${libdir} -lsss_certmap ++Cflags: ++URL: https://pagure.io/SSSD/sssd/ +diff --git a/src/lib/certmap/sss_certmap_attr_names.c b/src/lib/certmap/sss_certmap_attr_names.c +new file mode 100644 +index 0000000000000000000000000000000000000000..a28a464910728cdd1f316b2b979da84f440685ea +--- /dev/null ++++ b/src/lib/certmap/sss_certmap_attr_names.c +@@ -0,0 +1,107 @@ ++/* ++ SSSD ++ ++ Library for rule based certificate to user mapping - Attribute name ++ mapping for different implementations ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++/* NSS data taken from nss-utils:nss/lib/util/secoid.c and ++ * nss:nss/lib/certdb/alg1485.c */ ++ ++/* AD data taken from ++ * https://msdn.microsoft.com/en-us/library/windows/desktop/aa376556%28v=vs.85%29.aspx ++ * and wine source code dlls/crypt32/oid.c  and include/wincrypt.h . */ ++ ++#include ++#include ++#include ++ ++struct oid_attr_name_map { ++ bool nss_ad_differ; ++ const char *oid; ++ const char *nss; ++ const char *ad; ++} oid_attr_name_map[] = { ++ { false, "2.5.4.3", "CN", "CN"}, ++ { true, "2.5.4.8", "ST", "S"}, ++ { false, "2.5.4.10", "O", "O"}, ++ { false, "2.5.4.11", "OU", "OU"}, ++ { false, "2.5.4.46", "dnQualifier", "dnQualifier"}, ++ { false, "2.5.4.6", "C", "C"}, ++ { true, "2.5.4.5", "serialNumber", "SERIALNUMBER"}, ++ { false, "2.5.4.7", "L", "L"}, ++ { true, "2.5.4.12", "title", "T"}, ++ { false, "2.5.4.4", "SN", "SN"}, ++ { true, "2.5.4.42", "givenName", "G"}, ++ { true, "2.5.4.43", "initials", "I"}, ++ { true, "2.5.4.44", "generationQualifier", "OID.2.5.4.44"}, ++ { false, "0.9.2342.19200300.100.1.25", "DC", "DC"}, ++ { true, "0.9.2342.19200300.100.1.3", "MAIL", "OID,0.9.2342.19200300.100.1.3"}, ++ { true, "0.9.2342.19200300.100.1.1", "UID", "OID.0.9.2342.19200300.100.1.1"}, ++ { true, "2.5.4.13", "OID.2.5.4.13", "Description"}, ++ { true, "2.5.4.16", "postalAddress", "OID.2.5.4.16"}, ++ { true, "2.5.4.17", "postalCode", "PostalCode"}, ++ { true, "2.5.4.18", "postOfficeBox", "POBox"}, ++ { true, "2.5.4.51", "houseIdentifier", "OID.2.5.4.51"}, ++ { false, "1.2.840.113549.1.9.1", "E", "E"}, ++ { false, "2.5.4.9", "STREET", "STREET"}, ++ { true, "2.5.4.65", "pseudonym", "OID.2.5.4.65"}, ++ { true, "2.5.4.15", "businessCategory", "OID.2.5.4.15"}, ++ { true, "2.5.4.41", "name", "OID.2.5.4.41"}, ++ ++ { false, NULL, NULL, NULL} ++}; ++ ++char *check_ad_attr_name(TALLOC_CTX *mem_ctx, const char *rdn) ++{ ++ char *p; ++ size_t c; ++ size_t len; ++ ++ if (rdn == NULL) { ++ return NULL; ++ } ++ ++ p = strchr(rdn, '='); ++ if (p == NULL) { ++ return NULL; ++ } ++ ++ len = p - rdn; ++ if (len == 0) { ++ return NULL; ++ } ++ ++ for (c = 0; oid_attr_name_map[c].oid != NULL; c++) { ++ if (!oid_attr_name_map[c].nss_ad_differ) { ++ continue; ++ } ++ ++ if (strlen(oid_attr_name_map[c].nss) != len ++ || strncmp(rdn, oid_attr_name_map[c].nss, len) != 0) { ++ continue; ++ } ++ ++ return talloc_asprintf(mem_ctx, "%s%s", oid_attr_name_map[c].ad, p); ++ } ++ ++ return NULL; ++} +diff --git a/src/lib/certmap/sss_certmap_int.h b/src/lib/certmap/sss_certmap_int.h +new file mode 100644 +index 0000000000000000000000000000000000000000..28f1c596cfb5e78077b6a8e9baefa88b4900a022 +--- /dev/null ++++ b/src/lib/certmap/sss_certmap_int.h +@@ -0,0 +1,187 @@ ++/* ++ SSSD ++ ++ Library for rule based certificate to user mapping ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++#include ++#include ++ ++#ifndef __SSS_CERTMAP_INT_H__ ++#define __SSS_CERTMAP_INT_H__ ++ ++#define CM_DEBUG(cm_ctx, format, ...) do { \ ++ if (cm_ctx != NULL && cm_ctx->debug != NULL) { \ ++ cm_ctx->debug(cm_ctx->debug_priv, __FILE__, __LINE__, __FUNCTION__, \ ++ format, ##__VA_ARGS__); \ ++ } \ ++} while (0) ++ ++#define DEFAULT_MATCH_RULE "digitalSignatureclientAuth" ++#define DEFAULT_MAP_RULE "LDAP:(userCertificate;binary={cert!bin})" ++ ++enum san_opt { ++ SAN_OTHER_NAME = 0, ++ SAN_RFC822_NAME, ++ SAN_DNS_NAME, ++ SAN_X400_ADDRESS, ++ SAN_DIRECTORY_NAME, ++ SAN_EDIPART_NAME, ++ SAN_URI, ++ SAN_IP_ADDRESS, ++ SAN_REGISTERED_ID, ++ SAN_PKINIT, ++ SAN_NT, ++ SAN_PRINCIPAL, ++ SAN_STRING_OTHER_NAME, ++ ++ SAN_END, ++ SAN_INVALID ++}; ++ ++/* KRB5 matching rule */ ++enum relation_type { ++ relation_none = 0, ++ relation_and, ++ relation_or ++}; ++ ++struct component_list { ++ char *val; ++ regex_t regexp; ++ uint32_t ku; ++ const char **eku_oid_list; ++ enum san_opt san_opt; ++ char *str_other_name_oid; ++ uint8_t *bin_val; ++ size_t bin_val_len; ++ struct component_list *prev; ++ struct component_list *next; ++}; ++ ++struct krb5_match_rule { ++ enum relation_type r; ++ struct component_list *issuer; ++ struct component_list *subject; ++ struct component_list *ku; ++ struct component_list *eku; ++ struct component_list *san; ++}; ++ ++enum comp_type { ++ comp_none = 0, ++ comp_string, ++ comp_template ++}; ++ ++struct parsed_template { ++ char *name; ++ char *attr_name; ++ char *conversion; ++}; ++ ++struct ldap_mapping_rule_comp { ++ enum comp_type type; ++ char *val; ++ struct parsed_template *parsed_template; ++ struct ldap_mapping_rule_comp *prev; ++ struct ldap_mapping_rule_comp *next; ++}; ++ ++struct ldap_mapping_rule { ++ struct ldap_mapping_rule_comp *list; ++}; ++ ++struct match_map_rule { ++ uint32_t priority; ++ char *match_rule; ++ struct krb5_match_rule *parsed_match_rule; ++ char *map_rule; ++ struct ldap_mapping_rule *parsed_mapping_rule; ++ char **domains; ++ struct match_map_rule *prev; ++ struct match_map_rule *next; ++}; ++ ++struct priority_list { ++ uint32_t priority; ++ struct match_map_rule *rule_list; ++ struct priority_list *prev; ++ struct priority_list *next; ++}; ++ ++struct sss_certmap_ctx { ++ struct priority_list *prio_list; ++ sss_certmap_ext_debug *debug; ++ void *debug_priv; ++ struct ldap_mapping_rule *default_mapping_rule; ++}; ++ ++struct san_list { ++ enum san_opt san_opt; ++ char *val; ++ uint8_t *bin_val; ++ size_t bin_val_len; ++ char *other_name_oid; ++ char *short_name; ++ const char **rdn_list; ++ struct san_list *prev; ++ struct san_list *next; ++}; ++ ++/* key usage flags, see RFC 3280 section 4.2.1.3 */ ++#define SSS_KU_DIGITAL_SIGNATURE 0x0080 ++#define SSS_KU_NON_REPUDIATION 0x0040 ++#define SSS_KU_KEY_ENCIPHERMENT 0x0020 ++#define SSS_KU_DATA_ENCIPHERMENT 0x0010 ++#define SSS_KU_KEY_AGREEMENT 0x0008 ++#define SSS_KU_KEY_CERT_SIGN 0x0004 ++#define SSS_KU_CRL_SIGN 0x0002 ++#define SSS_KU_ENCIPHER_ONLY 0x0001 ++#define SSS_KU_DECIPHER_ONLY 0x8000 ++ ++struct sss_cert_content { ++ const char *issuer_str; ++ const char **issuer_rdn_list; ++ const char *subject_str; ++ const char **subject_rdn_list; ++ uint32_t key_usage; ++ const char **extended_key_usage_oids; ++ struct san_list *san_list; ++ ++ uint8_t *cert_der; ++ size_t cert_der_size; ++}; ++ ++int sss_cert_get_content(TALLOC_CTX *mem_ctx, ++ const uint8_t *der_blob, size_t der_size, ++ struct sss_cert_content **content); ++ ++char *check_ad_attr_name(TALLOC_CTX *mem_ctx, const char *rdn); ++ ++int parse_krb5_match_rule(struct sss_certmap_ctx *ctx, ++ const char *rule_start, ++ struct krb5_match_rule **match_rule); ++ ++int parse_ldap_mapping_rule(struct sss_certmap_ctx *ctx, ++ const char *rule_start, ++ struct ldap_mapping_rule **mapping_rule); ++#endif /* __SSS_CERTMAP_INT_H__ */ +diff --git a/src/lib/certmap/sss_certmap_krb5_match.c b/src/lib/certmap/sss_certmap_krb5_match.c +new file mode 100644 +index 0000000000000000000000000000000000000000..e40f17b8ace46e61087e0a2fa570a362a84cead2 +--- /dev/null ++++ b/src/lib/certmap/sss_certmap_krb5_match.c +@@ -0,0 +1,558 @@ ++/* ++ SSSD ++ ++ Library for rule based certificate to user mapping - KRB5 matching rules ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++#include "util/util.h" ++#include "util/cert.h" ++#include "util/crypto/sss_crypto.h" ++#include "lib/certmap/sss_certmap.h" ++#include "lib/certmap/sss_certmap_int.h" ++ ++static bool is_dotted_decimal(const char *s, size_t len) ++{ ++ size_t c = 0; ++ bool has_dot = false; ++ ++ if (s == NULL || !isdigit(s[c++])) { ++ return false; ++ } ++ ++ while ((len == 0 && s[c] != '\0') || (len != 0 && c < len)) { ++ if (s[c] != '.' && !isdigit(s[c])) { ++ return false; ++ } ++ if (!has_dot && s[c] == '.') { ++ has_dot = true; ++ } ++ c++; ++ } ++ ++ return (has_dot && isdigit(s[c - 1])); ++} ++ ++static int component_list_destructor(void *data) ++{ ++ struct component_list *comp = talloc_get_type(data, struct component_list); ++ ++ if (comp != NULL) { ++ regfree(&(comp->regexp)); ++ } ++ ++ return 0; ++} ++ ++/* ++ * The syntax of the MIT Kerberos style matching rules is: ++ * [KRB5:][relation-operator]component-rule ... ++ * ++ * where: ++ * ++ * relation-operator ++ * can be either &&, meaning all component rules must match, or ||, ++ * meaning only one component rule must match. The default is &&. ++ * ++ * component-rule ++ * can be one of the following. Note that there is no punctuation or whitespace between component rules. ++ * regular-expression ++ * regular-expression ++ * regular-expression ++ * extended-key-usage ++ * key-usage ++ * ++ * see man sss-certmap for more details ++ * ++ */ ++ ++static int get_comp_value(TALLOC_CTX *mem_ctx, ++ struct sss_certmap_ctx *ctx, ++ const char **cur, ++ struct component_list **_comp) ++ ++{ ++ struct component_list *comp = NULL; ++ const char *end; ++ int ret; ++ ++ comp = talloc_zero(mem_ctx, struct component_list); ++ if (comp == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ talloc_set_destructor((TALLOC_CTX *) comp, component_list_destructor); ++ ++ end = strchr(*cur, '<'); ++ ++ if (end == NULL) { ++ comp->val = talloc_strdup(comp, *cur); ++ } else { ++ comp->val = talloc_strndup(comp, *cur, end - *cur); ++ } ++ if (comp->val == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ if (*(comp->val) == '\0') { ++ CM_DEBUG(ctx, "Missing component value."); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ *cur += strlen(comp->val); ++ *_comp = comp; ++ ret = 0; ++ ++done: ++ if (ret != 0) { ++ talloc_free(comp); ++ } ++ ++ return ret; ++} ++ ++static int parse_krb5_get_eku_value(TALLOC_CTX *mem_ctx, ++ struct sss_certmap_ctx *ctx, ++ const char **cur, ++ struct component_list **_comp) ++{ ++ struct component_list *comp = NULL; ++ int ret; ++ char **eku_list; ++ size_t c; ++ size_t k; ++ const char *o; ++ size_t e = 0; ++ int eku_list_size; ++ ++ struct ext_key_usage { ++ const char *name; ++ const char *oid; ++ } ext_key_usage[] = { ++ /* RFC 3280 section 4.2.1.13 */ ++ {"serverAuth", "1.3.6.1.5.5.7.3.1"}, ++ {"clientAuth", "1.3.6.1.5.5.7.3.2"}, ++ {"codeSigning", "1.3.6.1.5.5.7.3.3"}, ++ {"emailProtection", "1.3.6.1.5.5.7.3.4"}, ++ {"timeStamping", "1.3.6.1.5.5.7.3.8"}, ++ {"OCSPSigning", "1.3.6.1.5.5.7.3.9"}, ++ ++ /* RFC 4556 section 3.2.2 */ ++ {"KPClientAuth", "1.3.6.1.5.2.3.4"}, ++ {"pkinit", "1.3.6.1.5.2.3.4"}, ++ ++ /* https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography*/ ++ {"msScLogin", "1.3.6.1.4.1.311.20.2.2"}, ++ ++ {NULL ,0} ++ }; ++ ++ ret = get_comp_value(mem_ctx, ctx, cur, &comp); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to parse regexp."); ++ goto done; ++ } ++ ++ ret = split_on_separator(mem_ctx, comp->val, ',', true, true, ++ &eku_list, &eku_list_size); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to split list."); ++ goto done; ++ } ++ ++ for (c = 0; eku_list[c] != NULL; c++) { ++ for (k = 0; ext_key_usage[k].name != NULL; k++) { ++CM_DEBUG(ctx, "[%s][%s].", eku_list[c], ext_key_usage[k].name); ++ if (strcasecmp(eku_list[c], ext_key_usage[k].name) == 0) { ++ if (comp->eku_oid_list == NULL) { ++ comp->eku_oid_list = talloc_zero_array(comp, const char *, ++ eku_list_size + 1); ++ if (comp->eku_oid_list == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ comp->eku_oid_list[e] = talloc_strdup(comp->eku_oid_list, ++ ext_key_usage[k].oid); ++ if (comp->eku_oid_list[e] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ e++; ++ break; ++ } ++ } ++ ++ if (ext_key_usage[k].name == NULL) { ++ /* check for an dotted-decimal OID */ ++ if (*(eku_list[c]) != '.') { ++ o = eku_list[c]; ++ if (is_dotted_decimal(o, 0)) { ++ /* looks like a OID, only '.' and digits */ ++ comp->eku_oid_list[e] = talloc_strdup(comp->eku_oid_list, ++ eku_list[c]); ++ if (comp->eku_oid_list[e] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ e++; ++ continue; ++ } ++ } ++ CM_DEBUG(ctx, "No matching extended key usage found."); ++ ret = EINVAL; ++ goto done; ++ } ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *_comp = comp; ++ } else { ++ talloc_free(comp); ++ } ++ ++ return ret; ++} ++ ++static int parse_krb5_get_ku_value(TALLOC_CTX *mem_ctx, ++ struct sss_certmap_ctx *ctx, ++ const char **cur, ++ struct component_list **_comp) ++{ ++ struct component_list *comp = NULL; ++ int ret; ++ char **ku_list; ++ size_t c; ++ size_t k; ++ ++ struct key_usage { ++ const char *name; ++ uint32_t flag; ++ } key_usage[] = { ++ {"digitalSignature" , SSS_KU_DIGITAL_SIGNATURE}, ++ {"nonRepudiation" , SSS_KU_NON_REPUDIATION}, ++ {"keyEncipherment" , SSS_KU_KEY_ENCIPHERMENT}, ++ {"dataEncipherment" , SSS_KU_DATA_ENCIPHERMENT}, ++ {"keyAgreement" , SSS_KU_KEY_AGREEMENT}, ++ {"keyCertSign" , SSS_KU_KEY_CERT_SIGN}, ++ {"cRLSign" , SSS_KU_CRL_SIGN}, ++ {"encipherOnly" , SSS_KU_ENCIPHER_ONLY}, ++ {"decipherOnly" , SSS_KU_DECIPHER_ONLY}, ++ {NULL ,0} ++ }; ++ ++ ++ ret = get_comp_value(mem_ctx, ctx, cur, &comp); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to get value."); ++ goto done; ++ } ++ ++ ret = split_on_separator(mem_ctx, comp->val, ',', true, true, ++ &ku_list, NULL); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to split list."); ++ goto done; ++ } ++ ++ for (c = 0; ku_list[c] != NULL; c++) { ++ for (k = 0; key_usage[k].name != NULL; k++) { ++ if (strcasecmp(ku_list[c], key_usage[k].name) == 0) { ++ comp->ku |= key_usage[k].flag; ++ break; ++ } ++ } ++ ++ if (key_usage[k].name == NULL) { ++ /* FIXME: add check for numerical ku */ ++ CM_DEBUG(ctx, "No matching key usage found."); ++ ret = EINVAL; ++ goto done; ++ } ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *_comp = comp; ++ } else { ++ talloc_free(comp); ++ } ++ ++ return ret; ++} ++ ++static int parse_krb5_get_component_value(TALLOC_CTX *mem_ctx, ++ struct sss_certmap_ctx *ctx, ++ const char **cur, ++ struct component_list **_comp) ++{ ++ struct component_list *comp = NULL; ++ int ret; ++ ++ ret = get_comp_value(mem_ctx, ctx, cur, &comp); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to parse regexp."); ++ goto done; ++ } ++ ++ ret = regcomp(&(comp->regexp), comp->val, REG_EXTENDED); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to parse regexp."); ++ goto done; ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *_comp = comp; ++ } else { ++ talloc_free(comp); ++ } ++ ++ return ret; ++} ++ ++struct san_name { ++ const char *name; ++ enum san_opt san_opt; ++ bool is_string; ++} san_names[] = { ++ /* https://www.ietf.org/rfc/rfc3280.txt section 4.2.1.7 */ ++ {"otherName", SAN_OTHER_NAME, false}, ++ {"rfc822Name", SAN_RFC822_NAME,true}, ++ {"dNSName", SAN_DNS_NAME, true}, ++ {"x400Address", SAN_X400_ADDRESS, false}, ++ {"directoryName", SAN_DIRECTORY_NAME, true}, ++ {"ediPartyName", SAN_EDIPART_NAME, false}, ++ {"uniformResourceIdentifier", SAN_URI, true}, ++ {"iPAddress", SAN_IP_ADDRESS, true}, ++ {"registeredID", SAN_REGISTERED_ID, true}, ++ /* https://www.ietf.org/rfc/rfc4556.txt section 3.2.2 */ ++ {"pkinitSAN", SAN_PKINIT, true}, ++ /* https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography */ ++ {"ntPrincipalName", SAN_NT, true}, ++ /* both previous principal types */ ++ {"Principal", SAN_PRINCIPAL, true}, ++ {"stringOtherName", SAN_STRING_OTHER_NAME, true}, ++ {NULL, SAN_END, false} ++}; ++ ++static int parse_krb5_get_san_option(TALLOC_CTX *mem_ctx, ++ struct sss_certmap_ctx *ctx, ++ const char **cur, ++ enum san_opt *option, ++ char **str_other_name_oid) ++{ ++ char *end; ++ size_t c; ++ size_t len; ++ ++ end = strchr(*cur, '>'); ++ if (end == NULL) { ++ CM_DEBUG(ctx, "Failed to parse SAN option."); ++ return EINVAL; ++ } ++ ++ len = end - *cur; ++ ++ if (len == 0) { ++ c= SAN_PRINCIPAL; ++ } else { ++ for (c = 0; san_names[c].name != NULL; c++) { ++ if (strncasecmp(*cur, san_names[c].name, len) == 0) { ++ break; ++ } ++ } ++ if (san_names[c].name == NULL) { ++ if (is_dotted_decimal(*cur, len)) { ++ c = SAN_STRING_OTHER_NAME; ++ *str_other_name_oid = talloc_strndup(mem_ctx, *cur, len); ++ if (*str_other_name_oid == NULL) { ++ CM_DEBUG(ctx, "talloc_strndup failed."); ++ return ENOMEM; ++ } ++ } else { ++ CM_DEBUG(ctx, "Unknown SAN option."); ++ return EINVAL; ++ } ++ } ++ } ++ ++ *option = san_names[c].san_opt; ++ *cur = end + 1; ++ ++ return 0; ++} ++ ++static int parse_krb5_get_san_value(TALLOC_CTX *mem_ctx, ++ struct sss_certmap_ctx *ctx, ++ const char **cur, ++ struct component_list **_comp) ++{ ++ struct component_list *comp = NULL; ++ enum san_opt san_opt = SAN_PRINCIPAL; ++ int ret; ++ char *str_other_name_oid = NULL; ++ ++ if (*(*cur - 1) == ':') { ++ ret = parse_krb5_get_san_option(mem_ctx, ctx, cur, &san_opt, ++ &str_other_name_oid); ++ if (ret != 0) { ++ goto done; ++ } ++ } ++ ++ if (san_names[san_opt].is_string) { ++ ret = parse_krb5_get_component_value(mem_ctx, ctx, cur, &comp); ++ if (ret != 0) { ++ goto done; ++ } ++ } else { ++ ret = get_comp_value(mem_ctx, ctx, cur, &comp); ++ if (ret != 0) { ++ goto done; ++ } ++ ++ if (comp->val != NULL) { ++ comp->bin_val = sss_base64_decode(comp, comp->val, ++ &comp->bin_val_len); ++ /* for some reasons the NSS version of sss_base64_decode might ++ * return a non-NULL value on error but len is still 0, so better ++ * check both. */ ++ if (comp->bin_val == NULL || comp->bin_val_len == 0) { ++ CM_DEBUG(ctx, "Base64 decode failed."); ++ ret = EINVAL; ++ goto done; ++ } ++ } ++ } ++ comp->san_opt = san_opt; ++ ++done: ++ if (ret == 0) { ++ comp->str_other_name_oid = talloc_steal(comp, str_other_name_oid); ++ *_comp = comp; ++ } else { ++ talloc_free(comp); ++ talloc_free(str_other_name_oid); ++ } ++ ++ return ret; ++} ++ ++int parse_krb5_match_rule(struct sss_certmap_ctx *ctx, ++ const char *rule_start, ++ struct krb5_match_rule **match_rule) ++{ ++ const char *cur; ++ struct krb5_match_rule *rule; ++ struct component_list *comp; ++ int ret; ++ ++ rule = talloc_zero(ctx, struct krb5_match_rule); ++ if (rule == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ cur = rule_start; ++ /* check relation */ ++ if (strncmp(cur, "&&", 2) == 0) { ++ rule->r = relation_and; ++ cur += 2; ++ } else if (strncmp(cur, "||", 2) == 0) { ++ rule->r = relation_or; ++ cur += 2; ++ } else { ++ rule->r = relation_and; ++ } ++ ++ while (*cur != '\0') { ++ /* new component must start with '<' */ ++ if (*cur != '<') { ++ CM_DEBUG(ctx, "Invalid KRB5 matching rule."); ++ ret = EINVAL; ++ goto done; ++ } ++ cur++; ++ ++ if (strncmp(cur, "ISSUER>", 7) == 0) { ++ cur += 7; ++ ret = parse_krb5_get_component_value(rule, ctx, &cur, &comp); ++ if (ret != 0) { ++ goto done; ++ } ++ DLIST_ADD(rule->issuer, comp); ++ } else if (strncmp(cur, "SUBJECT>", 8) == 0) { ++ cur += 8; ++ ret = parse_krb5_get_component_value(rule, ctx, &cur, &comp); ++ if (ret != 0) { ++ goto done; ++ } ++ DLIST_ADD(rule->subject, comp); ++ } else if (strncmp(cur, "KU>", 3) == 0) { ++ cur += 3; ++ ret = parse_krb5_get_ku_value(rule, ctx, &cur, &comp); ++ if (ret != 0) { ++ goto done; ++ } ++ DLIST_ADD(rule->ku, comp); ++ } else if (strncmp(cur, "EKU>", 4) == 0) { ++ cur += 4; ++ ret = parse_krb5_get_eku_value(rule, ctx, &cur, &comp); ++ if (ret != 0) { ++ goto done; ++ } ++ DLIST_ADD(rule->eku, comp); ++ } else if (strncmp(cur, "SAN>", 4) == 0 ++ || strncmp(cur, "SAN:", 4) == 0) { ++ cur += 4; ++ ret = parse_krb5_get_san_value(rule, ctx, &cur, &comp); ++ if (ret != 0) { ++ goto done; ++ } ++ DLIST_ADD(rule->san, comp); ++ } else { ++ CM_DEBUG(ctx, "Invalid KRB5 matching rule."); ++ ret = EINVAL; ++ goto done; ++ } ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *match_rule = rule; ++ } else { ++ talloc_free(rule); ++ } ++ ++ return ret; ++} +diff --git a/src/lib/certmap/sss_certmap_ldap_mapping.c b/src/lib/certmap/sss_certmap_ldap_mapping.c +new file mode 100644 +index 0000000000000000000000000000000000000000..c64c05b311f043b4d70f98f718780601c3e6a002 +--- /dev/null ++++ b/src/lib/certmap/sss_certmap_ldap_mapping.c +@@ -0,0 +1,367 @@ ++/* ++ SSSD ++ ++ Library for rule based certificate to user mapping - LDAP mapping rules ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++#include "util/util.h" ++#include "util/cert.h" ++#include "util/crypto/sss_crypto.h" ++#include "lib/certmap/sss_certmap.h" ++#include "lib/certmap/sss_certmap_int.h" ++struct template_table { ++ const char *name; ++ const char **attr_name; ++ const char **conversion; ++}; ++ ++const char *empty[] = {NULL}; ++const char *name_attr[] = {"short_name", NULL}; ++const char *x500_conv[] = {"ad_x500", "ad", "ad_ldap", ++ "nss_x500", "nss", "nss_ldap", NULL}; ++const char *bin_conv[] = {"bin", "base64", NULL}; ++ ++struct template_table template_table[] = { ++ {"issuer_dn", empty, x500_conv}, ++ {"subject_dn", empty, x500_conv}, ++ {"cert", empty, bin_conv}, ++ {"subject_rfc822_name", name_attr, empty}, ++ {"subject_dns_name", name_attr, empty}, ++ {"subject_x400_address", empty, empty}, ++ {"subject_directory_name", empty, empty}, ++ {"subject_ediparty_name", empty, empty}, ++ {"subject_uri", empty, empty}, ++ {"subject_ip_address", empty, empty}, ++ {"subject_registered_id", empty, empty}, ++ {"subject_pkinit_principal", name_attr, empty}, ++ {"subject_nt_principal", name_attr, empty}, ++ {"subject_principal", name_attr, empty}, ++ {NULL, NULL, NULL}}; ++ ++static int check_parsed_template(struct sss_certmap_ctx *ctx, ++ struct parsed_template *parsed) ++{ ++ size_t n; ++ size_t a; ++ size_t c; ++ bool attr_name_valid = false; ++ bool conversion_valid = false; ++ ++ for (n = 0; template_table[n].name != NULL; n++) { ++ if (strcmp(template_table[n].name, parsed->name) != 0) { ++ continue; ++ } ++ ++ if (parsed->attr_name != NULL) { ++ for (a = 0; template_table[n].attr_name[a] != NULL; a++) { ++ if (strcmp(template_table[n].attr_name[a], ++ parsed->attr_name) == 0) { ++ attr_name_valid = true; ++ break; ++ } ++ } ++ } else { ++ attr_name_valid = true; ++ } ++ ++ if (parsed->conversion != NULL) { ++ for (c = 0; template_table[n].conversion[c] != NULL; c++) { ++ if (strcmp(template_table[n].conversion[c], ++ parsed->conversion) == 0) { ++ conversion_valid = true; ++ break; ++ } ++ } ++ } else { ++ conversion_valid = true; ++ } ++ ++ if (attr_name_valid && conversion_valid) { ++ return 0; ++ } ++ } ++ ++ return EINVAL; ++} ++ ++static int parse_template(TALLOC_CTX *mem_ctx, struct sss_certmap_ctx *ctx, ++ const char *template, ++ struct parsed_template **parsed_template) ++{ ++ int ret; ++ struct parsed_template *parsed = NULL; ++ const char *dot; ++ const char *excl; ++ const char *p; ++ ++ parsed = talloc_zero(mem_ctx, struct parsed_template); ++ if (parsed == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ dot = strchr(template, '.'); ++ if (dot != NULL) { ++ p = strchr(dot + 1, '.'); ++ if (p != NULL) { ++ CM_DEBUG(ctx, "Only one '.' allowed in template."); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ if (dot == template) { ++ CM_DEBUG(ctx, "Missing name in template."); ++ ret = EINVAL; ++ goto done; ++ } ++ } ++ ++ excl = strchr(template, '!'); ++ if (excl != NULL) { ++ p = strchr(excl + 1, '!'); ++ if (p != NULL) { ++ CM_DEBUG(ctx, "Only one '!' allowed in template."); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ if (excl == template) { ++ CM_DEBUG(ctx, "Missing name in template."); ++ ret = EINVAL; ++ goto done; ++ } ++ } ++ ++ if (excl != NULL && excl[1] != '\0') { ++ parsed->conversion = talloc_strdup(parsed, excl + 1); ++ if (parsed->conversion == NULL) { ++ CM_DEBUG(ctx, "Memory allocation failed."); ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ if (dot != NULL && dot[1] != '\0' && dot[1] != '!') { ++ if (excl == NULL) { ++ parsed->attr_name = talloc_strdup(parsed, dot + 1); ++ } else { ++ parsed->attr_name = talloc_strndup(parsed, dot + 1, ++ (excl - dot - 1)); ++ } ++ if (parsed->attr_name == NULL) { ++ CM_DEBUG(ctx, "Memory allocation failed."); ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ if (dot != NULL) { ++ parsed->name = talloc_strndup(parsed, template, (dot - template)); ++ } else if (excl != NULL) { ++ parsed->name = talloc_strndup(parsed, template, (excl - template)); ++ } else { ++ parsed->name = talloc_strdup(parsed, template); ++ } ++ if (parsed->name == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = check_parsed_template(ctx, parsed); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Parse template invalid."); ++ goto done; ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *parsed_template = parsed; ++ } else { ++ talloc_free(parsed); ++ } ++ ++ return ret; ++} ++ ++static int add_comp(struct sss_certmap_ctx *ctx, struct ldap_mapping_rule *rule, ++ const char *string, enum comp_type type) ++{ ++ int ret; ++ struct ldap_mapping_rule_comp *comp; ++ ++ comp = talloc_zero(rule, struct ldap_mapping_rule_comp); ++ if (comp == NULL) { ++ return ENOMEM; ++ } ++ ++ comp->type = type; ++ comp->val = talloc_strdup(comp, string); ++ if (comp->val == NULL) { ++ talloc_free(comp); ++ return ENOMEM; ++ } ++ ++ if (type == comp_template) { ++ ret = parse_template(comp, ctx, string, &comp->parsed_template); ++ if (ret != 0) { ++ talloc_free(comp); ++ return ret; ++ } ++ } ++ ++ DLIST_ADD_END(rule->list, comp, struct ldap_mapping_rule_comp *); ++ ++ return 0; ++} ++ ++static int add_string(struct sss_certmap_ctx *ctx, ++ struct ldap_mapping_rule *rule, const char *string) ++{ ++ return add_comp(ctx, rule, string, comp_string); ++} ++ ++static int add_template(struct sss_certmap_ctx *ctx, ++ struct ldap_mapping_rule *rule, const char *string) ++{ ++ return add_comp(ctx, rule, string, comp_template); ++} ++ ++int parse_ldap_mapping_rule(struct sss_certmap_ctx *ctx, ++ const char *rule_start, ++ struct ldap_mapping_rule **mapping_rule) ++{ ++ size_t c; ++ const char *cur; ++ char *tmp_string = NULL; ++ size_t tmp_string_size; ++ struct ldap_mapping_rule *rule = NULL; ++ int ret; ++ bool in_template = false; ++ ++ rule = talloc_zero(ctx, struct ldap_mapping_rule); ++ if (rule == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tmp_string_size = strlen(rule_start) + 1; ++ tmp_string = talloc_zero_size(ctx, tmp_string_size); ++ if (tmp_string == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ cur = rule_start; ++ c = 0; ++ ++ while (*cur != '\0') { ++ if (c > tmp_string_size) { ++ CM_DEBUG(ctx, "Cannot parse mapping rule."); ++ ret = EIO; ++ goto done; ++ } ++ switch (*cur) { ++ case '{': ++ if (in_template) { ++ CM_DEBUG(ctx, "'{' not allowed in templates."); ++ ret = EINVAL; ++ goto done; ++ } ++ if (cur[1] == '{') { ++ /* Add only a single '{' to the output */ ++ tmp_string[c] = '{'; ++ c++; ++ cur += 2; ++ } else { ++ if (c != 0) { ++ ret = add_string(ctx, rule, tmp_string); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to add string."); ++ ret = EINVAL; ++ goto done; ++ } ++ memset(tmp_string, 0, tmp_string_size); ++ c = 0; ++ } ++ cur++; ++ in_template = true; ++ } ++ break; ++ case '}': ++ if (cur[1] == '}') { ++ if (in_template) { ++ CM_DEBUG(ctx, "'}}' not allowed in templates."); ++ ret = EINVAL; ++ goto done; ++ } else { ++ /* Add only a single '}' to the output */ ++ tmp_string[c] = '}'; ++ c++; ++ cur += 2; ++ } ++ } else { ++ ret = add_template(ctx, rule, tmp_string); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to add template."); ++ ret = EINVAL; ++ goto done; ++ } ++ memset(tmp_string, 0, tmp_string_size); ++ c = 0; ++ cur++; ++ in_template = false; ++ } ++ break; ++ default: ++ tmp_string[c] = *cur; ++ c++; ++ cur++; ++ } ++ } ++ if (in_template) { ++ CM_DEBUG(ctx, "Rule ended inside template."); ++ ret = EINVAL; ++ goto done; ++ } ++ if (c != 0) { ++ ret = add_string(ctx, rule, tmp_string); ++ if (ret != 0) { ++ CM_DEBUG(ctx, "Failed to add string."); ++ ret = EINVAL; ++ goto done; ++ } ++ } ++ ++ ret = 0; ++ ++done: ++ if (ret == 0) { ++ *mapping_rule = rule; ++ } else { ++ talloc_free(rule); ++ } ++ ++ talloc_free(tmp_string); ++ ++ return ret; ++} +diff --git a/src/man/Makefile.am b/src/man/Makefile.am +index 215ce693b56e74db394dbc238c03c87f5f6efe99..142d6e2743f814294e3d92c8342070b8230bb3e5 100644 +--- a/src/man/Makefile.am ++++ b/src/man/Makefile.am +@@ -59,7 +59,7 @@ man_MANS = \ + sss_useradd.8 sss_userdel.8 sss_usermod.8 \ + sss_groupadd.8 sss_groupdel.8 sss_groupmod.8 \ + sssd.8 sssd.conf.5 sssd-ldap.5 \ +- sssd-krb5.5 sssd-simple.5 \ ++ sssd-krb5.5 sssd-simple.5 sss-certmap.5 \ + sssd_krb5_locator_plugin.8 sss_groupshow.8 \ + pam_sss.8 sss_obfuscate.8 sss_cache.8 sss_debuglevel.8 sss_seed.8 \ + sss_override.8 idmap_sss.8 sssctl.8 \ +diff --git a/src/man/po/po4a.cfg b/src/man/po/po4a.cfg +index ffcf9a2793da3c0115bc846744ccb9592a9a68ef..d1f6ac39f841c61ae3d2393fb3402dc21b9cbd69 100644 +--- a/src/man/po/po4a.cfg ++++ b/src/man/po/po4a.cfg +@@ -6,6 +6,7 @@ + [type:docbook] pam_sss.8.xml $lang:$(builddir)/$lang/pam_sss.8.xml + [type:docbook] sssd_krb5_locator_plugin.8.xml $lang:$(builddir)/$lang/sssd_krb5_locator_plugin.8.xml + [type:docbook] sssd-simple.5.xml $lang:$(builddir)/$lang/sssd-simple.5.xml ++[type:docbook] sss-certmap.5.xml $lang:$(builddir)/$lang/sss-certmap.5.xml + [type:docbook] sssd-ipa.5.xml $lang:$(builddir)/$lang/sssd-ipa.5.xml + [type:docbook] sssd-ad.5.xml $lang:$(builddir)/$lang/sssd-ad.5.xml + [type:docbook] sssd-sudo.5.xml $lang:$(builddir)/$lang/sssd-sudo.5.xml +diff --git a/src/man/sss-certmap.5.xml b/src/man/sss-certmap.5.xml +new file mode 100644 +index 0000000000000000000000000000000000000000..bbe68509f2222613a7ed69599519d7fca0506df0 +--- /dev/null ++++ b/src/man/sss-certmap.5.xml +@@ -0,0 +1,600 @@ ++ ++ ++ ++SSSD Manual pages ++ ++ ++ ++ ++ sss-certmap ++ 5 ++ File Formats and Conventions ++ ++ ++ ++ sss-certmap ++ SSSD Certificate Matching and Mapping Rules ++ ++ ++ ++ DESCRIPTION ++ ++ The manual page describes the rules which can be used by SSSD and ++ other components to match X.509 certificates and map them to ++ accounts. ++ ++ ++ Each rule has four components, a priority, a ++ matching rule, a mapping rule and a ++ domain list. All components are optional. A missing ++ priority will add the rule with the lowest priority. ++ The default matching rule will match certificates with ++ the digitalSignature key usage and clientAuth extended key usage. If ++ the mapping rule is empty the certificates will be ++ searched in the userCertificate attribute as DER encoded binary. If ++ no domains are given only the local domain will be searched. ++ ++ ++ ++ ++ RULE COMPONENTS ++ ++ PRIORITY ++ ++ The rules are process by priority while the number '0' (zero) ++ indicates the highest priority. The higher the number the lower is ++ the priority. A missing value indicates the lowest priority. ++ ++ ++ Internally the priority is treated as unsigned 32bit integer, using ++ a priority value larger than 4294967295 will cause an error. ++ ++ ++ ++ MATCHING RULE ++ ++ The matching rule is used to select a certificate to which the ++ mapping rule should be applied. It uses a system similar to the one ++ used by pkinit_cert_match option of MIT Kerberos. It ++ consists of a keyword enclosed by '<' and '>' which identified ++ a certain part of the certificate and a pattern which should be ++ found for the rule to match. Multiple keyword pattern pairs can be ++ either joined with '&&' (and) or '||' (or). ++ ++ ++ The available options are: ++ ++ ++ <SUBJECT>regular-expression ++ ++ ++ With this a part or the whole subject name of the ++ certificate can be matched. For the matching POSIX ++ Extended Regular Expression syntax is used, see regex(7) ++ for details. ++ ++ ++ For the matching the subject name stored in the ++ certificate in DER encoded ASN.1 is converted into a ++ string according to RFC 4514. This means the most ++ specific name component comes first. Please note that ++ not all possible attribute names are covered by RFC ++ 4514. The names included are 'CN', 'L', 'ST', 'O', ++ 'OU', 'C', 'STREET', 'DC' and 'UID'. Other attribute ++ names might be shown differently on different platform ++ and by different tools. To avoid confusion those ++ attribute names are best not used or covered by a ++ suitable regular-expression. ++ ++ ++ Example: <SUBJECT>.*,DC=MY,DC=DOMAIN ++ ++ ++ ++ ++ <ISSUER>regular-expression ++ ++ ++ With this a part or the whole issuer name of the ++ certificate can be matched. All comments for ++ <SUBJECT> apply her as well. ++ ++ ++ Example: <ISSUER>^CN=My-CA,DC=MY,DC=DOMAIN$ ++ ++ ++ ++ ++ <KU>key-usage ++ ++ ++ This option can be used to specify which key usage ++ values the certificate should have. The following value ++ can be used in a comma separate list: ++ ++ digitalSignature ++ nonRepudiation ++ keyEncipherment ++ dataEncipherment ++ keyAgreement ++ keyCertSign ++ cRLSign ++ encipherOnly ++ decipherOnly ++ ++ ++ ++ A numerical value in the range of a 32bit unsigned ++ integer can be used as well to cover special use cases. ++ ++ ++ Example: <KU>digitalSignature,keyEncipherment ++ ++ ++ ++ ++ <EKU>extended-key-usage ++ ++ ++ This option can be used to specify which extended key ++ usage the certificate should have. The following value ++ can be used in a comma separated list: ++ ++ serverAuth ++ clientAuth ++ codeSigning ++ emailProtection ++ timeStamping ++ OCSPSigning ++ KPClientAuth ++ pkinit ++ msScLogin ++ ++ ++ ++ Extended key usages which are not listed above can be ++ specified with their OID in dotted-decimal notation. ++ ++ ++ Example: <EKU>clientAuth,1.3.6.1.5.2.3.4 ++ ++ ++ ++ ++ <SAN>regular-expression ++ ++ ++ To be compatible with the usage of MIT Kerberos this ++ option will match the Kerberos principals in the PKINIT ++ or AD NT Principal SAN as <SAN:Principal> does. ++ ++ ++ Example: <SAN>.*@MY\.REALM ++ ++ ++ ++ ++ <SAN:Principal>regular-expression ++ ++ ++ Match the Kerberos principals in the PKINIT or AD NT ++ Principal SAN. ++ ++ ++ Example: <SAN:Principal>.*@MY\.REALM ++ ++ ++ ++ ++ <SAN:ntPrincipalName>regular-expression ++ ++ ++ Match the Kerberos principals from the AD NT Principal ++ SAN. ++ ++ ++ Example: <SAN:ntPrincipalName>.*@MY.AD.REALM ++ ++ ++ ++ ++ <SAN:pkinit>regular-expression ++ ++ ++ Match the Kerberos principals from the PKINIT SAN. ++ ++ ++ Example: <SAN:ntPrincipalName>.*@MY\.PKINIT\.REALM ++ ++ ++ ++ ++ <SAN:dotted-decimal-oid>regular-expression ++ ++ ++ Take the value of the otherName SAN component given by ++ the OID in dotted-decimal notation, interpret it as ++ string and try to match it against the regular ++ expression. ++ ++ ++ Example: <SAN:1.2.3.4>test ++ ++ ++ ++ ++ <SAN:otherName>base64-string ++ ++ ++ Do a binary match with the base64 encoded blob against ++ all otherName SAN components. With this option it is ++ possible to match against custom otherName components ++ with special encodings which could not be treated as ++ strings. ++ ++ ++ Example: <SAN:otherName>MTIz ++ ++ ++ ++ ++ <SAN:rfc822Name>regular-expression ++ ++ ++ Match the value of the rfc822Name SAN. ++ ++ ++ Example: <SAN:rfc822Name>.*@email\.domain ++ ++ ++ ++ ++ <SAN:dNSName>regular-expression ++ ++ ++ Match the value of the dNSName SAN. ++ ++ ++ Example: <SAN:dNSName>.*\.my\.dns\.domain ++ ++ ++ ++ ++ <SAN:x400Address>base64-string ++ ++ ++ Binary match the value of the x400Address SAN. ++ ++ ++ Example: <SAN:x400Address>MTIz ++ ++ ++ ++ ++ <SAN:directoryName>regular-expression ++ ++ ++ Match the value of the directoryName SAN. The same ++ comments as given for <ISSUER> and <SUBJECT> ++ apply here as well. ++ ++ ++ Example: <SAN:directoryName>.*,DC=com ++ ++ ++ ++ ++ <SAN:ediPartyName>base64-string ++ ++ ++ Binary match the value of the ediPartyName SAN. ++ ++ ++ Example: <SAN:ediPartyName>MTIz ++ ++ ++ ++ ++ <SAN:uniformResourceIdentifier>regular-expression ++ ++ ++ Match the value of the uniformResourceIdentifier SAN. ++ ++ ++ Example: <SAN:uniformResourceIdentifier>URN:.* ++ ++ ++ ++ ++ <SAN:iPAddress>regular-expression ++ ++ ++ Match the value of the iPAddress SAN. ++ ++ ++ Example: <SAN:iPAddress>192\.168\..* ++ ++ ++ ++ ++ <SAN:registeredID>regular-expression ++ ++ ++ Match the value of the registeredID SAN as ++ dotted-decimal string. ++ ++ ++ Example: <SAN:registeredID>1\.2\.3\..* ++ ++ ++ ++ ++ ++ ++ ++ MAPPING RULE ++ ++ The mapping rule is used to associate a certificate with one or more ++ accounts. A Smartcard with the certificate and the matching private ++ key can then be used to authenticate as one of those accounts. ++ ++ ++ Currently SSSD basically only supports LDAP to lookup user ++ information (the exception is the proxy provider which is not of ++ relevance here). Because of this the mapping rule is based on LDAP ++ search filter syntax with templates to add certificate content to ++ the filter. It is expected that the filter will only contain the ++ specific data needed for the mapping an that the caller will embed ++ it in another filter to do the actual search. Because of this the ++ filter string should start and stop with '(' and ')' respectively. ++ ++ ++ In general it is recommended to use attributes from the certificate ++ and add them to special attributes to the LDAP user object. E.g. the ++ 'altSecurityIdentities' attribute in AD or the 'ipaCertMapData' ++ attribute for IPA can be used. ++ ++ ++ This should be preferred to read user specific data from the ++ certificate like e.g. an email address and search for it in the LDAP ++ server. The reason is that the user specific data in LDAP might ++ change for various reasons would would break the mapping. On the ++ other hand it would be hard to break the mapping on purpose for a ++ specific user. ++ ++ ++ The templates to add certificate data to the search filter are based ++ on Python-style formatting strings. They consists of a keyword in ++ curly braces with an optional sub-component specifier separated by a ++ '.' or an optional conversion/formatting option separated by a '!'. ++ Allowed values are: ++ ++ ++ {issuer_dn[!((ad|ad_x500)|ad_ldap|nss_x500|(nss|nss_ldap))]} ++ ++ ++ This template will add the full issuer DN converted to a ++ string according to RFC 4514. If X.500 ordering (most ++ specific RDN comes last) an option with the '_x500' ++ prefix should be used. ++ ++ ++ The conversion options starting with 'ad_' will use ++ attribute names as used by AD, e.g. 'S' instead of 'ST'. ++ ++ ++ The conversion options starting with 'nss_' will use ++ attribute names as used by NSS. ++ ++ ++ The default conversion option is 'nss', i.e. attribute ++ names according to NSS and LDAP/RFC 4514 ordering. ++ ++ ++ Example: (ipacertmapdata=X509:<I>{issuer_dn!ad}<S>{subject_dn!ad}) ++ ++ ++ ++ ++ {subject_dn[!((ad|ad_x500)|ad_ldap|nss_x500|(nss|nss_ldap))]} ++ ++ ++ This template will add the full subject DN converted to ++ string according to RFC 4514. If X.500 ordering (most ++ specific RDN comes last) an option with the '_x500' ++ prefix should be used. ++ ++ ++ The conversion options starting with 'ad_' will use ++ attribute names as used by AD, e.g. 'S' instead of 'ST'. ++ ++ ++ The conversion options starting with 'nss_' will use ++ attribute names as used by NSS. ++ ++ ++ The default conversion option is 'nss', i.e. attribute ++ names according to NSS and LDAP/RFC 4514 ordering. ++ ++ ++ Example: (ipacertmapdata=X509:<I>{issuer_dn!nss_x500}<S>{subject_dn!nss_x500}) ++ ++ ++ ++ ++ {cert[!(bin|base64)]} ++ ++ ++ This template will add the whole DER encoded certificate ++ as a string to the search filter. Depending on the ++ conversion option the binary certificate is either ++ converted to an escaped hex sequence '\xx' or base64. ++ The escaped hex sequence is the default and can e.g. be ++ used with the LDAP attribute 'userCertificate;binary'. ++ ++ ++ Example: (userCertificate;binary={cert!bin}) ++ ++ ++ ++ ++ {subject_principal[.short_name]} ++ ++ ++ This template will add the Kerberos principal which is ++ taken either from the SAN used by pkinit or the one used ++ by AD. The 'short_name' component represent the first ++ part of the principal before the '@' sign. ++ ++ ++ Example: (|(userPrincipal={subject_principal})(samAccountName={subject_principal.short_name})) ++ ++ ++ ++ ++ {subject_pkinit_principal[.short_name]} ++ ++ ++ This template will add the Kerberos principal which is ++ given by then SAN used by pkinit. The 'short_name' ++ component represent the first part of the principal ++ before the '@' sign. ++ ++ ++ Example: (|(userPrincipal={subject_pkinit_principal})(uid={subject_pkinit_principal.short_name})) ++ ++ ++ ++ ++ {subject_nt_principal[.short_name]} ++ ++ ++ This template will add the Kerberos principal which is ++ given by then SAN used by AD. The 'short_name' component ++ represent the first part of the principal before the '@' ++ sign. ++ ++ ++ Example: (|(userPrincipal={subject_principal})(samAccountName={subject_principal.short_name})) ++ ++ ++ ++ ++ {subject_rfc822_name[.short_name]} ++ ++ ++ This template will add the string which is stored in the ++ rfc822Name component of the SAN, typically an email ++ address. The 'short_name' component represent the first ++ part of the address before the '@' sign. ++ ++ ++ Example: (|(mail={subject_rfc822_name})(uid={subject_rfc822_name.short_name})) ++ ++ ++ ++ ++ {subject_dns_name[.short_name]} ++ ++ ++ This template will add the string which is stored in the ++ dNSName component of the SAN, typically a fully-qualified host name. ++ The 'short_name' component represent the first ++ part of the name before the first '.' sign. ++ ++ ++ Example: (|(fqdn={subject_dns_name})(host={subject_dns_name.short_name})) ++ ++ ++ ++ ++ {subject_uri} ++ ++ ++ This template will add the string which is stored in the ++ uniformResourceIdentifier component of the SAN. ++ ++ ++ Example: (uri={subject_uri}) ++ ++ ++ ++ ++ {subject_ip_address} ++ ++ ++ This template will add the string which is stored in the ++ iPAddress component of the SAN. ++ ++ ++ Example: (ip={subject_ip_address}) ++ ++ ++ ++ ++ {subject_x400_address} ++ ++ ++ This template will add the value which is stored in the ++ x400Address component of the SAN as escaped hex ++ sequence. ++ ++ ++ Example: (attr:binary={subject_x400_address}) ++ ++ ++ ++ ++ {subject_directory_name[!((ad|ad_x500)|ad_ldap|nss_x500|(nss|nss_ldap))]} ++ ++ ++ This template will add the DN string of the value which ++ is stored in the directoryName component of the SAN. ++ ++ ++ Example: (orig_dn={subject_directory_name}) ++ ++ ++ ++ ++ {subject_ediparty_name} ++ ++ ++ This template will add the value which is stored in the ++ ediPartyName component of the SAN as escaped hex ++ sequence. ++ ++ ++ Example: (attr:binary={subject_ediparty_name}) ++ ++ ++ ++ ++ {subject_registered_id} ++ ++ ++ This template will add the OID which is stored in the ++ registeredID component of the SAN as as dotted-decimal ++ string. ++ ++ ++ Example: (oid={subject_registered_id}) ++ ++ ++ ++ ++ ++ ++ ++ DOMAIN LIST ++ ++ If the domain list is not empty users mapped to a given certificate ++ are not only searched in the local domain but in the listed domains ++ as well as long as they are know by SSSD. Domains not know to SSSD ++ will be ignored. ++ ++ ++ ++ ++ +diff --git a/src/tests/cmocka/test_certmap.c b/src/tests/cmocka/test_certmap.c +new file mode 100644 +index 0000000000000000000000000000000000000000..c998443d086eaa72cc2a05c38ddfc5ba590a1ce7 +--- /dev/null ++++ b/src/tests/cmocka/test_certmap.c +@@ -0,0 +1,1443 @@ ++/* ++ SSSD ++ ++ certmap - Tests for SSSD's certificate mapping library ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "lib/certmap/sss_certmap.h" ++#include "lib/certmap/sss_certmap_int.h" ++ ++#include "util/crypto/sss_crypto.h" ++ ++#include "tests/cmocka/common_mock.h" ++#include "tests/common.h" ++ ++#ifdef HAVE_NSS ++#include "util/crypto/nss/nss_util.h" ++#endif ++ ++struct priv_sss_debug { ++ int level; ++}; ++ ++void ext_debug(void *private, const char *file, long line, const char *function, ++ const char *format, ...) ++{ ++ va_list ap; ++ struct priv_sss_debug *data = private; ++ int level = SSSDBG_OP_FAILURE; ++ ++ if (data != NULL) { ++ level = data->level; ++ } ++ ++ if (DEBUG_IS_SET(level)) { ++ va_start(ap, format); ++ sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED, ++ format, ap); ++ va_end(ap); ++ } ++} ++ ++static void test_sss_certmap_init(void **state) ++{ ++ int ret; ++ struct sss_certmap_ctx *ctx; ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ ++ sss_certmap_free_ctx(ctx); ++} ++ ++static struct sss_certmap_ctx *setup_prio(const int *l) ++{ ++ int ret; ++ size_t c; ++ struct sss_certmap_ctx *ctx; ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ ++ for (c = 0; c < 10; c++) { ++ ret = sss_certmap_add_rule(ctx, l[c], NULL, NULL, NULL); ++ assert_int_equal(ret, EOK); ++ } ++ ++ return ctx; ++} ++ ++static void test_sss_certmap_add_rule(void **state) ++{ ++ struct sss_certmap_ctx *ctx; ++ int i; ++ struct priority_list *p; ++ struct priority_list *last; ++ size_t c; ++ ++ const int tests_a[][10] = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, ++ {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, ++ {1, 3, 5 ,7, 9, 0, 2, 4, 6, 8}, ++ {0, 2, 4, 6, 8, 1, 3, 5, 7, 9}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; ++ ++ const int tests_b[][10] = {{0, 0, 0, 0, 1, 1, 1, 2, 2, 2}, ++ {2, 2, 2, 1, 1, 1, 0, 0, 0, 0}, ++ {0, 1, 2, 0, 1, 2, 0, 1, 2, 0}, ++ {0, 2, 1, 0, 2, 1, 0, 2, 1, 0}, ++ {0, 1, 2, 0, 2, 1, 0, 0, 1, 2}, ++ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; ++ ++ for (c = 0; tests_a[c][0] != 0 || tests_a[c][9] != 0; c++) { ++ ctx = setup_prio(tests_a[0]); ++ assert_non_null(ctx); ++ i = 0; ++ for (p = ctx->prio_list; p != NULL; p = p->next) { ++ assert_int_equal(i, p->priority); ++ assert_non_null(p->rule_list); ++ assert_int_equal(i, p->rule_list->priority); ++ assert_null(p->rule_list->prev); ++ assert_null(p->rule_list->next); ++ i++; ++ } ++ ++ i = 9; ++ for (last = ctx->prio_list; last->next != NULL; last = last->next); ++ for (p = last; p != NULL; p = p->prev) { ++ assert_int_equal(i, p->priority); ++ assert_int_equal(i, p->rule_list->priority); ++ i--; ++ } ++ ++ sss_certmap_free_ctx(ctx); ++ } ++ for (c = 0; tests_b[c][0] != 0 || tests_b[c][9] != 0; c++) { ++ ctx = setup_prio(tests_b[0]); ++ assert_non_null(ctx); ++ i = 0; ++ for (p = ctx->prio_list; p != NULL; p = p->next) { ++ assert_int_equal(i, p->priority); ++ assert_non_null(p->rule_list); ++ assert_int_equal(i, p->rule_list->priority); ++ assert_null(p->rule_list->prev); ++ assert_non_null(p->rule_list->next); ++ assert_ptr_equal(p->rule_list, p->rule_list->next->prev); ++ assert_non_null(p->rule_list->next->next); ++ assert_ptr_equal(p->rule_list->next, ++ p->rule_list->next->next->prev); ++ if (i == 0) { ++ assert_non_null(p->rule_list->next->next->next); ++ assert_ptr_equal(p->rule_list->next->next, ++ p->rule_list->next->next->next->prev); ++ assert_null(p->rule_list->next->next->next->next); ++ } else { ++ assert_null(p->rule_list->next->next->next); ++ } ++ i++; ++ } ++ sss_certmap_free_ctx(ctx); ++ } ++} ++ ++static void test_sss_certmap_add_matching_rule(void **state) ++{ ++ struct sss_certmap_ctx *ctx; ++ int ret; ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "fsdf", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "FDSF:fsdf", NULL, NULL); ++ assert_int_equal(ret, ESRCH); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "KRB5:", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "ddqwdq", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "digitalSignature,dddq", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ++ ret = sss_certmap_add_rule(ctx, 1, "", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "dwqwqw", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, ".", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, ".1.2.3", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "1.2.3.", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "1.a.3", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "prio_list); ++ ++ /* invalid base64 input */ ++ ret = sss_certmap_add_rule(ctx, 1, "...", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ /* invalid OID input */ ++ ret = sss_certmap_add_rule(ctx, 1, "dqq", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "dqq", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "dqq", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "dqq", NULL, NULL); ++ assert_int_equal(ret, EINVAL); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "a", NULL, NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, ++ relation_and); ++ assert_null(ctx->prio_list->rule_list->parsed_match_rule->subject); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); ++ assert_string_equal("a", ++ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); ++ talloc_free(ctx); ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ret = sss_certmap_add_rule(ctx, 1, "&&a", NULL, NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, ++ relation_and); ++ assert_null(ctx->prio_list->rule_list->parsed_match_rule->subject); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); ++ assert_string_equal("a", ++ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); ++ talloc_free(ctx); ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ret = sss_certmap_add_rule(ctx, 1, "KRB5:||a", NULL, NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, ++ relation_or); ++ assert_null(ctx->prio_list->rule_list->parsed_match_rule->subject); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); ++ assert_string_equal("a", ++ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); ++ talloc_free(ctx); ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ret = sss_certmap_add_rule(ctx, 1, "KRB5:ab", NULL, NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, ++ relation_and); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject); ++ assert_string_equal("b", ++ ctx->prio_list->rule_list->parsed_match_rule->subject->val); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); ++ assert_string_equal("a", ++ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); ++ talloc_free(ctx); ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ret = sss_certmap_add_rule(ctx, 1000, ++ "KRB5:abcd", ++ NULL, NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, ++ relation_and); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject); ++ assert_string_equal("d", ++ ctx->prio_list->rule_list->parsed_match_rule->subject->val); ++ assert_string_equal("b", ++ ctx->prio_list->rule_list->parsed_match_rule->subject->next->val); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); ++ assert_string_equal("c", ++ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); ++ assert_string_equal("a", ++ ctx->prio_list->rule_list->parsed_match_rule->issuer->next->val); ++ ++ ret = sss_certmap_add_rule(ctx, 99, ++ "KRB5:ab" ++ "dataEncipherment,cRLSignc" ++ "d", ++ NULL, NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, ++ relation_and); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject); ++ assert_string_equal("d", ++ ctx->prio_list->rule_list->parsed_match_rule->subject->val); ++ assert_string_equal("b", ++ ctx->prio_list->rule_list->parsed_match_rule->subject->next->val); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); ++ assert_string_equal("c", ++ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); ++ assert_string_equal("a", ++ ctx->prio_list->rule_list->parsed_match_rule->issuer->next->val); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->ku); ++ assert_int_equal(SSS_KU_CRL_SIGN|SSS_KU_DATA_ENCIPHERMENT, ++ ctx->prio_list->rule_list->parsed_match_rule->ku->ku); ++ ++ ret = sss_certmap_add_rule(ctx, 98, ++ "KRB5:ab" ++ "dataEncipherment,cRLSignc" ++ "clientAuth,emailProtection" ++ "d", ++ NULL, NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, ++ relation_and); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject); ++ assert_string_equal("d", ++ ctx->prio_list->rule_list->parsed_match_rule->subject->val); ++ assert_string_equal("b", ++ ctx->prio_list->rule_list->parsed_match_rule->subject->next->val); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer); ++ assert_string_equal("c", ++ ctx->prio_list->rule_list->parsed_match_rule->issuer->val); ++ assert_string_equal("a", ++ ctx->prio_list->rule_list->parsed_match_rule->issuer->next->val); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->ku); ++ assert_int_equal(SSS_KU_CRL_SIGN|SSS_KU_DATA_ENCIPHERMENT, ++ ctx->prio_list->rule_list->parsed_match_rule->ku->ku); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->eku); ++ assert_true(string_in_list("1.3.6.1.5.5.7.3.2", ++ discard_const( ++ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list), ++ true)); ++ assert_true(string_in_list("1.3.6.1.5.5.7.3.4", ++ discard_const( ++ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list), ++ true)); ++ assert_null( ++ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list[2]); ++ ++ ret = sss_certmap_add_rule(ctx, 97, ++ "KRB5:clientAuth,1.2.3,emailProtection", ++ NULL, NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, ++ relation_and); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->eku); ++ assert_true(string_in_list("1.3.6.1.5.5.7.3.2", ++ discard_const( ++ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list), ++ true)); ++ assert_true(string_in_list("1.3.6.1.5.5.7.3.4", ++ discard_const( ++ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list), ++ true)); ++ assert_true(string_in_list("1.2.3", ++ discard_const( ++ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list), ++ true)); ++ assert_null( ++ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list[3]); ++ ++ /* SAN tests */ ++ ret = sss_certmap_add_rule(ctx, 89, "KRB5:abc", NULL, NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, ++ relation_and); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->san); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->san->san_opt, ++ SAN_PRINCIPAL); ++ assert_string_equal(ctx->prio_list->rule_list->parsed_match_rule->san->val, ++ "abc"); ++ ++ ret = sss_certmap_add_rule(ctx, 88, "KRB5:def", NULL, NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, ++ relation_and); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->san); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->san->san_opt, ++ SAN_DNS_NAME); ++ assert_string_equal(ctx->prio_list->rule_list->parsed_match_rule->san->val, ++ "def"); ++ ++ ret = sss_certmap_add_rule(ctx, 87, "KRB5:aGlq", ++ NULL, NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, ++ relation_and); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->san); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->san->san_opt, ++ SAN_X400_ADDRESS); ++ assert_int_equal( ++ ctx->prio_list->rule_list->parsed_match_rule->san->bin_val_len, ++ 3); ++ assert_memory_equal( ++ ctx->prio_list->rule_list->parsed_match_rule->san->bin_val, ++ "hij", 3); ++ ++ ret = sss_certmap_add_rule(ctx, 86, "KRB5:klm", ++ NULL, NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r, ++ relation_and); ++ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->san); ++ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->san->san_opt, ++ SAN_STRING_OTHER_NAME); ++ assert_string_equal(ctx->prio_list->rule_list->parsed_match_rule->san->val, ++ "klm"); ++ assert_string_equal("1.2.3.4", ++ ctx->prio_list->rule_list->parsed_match_rule->san->str_other_name_oid); ++ ++ talloc_free(ctx); ++} ++ ++static void test_check_ad_attr_name(void **state) ++{ ++ char *res; ++ ++ res = check_ad_attr_name(NULL, NULL); ++ assert_null(res); ++ ++ res = check_ad_attr_name(NULL, ""); ++ assert_null(res); ++ ++ res = check_ad_attr_name(NULL, "dsddqwdas"); ++ assert_null(res); ++ ++ res = check_ad_attr_name(NULL, "dsddq=wdas"); ++ assert_null(res); ++ ++ res = check_ad_attr_name(NULL, "CN=abc"); ++ assert_null(res); ++ ++ res = check_ad_attr_name(NULL, "O=xyz"); ++ assert_null(res); ++ ++ res = check_ad_attr_name(NULL, "ST=def"); ++ assert_non_null(res); ++ assert_string_equal(res, "S=def"); ++ talloc_free(res); ++} ++ ++const uint8_t test_cert_der[] = { ++0x30, 0x82, 0x04, 0x09, 0x30, 0x82, 0x02, 0xf1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x09, ++0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, ++0x34, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x49, 0x50, 0x41, 0x2e, ++0x44, 0x45, 0x56, 0x45, 0x4c, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x15, ++0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, ++0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x34, 0x32, 0x38, 0x31, ++0x30, 0x32, 0x31, 0x31, 0x31, 0x5a, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x34, 0x32, 0x38, 0x31, 0x30, ++0x32, 0x31, 0x31, 0x31, 0x5a, 0x30, 0x32, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, ++0x0c, 0x09, 0x49, 0x50, 0x41, 0x2e, 0x44, 0x45, 0x56, 0x45, 0x4c, 0x31, 0x1c, 0x30, 0x1a, 0x06, ++0x03, 0x55, 0x04, 0x03, 0x0c, 0x13, 0x69, 0x70, 0x61, 0x2d, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x2e, ++0x69, 0x70, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, ++0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, ++0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb2, 0x32, 0x92, 0xab, 0x47, 0xb8, ++0x0c, 0x13, 0x54, 0x4a, 0x1f, 0x1e, 0x29, 0x06, 0xff, 0xd0, 0x50, 0xcb, 0xf7, 0x5f, 0x79, 0x91, ++0x65, 0xb1, 0x39, 0x01, 0x83, 0x6a, 0xad, 0x9e, 0x77, 0x3b, 0xf3, 0x0d, 0xd7, 0xb9, 0xf6, 0xdc, ++0x9e, 0x4a, 0x49, 0xa7, 0xd0, 0x66, 0x72, 0xcc, 0xbf, 0x77, 0xd6, 0xde, 0xa9, 0xfe, 0x67, 0x96, ++0xcc, 0x49, 0xf1, 0x37, 0x23, 0x2e, 0xc4, 0x50, 0xf4, 0xeb, 0xba, 0x62, 0xd4, 0x23, 0x4d, 0xf3, ++0x37, 0x38, 0x82, 0xee, 0x3b, 0x3f, 0x2c, 0xd0, 0x80, 0x9b, 0x17, 0xaa, 0x9b, 0xeb, 0xa6, 0xdd, ++0xf6, 0x15, 0xff, 0x06, 0xb2, 0xce, 0xff, 0xdf, 0x8a, 0x9e, 0x95, 0x85, 0x49, 0x1f, 0x84, 0xfd, ++0x81, 0x26, 0xce, 0x06, 0x32, 0x0d, 0x36, 0xca, 0x7c, 0x15, 0x81, 0x68, 0x6b, 0x8f, 0x3e, 0xb3, ++0xa2, 0xfc, 0xae, 0xaf, 0xc2, 0x44, 0x58, 0x15, 0x95, 0x40, 0xfc, 0x56, 0x19, 0x91, 0x80, 0xed, ++0x42, 0x11, 0x66, 0x04, 0xef, 0x3c, 0xe0, 0x76, 0x33, 0x4b, 0x83, 0xfa, 0x7e, 0xb4, 0x47, 0xdc, ++0xfb, 0xed, 0x46, 0xa5, 0x8d, 0x0a, 0x66, 0x87, 0xa5, 0xef, 0x7b, 0x74, 0x62, 0xac, 0xbe, 0x73, ++0x36, 0xc9, 0xb4, 0xfe, 0x20, 0xc4, 0x81, 0xf3, 0xfe, 0x78, 0x19, 0xa8, 0xd0, 0xaf, 0x7f, 0x81, ++0x72, 0x24, 0x61, 0xd9, 0x76, 0x93, 0xe3, 0x0b, 0xd2, 0x4f, 0x19, 0x17, 0x33, 0x57, 0xd4, 0x82, ++0xb0, 0xf1, 0xa8, 0x03, 0xf6, 0x01, 0x99, 0xa9, 0xb8, 0x8c, 0x83, 0xc9, 0xba, 0x19, 0x87, 0xea, ++0xd6, 0x3b, 0x06, 0xeb, 0x4c, 0xf7, 0xf1, 0xe5, 0x28, 0xa9, 0x10, 0xb6, 0x46, 0xde, 0xe1, 0xe1, ++0x3f, 0xc1, 0xcc, 0x72, 0xbe, 0x2a, 0x43, 0xc6, 0xf6, 0xd0, 0xb5, 0xa0, 0xc4, 0x24, 0x6e, 0x4f, ++0xbd, 0xec, 0x22, 0x8a, 0x07, 0x11, 0x3d, 0xf9, 0xd3, 0x15, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, ++0x82, 0x01, 0x26, 0x30, 0x82, 0x01, 0x22, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, ++0x30, 0x16, 0x80, 0x14, 0xf2, 0x9d, 0x42, 0x4e, 0x0f, 0xc4, 0x48, 0x25, 0x58, 0x2f, 0x1c, 0xce, ++0x0f, 0xa1, 0x3f, 0x22, 0xc8, 0x55, 0xc8, 0x91, 0x30, 0x3b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, ++0x05, 0x07, 0x01, 0x01, 0x04, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, ++0x05, 0x07, 0x30, 0x01, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x69, 0x70, 0x61, ++0x2d, 0x63, 0x61, 0x2e, 0x69, 0x70, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x2f, 0x63, 0x61, ++0x2f, 0x6f, 0x63, 0x73, 0x70, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, ++0x04, 0x03, 0x02, 0x04, 0xf0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, ++0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, ++0x05, 0x07, 0x03, 0x02, 0x30, 0x74, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x6d, 0x30, 0x6b, 0x30, ++0x69, 0xa0, 0x31, 0xa0, 0x2f, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x69, 0x70, ++0x61, 0x2d, 0x63, 0x61, 0x2e, 0x69, 0x70, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x2f, 0x69, ++0x70, 0x61, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x43, 0x52, 0x4c, ++0x2e, 0x62, 0x69, 0x6e, 0xa2, 0x34, 0xa4, 0x32, 0x30, 0x30, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, ++0x55, 0x04, 0x0a, 0x0c, 0x05, 0x69, 0x70, 0x61, 0x63, 0x61, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, ++0x55, 0x04, 0x03, 0x0c, 0x15, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, ++0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, ++0x0e, 0x04, 0x16, 0x04, 0x14, 0x2d, 0x2b, 0x3f, 0xcb, 0xf5, 0xb2, 0xff, 0x32, 0x2c, 0xa8, 0xc2, ++0x1c, 0xdd, 0xbd, 0x8c, 0x80, 0x1e, 0xdd, 0x31, 0x82, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, ++0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x9a, 0x47, 0x2e, ++0x50, 0xa7, 0x4d, 0x1d, 0x53, 0x0f, 0xc9, 0x71, 0x42, 0x0c, 0xe5, 0xda, 0x7d, 0x49, 0x64, 0xe7, ++0xab, 0xc8, 0xdf, 0xdf, 0x02, 0xc1, 0x87, 0xd1, 0x5b, 0xde, 0xda, 0x6f, 0x2b, 0xe4, 0xf0, 0xbe, ++0xba, 0x09, 0xdf, 0x02, 0x85, 0x0b, 0x8a, 0xe6, 0x9b, 0x06, 0x7d, 0x69, 0x38, 0x6c, 0x72, 0xff, ++0x4c, 0x7b, 0x2a, 0x0d, 0x3f, 0x23, 0x2f, 0x16, 0x46, 0xff, 0x05, 0x93, 0xb0, 0xea, 0x24, 0x28, ++0xd7, 0x12, 0xa1, 0x57, 0xb8, 0x59, 0x19, 0x25, 0xf3, 0x43, 0x0a, 0xd3, 0xfd, 0x0f, 0x37, 0x8d, ++0xb8, 0xca, 0x15, 0xe7, 0x48, 0x8a, 0xa0, 0xc7, 0xc7, 0x4b, 0x7f, 0x01, 0x3c, 0x58, 0xd7, 0x37, ++0xe5, 0xff, 0x7d, 0x2b, 0x01, 0xac, 0x0d, 0x9f, 0x51, 0x6a, 0xe5, 0x40, 0x24, 0xe6, 0x5e, 0x55, ++0x0d, 0xf7, 0xb8, 0x2f, 0x42, 0xac, 0x6d, 0xe5, 0x29, 0x6b, 0xc6, 0x0b, 0xa4, 0xbf, 0x19, 0xbd, ++0x39, 0x27, 0xee, 0xfe, 0xc5, 0xb3, 0xdb, 0x62, 0xd4, 0xbe, 0xd2, 0x47, 0xba, 0x96, 0x30, 0x5a, ++0xfd, 0x62, 0x00, 0xb8, 0x27, 0x5d, 0x2f, 0x3a, 0x94, 0x0b, 0x95, 0x35, 0x85, 0x40, 0x2c, 0xbc, ++0x67, 0xdf, 0x8a, 0xf9, 0xf1, 0x7b, 0x19, 0x96, 0x3e, 0x42, 0x48, 0x13, 0x23, 0x04, 0x95, 0xa9, ++0x6b, 0x11, 0x33, 0x81, 0x47, 0x5a, 0x83, 0x72, 0xf6, 0x20, 0xfa, 0x8e, 0x41, 0x7b, 0x8f, 0x77, ++0x47, 0x7c, 0xc7, 0x5d, 0x46, 0xf4, 0x4f, 0xfd, 0x81, 0x0a, 0xae, 0x39, 0x27, 0xb6, 0x6a, 0x26, ++0x63, 0xb1, 0xd3, 0xbf, 0x55, 0x83, 0x82, 0x9b, 0x36, 0x6c, 0x33, 0x64, 0x0f, 0x50, 0xc0, 0x55, ++0x94, 0x13, 0xc3, 0x85, 0xf4, 0xd5, 0x71, 0x65, 0xd0, 0xc0, 0xdd, 0xfc, 0xe6, 0xec, 0x9c, 0x5b, ++0xf0, 0x11, 0xb5, 0x2c, 0xf3, 0x48, 0xc1, 0x36, 0x8c, 0xa2, 0x96, 0x48, 0x84}; ++ ++const uint8_t test_cert2_der[] = { ++0x30, 0x82, 0x06, 0x98, 0x30, 0x82, 0x05, 0x80, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x61, ++0x22, 0x88, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x02, 0xa6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, ++0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x15, 0x30, 0x13, 0x06, 0x0a, ++0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x05, 0x64, 0x65, 0x76, 0x65, ++0x6c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, ++0x19, 0x16, 0x02, 0x61, 0x64, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f, ++0x61, 0x64, 0x2d, 0x41, 0x44, 0x2d, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x2d, 0x43, 0x41, 0x30, ++0x1e, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x31, 0x31, 0x31, 0x31, 0x33, 0x35, 0x31, 0x31, 0x31, 0x5a, ++0x17, 0x0d, 0x31, 0x37, 0x31, 0x31, 0x31, 0x31, 0x31, 0x33, 0x35, 0x31, 0x31, 0x31, 0x5a, 0x30, ++0x70, 0x31, 0x15, 0x30, 0x13, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, ++0x19, 0x16, 0x05, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x0a, 0x09, 0x92, ++0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x02, 0x61, 0x64, 0x31, 0x0e, 0x30, 0x0c, ++0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x31, 0x0c, 0x30, 0x0a, ++0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x03, 0x74, 0x20, 0x75, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, ++0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x16, 0x74, 0x65, 0x73, 0x74, 0x2e, ++0x75, 0x73, 0x65, 0x72, 0x40, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, ++0x6e, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, ++0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, ++0x01, 0x00, 0x9c, 0xcf, 0x36, 0x99, 0xde, 0x63, 0x74, 0x2b, 0x77, 0x25, 0x9e, 0x24, 0xd9, 0x77, ++0x4b, 0x5f, 0x98, 0xc0, 0x8c, 0xd7, 0x20, 0x91, 0xc0, 0x1c, 0xe8, 0x37, 0x45, 0xbf, 0x3c, 0xd9, ++0x33, 0xbd, 0xe9, 0xde, 0xc9, 0x5d, 0xd4, 0xcd, 0x06, 0x0a, 0x0d, 0xd4, 0xf1, 0x7c, 0x74, 0x5b, ++0x29, 0xd5, 0x66, 0x9c, 0x2c, 0x9f, 0x6b, 0x1a, 0x0f, 0x0d, 0xe6, 0x6c, 0x62, 0xa5, 0x41, 0x4f, ++0xc3, 0xa4, 0x88, 0x27, 0x11, 0x5d, 0xb7, 0xb1, 0xfb, 0xf8, 0x8d, 0xee, 0x43, 0x8d, 0x93, 0xb5, ++0x8c, 0xb4, 0x34, 0x06, 0xf5, 0xe9, 0x2f, 0x5a, 0x26, 0x68, 0xd7, 0x43, 0x60, 0x82, 0x5e, 0x22, ++0xa7, 0xc6, 0x34, 0x40, 0x19, 0xa5, 0x8e, 0xf0, 0x58, 0x9f, 0x16, 0x2d, 0x43, 0x3f, 0x0c, 0xda, ++0xe2, 0x23, 0xf6, 0x09, 0x2a, 0x5e, 0xbd, 0x84, 0x27, 0xc8, 0xab, 0xd5, 0x70, 0xf8, 0x3d, 0x9c, ++0x14, 0xc2, 0xc2, 0xa2, 0x77, 0xe8, 0x44, 0x73, 0x10, 0x01, 0x34, 0x40, 0x1f, 0xc6, 0x2f, 0xa0, ++0x70, 0xee, 0x2f, 0xd5, 0x4b, 0xbe, 0x4c, 0xc7, 0x45, 0xf7, 0xac, 0x9c, 0xc3, 0x68, 0x5b, 0x1d, ++0x5a, 0x4b, 0x77, 0x65, 0x76, 0xe4, 0xb3, 0x92, 0xf4, 0x84, 0x0a, 0x9e, 0x6a, 0x9c, 0xc9, 0x53, ++0x42, 0x9f, 0x6d, 0xfe, 0xf9, 0xf5, 0xf2, 0x9a, 0x15, 0x50, 0x47, 0xef, 0xf4, 0x06, 0x59, 0xc8, ++0x50, 0x48, 0x4b, 0x46, 0x95, 0x68, 0x25, 0xc5, 0xbd, 0x4f, 0x65, 0x34, 0x00, 0xfc, 0x31, 0x69, ++0xf8, 0x3e, 0xe0, 0x20, 0x83, 0x41, 0x27, 0x0b, 0x5c, 0x46, 0x98, 0x14, 0xf0, 0x07, 0xde, 0x02, ++0x17, 0xb1, 0xd2, 0x9c, 0xbe, 0x1c, 0x0d, 0x56, 0x22, 0x1b, 0x02, 0xfe, 0xda, 0x69, 0xb9, 0xef, ++0x91, 0x37, 0x39, 0x7f, 0x24, 0xda, 0xc4, 0x81, 0x5e, 0x82, 0x31, 0x2f, 0x98, 0x1d, 0xf7, 0x73, ++0x5b, 0x23, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x03, 0x5d, 0x30, 0x82, 0x03, 0x59, 0x30, ++0x3d, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x07, 0x04, 0x30, 0x30, 0x2e, ++0x06, 0x26, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x08, 0x87, 0x85, 0xa1, 0x23, 0x84, ++0xc8, 0xb2, 0x26, 0x83, 0x9d, 0x9d, 0x21, 0x82, 0xd4, 0xa6, 0x1b, 0x86, 0xa3, 0xba, 0x37, 0x81, ++0x10, 0x85, 0x89, 0xd5, 0x02, 0xd6, 0x8f, 0x24, 0x02, 0x01, 0x64, 0x02, 0x01, 0x02, 0x30, 0x29, ++0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x22, 0x30, 0x20, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, ++0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x04, 0x06, 0x0a, 0x2b, ++0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0a, 0x03, 0x04, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, ++0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x35, 0x06, 0x09, 0x2b, 0x06, 0x01, ++0x04, 0x01, 0x82, 0x37, 0x15, 0x0a, 0x04, 0x28, 0x30, 0x26, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, ++0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, ++0x03, 0x04, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0a, 0x03, 0x04, ++0x30, 0x81, 0x94, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x0f, 0x04, 0x81, ++0x86, 0x30, 0x81, 0x83, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, ++0x2a, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2d, 0x30, 0x0b, ++0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x16, 0x30, 0x0b, 0x06, 0x09, 0x60, ++0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x19, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, ++0x65, 0x03, 0x04, 0x01, 0x02, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, ++0x01, 0x05, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x07, 0x30, 0x07, ++0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x07, 0x30, 0x0e, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, ++0x0d, 0x03, 0x02, 0x02, 0x02, 0x00, 0x80, 0x30, 0x0e, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, ++0x0d, 0x03, 0x04, 0x02, 0x02, 0x02, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, ++0x04, 0x14, 0x49, 0xac, 0xad, 0xe0, 0x65, 0x30, 0xc4, 0xce, 0xa0, 0x09, 0x03, 0x5b, 0xad, 0x4a, ++0x7b, 0x49, 0x5e, 0xc9, 0x6c, 0xb4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, ++0x16, 0x80, 0x14, 0x62, 0x50, 0xb6, 0x8d, 0xa1, 0xe6, 0x2d, 0x91, 0xbf, 0xb0, 0x54, 0x4d, 0x8f, ++0xa8, 0xca, 0x10, 0xae, 0xb8, 0xdd, 0x54, 0x30, 0x81, 0xcc, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, ++0x81, 0xc4, 0x30, 0x81, 0xc1, 0x30, 0x81, 0xbe, 0xa0, 0x81, 0xbb, 0xa0, 0x81, 0xb8, 0x86, 0x81, ++0xb5, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x2f, 0x43, 0x4e, 0x3d, 0x61, 0x64, 0x2d, 0x41, ++0x44, 0x2d, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x2d, 0x43, 0x41, 0x2c, 0x43, 0x4e, 0x3d, 0x61, ++0x64, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2c, 0x43, 0x4e, 0x3d, 0x43, 0x44, 0x50, 0x2c, ++0x43, 0x4e, 0x3d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x25, 0x32, 0x30, 0x4b, 0x65, 0x79, 0x25, ++0x32, 0x30, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x53, 0x65, ++0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, ++0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x44, 0x43, 0x3d, 0x61, 0x64, 0x2c, 0x44, 0x43, ++0x3d, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x3f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, ++0x74, 0x65, 0x52, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, ++0x3f, 0x62, 0x61, 0x73, 0x65, 0x3f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6c, 0x61, 0x73, ++0x73, 0x3d, 0x63, 0x52, 0x4c, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, ++0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x30, 0x81, 0xbe, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, ++0x07, 0x01, 0x01, 0x04, 0x81, 0xb1, 0x30, 0x81, 0xae, 0x30, 0x81, 0xab, 0x06, 0x08, 0x2b, 0x06, ++0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x81, 0x9e, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, ++0x2f, 0x43, 0x4e, 0x3d, 0x61, 0x64, 0x2d, 0x41, 0x44, 0x2d, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, ++0x2d, 0x43, 0x41, 0x2c, 0x43, 0x4e, 0x3d, 0x41, 0x49, 0x41, 0x2c, 0x43, 0x4e, 0x3d, 0x50, 0x75, ++0x62, 0x6c, 0x69, 0x63, 0x25, 0x32, 0x30, 0x4b, 0x65, 0x79, 0x25, 0x32, 0x30, 0x53, 0x65, 0x72, ++0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, ++0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, ++0x6f, 0x6e, 0x2c, 0x44, 0x43, 0x3d, 0x61, 0x64, 0x2c, 0x44, 0x43, 0x3d, 0x64, 0x65, 0x76, 0x65, ++0x6c, 0x3f, 0x63, 0x41, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x3f, ++0x62, 0x61, 0x73, 0x65, 0x3f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6c, 0x61, 0x73, 0x73, ++0x3d, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x75, ++0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x3f, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x38, ++0x30, 0x36, 0xa0, 0x1c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x03, ++0xa0, 0x0e, 0x0c, 0x0c, 0x74, 0x75, 0x31, 0x40, 0x61, 0x64, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, ++0x81, 0x16, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x40, 0x65, 0x6d, 0x61, 0x69, ++0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, ++0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x41, 0x45, 0x0a, 0x6d, ++0xbb, 0x7f, 0x5c, 0x07, 0x0c, 0xc9, 0xb0, 0x39, 0x55, 0x6d, 0x7c, 0xb5, 0x02, 0xcd, 0xe8, 0xb2, ++0xe5, 0x02, 0x94, 0x77, 0x60, 0xdb, 0xd1, 0xaf, 0x1d, 0xdb, 0x44, 0x5f, 0xce, 0x83, 0xdb, 0x80, ++0x2e, 0xe2, 0xb2, 0x08, 0x25, 0x82, 0x14, 0xcb, 0x48, 0x95, 0x20, 0x13, 0x6c, 0xa9, 0xaa, 0xf8, ++0x31, 0x56, 0xed, 0xc0, 0x3b, 0xd4, 0xae, 0x2e, 0xe3, 0x8f, 0x05, 0xfc, 0xab, 0x5f, 0x2a, 0x69, ++0x23, 0xbc, 0xb8, 0x8c, 0xec, 0x2d, 0xa9, 0x0b, 0x86, 0x95, 0x73, 0x73, 0xdb, 0x17, 0xce, 0xc6, ++0xae, 0xc5, 0xb4, 0xc1, 0x25, 0x87, 0x3b, 0x67, 0x43, 0x9e, 0x87, 0x5a, 0xe6, 0xb9, 0xa0, 0x28, ++0x12, 0x3d, 0xa8, 0x2e, 0xd7, 0x5e, 0xef, 0x65, 0x2d, 0xe6, 0xa5, 0x67, 0x84, 0xac, 0xfd, 0x31, ++0xc1, 0x78, 0xd8, 0x72, 0x51, 0xa2, 0x88, 0x55, 0x0f, 0x97, 0x47, 0x93, 0x07, 0xea, 0x8a, 0x53, ++0x27, 0x4e, 0x34, 0x54, 0x34, 0x1f, 0xa0, 0x6a, 0x03, 0x44, 0xfb, 0x23, 0x61, 0x8e, 0x87, 0x8e, ++0x3c, 0xd0, 0x8f, 0xae, 0xe4, 0xcf, 0xee, 0x65, 0xa8, 0xba, 0x96, 0x68, 0x08, 0x1c, 0x60, 0xe2, ++0x4e, 0x11, 0xa3, 0x74, 0xb8, 0xa5, 0x4e, 0xea, 0x6a, 0x82, 0x4c, 0xc2, 0x4d, 0x63, 0x8e, 0x9f, ++0x7c, 0x2f, 0xa8, 0xc0, 0x62, 0xf8, 0xf7, 0xd9, 0x25, 0xc4, 0x91, 0xab, 0x4d, 0x6a, 0x44, 0xaf, ++0x75, 0x93, 0x53, 0x03, 0xa4, 0x99, 0xc8, 0xcd, 0x91, 0x89, 0x60, 0x75, 0x30, 0x99, 0x76, 0x05, ++0x5a, 0xa0, 0x03, 0xa7, 0xa1, 0x2c, 0x03, 0x04, 0x8f, 0xd4, 0x5a, 0x31, 0x52, 0x28, 0x5a, 0xe6, ++0xa2, 0xd3, 0x43, 0x21, 0x5b, 0xdc, 0xa2, 0x1d, 0x55, 0xa9, 0x48, 0xc5, 0xc4, 0xaa, 0xf3, 0x8b, ++0xe6, 0x3e, 0x75, 0x96, 0xe4, 0x3e, 0x64, 0xaf, 0xe8, 0xa7, 0x6a, 0xb6}; ++ ++void test_sss_cert_get_content(void **state) ++{ ++ int ret; ++ struct sss_cert_content *content; ++ ++ ret = sss_cert_get_content(NULL, test_cert_der, sizeof(test_cert_der), ++ &content); ++ assert_int_equal(ret , 0); ++ assert_non_null(content); ++ assert_non_null(content->issuer_str); ++ assert_string_equal(content->issuer_str, "CN=Certificate Authority,O=IPA.DEVEL"); ++ assert_non_null(content->subject_str); ++ assert_string_equal(content->subject_str, "CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); ++ assert_int_equal(content->key_usage, SSS_KU_DIGITAL_SIGNATURE ++ |SSS_KU_NON_REPUDIATION ++ |SSS_KU_KEY_ENCIPHERMENT ++ |SSS_KU_DATA_ENCIPHERMENT); ++ assert_non_null(content->extended_key_usage_oids); ++ assert_non_null(content->extended_key_usage_oids[0]); ++ assert_true(string_in_list("1.3.6.1.5.5.7.3.1", ++ discard_const(content->extended_key_usage_oids), true)); ++ assert_true(string_in_list("1.3.6.1.5.5.7.3.2", ++ discard_const(content->extended_key_usage_oids), true)); ++ assert_null(content->extended_key_usage_oids[2]); ++ assert_int_equal(content->cert_der_size, sizeof(test_cert_der)); ++ assert_memory_equal(content->cert_der, test_cert_der, sizeof(test_cert_der)); ++ ++ assert_non_null(content->issuer_rdn_list); ++ assert_string_equal(content->issuer_rdn_list[0], "O=IPA.DEVEL"); ++ assert_string_equal(content->issuer_rdn_list[1], "CN=Certificate Authority"); ++ assert_null(content->issuer_rdn_list[2]); ++ ++ assert_non_null(content->subject_rdn_list); ++ assert_string_equal(content->subject_rdn_list[0], "O=IPA.DEVEL"); ++ assert_string_equal(content->subject_rdn_list[1], "CN=ipa-devel.ipa.devel"); ++ assert_null(content->subject_rdn_list[2]); ++ ++ ++ talloc_free(content); ++} ++ ++void test_sss_cert_get_content_2(void **state) ++{ ++ int ret; ++ struct sss_cert_content *content; ++ struct san_list *i; ++ ++ ret = sss_cert_get_content(NULL, test_cert2_der, sizeof(test_cert2_der), ++ &content); ++ assert_int_equal(ret, 0); ++ assert_non_null(content); ++ assert_non_null(content->issuer_str); ++ assert_string_equal(content->issuer_str, ++ "CN=ad-AD-SERVER-CA,DC=ad,DC=devel"); ++ assert_non_null(content->subject_str); ++#if 0 ++FIXME: ++ assert_string_equal(content->subject_str, ++ "E=test.user@email.domain,CN=t u,CN=Users,DC=ad,DC=devel,DC=ad,DC=devel"); ++ //"CN=t u/emailAddress=test.user@email.domain,DC=ad,DC=devel"); ++#endif ++ assert_int_equal(content->key_usage, SSS_KU_DIGITAL_SIGNATURE ++ |SSS_KU_KEY_ENCIPHERMENT); ++ assert_non_null(content->extended_key_usage_oids); ++ assert_non_null(content->extended_key_usage_oids[0]); ++ assert_true(string_in_list("1.3.6.1.5.5.7.3.2", ++ discard_const(content->extended_key_usage_oids), true)); ++ assert_true(string_in_list("1.3.6.1.5.5.7.3.4", ++ discard_const(content->extended_key_usage_oids), true)); ++ /* Can use Microsoft Encrypted File System OID */ ++ assert_true(string_in_list("1.3.6.1.4.1.311.10.3.4", ++ discard_const(content->extended_key_usage_oids), true)); ++ assert_null(content->extended_key_usage_oids[3]); ++ assert_int_equal(content->cert_der_size, sizeof(test_cert2_der)); ++ assert_memory_equal(content->cert_der, test_cert2_der, ++ sizeof(test_cert2_der)); ++ ++ assert_non_null(content->issuer_rdn_list); ++ assert_string_equal(content->issuer_rdn_list[0], "DC=devel"); ++ assert_string_equal(content->issuer_rdn_list[1], "DC=ad"); ++ assert_string_equal(content->issuer_rdn_list[2], "CN=ad-AD-SERVER-CA"); ++ assert_null(content->issuer_rdn_list[3]); ++ ++ assert_non_null(content->subject_rdn_list); ++ assert_string_equal(content->subject_rdn_list[0], "DC=devel"); ++ assert_string_equal(content->subject_rdn_list[1], "DC=ad"); ++ assert_string_equal(content->subject_rdn_list[2], "CN=Users"); ++ assert_string_equal(content->subject_rdn_list[3], "CN=t u"); ++ assert_string_equal(content->subject_rdn_list[4], ++ "E=test.user@email.domain"); ++ //"CN=t u/emailAddress=test.user@email.domain"); ++ assert_null(content->subject_rdn_list[5]); ++ ++ assert_non_null(content->san_list); ++ ++ DLIST_FOR_EACH(i, content->san_list) { ++ switch (i->san_opt) { ++ case SAN_RFC822_NAME: ++ assert_string_equal(i->val, "test.user@email.domain"); ++ assert_string_equal(i->short_name, "test.user"); ++ break; ++ case SAN_STRING_OTHER_NAME: ++ assert_string_equal(i->other_name_oid, "1.3.6.1.4.1.311.20.2.3"); ++ assert_int_equal(i->bin_val_len, 14); ++ assert_memory_equal(i->bin_val, "\f\ftu1@ad.devel", 14); ++ break; ++ case SAN_NT: ++ case SAN_PRINCIPAL: ++ assert_string_equal(i->val, "tu1@ad.devel"); ++ assert_string_equal(i->short_name, "tu1"); ++ break; ++ default: ++ assert_true(false); ++ } ++ } ++ ++ talloc_free(content); ++} ++ ++static void test_sss_certmap_match_cert(void **state) ++{ ++ struct sss_certmap_ctx *ctx; ++ int ret; ++ size_t c; ++ ++ struct match_tests { ++ const char *rule; ++ int result; ++ } match_tests[] = { ++ {"KRB5:digitalSignature", 0}, ++ {"KRB5:digitalSignature,nonRepudiation", 0}, ++ {"KRB5:digitalSignature,cRLSign", ENOENT}, ++ {"KRB5:clientAuth", 0}, ++ {"KRB5:clientAuth,OCSPSigning", ENOENT}, ++ {"KRB5:clientAuth,serverAuth", 0}, ++ {NULL, 0} ++ }; ++ ++ struct match_tests match_tests_2[] = { ++ {"KRB5:digitalSignature", 0}, ++ {"KRB5:keyEncipherment", 0}, ++ {"KRB5:digitalSignature,keyEncipherment", 0}, ++ {"KRB5:digitalSignature,keyEncipherment,cRLSign", ENOENT}, ++ {"KRB5:clientAuth", 0}, ++ {"KRB5:clientAuth,1.3.6.1.4.1.311.10.3.4", 0}, ++ {"KRB5:clientAuth,1.3.6.1.4.1.311.10.3.41", ENOENT}, ++ {"KRB5:tu1", 0}, ++ {"KRB5:tu1", 0}, ++ {"KRB5:tu1", 0}, ++ {"KRB5:tu1", ENOENT}, ++ {"KRB5:^tu1@ad.devel$", 0}, ++ {"KRB5:tu", ENOENT}, ++ {"KRB5:test.user", 0}, ++ {"KRB5:test.usertu1", 0}, ++ {"KRB5:||test.usertu1", 0}, ++ {"KRB5:&&tu1tu1", ENOENT}, ++ {"KRB5:||tu1tu1", 0}, ++ {"KRB5:MTIz", ENOENT}, /* 123 */ ++ {"KRB5:DAx0dTFAYWQuZGV2ZWw=", 0}, /* "\f\ftu1@ad.devel" */ ++ {"KRB5:DAx0dTFAYWQuZGV2ZWx4", ENOENT}, /* "\f\ftu1@ad.develx" */ ++ {"KRB5:dHUxQGFkLmRldmVs", 0}, /* "tu1@ad.devel" */ ++ {"KRB5:test", ENOENT}, ++ {"KRB5:tu1@ad", 0}, ++ /* Fails becasue the NT principal SAN starts with binary values */ ++ {"KRB5:^tu1@ad.devel$", ENOENT}, ++ {NULL, 0} ++ }; ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, "KRB5:xyzxyz", ++ NULL, NULL); ++ assert_int_equal(ret, EOK); ++ ++ ret = sss_certmap_match_cert(ctx, discard_const(test_cert_der), ++ sizeof(test_cert_der)); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = sss_certmap_add_rule(ctx, 1, ++ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", ++ NULL, NULL); ++ assert_int_equal(ret, EOK); ++ ++ ret = sss_certmap_match_cert(ctx, discard_const(test_cert_der), ++ sizeof(test_cert_der)); ++ assert_int_equal(ret, 0); ++ ++ sss_certmap_free_ctx(ctx); ++ ++ for (c = 0; match_tests[c].rule != NULL; c++) { ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, match_tests[c].rule, NULL, NULL); ++ assert_int_equal(ret, EOK); ++ ++ ret = sss_certmap_match_cert(ctx, discard_const(test_cert_der), ++ sizeof(test_cert_der)); ++ assert_int_equal(ret, match_tests[c].result); ++ ++ sss_certmap_free_ctx(ctx); ++ } ++ ++ for (c = 0; match_tests_2[c].rule != NULL; c++) { ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ++ print_error("Checking matching rule [%s]\n", match_tests_2[c].rule); ++ ++ ret = sss_certmap_add_rule(ctx, 1, match_tests_2[c].rule, NULL, NULL); ++ assert_int_equal(ret, EOK); ++ ++ ret = sss_certmap_match_cert(ctx, discard_const(test_cert2_der), ++ sizeof(test_cert2_der)); ++ assert_int_equal(ret, match_tests_2[c].result); ++ ++ sss_certmap_free_ctx(ctx); ++ } ++} ++ ++static void test_sss_certmap_add_mapping_rule(void **state) ++{ ++ struct sss_certmap_ctx *ctx; ++ int ret; ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 1, NULL, "FWEAWEF:fwefwe", NULL); ++ assert_int_equal(ret, ESRCH); ++ ++ ret = sss_certmap_add_rule(ctx, 1, NULL, "LDAP:abc", NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule); ++ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list); ++ assert_int_equal(comp_string, ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->type); ++ assert_string_equal("abc", ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->val); ++ talloc_free(ctx); ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ret = sss_certmap_add_rule(ctx, 1, NULL, "LDAP:abc{issuer_dn}", NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule); ++ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list); ++ assert_int_equal(comp_string, ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->type); ++ assert_string_equal("abc", ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->val); ++ assert_int_equal(comp_template, ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->type); ++ assert_string_equal("issuer_dn", ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->val); ++ talloc_free(ctx); ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ret = sss_certmap_add_rule(ctx, 1, NULL, "{issuer_dn}a:b{{c}}", NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule); ++ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list); ++ assert_int_equal(comp_template, ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->type); ++ assert_string_equal("issuer_dn", ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->val); ++ assert_int_equal(comp_string, ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->type); ++ assert_string_equal("a:b{c}", ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->val); ++ talloc_free(ctx); ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ret = sss_certmap_add_rule(ctx, 1, NULL, "LDAP:{issuer_dn}{subject_dn}", ++ NULL); ++ assert_int_equal(ret, 0); ++ assert_non_null(ctx->prio_list); ++ assert_non_null(ctx->prio_list->rule_list); ++ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule); ++ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list); ++ assert_int_equal(comp_template, ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->type); ++ assert_string_equal("issuer_dn", ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->val); ++ assert_int_equal(comp_template, ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->type); ++ assert_string_equal("subject_dn", ++ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->val); ++ talloc_free(ctx); ++} ++ ++#define TEST_CERT_BIN \ ++ "\\30\\82\\04\\09\\30\\82\\02\\f1\\a0\\03\\02\\01\\02\\02\\01\\09" \ ++ "\\30\\0d\\06\\09\\2a\\86\\48\\86\\f7\\0d\\01\\01\\0b\\05\\00\\30" \ ++ "\\34\\31\\12\\30\\10\\06\\03\\55\\04\\0a\\0c\\09\\49\\50\\41\\2e" \ ++ "\\44\\45\\56\\45\\4c\\31\\1e\\30\\1c\\06\\03\\55\\04\\03\\0c\\15" \ ++ "\\43\\65\\72\\74\\69\\66\\69\\63\\61\\74\\65\\20\\41\\75\\74\\68" \ ++ "\\6f\\72\\69\\74\\79\\30\\1e\\17\\0d\\31\\35\\30\\34\\32\\38\\31" \ ++ "\\30\\32\\31\\31\\31\\5a\\17\\0d\\31\\37\\30\\34\\32\\38\\31\\30" \ ++ "\\32\\31\\31\\31\\5a\\30\\32\\31\\12\\30\\10\\06\\03\\55\\04\\0a" \ ++ "\\0c\\09\\49\\50\\41\\2e\\44\\45\\56\\45\\4c\\31\\1c\\30\\1a\\06" \ ++ "\\03\\55\\04\\03\\0c\\13\\69\\70\\61\\2d\\64\\65\\76\\65\\6c\\2e" \ ++ "\\69\\70\\61\\2e\\64\\65\\76\\65\\6c\\30\\82\\01\\22\\30\\0d\\06" \ ++ "\\09\\2a\\86\\48\\86\\f7\\0d\\01\\01\\01\\05\\00\\03\\82\\01\\0f" \ ++ "\\00\\30\\82\\01\\0a\\02\\82\\01\\01\\00\\b2\\32\\92\\ab\\47\\b8" \ ++ "\\0c\\13\\54\\4a\\1f\\1e\\29\\06\\ff\\d0\\50\\cb\\f7\\5f\\79\\91" \ ++ "\\65\\b1\\39\\01\\83\\6a\\ad\\9e\\77\\3b\\f3\\0d\\d7\\b9\\f6\\dc" \ ++ "\\9e\\4a\\49\\a7\\d0\\66\\72\\cc\\bf\\77\\d6\\de\\a9\\fe\\67\\96" \ ++ "\\cc\\49\\f1\\37\\23\\2e\\c4\\50\\f4\\eb\\ba\\62\\d4\\23\\4d\\f3" \ ++ "\\37\\38\\82\\ee\\3b\\3f\\2c\\d0\\80\\9b\\17\\aa\\9b\\eb\\a6\\dd" \ ++ "\\f6\\15\\ff\\06\\b2\\ce\\ff\\df\\8a\\9e\\95\\85\\49\\1f\\84\\fd" \ ++ "\\81\\26\\ce\\06\\32\\0d\\36\\ca\\7c\\15\\81\\68\\6b\\8f\\3e\\b3" \ ++ "\\a2\\fc\\ae\\af\\c2\\44\\58\\15\\95\\40\\fc\\56\\19\\91\\80\\ed" \ ++ "\\42\\11\\66\\04\\ef\\3c\\e0\\76\\33\\4b\\83\\fa\\7e\\b4\\47\\dc" \ ++ "\\fb\\ed\\46\\a5\\8d\\0a\\66\\87\\a5\\ef\\7b\\74\\62\\ac\\be\\73" \ ++ "\\36\\c9\\b4\\fe\\20\\c4\\81\\f3\\fe\\78\\19\\a8\\d0\\af\\7f\\81" \ ++ "\\72\\24\\61\\d9\\76\\93\\e3\\0b\\d2\\4f\\19\\17\\33\\57\\d4\\82" \ ++ "\\b0\\f1\\a8\\03\\f6\\01\\99\\a9\\b8\\8c\\83\\c9\\ba\\19\\87\\ea" \ ++ "\\d6\\3b\\06\\eb\\4c\\f7\\f1\\e5\\28\\a9\\10\\b6\\46\\de\\e1\\e1" \ ++ "\\3f\\c1\\cc\\72\\be\\2a\\43\\c6\\f6\\d0\\b5\\a0\\c4\\24\\6e\\4f" \ ++ "\\bd\\ec\\22\\8a\\07\\11\\3d\\f9\\d3\\15\\02\\03\\01\\00\\01\\a3" \ ++ "\\82\\01\\26\\30\\82\\01\\22\\30\\1f\\06\\03\\55\\1d\\23\\04\\18" \ ++ "\\30\\16\\80\\14\\f2\\9d\\42\\4e\\0f\\c4\\48\\25\\58\\2f\\1c\\ce" \ ++ "\\0f\\a1\\3f\\22\\c8\\55\\c8\\91\\30\\3b\\06\\08\\2b\\06\\01\\05" \ ++ "\\05\\07\\01\\01\\04\\2f\\30\\2d\\30\\2b\\06\\08\\2b\\06\\01\\05" \ ++ "\\05\\07\\30\\01\\86\\1f\\68\\74\\74\\70\\3a\\2f\\2f\\69\\70\\61" \ ++ "\\2d\\63\\61\\2e\\69\\70\\61\\2e\\64\\65\\76\\65\\6c\\2f\\63\\61" \ ++ "\\2f\\6f\\63\\73\\70\\30\\0e\\06\\03\\55\\1d\\0f\\01\\01\\ff\\04" \ ++ "\\04\\03\\02\\04\\f0\\30\\1d\\06\\03\\55\\1d\\25\\04\\16\\30\\14" \ ++ "\\06\\08\\2b\\06\\01\\05\\05\\07\\03\\01\\06\\08\\2b\\06\\01\\05" \ ++ "\\05\\07\\03\\02\\30\\74\\06\\03\\55\\1d\\1f\\04\\6d\\30\\6b\\30" \ ++ "\\69\\a0\\31\\a0\\2f\\86\\2d\\68\\74\\74\\70\\3a\\2f\\2f\\69\\70" \ ++ "\\61\\2d\\63\\61\\2e\\69\\70\\61\\2e\\64\\65\\76\\65\\6c\\2f\\69" \ ++ "\\70\\61\\2f\\63\\72\\6c\\2f\\4d\\61\\73\\74\\65\\72\\43\\52\\4c" \ ++ "\\2e\\62\\69\\6e\\a2\\34\\a4\\32\\30\\30\\31\\0e\\30\\0c\\06\\03" \ ++ "\\55\\04\\0a\\0c\\05\\69\\70\\61\\63\\61\\31\\1e\\30\\1c\\06\\03" \ ++ "\\55\\04\\03\\0c\\15\\43\\65\\72\\74\\69\\66\\69\\63\\61\\74\\65" \ ++ "\\20\\41\\75\\74\\68\\6f\\72\\69\\74\\79\\30\\1d\\06\\03\\55\\1d" \ ++ "\\0e\\04\\16\\04\\14\\2d\\2b\\3f\\cb\\f5\\b2\\ff\\32\\2c\\a8\\c2" \ ++ "\\1c\\dd\\bd\\8c\\80\\1e\\dd\\31\\82\\30\\0d\\06\\09\\2a\\86\\48" \ ++ "\\86\\f7\\0d\\01\\01\\0b\\05\\00\\03\\82\\01\\01\\00\\9a\\47\\2e" \ ++ "\\50\\a7\\4d\\1d\\53\\0f\\c9\\71\\42\\0c\\e5\\da\\7d\\49\\64\\e7" \ ++ "\\ab\\c8\\df\\df\\02\\c1\\87\\d1\\5b\\de\\da\\6f\\2b\\e4\\f0\\be" \ ++ "\\ba\\09\\df\\02\\85\\0b\\8a\\e6\\9b\\06\\7d\\69\\38\\6c\\72\\ff" \ ++ "\\4c\\7b\\2a\\0d\\3f\\23\\2f\\16\\46\\ff\\05\\93\\b0\\ea\\24\\28" \ ++ "\\d7\\12\\a1\\57\\b8\\59\\19\\25\\f3\\43\\0a\\d3\\fd\\0f\\37\\8d" \ ++ "\\b8\\ca\\15\\e7\\48\\8a\\a0\\c7\\c7\\4b\\7f\\01\\3c\\58\\d7\\37" \ ++ "\\e5\\ff\\7d\\2b\\01\\ac\\0d\\9f\\51\\6a\\e5\\40\\24\\e6\\5e\\55" \ ++ "\\0d\\f7\\b8\\2f\\42\\ac\\6d\\e5\\29\\6b\\c6\\0b\\a4\\bf\\19\\bd" \ ++ "\\39\\27\\ee\\fe\\c5\\b3\\db\\62\\d4\\be\\d2\\47\\ba\\96\\30\\5a" \ ++ "\\fd\\62\\00\\b8\\27\\5d\\2f\\3a\\94\\0b\\95\\35\\85\\40\\2c\\bc" \ ++ "\\67\\df\\8a\\f9\\f1\\7b\\19\\96\\3e\\42\\48\\13\\23\\04\\95\\a9" \ ++ "\\6b\\11\\33\\81\\47\\5a\\83\\72\\f6\\20\\fa\\8e\\41\\7b\\8f\\77" \ ++ "\\47\\7c\\c7\\5d\\46\\f4\\4f\\fd\\81\\0a\\ae\\39\\27\\b6\\6a\\26" \ ++ "\\63\\b1\\d3\\bf\\55\\83\\82\\9b\\36\\6c\\33\\64\\0f\\50\\c0\\55" \ ++ "\\94\\13\\c3\\85\\f4\\d5\\71\\65\\d0\\c0\\dd\\fc\\e6\\ec\\9c\\5b" \ ++ "\\f0\\11\\b5\\2c\\f3\\48\\c1\\36\\8c\\a2\\96\\48\\84" ++ ++#define TEST_CERT2_BIN \ ++ "\\30\\82\\06\\98\\30\\82\\05\\80\\a0\\03\\02\\01\\02\\02\\0a\\61" \ ++ "\\22\\88\\c2\\00\\00\\00\\00\\02\\a6\\30\\0d\\06\\09\\2a\\86\\48" \ ++ "\\86\\f7\\0d\\01\\01\\05\\05\\00\\30\\45\\31\\15\\30\\13\\06\\0a" \ ++ "\\09\\92\\26\\89\\93\\f2\\2c\\64\\01\\19\\16\\05\\64\\65\\76\\65" \ ++ "\\6c\\31\\12\\30\\10\\06\\0a\\09\\92\\26\\89\\93\\f2\\2c\\64\\01" \ ++ "\\19\\16\\02\\61\\64\\31\\18\\30\\16\\06\\03\\55\\04\\03\\13\\0f" \ ++ "\\61\\64\\2d\\41\\44\\2d\\53\\45\\52\\56\\45\\52\\2d\\43\\41\\30" \ ++ "\\1e\\17\\0d\\31\\36\\31\\31\\31\\31\\31\\33\\35\\31\\31\\31\\5a" \ ++ "\\17\\0d\\31\\37\\31\\31\\31\\31\\31\\33\\35\\31\\31\\31\\5a\\30" \ ++ "\\70\\31\\15\\30\\13\\06\\0a\\09\\92\\26\\89\\93\\f2\\2c\\64\\01" \ ++ "\\19\\16\\05\\64\\65\\76\\65\\6c\\31\\12\\30\\10\\06\\0a\\09\\92" \ ++ "\\26\\89\\93\\f2\\2c\\64\\01\\19\\16\\02\\61\\64\\31\\0e\\30\\0c" \ ++ "\\06\\03\\55\\04\\03\\13\\05\\55\\73\\65\\72\\73\\31\\0c\\30\\0a" \ ++ "\\06\\03\\55\\04\\03\\13\\03\\74\\20\\75\\31\\25\\30\\23\\06\\09" \ ++ "\\2a\\86\\48\\86\\f7\\0d\\01\\09\\01\\16\\16\\74\\65\\73\\74\\2e" \ ++ "\\75\\73\\65\\72\\40\\65\\6d\\61\\69\\6c\\2e\\64\\6f\\6d\\61\\69" \ ++ "\\6e\\30\\82\\01\\22\\30\\0d\\06\\09\\2a\\86\\48\\86\\f7\\0d\\01" \ ++ "\\01\\01\\05\\00\\03\\82\\01\\0f\\00\\30\\82\\01\\0a\\02\\82\\01" \ ++ "\\01\\00\\9c\\cf\\36\\99\\de\\63\\74\\2b\\77\\25\\9e\\24\\d9\\77" \ ++ "\\4b\\5f\\98\\c0\\8c\\d7\\20\\91\\c0\\1c\\e8\\37\\45\\bf\\3c\\d9" \ ++ "\\33\\bd\\e9\\de\\c9\\5d\\d4\\cd\\06\\0a\\0d\\d4\\f1\\7c\\74\\5b" \ ++ "\\29\\d5\\66\\9c\\2c\\9f\\6b\\1a\\0f\\0d\\e6\\6c\\62\\a5\\41\\4f" \ ++ "\\c3\\a4\\88\\27\\11\\5d\\b7\\b1\\fb\\f8\\8d\\ee\\43\\8d\\93\\b5" \ ++ "\\8c\\b4\\34\\06\\f5\\e9\\2f\\5a\\26\\68\\d7\\43\\60\\82\\5e\\22" \ ++ "\\a7\\c6\\34\\40\\19\\a5\\8e\\f0\\58\\9f\\16\\2d\\43\\3f\\0c\\da" \ ++ "\\e2\\23\\f6\\09\\2a\\5e\\bd\\84\\27\\c8\\ab\\d5\\70\\f8\\3d\\9c" \ ++ "\\14\\c2\\c2\\a2\\77\\e8\\44\\73\\10\\01\\34\\40\\1f\\c6\\2f\\a0" \ ++ "\\70\\ee\\2f\\d5\\4b\\be\\4c\\c7\\45\\f7\\ac\\9c\\c3\\68\\5b\\1d" \ ++ "\\5a\\4b\\77\\65\\76\\e4\\b3\\92\\f4\\84\\0a\\9e\\6a\\9c\\c9\\53" \ ++ "\\42\\9f\\6d\\fe\\f9\\f5\\f2\\9a\\15\\50\\47\\ef\\f4\\06\\59\\c8" \ ++ "\\50\\48\\4b\\46\\95\\68\\25\\c5\\bd\\4f\\65\\34\\00\\fc\\31\\69" \ ++ "\\f8\\3e\\e0\\20\\83\\41\\27\\0b\\5c\\46\\98\\14\\f0\\07\\de\\02" \ ++ "\\17\\b1\\d2\\9c\\be\\1c\\0d\\56\\22\\1b\\02\\fe\\da\\69\\b9\\ef" \ ++ "\\91\\37\\39\\7f\\24\\da\\c4\\81\\5e\\82\\31\\2f\\98\\1d\\f7\\73" \ ++ "\\5b\\23\\02\\03\\01\\00\\01\\a3\\82\\03\\5d\\30\\82\\03\\59\\30" \ ++ "\\3d\\06\\09\\2b\\06\\01\\04\\01\\82\\37\\15\\07\\04\\30\\30\\2e" \ ++ "\\06\\26\\2b\\06\\01\\04\\01\\82\\37\\15\\08\\87\\85\\a1\\23\\84" \ ++ "\\c8\\b2\\26\\83\\9d\\9d\\21\\82\\d4\\a6\\1b\\86\\a3\\ba\\37\\81" \ ++ "\\10\\85\\89\\d5\\02\\d6\\8f\\24\\02\\01\\64\\02\\01\\02\\30\\29" \ ++ "\\06\\03\\55\\1d\\25\\04\\22\\30\\20\\06\\08\\2b\\06\\01\\05\\05" \ ++ "\\07\\03\\02\\06\\08\\2b\\06\\01\\05\\05\\07\\03\\04\\06\\0a\\2b" \ ++ "\\06\\01\\04\\01\\82\\37\\0a\\03\\04\\30\\0e\\06\\03\\55\\1d\\0f" \ ++ "\\01\\01\\ff\\04\\04\\03\\02\\05\\a0\\30\\35\\06\\09\\2b\\06\\01" \ ++ "\\04\\01\\82\\37\\15\\0a\\04\\28\\30\\26\\30\\0a\\06\\08\\2b\\06" \ ++ "\\01\\05\\05\\07\\03\\02\\30\\0a\\06\\08\\2b\\06\\01\\05\\05\\07" \ ++ "\\03\\04\\30\\0c\\06\\0a\\2b\\06\\01\\04\\01\\82\\37\\0a\\03\\04" \ ++ "\\30\\81\\94\\06\\09\\2a\\86\\48\\86\\f7\\0d\\01\\09\\0f\\04\\81" \ ++ "\\86\\30\\81\\83\\30\\0b\\06\\09\\60\\86\\48\\01\\65\\03\\04\\01" \ ++ "\\2a\\30\\0b\\06\\09\\60\\86\\48\\01\\65\\03\\04\\01\\2d\\30\\0b" \ ++ "\\06\\09\\60\\86\\48\\01\\65\\03\\04\\01\\16\\30\\0b\\06\\09\\60" \ ++ "\\86\\48\\01\\65\\03\\04\\01\\19\\30\\0b\\06\\09\\60\\86\\48\\01" \ ++ "\\65\\03\\04\\01\\02\\30\\0b\\06\\09\\60\\86\\48\\01\\65\\03\\04" \ ++ "\\01\\05\\30\\0a\\06\\08\\2a\\86\\48\\86\\f7\\0d\\03\\07\\30\\07" \ ++ "\\06\\05\\2b\\0e\\03\\02\\07\\30\\0e\\06\\08\\2a\\86\\48\\86\\f7" \ ++ "\\0d\\03\\02\\02\\02\\00\\80\\30\\0e\\06\\08\\2a\\86\\48\\86\\f7" \ ++ "\\0d\\03\\04\\02\\02\\02\\00\\30\\1d\\06\\03\\55\\1d\\0e\\04\\16" \ ++ "\\04\\14\\49\\ac\\ad\\e0\\65\\30\\c4\\ce\\a0\\09\\03\\5b\\ad\\4a" \ ++ "\\7b\\49\\5e\\c9\\6c\\b4\\30\\1f\\06\\03\\55\\1d\\23\\04\\18\\30" \ ++ "\\16\\80\\14\\62\\50\\b6\\8d\\a1\\e6\\2d\\91\\bf\\b0\\54\\4d\\8f" \ ++ "\\a8\\ca\\10\\ae\\b8\\dd\\54\\30\\81\\cc\\06\\03\\55\\1d\\1f\\04" \ ++ "\\81\\c4\\30\\81\\c1\\30\\81\\be\\a0\\81\\bb\\a0\\81\\b8\\86\\81" \ ++ "\\b5\\6c\\64\\61\\70\\3a\\2f\\2f\\2f\\43\\4e\\3d\\61\\64\\2d\\41" \ ++ "\\44\\2d\\53\\45\\52\\56\\45\\52\\2d\\43\\41\\2c\\43\\4e\\3d\\61" \ ++ "\\64\\2d\\73\\65\\72\\76\\65\\72\\2c\\43\\4e\\3d\\43\\44\\50\\2c" \ ++ "\\43\\4e\\3d\\50\\75\\62\\6c\\69\\63\\25\\32\\30\\4b\\65\\79\\25" \ ++ "\\32\\30\\53\\65\\72\\76\\69\\63\\65\\73\\2c\\43\\4e\\3d\\53\\65" \ ++ "\\72\\76\\69\\63\\65\\73\\2c\\43\\4e\\3d\\43\\6f\\6e\\66\\69\\67" \ ++ "\\75\\72\\61\\74\\69\\6f\\6e\\2c\\44\\43\\3d\\61\\64\\2c\\44\\43" \ ++ "\\3d\\64\\65\\76\\65\\6c\\3f\\63\\65\\72\\74\\69\\66\\69\\63\\61" \ ++ "\\74\\65\\52\\65\\76\\6f\\63\\61\\74\\69\\6f\\6e\\4c\\69\\73\\74" \ ++ "\\3f\\62\\61\\73\\65\\3f\\6f\\62\\6a\\65\\63\\74\\43\\6c\\61\\73" \ ++ "\\73\\3d\\63\\52\\4c\\44\\69\\73\\74\\72\\69\\62\\75\\74\\69\\6f" \ ++ "\\6e\\50\\6f\\69\\6e\\74\\30\\81\\be\\06\\08\\2b\\06\\01\\05\\05" \ ++ "\\07\\01\\01\\04\\81\\b1\\30\\81\\ae\\30\\81\\ab\\06\\08\\2b\\06" \ ++ "\\01\\05\\05\\07\\30\\02\\86\\81\\9e\\6c\\64\\61\\70\\3a\\2f\\2f" \ ++ "\\2f\\43\\4e\\3d\\61\\64\\2d\\41\\44\\2d\\53\\45\\52\\56\\45\\52" \ ++ "\\2d\\43\\41\\2c\\43\\4e\\3d\\41\\49\\41\\2c\\43\\4e\\3d\\50\\75" \ ++ "\\62\\6c\\69\\63\\25\\32\\30\\4b\\65\\79\\25\\32\\30\\53\\65\\72" \ ++ "\\76\\69\\63\\65\\73\\2c\\43\\4e\\3d\\53\\65\\72\\76\\69\\63\\65" \ ++ "\\73\\2c\\43\\4e\\3d\\43\\6f\\6e\\66\\69\\67\\75\\72\\61\\74\\69" \ ++ "\\6f\\6e\\2c\\44\\43\\3d\\61\\64\\2c\\44\\43\\3d\\64\\65\\76\\65" \ ++ "\\6c\\3f\\63\\41\\43\\65\\72\\74\\69\\66\\69\\63\\61\\74\\65\\3f" \ ++ "\\62\\61\\73\\65\\3f\\6f\\62\\6a\\65\\63\\74\\43\\6c\\61\\73\\73" \ ++ "\\3d\\63\\65\\72\\74\\69\\66\\69\\63\\61\\74\\69\\6f\\6e\\41\\75" \ ++ "\\74\\68\\6f\\72\\69\\74\\79\\30\\3f\\06\\03\\55\\1d\\11\\04\\38" \ ++ "\\30\\36\\a0\\1c\\06\\0a\\2b\\06\\01\\04\\01\\82\\37\\14\\02\\03" \ ++ "\\a0\\0e\\0c\\0c\\74\\75\\31\\40\\61\\64\\2e\\64\\65\\76\\65\\6c" \ ++ "\\81\\16\\74\\65\\73\\74\\2e\\75\\73\\65\\72\\40\\65\\6d\\61\\69" \ ++ "\\6c\\2e\\64\\6f\\6d\\61\\69\\6e\\30\\0d\\06\\09\\2a\\86\\48\\86" \ ++ "\\f7\\0d\\01\\01\\05\\05\\00\\03\\82\\01\\01\\00\\41\\45\\0a\\6d" \ ++ "\\bb\\7f\\5c\\07\\0c\\c9\\b0\\39\\55\\6d\\7c\\b5\\02\\cd\\e8\\b2" \ ++ "\\e5\\02\\94\\77\\60\\db\\d1\\af\\1d\\db\\44\\5f\\ce\\83\\db\\80" \ ++ "\\2e\\e2\\b2\\08\\25\\82\\14\\cb\\48\\95\\20\\13\\6c\\a9\\aa\\f8" \ ++ "\\31\\56\\ed\\c0\\3b\\d4\\ae\\2e\\e3\\8f\\05\\fc\\ab\\5f\\2a\\69" \ ++ "\\23\\bc\\b8\\8c\\ec\\2d\\a9\\0b\\86\\95\\73\\73\\db\\17\\ce\\c6" \ ++ "\\ae\\c5\\b4\\c1\\25\\87\\3b\\67\\43\\9e\\87\\5a\\e6\\b9\\a0\\28" \ ++ "\\12\\3d\\a8\\2e\\d7\\5e\\ef\\65\\2d\\e6\\a5\\67\\84\\ac\\fd\\31" \ ++ "\\c1\\78\\d8\\72\\51\\a2\\88\\55\\0f\\97\\47\\93\\07\\ea\\8a\\53" \ ++ "\\27\\4e\\34\\54\\34\\1f\\a0\\6a\\03\\44\\fb\\23\\61\\8e\\87\\8e" \ ++ "\\3c\\d0\\8f\\ae\\e4\\cf\\ee\\65\\a8\\ba\\96\\68\\08\\1c\\60\\e2" \ ++ "\\4e\\11\\a3\\74\\b8\\a5\\4e\\ea\\6a\\82\\4c\\c2\\4d\\63\\8e\\9f" \ ++ "\\7c\\2f\\a8\\c0\\62\\f8\\f7\\d9\\25\\c4\\91\\ab\\4d\\6a\\44\\af" \ ++ "\\75\\93\\53\\03\\a4\\99\\c8\\cd\\91\\89\\60\\75\\30\\99\\76\\05" \ ++ "\\5a\\a0\\03\\a7\\a1\\2c\\03\\04\\8f\\d4\\5a\\31\\52\\28\\5a\\e6" \ ++ "\\a2\\d3\\43\\21\\5b\\dc\\a2\\1d\\55\\a9\\48\\c5\\c4\\aa\\f3\\8b" \ ++ "\\e6\\3e\\75\\96\\e4\\3e\\64\\af\\e8\\a7\\6a\\b6" ++ ++static void test_sss_certmap_get_search_filter(void **state) ++{ ++ int ret; ++ struct sss_certmap_ctx *ctx; ++ char *filter; ++ char **domains; ++ const char *dom_list[] = {"test.dom", NULL}; ++ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ++ ret = sss_certmap_add_rule(ctx, 100, ++ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", ++ "LDAP:rule100={issuer_dn}{subject_dn}", NULL); ++ assert_int_equal(ret, 0); ++ ++ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), ++ sizeof(test_cert_der), ++ &filter, &domains); ++ assert_int_equal(ret, 0); ++ assert_non_null(filter); ++ assert_string_equal(filter, "rule100=CN=Certificate Authority,O=IPA.DEVEL" ++ "CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); ++ assert_null(domains); ++ ++ ret = sss_certmap_add_rule(ctx, 99, ++ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", ++ "LDAP:rule99={issuer_dn}{subject_dn}", ++ dom_list); ++ assert_int_equal(ret, 0); ++ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), ++ sizeof(test_cert_der), ++ &filter, &domains); ++ assert_int_equal(ret, 0); ++ assert_non_null(filter); ++ assert_string_equal(filter, "rule99=CN=Certificate Authority,O=IPA.DEVEL" ++ "CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); ++ assert_non_null(domains); ++ assert_string_equal(domains[0], "test.dom"); ++ assert_null(domains[1]); ++ ++ ret = sss_certmap_add_rule(ctx, 98, ++ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", ++ "LDAP:rule98=userCertificate;binary={cert!bin}", ++ dom_list); ++ assert_int_equal(ret, 0); ++ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), ++ sizeof(test_cert_der), ++ &filter, &domains); ++ assert_int_equal(ret, 0); ++ assert_non_null(filter); ++ assert_string_equal(filter, "rule98=userCertificate;binary=" TEST_CERT_BIN); ++ assert_non_null(domains); ++ assert_string_equal(domains[0], "test.dom"); ++ assert_null(domains[1]); ++ ++ ret = sss_certmap_add_rule(ctx, 97, ++ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", ++ "LDAP:rule97={issuer_dn!nss_x500}{subject_dn}", ++ dom_list); ++ assert_int_equal(ret, 0); ++ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), ++ sizeof(test_cert_der), ++ &filter, &domains); ++ assert_int_equal(ret, 0); ++ assert_non_null(filter); ++ assert_string_equal(filter, "rule97=O=IPA.DEVEL,CN=Certificate Authority" ++ "CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); ++ assert_non_null(domains); ++ assert_string_equal(domains[0], "test.dom"); ++ assert_null(domains[1]); ++ ++ ret = sss_certmap_add_rule(ctx, 96, ++ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", ++ "LDAP:rule96={issuer_dn!nss_x500}{subject_dn!nss_x500}", ++ dom_list); ++ assert_int_equal(ret, 0); ++ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), ++ sizeof(test_cert_der), ++ &filter, &domains); ++ assert_int_equal(ret, 0); ++ assert_non_null(filter); ++ assert_string_equal(filter, "rule96=O=IPA.DEVEL,CN=Certificate Authority" ++ "O=IPA.DEVEL,CN=ipa-devel.ipa.devel"); ++ assert_non_null(domains); ++ assert_string_equal(domains[0], "test.dom"); ++ assert_null(domains[1]); ++ ++ ret = sss_certmap_add_rule(ctx, 95, ++ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", ++ NULL, NULL); ++ assert_int_equal(ret, 0); ++ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), ++ sizeof(test_cert_der), ++ &filter, &domains); ++ assert_int_equal(ret, 0); ++ assert_non_null(filter); ++ assert_string_equal(filter, "(userCertificate;binary=" TEST_CERT_BIN ")"); ++ assert_null(domains); ++ ++ ret = sss_certmap_add_rule(ctx, 94, ++ "KRB5:CN=Certificate Authority,O=IPA.DEVEL", ++ "LDAP:rule94={issuer_dn!ad_x500}{subject_dn!ad_x500}", ++ dom_list); ++ assert_int_equal(ret, 0); ++ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der), ++ sizeof(test_cert_der), ++ &filter, &domains); ++ assert_int_equal(ret, 0); ++ assert_non_null(filter); ++ assert_string_equal(filter, "rule94=O=IPA.DEVEL,CN=Certificate Authority" ++ "O=IPA.DEVEL,CN=ipa-devel.ipa.devel"); ++ assert_non_null(domains); ++ assert_string_equal(domains[0], "test.dom"); ++ assert_null(domains[1]); ++ ++ ++ ret = sss_certmap_add_rule(ctx, 89, NULL, ++ "(rule89={subject_nt_principal})", ++ NULL); ++ assert_int_equal(ret, 0); ++ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der), ++ sizeof(test_cert2_der), ++ &filter, &domains); ++ assert_int_equal(ret, 0); ++ assert_non_null(filter); ++ assert_string_equal(filter, "(rule89=tu1@ad.devel)"); ++ assert_null(domains); ++ ++ ret = sss_certmap_add_rule(ctx, 88, NULL, ++ "(rule88={subject_nt_principal.short_name})", ++ NULL); ++ assert_int_equal(ret, 0); ++ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der), ++ sizeof(test_cert2_der), ++ &filter, &domains); ++ assert_int_equal(ret, 0); ++ assert_non_null(filter); ++ assert_string_equal(filter, "(rule88=tu1)"); ++ assert_null(domains); ++ ++ ret = sss_certmap_add_rule(ctx, 87, NULL, ++ "LDAP:rule87={issuer_dn!nss_x500}{subject_dn!nss_x500}", ++ NULL); ++ assert_int_equal(ret, 0); ++ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der), ++ sizeof(test_cert2_der), ++ &filter, &domains); ++ assert_int_equal(ret, 0); ++ assert_non_null(filter); ++ assert_string_equal(filter, "rule87=DC=devel,DC=ad,CN=ad-AD-SERVER-CA" ++ "DC=devel,DC=ad,CN=Users,CN=t u,E=test.user@email.domain"); ++ assert_null(domains); ++ ++ ret = sss_certmap_add_rule(ctx, 86, NULL, ++ "LDAP:rule86={issuer_dn!ad_x500}{subject_dn!ad_x500}", ++ NULL); ++ assert_int_equal(ret, 0); ++ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der), ++ sizeof(test_cert2_der), ++ &filter, &domains); ++ assert_int_equal(ret, 0); ++ assert_non_null(filter); ++ assert_string_equal(filter, "rule86=DC=devel,DC=ad,CN=ad-AD-SERVER-CA" ++ "DC=devel,DC=ad,CN=Users,CN=t u,E=test.user@email.domain"); ++ assert_null(domains); ++ ++ ++ sss_certmap_free_ctx(ctx); ++ ++ /* check defaults when no rules are added yet */ ++ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(ctx); ++ assert_null(ctx->prio_list); ++ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der), ++ sizeof(test_cert2_der), ++ &filter, &domains); ++ assert_int_equal(ret, 0); ++ assert_non_null(filter); ++ assert_string_equal(filter, "(userCertificate;binary=" TEST_CERT2_BIN")"); ++ assert_null(domains); ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ int rv; ++ poptContext pc; ++ int opt; ++ struct poptOption long_options[] = { ++ POPT_AUTOHELP ++ SSSD_DEBUG_OPTS ++ POPT_TABLEEND ++ }; ++ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test(test_sss_certmap_init), ++ cmocka_unit_test(test_sss_certmap_add_rule), ++ cmocka_unit_test(test_sss_certmap_add_matching_rule), ++ cmocka_unit_test(test_check_ad_attr_name), ++ cmocka_unit_test(test_sss_cert_get_content), ++ cmocka_unit_test(test_sss_cert_get_content_2), ++ cmocka_unit_test(test_sss_certmap_match_cert), ++ cmocka_unit_test(test_sss_certmap_add_mapping_rule), ++ cmocka_unit_test(test_sss_certmap_get_search_filter), ++ }; ++ ++ /* Set debug level to invalid value so we can deside if -d 0 was used. */ ++ debug_level = SSSDBG_INVALID; ++ ++ pc = poptGetContext(argv[0], argc, argv, long_options, 0); ++ while((opt = poptGetNextOpt(pc)) != -1) { ++ switch(opt) { ++ default: ++ fprintf(stderr, "\nInvalid option %s: %s\n\n", ++ poptBadOption(pc, 0), poptStrerror(opt)); ++ poptPrintUsage(pc, stderr, 0); ++ return 1; ++ } ++ } ++ poptFreeContext(pc); ++ ++ DEBUG_CLI_INIT(debug_level); ++ ++#ifdef HAVE_NSS ++ nspr_nss_init(); ++#endif ++ ++ tests_set_cwd(); ++ rv = cmocka_run_group_tests(tests, NULL, NULL); ++ ++#ifdef HAVE_NSS ++ /* Cleanup NSS and NSPR to make valgrind happy. */ ++ nspr_nss_cleanup(); ++#endif ++ ++ return rv; ++} +diff --git a/src/tests/dlopen-tests.c b/src/tests/dlopen-tests.c +index 419857cc739d197493e46629d00aa5fb6cfde824..3914317de90f870fab42d2d72d8e2eb5ea8d9e14 100644 +--- a/src/tests/dlopen-tests.c ++++ b/src/tests/dlopen-tests.c +@@ -45,6 +45,7 @@ struct so { + { "libsss_idmap.so", { LIBPFX"libsss_idmap.so", NULL } }, + { "libsss_nss_idmap.so", { LIBPFX"libsss_nss_idmap.so", NULL } }, + { "libnss_sss.so", { LIBPFX"libnss_sss.so", NULL } }, ++ { "libsss_certmap.so", { LIBPFX"libsss_certmap.so", NULL } }, + { "pam_sss.so", { LIBPFX"pam_sss.so", NULL } }, + #ifdef BUILD_LIBWBCLIENT + { "libwbclient.so", { LIBPFX"libwbclient.so", NULL } }, +-- +2.9.3 + diff --git a/SOURCES/0005-certmap-add-placeholder-for-OpenSSL-implementation.patch b/SOURCES/0005-certmap-add-placeholder-for-OpenSSL-implementation.patch new file mode 100644 index 0000000..99a2bd8 --- /dev/null +++ b/SOURCES/0005-certmap-add-placeholder-for-OpenSSL-implementation.patch @@ -0,0 +1,151 @@ +From b1336bdfeacf904c8fdec04e06d8b90ef9ad15b3 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 15 Mar 2017 10:57:09 +0100 +Subject: [PATCH 05/15] certmap: add placeholder for OpenSSL implementation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +--- + Makefile.am | 30 +++++++++++++++++++++-------- + src/lib/certmap/sss_cert_content_crypto.c | 32 +++++++++++++++++++++++++++++++ + src/lib/certmap/sss_certmap_int.h | 8 +++++--- + 3 files changed, 59 insertions(+), 11 deletions(-) + create mode 100644 src/lib/certmap/sss_cert_content_crypto.c + +diff --git a/Makefile.am b/Makefile.am +index 8ca12c10d2713b6a72361d84b25486500c79f407..7947b7a5fbe3ca1034baac1c13c53300994b1bf8 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -278,9 +278,12 @@ if HAVE_CMOCKA + simple-access-tests \ + krb5_common_test \ + test_iobuf \ +- sss_certmap_test \ + $(NULL) + ++if HAVE_NSS ++non_interactive_cmocka_based_tests += sss_certmap_test ++endif #HAVE_NSS ++ + if HAVE_LIBRESOLV + non_interactive_cmocka_based_tests += test_resolv_fake + endif # HAVE_LIBRESOLV +@@ -1715,7 +1718,6 @@ sssd_check_socket_activated_responders_LDADD = \ + $(NULL) + endif + +-if HAVE_NSS + pkgconfig_DATA += src/lib/certmap/sss_certmap.pc + libsss_certmap_la_DEPENDENCIES = src/lib/certmap/sss_certmap.exports + libsss_certmap_la_SOURCES = \ +@@ -1726,26 +1728,38 @@ libsss_certmap_la_SOURCES = \ + src/lib/certmap/sss_certmap_ldap_mapping.c \ + src/util/util_ext.c \ + src/util/cert/cert_common.c \ +- src/util/crypto/nss/nss_base64.c \ +- src/util/cert/nss/cert.c \ +- src/util/crypto/nss/nss_util.c \ + $(NULL) + libsss_certmap_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(TALLOC_CFLAGS) \ +- $(NSS_CFLAGS) \ + $(NULL) + libsss_certmap_la_LIBADD = \ + $(TALLOC_LIBS) \ +- $(NSS_LIBS) \ + $(NULL) + libsss_certmap_la_LDFLAGS = \ + -Wl,--version-script,$(srcdir)/src/lib/certmap/sss_certmap.exports \ + -version-info 0:0:0 + ++if HAVE_NSS ++libsss_certmap_la_SOURCES += \ ++ src/util/crypto/nss/nss_base64.c \ ++ src/util/cert/nss/cert.c \ ++ src/util/crypto/nss/nss_util.c \ ++ $(NULL) ++libsss_certmap_la_CFLAGS += $(NSS_CFLAGS) ++libsss_certmap_la_LIBADD += $(NSS_LIBS) ++else ++libsss_certmap_la_SOURCES += \ ++ src/util/crypto/libcrypto/crypto_base64.c \ ++ src/util/cert/libcrypto/cert.c \ ++ $(NULL) ++ ++libsss_certmap_la_CFLAGS += $(CRYPTO_CFLAGS) ++libsss_certmap_la_LIBADD += $(CRYPTO_LIBS) ++endif ++ + dist_noinst_DATA += src/lib/certmap/sss_certmap.exports + dist_noinst_HEADERS += src/lib/certmap/sss_certmap_int.h +-endif + + ################# + # Feature Tests # +diff --git a/src/lib/certmap/sss_cert_content_crypto.c b/src/lib/certmap/sss_cert_content_crypto.c +new file mode 100644 +index 0000000000000000000000000000000000000000..bddcf9bce986bd986aa0aa5f16a0744a97ab36d6 +--- /dev/null ++++ b/src/lib/certmap/sss_cert_content_crypto.c +@@ -0,0 +1,32 @@ ++/* ++ SSSD - certificate handling utils - OpenSSL version ++ The calls defined here should be useable outside of SSSD as well, e.g. in ++ libsss_certmap. ++ ++ Copyright (C) Sumit Bose 2017 ++ ++ 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 . ++*/ ++ ++#include ++ ++#include "lib/certmap/sss_certmap.h" ++#include "lib/certmap/sss_certmap_int.h" ++ ++int sss_cert_get_content(TALLOC_CTX *mem_ctx, ++ const uint8_t *der_blob, size_t der_size, ++ struct sss_cert_content **content) ++{ ++ return EINVAL; ++} +diff --git a/src/lib/certmap/sss_certmap_int.h b/src/lib/certmap/sss_certmap_int.h +index 28f1c596cfb5e78077b6a8e9baefa88b4900a022..0b4cda73639be9b323ac3388f97be90bc1a771f2 100644 +--- a/src/lib/certmap/sss_certmap_int.h ++++ b/src/lib/certmap/sss_certmap_int.h +@@ -22,12 +22,14 @@ + along with this program. If not, see . + */ + +-#include +-#include +- + #ifndef __SSS_CERTMAP_INT_H__ + #define __SSS_CERTMAP_INT_H__ + ++#include ++#include ++#include ++#include ++ + #define CM_DEBUG(cm_ctx, format, ...) do { \ + if (cm_ctx != NULL && cm_ctx->debug != NULL) { \ + cm_ctx->debug(cm_ctx->debug_priv, __FILE__, __LINE__, __FUNCTION__, \ +-- +2.9.3 + diff --git a/SOURCES/0005-sssctl-Fix-format-string-for-size_t.patch b/SOURCES/0005-sssctl-Fix-format-string-for-size_t.patch deleted file mode 100644 index b2037a5..0000000 --- a/SOURCES/0005-sssctl-Fix-format-string-for-size_t.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 8d82518980eae15d4644ce55058ed852f7f657f5 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Fri, 8 Jul 2016 13:04:10 +0200 -Subject: [PATCH 05/18] sssctl: Fix format string for size_t - -src/tools/sssctl/sssctl_config.c: In function 'sssctl_config_check': -src/tools/sssctl/sssctl_config.c:93:14: warning: format '%lu' expects - argument of type 'long unsigned int', but argument 2 has type - 'size_t {aka unsigned int}' [-Wformat=] - printf(_("Issues identified by validators: %lu\n"), num_errors); - ^ -src/tools/sssctl/sssctl_config.c:93:12: note: in expansion of macro '_' - printf(_("Issues identified by validators: %lu\n"), num_errors); - ^ -Reviewed-by: Jakub Hrozek - -(cherry picked from commit cca5695e6cab64def52c009afc8f055a85f1fde4) ---- - src/tools/sssctl/sssctl_config.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/tools/sssctl/sssctl_config.c b/src/tools/sssctl/sssctl_config.c -index 4f6dbcdd7d04183c65b6613efbe5ab95df19e2c7..a66d7749c4aee9bd00c0ad2d296292658ffdb9b2 100644 ---- a/src/tools/sssctl/sssctl_config.c -+++ b/src/tools/sssctl/sssctl_config.c -@@ -91,7 +91,7 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline, - } - - /* Output from validators */ -- printf(_("Issues identified by validators: %lu\n"), num_errors); -+ printf(_("Issues identified by validators: %zu\n"), num_errors); - for (i = 0; i < num_errors; i++) { - printf("%s\n", strs[i]); - } --- -2.4.11 - diff --git a/SOURCES/0006-doxygen-Fix-path-to-header-file-ipa_hbac.h.patch b/SOURCES/0006-doxygen-Fix-path-to-header-file-ipa_hbac.h.patch deleted file mode 100644 index b3e1f55..0000000 --- a/SOURCES/0006-doxygen-Fix-path-to-header-file-ipa_hbac.h.patch +++ /dev/null @@ -1,31 +0,0 @@ -From fda4c78ca651ce478fe744f7de87c2064e80a05d Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Fri, 8 Jul 2016 13:27:47 +0200 -Subject: [PATCH 06/18] doxygen: Fix path to header file ipa_hbac.h - -Warning: tag INPUT: input source `src/providers/ipa/ipa_hbac.h' does not exist -warning: source src/providers/ipa/ipa_hbac.h is not - a readable file or directory... skipping. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit b9b2c0836f64f375babb75d92b924f3780f20521) ---- - src/lib/ipa_hbac/ipa_hbac.doxy.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/lib/ipa_hbac/ipa_hbac.doxy.in b/src/lib/ipa_hbac/ipa_hbac.doxy.in -index 6d4a92659f1974fa96b8fcfbcca0d4107e3a7dae..d1e9f995ddeffd92dad03b5d1fd18077b6aeb645 100644 ---- a/src/lib/ipa_hbac/ipa_hbac.doxy.in -+++ b/src/lib/ipa_hbac/ipa_hbac.doxy.in -@@ -678,7 +678,7 @@ WARN_LOGFILE = - # directories like "/usr/src/myproject". Separate the files or directories - # with spaces. - --INPUT = @abs_top_srcdir@/src/providers/ipa/ipa_hbac.h -+INPUT = @abs_top_srcdir@/src/lib/ipa_hbac/ipa_hbac.h - - # This tag can be used to specify the character encoding of the source files - # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is --- -2.4.11 - diff --git a/SOURCES/0006-sysdb-add-sysdb_attrs_copy.patch b/SOURCES/0006-sysdb-add-sysdb_attrs_copy.patch new file mode 100644 index 0000000..f41c5e7 --- /dev/null +++ b/SOURCES/0006-sysdb-add-sysdb_attrs_copy.patch @@ -0,0 +1,173 @@ +From cae55d342a5f5c5ac22ac913b9251c2112b22c42 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 21 Sep 2015 12:32:48 +0200 +Subject: [PATCH 06/15] sysdb: add sysdb_attrs_copy() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +--- + src/db/sysdb.c | 24 ++++++++++++++ + src/db/sysdb.h | 1 + + src/tests/sysdb-tests.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 112 insertions(+) + +diff --git a/src/db/sysdb.c b/src/db/sysdb.c +index 5160e3df3810a113d4ec1371350e51a074aaa146..98b7afbfab5141fa9b63a4aab31c620545b3c1f2 100644 +--- a/src/db/sysdb.c ++++ b/src/db/sysdb.c +@@ -752,6 +752,30 @@ done: + return ret; + } + ++errno_t sysdb_attrs_copy(struct sysdb_attrs *src, struct sysdb_attrs *dst) ++{ ++ int ret; ++ size_t c; ++ size_t d; ++ ++ if (src == NULL || dst == NULL) { ++ return EINVAL; ++ } ++ ++ for (c = 0; c < src->num; c++) { ++ for (d = 0; d < src->a[c].num_values; d++) { ++ ret = sysdb_attrs_add_val_safe(dst, src->a[c].name, ++ &src->a[c].values[d]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_val failed.\n"); ++ return ret; ++ } ++ } ++ } ++ ++ return EOK; ++} ++ + int sysdb_attrs_users_from_str_list(struct sysdb_attrs *attrs, + const char *attr_name, + const char *domain, +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 83d0d794c737c094d1fd52e7cc7f2113b5d9a7a0..c677957bb639e40db2f985205160612094302e78 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -352,6 +352,7 @@ int sysdb_attrs_add_lc_name_alias_safe(struct sysdb_attrs *attrs, + int sysdb_attrs_copy_values(struct sysdb_attrs *src, + struct sysdb_attrs *dst, + const char *name); ++errno_t sysdb_attrs_copy(struct sysdb_attrs *src, struct sysdb_attrs *dst); + int sysdb_attrs_get_el(struct sysdb_attrs *attrs, const char *name, + struct ldb_message_element **el); + int sysdb_attrs_get_el_ext(struct sysdb_attrs *attrs, const char *name, +diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c +index 013b01a9a68d9de87d796d3aff41d98cef8cccc3..c343c734a27a335303974b6866a5d9e88d4c307e 100644 +--- a/src/tests/sysdb-tests.c ++++ b/src/tests/sysdb-tests.c +@@ -4997,6 +4997,92 @@ START_TEST(test_sysdb_attrs_add_string_safe) + } + END_TEST + ++START_TEST(test_sysdb_attrs_copy) ++{ ++ int ret; ++ struct sysdb_attrs *src; ++ struct sysdb_attrs *dst; ++ TALLOC_CTX *tmp_ctx; ++ const char *val; ++ const char **array; ++ ++ ret = sysdb_attrs_copy(NULL, NULL); ++ fail_unless(ret == EINVAL, "Wrong return code"); ++ ++ tmp_ctx = talloc_new(NULL); ++ fail_unless(tmp_ctx != NULL, "talloc_new failed"); ++ ++ src = sysdb_new_attrs(tmp_ctx); ++ fail_unless(src != NULL, "sysdb_new_attrs failed"); ++ ++ ret = sysdb_attrs_copy(src, NULL); ++ fail_unless(ret == EINVAL, "Wrong return code"); ++ ++ dst = sysdb_new_attrs(tmp_ctx); ++ fail_unless(dst != NULL, "sysdb_new_attrs failed"); ++ ++ ret = sysdb_attrs_copy(NULL, dst); ++ fail_unless(ret == EINVAL, "Wrong return code"); ++ ++ ret = sysdb_attrs_copy(src, dst); ++ fail_unless(ret == EOK, "sysdb_attrs_copy failed"); ++ fail_unless(dst->num == 0, "Wrong number of elements"); ++ ++ ret = sysdb_attrs_add_string(src, TEST_ATTR_NAME, TEST_ATTR_VALUE); ++ fail_unless(ret == EOK, "sysdb_attrs_add_val failed."); ++ ++ ret = sysdb_attrs_copy(src, dst); ++ fail_unless(ret == EOK, "sysdb_attrs_copy failed"); ++ fail_unless(dst->num == 1, "Wrong number of elements"); ++ ret = sysdb_attrs_get_string(dst, TEST_ATTR_NAME, &val); ++ fail_unless(ret == EOK, "sysdb_attrs_get_string failed.\n"); ++ fail_unless(strcmp(val, TEST_ATTR_VALUE) == 0, "Wrong attribute value."); ++ ++ /* Make sure the same entry is not copied twice */ ++ ret = sysdb_attrs_copy(src, dst); ++ fail_unless(ret == EOK, "sysdb_attrs_copy failed"); ++ fail_unless(dst->num == 1, "Wrong number of elements"); ++ ret = sysdb_attrs_get_string(dst, TEST_ATTR_NAME, &val); ++ fail_unless(ret == EOK, "sysdb_attrs_get_string failed.\n"); ++ fail_unless(strcmp(val, TEST_ATTR_VALUE) == 0, "Wrong attribute value."); ++ ++ /* Add new value to existing attribute */ ++ ret = sysdb_attrs_add_string(src, TEST_ATTR_NAME, TEST_ATTR_VALUE"_2nd"); ++ fail_unless(ret == EOK, "sysdb_attrs_add_val failed."); ++ ++ ret = sysdb_attrs_copy(src, dst); ++ fail_unless(ret == EOK, "sysdb_attrs_copy failed"); ++ fail_unless(dst->num == 1, "Wrong number of elements"); ++ ret = sysdb_attrs_get_string_array(dst, TEST_ATTR_NAME, tmp_ctx, &array); ++ fail_unless(ret == EOK, "sysdb_attrs_get_string_array failed.\n"); ++ fail_unless(strcmp(array[0], TEST_ATTR_VALUE) == 0, ++ "Wrong attribute value."); ++ fail_unless(strcmp(array[1], TEST_ATTR_VALUE"_2nd") == 0, ++ "Wrong attribute value."); ++ fail_unless(array[2] == NULL, "Wrong number of values."); ++ ++ /* Add new attribute */ ++ ret = sysdb_attrs_add_string(src, TEST_ATTR_NAME"_2nd", TEST_ATTR_VALUE); ++ fail_unless(ret == EOK, "sysdb_attrs_add_val failed."); ++ ++ ret = sysdb_attrs_copy(src, dst); ++ fail_unless(ret == EOK, "sysdb_attrs_copy failed"); ++ fail_unless(dst->num == 2, "Wrong number of elements"); ++ ret = sysdb_attrs_get_string_array(dst, TEST_ATTR_NAME, tmp_ctx, &array); ++ fail_unless(ret == EOK, "sysdb_attrs_get_string_array failed.\n"); ++ fail_unless(strcmp(array[0], TEST_ATTR_VALUE) == 0, ++ "Wrong attribute value."); ++ fail_unless(strcmp(array[1], TEST_ATTR_VALUE"_2nd") == 0, ++ "Wrong attribute value."); ++ fail_unless(array[2] == NULL, "Wrong number of values."); ++ ret = sysdb_attrs_get_string(dst, TEST_ATTR_NAME"_2nd", &val); ++ fail_unless(ret == EOK, "sysdb_attrs_get_string failed.\n"); ++ fail_unless(strcmp(val, TEST_ATTR_VALUE) == 0, "Wrong attribute value."); ++ ++ talloc_free(tmp_ctx); ++} ++END_TEST ++ + START_TEST (test_sysdb_search_return_ENOENT) + { + struct sysdb_test_ctx *test_ctx; +@@ -6995,6 +7081,7 @@ Suite *create_sysdb_suite(void) + tcase_add_test(tc_sysdb, test_sysdb_attrs_add_val); + tcase_add_test(tc_sysdb, test_sysdb_attrs_add_val_safe); + tcase_add_test(tc_sysdb, test_sysdb_attrs_add_string_safe); ++ tcase_add_test(tc_sysdb, test_sysdb_attrs_copy); + + /* ===== Test search return empty result ===== */ + tcase_add_test(tc_sysdb, test_sysdb_search_return_ENOENT); +-- +2.9.3 + diff --git a/SOURCES/0007-ipa_hbac-Fix-documentation-for-hbac_enable_debug.patch b/SOURCES/0007-ipa_hbac-Fix-documentation-for-hbac_enable_debug.patch deleted file mode 100644 index 0308ac2..0000000 --- a/SOURCES/0007-ipa_hbac-Fix-documentation-for-hbac_enable_debug.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 3743b49557f63d0ca541103fe0929e432cde3678 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Fri, 8 Jul 2016 14:39:43 +0200 -Subject: [PATCH 07/18] ipa_hbac: Fix documentation for hbac_enable_debug - -src/lib/ipa_hbac/ipa_hbac.h:68: warning: expected whitespace after [ command - -Reviewed-by: Jakub Hrozek -(cherry picked from commit f3db22862d22821be2d566435cb0c59387343fc2) ---- - src/lib/ipa_hbac/ipa_hbac.h | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/lib/ipa_hbac/ipa_hbac.h b/src/lib/ipa_hbac/ipa_hbac.h -index 8801c20c492caf53a089c2724c2ed4a96805904c..f9d339c058f109acdea95fa185182f08d1e8af9e 100644 ---- a/src/lib/ipa_hbac/ipa_hbac.h -+++ b/src/lib/ipa_hbac/ipa_hbac.h -@@ -65,8 +65,8 @@ typedef void (*hbac_debug_fn_t)(const char *file, int line, - ...) HBAC_ATTRIBUTE_PRINTF(5, 6); - - /** -- * HBAC uses external_debug_fn for logging messages. -- * @param[in|out] external_debug_void Pointer to external logging function. -+ * HBAC uses external_debug_fn for logging messages. -+ * @param[in] external_debug_fn Pointer to external logging function. - */ - void hbac_enable_debug(hbac_debug_fn_t external_debug_fn); - --- -2.4.11 - diff --git a/SOURCES/0007-sdap_get_users_send-new-argument-mapped_attrs.patch b/SOURCES/0007-sdap_get_users_send-new-argument-mapped_attrs.patch new file mode 100644 index 0000000..9292f78 --- /dev/null +++ b/SOURCES/0007-sdap_get_users_send-new-argument-mapped_attrs.patch @@ -0,0 +1,316 @@ +From af96fbe97576133ca6077c47f39b812e7e289040 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Sun, 12 Mar 2017 18:31:03 +0100 +Subject: [PATCH 07/15] sdap_get_users_send(): new argument mapped_attrs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mapped_attrs can be a list of sysdb_attrs which are not available on +the server side but should be store with the cached user entry. This is +needed e.g. when the input to look up the user in LDAP is not an +attribute which is stored in LDAP but some data where LDAP attributes +are extracted from. The current use case is the certificate mapping +library which can create LDAP search filters based on content of the +certificate. To allow upcoming cache lookup to use the input directly it +is stored in the user object in the cache. + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +--- + src/db/sysdb.h | 3 ++ + src/db/sysdb_ops.c | 61 ++++++++++++++++++++++++++++++ + src/providers/ldap/ldap_id.c | 4 +- + src/providers/ldap/sdap_async.h | 3 +- + src/providers/ldap/sdap_async_enum.c | 2 +- + src/providers/ldap/sdap_async_initgroups.c | 2 +- + src/providers/ldap/sdap_async_private.h | 1 + + src/providers/ldap/sdap_async_users.c | 41 +++++++++++++++++++- + src/providers/ldap/sdap_users.h | 1 + + 9 files changed, 111 insertions(+), 7 deletions(-) + +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index c677957bb639e40db2f985205160612094302e78..098f47f91187aac75c58c02f0af738c344765762 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -1246,6 +1246,9 @@ errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx, + errno_t sysdb_remove_cert(struct sss_domain_info *domain, + const char *cert); + ++errno_t sysdb_remove_mapped_data(struct sss_domain_info *domain, ++ struct sysdb_attrs *mapped_attr); ++ + /* === Functions related to GPOs === */ + + #define SYSDB_GPO_CONTAINER "cn=gpos,cn=ad,cn=custom" +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 242d3ce3bb795691e329790a07c3493672e8f523..6c2254df2b75d3d3419528523103ad9cddb40c9d 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -4685,6 +4685,67 @@ errno_t sysdb_search_user_by_cert(TALLOC_CTX *mem_ctx, + return sysdb_search_object_by_cert(mem_ctx, domain, cert, user_attrs, res); + } + ++errno_t sysdb_remove_mapped_data(struct sss_domain_info *domain, ++ struct sysdb_attrs *mapped_attr) ++{ ++ int ret; ++ char *val; ++ char *filter; ++ const char *attrs[] = {SYSDB_NAME, NULL}; ++ struct ldb_result *res = NULL; ++ size_t c; ++ bool all_ok = true; ++ ++ if (mapped_attr->num != 1 || mapped_attr->a[0].num_values != 1) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unsupported number of attributes.\n"); ++ return EINVAL; ++ } ++ ++ ret = bin_to_ldap_filter_value(NULL, mapped_attr->a[0].values[0].data, ++ mapped_attr->a[0].values[0].length, &val); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "bin_to_ldap_filter_value failed.\n"); ++ return ret; ++ } ++ ++ filter = talloc_asprintf(NULL, "(&("SYSDB_UC")(%s=%s))", ++ mapped_attr->a[0].name, val); ++ talloc_free(val); ++ if (filter == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); ++ return ENOMEM; ++ } ++ ++ ret = sysdb_search_object_attr(NULL, domain, filter, attrs, false, &res); ++ talloc_free(filter); ++ if (ret == ENOENT || res == NULL) { ++ DEBUG(SSSDBG_TRACE_ALL, "Mapped data not found.\n"); ++ talloc_free(res); ++ return EOK; ++ } else if (ret != EOK) { ++ talloc_free(res); ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_object_attr failed.\n"); ++ return ret; ++ } ++ ++ for (c = 0; c < res->count; c++) { ++ DEBUG(SSSDBG_TRACE_ALL, "Removing mapped data from [%s].\n", ++ ldb_dn_get_linearized(res->msgs[c]->dn)); ++ /* The timestamp cache is skipped on purpose here. */ ++ ret = sysdb_set_cache_entry_attr(domain->sysdb->ldb, res->msgs[c]->dn, ++ mapped_attr, SYSDB_MOD_DEL); ++ if (ret != EOK) { ++ all_ok = false; ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to remove mapped data from [%s], skipping.\n", ++ ldb_dn_get_linearized(res->msgs[c]->dn)); ++ } ++ } ++ talloc_free(res); ++ ++ return (all_ok ? EOK : EIO); ++} ++ + errno_t sysdb_remove_cert(struct sss_domain_info *domain, + const char *cert) + { +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index e9455b538daa2d65d944dbb68022a2773623d7b7..898ddb18689d55fcc3fdf021b38df0e574003eb2 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -442,7 +442,7 @@ static void users_get_search(struct tevent_req *req) + state->attrs, state->filter, + dp_opt_get_int(state->ctx->opts->basic, + SDAP_SEARCH_TIMEOUT), +- lookup_type); ++ lookup_type, NULL); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; +@@ -507,7 +507,7 @@ static void users_get_done(struct tevent_req *subreq) + ret = sdap_fallback_local_user(state, state->shortname, uid, &usr_attrs); + if (ret == EOK) { + ret = sdap_save_user(state, state->ctx->opts, state->domain, +- usr_attrs[0], NULL, 0); ++ usr_attrs[0], NULL, NULL, 0); + } + } + } +diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h +index 2ebde6b83646408e446c91cb324809cb767b2617..6e5800b42ba4a045fa7985b09a80b6b86b8c6055 100644 +--- a/src/providers/ldap/sdap_async.h ++++ b/src/providers/ldap/sdap_async.h +@@ -90,7 +90,8 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx, + const char **attrs, + const char *filter, + int timeout, +- enum sdap_entry_lookup_type lookup_type); ++ enum sdap_entry_lookup_type lookup_type, ++ struct sysdb_attrs *mapped_attrs); + int sdap_get_users_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, char **timestamp); + +diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c +index 387e53155b567ce106cc68009c7cb99e27d24a17..3f65059e18d5c8b548da0babec867d27c3a64198 100644 +--- a/src/providers/ldap/sdap_async_enum.c ++++ b/src/providers/ldap/sdap_async_enum.c +@@ -635,7 +635,7 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx, + state->attrs, state->filter, + dp_opt_get_int(state->ctx->opts->basic, + SDAP_ENUM_SEARCH_TIMEOUT), +- SDAP_LOOKUP_ENUMERATE); ++ SDAP_LOOKUP_ENUMERATE, NULL); + if (!subreq) { + ret = ENOMEM; + goto fail; +diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c +index 8c7a65bf36abf341e077cf9eac18a234d3a07c07..79af7a3eda3fe8533933535c98c2b4b4698dfda2 100644 +--- a/src/providers/ldap/sdap_async_initgroups.c ++++ b/src/providers/ldap/sdap_async_initgroups.c +@@ -2991,7 +2991,7 @@ static void sdap_get_initgr_user(struct tevent_req *subreq) + DEBUG(SSSDBG_TRACE_ALL, "Storing the user\n"); + + ret = sdap_save_user(state, state->opts, state->dom, state->orig_user, +- NULL, 0); ++ NULL, NULL, 0); + if (ret) { + goto fail; + } +diff --git a/src/providers/ldap/sdap_async_private.h b/src/providers/ldap/sdap_async_private.h +index 266bc03115e2bdd6a283f5f7da565fd00d3a77be..72507442a9ffd5c0e24ccbd95d75d3ebf9bf0940 100644 +--- a/src/providers/ldap/sdap_async_private.h ++++ b/src/providers/ldap/sdap_async_private.h +@@ -94,6 +94,7 @@ int sdap_save_users(TALLOC_CTX *memctx, + struct sdap_options *opts, + struct sysdb_attrs **users, + int num_users, ++ struct sysdb_attrs *mapped_attrs, + char **_usn_value); + + int sdap_initgr_common_store(struct sysdb_ctx *sysdb, +diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c +index 87d91d8247c37a4c6a1d83b7189399056528fc90..3d957ab584865f74499bc732395388a78965fe5f 100644 +--- a/src/providers/ldap/sdap_async_users.c ++++ b/src/providers/ldap/sdap_async_users.c +@@ -117,6 +117,7 @@ int sdap_save_user(TALLOC_CTX *memctx, + struct sdap_options *opts, + struct sss_domain_info *dom, + struct sysdb_attrs *attrs, ++ struct sysdb_attrs *mapped_attrs, + char **_usn_value, + time_t now) + { +@@ -511,6 +512,11 @@ int sdap_save_user(TALLOC_CTX *memctx, + user_attrs, missing, cache_timeout, now); + if (ret) goto done; + ++ if (mapped_attrs != NULL) { ++ ret = sysdb_set_user_attr(dom, user_name, mapped_attrs, SYSDB_MOD_ADD); ++ if (ret) return ret; ++ } ++ + if (_usn_value) { + *_usn_value = talloc_steal(memctx, usn_value); + } +@@ -537,6 +543,7 @@ int sdap_save_users(TALLOC_CTX *memctx, + struct sdap_options *opts, + struct sysdb_attrs **users, + int num_users, ++ struct sysdb_attrs *mapped_attrs, + char **_usn_value) + { + TALLOC_CTX *tmpctx; +@@ -565,11 +572,20 @@ int sdap_save_users(TALLOC_CTX *memctx, + } + in_transaction = true; + ++ if (mapped_attrs != NULL) { ++ ret = sysdb_remove_mapped_data(dom, mapped_attrs); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_remove_mapped_data failed, " ++ "some cached entries might contain invalid mapping data.\n"); ++ } ++ } ++ + now = time(NULL); + for (i = 0; i < num_users; i++) { + usn_value = NULL; + +- ret = sdap_save_user(tmpctx, opts, dom, users[i], &usn_value, now); ++ ret = sdap_save_user(tmpctx, opts, dom, users[i], mapped_attrs, ++ &usn_value, now); + + /* Do not fail completely on errors. + * Just report the failure to save and go on */ +@@ -868,6 +884,7 @@ struct sdap_get_users_state { + + char *higher_usn; + struct sysdb_attrs **users; ++ struct sysdb_attrs *mapped_attrs; + size_t count; + }; + +@@ -883,7 +900,8 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx, + const char **attrs, + const char *filter, + int timeout, +- enum sdap_entry_lookup_type lookup_type) ++ enum sdap_entry_lookup_type lookup_type, ++ struct sysdb_attrs *mapped_attrs) + { + errno_t ret; + struct tevent_req *req; +@@ -900,6 +918,23 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx, + state->filter = filter; + PROBE(SDAP_SEARCH_USER_SEND, state->filter); + ++ if (mapped_attrs == NULL) { ++ state->mapped_attrs = NULL; ++ } else { ++ state->mapped_attrs = sysdb_new_attrs(state); ++ if (state->mapped_attrs == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_attrs_copy(mapped_attrs, state->mapped_attrs); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_copy failed.\n"); ++ goto done; ++ } ++ } ++ + subreq = sdap_search_user_send(state, ev, dom, opts, search_bases, + sh, attrs, filter, timeout, lookup_type); + if (subreq == NULL) { +@@ -938,9 +973,11 @@ static void sdap_get_users_done(struct tevent_req *subreq) + } + + PROBE(SDAP_SEARCH_USER_SAVE_BEGIN, state->filter); ++ + ret = sdap_save_users(state, state->sysdb, + state->dom, state->opts, + state->users, state->count, ++ state->mapped_attrs, + &state->higher_usn); + PROBE(SDAP_SEARCH_USER_SAVE_END, state->filter); + if (ret) { +diff --git a/src/providers/ldap/sdap_users.h b/src/providers/ldap/sdap_users.h +index 78dafb31a2a07e7289055daec77c5dc5da1bdeef..a6d088a6d7114db75b0f0ea22ef85c57da6fab0f 100644 +--- a/src/providers/ldap/sdap_users.h ++++ b/src/providers/ldap/sdap_users.h +@@ -34,6 +34,7 @@ int sdap_save_user(TALLOC_CTX *memctx, + struct sdap_options *opts, + struct sss_domain_info *dom, + struct sysdb_attrs *attrs, ++ struct sysdb_attrs *mapped_attrs, + char **_usn_value, + time_t now); + +-- +2.9.3 + diff --git a/SOURCES/0008-LDAP-always-store-the-certificate-from-the-request.patch b/SOURCES/0008-LDAP-always-store-the-certificate-from-the-request.patch new file mode 100644 index 0000000..108254d --- /dev/null +++ b/SOURCES/0008-LDAP-always-store-the-certificate-from-the-request.patch @@ -0,0 +1,178 @@ +From a3cc501e36f5cf1e4a8187d723b53111f5481b36 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 30 Nov 2015 12:14:55 +0100 +Subject: [PATCH 08/15] LDAP: always store the certificate from the request +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Store the certificate used to lookup a user as mapped attribute in the +cached user object. + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +--- + src/db/sysdb.h | 1 + + src/db/sysdb_ops.c | 4 ++-- + src/providers/ldap/ldap_id.c | 19 ++++++++++++++++++- + src/tests/cmocka/test_nss_srv.c | 2 +- + src/tests/cmocka/test_pam_srv.c | 6 +++--- + src/tests/sysdb-tests.c | 4 ++-- + 6 files changed, 27 insertions(+), 9 deletions(-) + +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 098f47f91187aac75c58c02f0af738c344765762..3db22b3689bf6ffd9a48e29c229916e3fac9ca1b 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -139,6 +139,7 @@ + + #define SYSDB_AUTH_TYPE "authType" + #define SYSDB_USER_CERT "userCertificate" ++#define SYSDB_USER_MAPPED_CERT "userMappedCertificate" + #define SYSDB_USER_EMAIL "mail" + + #define SYSDB_SUBDOMAIN_REALM "realmName" +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 6c2254df2b75d3d3419528523103ad9cddb40c9d..8ae25764478e522255b177f9e8de1d3ca1ad43fd 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -4660,7 +4660,7 @@ errno_t sysdb_search_object_by_cert(TALLOC_CTX *mem_ctx, + int ret; + char *user_filter; + +- ret = sss_cert_derb64_to_ldap_filter(mem_ctx, cert, SYSDB_USER_CERT, ++ ret = sss_cert_derb64_to_ldap_filter(mem_ctx, cert, SYSDB_USER_MAPPED_CERT, + &user_filter); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_cert_derb64_to_ldap_filter failed.\n"); +@@ -4749,7 +4749,7 @@ errno_t sysdb_remove_mapped_data(struct sss_domain_info *domain, + errno_t sysdb_remove_cert(struct sss_domain_info *domain, + const char *cert) + { +- struct ldb_message_element el = { 0, SYSDB_USER_CERT, 0, NULL }; ++ struct ldb_message_element el = { 0, SYSDB_USER_MAPPED_CERT, 0, NULL }; + struct sysdb_attrs del_attrs = { 1, &el }; + const char *attrs[] = {SYSDB_NAME, NULL}; + struct ldb_result *res = NULL; +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index 898ddb18689d55fcc3fdf021b38df0e574003eb2..a8b4bc2cfc6e9d4e0d74b0e3e036afbcbf7eb26e 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -60,6 +60,7 @@ struct users_get_state { + int dp_error; + int sdap_ret; + bool noexist_delete; ++ struct sysdb_attrs *extra_attrs; + }; + + static int users_get_retry(struct tevent_req *req); +@@ -99,6 +100,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + state->conn = conn; + state->dp_error = DP_ERR_FATAL; + state->noexist_delete = noexist_delete; ++ state->extra_attrs = NULL; + + state->op = sdap_id_op_create(state, state->conn->conn_cache); + if (!state->op) { +@@ -251,6 +253,21 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + "sss_cert_derb64_to_ldap_filter failed.\n"); + goto done; + } ++ ++ state->extra_attrs = sysdb_new_attrs(state); ++ if (state->extra_attrs == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_attrs_add_base64_blob(state->extra_attrs, ++ SYSDB_USER_MAPPED_CERT, filter_value); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_base64_blob failed.\n"); ++ goto done; ++ } ++ + break; + default: + ret = EINVAL; +@@ -442,7 +459,7 @@ static void users_get_search(struct tevent_req *req) + state->attrs, state->filter, + dp_opt_get_int(state->ctx->opts->basic, + SDAP_SEARCH_TIMEOUT), +- lookup_type, NULL); ++ lookup_type, state->extra_attrs); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; +diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c +index 72bbaf9bf35ebb3fc4208afaa3c7af95922afcb0..76b9c6fb05673130de0957e93291919c263a28f3 100644 +--- a/src/tests/cmocka/test_nss_srv.c ++++ b/src/tests/cmocka/test_nss_srv.c +@@ -3508,7 +3508,7 @@ static void test_nss_getnamebycert(void **state) + der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size); + assert_non_null(der); + +- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); ++ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); + talloc_free(der); + assert_int_equal(ret, EOK); + +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index ae2e555f7024027d1c0063031f8882bf81a31905..847419658bb983e6548722d6fa6fb22c63ee86b8 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -1598,7 +1598,7 @@ static int test_lookup_by_cert_cb(void *pvt) + der = sss_base64_decode(pam_test_ctx, pvt, &der_size); + assert_non_null(der); + +- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); ++ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); + talloc_free(der); + assert_int_equal(ret, EOK); + +@@ -1630,7 +1630,7 @@ static int test_lookup_by_cert_double_cb(void *pvt) + der = sss_base64_decode(pam_test_ctx, pvt, &der_size); + assert_non_null(der); + +- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); ++ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); + talloc_free(der); + assert_int_equal(ret, EOK); + +@@ -1658,7 +1658,7 @@ static int test_lookup_by_cert_wrong_user_cb(void *pvt) + der = sss_base64_decode(pam_test_ctx, pvt, &der_size); + assert_non_null(der); + +- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); ++ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); + talloc_free(der); + assert_int_equal(ret, EOK); + +diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c +index c343c734a27a335303974b6866a5d9e88d4c307e..5bdd631fbfa1b4463fb169e5f07b65fb2c784096 100644 +--- a/src/tests/sysdb-tests.c ++++ b/src/tests/sysdb-tests.c +@@ -5721,7 +5721,7 @@ START_TEST(test_sysdb_search_user_by_cert) + val.data = sss_base64_decode(test_ctx, TEST_USER_CERT_DERB64, &val.length); + fail_unless(val.data != NULL, "sss_base64_decode failed."); + +- ret = sysdb_attrs_add_val(data->attrs, SYSDB_USER_CERT, &val); ++ ret = sysdb_attrs_add_val(data->attrs, SYSDB_USER_MAPPED_CERT, &val); + fail_unless(ret == EOK, "sysdb_attrs_add_val failed with [%d][%s].", + ret, strerror(ret)); + +@@ -5750,7 +5750,7 @@ START_TEST(test_sysdb_search_user_by_cert) + data2 = test_data_new_user(test_ctx, 2345671); + fail_if(data2 == NULL); + +- ret = sysdb_attrs_add_val(data2->attrs, SYSDB_USER_CERT, &val); ++ ret = sysdb_attrs_add_val(data2->attrs, SYSDB_USER_MAPPED_CERT, &val); + fail_unless(ret == EOK, "sysdb_attrs_add_val failed with [%d][%s].", + ret, strerror(ret)); + +-- +2.9.3 + diff --git a/SOURCES/0008-sssctl-Fix-warning-maybe-uninitialized.patch b/SOURCES/0008-sssctl-Fix-warning-maybe-uninitialized.patch deleted file mode 100644 index 77fde17..0000000 --- a/SOURCES/0008-sssctl-Fix-warning-maybe-uninitialized.patch +++ /dev/null @@ -1,63 +0,0 @@ -From e64aac5e33523f8473471b945403f0d9ba74c8cf Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Fri, 8 Jul 2016 15:27:23 +0200 -Subject: [PATCH 08/18] sssctl: Fix warning maybe-uninitialized -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -It looks like some special gcc optimalisation and special case -may cause to have unitialized output argument _dom when return -code is EOK - -src/tools/sssctl/sssctl_cache.c: In function ‘sssctl_print_object’: -src/tools/sssctl/sssctl_cache.c:491:8: error: ‘dom’ may be used - uninitialized in this function [-Werror=maybe-uninitialized] - if (dom == NULL) { - ^ -src/tools/sssctl/sssctl_cache.c:447:15: error: ‘entry’ may be used - uninitialized in this function [-Werror=maybe-uninitialized] - *_entry = talloc_steal(mem_ctx, entry); - ^~~~~~~~~~~~ -src/tools/sssctl/sssctl_cache.c:412:25: note: ‘entry’ was declared here - struct sysdb_attrs *entry; - ^~~~~ - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 64d664c201916d8678b5f4bd7e1559c7ece9217d) ---- - src/tools/sssctl/sssctl_cache.c | 14 +++++++++----- - 1 file changed, 9 insertions(+), 5 deletions(-) - -diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c -index 28de6c139d844f98f9b06844492c935696e19643..e23bb89db95217e66a441b7e4d6d32e668486cc8 100644 ---- a/src/tools/sssctl/sssctl_cache.c -+++ b/src/tools/sssctl/sssctl_cache.c -@@ -372,15 +372,19 @@ static errno_t sssctl_find_object(TALLOC_CTX *mem_ctx, - - ret = sssctl_query_cache(tmp_ctx, dom->sysdb, base_dn, filter, - attrs, &entry); -- if (ret == EOK) { -+ switch(ret) { -+ case EOK: - /* Entry was found. */ - *_entry = talloc_steal(mem_ctx, entry); - *_dom = dom; - goto done; -- } else if (ret == ENOENT && fqn_provided) { -- /* Not found but a domain was provided in input. We're done. */ -- goto done; -- } else if (ret != ENOENT) { -+ case ENOENT: -+ if (fqn_provided) { -+ /* Not found but a domain was provided in input. We're done. */ -+ goto done; -+ } -+ break; -+ default: - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to query cache [%d]: %s\n", - ret, sss_strerror(ret)); - goto done; --- -2.4.11 - diff --git a/SOURCES/0009-NOUPSTREAM-Bundle-http-parser.patch b/SOURCES/0009-NOUPSTREAM-Bundle-http-parser.patch deleted file mode 100644 index a17b34c..0000000 --- a/SOURCES/0009-NOUPSTREAM-Bundle-http-parser.patch +++ /dev/null @@ -1,2922 +0,0 @@ -From bd5daccde22322d216d450f40a50c1a3d7c5a32c Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 12 Jul 2016 13:36:32 +0200 -Subject: [PATCH 09/18] NOUPSTREAM: Bundle http-parser - ---- - Makefile.am | 15 + - src/external/libhttp_parser.m4 | 7 +- - src/responder/secrets/http_parser.c | 2469 ++++++++++++++++++++++++++++++++ - src/responder/secrets/http_parser.h | 362 +++++ - src/responder/secrets/secsrv_private.h | 2 +- - 5 files changed, 2850 insertions(+), 5 deletions(-) - create mode 100644 src/responder/secrets/http_parser.c - create mode 100644 src/responder/secrets/http_parser.h - -diff --git a/Makefile.am b/Makefile.am -index 706b60d6a065e0a983f5a1cfbc26a78331c67d58..d05919705910fa565ff954224ce40feb5d7ff39f 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -1370,6 +1370,9 @@ sssd_secrets_SOURCES = \ - $(SSSD_RESPONDER_OBJ) \ - $(SSSD_RESOLV_OBJ) \ - $(NULL) -+sssd_secrets_CFLAGS = \ -+ $(AM_CFLAGS) \ -+ $(NULL) - sssd_secrets_LDADD = \ - $(HTTP_PARSER_LIBS) \ - $(JANSSON_LIBS) \ -@@ -1379,6 +1382,18 @@ sssd_secrets_LDADD = \ - $(CARES_LIBS) \ - $(SSSD_INTERNAL_LTLIBS) \ - $(NULL) -+ -+if BUNDLE_HTTP_PARSER -+sssd_secrets_CFLAGS += \ -+ -DHTTP_PARSER_STRICT=1 \ -+ $(NULL) -+ -+sssd_secrets_SOURCES += \ -+ src/responder/secrets/http_parser.c \ -+ src/responder/secrets/http_parser.h \ -+ $(NULL) -+endif -+ - endif - - sssd_be_SOURCES = \ -diff --git a/src/external/libhttp_parser.m4 b/src/external/libhttp_parser.m4 -index 504bdf0f66c95b3d224c677a205a46e6f8b44726..c4c5b0dad29da281295529be047d30e502f5de70 100644 ---- a/src/external/libhttp_parser.m4 -+++ b/src/external/libhttp_parser.m4 -@@ -16,7 +16,6 @@ AS_IF([test x"$found_http_parser" != xyes], - [-L$sss_extra_libdir -lhttp_parser]) - ], - [-L$sss_extra_libdir -lhttp_parser_strict])], -- [AC_MSG_ERROR([ --You must have the header file http_parse.h installed to build sssd --with secrets responder. If you want to build sssd without secret responder --then specify --without-secrets when running configure.])])]) -+ [AC_MSG_WARN([Will use bundled http-parser])])]) -+ -+AM_CONDITIONAL([BUNDLE_HTTP_PARSER], [test x"$HTTP_PARSER_LIBS" = x]) -diff --git a/src/responder/secrets/http_parser.c b/src/responder/secrets/http_parser.c -new file mode 100644 -index 0000000000000000000000000000000000000000..3c896ffadcc0dbf13942457d32c77d15bfec33e7 ---- /dev/null -+++ b/src/responder/secrets/http_parser.c -@@ -0,0 +1,2469 @@ -+/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev -+ * -+ * Additional changes are licensed under the same terms as NGINX and -+ * copyright Joyent, Inc. and other Node contributors. All rights reserved. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to -+ * deal in the Software without restriction, including without limitation the -+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -+ * sell copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -+ * IN THE SOFTWARE. -+ */ -+#include "http_parser.h" -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifndef ULLONG_MAX -+# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ -+#endif -+ -+#ifndef MIN -+# define MIN(a,b) ((a) < (b) ? (a) : (b)) -+#endif -+ -+#ifndef ARRAY_SIZE -+# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -+#endif -+ -+#ifndef BIT_AT -+# define BIT_AT(a, i) \ -+ (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ -+ (1 << ((unsigned int) (i) & 7)))) -+#endif -+ -+#ifndef ELEM_AT -+# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) -+#endif -+ -+#define SET_ERRNO(e) \ -+do { \ -+ parser->http_errno = (e); \ -+} while(0) -+ -+#define CURRENT_STATE() p_state -+#define UPDATE_STATE(V) p_state = (enum state) (V); -+#define RETURN(V) \ -+do { \ -+ parser->state = CURRENT_STATE(); \ -+ return (V); \ -+} while (0); -+#define REEXECUTE() \ -+ goto reexecute; \ -+ -+ -+#ifdef __GNUC__ -+# define LIKELY(X) __builtin_expect(!!(X), 1) -+# define UNLIKELY(X) __builtin_expect(!!(X), 0) -+#else -+# define LIKELY(X) (X) -+# define UNLIKELY(X) (X) -+#endif -+ -+ -+/* Run the notify callback FOR, returning ER if it fails */ -+#define CALLBACK_NOTIFY_(FOR, ER) \ -+do { \ -+ assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ -+ \ -+ if (LIKELY(settings->on_##FOR)) { \ -+ parser->state = CURRENT_STATE(); \ -+ if (UNLIKELY(0 != settings->on_##FOR(parser))) { \ -+ SET_ERRNO(HPE_CB_##FOR); \ -+ } \ -+ UPDATE_STATE(parser->state); \ -+ \ -+ /* We either errored above or got paused; get out */ \ -+ if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ -+ return (ER); \ -+ } \ -+ } \ -+} while (0) -+ -+/* Run the notify callback FOR and consume the current byte */ -+#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) -+ -+/* Run the notify callback FOR and don't consume the current byte */ -+#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) -+ -+/* Run data callback FOR with LEN bytes, returning ER if it fails */ -+#define CALLBACK_DATA_(FOR, LEN, ER) \ -+do { \ -+ assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ -+ \ -+ if (FOR##_mark) { \ -+ if (LIKELY(settings->on_##FOR)) { \ -+ parser->state = CURRENT_STATE(); \ -+ if (UNLIKELY(0 != \ -+ settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \ -+ SET_ERRNO(HPE_CB_##FOR); \ -+ } \ -+ UPDATE_STATE(parser->state); \ -+ \ -+ /* We either errored above or got paused; get out */ \ -+ if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ -+ return (ER); \ -+ } \ -+ } \ -+ FOR##_mark = NULL; \ -+ } \ -+} while (0) -+ -+/* Run the data callback FOR and consume the current byte */ -+#define CALLBACK_DATA(FOR) \ -+ CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) -+ -+/* Run the data callback FOR and don't consume the current byte */ -+#define CALLBACK_DATA_NOADVANCE(FOR) \ -+ CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) -+ -+/* Set the mark FOR; non-destructive if mark is already set */ -+#define MARK(FOR) \ -+do { \ -+ if (!FOR##_mark) { \ -+ FOR##_mark = p; \ -+ } \ -+} while (0) -+ -+/* Don't allow the total size of the HTTP headers (including the status -+ * line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect -+ * embedders against denial-of-service attacks where the attacker feeds -+ * us a never-ending header that the embedder keeps buffering. -+ * -+ * This check is arguably the responsibility of embedders but we're doing -+ * it on the embedder's behalf because most won't bother and this way we -+ * make the web a little safer. HTTP_MAX_HEADER_SIZE is still far bigger -+ * than any reasonable request or response so this should never affect -+ * day-to-day operation. -+ */ -+#define COUNT_HEADER_SIZE(V) \ -+do { \ -+ parser->nread += (V); \ -+ if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) { \ -+ SET_ERRNO(HPE_HEADER_OVERFLOW); \ -+ goto error; \ -+ } \ -+} while (0) -+ -+ -+#define PROXY_CONNECTION "proxy-connection" -+#define CONNECTION "connection" -+#define CONTENT_LENGTH "content-length" -+#define TRANSFER_ENCODING "transfer-encoding" -+#define UPGRADE "upgrade" -+#define CHUNKED "chunked" -+#define KEEP_ALIVE "keep-alive" -+#define CLOSE "close" -+ -+ -+static const char *method_strings[] = -+ { -+#define XX(num, name, string) #string, -+ HTTP_METHOD_MAP(XX) -+#undef XX -+ }; -+ -+ -+/* Tokens as defined by rfc 2616. Also lowercases them. -+ * token = 1* -+ * separators = "(" | ")" | "<" | ">" | "@" -+ * | "," | ";" | ":" | "\" | <"> -+ * | "/" | "[" | "]" | "?" | "=" -+ * | "{" | "}" | SP | HT -+ */ -+static const char tokens[256] = { -+/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ -+ 0, 0, 0, 0, 0, 0, 0, 0, -+/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ -+ 0, 0, 0, 0, 0, 0, 0, 0, -+/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ -+ 0, 0, 0, 0, 0, 0, 0, 0, -+/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ -+ 0, 0, 0, 0, 0, 0, 0, 0, -+/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ -+ 0, '!', 0, '#', '$', '%', '&', '\'', -+/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ -+ 0, 0, '*', '+', 0, '-', '.', 0, -+/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ -+ '0', '1', '2', '3', '4', '5', '6', '7', -+/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ -+ '8', '9', 0, 0, 0, 0, 0, 0, -+/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ -+ 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', -+/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ -+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -+/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ -+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -+/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ -+ 'x', 'y', 'z', 0, 0, 0, '^', '_', -+/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ -+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', -+/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ -+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -+/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ -+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -+/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ -+ 'x', 'y', 'z', 0, '|', 0, '~', 0 }; -+ -+ -+static const int8_t unhex[256] = -+ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+ , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 -+ ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+ ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+ ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+ }; -+ -+ -+#if HTTP_PARSER_STRICT -+# define T(v) 0 -+#else -+# define T(v) v -+#endif -+ -+ -+static const uint8_t normal_url_char[32] = { -+/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ -+ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -+/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ -+ 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, -+/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ -+ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -+/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ -+ 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -+/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ -+ 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, -+/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ -+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -+/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ -+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -+/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ -+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, -+/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ -+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -+/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ -+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -+/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ -+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -+/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ -+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -+/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ -+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -+/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ -+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -+/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ -+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -+/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ -+ 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; -+ -+#undef T -+ -+enum state -+ { s_dead = 1 /* important that this is > 0 */ -+ -+ , s_start_req_or_res -+ , s_res_or_resp_H -+ , s_start_res -+ , s_res_H -+ , s_res_HT -+ , s_res_HTT -+ , s_res_HTTP -+ , s_res_first_http_major -+ , s_res_http_major -+ , s_res_first_http_minor -+ , s_res_http_minor -+ , s_res_first_status_code -+ , s_res_status_code -+ , s_res_status_start -+ , s_res_status -+ , s_res_line_almost_done -+ -+ , s_start_req -+ -+ , s_req_method -+ , s_req_spaces_before_url -+ , s_req_schema -+ , s_req_schema_slash -+ , s_req_schema_slash_slash -+ , s_req_server_start -+ , s_req_server -+ , s_req_server_with_at -+ , s_req_path -+ , s_req_query_string_start -+ , s_req_query_string -+ , s_req_fragment_start -+ , s_req_fragment -+ , s_req_http_start -+ , s_req_http_H -+ , s_req_http_HT -+ , s_req_http_HTT -+ , s_req_http_HTTP -+ , s_req_first_http_major -+ , s_req_http_major -+ , s_req_first_http_minor -+ , s_req_http_minor -+ , s_req_line_almost_done -+ -+ , s_header_field_start -+ , s_header_field -+ , s_header_value_discard_ws -+ , s_header_value_discard_ws_almost_done -+ , s_header_value_discard_lws -+ , s_header_value_start -+ , s_header_value -+ , s_header_value_lws -+ -+ , s_header_almost_done -+ -+ , s_chunk_size_start -+ , s_chunk_size -+ , s_chunk_parameters -+ , s_chunk_size_almost_done -+ -+ , s_headers_almost_done -+ , s_headers_done -+ -+ /* Important: 's_headers_done' must be the last 'header' state. All -+ * states beyond this must be 'body' states. It is used for overflow -+ * checking. See the PARSING_HEADER() macro. -+ */ -+ -+ , s_chunk_data -+ , s_chunk_data_almost_done -+ , s_chunk_data_done -+ -+ , s_body_identity -+ , s_body_identity_eof -+ -+ , s_message_done -+ }; -+ -+ -+#define PARSING_HEADER(state) (state <= s_headers_done) -+ -+ -+enum header_states -+ { h_general = 0 -+ , h_C -+ , h_CO -+ , h_CON -+ -+ , h_matching_connection -+ , h_matching_proxy_connection -+ , h_matching_content_length -+ , h_matching_transfer_encoding -+ , h_matching_upgrade -+ -+ , h_connection -+ , h_content_length -+ , h_transfer_encoding -+ , h_upgrade -+ -+ , h_matching_transfer_encoding_chunked -+ , h_matching_connection_token_start -+ , h_matching_connection_keep_alive -+ , h_matching_connection_close -+ , h_matching_connection_upgrade -+ , h_matching_connection_token -+ -+ , h_transfer_encoding_chunked -+ , h_connection_keep_alive -+ , h_connection_close -+ , h_connection_upgrade -+ }; -+ -+enum http_host_state -+ { -+ s_http_host_dead = 1 -+ , s_http_userinfo_start -+ , s_http_userinfo -+ , s_http_host_start -+ , s_http_host_v6_start -+ , s_http_host -+ , s_http_host_v6 -+ , s_http_host_v6_end -+ , s_http_host_v6_zone_start -+ , s_http_host_v6_zone -+ , s_http_host_port_start -+ , s_http_host_port -+}; -+ -+/* Macros for character classes; depends on strict-mode */ -+#define CR '\r' -+#define LF '\n' -+#define LOWER(c) (unsigned char)(c | 0x20) -+#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') -+#define IS_NUM(c) ((c) >= '0' && (c) <= '9') -+#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) -+#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) -+#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ -+ (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ -+ (c) == ')') -+#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ -+ (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ -+ (c) == '$' || (c) == ',') -+ -+#define STRICT_TOKEN(c) (tokens[(unsigned char)c]) -+ -+#if HTTP_PARSER_STRICT -+#define TOKEN(c) (tokens[(unsigned char)c]) -+#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) -+#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') -+#else -+#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) -+#define IS_URL_CHAR(c) \ -+ (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) -+#define IS_HOST_CHAR(c) \ -+ (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') -+#endif -+ -+/** -+ * Verify that a char is a valid visible (printable) US-ASCII -+ * character or %x80-FF -+ **/ -+#define IS_HEADER_CHAR(ch) \ -+ (ch == CR || ch == LF || ch == 9 || ((unsigned char)ch > 31 && ch != 127)) -+ -+#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) -+ -+ -+#if HTTP_PARSER_STRICT -+# define STRICT_CHECK(cond) \ -+do { \ -+ if (cond) { \ -+ SET_ERRNO(HPE_STRICT); \ -+ goto error; \ -+ } \ -+} while (0) -+# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) -+#else -+# define STRICT_CHECK(cond) -+# define NEW_MESSAGE() start_state -+#endif -+ -+ -+/* Map errno values to strings for human-readable output */ -+#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, -+static struct { -+ const char *name; -+ const char *description; -+} http_strerror_tab[] = { -+ HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) -+}; -+#undef HTTP_STRERROR_GEN -+ -+int http_message_needs_eof(const http_parser *parser); -+ -+/* Our URL parser. -+ * -+ * This is designed to be shared by http_parser_execute() for URL validation, -+ * hence it has a state transition + byte-for-byte interface. In addition, it -+ * is meant to be embedded in http_parser_parse_url(), which does the dirty -+ * work of turning state transitions URL components for its API. -+ * -+ * This function should only be invoked with non-space characters. It is -+ * assumed that the caller cares about (and can detect) the transition between -+ * URL and non-URL states by looking for these. -+ */ -+static enum state -+parse_url_char(enum state s, const char ch) -+{ -+ if (ch == ' ' || ch == '\r' || ch == '\n') { -+ return s_dead; -+ } -+ -+#if HTTP_PARSER_STRICT -+ if (ch == '\t' || ch == '\f') { -+ return s_dead; -+ } -+#endif -+ -+ switch (s) { -+ case s_req_spaces_before_url: -+ /* Proxied requests are followed by scheme of an absolute URI (alpha). -+ * All methods except CONNECT are followed by '/' or '*'. -+ */ -+ -+ if (ch == '/' || ch == '*') { -+ return s_req_path; -+ } -+ -+ if (IS_ALPHA(ch)) { -+ return s_req_schema; -+ } -+ -+ break; -+ -+ case s_req_schema: -+ if (IS_ALPHA(ch)) { -+ return s; -+ } -+ -+ if (ch == ':') { -+ return s_req_schema_slash; -+ } -+ -+ break; -+ -+ case s_req_schema_slash: -+ if (ch == '/') { -+ return s_req_schema_slash_slash; -+ } -+ -+ break; -+ -+ case s_req_schema_slash_slash: -+ if (ch == '/') { -+ return s_req_server_start; -+ } -+ -+ break; -+ -+ case s_req_server_with_at: -+ if (ch == '@') { -+ return s_dead; -+ } -+ -+ /* FALLTHROUGH */ -+ case s_req_server_start: -+ case s_req_server: -+ if (ch == '/') { -+ return s_req_path; -+ } -+ -+ if (ch == '?') { -+ return s_req_query_string_start; -+ } -+ -+ if (ch == '@') { -+ return s_req_server_with_at; -+ } -+ -+ if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { -+ return s_req_server; -+ } -+ -+ break; -+ -+ case s_req_path: -+ if (IS_URL_CHAR(ch)) { -+ return s; -+ } -+ -+ switch (ch) { -+ case '?': -+ return s_req_query_string_start; -+ -+ case '#': -+ return s_req_fragment_start; -+ } -+ -+ break; -+ -+ case s_req_query_string_start: -+ case s_req_query_string: -+ if (IS_URL_CHAR(ch)) { -+ return s_req_query_string; -+ } -+ -+ switch (ch) { -+ case '?': -+ /* allow extra '?' in query string */ -+ return s_req_query_string; -+ -+ case '#': -+ return s_req_fragment_start; -+ } -+ -+ break; -+ -+ case s_req_fragment_start: -+ if (IS_URL_CHAR(ch)) { -+ return s_req_fragment; -+ } -+ -+ switch (ch) { -+ case '?': -+ return s_req_fragment; -+ -+ case '#': -+ return s; -+ } -+ -+ break; -+ -+ case s_req_fragment: -+ if (IS_URL_CHAR(ch)) { -+ return s; -+ } -+ -+ switch (ch) { -+ case '?': -+ case '#': -+ return s; -+ } -+ -+ break; -+ -+ default: -+ break; -+ } -+ -+ /* We should never fall out of the switch above unless there's an error */ -+ return s_dead; -+} -+ -+size_t http_parser_execute (http_parser *parser, -+ const http_parser_settings *settings, -+ const char *data, -+ size_t len) -+{ -+ char c, ch; -+ int8_t unhex_val; -+ const char *p = data; -+ const char *header_field_mark = 0; -+ const char *header_value_mark = 0; -+ const char *url_mark = 0; -+ const char *body_mark = 0; -+ const char *status_mark = 0; -+ enum state p_state = (enum state) parser->state; -+ const unsigned int lenient = parser->lenient_http_headers; -+ -+ /* We're in an error state. Don't bother doing anything. */ -+ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { -+ return 0; -+ } -+ -+ if (len == 0) { -+ switch (CURRENT_STATE()) { -+ case s_body_identity_eof: -+ /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if -+ * we got paused. -+ */ -+ CALLBACK_NOTIFY_NOADVANCE(message_complete); -+ return 0; -+ -+ case s_dead: -+ case s_start_req_or_res: -+ case s_start_res: -+ case s_start_req: -+ return 0; -+ -+ default: -+ SET_ERRNO(HPE_INVALID_EOF_STATE); -+ return 1; -+ } -+ } -+ -+ -+ if (CURRENT_STATE() == s_header_field) -+ header_field_mark = data; -+ if (CURRENT_STATE() == s_header_value) -+ header_value_mark = data; -+ switch (CURRENT_STATE()) { -+ case s_req_path: -+ case s_req_schema: -+ case s_req_schema_slash: -+ case s_req_schema_slash_slash: -+ case s_req_server_start: -+ case s_req_server: -+ case s_req_server_with_at: -+ case s_req_query_string_start: -+ case s_req_query_string: -+ case s_req_fragment_start: -+ case s_req_fragment: -+ url_mark = data; -+ break; -+ case s_res_status: -+ status_mark = data; -+ break; -+ default: -+ break; -+ } -+ -+ for (p=data; p != data + len; p++) { -+ ch = *p; -+ -+ if (PARSING_HEADER(CURRENT_STATE())) -+ COUNT_HEADER_SIZE(1); -+ -+reexecute: -+ switch (CURRENT_STATE()) { -+ -+ case s_dead: -+ /* this state is used after a 'Connection: close' message -+ * the parser will error out if it reads another message -+ */ -+ if (LIKELY(ch == CR || ch == LF)) -+ break; -+ -+ SET_ERRNO(HPE_CLOSED_CONNECTION); -+ goto error; -+ -+ case s_start_req_or_res: -+ { -+ if (ch == CR || ch == LF) -+ break; -+ parser->flags = 0; -+ parser->content_length = ULLONG_MAX; -+ -+ if (ch == 'H') { -+ UPDATE_STATE(s_res_or_resp_H); -+ -+ CALLBACK_NOTIFY(message_begin); -+ } else { -+ parser->type = HTTP_REQUEST; -+ UPDATE_STATE(s_start_req); -+ REEXECUTE(); -+ } -+ -+ break; -+ } -+ -+ case s_res_or_resp_H: -+ if (ch == 'T') { -+ parser->type = HTTP_RESPONSE; -+ UPDATE_STATE(s_res_HT); -+ } else { -+ if (UNLIKELY(ch != 'E')) { -+ SET_ERRNO(HPE_INVALID_CONSTANT); -+ goto error; -+ } -+ -+ parser->type = HTTP_REQUEST; -+ parser->method = HTTP_HEAD; -+ parser->index = 2; -+ UPDATE_STATE(s_req_method); -+ } -+ break; -+ -+ case s_start_res: -+ { -+ parser->flags = 0; -+ parser->content_length = ULLONG_MAX; -+ -+ switch (ch) { -+ case 'H': -+ UPDATE_STATE(s_res_H); -+ break; -+ -+ case CR: -+ case LF: -+ break; -+ -+ default: -+ SET_ERRNO(HPE_INVALID_CONSTANT); -+ goto error; -+ } -+ -+ CALLBACK_NOTIFY(message_begin); -+ break; -+ } -+ -+ case s_res_H: -+ STRICT_CHECK(ch != 'T'); -+ UPDATE_STATE(s_res_HT); -+ break; -+ -+ case s_res_HT: -+ STRICT_CHECK(ch != 'T'); -+ UPDATE_STATE(s_res_HTT); -+ break; -+ -+ case s_res_HTT: -+ STRICT_CHECK(ch != 'P'); -+ UPDATE_STATE(s_res_HTTP); -+ break; -+ -+ case s_res_HTTP: -+ STRICT_CHECK(ch != '/'); -+ UPDATE_STATE(s_res_first_http_major); -+ break; -+ -+ case s_res_first_http_major: -+ if (UNLIKELY(ch < '0' || ch > '9')) { -+ SET_ERRNO(HPE_INVALID_VERSION); -+ goto error; -+ } -+ -+ parser->http_major = ch - '0'; -+ UPDATE_STATE(s_res_http_major); -+ break; -+ -+ /* major HTTP version or dot */ -+ case s_res_http_major: -+ { -+ if (ch == '.') { -+ UPDATE_STATE(s_res_first_http_minor); -+ break; -+ } -+ -+ if (!IS_NUM(ch)) { -+ SET_ERRNO(HPE_INVALID_VERSION); -+ goto error; -+ } -+ -+ parser->http_major *= 10; -+ parser->http_major += ch - '0'; -+ -+ if (UNLIKELY(parser->http_major > 999)) { -+ SET_ERRNO(HPE_INVALID_VERSION); -+ goto error; -+ } -+ -+ break; -+ } -+ -+ /* first digit of minor HTTP version */ -+ case s_res_first_http_minor: -+ if (UNLIKELY(!IS_NUM(ch))) { -+ SET_ERRNO(HPE_INVALID_VERSION); -+ goto error; -+ } -+ -+ parser->http_minor = ch - '0'; -+ UPDATE_STATE(s_res_http_minor); -+ break; -+ -+ /* minor HTTP version or end of request line */ -+ case s_res_http_minor: -+ { -+ if (ch == ' ') { -+ UPDATE_STATE(s_res_first_status_code); -+ break; -+ } -+ -+ if (UNLIKELY(!IS_NUM(ch))) { -+ SET_ERRNO(HPE_INVALID_VERSION); -+ goto error; -+ } -+ -+ parser->http_minor *= 10; -+ parser->http_minor += ch - '0'; -+ -+ if (UNLIKELY(parser->http_minor > 999)) { -+ SET_ERRNO(HPE_INVALID_VERSION); -+ goto error; -+ } -+ -+ break; -+ } -+ -+ case s_res_first_status_code: -+ { -+ if (!IS_NUM(ch)) { -+ if (ch == ' ') { -+ break; -+ } -+ -+ SET_ERRNO(HPE_INVALID_STATUS); -+ goto error; -+ } -+ parser->status_code = ch - '0'; -+ UPDATE_STATE(s_res_status_code); -+ break; -+ } -+ -+ case s_res_status_code: -+ { -+ if (!IS_NUM(ch)) { -+ switch (ch) { -+ case ' ': -+ UPDATE_STATE(s_res_status_start); -+ break; -+ case CR: -+ UPDATE_STATE(s_res_line_almost_done); -+ break; -+ case LF: -+ UPDATE_STATE(s_header_field_start); -+ break; -+ default: -+ SET_ERRNO(HPE_INVALID_STATUS); -+ goto error; -+ } -+ break; -+ } -+ -+ parser->status_code *= 10; -+ parser->status_code += ch - '0'; -+ -+ if (UNLIKELY(parser->status_code > 999)) { -+ SET_ERRNO(HPE_INVALID_STATUS); -+ goto error; -+ } -+ -+ break; -+ } -+ -+ case s_res_status_start: -+ { -+ if (ch == CR) { -+ UPDATE_STATE(s_res_line_almost_done); -+ break; -+ } -+ -+ if (ch == LF) { -+ UPDATE_STATE(s_header_field_start); -+ break; -+ } -+ -+ MARK(status); -+ UPDATE_STATE(s_res_status); -+ parser->index = 0; -+ break; -+ } -+ -+ case s_res_status: -+ if (ch == CR) { -+ UPDATE_STATE(s_res_line_almost_done); -+ CALLBACK_DATA(status); -+ break; -+ } -+ -+ if (ch == LF) { -+ UPDATE_STATE(s_header_field_start); -+ CALLBACK_DATA(status); -+ break; -+ } -+ -+ break; -+ -+ case s_res_line_almost_done: -+ STRICT_CHECK(ch != LF); -+ UPDATE_STATE(s_header_field_start); -+ break; -+ -+ case s_start_req: -+ { -+ if (ch == CR || ch == LF) -+ break; -+ parser->flags = 0; -+ parser->content_length = ULLONG_MAX; -+ -+ if (UNLIKELY(!IS_ALPHA(ch))) { -+ SET_ERRNO(HPE_INVALID_METHOD); -+ goto error; -+ } -+ -+ parser->method = (enum http_method) 0; -+ parser->index = 1; -+ switch (ch) { -+ case 'A': parser->method = HTTP_ACL; break; -+ case 'B': parser->method = HTTP_BIND; break; -+ case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; -+ case 'D': parser->method = HTTP_DELETE; break; -+ case 'G': parser->method = HTTP_GET; break; -+ case 'H': parser->method = HTTP_HEAD; break; -+ case 'L': parser->method = HTTP_LOCK; /* or LINK */ break; -+ case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break; -+ case 'N': parser->method = HTTP_NOTIFY; break; -+ case 'O': parser->method = HTTP_OPTIONS; break; -+ case 'P': parser->method = HTTP_POST; -+ /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ -+ break; -+ case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break; -+ case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; -+ case 'T': parser->method = HTTP_TRACE; break; -+ case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break; -+ default: -+ SET_ERRNO(HPE_INVALID_METHOD); -+ goto error; -+ } -+ UPDATE_STATE(s_req_method); -+ -+ CALLBACK_NOTIFY(message_begin); -+ -+ break; -+ } -+ -+ case s_req_method: -+ { -+ const char *matcher; -+ if (UNLIKELY(ch == '\0')) { -+ SET_ERRNO(HPE_INVALID_METHOD); -+ goto error; -+ } -+ -+ matcher = method_strings[parser->method]; -+ if (ch == ' ' && matcher[parser->index] == '\0') { -+ UPDATE_STATE(s_req_spaces_before_url); -+ } else if (ch == matcher[parser->index]) { -+ ; /* nada */ -+ } else if (IS_ALPHA(ch)) { -+ -+ switch (parser->method << 16 | parser->index << 8 | ch) { -+#define XX(meth, pos, ch, new_meth) \ -+ case (HTTP_##meth << 16 | pos << 8 | ch): \ -+ parser->method = HTTP_##new_meth; break; -+ -+ XX(POST, 1, 'U', PUT) -+ XX(POST, 1, 'A', PATCH) -+ XX(CONNECT, 1, 'H', CHECKOUT) -+ XX(CONNECT, 2, 'P', COPY) -+ XX(MKCOL, 1, 'O', MOVE) -+ XX(MKCOL, 1, 'E', MERGE) -+ XX(MKCOL, 2, 'A', MKACTIVITY) -+ XX(MKCOL, 3, 'A', MKCALENDAR) -+ XX(SUBSCRIBE, 1, 'E', SEARCH) -+ XX(REPORT, 2, 'B', REBIND) -+ XX(POST, 1, 'R', PROPFIND) -+ XX(PROPFIND, 4, 'P', PROPPATCH) -+ XX(PUT, 2, 'R', PURGE) -+ XX(LOCK, 1, 'I', LINK) -+ XX(UNLOCK, 2, 'S', UNSUBSCRIBE) -+ XX(UNLOCK, 2, 'B', UNBIND) -+ XX(UNLOCK, 3, 'I', UNLINK) -+#undef XX -+ -+ default: -+ SET_ERRNO(HPE_INVALID_METHOD); -+ goto error; -+ } -+ } else if (ch == '-' && -+ parser->index == 1 && -+ parser->method == HTTP_MKCOL) { -+ parser->method = HTTP_MSEARCH; -+ } else { -+ SET_ERRNO(HPE_INVALID_METHOD); -+ goto error; -+ } -+ -+ ++parser->index; -+ break; -+ } -+ -+ case s_req_spaces_before_url: -+ { -+ if (ch == ' ') break; -+ -+ MARK(url); -+ if (parser->method == HTTP_CONNECT) { -+ UPDATE_STATE(s_req_server_start); -+ } -+ -+ UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); -+ if (UNLIKELY(CURRENT_STATE() == s_dead)) { -+ SET_ERRNO(HPE_INVALID_URL); -+ goto error; -+ } -+ -+ break; -+ } -+ -+ case s_req_schema: -+ case s_req_schema_slash: -+ case s_req_schema_slash_slash: -+ case s_req_server_start: -+ { -+ switch (ch) { -+ /* No whitespace allowed here */ -+ case ' ': -+ case CR: -+ case LF: -+ SET_ERRNO(HPE_INVALID_URL); -+ goto error; -+ default: -+ UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); -+ if (UNLIKELY(CURRENT_STATE() == s_dead)) { -+ SET_ERRNO(HPE_INVALID_URL); -+ goto error; -+ } -+ } -+ -+ break; -+ } -+ -+ case s_req_server: -+ case s_req_server_with_at: -+ case s_req_path: -+ case s_req_query_string_start: -+ case s_req_query_string: -+ case s_req_fragment_start: -+ case s_req_fragment: -+ { -+ switch (ch) { -+ case ' ': -+ UPDATE_STATE(s_req_http_start); -+ CALLBACK_DATA(url); -+ break; -+ case CR: -+ case LF: -+ parser->http_major = 0; -+ parser->http_minor = 9; -+ UPDATE_STATE((ch == CR) ? -+ s_req_line_almost_done : -+ s_header_field_start); -+ CALLBACK_DATA(url); -+ break; -+ default: -+ UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); -+ if (UNLIKELY(CURRENT_STATE() == s_dead)) { -+ SET_ERRNO(HPE_INVALID_URL); -+ goto error; -+ } -+ } -+ break; -+ } -+ -+ case s_req_http_start: -+ switch (ch) { -+ case 'H': -+ UPDATE_STATE(s_req_http_H); -+ break; -+ case ' ': -+ break; -+ default: -+ SET_ERRNO(HPE_INVALID_CONSTANT); -+ goto error; -+ } -+ break; -+ -+ case s_req_http_H: -+ STRICT_CHECK(ch != 'T'); -+ UPDATE_STATE(s_req_http_HT); -+ break; -+ -+ case s_req_http_HT: -+ STRICT_CHECK(ch != 'T'); -+ UPDATE_STATE(s_req_http_HTT); -+ break; -+ -+ case s_req_http_HTT: -+ STRICT_CHECK(ch != 'P'); -+ UPDATE_STATE(s_req_http_HTTP); -+ break; -+ -+ case s_req_http_HTTP: -+ STRICT_CHECK(ch != '/'); -+ UPDATE_STATE(s_req_first_http_major); -+ break; -+ -+ /* first digit of major HTTP version */ -+ case s_req_first_http_major: -+ if (UNLIKELY(ch < '1' || ch > '9')) { -+ SET_ERRNO(HPE_INVALID_VERSION); -+ goto error; -+ } -+ -+ parser->http_major = ch - '0'; -+ UPDATE_STATE(s_req_http_major); -+ break; -+ -+ /* major HTTP version or dot */ -+ case s_req_http_major: -+ { -+ if (ch == '.') { -+ UPDATE_STATE(s_req_first_http_minor); -+ break; -+ } -+ -+ if (UNLIKELY(!IS_NUM(ch))) { -+ SET_ERRNO(HPE_INVALID_VERSION); -+ goto error; -+ } -+ -+ parser->http_major *= 10; -+ parser->http_major += ch - '0'; -+ -+ if (UNLIKELY(parser->http_major > 999)) { -+ SET_ERRNO(HPE_INVALID_VERSION); -+ goto error; -+ } -+ -+ break; -+ } -+ -+ /* first digit of minor HTTP version */ -+ case s_req_first_http_minor: -+ if (UNLIKELY(!IS_NUM(ch))) { -+ SET_ERRNO(HPE_INVALID_VERSION); -+ goto error; -+ } -+ -+ parser->http_minor = ch - '0'; -+ UPDATE_STATE(s_req_http_minor); -+ break; -+ -+ /* minor HTTP version or end of request line */ -+ case s_req_http_minor: -+ { -+ if (ch == CR) { -+ UPDATE_STATE(s_req_line_almost_done); -+ break; -+ } -+ -+ if (ch == LF) { -+ UPDATE_STATE(s_header_field_start); -+ break; -+ } -+ -+ /* XXX allow spaces after digit? */ -+ -+ if (UNLIKELY(!IS_NUM(ch))) { -+ SET_ERRNO(HPE_INVALID_VERSION); -+ goto error; -+ } -+ -+ parser->http_minor *= 10; -+ parser->http_minor += ch - '0'; -+ -+ if (UNLIKELY(parser->http_minor > 999)) { -+ SET_ERRNO(HPE_INVALID_VERSION); -+ goto error; -+ } -+ -+ break; -+ } -+ -+ /* end of request line */ -+ case s_req_line_almost_done: -+ { -+ if (UNLIKELY(ch != LF)) { -+ SET_ERRNO(HPE_LF_EXPECTED); -+ goto error; -+ } -+ -+ UPDATE_STATE(s_header_field_start); -+ break; -+ } -+ -+ case s_header_field_start: -+ { -+ if (ch == CR) { -+ UPDATE_STATE(s_headers_almost_done); -+ break; -+ } -+ -+ if (ch == LF) { -+ /* they might be just sending \n instead of \r\n so this would be -+ * the second \n to denote the end of headers*/ -+ UPDATE_STATE(s_headers_almost_done); -+ REEXECUTE(); -+ } -+ -+ c = TOKEN(ch); -+ -+ if (UNLIKELY(!c)) { -+ SET_ERRNO(HPE_INVALID_HEADER_TOKEN); -+ goto error; -+ } -+ -+ MARK(header_field); -+ -+ parser->index = 0; -+ UPDATE_STATE(s_header_field); -+ -+ switch (c) { -+ case 'c': -+ parser->header_state = h_C; -+ break; -+ -+ case 'p': -+ parser->header_state = h_matching_proxy_connection; -+ break; -+ -+ case 't': -+ parser->header_state = h_matching_transfer_encoding; -+ break; -+ -+ case 'u': -+ parser->header_state = h_matching_upgrade; -+ break; -+ -+ default: -+ parser->header_state = h_general; -+ break; -+ } -+ break; -+ } -+ -+ case s_header_field: -+ { -+ const char* start = p; -+ for (; p != data + len; p++) { -+ ch = *p; -+ c = TOKEN(ch); -+ -+ if (!c) -+ break; -+ -+ switch (parser->header_state) { -+ case h_general: -+ break; -+ -+ case h_C: -+ parser->index++; -+ parser->header_state = (c == 'o' ? h_CO : h_general); -+ break; -+ -+ case h_CO: -+ parser->index++; -+ parser->header_state = (c == 'n' ? h_CON : h_general); -+ break; -+ -+ case h_CON: -+ parser->index++; -+ switch (c) { -+ case 'n': -+ parser->header_state = h_matching_connection; -+ break; -+ case 't': -+ parser->header_state = h_matching_content_length; -+ break; -+ default: -+ parser->header_state = h_general; -+ break; -+ } -+ break; -+ -+ /* connection */ -+ -+ case h_matching_connection: -+ parser->index++; -+ if (parser->index > sizeof(CONNECTION)-1 -+ || c != CONNECTION[parser->index]) { -+ parser->header_state = h_general; -+ } else if (parser->index == sizeof(CONNECTION)-2) { -+ parser->header_state = h_connection; -+ } -+ break; -+ -+ /* proxy-connection */ -+ -+ case h_matching_proxy_connection: -+ parser->index++; -+ if (parser->index > sizeof(PROXY_CONNECTION)-1 -+ || c != PROXY_CONNECTION[parser->index]) { -+ parser->header_state = h_general; -+ } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { -+ parser->header_state = h_connection; -+ } -+ break; -+ -+ /* content-length */ -+ -+ case h_matching_content_length: -+ parser->index++; -+ if (parser->index > sizeof(CONTENT_LENGTH)-1 -+ || c != CONTENT_LENGTH[parser->index]) { -+ parser->header_state = h_general; -+ } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { -+ if (parser->flags & F_CONTENTLENGTH) { -+ SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); -+ goto error; -+ } -+ parser->header_state = h_content_length; -+ parser->flags |= F_CONTENTLENGTH; -+ } -+ break; -+ -+ /* transfer-encoding */ -+ -+ case h_matching_transfer_encoding: -+ parser->index++; -+ if (parser->index > sizeof(TRANSFER_ENCODING)-1 -+ || c != TRANSFER_ENCODING[parser->index]) { -+ parser->header_state = h_general; -+ } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { -+ parser->header_state = h_transfer_encoding; -+ } -+ break; -+ -+ /* upgrade */ -+ -+ case h_matching_upgrade: -+ parser->index++; -+ if (parser->index > sizeof(UPGRADE)-1 -+ || c != UPGRADE[parser->index]) { -+ parser->header_state = h_general; -+ } else if (parser->index == sizeof(UPGRADE)-2) { -+ parser->header_state = h_upgrade; -+ } -+ break; -+ -+ case h_connection: -+ case h_content_length: -+ case h_transfer_encoding: -+ case h_upgrade: -+ if (ch != ' ') parser->header_state = h_general; -+ break; -+ -+ default: -+ assert(0 && "Unknown header_state"); -+ break; -+ } -+ } -+ -+ COUNT_HEADER_SIZE(p - start); -+ -+ if (p == data + len) { -+ --p; -+ break; -+ } -+ -+ if (ch == ':') { -+ UPDATE_STATE(s_header_value_discard_ws); -+ CALLBACK_DATA(header_field); -+ break; -+ } -+ -+ SET_ERRNO(HPE_INVALID_HEADER_TOKEN); -+ goto error; -+ } -+ -+ case s_header_value_discard_ws: -+ if (ch == ' ' || ch == '\t') break; -+ -+ if (ch == CR) { -+ UPDATE_STATE(s_header_value_discard_ws_almost_done); -+ break; -+ } -+ -+ if (ch == LF) { -+ UPDATE_STATE(s_header_value_discard_lws); -+ break; -+ } -+ -+ /* FALLTHROUGH */ -+ -+ case s_header_value_start: -+ { -+ MARK(header_value); -+ -+ UPDATE_STATE(s_header_value); -+ parser->index = 0; -+ -+ c = LOWER(ch); -+ -+ switch (parser->header_state) { -+ case h_upgrade: -+ parser->flags |= F_UPGRADE; -+ parser->header_state = h_general; -+ break; -+ -+ case h_transfer_encoding: -+ /* looking for 'Transfer-Encoding: chunked' */ -+ if ('c' == c) { -+ parser->header_state = h_matching_transfer_encoding_chunked; -+ } else { -+ parser->header_state = h_general; -+ } -+ break; -+ -+ case h_content_length: -+ if (UNLIKELY(!IS_NUM(ch))) { -+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); -+ goto error; -+ } -+ -+ parser->content_length = ch - '0'; -+ break; -+ -+ case h_connection: -+ /* looking for 'Connection: keep-alive' */ -+ if (c == 'k') { -+ parser->header_state = h_matching_connection_keep_alive; -+ /* looking for 'Connection: close' */ -+ } else if (c == 'c') { -+ parser->header_state = h_matching_connection_close; -+ } else if (c == 'u') { -+ parser->header_state = h_matching_connection_upgrade; -+ } else { -+ parser->header_state = h_matching_connection_token; -+ } -+ break; -+ -+ /* Multi-value `Connection` header */ -+ case h_matching_connection_token_start: -+ break; -+ -+ default: -+ parser->header_state = h_general; -+ break; -+ } -+ break; -+ } -+ -+ case s_header_value: -+ { -+ const char* start = p; -+ enum header_states h_state = (enum header_states) parser->header_state; -+ for (; p != data + len; p++) { -+ ch = *p; -+ if (ch == CR) { -+ UPDATE_STATE(s_header_almost_done); -+ parser->header_state = h_state; -+ CALLBACK_DATA(header_value); -+ break; -+ } -+ -+ if (ch == LF) { -+ UPDATE_STATE(s_header_almost_done); -+ COUNT_HEADER_SIZE(p - start); -+ parser->header_state = h_state; -+ CALLBACK_DATA_NOADVANCE(header_value); -+ REEXECUTE(); -+ } -+ -+ if (!lenient && !IS_HEADER_CHAR(ch)) { -+ SET_ERRNO(HPE_INVALID_HEADER_TOKEN); -+ goto error; -+ } -+ -+ c = LOWER(ch); -+ -+ switch (h_state) { -+ case h_general: -+ { -+ const char* p_cr; -+ const char* p_lf; -+ size_t limit = data + len - p; -+ -+ limit = MIN(limit, HTTP_MAX_HEADER_SIZE); -+ -+ p_cr = (const char*) memchr(p, CR, limit); -+ p_lf = (const char*) memchr(p, LF, limit); -+ if (p_cr != NULL) { -+ if (p_lf != NULL && p_cr >= p_lf) -+ p = p_lf; -+ else -+ p = p_cr; -+ } else if (UNLIKELY(p_lf != NULL)) { -+ p = p_lf; -+ } else { -+ p = data + len; -+ } -+ --p; -+ -+ break; -+ } -+ -+ case h_connection: -+ case h_transfer_encoding: -+ assert(0 && "Shouldn't get here."); -+ break; -+ -+ case h_content_length: -+ { -+ uint64_t t; -+ -+ if (ch == ' ') break; -+ -+ if (UNLIKELY(!IS_NUM(ch))) { -+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); -+ parser->header_state = h_state; -+ goto error; -+ } -+ -+ t = parser->content_length; -+ t *= 10; -+ t += ch - '0'; -+ -+ /* Overflow? Test against a conservative limit for simplicity. */ -+ if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) { -+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); -+ parser->header_state = h_state; -+ goto error; -+ } -+ -+ parser->content_length = t; -+ break; -+ } -+ -+ /* Transfer-Encoding: chunked */ -+ case h_matching_transfer_encoding_chunked: -+ parser->index++; -+ if (parser->index > sizeof(CHUNKED)-1 -+ || c != CHUNKED[parser->index]) { -+ h_state = h_general; -+ } else if (parser->index == sizeof(CHUNKED)-2) { -+ h_state = h_transfer_encoding_chunked; -+ } -+ break; -+ -+ case h_matching_connection_token_start: -+ /* looking for 'Connection: keep-alive' */ -+ if (c == 'k') { -+ h_state = h_matching_connection_keep_alive; -+ /* looking for 'Connection: close' */ -+ } else if (c == 'c') { -+ h_state = h_matching_connection_close; -+ } else if (c == 'u') { -+ h_state = h_matching_connection_upgrade; -+ } else if (STRICT_TOKEN(c)) { -+ h_state = h_matching_connection_token; -+ } else if (c == ' ' || c == '\t') { -+ /* Skip lws */ -+ } else { -+ h_state = h_general; -+ } -+ break; -+ -+ /* looking for 'Connection: keep-alive' */ -+ case h_matching_connection_keep_alive: -+ parser->index++; -+ if (parser->index > sizeof(KEEP_ALIVE)-1 -+ || c != KEEP_ALIVE[parser->index]) { -+ h_state = h_matching_connection_token; -+ } else if (parser->index == sizeof(KEEP_ALIVE)-2) { -+ h_state = h_connection_keep_alive; -+ } -+ break; -+ -+ /* looking for 'Connection: close' */ -+ case h_matching_connection_close: -+ parser->index++; -+ if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { -+ h_state = h_matching_connection_token; -+ } else if (parser->index == sizeof(CLOSE)-2) { -+ h_state = h_connection_close; -+ } -+ break; -+ -+ /* looking for 'Connection: upgrade' */ -+ case h_matching_connection_upgrade: -+ parser->index++; -+ if (parser->index > sizeof(UPGRADE) - 1 || -+ c != UPGRADE[parser->index]) { -+ h_state = h_matching_connection_token; -+ } else if (parser->index == sizeof(UPGRADE)-2) { -+ h_state = h_connection_upgrade; -+ } -+ break; -+ -+ case h_matching_connection_token: -+ if (ch == ',') { -+ h_state = h_matching_connection_token_start; -+ parser->index = 0; -+ } -+ break; -+ -+ case h_transfer_encoding_chunked: -+ if (ch != ' ') h_state = h_general; -+ break; -+ -+ case h_connection_keep_alive: -+ case h_connection_close: -+ case h_connection_upgrade: -+ if (ch == ',') { -+ if (h_state == h_connection_keep_alive) { -+ parser->flags |= F_CONNECTION_KEEP_ALIVE; -+ } else if (h_state == h_connection_close) { -+ parser->flags |= F_CONNECTION_CLOSE; -+ } else if (h_state == h_connection_upgrade) { -+ parser->flags |= F_CONNECTION_UPGRADE; -+ } -+ h_state = h_matching_connection_token_start; -+ parser->index = 0; -+ } else if (ch != ' ') { -+ h_state = h_matching_connection_token; -+ } -+ break; -+ -+ default: -+ UPDATE_STATE(s_header_value); -+ h_state = h_general; -+ break; -+ } -+ } -+ parser->header_state = h_state; -+ -+ COUNT_HEADER_SIZE(p - start); -+ -+ if (p == data + len) -+ --p; -+ break; -+ } -+ -+ case s_header_almost_done: -+ { -+ if (UNLIKELY(ch != LF)) { -+ SET_ERRNO(HPE_LF_EXPECTED); -+ goto error; -+ } -+ -+ UPDATE_STATE(s_header_value_lws); -+ break; -+ } -+ -+ case s_header_value_lws: -+ { -+ if (ch == ' ' || ch == '\t') { -+ UPDATE_STATE(s_header_value_start); -+ REEXECUTE(); -+ } -+ -+ /* finished the header */ -+ switch (parser->header_state) { -+ case h_connection_keep_alive: -+ parser->flags |= F_CONNECTION_KEEP_ALIVE; -+ break; -+ case h_connection_close: -+ parser->flags |= F_CONNECTION_CLOSE; -+ break; -+ case h_transfer_encoding_chunked: -+ parser->flags |= F_CHUNKED; -+ break; -+ case h_connection_upgrade: -+ parser->flags |= F_CONNECTION_UPGRADE; -+ break; -+ default: -+ break; -+ } -+ -+ UPDATE_STATE(s_header_field_start); -+ REEXECUTE(); -+ } -+ -+ case s_header_value_discard_ws_almost_done: -+ { -+ STRICT_CHECK(ch != LF); -+ UPDATE_STATE(s_header_value_discard_lws); -+ break; -+ } -+ -+ case s_header_value_discard_lws: -+ { -+ if (ch == ' ' || ch == '\t') { -+ UPDATE_STATE(s_header_value_discard_ws); -+ break; -+ } else { -+ switch (parser->header_state) { -+ case h_connection_keep_alive: -+ parser->flags |= F_CONNECTION_KEEP_ALIVE; -+ break; -+ case h_connection_close: -+ parser->flags |= F_CONNECTION_CLOSE; -+ break; -+ case h_connection_upgrade: -+ parser->flags |= F_CONNECTION_UPGRADE; -+ break; -+ case h_transfer_encoding_chunked: -+ parser->flags |= F_CHUNKED; -+ break; -+ default: -+ break; -+ } -+ -+ /* header value was empty */ -+ MARK(header_value); -+ UPDATE_STATE(s_header_field_start); -+ CALLBACK_DATA_NOADVANCE(header_value); -+ REEXECUTE(); -+ } -+ } -+ -+ case s_headers_almost_done: -+ { -+ STRICT_CHECK(ch != LF); -+ -+ if (parser->flags & F_TRAILING) { -+ /* End of a chunked request */ -+ UPDATE_STATE(s_message_done); -+ CALLBACK_NOTIFY_NOADVANCE(chunk_complete); -+ REEXECUTE(); -+ } -+ -+ /* Cannot use chunked encoding and a content-length header together -+ per the HTTP specification. */ -+ if ((parser->flags & F_CHUNKED) && -+ (parser->flags & F_CONTENTLENGTH)) { -+ SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); -+ goto error; -+ } -+ -+ UPDATE_STATE(s_headers_done); -+ -+ /* Set this here so that on_headers_complete() callbacks can see it */ -+ parser->upgrade = -+ ((parser->flags & (F_UPGRADE | F_CONNECTION_UPGRADE)) == -+ (F_UPGRADE | F_CONNECTION_UPGRADE) || -+ parser->method == HTTP_CONNECT); -+ -+ /* Here we call the headers_complete callback. This is somewhat -+ * different than other callbacks because if the user returns 1, we -+ * will interpret that as saying that this message has no body. This -+ * is needed for the annoying case of recieving a response to a HEAD -+ * request. -+ * -+ * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so -+ * we have to simulate it by handling a change in errno below. -+ */ -+ if (settings->on_headers_complete) { -+ switch (settings->on_headers_complete(parser)) { -+ case 0: -+ break; -+ -+ case 2: -+ parser->upgrade = 1; -+ -+ case 1: -+ parser->flags |= F_SKIPBODY; -+ break; -+ -+ default: -+ SET_ERRNO(HPE_CB_headers_complete); -+ RETURN(p - data); /* Error */ -+ } -+ } -+ -+ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { -+ RETURN(p - data); -+ } -+ -+ REEXECUTE(); -+ } -+ -+ case s_headers_done: -+ { -+ int hasBody; -+ STRICT_CHECK(ch != LF); -+ -+ parser->nread = 0; -+ -+ hasBody = parser->flags & F_CHUNKED || -+ (parser->content_length > 0 && parser->content_length != ULLONG_MAX); -+ if (parser->upgrade && (parser->method == HTTP_CONNECT || -+ (parser->flags & F_SKIPBODY) || !hasBody)) { -+ /* Exit, the rest of the message is in a different protocol. */ -+ UPDATE_STATE(NEW_MESSAGE()); -+ CALLBACK_NOTIFY(message_complete); -+ RETURN((p - data) + 1); -+ } -+ -+ if (parser->flags & F_SKIPBODY) { -+ UPDATE_STATE(NEW_MESSAGE()); -+ CALLBACK_NOTIFY(message_complete); -+ } else if (parser->flags & F_CHUNKED) { -+ /* chunked encoding - ignore Content-Length header */ -+ UPDATE_STATE(s_chunk_size_start); -+ } else { -+ if (parser->content_length == 0) { -+ /* Content-Length header given but zero: Content-Length: 0\r\n */ -+ UPDATE_STATE(NEW_MESSAGE()); -+ CALLBACK_NOTIFY(message_complete); -+ } else if (parser->content_length != ULLONG_MAX) { -+ /* Content-Length header given and non-zero */ -+ UPDATE_STATE(s_body_identity); -+ } else { -+ if (!http_message_needs_eof(parser)) { -+ /* Assume content-length 0 - read the next */ -+ UPDATE_STATE(NEW_MESSAGE()); -+ CALLBACK_NOTIFY(message_complete); -+ } else { -+ /* Read body until EOF */ -+ UPDATE_STATE(s_body_identity_eof); -+ } -+ } -+ } -+ -+ break; -+ } -+ -+ case s_body_identity: -+ { -+ uint64_t to_read = MIN(parser->content_length, -+ (uint64_t) ((data + len) - p)); -+ -+ assert(parser->content_length != 0 -+ && parser->content_length != ULLONG_MAX); -+ -+ /* The difference between advancing content_length and p is because -+ * the latter will automaticaly advance on the next loop iteration. -+ * Further, if content_length ends up at 0, we want to see the last -+ * byte again for our message complete callback. -+ */ -+ MARK(body); -+ parser->content_length -= to_read; -+ p += to_read - 1; -+ -+ if (parser->content_length == 0) { -+ UPDATE_STATE(s_message_done); -+ -+ /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. -+ * -+ * The alternative to doing this is to wait for the next byte to -+ * trigger the data callback, just as in every other case. The -+ * problem with this is that this makes it difficult for the test -+ * harness to distinguish between complete-on-EOF and -+ * complete-on-length. It's not clear that this distinction is -+ * important for applications, but let's keep it for now. -+ */ -+ CALLBACK_DATA_(body, p - body_mark + 1, p - data); -+ REEXECUTE(); -+ } -+ -+ break; -+ } -+ -+ /* read until EOF */ -+ case s_body_identity_eof: -+ MARK(body); -+ p = data + len - 1; -+ -+ break; -+ -+ case s_message_done: -+ UPDATE_STATE(NEW_MESSAGE()); -+ CALLBACK_NOTIFY(message_complete); -+ if (parser->upgrade) { -+ /* Exit, the rest of the message is in a different protocol. */ -+ RETURN((p - data) + 1); -+ } -+ break; -+ -+ case s_chunk_size_start: -+ { -+ assert(parser->nread == 1); -+ assert(parser->flags & F_CHUNKED); -+ -+ unhex_val = unhex[(unsigned char)ch]; -+ if (UNLIKELY(unhex_val == -1)) { -+ SET_ERRNO(HPE_INVALID_CHUNK_SIZE); -+ goto error; -+ } -+ -+ parser->content_length = unhex_val; -+ UPDATE_STATE(s_chunk_size); -+ break; -+ } -+ -+ case s_chunk_size: -+ { -+ uint64_t t; -+ -+ assert(parser->flags & F_CHUNKED); -+ -+ if (ch == CR) { -+ UPDATE_STATE(s_chunk_size_almost_done); -+ break; -+ } -+ -+ unhex_val = unhex[(unsigned char)ch]; -+ -+ if (unhex_val == -1) { -+ if (ch == ';' || ch == ' ') { -+ UPDATE_STATE(s_chunk_parameters); -+ break; -+ } -+ -+ SET_ERRNO(HPE_INVALID_CHUNK_SIZE); -+ goto error; -+ } -+ -+ t = parser->content_length; -+ t *= 16; -+ t += unhex_val; -+ -+ /* Overflow? Test against a conservative limit for simplicity. */ -+ if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) { -+ SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); -+ goto error; -+ } -+ -+ parser->content_length = t; -+ break; -+ } -+ -+ case s_chunk_parameters: -+ { -+ assert(parser->flags & F_CHUNKED); -+ /* just ignore this shit. TODO check for overflow */ -+ if (ch == CR) { -+ UPDATE_STATE(s_chunk_size_almost_done); -+ break; -+ } -+ break; -+ } -+ -+ case s_chunk_size_almost_done: -+ { -+ assert(parser->flags & F_CHUNKED); -+ STRICT_CHECK(ch != LF); -+ -+ parser->nread = 0; -+ -+ if (parser->content_length == 0) { -+ parser->flags |= F_TRAILING; -+ UPDATE_STATE(s_header_field_start); -+ } else { -+ UPDATE_STATE(s_chunk_data); -+ } -+ CALLBACK_NOTIFY(chunk_header); -+ break; -+ } -+ -+ case s_chunk_data: -+ { -+ uint64_t to_read = MIN(parser->content_length, -+ (uint64_t) ((data + len) - p)); -+ -+ assert(parser->flags & F_CHUNKED); -+ assert(parser->content_length != 0 -+ && parser->content_length != ULLONG_MAX); -+ -+ /* See the explanation in s_body_identity for why the content -+ * length and data pointers are managed this way. -+ */ -+ MARK(body); -+ parser->content_length -= to_read; -+ p += to_read - 1; -+ -+ if (parser->content_length == 0) { -+ UPDATE_STATE(s_chunk_data_almost_done); -+ } -+ -+ break; -+ } -+ -+ case s_chunk_data_almost_done: -+ assert(parser->flags & F_CHUNKED); -+ assert(parser->content_length == 0); -+ STRICT_CHECK(ch != CR); -+ UPDATE_STATE(s_chunk_data_done); -+ CALLBACK_DATA(body); -+ break; -+ -+ case s_chunk_data_done: -+ assert(parser->flags & F_CHUNKED); -+ STRICT_CHECK(ch != LF); -+ parser->nread = 0; -+ UPDATE_STATE(s_chunk_size_start); -+ CALLBACK_NOTIFY(chunk_complete); -+ break; -+ -+ default: -+ assert(0 && "unhandled state"); -+ SET_ERRNO(HPE_INVALID_INTERNAL_STATE); -+ goto error; -+ } -+ } -+ -+ /* Run callbacks for any marks that we have leftover after we ran our of -+ * bytes. There should be at most one of these set, so it's OK to invoke -+ * them in series (unset marks will not result in callbacks). -+ * -+ * We use the NOADVANCE() variety of callbacks here because 'p' has already -+ * overflowed 'data' and this allows us to correct for the off-by-one that -+ * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' -+ * value that's in-bounds). -+ */ -+ -+ assert(((header_field_mark ? 1 : 0) + -+ (header_value_mark ? 1 : 0) + -+ (url_mark ? 1 : 0) + -+ (body_mark ? 1 : 0) + -+ (status_mark ? 1 : 0)) <= 1); -+ -+ CALLBACK_DATA_NOADVANCE(header_field); -+ CALLBACK_DATA_NOADVANCE(header_value); -+ CALLBACK_DATA_NOADVANCE(url); -+ CALLBACK_DATA_NOADVANCE(body); -+ CALLBACK_DATA_NOADVANCE(status); -+ -+ RETURN(len); -+ -+error: -+ if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { -+ SET_ERRNO(HPE_UNKNOWN); -+ } -+ -+ RETURN(p - data); -+} -+ -+ -+/* Does the parser need to see an EOF to find the end of the message? */ -+int -+http_message_needs_eof (const http_parser *parser) -+{ -+ if (parser->type == HTTP_REQUEST) { -+ return 0; -+ } -+ -+ /* See RFC 2616 section 4.4 */ -+ if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ -+ parser->status_code == 204 || /* No Content */ -+ parser->status_code == 304 || /* Not Modified */ -+ parser->flags & F_SKIPBODY) { /* response to a HEAD request */ -+ return 0; -+ } -+ -+ if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { -+ return 0; -+ } -+ -+ return 1; -+} -+ -+ -+int -+http_should_keep_alive (const http_parser *parser) -+{ -+ if (parser->http_major > 0 && parser->http_minor > 0) { -+ /* HTTP/1.1 */ -+ if (parser->flags & F_CONNECTION_CLOSE) { -+ return 0; -+ } -+ } else { -+ /* HTTP/1.0 or earlier */ -+ if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { -+ return 0; -+ } -+ } -+ -+ return !http_message_needs_eof(parser); -+} -+ -+ -+const char * -+http_method_str (enum http_method m) -+{ -+ return ELEM_AT(method_strings, m, ""); -+} -+ -+ -+void -+http_parser_init (http_parser *parser, enum http_parser_type t) -+{ -+ void *data = parser->data; /* preserve application data */ -+ memset(parser, 0, sizeof(*parser)); -+ parser->data = data; -+ parser->type = t; -+ parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); -+ parser->http_errno = HPE_OK; -+} -+ -+void -+http_parser_settings_init(http_parser_settings *settings) -+{ -+ memset(settings, 0, sizeof(*settings)); -+} -+ -+const char * -+http_errno_name(enum http_errno err) { -+ assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); -+ return http_strerror_tab[err].name; -+} -+ -+const char * -+http_errno_description(enum http_errno err) { -+ assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); -+ return http_strerror_tab[err].description; -+} -+ -+static enum http_host_state -+http_parse_host_char(enum http_host_state s, const char ch) { -+ switch(s) { -+ case s_http_userinfo: -+ case s_http_userinfo_start: -+ if (ch == '@') { -+ return s_http_host_start; -+ } -+ -+ if (IS_USERINFO_CHAR(ch)) { -+ return s_http_userinfo; -+ } -+ break; -+ -+ case s_http_host_start: -+ if (ch == '[') { -+ return s_http_host_v6_start; -+ } -+ -+ if (IS_HOST_CHAR(ch)) { -+ return s_http_host; -+ } -+ -+ break; -+ -+ case s_http_host: -+ if (IS_HOST_CHAR(ch)) { -+ return s_http_host; -+ } -+ -+ /* FALLTHROUGH */ -+ case s_http_host_v6_end: -+ if (ch == ':') { -+ return s_http_host_port_start; -+ } -+ -+ break; -+ -+ case s_http_host_v6: -+ if (ch == ']') { -+ return s_http_host_v6_end; -+ } -+ -+ /* FALLTHROUGH */ -+ case s_http_host_v6_start: -+ if (IS_HEX(ch) || ch == ':' || ch == '.') { -+ return s_http_host_v6; -+ } -+ -+ if (s == s_http_host_v6 && ch == '%') { -+ return s_http_host_v6_zone_start; -+ } -+ break; -+ -+ case s_http_host_v6_zone: -+ if (ch == ']') { -+ return s_http_host_v6_end; -+ } -+ -+ /* FALLTHROUGH */ -+ case s_http_host_v6_zone_start: -+ /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */ -+ if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' || -+ ch == '~') { -+ return s_http_host_v6_zone; -+ } -+ break; -+ -+ case s_http_host_port: -+ case s_http_host_port_start: -+ if (IS_NUM(ch)) { -+ return s_http_host_port; -+ } -+ -+ break; -+ -+ default: -+ break; -+ } -+ return s_http_host_dead; -+} -+ -+static int -+http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { -+ enum http_host_state s; -+ -+ const char *p; -+ size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; -+ -+ assert(u->field_set & (1 << UF_HOST)); -+ -+ u->field_data[UF_HOST].len = 0; -+ -+ s = found_at ? s_http_userinfo_start : s_http_host_start; -+ -+ for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { -+ enum http_host_state new_s = http_parse_host_char(s, *p); -+ -+ if (new_s == s_http_host_dead) { -+ return 1; -+ } -+ -+ switch(new_s) { -+ case s_http_host: -+ if (s != s_http_host) { -+ u->field_data[UF_HOST].off = p - buf; -+ } -+ u->field_data[UF_HOST].len++; -+ break; -+ -+ case s_http_host_v6: -+ if (s != s_http_host_v6) { -+ u->field_data[UF_HOST].off = p - buf; -+ } -+ u->field_data[UF_HOST].len++; -+ break; -+ -+ case s_http_host_v6_zone_start: -+ case s_http_host_v6_zone: -+ u->field_data[UF_HOST].len++; -+ break; -+ -+ case s_http_host_port: -+ if (s != s_http_host_port) { -+ u->field_data[UF_PORT].off = p - buf; -+ u->field_data[UF_PORT].len = 0; -+ u->field_set |= (1 << UF_PORT); -+ } -+ u->field_data[UF_PORT].len++; -+ break; -+ -+ case s_http_userinfo: -+ if (s != s_http_userinfo) { -+ u->field_data[UF_USERINFO].off = p - buf ; -+ u->field_data[UF_USERINFO].len = 0; -+ u->field_set |= (1 << UF_USERINFO); -+ } -+ u->field_data[UF_USERINFO].len++; -+ break; -+ -+ default: -+ break; -+ } -+ s = new_s; -+ } -+ -+ /* Make sure we don't end somewhere unexpected */ -+ switch (s) { -+ case s_http_host_start: -+ case s_http_host_v6_start: -+ case s_http_host_v6: -+ case s_http_host_v6_zone_start: -+ case s_http_host_v6_zone: -+ case s_http_host_port_start: -+ case s_http_userinfo: -+ case s_http_userinfo_start: -+ return 1; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+void -+http_parser_url_init(struct http_parser_url *u) { -+ memset(u, 0, sizeof(*u)); -+} -+ -+int -+http_parser_parse_url(const char *buf, size_t buflen, int is_connect, -+ struct http_parser_url *u) -+{ -+ enum state s; -+ const char *p; -+ enum http_parser_url_fields uf, old_uf; -+ int found_at = 0; -+ -+ u->port = u->field_set = 0; -+ s = is_connect ? s_req_server_start : s_req_spaces_before_url; -+ old_uf = UF_MAX; -+ -+ for (p = buf; p < buf + buflen; p++) { -+ s = parse_url_char(s, *p); -+ -+ /* Figure out the next field that we're operating on */ -+ switch (s) { -+ case s_dead: -+ return 1; -+ -+ /* Skip delimeters */ -+ case s_req_schema_slash: -+ case s_req_schema_slash_slash: -+ case s_req_server_start: -+ case s_req_query_string_start: -+ case s_req_fragment_start: -+ continue; -+ -+ case s_req_schema: -+ uf = UF_SCHEMA; -+ break; -+ -+ case s_req_server_with_at: -+ found_at = 1; -+ -+ /* FALLTROUGH */ -+ case s_req_server: -+ uf = UF_HOST; -+ break; -+ -+ case s_req_path: -+ uf = UF_PATH; -+ break; -+ -+ case s_req_query_string: -+ uf = UF_QUERY; -+ break; -+ -+ case s_req_fragment: -+ uf = UF_FRAGMENT; -+ break; -+ -+ default: -+ assert(!"Unexpected state"); -+ return 1; -+ } -+ -+ /* Nothing's changed; soldier on */ -+ if (uf == old_uf) { -+ u->field_data[uf].len++; -+ continue; -+ } -+ -+ u->field_data[uf].off = p - buf; -+ u->field_data[uf].len = 1; -+ -+ u->field_set |= (1 << uf); -+ old_uf = uf; -+ } -+ -+ /* host must be present if there is a schema */ -+ /* parsing http:///toto will fail */ -+ if ((u->field_set & (1 << UF_SCHEMA)) && -+ (u->field_set & (1 << UF_HOST)) == 0) { -+ return 1; -+ } -+ -+ if (u->field_set & (1 << UF_HOST)) { -+ if (http_parse_host(buf, u, found_at) != 0) { -+ return 1; -+ } -+ } -+ -+ /* CONNECT requests can only contain "hostname:port" */ -+ if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { -+ return 1; -+ } -+ -+ if (u->field_set & (1 << UF_PORT)) { -+ /* Don't bother with endp; we've already validated the string */ -+ unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); -+ -+ /* Ports have a max value of 2^16 */ -+ if (v > 0xffff) { -+ return 1; -+ } -+ -+ u->port = (uint16_t) v; -+ } -+ -+ return 0; -+} -+ -+void -+http_parser_pause(http_parser *parser, int paused) { -+ /* Users should only be pausing/unpausing a parser that is not in an error -+ * state. In non-debug builds, there's not much that we can do about this -+ * other than ignore it. -+ */ -+ if (HTTP_PARSER_ERRNO(parser) == HPE_OK || -+ HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { -+ SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); -+ } else { -+ assert(0 && "Attempting to pause parser in error state"); -+ } -+} -+ -+int -+http_body_is_final(const struct http_parser *parser) { -+ return parser->state == s_message_done; -+} -+ -+unsigned long -+http_parser_version(void) { -+ return HTTP_PARSER_VERSION_MAJOR * 0x10000 | -+ HTTP_PARSER_VERSION_MINOR * 0x00100 | -+ HTTP_PARSER_VERSION_PATCH * 0x00001; -+} -diff --git a/src/responder/secrets/http_parser.h b/src/responder/secrets/http_parser.h -new file mode 100644 -index 0000000000000000000000000000000000000000..105ae510a8ab57509de2c68bbe1504e39ffb165e ---- /dev/null -+++ b/src/responder/secrets/http_parser.h -@@ -0,0 +1,362 @@ -+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to -+ * deal in the Software without restriction, including without limitation the -+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -+ * sell copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -+ * IN THE SOFTWARE. -+ */ -+#ifndef http_parser_h -+#define http_parser_h -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* Also update SONAME in the Makefile whenever you change these. */ -+#define HTTP_PARSER_VERSION_MAJOR 2 -+#define HTTP_PARSER_VERSION_MINOR 7 -+#define HTTP_PARSER_VERSION_PATCH 0 -+ -+#include -+#if defined(_WIN32) && !defined(__MINGW32__) && \ -+ (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__) -+#include -+#include -+typedef __int8 int8_t; -+typedef unsigned __int8 uint8_t; -+typedef __int16 int16_t; -+typedef unsigned __int16 uint16_t; -+typedef __int32 int32_t; -+typedef unsigned __int32 uint32_t; -+typedef __int64 int64_t; -+typedef unsigned __int64 uint64_t; -+#else -+#include -+#endif -+ -+/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run -+ * faster -+ */ -+#ifndef HTTP_PARSER_STRICT -+# define HTTP_PARSER_STRICT 1 -+#endif -+ -+/* Maximium header size allowed. If the macro is not defined -+ * before including this header then the default is used. To -+ * change the maximum header size, define the macro in the build -+ * environment (e.g. -DHTTP_MAX_HEADER_SIZE=). To remove -+ * the effective limit on the size of the header, define the macro -+ * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff) -+ */ -+#ifndef HTTP_MAX_HEADER_SIZE -+# define HTTP_MAX_HEADER_SIZE (80*1024) -+#endif -+ -+typedef struct http_parser http_parser; -+typedef struct http_parser_settings http_parser_settings; -+ -+ -+/* Callbacks should return non-zero to indicate an error. The parser will -+ * then halt execution. -+ * -+ * The one exception is on_headers_complete. In a HTTP_RESPONSE parser -+ * returning '1' from on_headers_complete will tell the parser that it -+ * should not expect a body. This is used when receiving a response to a -+ * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: -+ * chunked' headers that indicate the presence of a body. -+ * -+ * Returning `2` from on_headers_complete will tell parser that it should not -+ * expect neither a body nor any futher responses on this connection. This is -+ * useful for handling responses to a CONNECT request which may not contain -+ * `Upgrade` or `Connection: upgrade` headers. -+ * -+ * http_data_cb does not return data chunks. It will be called arbitrarily -+ * many times for each string. E.G. you might get 10 callbacks for "on_url" -+ * each providing just a few characters more data. -+ */ -+typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); -+typedef int (*http_cb) (http_parser*); -+ -+ -+/* Request Methods */ -+#define HTTP_METHOD_MAP(XX) \ -+ XX(0, DELETE, DELETE) \ -+ XX(1, GET, GET) \ -+ XX(2, HEAD, HEAD) \ -+ XX(3, POST, POST) \ -+ XX(4, PUT, PUT) \ -+ /* pathological */ \ -+ XX(5, CONNECT, CONNECT) \ -+ XX(6, OPTIONS, OPTIONS) \ -+ XX(7, TRACE, TRACE) \ -+ /* WebDAV */ \ -+ XX(8, COPY, COPY) \ -+ XX(9, LOCK, LOCK) \ -+ XX(10, MKCOL, MKCOL) \ -+ XX(11, MOVE, MOVE) \ -+ XX(12, PROPFIND, PROPFIND) \ -+ XX(13, PROPPATCH, PROPPATCH) \ -+ XX(14, SEARCH, SEARCH) \ -+ XX(15, UNLOCK, UNLOCK) \ -+ XX(16, BIND, BIND) \ -+ XX(17, REBIND, REBIND) \ -+ XX(18, UNBIND, UNBIND) \ -+ XX(19, ACL, ACL) \ -+ /* subversion */ \ -+ XX(20, REPORT, REPORT) \ -+ XX(21, MKACTIVITY, MKACTIVITY) \ -+ XX(22, CHECKOUT, CHECKOUT) \ -+ XX(23, MERGE, MERGE) \ -+ /* upnp */ \ -+ XX(24, MSEARCH, M-SEARCH) \ -+ XX(25, NOTIFY, NOTIFY) \ -+ XX(26, SUBSCRIBE, SUBSCRIBE) \ -+ XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ -+ /* RFC-5789 */ \ -+ XX(28, PATCH, PATCH) \ -+ XX(29, PURGE, PURGE) \ -+ /* CalDAV */ \ -+ XX(30, MKCALENDAR, MKCALENDAR) \ -+ /* RFC-2068, section 19.6.1.2 */ \ -+ XX(31, LINK, LINK) \ -+ XX(32, UNLINK, UNLINK) \ -+ -+enum http_method -+ { -+#define XX(num, name, string) HTTP_##name = num, -+ HTTP_METHOD_MAP(XX) -+#undef XX -+ }; -+ -+ -+enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; -+ -+ -+/* Flag values for http_parser.flags field */ -+enum flags -+ { F_CHUNKED = 1 << 0 -+ , F_CONNECTION_KEEP_ALIVE = 1 << 1 -+ , F_CONNECTION_CLOSE = 1 << 2 -+ , F_CONNECTION_UPGRADE = 1 << 3 -+ , F_TRAILING = 1 << 4 -+ , F_UPGRADE = 1 << 5 -+ , F_SKIPBODY = 1 << 6 -+ , F_CONTENTLENGTH = 1 << 7 -+ }; -+ -+ -+/* Map for errno-related constants -+ * -+ * The provided argument should be a macro that takes 2 arguments. -+ */ -+#define HTTP_ERRNO_MAP(XX) \ -+ /* No error */ \ -+ XX(OK, "success") \ -+ \ -+ /* Callback-related errors */ \ -+ XX(CB_message_begin, "the on_message_begin callback failed") \ -+ XX(CB_url, "the on_url callback failed") \ -+ XX(CB_header_field, "the on_header_field callback failed") \ -+ XX(CB_header_value, "the on_header_value callback failed") \ -+ XX(CB_headers_complete, "the on_headers_complete callback failed") \ -+ XX(CB_body, "the on_body callback failed") \ -+ XX(CB_message_complete, "the on_message_complete callback failed") \ -+ XX(CB_status, "the on_status callback failed") \ -+ XX(CB_chunk_header, "the on_chunk_header callback failed") \ -+ XX(CB_chunk_complete, "the on_chunk_complete callback failed") \ -+ \ -+ /* Parsing-related errors */ \ -+ XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ -+ XX(HEADER_OVERFLOW, \ -+ "too many header bytes seen; overflow detected") \ -+ XX(CLOSED_CONNECTION, \ -+ "data received after completed connection: close message") \ -+ XX(INVALID_VERSION, "invalid HTTP version") \ -+ XX(INVALID_STATUS, "invalid HTTP status code") \ -+ XX(INVALID_METHOD, "invalid HTTP method") \ -+ XX(INVALID_URL, "invalid URL") \ -+ XX(INVALID_HOST, "invalid host") \ -+ XX(INVALID_PORT, "invalid port") \ -+ XX(INVALID_PATH, "invalid path") \ -+ XX(INVALID_QUERY_STRING, "invalid query string") \ -+ XX(INVALID_FRAGMENT, "invalid fragment") \ -+ XX(LF_EXPECTED, "LF character expected") \ -+ XX(INVALID_HEADER_TOKEN, "invalid character in header") \ -+ XX(INVALID_CONTENT_LENGTH, \ -+ "invalid character in content-length header") \ -+ XX(UNEXPECTED_CONTENT_LENGTH, \ -+ "unexpected content-length header") \ -+ XX(INVALID_CHUNK_SIZE, \ -+ "invalid character in chunk size header") \ -+ XX(INVALID_CONSTANT, "invalid constant string") \ -+ XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ -+ XX(STRICT, "strict mode assertion failed") \ -+ XX(PAUSED, "parser is paused") \ -+ XX(UNKNOWN, "an unknown error occurred") -+ -+ -+/* Define HPE_* values for each errno value above */ -+#define HTTP_ERRNO_GEN(n, s) HPE_##n, -+enum http_errno { -+ HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) -+}; -+#undef HTTP_ERRNO_GEN -+ -+ -+/* Get an http_errno value from an http_parser */ -+#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) -+ -+ -+struct http_parser { -+ /** PRIVATE **/ -+ unsigned int type : 2; /* enum http_parser_type */ -+ unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */ -+ unsigned int state : 7; /* enum state from http_parser.c */ -+ unsigned int header_state : 7; /* enum header_state from http_parser.c */ -+ unsigned int index : 7; /* index into current matcher */ -+ unsigned int lenient_http_headers : 1; -+ -+ uint32_t nread; /* # bytes read in various scenarios */ -+ uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ -+ -+ /** READ-ONLY **/ -+ unsigned short http_major; -+ unsigned short http_minor; -+ unsigned int status_code : 16; /* responses only */ -+ unsigned int method : 8; /* requests only */ -+ unsigned int http_errno : 7; -+ -+ /* 1 = Upgrade header was present and the parser has exited because of that. -+ * 0 = No upgrade header present. -+ * Should be checked when http_parser_execute() returns in addition to -+ * error checking. -+ */ -+ unsigned int upgrade : 1; -+ -+ /** PUBLIC **/ -+ void *data; /* A pointer to get hook to the "connection" or "socket" object */ -+}; -+ -+ -+struct http_parser_settings { -+ http_cb on_message_begin; -+ http_data_cb on_url; -+ http_data_cb on_status; -+ http_data_cb on_header_field; -+ http_data_cb on_header_value; -+ http_cb on_headers_complete; -+ http_data_cb on_body; -+ http_cb on_message_complete; -+ /* When on_chunk_header is called, the current chunk length is stored -+ * in parser->content_length. -+ */ -+ http_cb on_chunk_header; -+ http_cb on_chunk_complete; -+}; -+ -+ -+enum http_parser_url_fields -+ { UF_SCHEMA = 0 -+ , UF_HOST = 1 -+ , UF_PORT = 2 -+ , UF_PATH = 3 -+ , UF_QUERY = 4 -+ , UF_FRAGMENT = 5 -+ , UF_USERINFO = 6 -+ , UF_MAX = 7 -+ }; -+ -+ -+/* Result structure for http_parser_parse_url(). -+ * -+ * Callers should index into field_data[] with UF_* values iff field_set -+ * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and -+ * because we probably have padding left over), we convert any port to -+ * a uint16_t. -+ */ -+struct http_parser_url { -+ uint16_t field_set; /* Bitmask of (1 << UF_*) values */ -+ uint16_t port; /* Converted UF_PORT string */ -+ -+ struct { -+ uint16_t off; /* Offset into buffer in which field starts */ -+ uint16_t len; /* Length of run in buffer */ -+ } field_data[UF_MAX]; -+}; -+ -+ -+/* Returns the library version. Bits 16-23 contain the major version number, -+ * bits 8-15 the minor version number and bits 0-7 the patch level. -+ * Usage example: -+ * -+ * unsigned long version = http_parser_version(); -+ * unsigned major = (version >> 16) & 255; -+ * unsigned minor = (version >> 8) & 255; -+ * unsigned patch = version & 255; -+ * printf("http_parser v%u.%u.%u\n", major, minor, patch); -+ */ -+unsigned long http_parser_version(void); -+ -+void http_parser_init(http_parser *parser, enum http_parser_type type); -+ -+ -+/* Initialize http_parser_settings members to 0 -+ */ -+void http_parser_settings_init(http_parser_settings *settings); -+ -+ -+/* Executes the parser. Returns number of parsed bytes. Sets -+ * `parser->http_errno` on error. */ -+size_t http_parser_execute(http_parser *parser, -+ const http_parser_settings *settings, -+ const char *data, -+ size_t len); -+ -+ -+/* If http_should_keep_alive() in the on_headers_complete or -+ * on_message_complete callback returns 0, then this should be -+ * the last message on the connection. -+ * If you are the server, respond with the "Connection: close" header. -+ * If you are the client, close the connection. -+ */ -+int http_should_keep_alive(const http_parser *parser); -+ -+/* Returns a string version of the HTTP method. */ -+const char *http_method_str(enum http_method m); -+ -+/* Return a string name of the given error */ -+const char *http_errno_name(enum http_errno err); -+ -+/* Return a string description of the given error */ -+const char *http_errno_description(enum http_errno err); -+ -+/* Initialize all http_parser_url members to 0 */ -+void http_parser_url_init(struct http_parser_url *u); -+ -+/* Parse a URL; return nonzero on failure */ -+int http_parser_parse_url(const char *buf, size_t buflen, -+ int is_connect, -+ struct http_parser_url *u); -+ -+/* Pause or un-pause the parser; a nonzero value pauses */ -+void http_parser_pause(http_parser *parser, int paused); -+ -+/* Checks if this is the final chunk of the body. */ -+int http_body_is_final(const http_parser *parser); -+ -+#ifdef __cplusplus -+} -+#endif -+#endif -diff --git a/src/responder/secrets/secsrv_private.h b/src/responder/secrets/secsrv_private.h -index c3b663996e138bbb14f1ab74db75398ffd0bd5c7..47ed7642cf8da5ecfc8f995199746596a12b3e1d 100644 ---- a/src/responder/secrets/secsrv_private.h -+++ b/src/responder/secrets/secsrv_private.h -@@ -25,7 +25,7 @@ - #include "config.h" - #include "responder/common/responder.h" - #include "responder/secrets/secsrv.h" --#include -+#include "http_parser.h" - - struct sec_kvp { - char *name; --- -2.4.11 - diff --git a/SOURCES/0009-sss_cert_derb64_to_ldap_filter-add-sss_certmap-suppo.patch b/SOURCES/0009-sss_cert_derb64_to_ldap_filter-add-sss_certmap-suppo.patch new file mode 100644 index 0000000..d53da7d --- /dev/null +++ b/SOURCES/0009-sss_cert_derb64_to_ldap_filter-add-sss_certmap-suppo.patch @@ -0,0 +1,235 @@ +From 2e12cbdc8e2676b045a972045e9dae75b232dc76 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 2 Feb 2017 16:34:32 +0100 +Subject: [PATCH 09/15] sss_cert_derb64_to_ldap_filter: add sss_certmap support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use certificate mapping library if available to lookup a user by +certificate in LDAP. + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +--- + Makefile.am | 1 + + src/db/sysdb_ops.c | 2 +- + src/db/sysdb_views.c | 4 +- + src/providers/ipa/ipa_views.c | 2 +- + src/providers/ldap/ldap_id.c | 2 +- + src/tests/cmocka/test_cert_utils.c | 4 +- + src/util/cert.h | 3 ++ + src/util/cert/cert_common.c | 76 ++++++++++++++++++++++++++++++++------ + 8 files changed, 76 insertions(+), 18 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 7947b7a5fbe3ca1034baac1c13c53300994b1bf8..f262cc24832358910dbb92ccd46f93c9eda8a295 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -952,6 +952,7 @@ libsss_cert_la_LIBADD = \ + $(TALLOC_LIBS) \ + libsss_crypt.la \ + libsss_debug.la \ ++ libsss_certmap.la \ + $(NULL) + libsss_cert_la_LDFLAGS = \ + -avoid-version \ +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 8ae25764478e522255b177f9e8de1d3ca1ad43fd..919f22370ff87eff2bf0bb569ca90f1ee699a61e 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -4661,7 +4661,7 @@ errno_t sysdb_search_object_by_cert(TALLOC_CTX *mem_ctx, + char *user_filter; + + ret = sss_cert_derb64_to_ldap_filter(mem_ctx, cert, SYSDB_USER_MAPPED_CERT, +- &user_filter); ++ NULL, NULL, &user_filter); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_cert_derb64_to_ldap_filter failed.\n"); + return ret; +diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c +index 9dc48f5b6c414bbc7c64bcd1fe73553f388588bd..1c416dd14049237e9f35d52f154035e3ff861469 100644 +--- a/src/db/sysdb_views.c ++++ b/src/db/sysdb_views.c +@@ -862,8 +862,8 @@ errno_t sysdb_search_override_by_cert(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sss_cert_derb64_to_ldap_filter(tmp_ctx, cert, SYSDB_USER_CERT, +- &cert_filter); ++ ret = sss_cert_derb64_to_ldap_filter(tmp_ctx, cert, SYSDB_USER_CERT, NULL, ++ NULL, &cert_filter); + + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_cert_derb64_to_ldap_filter failed.\n"); +diff --git a/src/providers/ipa/ipa_views.c b/src/providers/ipa/ipa_views.c +index 29f589ec1fd05f59175dcc4592e6395941e6e034..5b6fcbc9b7c6f2ea7dbeecb01a5a3fd11b8a6854 100644 +--- a/src/providers/ipa/ipa_views.c ++++ b/src/providers/ipa/ipa_views.c +@@ -156,7 +156,7 @@ static errno_t dp_id_data_to_override_filter(TALLOC_CTX *mem_ctx, + if ((ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_BY_CERT) { + ret = sss_cert_derb64_to_ldap_filter(mem_ctx, ar->filter_value, + ipa_opts->override_map[IPA_AT_OVERRIDE_USER_CERT].name, +- &cert_filter); ++ NULL, NULL, &cert_filter); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "sss_cert_derb64_to_ldap_filter failed.\n"); +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index a8b4bc2cfc6e9d4e0d74b0e3e036afbcbf7eb26e..8e60769d09383ac8ebe33e5f64fd4fd9788e82cd 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -247,7 +247,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + } + + ret = sss_cert_derb64_to_ldap_filter(state, filter_value, attr_name, +- &user_filter); ++ NULL, NULL, &user_filter); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "sss_cert_derb64_to_ldap_filter failed.\n"); +diff --git a/src/tests/cmocka/test_cert_utils.c b/src/tests/cmocka/test_cert_utils.c +index 35e8cb7513968079861048a7e8b0631229f202c0..5830131754e4cf318273151b586ef36d6a349829 100644 +--- a/src/tests/cmocka/test_cert_utils.c ++++ b/src/tests/cmocka/test_cert_utils.c +@@ -297,11 +297,11 @@ void test_sss_cert_derb64_to_ldap_filter(void **state) + struct test_state *ts = talloc_get_type_abort(*state, struct test_state); + assert_non_null(ts); + +- ret = sss_cert_derb64_to_ldap_filter(ts, NULL, NULL, NULL); ++ ret = sss_cert_derb64_to_ldap_filter(ts, NULL, NULL, NULL, NULL, NULL); + assert_int_equal(ret, EINVAL); + + ret = sss_cert_derb64_to_ldap_filter(ts, "AAECAwQFBgcICQ==", "attrName", +- &filter); ++ NULL, NULL, &filter); + assert_int_equal(ret, EOK); + assert_string_equal(filter, + "(attrName=\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09)"); +diff --git a/src/util/cert.h b/src/util/cert.h +index bb64d0d7a0a48207df60f6e6e554da5e16a16b03..4598aa8df0cd860fed71d9cd2e4beec7f1910578 100644 +--- a/src/util/cert.h ++++ b/src/util/cert.h +@@ -21,6 +21,7 @@ + #include + + #include "util/util.h" ++#include "lib/certmap/sss_certmap.h" + + #ifndef __CERT_H__ + #define __CERT_H__ +@@ -39,6 +40,8 @@ errno_t sss_cert_pem_to_derb64(TALLOC_CTX *mem_ctx, const char *pem, + + errno_t sss_cert_derb64_to_ldap_filter(TALLOC_CTX *mem_ctx, const char *derb64, + const char *attr_name, ++ struct sss_certmap_ctx *certmap_ctx, ++ struct sss_domain_info *dom, + char **ldap_filter); + + errno_t bin_to_ldap_filter_value(TALLOC_CTX *mem_ctx, +diff --git a/src/util/cert/cert_common.c b/src/util/cert/cert_common.c +index a29696ed3cd9f2168f47323fac97d44e9b49f921..766877089429ff1c01000a3986316c74583e3fa4 100644 +--- a/src/util/cert/cert_common.c ++++ b/src/util/cert/cert_common.c +@@ -72,12 +72,17 @@ errno_t sss_cert_pem_to_derb64(TALLOC_CTX *mem_ctx, const char *pem, + + errno_t sss_cert_derb64_to_ldap_filter(TALLOC_CTX *mem_ctx, const char *derb64, + const char *attr_name, ++ struct sss_certmap_ctx *certmap_ctx, ++ struct sss_domain_info *dom, + char **ldap_filter) + { + int ret; + unsigned char *der; + size_t der_size; + char *val; ++ char *filter = NULL; ++ char **domains = NULL; ++ size_t c; + + if (derb64 == NULL || attr_name == NULL) { + return EINVAL; +@@ -89,18 +94,67 @@ errno_t sss_cert_derb64_to_ldap_filter(TALLOC_CTX *mem_ctx, const char *derb64, + return EINVAL; + } + +- ret = bin_to_ldap_filter_value(mem_ctx, der, der_size, &val); +- talloc_free(der); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "bin_to_ldap_filter_value failed.\n"); +- return ret; +- } ++ if (certmap_ctx == NULL) { ++ ret = bin_to_ldap_filter_value(mem_ctx, der, der_size, &val); ++ talloc_free(der); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "bin_to_ldap_filter_value failed.\n"); ++ return ret; ++ } + +- *ldap_filter = talloc_asprintf(mem_ctx, "(%s=%s)", attr_name, val); +- talloc_free(val); +- if (*ldap_filter == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); +- return ENOMEM; ++ *ldap_filter = talloc_asprintf(mem_ctx, "(%s=%s)", attr_name, val); ++ talloc_free(val); ++ if (*ldap_filter == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); ++ return ENOMEM; ++ } ++ } else { ++ ret = sss_certmap_get_search_filter(certmap_ctx, der, der_size, ++ &filter, &domains); ++ talloc_free(der); ++ if (ret != 0) { ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Certificate does not match matching-rules.\n"); ++ } else { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sss_certmap_get_search_filter failed.\n"); ++ } ++ } else { ++ if (domains == NULL) { ++ if (IS_SUBDOMAIN(dom)) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Rule applies only to local domain.\n"); ++ ret = ENOENT; ++ } ++ } else { ++ for (c = 0; domains[c] != NULL; c++) { ++ if (strcasecmp(dom->name, domains[c]) == 0) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Rule applies to current domain [%s].\n", ++ dom->name); ++ ret = EOK; ++ break; ++ } ++ } ++ if (domains[c] == NULL) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Rule does not apply to current domain [%s].\n", ++ dom->name); ++ ret = ENOENT; ++ } ++ } ++ } ++ ++ if (ret == EOK) { ++ *ldap_filter = talloc_strdup(mem_ctx, filter); ++ if (*ldap_filter == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ ret = ENOMEM; ++ } ++ } ++ sss_certmap_free_filter_and_domains(filter, domains); ++ return ret; + } + + return EOK; +-- +2.9.3 + diff --git a/SOURCES/0010-MAN-Update-description-of-sssctl.patch b/SOURCES/0010-MAN-Update-description-of-sssctl.patch deleted file mode 100644 index 4e5482c..0000000 --- a/SOURCES/0010-MAN-Update-description-of-sssctl.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 41a8e0f463188dd6a78d44908a8601c7c7576b59 Mon Sep 17 00:00:00 2001 -From: Dan Lavu -Date: Mon, 11 Jul 2016 12:27:34 +0200 -Subject: [PATCH 10/14] MAN: Update description of sssctl -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Pavel Březina -(cherry picked from commit 8ad1883c79fc1e356bbd2d3e4badd4af9955b9fc) ---- - src/man/sssctl.8.xml | 13 ++++++------- - 1 file changed, 6 insertions(+), 7 deletions(-) - -diff --git a/src/man/sssctl.8.xml b/src/man/sssctl.8.xml -index 721d0a2f7558b105c22135388757f92270265c4a..cbb632b68b145680ab94523b90180c5f76d69eb9 100644 ---- a/src/man/sssctl.8.xml -+++ b/src/man/sssctl.8.xml -@@ -29,12 +29,11 @@ - - DESCRIPTION - -- sssctl provides simple and unified way to obtain -- information about SSSD status such as active server or list of -- auto-discovered servers and domains or information about cached -- objects. It also provides tools to manage SSSD data files during -- troubleshooting such as a safe way to remove cache files or fetching -- all SSSD log files and more. -+ sssctl provides a simple and unified way -+ to obtain information about SSSD status, such as active server, -+ auto-discovered servers, domains and cached objects. In addition, -+ it can manage SSSD data files for troubleshooting in such a way -+ that is safe to manipulate while SSSD is running. - - - -@@ -42,7 +41,7 @@ - AVAILABLE COMMANDS - - To list all available commands run sssctl -- without any parameter. To print help for selected command -+ without any parameters. To print help for selected command - run sssctl COMMAND --help. - - --- -2.4.11 - diff --git a/SOURCES/0010-sysdb-add-certmap-related-calls.patch b/SOURCES/0010-sysdb-add-certmap-related-calls.patch new file mode 100644 index 0000000..5b33d5f --- /dev/null +++ b/SOURCES/0010-sysdb-add-certmap-related-calls.patch @@ -0,0 +1,846 @@ +From cfb6a115568ab24fe5df365d1436419b504111ec Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 6 Feb 2017 10:27:22 +0100 +Subject: [PATCH 10/15] sysdb: add certmap related calls +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add sysdb calls to write and read data for the certificate mapping +library to the cache. + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +--- + Makefile.am | 17 ++ + src/db/sysdb.h | 27 +++ + src/db/sysdb_certmap.c | 425 ++++++++++++++++++++++++++++++++++ + src/tests/cmocka/test_sysdb_certmap.c | 260 +++++++++++++++++++++ + 4 files changed, 729 insertions(+) + create mode 100644 src/db/sysdb_certmap.c + create mode 100644 src/tests/cmocka/test_sysdb_certmap.c + +diff --git a/Makefile.am b/Makefile.am +index f262cc24832358910dbb92ccd46f93c9eda8a295..bd0ca0d303e1742ad26c7648cd24e2c0135af34e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -254,6 +254,7 @@ if HAVE_CMOCKA + test_sysdb_ts_cache \ + test_sysdb_views \ + test_sysdb_subdomains \ ++ test_sysdb_certmap \ + test_sysdb_sudo \ + test_sysdb_utils \ + test_wbc_calls \ +@@ -974,6 +975,7 @@ libsss_util_la_SOURCES = \ + src/db/sysdb_ranges.c \ + src/db/sysdb_idmap.c \ + src/db/sysdb_gpo.c \ ++ src/db/sysdb_certmap.c \ + src/monitor/monitor_sbus.c \ + src/providers/dp_auth_util.c \ + src/providers/dp_pam_data_util.c \ +@@ -2773,6 +2775,21 @@ test_sysdb_subdomains_LDADD = \ + libsss_test_common.la \ + $(NULL) + ++test_sysdb_certmap_SOURCES = \ ++ src/tests/cmocka/test_sysdb_certmap.c \ ++ $(NULL) ++test_sysdb_certmap_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(NULL) ++test_sysdb_certmap_LDADD = \ ++ $(CMOCKA_LIBS) \ ++ $(LDB_LIBS) \ ++ $(POPT_LIBS) \ ++ $(TALLOC_LIBS) \ ++ $(SSSD_INTERNAL_LTLIBS) \ ++ libsss_test_common.la \ ++ $(NULL) ++ + test_sysdb_sudo_SOURCES = \ + src/tests/cmocka/test_sysdb_sudo.c \ + $(NULL) +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 3db22b3689bf6ffd9a48e29c229916e3fac9ca1b..0cbb2c5c02355e9e9a4e73b075f92d16e4855045 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -39,6 +39,7 @@ + #define SYSDB_NETGROUP_CONTAINER "cn=Netgroups" + #define SYSDB_RANGE_CONTAINER "cn=ranges" + #define SYSDB_VIEW_CONTAINER "cn=views" ++#define SYSDB_CERTMAP_CONTAINER "cn=certmap" + #define SYSDB_TMPL_USER_BASE SYSDB_USERS_CONTAINER","SYSDB_DOM_BASE + #define SYSDB_TMPL_GROUP_BASE SYSDB_GROUPS_CONTAINER","SYSDB_DOM_BASE + #define SYSDB_TMPL_CUSTOM_BASE SYSDB_CUSTOM_CONTAINER","SYSDB_DOM_BASE +@@ -46,6 +47,7 @@ + #define SYSDB_TMPL_RANGE_BASE SYSDB_RANGE_CONTAINER","SYSDB_BASE + #define SYSDB_TMPL_VIEW_BASE SYSDB_VIEW_CONTAINER","SYSDB_BASE + #define SYSDB_TMPL_VIEW_SEARCH_BASE "cn=%s,"SYSDB_TMPL_VIEW_BASE ++#define SYSDB_TMPL_CERTMAP_BASE SYSDB_CERTMAP_CONTAINER","SYSDB_BASE + + #define SYSDB_SUBDOMAIN_CLASS "subdomain" + #define SYSDB_USER_CLASS "user" +@@ -58,6 +60,7 @@ + #define SYSDB_ID_RANGE_CLASS "idRange" + #define SYSDB_DOMAIN_ID_RANGE_CLASS "domainIDRange" + #define SYSDB_TRUSTED_AD_DOMAIN_RANGE_CLASS "TrustedADDomainRange" ++#define SYSDB_CERTMAP_CLASS "certificateMappingRule" + + #define SYSDB_DN "dn" + #define SYSDB_NAME "name" +@@ -158,6 +161,12 @@ + #define SYSDB_DOMAIN_ID "domainID" + #define SYSDB_ID_RANGE_TYPE "idRangeType" + ++#define SYSDB_CERTMAP_PRIORITY "priority" ++#define SYSDB_CERTMAP_MATCHING_RULE "matchingRule" ++#define SYSDB_CERTMAP_MAPPING_RULE "mappingRule" ++#define SYSDB_CERTMAP_DOMAINS "domains" ++#define SYSDB_CERTMAP_USER_NAME_HINT "userNameHint" ++ + #define ORIGINALAD_PREFIX "originalAD" + #define OVERRIDE_PREFIX "override" + #define SYSDB_DEFAULT_OVERRIDE_NAME "defaultOverrideName" +@@ -264,6 +273,7 @@ + #define SYSDB_TMPL_CUSTOM SYSDB_NAME"=%s,cn=%s,"SYSDB_TMPL_CUSTOM_BASE + #define SYSDB_TMPL_RANGE SYSDB_NAME"=%s,"SYSDB_TMPL_RANGE_BASE + #define SYSDB_TMPL_OVERRIDE SYSDB_OVERRIDE_ANCHOR_UUID"=%s,"SYSDB_TMPL_VIEW_SEARCH_BASE ++#define SYSDB_TMPL_CERTMAP SYSDB_NAME"=%s,"SYSDB_TMPL_CERTMAP_BASE + + #define SYSDB_MOD_ADD LDB_FLAG_MOD_ADD + #define SYSDB_MOD_DEL LDB_FLAG_MOD_DELETE +@@ -320,6 +330,15 @@ struct range_info { + char *range_type; + }; + ++struct certmap_info { ++ char *name; ++ uint32_t priority; ++ char *match_rule; ++ char *map_rule; ++ const char **domains; ++}; ++ ++ + /* These attributes are stored in the timestamp cache */ + extern const char *sysdb_ts_cache_attrs[]; + +@@ -619,6 +638,14 @@ uint64_t sss_view_ldb_msg_find_attr_as_uint64(struct sss_domain_info *dom, + const char *attr_name, + uint64_t default_value); + ++errno_t sysdb_update_certmap(struct sysdb_ctx *sysdb, ++ struct certmap_info **certmaps, ++ bool user_name_hint); ++ ++errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, ++ struct certmap_info ***certmaps, ++ bool *user_name_hint); ++ + /* Sysdb initialization. + * call this function *only* once to initialize the database and get + * the sysdb ctx */ +diff --git a/src/db/sysdb_certmap.c b/src/db/sysdb_certmap.c +new file mode 100644 +index 0000000000000000000000000000000000000000..4917796b11c3967b4d147ebee7c7e83f09b872ce +--- /dev/null ++++ b/src/db/sysdb_certmap.c +@@ -0,0 +1,425 @@ ++/* ++ SSSD ++ ++ System Database - certificate mapping rules related calls ++ ++ Copyright (C) 2017 Sumit Bose ++ ++ 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 . ++*/ ++ ++ ++#include "util/util.h" ++#include "db/sysdb_private.h" ++ ++static errno_t sysdb_create_certmap_container(struct sysdb_ctx *sysdb, ++ bool user_name_hint) ++{ ++ struct ldb_message *msg = NULL; ++ errno_t ret; ++ ++ msg = ldb_msg_new(sysdb); ++ if (msg == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ msg->dn = ldb_dn_new(msg, sysdb->ldb, SYSDB_TMPL_CERTMAP_BASE); ++ if (msg->dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ret = ldb_msg_add_string(msg, "cn", "certmap"); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ ret = ldb_msg_add_string(msg, SYSDB_CERTMAP_USER_NAME_HINT, ++ user_name_hint ? "TRUE" : "FALSE"); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ /* do a synchronous add */ ++ ret = ldb_add(sysdb->ldb, msg); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to add certmap container (%d, [%s])!\n", ++ ret, ldb_errstring(sysdb->ldb)); ++ ret = EIO; ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(msg); ++ ++ return ret; ++} ++ ++static errno_t sysdb_certmap_add(struct sysdb_ctx *sysdb, ++ struct certmap_info *certmap) ++{ ++ struct ldb_message *msg; ++ struct ldb_message_element *el; ++ int ret; ++ TALLOC_CTX *tmp_ctx; ++ size_t c; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed"); ++ return ENOMEM; ++ } ++ ++ msg = ldb_msg_new(tmp_ctx); ++ if (msg == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ msg->dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, ++ SYSDB_TMPL_CERTMAP, certmap->name); ++ if (msg->dn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new_fmt failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_CERTMAP_CLASS); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_string failed.\n"); ++ goto done; ++ } ++ ++ ret = sysdb_add_string(msg, SYSDB_NAME, certmap->name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_string failed.\n"); ++ goto done; ++ } ++ ++ if (certmap->map_rule != NULL) { ++ ret = sysdb_add_string(msg, SYSDB_CERTMAP_MAPPING_RULE, ++ certmap->map_rule); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_string failed.\n"); ++ goto done; ++ } ++ } ++ ++ if (certmap->match_rule != NULL) { ++ ret = sysdb_add_string(msg, SYSDB_CERTMAP_MATCHING_RULE, ++ certmap->match_rule); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_string failed.\n"); ++ goto done; ++ } ++ } ++ ++ if (certmap->domains != NULL) { ++ for (c = 0; certmap->domains[c] != NULL; c++); ++ el = talloc_zero(tmp_ctx, struct ldb_message_element); ++ if (el == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ el->name = talloc_strdup(el, SYSDB_CERTMAP_DOMAINS); ++ if(el->name == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ el->num_values = c; ++ el->values = talloc_zero_array(el, struct ldb_val, c + 1); ++ if (el->values == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (c = 0; certmap->domains[c] != NULL; c++) { ++ el->values[c].data = (uint8_t *) talloc_strdup(el->values, ++ certmap->domains[c]); ++ if (el->values[c].data == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ el->values[c].length = strlen(certmap->domains[c]); ++ } ++ ++ ret = ldb_msg_add(msg, el, LDB_FLAG_MOD_ADD); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add failed.\n"); ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ } ++ ++ ret = sysdb_add_ulong(msg, SYSDB_CERTMAP_PRIORITY, ++ (unsigned long)certmap->priority); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_ulong failed.\n"); ++ goto done; ++ } ++ ++ ret = ldb_add(sysdb->ldb, msg); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_add failed.\n"); ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret) { ++ DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, sss_strerror(ret)); ++ } ++ talloc_zfree(tmp_ctx); ++ return ret; ++} ++ ++errno_t sysdb_update_certmap(struct sysdb_ctx *sysdb, ++ struct certmap_info **certmaps, ++ bool user_name_hint) ++{ ++ size_t c; ++ struct ldb_dn *container_dn = NULL; ++ bool in_transaction = false; ++ int ret; ++ int sret; ++ ++ if (certmaps == NULL) { ++ return EINVAL; ++ } ++ ++ container_dn = ldb_dn_new(sysdb, sysdb->ldb, SYSDB_TMPL_CERTMAP_BASE); ++ if (container_dn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n"); ++ return ENOMEM; ++ } ++ ++ ret = sysdb_transaction_start(sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_start failed.\n"); ++ goto done; ++ } ++ in_transaction = true; ++ ++ ret = sysdb_delete_recursive(sysdb, container_dn, true); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_delete_recursive failed.\n"); ++ goto done; ++ } ++ ret = sysdb_create_certmap_container(sysdb, user_name_hint); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_create_certmap_container failed.\n"); ++ goto done; ++ } ++ ++ for (c = 0; certmaps[c] != NULL; c++) { ++ ret = sysdb_certmap_add(sysdb, certmaps[c]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_certmap_add failed.\n"); ++ goto done; ++ } ++ } ++ ++ ret = sysdb_transaction_commit(sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_transaction_commit failed.\n"); ++ goto done; ++ } ++ in_transaction = false; ++ ++done: ++ if (in_transaction) { ++ sret = sysdb_transaction_cancel(sysdb); ++ if (sret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction.\n"); ++ } ++ } ++ ++ talloc_free(container_dn); ++ ++ return ret; ++} ++ ++errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, ++ struct certmap_info ***certmaps, bool *user_name_hint) ++{ ++ size_t c; ++ size_t d; ++ struct ldb_dn *container_dn = NULL; ++ int ret; ++ struct certmap_info **maps; ++ TALLOC_CTX *tmp_ctx = NULL; ++ struct ldb_result *res; ++ const char *tmp_str; ++ uint64_t tmp_uint; ++ struct ldb_message_element *tmp_el; ++ const char *attrs[] = {SYSDB_NAME, ++ SYSDB_CERTMAP_PRIORITY, ++ SYSDB_CERTMAP_MATCHING_RULE, ++ SYSDB_CERTMAP_MAPPING_RULE, ++ SYSDB_CERTMAP_DOMAINS, ++ NULL}; ++ const char *config_attrs[] = {SYSDB_CERTMAP_USER_NAME_HINT, ++ NULL}; ++ size_t num_values; ++ bool hint = false; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ container_dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_TMPL_CERTMAP_BASE); ++ if (container_dn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_search(sysdb->ldb, tmp_ctx, &res, container_dn, LDB_SCOPE_BASE, ++ config_attrs, SYSDB_CERTMAP_USER_NAME_HINT"=*"); ++ if (ret != LDB_SUCCESS || res->count != 1) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to read certmap config, skipping.\n"); ++ } else { ++ hint = ldb_msg_find_attr_as_bool(res->msgs[0], ++ SYSDB_CERTMAP_USER_NAME_HINT, false); ++ } ++ ++ ret = ldb_search(sysdb->ldb, tmp_ctx, &res, ++ container_dn, LDB_SCOPE_SUBTREE, ++ attrs, "objectclass=%s", SYSDB_CERTMAP_CLASS); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_search failed.\n"); ++ ret = EIO; ++ goto done; ++ } ++ ++ if (res->count == 0) { ++ DEBUG(SSSDBG_TRACE_FUNC, "No certificate maps found.\n"); ++ ret = ENOENT; ++ goto done; ++ } ++ ++ maps = talloc_zero_array(tmp_ctx, struct certmap_info *, res->count + 1); ++ if (maps == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (c = 0; c < res->count; c++) { ++ maps[c] = talloc_zero(maps, struct certmap_info); ++ if (maps[c] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ tmp_str = ldb_msg_find_attr_as_string(res->msgs[c], SYSDB_NAME, NULL); ++ if (tmp_str == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "The object [%s] doesn't have a name.\n", ++ ldb_dn_get_linearized(res->msgs[c]->dn)); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ maps[c]->name = talloc_strdup(maps, tmp_str); ++ if (maps[c]->name == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tmp_str = ldb_msg_find_attr_as_string(res->msgs[c], ++ SYSDB_CERTMAP_MAPPING_RULE, NULL); ++ if (tmp_str != NULL) { ++ maps[c]->map_rule = talloc_strdup(maps, tmp_str); ++ if (maps[c]->map_rule == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ tmp_str = ldb_msg_find_attr_as_string(res->msgs[c], ++ SYSDB_CERTMAP_MATCHING_RULE, NULL); ++ if (tmp_str != NULL) { ++ maps[c]->match_rule = talloc_strdup(maps, tmp_str); ++ if (maps[c]->match_rule == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ tmp_uint = ldb_msg_find_attr_as_uint64(res->msgs[c], ++ SYSDB_CERTMAP_PRIORITY, ++ (uint64_t) -1); ++ if (tmp_uint != (uint64_t) -1) { ++ if (tmp_uint >= UINT32_MAX) { ++ DEBUG(SSSDBG_OP_FAILURE, "Priority value [%lu] too large.\n", ++ (unsigned long) tmp_uint); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ maps[c]->priority = (uint32_t) tmp_uint; ++ } ++ ++ tmp_el = ldb_msg_find_element(res->msgs[c], SYSDB_CERTMAP_DOMAINS); ++ if (tmp_el != NULL) { ++ num_values = tmp_el->num_values; ++ } else { ++ num_values = 0; ++ } ++ ++ maps[c]->domains = talloc_zero_array(maps[c], const char *, ++ num_values + 1); ++ if (maps[c]->domains == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (d = 0; d < num_values; d++) { ++ maps[c]->domains[d] = talloc_strndup(maps[c]->domains, ++ (char *) tmp_el->values[d].data, ++ tmp_el->values[d].length); ++ if (maps[c]->domains[d] == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ } ++ ++ *certmaps = talloc_steal(mem_ctx, maps); ++ *user_name_hint = hint; ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ ++ return ret; ++} +diff --git a/src/tests/cmocka/test_sysdb_certmap.c b/src/tests/cmocka/test_sysdb_certmap.c +new file mode 100644 +index 0000000000000000000000000000000000000000..fb07165561779226935f436c308c85abfc305635 +--- /dev/null ++++ b/src/tests/cmocka/test_sysdb_certmap.c +@@ -0,0 +1,260 @@ ++/* ++ SSSD ++ ++ sysdb_certmap - Tests for sysdb certmap realted calls ++ ++ Authors: ++ Jakub Hrozek ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "tests/cmocka/common_mock.h" ++#include "tests/common.h" ++ ++#define TESTS_PATH "certmap_" BASE_FILE_STEM ++#define TEST_CONF_DB "test_sysdb_certmap.ldb" ++#define TEST_ID_PROVIDER "ldap" ++#define TEST_DOM_NAME "certmap_test" ++ ++struct certmap_test_ctx { ++ struct sss_test_ctx *tctx; ++}; ++ ++static int test_sysdb_setup(void **state) ++{ ++ struct certmap_test_ctx *test_ctx; ++ struct sss_test_conf_param params[] = { ++ { NULL, NULL }, /* Sentinel */ ++ }; ++ ++ assert_true(leak_check_setup()); ++ ++ test_ctx = talloc_zero(global_talloc_context, ++ struct certmap_test_ctx); ++ assert_non_null(test_ctx); ++ check_leaks_push(test_ctx); ++ ++ test_dom_suite_setup(TESTS_PATH); ++ ++ test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, ++ TEST_CONF_DB, TEST_DOM_NAME, ++ TEST_ID_PROVIDER, params); ++ assert_non_null(test_ctx->tctx); ++ ++ *state = test_ctx; ++ return 0; ++} ++ ++static int test_sysdb_teardown(void **state) ++{ ++ struct certmap_test_ctx *test_ctx = ++ talloc_get_type(*state, struct certmap_test_ctx); ++ ++ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME); ++ talloc_free(test_ctx->tctx); ++ assert_true(check_leaks_pop(test_ctx)); ++ talloc_free(test_ctx); ++ assert_true(leak_check_teardown()); ++ return 0; ++} ++ ++static void test_sysdb_get_certmap_not_exists(void **state) ++{ ++ int ret; ++ struct certmap_info **certmap; ++ bool user_name_hint; ++ struct certmap_test_ctx *ctctx = talloc_get_type(*state, ++ struct certmap_test_ctx); ++ ++ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, ++ &user_name_hint); ++ assert_int_equal(ret, ENOENT); ++ ++} ++ ++static void check_certmap(struct certmap_info *m, struct certmap_info *r, ++ size_t exp_domains) ++{ ++ size_t d; ++ ++ assert_non_null(r); ++ assert_non_null(m); ++ assert_string_equal(m->name, r->name); ++ ++ if (r->map_rule == NULL) { ++ assert_null(m->map_rule); ++ } else { ++ assert_string_equal(m->map_rule, r->map_rule); ++ } ++ ++ if (r->match_rule == NULL) { ++ assert_null(m->match_rule); ++ } else { ++ assert_string_equal(m->match_rule, r->match_rule); ++ } ++ ++ assert_int_equal(m->priority, r->priority); ++ assert_non_null(m->domains); ++ if (r->domains == NULL) { ++ assert_null(m->domains[0]); ++ } else { ++ for (d = 0; r->domains[d]; d++) { ++ assert_non_null(m->domains[d]); ++ assert_true(string_in_list(m->domains[d], discard_const(r->domains), ++ true)); ++ } ++ ++ assert_int_equal(d, exp_domains); ++ } ++ ++} ++ ++static void test_sysdb_update_certmap(void **state) ++{ ++ int ret; ++ const char *domains[] = { "dom1.test", "dom2.test", "dom3.test", NULL }; ++ struct certmap_info map_a = { discard_const("map_a"), 11, discard_const("abc"), discard_const("def"), NULL }; ++ struct certmap_info map_b = { discard_const("map_b"), 22, discard_const("abc"), NULL, domains }; ++ struct certmap_info *certmap_empty[] = { NULL }; ++ struct certmap_info *certmap_a[] = { &map_a, NULL }; ++ struct certmap_info *certmap_b[] = { &map_b, NULL }; ++ struct certmap_info *certmap_ab[] = { &map_a, &map_b, NULL }; ++ struct certmap_info **certmap; ++ struct certmap_test_ctx *ctctx = talloc_get_type(*state, ++ struct certmap_test_ctx); ++ bool user_name_hint; ++ ++ ret = sysdb_update_certmap(ctctx->tctx->sysdb, NULL, false); ++ assert_int_equal(ret, EINVAL); ++ ++ ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_empty, false); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, ++ &user_name_hint); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_a, false); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, ++ &user_name_hint); ++ assert_int_equal(ret, EOK); ++ assert_false(user_name_hint); ++ assert_non_null(certmap); ++ assert_non_null(certmap[0]); ++ assert_string_equal(certmap[0]->name, map_a.name); ++ assert_string_equal(certmap[0]->map_rule, map_a.map_rule); ++ assert_string_equal(certmap[0]->match_rule, map_a.match_rule); ++ assert_int_equal(certmap[0]->priority, map_a.priority); ++ assert_non_null(certmap[0]->domains); ++ assert_null(certmap[0]->domains[0]); ++ assert_null(certmap[1]); ++ check_certmap(certmap[0], &map_a, 0); ++ talloc_free(certmap); ++ ++ ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_b, true); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, ++ &user_name_hint); ++ assert_int_equal(ret, EOK); ++ assert_true(user_name_hint); ++ assert_non_null(certmap); ++ assert_non_null(certmap[0]); ++ ++ check_certmap(certmap[0], &map_b, 3); ++ assert_null(certmap[1]); ++ talloc_free(certmap); ++ ++ ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_ab, false); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, ++ &user_name_hint); ++ assert_int_equal(ret, EOK); ++ assert_false(user_name_hint); ++ assert_non_null(certmap); ++ assert_non_null(certmap[0]); ++ assert_non_null(certmap[1]); ++ assert_null(certmap[2]); ++ if (strcmp(certmap[0]->name, "map_a") == 0) { ++ check_certmap(certmap[0], &map_a, 0); ++ check_certmap(certmap[1], &map_b, 3); ++ } else { ++ check_certmap(certmap[0], &map_b, 3); ++ check_certmap(certmap[1], &map_a, 0); ++ } ++ talloc_free(certmap); ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ int rv; ++ int no_cleanup = 0; ++ poptContext pc; ++ int opt; ++ struct poptOption long_options[] = { ++ POPT_AUTOHELP ++ SSSD_DEBUG_OPTS ++ {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0, ++ _("Do not delete the test database after a test run"), NULL }, ++ POPT_TABLEEND ++ }; ++ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test_setup_teardown(test_sysdb_get_certmap_not_exists, ++ test_sysdb_setup, ++ test_sysdb_teardown), ++ cmocka_unit_test_setup_teardown(test_sysdb_update_certmap, ++ test_sysdb_setup, ++ test_sysdb_teardown), ++ }; ++ ++ /* Set debug level to invalid value so we can deside if -d 0 was used. */ ++ debug_level = SSSDBG_INVALID; ++ ++ pc = poptGetContext(argv[0], argc, argv, long_options, 0); ++ while((opt = poptGetNextOpt(pc)) != -1) { ++ switch(opt) { ++ default: ++ fprintf(stderr, "\nInvalid option %s: %s\n\n", ++ poptBadOption(pc, 0), poptStrerror(opt)); ++ poptPrintUsage(pc, stderr, 0); ++ return 1; ++ } ++ } ++ poptFreeContext(pc); ++ ++ DEBUG_CLI_INIT(debug_level); ++ ++ tests_set_cwd(); ++ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, LOCAL_SYSDB_FILE); ++ test_dom_suite_setup(TESTS_PATH); ++ rv = cmocka_run_group_tests(tests, NULL, NULL); ++ ++ if (rv == 0 && no_cleanup == 0) { ++ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, LOCAL_SYSDB_FILE); ++ } ++ return rv; ++} +-- +2.9.3 + diff --git a/SOURCES/0011-IPA-add-certmap-support.patch b/SOURCES/0011-IPA-add-certmap-support.patch new file mode 100644 index 0000000..d2b8ff6 --- /dev/null +++ b/SOURCES/0011-IPA-add-certmap-support.patch @@ -0,0 +1,484 @@ +From d51754859a83e7fedf0cac90ad8bf5de09f35463 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 6 Feb 2017 10:28:46 +0100 +Subject: [PATCH 11/15] IPA: add certmap support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Read certificate mapping data from the IPA server and configure the +certificate mapping library accordingly. + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +--- + src/providers/ipa/ipa_config.h | 2 + + src/providers/ipa/ipa_subdomains.c | 354 ++++++++++++++++++++++++++++++ + src/providers/ipa/ipa_subdomains_server.c | 4 + + src/providers/ldap/ldap_id.c | 4 +- + src/providers/ldap/sdap.h | 4 + + 5 files changed, 367 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ipa/ipa_config.h b/src/providers/ipa/ipa_config.h +index 2f1e147d7edab0aca2a16269c6a73bc607b21bd5..60f2d5d7b71227a1d86889ceaf6f0f9ac868480d 100644 +--- a/src/providers/ipa/ipa_config.h ++++ b/src/providers/ipa/ipa_config.h +@@ -37,6 +37,8 @@ + #define IPA_CONFIG_SEARCH_BASE_TEMPLATE "cn=etc,%s" + #define IPA_CONFIG_FILTER "(&(cn=ipaConfig)(objectClass=ipaGuiConfig))" + ++#define IPA_OC_CONFIG "ipaConfig" ++ + struct tevent_req * ipa_get_config_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sdap_handle *sh, +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index b2e96b204213a52014edcc6042ffa1ff8152b8bf..7537550606ef09c0b87a80932c75aa4f93c0efab 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -56,6 +56,24 @@ + + #define IPA_SUBDOMAIN_DISABLED_PERIOD 3600 + ++#define IPA_OC_CERTMAP_CONFIG_OBJECT "ipaCertMapConfigObject" ++#define IPA_CERTMAP_PROMPT_USERNAME "ipaCertMapPromptUserName" ++ ++#define IPA_OC_CERTMAP_RULE "ipaCertMapRule" ++#define IPA_CERTMAP_MAPRULE "ipaCertMapMapRule" ++#define IPA_CERTMAP_MATCHRULE "ipaCertMapMatchRule" ++#define IPA_CERTMAP_PRIORITY "ipaCertMapPriority" ++#define IPA_ENABLED_FLAG "ipaEnabledFlag" ++#define IPA_TRUE_VALUE "TRUE" ++#define IPA_ASSOCIATED_DOMAIN "associatedDomain" ++ ++#define OBJECTCLASS "objectClass" ++ ++#define CERTMAP_FILTER "(|(&("OBJECTCLASS"="IPA_OC_CERTMAP_RULE")" \ ++ "("IPA_ENABLED_FLAG"="IPA_TRUE_VALUE"))" \ ++ "("OBJECTCLASS"="IPA_OC_CERTMAP_CONFIG_OBJECT"))" ++ ++ + struct ipa_subdomains_ctx { + struct be_ctx *be_ctx; + struct ipa_id_ctx *ipa_id_ctx; +@@ -286,6 +304,193 @@ done: + return ret; + } + ++struct priv_sss_debug { ++ int level; ++}; ++ ++void ext_debug(void *private, const char *file, long line, const char *function, ++ const char *format, ...) ++{ ++ va_list ap; ++ struct priv_sss_debug *data = private; ++ int level = SSSDBG_OP_FAILURE; ++ ++ if (data != NULL) { ++ level = data->level; ++ } ++ ++ if (DEBUG_IS_SET(level)) { ++ va_start(ap, format); ++ sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED, ++ format, ap); ++ va_end(ap); ++ } ++} ++ ++static errno_t ipa_certmap_parse_results(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ struct sdap_options *sdap_opts, ++ size_t count, ++ struct sysdb_attrs **reply, ++ struct certmap_info ***_certmap_list) ++{ ++ struct certmap_info **certmap_list = NULL; ++ struct certmap_info *m; ++ const char *value; ++ const char **values; ++ size_t c; ++ size_t lc = 0; ++ int ret; ++ struct sss_certmap_ctx *certmap_ctx = NULL; ++ const char **ocs = NULL; ++ bool user_name_hint = false; ++ ++ certmap_list = talloc_zero_array(mem_ctx, struct certmap_info *, count + 1); ++ if (certmap_list == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n"); ++ return ENOMEM; ++ } ++ ++ for (c = 0; c < count; c++) { ++ ret = sysdb_attrs_get_string_array(reply[c], SYSDB_OBJECTCLASS, mem_ctx, ++ &ocs); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing objectclasses for config objects.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ if (string_in_list(IPA_OC_CERTMAP_CONFIG_OBJECT, discard_const(ocs), ++ false)) { ++ ret = sysdb_attrs_get_bool(reply[c], IPA_CERTMAP_PROMPT_USERNAME, ++ &user_name_hint); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to read user name hint option, skipping.\n"); ++ } ++ continue; ++ } ++ ++ m = talloc_zero(certmap_list, struct certmap_info); ++ if (m == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_attrs_get_string(reply[c], IPA_CN, &value); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); ++ goto done; ++ } ++ ++ m->name = talloc_strdup(m, value); ++ if (m->name == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_attrs_get_string(reply[c], IPA_CERTMAP_MATCHRULE, &value); ++ if (ret == EOK) { ++ m->match_rule = talloc_strdup(m, value); ++ if (m->match_rule == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ } else if (ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); ++ goto done; ++ } ++ ++ ret = sysdb_attrs_get_string(reply[c], IPA_CERTMAP_MAPRULE, &value); ++ if (ret == EOK) { ++ m->map_rule = talloc_strdup(m, value); ++ if (m->map_rule == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ } else if (ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); ++ goto done; ++ } ++ ++ ret = sysdb_attrs_get_string_array(reply[c], IPA_ASSOCIATED_DOMAIN, m, ++ &values); ++ if (ret == EOK) { ++ m->domains = values; ++ } else if (ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); ++ goto done; ++ } ++ ++ ret = sysdb_attrs_get_uint32_t(reply[c], IPA_CERTMAP_PRIORITY, ++ &m->priority); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); ++ goto done; ++ } else if (ret == ENOENT) { ++ m->priority = SSS_CERTMAP_MIN_PRIO; ++ } ++ ++ certmap_list[lc++] = m; ++ } ++ ++ certmap_list[lc] = NULL; ++ ++ ret = sss_certmap_init(mem_ctx, ext_debug, NULL, &certmap_ctx); ++ if (ret != 0) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_init failed.\n"); ++ goto done; ++ } ++ ++ for (c = 0; certmap_list[c] != NULL; c++) { ++ DEBUG(SSSDBG_TRACE_ALL, "Trying to add rule [%s][%d][%s][%s].\n", ++ certmap_list[c]->name, ++ certmap_list[c]->priority, ++ certmap_list[c]->match_rule, ++ certmap_list[c]->map_rule); ++ ++ ret = sss_certmap_add_rule(certmap_ctx, certmap_list[c]->priority, ++ certmap_list[c]->match_rule, ++ certmap_list[c]->map_rule, ++ certmap_list[c]->domains); ++ if (ret != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_certmap_add_rule failed for rule [%s], skipping. " ++ "Please check for typos and if rule syntax is supported.\n", ++ certmap_list[c]->name); ++ goto done; ++ } ++ } ++ ++ ret = sysdb_update_certmap(domain->sysdb, certmap_list, user_name_hint); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_certmap failed"); ++ goto done; ++ } ++ ++ sss_certmap_free_ctx(sdap_opts->certmap_ctx); ++ sdap_opts->certmap_ctx = talloc_steal(sdap_opts, certmap_ctx); ++ ++ if (_certmap_list != NULL) { ++ *_certmap_list = certmap_list; ++ } ++ ret = EOK; ++ ++done: ++ talloc_free(ocs); ++ if (ret != EOK) { ++ sss_certmap_free_ctx(certmap_ctx); ++ talloc_free(certmap_list); ++ } ++ ++ return ret; ++} ++ + static errno_t ipa_subdom_enumerates(struct sss_domain_info *parent, + struct sysdb_attrs *attrs, + bool *_enumerates) +@@ -801,6 +1006,125 @@ static errno_t ipa_subdomains_ranges_recv(struct tevent_req *req) + return EOK; + } + ++#define IPA_CERTMAP_SEARCH_BASE_TEMPLATE "cn=certmap,%s" ++ ++struct ipa_subdomains_certmap_state { ++ struct sss_domain_info *domain; ++ struct sdap_options *sdap_opts; ++}; ++ ++static void ipa_subdomains_certmap_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++ipa_subdomains_certmap_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ipa_subdomains_ctx *sd_ctx, ++ struct sdap_handle *sh) ++{ ++ struct ipa_subdomains_certmap_state *state; ++ struct tevent_req *subreq; ++ struct tevent_req *req; ++ errno_t ret; ++ char *ldap_basedn; ++ char *search_base; ++ const char *attrs[] = { OBJECTCLASS, IPA_CN, ++ IPA_CERTMAP_MAPRULE, IPA_CERTMAP_MATCHRULE, ++ IPA_CERTMAP_PRIORITY, IPA_ASSOCIATED_DOMAIN, ++ IPA_CERTMAP_PROMPT_USERNAME, ++ NULL }; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct ipa_subdomains_certmap_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ state->domain = sd_ctx->be_ctx->domain; ++ state->sdap_opts = sd_ctx->sdap_id_ctx->opts; ++ ++ ret = domain_to_basedn(state, state->domain->name, &ldap_basedn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "domain_to_basedn failed.\n"); ++ goto immediately; ++ } ++ ++ search_base = talloc_asprintf(state, IPA_CERTMAP_SEARCH_BASE_TEMPLATE, ++ ldap_basedn); ++ if (search_base == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ subreq = sdap_get_generic_send(state, ev, sd_ctx->sdap_id_ctx->opts, sh, ++ search_base, LDAP_SCOPE_SUBTREE, ++ CERTMAP_FILTER, ++ attrs, NULL, 0, 0, false); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_subdomains_certmap_done, req); ++ ++ return req; ++ ++immediately: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ ++ return req; ++} ++ ++static void ipa_subdomains_certmap_done(struct tevent_req *subreq) ++{ ++ struct ipa_subdomains_certmap_state *state; ++ struct tevent_req *req; ++ struct sysdb_attrs **reply; ++ size_t reply_count; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_subdomains_certmap_state); ++ ++ ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get data from LDAP [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = ipa_certmap_parse_results(state, state->domain, ++ state->sdap_opts, ++ reply_count, reply, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to parse certmap results [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++static errno_t ipa_subdomains_certmap_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} ++ + struct ipa_subdomains_master_state { + struct sss_domain_info *domain; + struct ipa_options *ipa_options; +@@ -1365,6 +1689,7 @@ struct ipa_subdomains_refresh_state { + static errno_t ipa_subdomains_refresh_retry(struct tevent_req *req); + static void ipa_subdomains_refresh_connect_done(struct tevent_req *subreq); + static void ipa_subdomains_refresh_ranges_done(struct tevent_req *subreq); ++static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq); + static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq); + static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq); + static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq); +@@ -1487,6 +1812,35 @@ static void ipa_subdomains_refresh_ranges_done(struct tevent_req *subreq) + return; + } + ++ subreq = ipa_subdomains_certmap_send(state, state->ev, state->sd_ctx, ++ sdap_id_op_handle(state->sdap_op)); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_subdomains_refresh_certmap_done, req); ++ return; ++} ++ ++static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq) ++{ ++ struct ipa_subdomains_refresh_state *state; ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_subdomains_refresh_state); ++ ++ ret = ipa_subdomains_certmap_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to read certificate mapping rules " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ + subreq = ipa_subdomains_master_send(state, state->ev, state->sd_ctx, + sdap_id_op_handle(state->sdap_op)); + if (subreq == NULL) { +diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c +index 1af8676c5a9c49121d0f0118a46796c6637f04f9..ae3baf036e4278fb67d86b42742fb7e80b46724e 100644 +--- a/src/providers/ipa/ipa_subdomains_server.c ++++ b/src/providers/ipa/ipa_subdomains_server.c +@@ -362,6 +362,10 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx, + ad_id_ctx->sdap_id_ctx->opts->idmap_ctx = + id_ctx->sdap_id_ctx->opts->idmap_ctx; + ++ /* Set up the certificate mapping context */ ++ ad_id_ctx->sdap_id_ctx->opts->certmap_ctx = ++ id_ctx->sdap_id_ctx->opts->certmap_ctx; ++ + *_ad_id_ctx = ad_id_ctx; + return EOK; + } +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index 8e60769d09383ac8ebe33e5f64fd4fd9788e82cd..0bee0ca8d71abece6749fdb8393b9ceacb64417d 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -247,7 +247,9 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + } + + ret = sss_cert_derb64_to_ldap_filter(state, filter_value, attr_name, +- NULL, NULL, &user_filter); ++ ctx->opts->certmap_ctx, ++ state->domain, ++ &user_filter); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "sss_cert_derb64_to_ldap_filter failed.\n"); +diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h +index 6079a8bf62d0bdf23c8d462dc0f19c705e391a6e..afdc01948eefe9dda943c8c7ad01a42dd76a1da8 100644 +--- a/src/providers/ldap/sdap.h ++++ b/src/providers/ldap/sdap.h +@@ -25,6 +25,7 @@ + #include "providers/backend.h" + #include + #include "util/sss_ldap.h" ++#include "lib/certmap/sss_certmap.h" + + struct sdap_msg { + struct sdap_msg *next; +@@ -478,6 +479,9 @@ struct sdap_options { + + bool support_matching_rule; + enum dc_functional_level dc_functional_level; ++ ++ /* Certificate mapping support */ ++ struct sss_certmap_ctx *certmap_ctx; + }; + + struct sdap_server_opts { +-- +2.9.3 + diff --git a/SOURCES/0011-nss-srv-tests-Fix-prototype-of-wrapped-ncache-functi.patch b/SOURCES/0011-nss-srv-tests-Fix-prototype-of-wrapped-ncache-functi.patch deleted file mode 100644 index eafe318..0000000 --- a/SOURCES/0011-nss-srv-tests-Fix-prototype-of-wrapped-ncache-functi.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 721f83fa5661c861674c17edbb309bb9ade15892 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Mon, 4 Jul 2016 14:08:46 +0200 -Subject: [PATCH 11/14] nss-srv-tests: Fix prototype of wrapped ncache - functions -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The argument ttl was recently removed from negative cache functions -(sss_ncache_check_user, sss_ncache_check_uid, sss_ncache_check_sid, -sss_ncache_check_cert) but it was not removed from wrapped versions -in nss-srv-tests. It caused a crash on machine with big endian -and when configure wih --coverage. - -Reviewed-by: Pavel Březina -(cherry picked from commit 35567de112cd5d82acb582cbdb44c8652bbdfda1) ---- - src/tests/cmocka/test_nss_srv.c | 28 ++++++++++++---------------- - 1 file changed, 12 insertions(+), 16 deletions(-) - -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index 5e0398f20b9906df39371826e50a9c78675dfa74..4137e9151be561a57a8f2e674f385ecb37119255 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -151,60 +151,56 @@ int __wrap_sss_cmd_send_empty(struct cli_ctx *cctx, TALLOC_CTX *freectx) - } - - /* Intercept negative cache lookups */ --int __real_sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl, -+int __real_sss_ncache_check_user(struct sss_nc_ctx *ctx, - struct sss_domain_info *dom, const char *name); - --int __wrap_sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl, -+int __wrap_sss_ncache_check_user(struct sss_nc_ctx *ctx, - struct sss_domain_info *dom, const char *name) - { - int ret; - -- ret = __real_sss_ncache_check_user(ctx, ttl, dom, name); -+ ret = __real_sss_ncache_check_user(ctx, dom, name); - if (ret == EEXIST) { - nss_test_ctx->ncache_hits++; - } - return ret; - } - --int __real_sss_ncache_check_uid(struct sss_nc_ctx *ctx, int ttl, -+int __real_sss_ncache_check_uid(struct sss_nc_ctx *ctx, - struct sss_domain_info *dom, uid_t uid); - --int __wrap_sss_ncache_check_uid(struct sss_nc_ctx *ctx, int ttl, -+int __wrap_sss_ncache_check_uid(struct sss_nc_ctx *ctx, - struct sss_domain_info *dom, uid_t uid) - { - int ret; - -- ret = __real_sss_ncache_check_uid(ctx, ttl, dom, uid); -+ ret = __real_sss_ncache_check_uid(ctx, dom, uid); - if (ret == EEXIST) { - nss_test_ctx->ncache_hits++; - } - return ret; - } - --int __real_sss_ncache_check_sid(struct sss_nc_ctx *ctx, -- int ttl, const char *sid); -+int __real_sss_ncache_check_sid(struct sss_nc_ctx *ctx, const char *sid); - --int __wrap_sss_ncache_check_sid(struct sss_nc_ctx *ctx, -- int ttl, const char *sid) -+int __wrap_sss_ncache_check_sid(struct sss_nc_ctx *ctx, const char *sid) - { - int ret; - -- ret = __real_sss_ncache_check_sid(ctx, ttl, sid); -+ ret = __real_sss_ncache_check_sid(ctx, sid); - if (ret == EEXIST) { - nss_test_ctx->ncache_hits++; - } - return ret; - } - --int __real_sss_ncache_check_cert(struct sss_nc_ctx *ctx, -- int ttl, const char *cert); -+int __real_sss_ncache_check_cert(struct sss_nc_ctx *ctx, const char *cert); - --int __wrap_sss_ncache_check_cert(struct sss_nc_ctx *ctx, -- int ttl, const char *cert) -+int __wrap_sss_ncache_check_cert(struct sss_nc_ctx *ctx, const char *cert) - { - int ret; - -- ret = __real_sss_ncache_check_cert(ctx, ttl, cert); -+ ret = __real_sss_ncache_check_cert(ctx, cert); - if (ret == EEXIST) { - nss_test_ctx->ncache_hits++; - } --- -2.4.11 - diff --git a/SOURCES/0012-TOOLS-Prevent-dereference-of-null-pointer.patch b/SOURCES/0012-TOOLS-Prevent-dereference-of-null-pointer.patch deleted file mode 100644 index 8ff9bfb..0000000 --- a/SOURCES/0012-TOOLS-Prevent-dereference-of-null-pointer.patch +++ /dev/null @@ -1,139 +0,0 @@ -From be811502403246414b99f3a8834355c53f6f0511 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Mon, 6 Jun 2016 18:15:44 +0200 -Subject: [PATCH 12/14] TOOLS: Prevent dereference of null pointer -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -VAR_CHECK is called with (var, EOK, ...) -EOK would be returned in case of "var != EOK" -and output argument _attrs would not be initialized. -Therefore there could be dereference of null pointer -after calling function usermod_build_attrs. - -Reviewed-by: Pavel Březina -(cherry picked from commit f9d3aec54d19a771a6eafe09ba6d445cc094bfae) ---- - src/tools/sss_sync_ops.c | 63 +++++++++++++++++++++--------------------------- - 1 file changed, 28 insertions(+), 35 deletions(-) - -diff --git a/src/tools/sss_sync_ops.c b/src/tools/sss_sync_ops.c -index 7f2e3ea85d5874e3c40f53f327b400e38e430228..a23a0b8c30366d2fb68554bfed184b8fce675e2b 100644 ---- a/src/tools/sss_sync_ops.c -+++ b/src/tools/sss_sync_ops.c -@@ -37,13 +37,6 @@ - #define ATTR_NAME_SEP '=' - #define ATTR_VAL_SEP ',' - --#define VAR_CHECK(var, val, attr, msg) do { \ -- if (var != (val)) { \ -- DEBUG(SSSDBG_CRIT_FAILURE, msg" attribute: %s\n", attr); \ -- return val; \ -- } \ --} while(0) -- - static int attr_name_val_split(TALLOC_CTX *mem_ctx, const char *nameval, - char **_name, char ***_values, int *_nvals) - { -@@ -200,8 +193,9 @@ static int usermod_build_attrs(TALLOC_CTX *mem_ctx, - int lock, - struct sysdb_attrs **_attrs) - { -- int ret; -+ int ret = EOK; - struct sysdb_attrs *attrs; -+ const char *attr_name = NULL; - - attrs = sysdb_new_attrs(mem_ctx); - if (attrs == NULL) { -@@ -209,60 +203,59 @@ static int usermod_build_attrs(TALLOC_CTX *mem_ctx, - } - - if (shell) { -+ attr_name = SYSDB_SHELL; - ret = sysdb_attrs_add_string(attrs, -- SYSDB_SHELL, -+ attr_name, - shell); -- VAR_CHECK(ret, EOK, SYSDB_SHELL, -- "Could not add attribute to changeset\n"); - } - -- if (home) { -+ if (ret == EOK && home) { -+ attr_name = SYSDB_HOMEDIR; - ret = sysdb_attrs_add_string(attrs, -- SYSDB_HOMEDIR, -+ attr_name, - home); -- VAR_CHECK(ret, EOK, SYSDB_HOMEDIR, -- "Could not add attribute to changeset\n"); - } - -- if (gecos) { -+ if (ret == EOK && gecos) { -+ attr_name = SYSDB_GECOS; - ret = sysdb_attrs_add_string(attrs, -- SYSDB_GECOS, -+ attr_name, - gecos); -- VAR_CHECK(ret, EOK, SYSDB_GECOS, -- "Could not add attribute to changeset\n"); - } - -- if (uid) { -+ if (ret == EOK && uid) { -+ attr_name = SYSDB_UIDNUM; - ret = sysdb_attrs_add_long(attrs, -- SYSDB_UIDNUM, -+ attr_name, - uid); -- VAR_CHECK(ret, EOK, SYSDB_UIDNUM, -- "Could not add attribute to changeset\n"); - } - -- if (gid) { -+ if (ret == EOK && gid) { -+ attr_name = SYSDB_GIDNUM; - ret = sysdb_attrs_add_long(attrs, -- SYSDB_GIDNUM, -+ attr_name, - gid); -- VAR_CHECK(ret, EOK, SYSDB_GIDNUM, -- "Could not add attribute to changeset\n"); - } - -- if (lock == DO_LOCK) { -+ if (ret == EOK && lock == DO_LOCK) { -+ attr_name = SYSDB_DISABLED; - ret = sysdb_attrs_add_string(attrs, -- SYSDB_DISABLED, -+ attr_name, - "true"); -- VAR_CHECK(ret, EOK, SYSDB_DISABLED, -- "Could not add attribute to changeset\n"); - } - -- if (lock == DO_UNLOCK) { -+ if (ret == EOK && lock == DO_UNLOCK) { -+ attr_name = SYSDB_DISABLED; - /* PAM code checks for 'false' value in SYSDB_DISABLED attribute */ - ret = sysdb_attrs_add_string(attrs, -- SYSDB_DISABLED, -+ attr_name, - "false"); -- VAR_CHECK(ret, EOK, SYSDB_DISABLED, -- "Could not add attribute to changeset\n"); -+ } -+ -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Could not add attribute [%s] to changeset.\n", attr_name); -+ return ret; - } - - *_attrs = attrs; --- -2.4.11 - diff --git a/SOURCES/0012-nss-idmap-add-sss_nss_getlistbycert.patch b/SOURCES/0012-nss-idmap-add-sss_nss_getlistbycert.patch new file mode 100644 index 0000000..f879ce1 --- /dev/null +++ b/SOURCES/0012-nss-idmap-add-sss_nss_getlistbycert.patch @@ -0,0 +1,736 @@ +From f2a81a22124e93a026ec0f06b77eab50998ecba5 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 15 Mar 2017 14:21:26 +0100 +Subject: [PATCH 12/15] nss-idmap: add sss_nss_getlistbycert() + +This patch adds a getlistbycert() call to libsss_nss_idmap to make it on +par with InfoPipe. + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +--- + Makefile.am | 2 +- + src/python/pysss_nss_idmap.c | 103 ++++++++++++++++++- + src/responder/nss/nss_cmd.c | 7 ++ + src/responder/nss/nss_protocol.h | 6 ++ + src/responder/nss/nss_protocol_sid.c | 63 ++++++++++++ + src/sss_client/idmap/sss_nss_idmap.c | 110 +++++++++++++++++++- + src/sss_client/idmap/sss_nss_idmap.exports | 6 ++ + src/sss_client/idmap/sss_nss_idmap.h | 17 +++- + src/sss_client/sss_cli.h | 5 + + src/tests/cmocka/test_nss_srv.c | 158 +++++++++++++++++++++++++++++ + 10 files changed, 471 insertions(+), 6 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index bd0ca0d303e1742ad26c7648cd24e2c0135af34e..7516338bc6fd95045d20db8155a0c82fd7003358 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1128,7 +1128,7 @@ libsss_nss_idmap_la_LIBADD = \ + $(CLIENT_LIBS) + libsss_nss_idmap_la_LDFLAGS = \ + -Wl,--version-script,$(srcdir)/src/sss_client/idmap/sss_nss_idmap.exports \ +- -version-info 2:0:2 ++ -version-info 3:0:3 + + dist_noinst_DATA += src/sss_client/idmap/sss_nss_idmap.exports + +diff --git a/src/python/pysss_nss_idmap.c b/src/python/pysss_nss_idmap.c +index c57cc10a86a7a9a22a791c1eae027a1aafa8f780..2e5851c7a6e48629fd93e428aada499fcbe36ebb 100644 +--- a/src/python/pysss_nss_idmap.c ++++ b/src/python/pysss_nss_idmap.c +@@ -36,9 +36,37 @@ enum lookup_type { + SIDBYID, + NAMEBYSID, + IDBYSID, +- NAMEBYCERT ++ NAMEBYCERT, ++ LISTBYCERT + }; + ++static int add_dict_to_list(PyObject *py_list, PyObject *res_type, ++ PyObject *res, PyObject *id_type) ++{ ++ int ret; ++ PyObject *py_dict; ++ ++ py_dict = PyDict_New(); ++ if (py_dict == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = PyDict_SetItem(py_dict, res_type, res); ++ if (ret != 0) { ++ Py_XDECREF(py_dict); ++ return ret; ++ } ++ ++ ret = PyDict_SetItem(py_dict, PyBytes_FromString(SSS_TYPE_KEY), id_type); ++ if (ret != 0) { ++ Py_XDECREF(py_dict); ++ return ret; ++ } ++ ++ ret = PyList_Append(py_list, py_dict); ++ ++ return ret; ++} + static int add_dict(PyObject *py_result, PyObject *key, PyObject *res_type, + PyObject *res, PyObject *id_type) + { +@@ -191,6 +219,57 @@ static int do_getnamebycert(PyObject *py_result, PyObject *py_cert) + return ret; + } + ++static int do_getlistbycert(PyObject *py_result, PyObject *py_cert) ++{ ++ int ret; ++ const char *cert; ++ char **names = NULL; ++ enum sss_id_type *id_types = NULL; ++ size_t c; ++ ++ cert = py_string_or_unicode_as_string(py_cert); ++ if (cert == NULL) { ++ return EINVAL; ++ } ++ ++ ret = sss_nss_getlistbycert(cert, &names, &id_types); ++ if (ret == 0) { ++ ++ PyObject *py_list; ++ ++ py_list = PyList_New(0); ++ if (py_list == NULL) { ++ return ENOMEM; ++ } ++ ++ for (c = 0; names[c] != NULL; c++) { ++ ret = add_dict_to_list(py_list, ++ PyBytes_FromString(SSS_NAME_KEY), ++ PyUnicode_FromString(names[c]), ++ PYNUMBER_FROMLONG(id_types[c])); ++ if (ret != 0) { ++ goto done; ++ } ++ } ++ ret = PyDict_SetItem(py_result, py_cert, py_list); ++ if (ret != 0) { ++ goto done; ++ } ++ } ++ ++done: ++ free(id_types); ++ if (names != NULL) { ++ for (c = 0; names[c] != NULL; c++) { ++ free(names[c]); ++ } ++ free(names); ++ } ++ ++ return ret; ++} ++ ++ + static int do_getidbysid(PyObject *py_result, PyObject *py_sid) + { + const char *sid; +@@ -231,6 +310,9 @@ static int do_lookup(enum lookup_type type, PyObject *py_result, + case NAMEBYCERT: + return do_getnamebycert(py_result, py_inp); + break; ++ case LISTBYCERT: ++ return do_getlistbycert(py_result, py_inp); ++ break; + default: + return ENOSYS; + } +@@ -368,7 +450,7 @@ static PyObject * py_getidbysid(PyObject *module, PyObject *args) + } + + PyDoc_STRVAR(getnamebycert_doc, +-"getnamebycert(sid or list/tuple of certificates) -> dict(sid => dict(results))\n\ ++"getnamebycert(certificate or list/tuple of certificates) -> dict(certificate => dict(results))\n\ + \n\ + Returns a dictionary with a dictonary of results for each given certificates.\n\ + The result dictonary contain the name and the type of the object which can be\n\ +@@ -382,6 +464,21 @@ static PyObject * py_getnamebycert(PyObject *module, PyObject *args) + return check_args(NAMEBYCERT, args); + } + ++PyDoc_STRVAR(getlistbycert_doc, ++"getnamebycert(certificate or list/tuple of certificates) -> dict(certificate => dict(results))\n\ ++\n\ ++Returns a dictionary with a dictonary of results for each given certificates.\n\ ++The result dictonary contain the name and the type of the object which can be\n\ ++accessed with the key constants NAME_KEY and TYPE_KEY, respectively.\n\ ++\n\ ++NOTE: getlistbycert currently works only with id_provider set as \"ad\" or \"ipa\"" ++); ++ ++static PyObject * py_getlistbycert(PyObject *module, PyObject *args) ++{ ++ return check_args(LISTBYCERT, args); ++} ++ + static PyMethodDef methods[] = { + { sss_py_const_p(char, "getsidbyname"), (PyCFunction) py_getsidbyname, + METH_VARARGS, getsidbyname_doc }, +@@ -393,6 +490,8 @@ static PyMethodDef methods[] = { + METH_VARARGS, getidbysid_doc }, + { sss_py_const_p(char, "getnamebycert"), (PyCFunction) py_getnamebycert, + METH_VARARGS, getnamebycert_doc }, ++ { sss_py_const_p(char, "getlistbycert"), (PyCFunction) py_getlistbycert, ++ METH_VARARGS, getlistbycert_doc }, + { NULL,NULL, 0, NULL } + }; + +diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c +index 08b3d32f2662efc1cc803f6e9e5f2d064f7d3033..1931bf62a686c7f30852dac547866609cf54a81b 100644 +--- a/src/responder/nss/nss_cmd.c ++++ b/src/responder/nss/nss_cmd.c +@@ -932,6 +932,12 @@ static errno_t nss_cmd_getnamebycert(struct cli_ctx *cli_ctx) + nss_protocol_fill_single_name); + } + ++static errno_t nss_cmd_getlistbycert(struct cli_ctx *cli_ctx) ++{ ++ return nss_getby_cert(cli_ctx, CACHE_REQ_USER_BY_CERT, ++ nss_protocol_fill_name_list); ++} ++ + struct sss_cmd_table *get_nss_cmds(void) + { + static struct sss_cmd_table nss_cmds[] = { +@@ -961,6 +967,7 @@ struct sss_cmd_table *get_nss_cmds(void) + { SSS_NSS_GETIDBYSID, nss_cmd_getidbysid }, + { SSS_NSS_GETORIGBYNAME, nss_cmd_getorigbyname }, + { SSS_NSS_GETNAMEBYCERT, nss_cmd_getnamebycert }, ++ { SSS_NSS_GETLISTBYCERT, nss_cmd_getlistbycert }, + { SSS_CLI_NULL, NULL } + }; + +diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h +index c94e7b911eb3c0f97b8c06b1766573311cde41ae..e4c0e52c0e642e885ef2c8423ea564beff7242cf 100644 +--- a/src/responder/nss/nss_protocol.h ++++ b/src/responder/nss/nss_protocol.h +@@ -175,6 +175,12 @@ nss_protocol_fill_single_name(struct nss_ctx *nss_ctx, + struct cache_req_result *result); + + errno_t ++nss_protocol_fill_name_list(struct nss_ctx *nss_ctx, ++ struct nss_cmd_ctx *cmd_ctx, ++ struct sss_packet *packet, ++ struct cache_req_result *result); ++ ++errno_t + nss_protocol_fill_id(struct nss_ctx *nss_ctx, + struct nss_cmd_ctx *cmd_ctx, + struct sss_packet *packet, +diff --git a/src/responder/nss/nss_protocol_sid.c b/src/responder/nss/nss_protocol_sid.c +index 0b97e65f75412d40832d861568d8e2f9de5e1732..a6a4e27d039c67ef98f6d5900d5e3fcadb3ee717 100644 +--- a/src/responder/nss/nss_protocol_sid.c ++++ b/src/responder/nss/nss_protocol_sid.c +@@ -498,3 +498,66 @@ nss_protocol_fill_id(struct nss_ctx *nss_ctx, + + return EOK; + } ++ ++errno_t ++nss_protocol_fill_name_list(struct nss_ctx *nss_ctx, ++ struct nss_cmd_ctx *cmd_ctx, ++ struct sss_packet *packet, ++ struct cache_req_result *result) ++{ ++ enum sss_id_type *id_types; ++ size_t rp = 0; ++ size_t body_len; ++ uint8_t *body; ++ errno_t ret; ++ struct sized_string *sz_names; ++ size_t len; ++ size_t c; ++ const char *tmp_str; ++ ++ sz_names = talloc_array(cmd_ctx, struct sized_string, result->count); ++ if (sz_names == NULL) { ++ return ENOMEM; ++ } ++ ++ id_types = talloc_array(cmd_ctx, enum sss_id_type, result->count); ++ if (id_types == NULL) { ++ return ENOMEM; ++ } ++ ++ len = 0; ++ for (c = 0; c < result->count; c++) { ++ ret = nss_get_id_type(cmd_ctx, result, &(id_types[c])); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ tmp_str = nss_get_name_from_msg(result->domain, result->msgs[c]); ++ if (tmp_str == NULL) { ++ return EINVAL; ++ } ++ to_sized_string(&(sz_names[c]), tmp_str); ++ ++ len += sz_names[c].len; ++ } ++ ++ len += (2 + result->count) * sizeof(uint32_t); ++ ++ ret = sss_packet_grow(packet, len); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n"); ++ return ret; ++ } ++ ++ sss_packet_get_body(packet, &body, &body_len); ++ ++ SAFEALIGN_SET_UINT32(&body[rp], result->count, &rp); /* Num results. */ ++ SAFEALIGN_SET_UINT32(&body[rp], 0, &rp); /* Reserved. */ ++ for (c = 0; c < result->count; c++) { ++ SAFEALIGN_SET_UINT32(&body[rp], id_types[c], &rp); ++ SAFEALIGN_SET_STRING(&body[rp], sz_names[c].str, sz_names[c].len, ++ &rp); ++ } ++ ++ return EOK; ++} +diff --git a/src/sss_client/idmap/sss_nss_idmap.c b/src/sss_client/idmap/sss_nss_idmap.c +index fa5a499e3606f7e45a406de4d63002ba35365cb1..6f3af267a1e763e7dce77e3862be377ae2bfe984 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.c ++++ b/src/sss_client/idmap/sss_nss_idmap.c +@@ -31,6 +31,7 @@ + #include "util/strtonum.h" + + #define DATA_START (3 * sizeof(uint32_t)) ++#define LIST_START (2 * sizeof(uint32_t)) + union input { + const char *str; + uint32_t id; +@@ -38,10 +39,12 @@ union input { + + struct output { + enum sss_id_type type; ++ enum sss_id_type *types; + union { + char *str; + uint32_t id; + struct sss_nss_kv *kv_list; ++ char **names; + } d; + }; + +@@ -72,6 +75,63 @@ void sss_nss_free_kv(struct sss_nss_kv *kv_list) + } + } + ++void sss_nss_free_list(char **l) ++{ ++ size_t c; ++ ++ if (l != NULL) { ++ for (c = 0; l[c] != NULL; c++) { ++ free(l[c]); ++ } ++ free(l); ++ } ++} ++ ++static int buf_to_name_type_list(uint8_t *buf, size_t buf_len, uint32_t num, ++ char ***names, enum sss_id_type **types) ++{ ++ int ret; ++ size_t c; ++ char **n = NULL; ++ enum sss_id_type *t = NULL; ++ size_t rp = 0; ++ ++ n = calloc(num + 1, sizeof(char *)); ++ if (n == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ t = calloc(num + 1, sizeof(enum sss_id_type)); ++ if (t == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (c = 0; c < num; c++) { ++ SAFEALIGN_COPY_UINT32(&(t[c]), buf + rp, &rp); ++ n[c] = strdup((char *) buf + rp); ++ if (n[c] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ rp += strlen(n[c]) + 1; ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ sss_nss_free_list(n); ++ free(t); ++ } else { ++ *names = n; ++ *types = t; ++ } ++ ++ return ret; ++} ++ + static int buf_to_kv_list(uint8_t *buf, size_t buf_len, + struct sss_nss_kv **kv_list) + { +@@ -153,13 +213,14 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , + size_t data_len; + uint32_t c; + struct sss_nss_kv *kv_list; ++ char **names; ++ enum sss_id_type *types; + + switch (cmd) { + case SSS_NSS_GETSIDBYNAME: + case SSS_NSS_GETNAMEBYSID: + case SSS_NSS_GETIDBYSID: + case SSS_NSS_GETORIGBYNAME: +- case SSS_NSS_GETNAMEBYCERT: + ret = sss_strnlen(inp.str, 2048, &inp_len); + if (ret != EOK) { + return EINVAL; +@@ -169,6 +230,17 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , + rd.data = inp.str; + + break; ++ case SSS_NSS_GETNAMEBYCERT: ++ case SSS_NSS_GETLISTBYCERT: ++ ret = sss_strnlen(inp.str, 10 * 1024 , &inp_len); ++ if (ret != EOK) { ++ return EINVAL; ++ } ++ ++ rd.len = inp_len + 1; ++ rd.data = inp.str; ++ ++ break; + case SSS_NSS_GETSIDBYID: + rd.len = sizeof(uint32_t); + rd.data = &inp.id; +@@ -195,7 +267,7 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , + if (num_results == 0) { + ret = ENOENT; + goto done; +- } else if (num_results > 1) { ++ } else if (num_results > 1 && cmd != SSS_NSS_GETLISTBYCERT) { + ret = EBADMSG; + goto done; + } +@@ -237,6 +309,18 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd , + out->d.id = c; + + break; ++ case SSS_NSS_GETLISTBYCERT: ++ ret = buf_to_name_type_list(repbuf + LIST_START, replen - LIST_START, ++ num_results, ++ &names, &types); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ out->types = types; ++ out->d.names = names; ++ ++ break; + case SSS_NSS_GETORIGBYNAME: + ret = buf_to_kv_list(repbuf + DATA_START, data_len, &kv_list); + if (ret != EOK) { +@@ -392,3 +476,25 @@ int sss_nss_getnamebycert(const char *cert, char **fq_name, + + return ret; + } ++ ++int sss_nss_getlistbycert(const char *cert, char ***fq_name, ++ enum sss_id_type **type) ++{ ++ int ret; ++ union input inp; ++ struct output out; ++ ++ if (fq_name == NULL || cert == NULL || *cert == '\0') { ++ return EINVAL; ++ } ++ ++ inp.str = cert; ++ ++ ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETLISTBYCERT, &out); ++ if (ret == EOK) { ++ *fq_name = out.d.names; ++ *type = out.types; ++ } ++ ++ return ret; ++} +diff --git a/src/sss_client/idmap/sss_nss_idmap.exports b/src/sss_client/idmap/sss_nss_idmap.exports +index bd5d80212017d38334c3cdeefa47d6029f42aebb..49dac6fc9351b0ca98cd46e83b85ec8ef0075a0d 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.exports ++++ b/src/sss_client/idmap/sss_nss_idmap.exports +@@ -25,3 +25,9 @@ SSS_NSS_IDMAP_0.2.0 { + global: + sss_nss_getnamebycert; + } SSS_NSS_IDMAP_0.1.0; ++ ++SSS_NSS_IDMAP_0.3.0 { ++ # public functions ++ global: ++ sss_nss_getlistbycert; ++} SSS_NSS_IDMAP_0.2.0; +diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h +index 8a6299194e7b91e084b26c0c96e2f93875a832e7..cbf19479ff9ec6e0d6e07e1f7e48a1571e147740 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.h ++++ b/src/sss_client/idmap/sss_nss_idmap.h +@@ -130,7 +130,7 @@ int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list, + * @param[in] cert base64 encoded certificate + * @param[out] fq_name Fully qualified name of a user or a group, + * must be freed by the caller +- * @param[out] type Type of the object related to the SID ++ * @param[out] type Type of the object related to the cert + * + * @return + * - see #sss_nss_getsidbyname +@@ -139,6 +139,21 @@ int sss_nss_getnamebycert(const char *cert, char **fq_name, + enum sss_id_type *type); + + /** ++ * @brief Return a list of fully qualified names for the given base64 encoded ++ * X.509 certificate in DER format ++ * ++ * @param[in] cert base64 encoded certificate ++ * @param[out] fq_name List of fully qualified name of users or groups, ++ * must be freed by the caller ++ * @param[out] type List of types of the objects related to the cert ++ * ++ * @return ++ * - see #sss_nss_getsidbyname ++ */ ++int sss_nss_getlistbycert(const char *cert, char ***fq_name, ++ enum sss_id_type **type); ++ ++/** + * @brief Free key-value list returned by sss_nss_getorigbyname() + * + * @param[in] kv_list Key-value list returned by sss_nss_getorigbyname(). +diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h +index 8091e11515184dc9b7f32eed535055d9eee3143f..59fee7a4eceb2c185e156e812af7f2f4c6b2a0dd 100644 +--- a/src/sss_client/sss_cli.h ++++ b/src/sss_client/sss_cli.h +@@ -260,6 +260,11 @@ SSS_NSS_GETNAMEBYCERT = 0x0116, /**< Takes the zero terminated string + of a X509 certificate and returns the zero + terminated fully qualified name of the + related object. */ ++SSS_NSS_GETLISTBYCERT = 0x0117, /**< Takes the zero terminated string ++ of the base64 encoded DER representation ++ of a X509 certificate and returns a list ++ of zero terminated fully qualified names ++ of the related objects. */ + }; + + /** +diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c +index 76b9c6fb05673130de0957e93291919c263a28f3..50714715cc80338640f2a77ecbe17bd5e0d6e911 100644 +--- a/src/tests/cmocka/test_nss_srv.c ++++ b/src/tests/cmocka/test_nss_srv.c +@@ -3454,6 +3454,16 @@ struct passwd testbycert = { + .pw_passwd = discard_const("*"), + }; + ++struct passwd testbycert2 = { ++ .pw_name = discard_const("testcertuser2"), ++ .pw_uid = 23457, ++ .pw_gid = 6890, ++ .pw_dir = discard_const("/home/testcertuser2"), ++ .pw_gecos = discard_const("test cert user2"), ++ .pw_shell = discard_const("/bin/sh"), ++ .pw_passwd = discard_const("*"), ++}; ++ + #define TEST_TOKEN_CERT \ + "MIIECTCCAvGgAwIBAgIBCDANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ + "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTA2MjMx" \ +@@ -3495,6 +3505,57 @@ static int test_nss_getnamebycert_check(uint32_t status, uint8_t *body, size_t b + return EOK; + } + ++static int test_nss_getlistbycert_check(uint32_t status, uint8_t *body, size_t blen) ++{ ++ size_t rp = 0; ++ uint32_t id_type; ++ uint32_t num; ++ uint32_t reserved; ++ const char *name; ++ int found = 0; ++ const char *fq_name1 = "testcertuser@"TEST_DOM_NAME ; ++ const char *fq_name2 = "testcertuser2@"TEST_DOM_NAME; ++ ++ assert_int_equal(status, EOK); ++ ++ /* num_results and reserved */ ++ SAFEALIGN_COPY_UINT32(&num, body + rp, &rp); ++ assert_in_range(num, 1, 2); ++ SAFEALIGN_COPY_UINT32(&reserved, body + rp, &rp); ++ assert_int_equal(reserved, 0); ++ ++ SAFEALIGN_COPY_UINT32(&id_type, body + rp, &rp); ++ assert_int_equal(id_type, SSS_ID_TYPE_UID); ++ ++ name = (const char *)body + rp; ++ if (num == 1) { ++ assert_string_equal(name, fq_name1); ++ return EOK; ++ } ++ ++ rp += strlen(name) + 1; ++ if (strcmp(name, fq_name1) == 0) { ++ found = 1; ++ } else if (strcmp(name, fq_name2) == 0) { ++ found = 2; ++ } ++ assert_in_range(found, 1, 2); ++ ++ SAFEALIGN_COPY_UINT32(&id_type, body + rp, &rp); ++ assert_int_equal(id_type, SSS_ID_TYPE_UID); ++ ++ name = (const char *)body + rp; ++ if (found == 1) { ++ assert_string_equal(name, fq_name2); ++ } else { ++ assert_string_equal(name, fq_name1); ++ } ++ ++ ++ return EOK; ++} ++ ++ + static void test_nss_getnamebycert(void **state) + { + errno_t ret; +@@ -3572,6 +3633,99 @@ void test_nss_getnamebycert_neg(void **state) + assert_int_equal(nss_test_ctx->ncache_hits, 1); + } + ++static void test_nss_getlistbycert(void **state) ++{ ++ errno_t ret; ++ struct sysdb_attrs *attrs; ++ unsigned char *der = NULL; ++ size_t der_size; ++ ++ attrs = sysdb_new_attrs(nss_test_ctx); ++ assert_non_null(attrs); ++ ++ der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size); ++ assert_non_null(der); ++ ++ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); ++ talloc_free(der); ++ assert_int_equal(ret, EOK); ++ ++ /* Prime the cache with a valid user */ ++ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, ++ &testbycert, attrs, 0); ++ assert_int_equal(ret, EOK); ++ talloc_free(attrs); ++ ++ mock_input_cert(TEST_TOKEN_CERT); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETLISTBYCERT); ++ mock_fill_bysid(); ++ ++ /* Query for that user, call a callback when command finishes */ ++ /* Should go straight to back end, without contacting DP. */ ++ /* If there is only a single user mapped the result will look like the */ ++ /* result of getnamebycert. */ ++ set_cmd_cb(test_nss_getlistbycert_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETLISTBYCERT, ++ 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 void test_nss_getlistbycert_multi(void **state) ++{ ++ errno_t ret; ++ struct sysdb_attrs *attrs; ++ unsigned char *der = NULL; ++ size_t der_size; ++ ++ der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size); ++ assert_non_null(der); ++ ++ attrs = sysdb_new_attrs(nss_test_ctx); ++ assert_non_null(attrs); ++ ++ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); ++ assert_int_equal(ret, EOK); ++ ++ /* Prime the cache with two valid user */ ++ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, ++ &testbycert, attrs, 0); ++ assert_int_equal(ret, EOK); ++ talloc_free(attrs); ++ ++ /* Looks like attrs is modified during store_user() makes sure we start ++ * with fresh data. */ ++ attrs = sysdb_new_attrs(nss_test_ctx); ++ assert_non_null(attrs); ++ ++ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); ++ talloc_free(der); ++ assert_int_equal(ret, EOK); ++ ++ ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, ++ &testbycert2, attrs, 0); ++ assert_int_equal(ret, EOK); ++ talloc_free(attrs); ++ ++ mock_input_cert(TEST_TOKEN_CERT); ++ will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETLISTBYCERT); ++ mock_fill_bysid(); ++ ++ /* Query for that user, call a callback when command finishes */ ++ /* Should go straight to back end, without contacting DP */ ++ set_cmd_cb(test_nss_getlistbycert_check); ++ ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETLISTBYCERT, ++ 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 passwd sid_user = { + .pw_name = discard_const("testusersid"), + .pw_uid = 1234, +@@ -3818,6 +3972,10 @@ int main(int argc, const char *argv[]) + nss_test_setup, nss_test_teardown), + cmocka_unit_test_setup_teardown(test_nss_getnamebycert, + nss_test_setup, nss_test_teardown), ++ cmocka_unit_test_setup_teardown(test_nss_getlistbycert, ++ nss_test_setup, nss_test_teardown), ++ cmocka_unit_test_setup_teardown(test_nss_getlistbycert_multi, ++ nss_test_setup, nss_test_teardown), + cmocka_unit_test_setup_teardown(test_nss_getsidbyname, + nss_test_setup, nss_test_teardown), + cmocka_unit_test_setup_teardown(test_nss_getsidbyupn, +-- +2.9.3 + diff --git a/SOURCES/0013-config-override_space-is-monitor-s-option.patch b/SOURCES/0013-config-override_space-is-monitor-s-option.patch deleted file mode 100644 index f9d2ccd..0000000 --- a/SOURCES/0013-config-override_space-is-monitor-s-option.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 3904a70f86d793954822abc543783d57fb36c8ea Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Mon, 11 Jul 2016 13:11:41 +0200 -Subject: [PATCH 13/14] config: override_space is monitor's option -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We read override_space from [sssd] not -[nss] section. - -Resolves: -https://fedorahosted.org/sssd/ticket/3068 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit fc04d11c2fdde0bfe280c6030df2b1d6bf15ce63) ---- - src/config/SSSDConfig/__init__.py.in | 2 +- - src/config/SSSDConfigTest.py | 3 ++- - src/config/cfg_rules.ini | 2 +- - src/config/etc/sssd.api.conf | 2 +- - 4 files changed, 5 insertions(+), 4 deletions(-) - -diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in -index 52af1386c7b6fc858b27d6f1d9197a7906519fc1..ebdd049e4df7ac2349293d6ce3802e7349098273 100644 ---- a/src/config/SSSDConfig/__init__.py.in -+++ b/src/config/SSSDConfig/__init__.py.in -@@ -63,6 +63,7 @@ option_strings = { - 'default_domain_suffix' : _('Domain to add to names without a domain component.'), - 'user' : _('The user to drop privileges to'), - 'certificate_verification' : _('Tune certificate verification'), -+ 'override_space': _('All spaces in group or user names will be replaced with this character'), - - # [nss] - 'enum_cache_timeout' : _('Enumeration cache timeout length (seconds)'), -@@ -81,7 +82,6 @@ option_strings = { - 'shell_fallback' : _('If a shell stored in central directory is allowed but not available, use this fallback'), - 'default_shell': _('Shell to use if the provider does not list one'), - 'memcache_timeout': _('How long will be in-memory cache records valid'), -- 'override_space': _('All spaces in group or user names will be replaced with this character'), - - # [pam] - 'offline_credentials_expiration' : _('How long to allow cached logins between online logins (days)'), -diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py -index 6ec30234e24b7b48ccab6a98e1f9396990509190..5fa9bce8e6502c0ebf42671058c5e3d5de00ea0d 100755 ---- a/src/config/SSSDConfigTest.py -+++ b/src/config/SSSDConfigTest.py -@@ -310,7 +310,8 @@ class SSSDConfigTestSSSDService(unittest.TestCase): - 'client_idle_timeout', - 'diag_cmd', - 'description', -- 'certificate_verification'] -+ 'certificate_verification', -+ 'override_space'] - - 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 d738ddf5ac5c220dbf2c3c99782368c684072e3f..ae4a9af2cdfd622e1234e26ae7285ff4e47889dc 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -38,6 +38,7 @@ option = krb5_rcache_dir - option = user - option = default_domain_suffix - option = certificate_verification -+option = override_space - - [rule/allowed_nss_options] - validator = ini_allowed_options -@@ -75,7 +76,6 @@ option = shell_fallback - option = default_shell - option = get_domains_timeout - option = memcache_timeout --option = override_space - - [rule/allowed_pam_options] - validator = ini_allowed_options -diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf -index 91146593d7fcda2930ff85e8ee3e889cc12af962..df6bdeb392b33a1437d790027054ee5e7b33e724 100644 ---- a/src/config/etc/sssd.api.conf -+++ b/src/config/etc/sssd.api.conf -@@ -28,6 +28,7 @@ krb5_rcache_dir = str, None, false - user = str, None, false - default_domain_suffix = str, None, false - certificate_verification = str, None, false -+override_space = str, None, false - - [nss] - # Name service -@@ -49,7 +50,6 @@ shell_fallback = str, None, false - default_shell = str, None, false - get_domains_timeout = int, None, false - memcache_timeout = int, None, false --override_space = str, None, false - - [pam] - # Authentication service --- -2.4.11 - diff --git a/SOURCES/0013-nss-allow-larger-buffer-for-certificate-based-reques.patch b/SOURCES/0013-nss-allow-larger-buffer-for-certificate-based-reques.patch new file mode 100644 index 0000000..d0dea12 --- /dev/null +++ b/SOURCES/0013-nss-allow-larger-buffer-for-certificate-based-reques.patch @@ -0,0 +1,70 @@ +From e7c9ff18f41d9951aff3c99dca7db1871e53cfaf Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 28 Feb 2017 14:19:53 +0100 +Subject: [PATCH 13/15] nss: allow larger buffer for certificate based requests + +To make sure larger certificates can be processed as well the maximal +buffer size is increased for requests by certificate. + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +--- + src/responder/common/responder_packet.c | 21 ++++++++++++++++++++- + src/responder/common/responder_packet.h | 1 + + 2 files changed, 21 insertions(+), 1 deletion(-) + +diff --git a/src/responder/common/responder_packet.c b/src/responder/common/responder_packet.c +index 4f5e110837eb76609d31a77c62a00e00530ffc90..cc4d66995965cca4c86a80c31d2afd4c9ac3e0e4 100644 +--- a/src/responder/common/responder_packet.c ++++ b/src/responder/common/responder_packet.c +@@ -179,6 +179,8 @@ int sss_packet_recv(struct sss_packet *packet, int fd) + size_t rb; + size_t len; + void *buf; ++ size_t new_len; ++ int ret; + + buf = (uint8_t *)packet->buffer + packet->iop; + if (packet->iop > 4) len = sss_packet_get_len(packet) - packet->iop; +@@ -205,7 +207,24 @@ int sss_packet_recv(struct sss_packet *packet, int fd) + } + + if (sss_packet_get_len(packet) > packet->memsize) { +- return EINVAL; ++ /* Allow certificate based requests to use larger buffer but not ++ * larger than SSS_CERT_PACKET_MAX_RECV_SIZE. Due to the way ++ * sss_packet_grow() works the packet len must be set to '0' first and ++ * then grow to the expected size. */ ++ if ((sss_packet_get_cmd(packet) == SSS_NSS_GETNAMEBYCERT ++ || sss_packet_get_cmd(packet) == SSS_NSS_GETLISTBYCERT) ++ && packet->memsize < SSS_CERT_PACKET_MAX_RECV_SIZE ++ && (new_len = sss_packet_get_len(packet)) ++ < SSS_CERT_PACKET_MAX_RECV_SIZE) { ++ new_len = sss_packet_get_len(packet); ++ sss_packet_set_len(packet, 0); ++ ret = sss_packet_grow(packet, new_len); ++ if (ret != EOK) { ++ return ret; ++ } ++ } else { ++ return EINVAL; ++ } + } + + packet->iop += rb; +diff --git a/src/responder/common/responder_packet.h b/src/responder/common/responder_packet.h +index 3ad0eee28477e446c9e4996617beb55f32923d47..afceb4aaefa40fd86bdfde820c92c09b65cd8702 100644 +--- a/src/responder/common/responder_packet.h ++++ b/src/responder/common/responder_packet.h +@@ -25,6 +25,7 @@ + #include "sss_client/sss_cli.h" + + #define SSS_PACKET_MAX_RECV_SIZE 1024 ++#define SSS_CERT_PACKET_MAX_RECV_SIZE ( 10 * SSS_PACKET_MAX_RECV_SIZE ) + + struct sss_packet; + +-- +2.9.3 + diff --git a/SOURCES/0014-IPA-Add-s2n-request-to-string-function.patch b/SOURCES/0014-IPA-Add-s2n-request-to-string-function.patch new file mode 100644 index 0000000..287bfdf --- /dev/null +++ b/SOURCES/0014-IPA-Add-s2n-request-to-string-function.patch @@ -0,0 +1,44 @@ +From 8820b7bba01312419171c4949a9f1c5c8c061a55 Mon Sep 17 00:00:00 2001 +From: Justin Stephenson +Date: Mon, 20 Mar 2017 11:51:05 -0400 +Subject: [PATCH 14/15] IPA: Add s2n request to string function + +Add a function to convert request_types to string allowing the +ability to print request type information for ipa_s2n functions during +IPA client operations. + +Reviewed-by: Sumit Bose +--- + src/providers/ipa/ipa_s2n_exop.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index 07bbb2b4d252c8ca9ada4d890c36c903c9f75773..4fe20689fe4c0f2bb5217691dd05b37d2a1cc820 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -979,6 +979,22 @@ done: + return ret; + } + ++static const char *ipa_s2n_reqtype2str(enum request_types request_type) ++{ ++ switch (request_type) { ++ case REQ_SIMPLE: ++ return "REQ_SIMPLE"; ++ case REQ_FULL: ++ return "REQ_FULL"; ++ case REQ_FULL_WITH_MEMBERS: ++ return "REQ_FULL_WITH_MEMBERS"; ++ default: ++ break; ++ } ++ ++ return "Unknown request type"; ++} ++ + struct ipa_s2n_get_list_state { + struct tevent_context *ev; + struct ipa_id_ctx *ipa_ctx; +-- +2.9.3 + diff --git a/SOURCES/0014-config-Fix-user_attributes.patch b/SOURCES/0014-config-Fix-user_attributes.patch deleted file mode 100644 index df2c8e3..0000000 --- a/SOURCES/0014-config-Fix-user_attributes.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 08f1019768f6fa569eccf4892e3b5b57372b971d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Mon, 11 Jul 2016 13:23:40 +0200 -Subject: [PATCH 14/14] config: Fix user_attributes -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fixes: -https://fedorahosted.org/sssd/ticket/3068 - -Option user_attributes is also available in -NSS responder, but not in PAC responder. - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 0a172552ec16f3b84d127399551cad786da8fd9d) ---- - src/config/SSSDConfig/__init__.py.in | 1 + - src/config/cfg_rules.ini | 2 +- - src/config/etc/sssd.api.conf | 2 +- - 3 files changed, 3 insertions(+), 2 deletions(-) - -diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in -index ebdd049e4df7ac2349293d6ce3802e7349098273..b5e078d0118a15c10b43fbe050176943ec90e0ee 100644 ---- a/src/config/SSSDConfig/__init__.py.in -+++ b/src/config/SSSDConfig/__init__.py.in -@@ -82,6 +82,7 @@ option_strings = { - 'shell_fallback' : _('If a shell stored in central directory is allowed but not available, use this fallback'), - 'default_shell': _('Shell to use if the provider does not list one'), - 'memcache_timeout': _('How long will be in-memory cache records valid'), -+ 'user_attributes': _('List of user attributes the NSS responder is allowed to publish'), - - # [pam] - 'offline_credentials_expiration' : _('How long to allow cached logins between online logins (days)'), -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index ae4a9af2cdfd622e1234e26ae7285ff4e47889dc..85a15be3493cf4b8c5a612b0f66ae4c86d39b1ab 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -58,6 +58,7 @@ option = description - option = diag_cmd - - # Name service -+option = user_attributes - option = enum_cache_timeout - option = entry_cache_nowait_percentage - option = entry_negative_timeout -@@ -192,7 +193,6 @@ option = diag_cmd - - # PAC responder - option = allowed_uids --option = user_attributes - option = pac_lifetime - - [rule/allowed_ifp_options] -diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf -index df6bdeb392b33a1437d790027054ee5e7b33e724..2d7c5049f5e5bf9df6e5445ee6e5c62211bf1c45 100644 ---- a/src/config/etc/sssd.api.conf -+++ b/src/config/etc/sssd.api.conf -@@ -50,6 +50,7 @@ shell_fallback = str, None, false - default_shell = str, None, false - get_domains_timeout = int, None, false - memcache_timeout = int, None, false -+user_attributes = str, None, false - - [pam] - # Authentication service -@@ -86,7 +87,6 @@ ca_db = str, None, false - [pac] - # PAC responder - allowed_uids = str, None, false --user_attributes = str, None, false - pac_lifetime = int, None, false - - [ifp] --- -2.4.11 - diff --git a/SOURCES/0015-IPA-Enhance-debug-logging-for-ipa-s2n-operations.patch b/SOURCES/0015-IPA-Enhance-debug-logging-for-ipa-s2n-operations.patch new file mode 100644 index 0000000..8031b4c --- /dev/null +++ b/SOURCES/0015-IPA-Enhance-debug-logging-for-ipa-s2n-operations.patch @@ -0,0 +1,82 @@ +From 359fe83281f2f54d71da65879eafec5ae383f33f Mon Sep 17 00:00:00 2001 +From: Justin Stephenson +Date: Thu, 16 Mar 2017 14:46:55 -0400 +Subject: [PATCH 15/15] IPA: Enhance debug logging for ipa s2n operations + +Add log messages to provide useful debug logging surrounding +IPA client extended operations to the IPA Server during AD trust +requests to retrieve information. Print more details about the +objects requested and received during the ipa_s2n operations. + +This will improve log analysis and troubleshooting efforts during AD +trust user and group resolution failures on IPA clients, such as missing +groups. + +Reviewed-by: Sumit Bose +--- + src/providers/ipa/ipa_s2n_exop.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index 4fe20689fe4c0f2bb5217691dd05b37d2a1cc820..c99312274073858e5e03f3e82c069dafc839eb61 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -1156,6 +1156,13 @@ static errno_t ipa_s2n_get_list_step(struct tevent_req *req) + need_v1 = true; + } + ++ if (state->req_input.type == REQ_INP_NAME ++ && state->req_input.inp.name != NULL) { ++ DEBUG(SSSDBG_TRACE_FUNC, "Sending request_type: [%s] for group [%s].\n", ++ ipa_s2n_reqtype2str(state->request_type), ++ state->list[state->list_idx]); ++ } ++ + subreq = ipa_s2n_exop_send(state, state->ev, state->sh, need_v1, + state->exop_timeout, bv_req); + if (subreq == NULL) { +@@ -1194,6 +1201,9 @@ static void ipa_s2n_get_list_next(struct tevent_req *subreq) + goto fail; + } + ++ DEBUG(SSSDBG_TRACE_FUNC, "Received [%s] attributes from IPA server.\n", ++ state->attrs->a.name); ++ + if (is_default_view(state->ipa_ctx->view_name)) { + ret = ipa_s2n_get_list_save_step(req); + if (ret == EOK) { +@@ -1375,6 +1385,11 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx, + goto fail; + } + ++ DEBUG(SSSDBG_TRACE_FUNC, "Sending request_type: [%s] for trust user [%s] " ++ "to IPA server\n", ++ ipa_s2n_reqtype2str(state->request_type), ++ req_input->inp.name); ++ + subreq = ipa_s2n_exop_send(state, state->ev, state->sh, is_v1, + state->exop_timeout, bv_req); + if (subreq == NULL) { +@@ -1661,6 +1676,19 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + state->attrs = attrs; + + if (attrs->response_type == RESP_USER_GROUPLIST) { ++ ++ if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) { ++ size_t c; ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Received [%zu] groups in group list " ++ "from IPA Server\n", attrs->ngroups); ++ ++ for (c = 0; c < attrs->ngroups; c++) { ++ DEBUG(SSSDBG_TRACE_FUNC, "[%s].\n", attrs->groups[c]); ++ } ++ } ++ ++ + ret = get_group_dn_list(state, state->dom, + attrs->ngroups, attrs->groups, + &group_dn_list, &missing_list); +-- +2.9.3 + diff --git a/SOURCES/0015-sysdb-tests-Fix-cast-from-pointer-to-integer.patch b/SOURCES/0015-sysdb-tests-Fix-cast-from-pointer-to-integer.patch deleted file mode 100644 index 47af5b0..0000000 --- a/SOURCES/0015-sysdb-tests-Fix-cast-from-pointer-to-integer.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 7b8c9b01882788d5112b0a529bf74163805889d3 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Fri, 8 Jul 2016 13:37:10 +0200 -Subject: [PATCH 15/18] sysdb-tests: Fix cast from pointer to integer -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -src/tests/sysdb-tests.c: In function 'test_sysdb_memberof_close_loop': -src/tests/sysdb-tests.c:2740:5: warning: passing argument - 1 of '_ck_assert_msg' makes integer from pointer without a cast - [enabled by default] - fail_unless(data->attrlist[0], "talloc_array failed."); - ^ -In file included from src/tests/sysdb-tests.c:23:0: -/usr/include/check.h:237:16: note: expected 'int' but argument - is of type 'const char *' - void CK_EXPORT _ck_assert_msg (int result, const char *file, - ^ -Reviewed-by: Pavel Březina - -(cherry picked from commit 2bb9e88328ef44eddd935c250ae12337442c5900) ---- - src/tests/sysdb-tests.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c -index 429aa39538901fe387e41eebb27662d7b958142c..bac8a8788b4fde0d6039121efead6fc20fa046f9 100644 ---- a/src/tests/sysdb-tests.c -+++ b/src/tests/sysdb-tests.c -@@ -2737,7 +2737,7 @@ START_TEST (test_sysdb_memberof_close_loop) - fail_unless(data->attrlist != NULL, "talloc_array failed."); - data->attrlist[0] = test_asprintf_fqname(data, test_ctx->domain, - "testgroup%d", data->gid + 9); -- fail_unless(data->attrlist[0], "talloc_array failed."); -+ fail_unless(data->attrlist[0] != NULL, "talloc_array failed."); - data->attrlist[1] = NULL; - - ret = test_memberof_store_group(data); --- -2.4.11 - diff --git a/SOURCES/0016-PROVIDERS-Setting-right-u-g-id-if-unprivileged.patch b/SOURCES/0016-PROVIDERS-Setting-right-u-g-id-if-unprivileged.patch deleted file mode 100644 index cdc951f..0000000 --- a/SOURCES/0016-PROVIDERS-Setting-right-u-g-id-if-unprivileged.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0686ce29cadb7875638d5f782199ea4bb186dee3 Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Tue, 12 Jul 2016 16:14:04 +0200 -Subject: [PATCH 16/18] PROVIDERS: Setting right {u,g}id if unprivileged -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -be_ctx had talloc_zero() initialized uid and gid which was used -in function dp_init(). Therefore back-end was every time started as root -and therefore non-root responders could not communicate with back-end -due to wrong permission of unix sockets. - -This patch sets right uid and gid to data-providers if sssd runs -as non-root user. - -Resolves: -https://fedorahosted.org/sssd/ticket/3077 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 75dead699a19dda7d8dfca89e2f97efbf0c264a2) ---- - 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 78efed851b2bf053ba890caa05e655431996892a..2ae713054429e789c1ba79c1f5e7a3889af3b291 100644 ---- a/src/providers/data_provider_be.c -+++ b/src/providers/data_provider_be.c -@@ -386,6 +386,8 @@ errno_t be_process_init(TALLOC_CTX *mem_ctx, - - be_ctx->ev = ev; - be_ctx->cdb = cdb; -+ be_ctx->uid = uid; -+ be_ctx->gid = gid; - be_ctx->identity = talloc_asprintf(be_ctx, "%%BE_%s", be_domain); - be_ctx->conf_path = talloc_asprintf(be_ctx, CONFDB_DOMAIN_PATH_TMPL, be_domain); - if (be_ctx->identity == NULL || be_ctx->conf_path == NULL) { --- -2.4.11 - diff --git a/SOURCES/0016-UTIL-iobuf-Make-input-parameter-for-the-readonly-ope.patch b/SOURCES/0016-UTIL-iobuf-Make-input-parameter-for-the-readonly-ope.patch new file mode 100644 index 0000000..5ded3ab --- /dev/null +++ b/SOURCES/0016-UTIL-iobuf-Make-input-parameter-for-the-readonly-ope.patch @@ -0,0 +1,45 @@ +From 4ea851ed034efdb06d13b34797b9f849e3dcec97 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 15 Mar 2017 13:32:42 +0100 +Subject: [PATCH 16/36] UTIL: iobuf: Make input parameter for the readonly + operation const +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + src/util/sss_iobuf.c | 2 +- + src/util/sss_iobuf.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/util/sss_iobuf.c b/src/util/sss_iobuf.c +index 7c72ea94d7a005dfd9671793b3ad470a6de7967a..900418b750a3455ebc2c3bb1893db726692260b8 100644 +--- a/src/util/sss_iobuf.c ++++ b/src/util/sss_iobuf.c +@@ -49,7 +49,7 @@ struct sss_iobuf *sss_iobuf_init_empty(TALLOC_CTX *mem_ctx, + } + + struct sss_iobuf *sss_iobuf_init_readonly(TALLOC_CTX *mem_ctx, +- uint8_t *data, ++ const uint8_t *data, + size_t size) + { + struct sss_iobuf *iobuf; +diff --git a/src/util/sss_iobuf.h b/src/util/sss_iobuf.h +index eae357a40f2948e63df189f2842edee68691a542..900faaa212230f72f52e344c085167e80ae2b465 100644 +--- a/src/util/sss_iobuf.h ++++ b/src/util/sss_iobuf.h +@@ -47,7 +47,7 @@ struct sss_iobuf *sss_iobuf_init_empty(TALLOC_CTX *mem_ctx, + * @return The newly created buffer on success or NULL on an error. + */ + struct sss_iobuf *sss_iobuf_init_readonly(TALLOC_CTX *mem_ctx, +- uint8_t *data, ++ const uint8_t *data, + size_t size); + + /* +-- +2.9.3 + diff --git a/SOURCES/0017-UTIL-Fix-a-typo-in-the-tcurl-test-tool.patch b/SOURCES/0017-UTIL-Fix-a-typo-in-the-tcurl-test-tool.patch new file mode 100644 index 0000000..c51e496 --- /dev/null +++ b/SOURCES/0017-UTIL-Fix-a-typo-in-the-tcurl-test-tool.patch @@ -0,0 +1,32 @@ +From c402799ea8b24d2e382d0ad7a06ee92861852972 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 15 Mar 2017 13:42:03 +0100 +Subject: [PATCH 17/36] UTIL: Fix a typo in the tcurl test tool +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + src/tests/tcurl_test_tool.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c +index 35ea979780df47c92ed92bc5bba713faa8909b90..38cea432885c97ca3827c8f158bf7e3ebfc67b31 100644 +--- a/src/tests/tcurl_test_tool.c ++++ b/src/tests/tcurl_test_tool.c +@@ -204,8 +204,8 @@ int main(int argc, const char *argv[]) + urls[i], + headers, + inbufs[i], +- 10); +- if (ctx == NULL) { ++ 5); ++ if (req == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Could not create request\n"); + talloc_zfree(tool_ctx); + return 1; +-- +2.9.3 + diff --git a/SOURCES/0017-config-Allow-timeout-for-all-sevices.patch b/SOURCES/0017-config-Allow-timeout-for-all-sevices.patch deleted file mode 100644 index fae8cf5..0000000 --- a/SOURCES/0017-config-Allow-timeout-for-all-sevices.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 18b2f16e2b086509cafb453943387fff2d1b0d19 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Mon, 11 Jul 2016 13:03:28 +0200 -Subject: [PATCH 17/18] config: Allow timeout for all sevices -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Allow option "timeout" for all sevices. -Also remove unused macro CONFDB_SERVICE_TIMEOUT. - -Resolves: -https://fedorahosted.org/sssd/ticket/3068 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 1b9b5477027d86a2afb2e72981253d108c5398da) ---- - src/confdb/confdb.h | 1 - - src/config/cfg_rules.ini | 7 +++++++ - src/config/etc/sssd.api.conf | 2 +- - 3 files changed, 8 insertions(+), 2 deletions(-) - -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index 54b1cbc82546a76013c35c6cd3b1924663e9bb23..cc8f66f02eb5ac10ced826326f80bbf5eda82ee1 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -58,7 +58,6 @@ - #define CONFDB_SERVICE_DEBUG_TIMESTAMPS "debug_timestamps" - #define CONFDB_SERVICE_DEBUG_MICROSECONDS "debug_microseconds" - #define CONFDB_SERVICE_DEBUG_TO_FILES "debug_to_files" --#define CONFDB_SERVICE_TIMEOUT "timeout" - #define CONFDB_SERVICE_FORCE_TIMEOUT "force_timeout" - #define CONFDB_SERVICE_RECON_RETRIES "reconnection_retries" - #define CONFDB_SERVICE_FD_LIMIT "fd_limit" -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 85a15be3493cf4b8c5a612b0f66ae4c86d39b1ab..5c8d05a817331dd23fd7e349719bd4b44a5bdd02 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -44,6 +44,7 @@ option = override_space - validator = ini_allowed_options - section_re = ^nss$ - -+option = timeout - option = debug - option = debug_level - option = debug_timestamps -@@ -82,6 +83,7 @@ option = memcache_timeout - validator = ini_allowed_options - section_re = ^pam$ - -+option = timeout - option = debug - option = debug_level - option = debug_timestamps -@@ -115,6 +117,7 @@ option = p11_child_timeout - validator = ini_allowed_options - section_re = ^sudo$ - -+option = timeout - option = debug - option = debug_level - option = debug_timestamps -@@ -136,6 +139,7 @@ option = sudo_inverse_order - validator = ini_allowed_options - section_re = ^autofs$ - -+option = timeout - option = debug - option = debug_level - option = debug_timestamps -@@ -156,6 +160,7 @@ option = autofs_negative_timeout - validator = ini_allowed_options - section_re = ^ssh$ - -+option = timeout - option = debug - option = debug_level - option = debug_timestamps -@@ -178,6 +183,7 @@ option = ca_db - validator = ini_allowed_options - section_re = ^pac$ - -+option = timeout - option = debug - option = debug_level - option = debug_timestamps -@@ -199,6 +205,7 @@ option = pac_lifetime - validator = ini_allowed_options - section_re = ^ifp$ - -+option = timeout - option = debug - option = debug_level - option = debug_timestamps -diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf -index 2d7c5049f5e5bf9df6e5445ee6e5c62211bf1c45..e4011a384cdb3fb3bce93494cbb278ec2622ee40 100644 ---- a/src/config/etc/sssd.api.conf -+++ b/src/config/etc/sssd.api.conf -@@ -3,6 +3,7 @@ - - [service] - # Options available to all services -+timeout = int, None, false - debug = int, None, false - debug_level = int, None, false - debug_timestamps = bool, None, false -@@ -20,7 +21,6 @@ diag_cmd = str, None, false - # Monitor service - services = list, str, true, nss, pam - domains = list, str, true --timeout = int, None, false - sbus_timeout = int, None, false - re_expression = str, None, false - full_name_format = str, None, false --- -2.4.11 - diff --git a/SOURCES/0018-UTIL-Add-SAFEALIGN_COPY_UINT8_CHECK.patch b/SOURCES/0018-UTIL-Add-SAFEALIGN_COPY_UINT8_CHECK.patch new file mode 100644 index 0000000..bb11f98 --- /dev/null +++ b/SOURCES/0018-UTIL-Add-SAFEALIGN_COPY_UINT8_CHECK.patch @@ -0,0 +1,36 @@ +From 4aecf8a2d3962d962da1e2f98b0bb3b84a8ae536 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Thu, 23 Feb 2017 20:55:05 +0100 +Subject: [PATCH 18/36] UTIL: Add SAFEALIGN_COPY_UINT8_CHECK +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This macro will be used later in the KCM code + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + src/util/util_safealign.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/util/util_safealign.h b/src/util/util_safealign.h +index 0d9a579cdbfafc30bf2d0a6ad2651c71428ebd93..57f04a17d4a38300b959c1593d756b351ebd89e8 100644 +--- a/src/util/util_safealign.h ++++ b/src/util/util_safealign.h +@@ -130,6 +130,12 @@ safealign_memcpy(void *dest, const void *src, size_t n, size_t *counter) + safealign_memcpy(dest, src, srclen, pctr); \ + } while(0) + ++#define SAFEALIGN_COPY_UINT8_CHECK(dest, src, len, pctr) do { \ ++ if ((*(pctr) + sizeof(uint8_t)) > (len) || \ ++ SIZE_T_OVERFLOW(*(pctr), sizeof(uint8_t))) { return EINVAL; } \ ++ safealign_memcpy(dest, src, sizeof(uint8_t), pctr); \ ++} while(0) ++ + /* Aliases for backward compatibility. */ + #define SAFEALIGN_SET_VALUE SAFEALIGN_SETMEM_VALUE + #define SAFEALIGN_SET_INT64 SAFEALIGN_SETMEM_INT64 +-- +2.9.3 + diff --git a/SOURCES/0018-config-Add-config_file_version-to-schema.patch b/SOURCES/0018-config-Add-config_file_version-to-schema.patch deleted file mode 100644 index 3d47710..0000000 --- a/SOURCES/0018-config-Add-config_file_version-to-schema.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 5e8d4f0107c5e6f1836740945b610a54c216bd7f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Mon, 11 Jul 2016 13:34:03 +0200 -Subject: [PATCH 18/18] config: Add config_file_version to schema -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: -https://fedorahosted.org/sssd/ticket/3068 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit aeab20358006d728a284f969f92f3890498cd651) ---- - src/config/SSSDConfigTest.py | 1 + - src/config/cfg_rules.ini | 1 + - src/config/etc/sssd.api.conf | 1 + - 3 files changed, 3 insertions(+) - -diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py -index 5fa9bce8e6502c0ebf42671058c5e3d5de00ea0d..332d8702d983b6ec8bf12ec781a1bbf296b552e0 100755 ---- a/src/config/SSSDConfigTest.py -+++ b/src/config/SSSDConfigTest.py -@@ -289,6 +289,7 @@ class SSSDConfigTestSSSDService(unittest.TestCase): - - options = service.list_options() - control_list = [ -+ 'config_file_version', - 'services', - 'domains', - 'timeout', -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 5c8d05a817331dd23fd7e349719bd4b44a5bdd02..635c078436e8ca47f60e8d82341cb131469fe4c9 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -39,6 +39,7 @@ option = user - option = default_domain_suffix - option = certificate_verification - option = override_space -+option = config_file_version - - [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 e4011a384cdb3fb3bce93494cbb278ec2622ee40..737f0e149d56bd07b078cb83acbc43ea2ed3a057 100644 ---- a/src/config/etc/sssd.api.conf -+++ b/src/config/etc/sssd.api.conf -@@ -19,6 +19,7 @@ diag_cmd = str, None, false - - [sssd] - # Monitor service -+config_file_version = int, None, false - services = list, str, true, nss, pam - domains = list, str, true - sbus_timeout = int, None, false --- -2.4.11 - diff --git a/SOURCES/0019-UTIL-Add-utility-macro-cli_creds_get_gid.patch b/SOURCES/0019-UTIL-Add-utility-macro-cli_creds_get_gid.patch new file mode 100644 index 0000000..84752b5 --- /dev/null +++ b/SOURCES/0019-UTIL-Add-utility-macro-cli_creds_get_gid.patch @@ -0,0 +1,34 @@ +From 62acd53dc2880b23cfb221ce40537abfb6e011bb Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 20 Sep 2016 22:00:27 +0200 +Subject: [PATCH 19/36] UTIL: Add utility macro cli_creds_get_gid() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The KCM responder checks the owneship of the ccache based on both UID +and GID of the peer. In order to reuse the already existing creds +structure, let's just add a new macro that returns the GID from the +creds structure. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + src/util/util_creds.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/util/util_creds.h b/src/util/util_creds.h +index 65468fa12b8c6921859574c40f5759c936a10e86..936b9965d1ccd2b437d93b38d789b6f8389f47a6 100644 +--- a/src/util/util_creds.h ++++ b/src/util/util_creds.h +@@ -71,6 +71,7 @@ struct cli_creds { + }; + + #define cli_creds_get_uid(x) x->ucred.uid ++#define cli_creds_get_gid(x) x->ucred.gid + + #else /* not HAVE_UCRED */ + struct cli_creds { +-- +2.9.3 + diff --git a/SOURCES/0019-dyndns-Add-checks-for-NULL.patch b/SOURCES/0019-dyndns-Add-checks-for-NULL.patch deleted file mode 100644 index f038acd..0000000 --- a/SOURCES/0019-dyndns-Add-checks-for-NULL.patch +++ /dev/null @@ -1,57 +0,0 @@ -From b0330a760d838b30c88d6f02f0148b84093761c3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 12 Jul 2016 12:11:18 +0200 -Subject: [PATCH 19/19] dyndns: Add checks for NULL -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Fixes: -https://fedorahosted.org/sssd/ticket/3076 - -We segfaulted in this area once. This patch -makes the code more defensive and adds -some DEBUG messages. - -Normally the structures are filled in online -and/or resolve callbacks. - -Reviewed-by: Pavel Březina ---- - src/providers/ipa/ipa_dyndns.c | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) - -diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c -index 7217c61452e7ead2949a9f7d57b2f2fc58953af1..dc910770c771d4b7a7ee62d25be7c48e16c988a7 100644 ---- a/src/providers/ipa/ipa_dyndns.c -+++ b/src/providers/ipa/ipa_dyndns.c -@@ -162,6 +162,26 @@ ipa_dyndns_update_send(struct ipa_options *ctx) - } - state->ipa_ctx = ctx; - -+ /* The following three checks are here to prevent SEGFAULT -+ * from ticket #3076. */ -+ if (ctx->service == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "service structure not initialized\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ if (ctx->service->sdap == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "sdap structure not initialized\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ if (ctx->service->sdap->uri == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "LDAP uri not set\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ - if (ctx->dyndns_ctx->last_refresh + 60 > time(NULL) || - ctx->dyndns_ctx->timer_in_progress) { - DEBUG(SSSDBG_FUNC_DATA, "Last periodic update ran recently or timer " --- -2.4.11 - diff --git a/SOURCES/0020-UTIL-Add-type-specific-getsetters-to-sss_iobuf.patch b/SOURCES/0020-UTIL-Add-type-specific-getsetters-to-sss_iobuf.patch new file mode 100644 index 0000000..97c4775 --- /dev/null +++ b/SOURCES/0020-UTIL-Add-type-specific-getsetters-to-sss_iobuf.patch @@ -0,0 +1,194 @@ +From cef2ade5294bd9dc06f7eca26287c2e90e2c2ee1 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Thu, 23 Feb 2017 21:57:13 +0100 +Subject: [PATCH 20/36] UTIL: Add type-specific getsetters to sss_iobuf +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The KCM responder receives its input as unstructured data. To make the +parsing easier, this commit adds several type-specific getsetters to the +iobuf module. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + src/util/sss_iobuf.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++ + src/util/sss_iobuf.h | 33 ++++++++++++++++ + 2 files changed, 141 insertions(+) + +diff --git a/src/util/sss_iobuf.c b/src/util/sss_iobuf.c +index 900418b750a3455ebc2c3bb1893db726692260b8..fc288d2df2bfaaba393dd490d4da8976de804cb5 100644 +--- a/src/util/sss_iobuf.c ++++ b/src/util/sss_iobuf.c +@@ -184,6 +184,25 @@ errno_t sss_iobuf_read(struct sss_iobuf *iobuf, + return EOK; + } + ++errno_t sss_iobuf_read_len(struct sss_iobuf *iobuf, ++ size_t len, ++ uint8_t *_buf) ++{ ++ size_t read; ++ errno_t ret; ++ ++ ret = sss_iobuf_read(iobuf, len, _buf, &read); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ if (read != len) { ++ return ENOBUFS; ++ } ++ ++ return EOK; ++} ++ + errno_t sss_iobuf_write_len(struct sss_iobuf *iobuf, + uint8_t *buf, + size_t len) +@@ -203,3 +222,92 @@ errno_t sss_iobuf_write_len(struct sss_iobuf *iobuf, + + return EOK; + } ++ ++errno_t sss_iobuf_read_uint32(struct sss_iobuf *iobuf, ++ uint32_t *_val) ++{ ++ SAFEALIGN_COPY_UINT32_CHECK(_val, iobuf_ptr(iobuf), ++ iobuf->capacity, &iobuf->dp); ++ return EOK; ++} ++ ++errno_t sss_iobuf_read_int32(struct sss_iobuf *iobuf, ++ int32_t *_val) ++{ ++ SAFEALIGN_COPY_INT32_CHECK(_val, iobuf_ptr(iobuf), ++ iobuf->capacity, &iobuf->dp); ++ return EOK; ++} ++ ++errno_t sss_iobuf_write_uint32(struct sss_iobuf *iobuf, ++ uint32_t val) ++{ ++ errno_t ret; ++ ++ ret = ensure_bytes(iobuf, sizeof(uint32_t)); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ SAFEALIGN_SETMEM_UINT32(iobuf_ptr(iobuf), val, &iobuf->dp); ++ return EOK; ++} ++ ++errno_t sss_iobuf_write_int32(struct sss_iobuf *iobuf, ++ int32_t val) ++{ ++ errno_t ret; ++ ++ ret = ensure_bytes(iobuf, sizeof(int32_t)); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ SAFEALIGN_SETMEM_INT32(iobuf_ptr(iobuf), val, &iobuf->dp); ++ return EOK; ++} ++ ++errno_t sss_iobuf_read_stringz(struct sss_iobuf *iobuf, ++ const char **_out) ++{ ++ uint8_t *end; ++ size_t len; ++ ++ if (iobuf == NULL) { ++ return EINVAL; ++ } ++ ++ if (_out == NULL) { ++ return EINVAL; ++ } ++ ++ *_out = NULL; ++ ++ end = memchr(iobuf_ptr(iobuf), '\0', sss_iobuf_get_size(iobuf)); ++ if (end == NULL) { ++ return EINVAL; ++ } ++ ++ len = end + 1 - iobuf_ptr(iobuf); ++ if (sss_iobuf_get_size(iobuf) < len) { ++ return EINVAL; ++ } ++ ++ *_out = (const char *) iobuf_ptr(iobuf); ++ iobuf->dp += len; ++ return EOK; ++} ++ ++errno_t sss_iobuf_write_stringz(struct sss_iobuf *iobuf, ++ const char *str) ++{ ++ if (iobuf == NULL || str == NULL) { ++ return EINVAL; ++ } ++ ++ SAFEALIGN_MEMCPY_CHECK(iobuf_ptr(iobuf), ++ str, strlen(str)+1, ++ sss_iobuf_get_size(iobuf), ++ &iobuf->dp); ++ return EOK; ++} +diff --git a/src/util/sss_iobuf.h b/src/util/sss_iobuf.h +index 900faaa212230f72f52e344c085167e80ae2b465..cc3dfd1e98eeb49b979ac321bd0253bffa8a6dff 100644 +--- a/src/util/sss_iobuf.h ++++ b/src/util/sss_iobuf.h +@@ -96,6 +96,22 @@ errno_t sss_iobuf_read(struct sss_iobuf *iobuf, + size_t *_read); + + /* ++ * @brief Read an exact number of bytes from an IO buffer ++ * ++ * Read exactly len bytes from an IO buffer. If the buffer contains fewer ++ * bytes than len, ENOBUFS is returned. ++ * ++ * @param[in] iobuf The IO buffer to read from ++ * @param[in] len The maximum number of bytes to read ++ * @param[out] _buf The buffer to read data into from iobuf ++ * ++ * @return EOK on success, errno otherwise ++ */ ++errno_t sss_iobuf_read_len(struct sss_iobuf *iobuf, ++ size_t len, ++ uint8_t *_buf); ++ ++/* + * @brief Write into an IO buffer + * + * Attempts to write len bytes into the iobuf. If the capacity is exceeded, +@@ -115,4 +131,21 @@ errno_t sss_iobuf_write_len(struct sss_iobuf *iobuf, + uint8_t *buf, + size_t len); + ++errno_t sss_iobuf_read_uint32(struct sss_iobuf *iobuf, ++ uint32_t *_val); ++ ++errno_t sss_iobuf_write_uint32(struct sss_iobuf *iobuf, ++ uint32_t val); ++ ++errno_t sss_iobuf_read_int32(struct sss_iobuf *iobuf, ++ int32_t *_val); ++ ++errno_t sss_iobuf_write_int32(struct sss_iobuf *iobuf, ++ int32_t val); ++ ++errno_t sss_iobuf_read_stringz(struct sss_iobuf *iobuf, ++ const char **_out); ++ ++errno_t sss_iobuf_write_stringz(struct sss_iobuf *iobuf, ++ const char *str); + #endif /* __SSS_IOBUF_H_ */ +-- +2.9.3 + diff --git a/SOURCES/0020-sdap-Fix-ldap_rfc_2307_fallback_to_local_users.patch b/SOURCES/0020-sdap-Fix-ldap_rfc_2307_fallback_to_local_users.patch deleted file mode 100644 index 331cf4d..0000000 --- a/SOURCES/0020-sdap-Fix-ldap_rfc_2307_fallback_to_local_users.patch +++ /dev/null @@ -1,42 +0,0 @@ -From dad90587794fdc2112f2099d5f6cdd9e138781be Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Wed, 13 Jul 2016 20:02:47 +0200 -Subject: [PATCH 20/27] sdap: Fix ldap_rfc_2307_fallback_to_local_users -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We wrongly tried to store empty -user attributes instead of the -local user attributes with -ldap_rfc_2307_fallback_to_local_users -set to true. This gave us bad -initgroups results and caused -segfaults. - -Resolves: -https://fedorahosted.org/sssd/ticket/3045 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit aa8ec3758d885d6ae4088174369d30f8493ec898) ---- - src/providers/ldap/sdap_async_initgroups.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c -index d14563cb045a0ce34b72051744894362fc32d003..17593f0a268813662d6c7fbf658b1eb4599ce3c3 100644 ---- a/src/providers/ldap/sdap_async_initgroups.c -+++ b/src/providers/ldap/sdap_async_initgroups.c -@@ -2893,6 +2893,9 @@ static void sdap_get_initgr_user(struct tevent_req *subreq) - (dp_opt_get_bool(state->opts->basic, - SDAP_RFC2307_FALLBACK_TO_LOCAL_USERS) == true)) { - ret = sdap_fallback_local_user(state, state->shortname, -1, &usr_attrs); -+ if (ret == EOK) { -+ state->orig_user = usr_attrs[0]; -+ } - } else { - ret = ENOENT; - } --- -2.4.11 - diff --git a/SOURCES/0021-UTIL-krb5-principal-un-marshalling.patch b/SOURCES/0021-UTIL-krb5-principal-un-marshalling.patch new file mode 100644 index 0000000..c088f68 --- /dev/null +++ b/SOURCES/0021-UTIL-krb5-principal-un-marshalling.patch @@ -0,0 +1,262 @@ +From aa309f35905951c6fdd12d286bb3aeeb61a62088 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 20 Sep 2016 22:03:30 +0200 +Subject: [PATCH 21/36] UTIL: krb5 principal (un)marshalling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The KCM responder needs to read the contents of the principal blob that +the Kerberos library sends. Since libkrb5 doesn't export any API to do +so, we need to implement marshalling and unmarshalling of the principal +ourselves. + +In future, when the KCM server also supports renewals, we will also need +to unmarshall the credentials, but until that is not really needed, the +credentials will be stored as a blob. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + src/util/sss_krb5.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + src/util/sss_krb5.h | 9 +++ + 2 files changed, 204 insertions(+) + +diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c +index 4808a7703d07bb4eba91f14a7a515aadaec1774b..d461cf881566af37f31524c16f6a5f1511a5dc89 100644 +--- a/src/util/sss_krb5.c ++++ b/src/util/sss_krb5.c +@@ -24,6 +24,7 @@ + + #include "config.h" + ++#include "util/sss_iobuf.h" + #include "util/util.h" + #include "util/sss_krb5.h" + +@@ -1128,3 +1129,197 @@ done: + + return res; + } ++ ++static errno_t iobuf_read_uint32be(struct sss_iobuf *iobuf, ++ uint32_t *_val) ++{ ++ uint32_t beval; ++ errno_t ret; ++ ++ ret = sss_iobuf_read_uint32(iobuf, &beval); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ *_val = be32toh(beval); ++ return EOK; ++} ++ ++static errno_t iobuf_write_uint32be(struct sss_iobuf *iobuf, ++ uint32_t val) ++{ ++ uint32_t beval; ++ ++ beval = htobe32(val); ++ return sss_iobuf_write_uint32(iobuf, beval); ++} ++ ++static errno_t iobuf_get_len_bytes(TALLOC_CTX *mem_ctx, ++ struct sss_iobuf *iobuf, ++ uint32_t *_nbytes, ++ uint8_t **_bytes) ++{ ++ errno_t ret; ++ uint32_t nbytes; ++ uint8_t *bytes = NULL; ++ ++ ret = iobuf_read_uint32be(iobuf, &nbytes); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ bytes = talloc_zero_size(mem_ctx, nbytes); ++ if (bytes == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sss_iobuf_read_len(iobuf, nbytes, bytes); ++ if (ret != EOK) { ++ talloc_free(bytes); ++ return ret; ++ } ++ ++ *_bytes = bytes; ++ *_nbytes = nbytes; ++ return EOK; ++} ++ ++static errno_t get_krb5_data(TALLOC_CTX *mem_ctx, ++ struct sss_iobuf *iobuf, ++ krb5_data *k5data) ++{ ++ errno_t ret; ++ uint32_t nbytes; ++ uint8_t *bytes = NULL; ++ ++ ret = iobuf_get_len_bytes(mem_ctx, iobuf, &nbytes, &bytes); ++ if (ret != EOK) { ++ talloc_free(bytes); ++ return ret; ++ } ++ ++ k5data->data = (char *) bytes; /* FIXME - the cast is ugly */ ++ k5data->length = nbytes; ++ return EOK; ++} ++ ++static errno_t set_krb5_data(struct sss_iobuf *iobuf, ++ krb5_data *k5data) ++{ ++ errno_t ret; ++ ++ ret = iobuf_write_uint32be(iobuf, k5data->length); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ if (k5data->length > 0) { ++ ret = sss_iobuf_write_len(iobuf, ++ (uint8_t *) k5data->data, ++ k5data->length); ++ if (ret != EOK) { ++ return ret; ++ } ++ } ++ ++ return EOK; ++} ++ ++/* FIXME - it would be nice if Kerberos exported these APIs.. */ ++krb5_error_code sss_krb5_unmarshal_princ(TALLOC_CTX *mem_ctx, ++ struct sss_iobuf *iobuf, ++ krb5_principal *_princ) ++{ ++ krb5_principal princ = NULL; ++ krb5_error_code ret; ++ uint32_t ncomps; ++ ++ if (iobuf == NULL || _princ == NULL) { ++ return EINVAL; ++ } ++ ++ princ = talloc_zero(mem_ctx, struct krb5_principal_data); ++ if (princ == NULL) { ++ return ENOMEM; ++ } ++ ++ princ->magic = KV5M_PRINCIPAL; ++ ++ ret = iobuf_read_uint32be(iobuf, (uint32_t *) &princ->type); ++ if (ret != EOK) { ++ goto fail; ++ } ++ ++ ret = iobuf_read_uint32be(iobuf, &ncomps); ++ if (ret != EOK) { ++ goto fail; ++ } ++ ++ if (ncomps > sss_iobuf_get_capacity(iobuf)) { ++ /* Sanity check to avoid large allocations */ ++ ret = EINVAL; ++ goto fail; ++ } ++ ++ if (ncomps != 0) { ++ princ->data = talloc_zero_array(princ, krb5_data, ncomps); ++ if (princ->data == NULL) { ++ ret = ENOMEM; ++ goto fail; ++ } ++ ++ princ->length = ncomps; ++ } ++ ++ ret = get_krb5_data(princ, iobuf, &princ->realm); ++ if (ret != EOK) { ++ goto fail; ++ } ++ ++ for (size_t i = 0; i < ncomps; i++) { ++ ret = get_krb5_data(princ->data, iobuf, &princ->data[i]); ++ if (ret != EOK) { ++ goto fail; ++ } ++ } ++ ++ *_princ = princ; ++ return 0; ++ ++fail: ++ talloc_free(princ); ++ return ret; ++} ++ ++krb5_error_code sss_krb5_marshal_princ(krb5_principal princ, ++ struct sss_iobuf *iobuf) ++{ ++ krb5_error_code ret; ++ ++ if (iobuf == NULL || princ == NULL) { ++ return EINVAL; ++ } ++ ++ ret = iobuf_write_uint32be(iobuf, princ->type); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = iobuf_write_uint32be(iobuf, princ->length); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = set_krb5_data(iobuf, &princ->realm); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ for (int i = 0; i < princ->length; i++) { ++ ret = set_krb5_data(iobuf, &princ->data[i]); ++ if (ret != EOK) { ++ return ret; ++ } ++ } ++ return EOK; ++} +diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h +index ac0f6082c75a8878f72346733e592b7575d44089..0d9043be98749b1a21a1b74c68f07298fa27f230 100644 +--- a/src/util/sss_krb5.h ++++ b/src/util/sss_krb5.h +@@ -32,6 +32,7 @@ + #include + #endif + ++#include "util/sss_iobuf.h" + #include "util/util.h" + + #define KRB5_CHILD_LOG_FILE "krb5_child" +@@ -186,4 +187,12 @@ krb5_error_code sss_krb5_kt_have_content(krb5_context context, + krb5_keytab keytab); + + bool sss_krb5_realm_has_proxy(const char *realm); ++ ++krb5_error_code sss_krb5_marshal_princ(krb5_principal princ, ++ struct sss_iobuf *iobuf); ++ ++krb5_error_code sss_krb5_unmarshal_princ(TALLOC_CTX *mem_ctx, ++ struct sss_iobuf *iobuf, ++ krb5_principal *_princ); ++ + #endif /* __SSS_KRB5_H__ */ +-- +2.9.3 + diff --git a/SOURCES/0021-test_utils-Clean-files-after-sss_write_krb5_conf_sni.patch b/SOURCES/0021-test_utils-Clean-files-after-sss_write_krb5_conf_sni.patch deleted file mode 100644 index 7ad0c30..0000000 --- a/SOURCES/0021-test_utils-Clean-files-after-sss_write_krb5_conf_sni.patch +++ /dev/null @@ -1,56 +0,0 @@ -From a2e8989fd06af0dcf4dd7b8013bda6bcb49839f0 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Tue, 12 Jul 2016 12:37:16 +0200 -Subject: [PATCH 21/27] test_utils: Clean files after - sss_write_krb5_conf_snippet -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The test directory was not removed (tp_test_utils-test_utils) -because it contain the snippet for krb5_libdefaults. - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 059904af2d20debcb8ffe1c6f45b996c2c57574e) ---- - src/tests/cmocka/test_utils.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c -index fd20990ce7ac632b3b62bf84a20cc75a5ec0e968..b08b19708bb59a076a79805fa37a15924152b8e2 100644 ---- a/src/tests/cmocka/test_utils.c -+++ b/src/tests/cmocka/test_utils.c -@@ -1252,6 +1252,7 @@ void test_sss_write_krb5_conf_snippet(void **state) - char *cwd; - char *path; - char *file; -+ char *file_krb5_libdefaults; - - ret = sss_write_krb5_conf_snippet(NULL, false); - assert_int_equal(ret, EINVAL); -@@ -1274,6 +1275,10 @@ void test_sss_write_krb5_conf_snippet(void **state) - ret = asprintf(&file, "%s/%s/localauth_plugin", cwd, TESTS_PATH); - assert_true(ret > 0); - -+ ret = asprintf(&file_krb5_libdefaults, -+ "%s/%s/krb5_libdefaults", cwd, TESTS_PATH); -+ assert_true(ret > 0); -+ - ret = sss_write_krb5_conf_snippet(path, true); - assert_int_equal(ret, EOK); - -@@ -1286,7 +1291,11 @@ void test_sss_write_krb5_conf_snippet(void **state) - assert_int_equal(ret, EOK); - #endif - -+ ret = unlink(file_krb5_libdefaults); -+ assert_int_equal(ret, EOK); -+ - free(file); -+ free(file_krb5_libdefaults); - free(path); - } - --- -2.4.11 - diff --git a/SOURCES/0022-IPA-read-ipaNTAdditionalSuffixes-for-master-and-trus.patch b/SOURCES/0022-IPA-read-ipaNTAdditionalSuffixes-for-master-and-trus.patch deleted file mode 100644 index 478a9ba..0000000 --- a/SOURCES/0022-IPA-read-ipaNTAdditionalSuffixes-for-master-and-trus.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 4ec714f1681355d95420733a40e3c37cd0bfe6ee Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 23 Jun 2016 11:58:30 +0200 -Subject: [PATCH 22/27] IPA: read ipaNTAdditionalSuffixes for master and - trusted domains - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 39f21d2b61685362642d42bc2f94f829671cd5ef) ---- - src/providers/ipa/ipa_subdomains.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c -index a02a65d97dde68f1da900b9fdca05c54035ce005..263d6207960c232d08114bd0163b3fd03a690685 100644 ---- a/src/providers/ipa/ipa_subdomains.c -+++ b/src/providers/ipa/ipa_subdomains.c -@@ -40,6 +40,7 @@ - #define IPA_SID "ipaNTSecurityIdentifier" - #define IPA_TRUSTED_DOMAIN_SID "ipaNTTrustedDomainSID" - #define IPA_RANGE_TYPE "ipaRangeType" -+#define IPA_ADDITIONAL_SUFFIXES "ipaNTAdditionalSuffixes" - - #define IPA_BASE_ID "ipaBaseID" - #define IPA_ID_RANGE_SIZE "ipaIDRangeSize" -@@ -788,7 +789,8 @@ ipa_subdomains_master_send(TALLOC_CTX *mem_ctx, - struct tevent_req *subreq; - struct tevent_req *req; - errno_t ret; -- const char *attrs[] = { IPA_CN, IPA_FLATNAME, IPA_SID, NULL }; -+ const char *attrs[] = { IPA_CN, IPA_FLATNAME, IPA_SID, -+ IPA_ADDITIONAL_SUFFIXES, NULL }; - - req = tevent_req_create(mem_ctx, &state, - struct ipa_subdomains_master_state); -@@ -939,7 +941,8 @@ ipa_subdomains_slave_send(TALLOC_CTX *mem_ctx, - struct tevent_req *req; - errno_t ret; - const char *attrs[] = { IPA_CN, IPA_FLATNAME, IPA_TRUSTED_DOMAIN_SID, -- IPA_TRUST_DIRECTION, NULL }; -+ IPA_TRUST_DIRECTION, IPA_ADDITIONAL_SUFFIXES, -+ NULL }; - - req = tevent_req_create(mem_ctx, &state, - struct ipa_subdomains_slave_state); --- -2.4.11 - diff --git a/SOURCES/0022-KCM-Initial-responder-build-and-packaging.patch b/SOURCES/0022-KCM-Initial-responder-build-and-packaging.patch new file mode 100644 index 0000000..c2ba5a6 --- /dev/null +++ b/SOURCES/0022-KCM-Initial-responder-build-and-packaging.patch @@ -0,0 +1,1013 @@ +From 8cb263f039da9e616e907d25701593dca22b11ed Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 1 Aug 2016 12:52:07 +0200 +Subject: [PATCH 22/36] KCM: Initial responder build and packaging +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Adds the initial build of the Kerberos Cache Manager responder (KCM). + +This is a deamon that is capable of holding and storing Kerberos +ccaches. When KCM is used, the kerberos libraries (invoked through e.g. +kinit) are referred to as a 'client' and the KCM deamon is referred to +as 'server'. + +At the moment, only the Heimdal implementation of Kerberos implements the +KCM server: + https://www.h5l.org/manual/HEAD/info/heimdal/Credential-cache-server-_002d-KCM.html +This patch adds a KCM server to SSSD. + +In MIT, only the 'client-side' support was added: + http://k5wiki.kerberos.org/wiki/Projects/KCM_client +This page also describes the protocol between the client and the server. + +The client is capable of talking to the server over either UNIX sockets +(Linux, most Unixes) or Mach RPC (macOS). Our server only implements the +UNIX sockets way and should be socket-activated by systemd, although can +in theory be also ran explicitly. + +The KCM server only builds if the configuration option "--with-kcm" is +enabled. It is packaged in a new subpackage sssd-kcm in order to allow +distributions to enable the KCM credential caches by installing this +subpackage only, without the rest of the SSSD. The sssd-kcm subpackage +also includes a krb5.conf.d snippet that allows the admin to just uncomment +the KCM defaults and instructs them to start the socket. + +The server can be configured in sssd.conf in the "[kcm]" section. +By default, the server only listens on the same socket path the Heimdal +server uses, which is "/var/run/.heim_org.h5l.kcm-socket". This is, +however, configurable. + +The file src/responder/kcm/kcm.h is more or less directly imported from +the MIT Kerberos tree, with an additional sentinel code and some +comments. Not all KCM operations are implemented, only those that also +the MIT client implements. That said, this KCM server should also be +usable with a Heimdal client, although no special testing was with this +hybrid. + +The patch also adds several error codes that will be used in later +patches. + +Related to: + https://pagure.io/SSSD/sssd/issue/2887 + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + Makefile.am | 53 ++++++++ + configure.ac | 10 +- + contrib/kcm_default_ccache | 12 ++ + contrib/sssd.spec.in | 41 ++++++ + src/conf_macros.m4 | 16 +++ + src/confdb/confdb.h | 3 + + src/config/cfg_rules.ini | 19 +++ + src/external/libcurl.m4 | 6 +- + src/responder/kcm/kcm.c | 254 +++++++++++++++++++++++++++++++++++ + src/responder/kcm/kcm.h | 97 +++++++++++++ + src/responder/kcm/kcmsrv_cmd.c | 65 +++++++++ + src/responder/kcm/kcmsrv_pvt.h | 58 ++++++++ + src/sysv/systemd/sssd-kcm.service.in | 9 ++ + src/sysv/systemd/sssd-kcm.socket.in | 10 ++ + src/util/util_errors.c | 5 + + src/util/util_errors.h | 5 + + 16 files changed, 658 insertions(+), 5 deletions(-) + create mode 100644 contrib/kcm_default_ccache + create mode 100644 src/responder/kcm/kcm.c + create mode 100644 src/responder/kcm/kcm.h + create mode 100644 src/responder/kcm/kcmsrv_cmd.c + create mode 100644 src/responder/kcm/kcmsrv_pvt.h + create mode 100644 src/sysv/systemd/sssd-kcm.service.in + create mode 100644 src/sysv/systemd/sssd-kcm.socket.in + +diff --git a/Makefile.am b/Makefile.am +index 7516338bc6fd95045d20db8155a0c82fd7003358..4248536e90370c1aab59549a9c18408ef314e6d4 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -87,6 +87,7 @@ sudolibdir = @sudolibpath@ + polkitdir = @polkitdir@ + pamconfdir = $(sysconfdir)/pam.d + systemtap_tapdir = @tapset_dir@ ++krb5sysincludedir = $(sysconfdir)/krb5.conf.d + + if HAVE_SYSTEMD_UNIT + ifp_exec_cmd = $(sssdlibexecdir)/sssd_ifp --uid 0 --gid 0 --debug-to-files --dbus-activated +@@ -186,6 +187,11 @@ endif + if BUILD_SECRETS + sssdlibexec_PROGRAMS += sssd_secrets + endif ++if BUILD_KCM ++sssdlibexec_PROGRAMS += sssd_kcm ++dist_krb5sysinclude_DATA = contrib/kcm_default_ccache ++endif ++ + + if BUILD_PAC_RESPONDER + sssdlibexec_PROGRAMS += sssd_pac +@@ -703,6 +709,8 @@ dist_noinst_HEADERS = \ + src/responder/secrets/secsrv_private.h \ + src/responder/secrets/secsrv_local.h \ + src/responder/secrets/secsrv_proxy.h \ ++ src/responder/kcm/kcm.h \ ++ src/responder/kcm/kcmsrv_pvt.h \ + src/sbus/sbus_client.h \ + src/sbus/sssd_dbus.h \ + src/sbus/sssd_dbus_meta.h \ +@@ -1476,6 +1484,24 @@ sssd_secrets_LDADD = \ + $(NULL) + endif + ++if BUILD_KCM ++sssd_kcm_SOURCES = \ ++ src/responder/kcm/kcm.c \ ++ src/responder/kcm/kcmsrv_cmd.c \ ++ src/util/sss_sockets.c \ ++ $(SSSD_RESPONDER_OBJ) \ ++ $(NULL) ++sssd_kcm_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(KRB5_CFLAGS) \ ++ $(NULL) ++sssd_kcm_LDADD = \ ++ $(KRB5_LIBS) \ ++ $(SSSD_LIBS) \ ++ $(SSSD_INTERNAL_LTLIBS) \ ++ $(NULL) ++endif ++ + sssd_be_SOURCES = \ + src/providers/data_provider_be.c \ + src/providers/data_provider_req.c \ +@@ -4259,6 +4285,12 @@ if BUILD_SUDO + src/sysv/systemd/sssd-sudo.service \ + $(NULL) + endif ++if BUILD_KCM ++ systemdunit_DATA += \ ++ src/sysv/systemd/sssd-kcm.socket \ ++ src/sysv/systemd/sssd-kcm.service \ ++ $(NULL) ++endif + if WITH_JOURNALD + systemdconf_DATA += \ + src/sysv/systemd/journal.conf +@@ -4350,6 +4382,12 @@ EXTRA_DIST += \ + src/sysv/systemd/sssd-sudo.service.in \ + $(NULL) + endif ++if BUILD_KCM ++EXTRA_DIST += \ ++ src/sysv/systemd/sssd-kcm.socket.in \ ++ src/sysv/systemd/sssd-kcm.service.in \ ++ $(NULL) ++endif + + src/sysv/systemd/sssd.service: src/sysv/systemd/sssd.service.in Makefile + @$(MKDIR_P) src/sysv/systemd/ +@@ -4433,6 +4471,16 @@ src/sysv/systemd/sssd-sudo.service: src/sysv/systemd/sssd-sudo.service.in Makefi + $(replace_script) + endif + ++if BUILD_KCM ++src/sysv/systemd/sssd-kcm.socket: src/sysv/systemd/sssd-kcm.socket.in Makefile ++ @$(MKDIR_P) src/sysv/systemd/ ++ $(replace_script) ++ ++src/sysv/systemd/sssd-kcm.service: src/sysv/systemd/sssd-kcm.service.in Makefile ++ @$(MKDIR_P) src/sysv/systemd/ ++ $(replace_script) ++endif ++ + SSSD_USER_DIRS = \ + $(DESTDIR)$(dbpath) \ + $(DESTDIR)$(keytabdir) \ +@@ -4596,6 +4644,9 @@ install-data-hook: + if BUILD_SAMBA + mv $(DESTDIR)/$(winbindplugindir)/winbind_idmap_sss.so $(DESTDIR)/$(winbindplugindir)/sss.so + endif ++if BUILD_KCM ++ $(MKDIR_P) $(DESTDIR)/$(krb5sysincludedir) ++endif + + uninstall-hook: + if [ -f $(abs_builddir)/src/config/.files2 ]; then \ +@@ -4670,6 +4721,8 @@ endif + rm -f $(builddir)/src/sysv/systemd/sssd-sudo.service + rm -f $(builddir)/src/sysv/systemd/sssd-secrets.socket + rm -f $(builddir)/src/sysv/systemd/sssd-secrets.service ++ rm -f $(builddir)/src/sysv/systemd/sssd-kcm.socket ++ rm -f $(builddir)/src/sysv/systemd/sssd-kcm.service + rm -f $(builddir)/src/sysv/systemd/journal.conf + + CLEANFILES += *.X */*.X */*/*.X +diff --git a/configure.ac b/configure.ac +index dd1012015a5fea9f25e5b5199b4868fbc0bc14c4..c363d48a806cc1998e85779a92b6b59b0e2a5c9c 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -155,6 +155,7 @@ WITH_SSSD_USER + SSSD_RUNSTATEDIR + WITH_SECRETS + WITH_SECRETS_DB_PATH ++WITH_KCM + + m4_include([src/external/pkg.m4]) + m4_include([src/external/libpopt.m4]) +@@ -193,13 +194,20 @@ m4_include([src/external/libresolv.m4]) + m4_include([src/external/intgcheck.m4]) + m4_include([src/external/systemtap.m4]) + m4_include([src/external/service.m4]) +-m4_include([src/external/libcurl.m4]) + + if test x$with_secrets = xyes; then + m4_include([src/external/libhttp_parser.m4]) + m4_include([src/external/libjansson.m4]) + fi + ++if test x$with_kcm = xyes; then ++ m4_include([src/external/libcurl.m4]) ++fi ++# This variable is defined by external/libcurl.m4, but conditionals ++# must be always evaluated ++AM_CONDITIONAL([BUILD_WITH_LIBCURL], ++ [test x"$have_curlopt_unix_sockpath" = xyes]) ++ + WITH_UNICODE_LIB + if test x$unicode_lib = xlibunistring; then + m4_include([src/external/libunistring.m4]) +diff --git a/contrib/kcm_default_ccache b/contrib/kcm_default_ccache +new file mode 100644 +index 0000000000000000000000000000000000000000..ac88fca86b60b19f772912b5d9d14595a96d101d +--- /dev/null ++++ b/contrib/kcm_default_ccache +@@ -0,0 +1,12 @@ ++# This file should normally be installed by your distribution into a ++# directory that is included from the Kerberos configuration file (/etc/krb5.conf) ++# On Fedora/RHEL/CentOS, this is /etc/krb5.conf.d/ ++# ++# To enable the KCM credential cache, uncomment the following lines and ++# enable the KCM socket and the service: ++# systemctl enable sssd-kcm.socket ++# systemctl start sssd-kcm.socket ++# systemctl enable sssd-kcm.service ++ ++#[libdefaults] ++# default_ccache_name = KCM: +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index 28ebe07a26a3112210b092b7831e7f6aae061c8d..5c7c2af521a84ef2ca6cca7b2d6cd1f9b3057056 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -112,6 +112,13 @@ + %global enable_systemtap_opt --enable-systemtap + %endif + ++%if (0%{?fedora} >= 23 || 0%{?rhel} >= 7) ++ %global with_kcm 1 ++ %global with_kcm_option --with-kcm ++%else ++ %global with_kcm_option --without-kcm ++%endif ++ + Name: @PACKAGE_NAME@ + Version: @PACKAGE_VERSION@ + Release: 0@PRERELEASE_VERSION@%{?dist} +@@ -677,6 +684,18 @@ Requires: libsss_certmap = %{version}-%{release} + %description -n libsss_certmap-devel + Library to map certificates to users based on rules + ++%if (0%{?with_kcm} == 1) ++%package kcm ++Summary: An implementation of a Kerberos KCM server ++Group: Applications/System ++License: GPLv3+ ++Requires: sssd-common = %{version}-%{release} ++ ++%description kcm ++An implementation of a Kerberos KCM server. Use this package if you want to ++use the KCM: Kerberos credentials cache. ++%endif ++ + %prep + %setup -q -n %{name}-%{version} + +@@ -706,6 +725,7 @@ autoreconf -ivf + %{?with_python3_option} \ + %{?enable_polkit_rules_option} \ + %{?enable_systemtap_opt} \ ++ %{?with_kcm_option} \ + %{?experimental} + + make %{?_smp_mflags} all +@@ -1178,6 +1198,15 @@ done + %{_libdir}/libsss_certmap.so + %{_libdir}/pkgconfig/sss_certmap.pc + ++%if (0%{?with_kcm} == 1) ++%files kcm ++%{_libexecdir}/%{servicename}/sssd_kcm ++%dir %{_sysconfdir}/krb5.conf.d ++%config(noreplace) %{_sysconfdir}/krb5.conf.d/kcm_default_ccache ++%{_unitdir}/sssd-kcm.socket ++%{_unitdir}/sssd-kcm.service ++%endif ++ + %pre common + getent group sssd >/dev/null || groupadd -r sssd + getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd +@@ -1274,6 +1303,18 @@ fi + + %postun -n libsss_simpleifp -p /sbin/ldconfig + ++%if (0%{?with_kcm} == 1) ++%post kcm ++%systemd_post sssd-kcm.socket ++ ++%preun kcm ++%systemd_preun sssd-kcm.socket ++ ++%postun kcm ++%systemd_postun_with_restart sssd-kcm.socket ++%systemd_postun_with_restart sssd-kcm.service ++%endif ++ + %changelog + * Mon Mar 15 2010 Stephen Gallagher - @PACKAGE_VERSION@-0@PRERELEASE_VERSION@ + - Automated build of the SSSD +diff --git a/src/conf_macros.m4 b/src/conf_macros.m4 +index 749e7694f4dd7086468e461194ef274be2094236..420997229cb3c244afd8fb21b074e43a21de0eda 100644 +--- a/src/conf_macros.m4 ++++ b/src/conf_macros.m4 +@@ -887,6 +887,22 @@ AC_DEFUN([WITH_SECRETS], + AM_CONDITIONAL([BUILD_SECRETS], [test x"$with_secrets" = xyes]) + ]) + ++AC_DEFUN([WITH_KCM], ++ [ AC_ARG_WITH([kcm], ++ [AC_HELP_STRING([--with-kcm], ++ [Whether to build with KCM server support [yes]] ++ ) ++ ], ++ [with_kcm=$withval], ++ with_kcm=yes ++ ) ++ ++ if test x"$with_kcm" = xyes; then ++ AC_DEFINE(BUILD_KCM, 1, [whether to build with KCM server support]) ++ fi ++ AM_CONDITIONAL([BUILD_KCM], [test x"$with_kcm" = xyes]) ++ ]) ++ + AC_DEFUN([WITH_SECRETS_DB_PATH], + [ AC_ARG_WITH([secrets-db-path], + [AC_HELP_STRING([--with-secrets-db-path=PATH], +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index c05b1cee45ece748bf8e2b1e1ecf3dc28979e48b..c443e869a7a6782265b42c4ad122867c4e3dd8e0 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -231,6 +231,9 @@ + #define CONFDB_SEC_MAX_SECRETS "max_secrets" + #define CONFDB_SEC_MAX_PAYLOAD_SIZE "max_payload_size" + ++/* KCM Service */ ++#define CONFDB_KCM_CONF_ENTRY "config/kcm" ++#define CONFDB_KCM_SOCKET "socket_path" + + struct confdb_ctx; + struct config_file_ctx; +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index c287328828cae2f0ad8a5a105f1c2b3e05353021..5e789c51658c51c0af1338d23d6c0f30f40bf119 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -9,6 +9,7 @@ section = ssh + section = pac + section = ifp + section = secrets ++section = kcm + section_re = ^secrets/users/[0-9]\+$ + section_re = ^domain/.*$ + +@@ -262,6 +263,24 @@ option = forward_headers + option = username + option = password + ++# KCM responder ++[rule/allowed_kcm_options] ++validator = ini_allowed_options ++section_re = ^kcm$ ++ ++option = timeout ++option = debug ++option = debug_level ++option = debug_timestamps ++option = debug_microseconds ++option = debug_to_files ++option = command ++option = reconnection_retries ++option = fd_limit ++option = client_idle_timeout ++option = description ++option = socket_path ++ + [rule/allowed_domain_options] + validator = ini_allowed_options + section_re = ^domain/.*$ +diff --git a/src/external/libcurl.m4 b/src/external/libcurl.m4 +index 3bc303ca4e1dea8a04117e32b8c4466b80d885b1..b420b04ad806bd1251f086b773ffe480d39f8bd3 100644 +--- a/src/external/libcurl.m4 ++++ b/src/external/libcurl.m4 +@@ -9,8 +9,8 @@ AS_IF([test x$enable_libcurl = xyes], + [PKG_CHECK_MODULES([CURL], + [libcurl], + [found_libcurl=yes], +- [AC_MSG_WARN([ +-The libcurl development library was not found. Some features will be disabled.]) ++ [AC_MSG_ERROR([ ++The libcurl development library was not found.]) + ])]) + + AS_IF([test x"$found_libcurl" = xyes], +@@ -32,7 +32,5 @@ AS_IF([test x"$found_libcurl" = xyes], + AC_SUBST(CURL_LIBS) + AC_SUBST(CURL_CFLAGS) + +-AM_CONDITIONAL([BUILD_WITH_LIBCURL], +- [test x"$have_curlopt_unix_sockpath" = xyes]) + AM_COND_IF([BUILD_WITH_LIBCURL], + [AC_DEFINE_UNQUOTED(HAVE_LIBCURL, 1, [Build with libcurl support])]) +diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c +new file mode 100644 +index 0000000000000000000000000000000000000000..90a6999c5e39d48a1a2ea8168d171612a65077d5 +--- /dev/null ++++ b/src/responder/kcm/kcm.c +@@ -0,0 +1,254 @@ ++/* ++ SSSD ++ ++ KCM Server - the mainloop and server setup ++ ++ Copyright (C) Red Hat, 2016 ++ ++ 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 . ++*/ ++ ++#include "config.h" ++ ++#include ++#include ++ ++#include "responder/kcm/kcm.h" ++#include "responder/kcm/kcmsrv_pvt.h" ++#include "responder/common/responder.h" ++#include "util/util.h" ++ ++#define DEFAULT_KCM_FD_LIMIT 2048 ++ ++#ifndef SSS_KCM_SOCKET_NAME ++#define SSS_KCM_SOCKET_NAME DEFAULT_KCM_SOCKET_PATH ++#endif ++ ++static int kcm_responder_ctx_destructor(void *ptr) ++{ ++ struct resp_ctx *rctx = talloc_get_type(ptr, struct resp_ctx); ++ ++ /* mark that we are shutting down the responder, so it is propagated ++ * into underlying contexts that are freed right before rctx */ ++ DEBUG(SSSDBG_TRACE_FUNC, "Responder is being shut down\n"); ++ rctx->shutting_down = true; ++ ++ return 0; ++} ++ ++static int kcm_get_config(struct kcm_ctx *kctx) ++{ ++ int ret; ++ char *sock_name; ++ ++ ret = confdb_get_int(kctx->rctx->cdb, ++ CONFDB_KCM_CONF_ENTRY, ++ CONFDB_SERVICE_FD_LIMIT, ++ DEFAULT_KCM_FD_LIMIT, ++ &kctx->fd_limit); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to get file descriptors limit\n"); ++ goto done; ++ } ++ ++ ret = confdb_get_int(kctx->rctx->cdb, ++ kctx->rctx->confdb_service_path, ++ CONFDB_RESPONDER_CLI_IDLE_TIMEOUT, ++ CONFDB_RESPONDER_CLI_IDLE_DEFAULT_TIMEOUT, ++ &kctx->rctx->client_idle_timeout); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get the client idle timeout [%d]: %s\n", ++ ret, strerror(ret)); ++ goto done; ++ } ++ ++ /* Ensure that the client timeout is at least ten seconds */ ++ if (kctx->rctx->client_idle_timeout < 10) { ++ kctx->rctx->client_idle_timeout = 10; ++ } ++ ++ ret = confdb_get_string(kctx->rctx->cdb, ++ kctx->rctx, ++ kctx->rctx->confdb_service_path, ++ CONFDB_KCM_SOCKET, ++ SSS_KCM_SOCKET_NAME, ++ &sock_name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get the client idle timeout [%d]: %s\n", ++ ret, strerror(ret)); ++ goto done; ++ } ++ kctx->rctx->sock_name = sock_name; ++ ++ ret = EOK; ++ ++done: ++ return ret; ++} ++ ++static int kcm_data_destructor(void *ptr) ++{ ++ struct kcm_resp_ctx *kcm_data = talloc_get_type(ptr, struct kcm_resp_ctx); ++ ++ if (kcm_data != NULL) { ++ krb5_free_context(kcm_data->k5c); ++ } ++ return 0; ++} ++ ++static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx) ++{ ++ struct kcm_resp_ctx *kcm_data; ++ krb5_error_code kret; ++ ++ kcm_data = talloc_zero(mem_ctx, struct kcm_resp_ctx); ++ if (kcm_data == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing kcm data\n"); ++ return NULL; ++ } ++ ++ kret = krb5_init_context(&kcm_data->k5c); ++ if (kret != EOK) { ++ talloc_free(kcm_data); ++ return NULL; ++ } ++ talloc_set_destructor((TALLOC_CTX*)kcm_data, kcm_data_destructor); ++ ++ return kcm_data; ++} ++ ++static int kcm_process_init(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct confdb_ctx *cdb) ++{ ++ struct resp_ctx *rctx; ++ struct kcm_ctx *kctx; ++ int ret; ++ ++ rctx = talloc_zero(mem_ctx, struct resp_ctx); ++ if (rctx == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing resp_ctx\n"); ++ return ENOMEM; ++ } ++ rctx->ev = ev; ++ rctx->cdb = cdb; ++ rctx->confdb_service_path = CONFDB_KCM_CONF_ENTRY; ++ rctx->shutting_down = false; ++ rctx->lfd = -1; ++ rctx->priv_lfd = -1; ++ ++ talloc_set_destructor((TALLOC_CTX*)rctx, kcm_responder_ctx_destructor); ++ ++ kctx = talloc_zero(rctx, struct kcm_ctx); ++ if (kctx == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing kcm_ctx\n"); ++ ret = ENOMEM; ++ goto fail; ++ } ++ ++ kctx->rctx = rctx; ++ kctx->rctx->pvt_ctx = kctx; ++ ++ ret = kcm_get_config(kctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "fatal error getting KCM config\n"); ++ goto fail; ++ } ++ ++ kctx->kcm_data = kcm_data_setup(kctx); ++ if (kctx->kcm_data == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "fatal error initializing responder data\n"); ++ ret = EIO; ++ goto fail; ++ } ++ ++ /* Set up file descriptor limits */ ++ responder_set_fd_limit(kctx->fd_limit); ++ ++ ret = activate_unix_sockets(rctx, kcm_connection_setup); ++ if (ret != EOK) goto fail; ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "KCM Initialization complete\n"); ++ ++ return EOK; ++ ++fail: ++ talloc_free(rctx); ++ return ret; ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ int opt; ++ poptContext pc; ++ struct main_context *main_ctx; ++ int ret; ++ uid_t uid; ++ gid_t gid; ++ ++ struct poptOption long_options[] = { ++ POPT_AUTOHELP ++ SSSD_MAIN_OPTS ++ SSSD_SERVER_OPTS(uid, gid) ++ POPT_TABLEEND ++ }; ++ ++ /* Set debug level to invalid value so we can deside if -d 0 was used. */ ++ debug_level = SSSDBG_INVALID; ++ ++ umask(DFL_RSP_UMASK); ++ ++ pc = poptGetContext(argv[0], argc, argv, long_options, 0); ++ while((opt = poptGetNextOpt(pc)) != -1) { ++ switch(opt) { ++ default: ++ fprintf(stderr, "\nInvalid option %s: %s\n\n", ++ poptBadOption(pc, 0), poptStrerror(opt)); ++ poptPrintUsage(pc, stderr, 0); ++ return 1; ++ } ++ } ++ ++ poptFreeContext(pc); ++ ++ DEBUG_INIT(debug_level); ++ ++ /* set up things like debug, signals, daemonization, etc... */ ++ debug_log_file = "sssd_kcm"; ++ ++ ret = server_setup("sssd[kcm]", 0, uid, gid, CONFDB_KCM_CONF_ENTRY, ++ &main_ctx); ++ if (ret != EOK) return 2; ++ ++ ret = die_if_parent_died(); ++ if (ret != EOK) { ++ /* This is not fatal, don't return */ ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Could not set up to exit when parent process does\n"); ++ } ++ ++ ret = kcm_process_init(main_ctx, ++ main_ctx->event_ctx, ++ main_ctx->confdb_ctx); ++ if (ret != EOK) return 3; ++ ++ /* loop on main */ ++ server_loop(main_ctx); ++ ++ return 0; ++} +diff --git a/src/responder/kcm/kcm.h b/src/responder/kcm/kcm.h +new file mode 100644 +index 0000000000000000000000000000000000000000..1ea7e9bbca754dca2eeb72a08830fa2f95713b4f +--- /dev/null ++++ b/src/responder/kcm/kcm.h +@@ -0,0 +1,97 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* include/kcm.h - Kerberos cache manager protocol declarations */ ++/* ++ * Copyright (C) 2014 by the Massachusetts Institute of Technology. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ++ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef KCM_H ++#define KCM_H ++ ++#define KCM_PROTOCOL_VERSION_MAJOR 2 ++#define KCM_PROTOCOL_VERSION_MINOR 0 ++ ++#define KCM_UUID_LEN 16 ++ ++/* This should ideally be in RUNSTATEDIR, but Heimdal uses a hardcoded ++ * /var/run, and we need to use the same default path. */ ++#define DEFAULT_KCM_SOCKET_PATH "/var/run/.heim_org.h5l.kcm-socket" ++#define DEFAULT_KCM_MACH_SERVICE "org.h5l.kcm" ++ ++/* ++ * All requests begin with: ++ * major version (1 bytes) ++ * minor version (1 bytes) ++ * opcode (16-bit big-endian) ++ * ++ * All replies begin with a 32-bit big-endian reply code. ++ * ++ * Parameters are appended to the request or reply with no delimiters. Flags ++ * and time offsets are stored as 32-bit big-endian integers. Names are ++ * marshalled as zero-terminated strings. Principals and credentials are ++ * marshalled in the v4 FILE ccache format. UUIDs are 16 bytes. UUID lists ++ * are not delimited, so nothing can come after them. ++ */ ++ ++/* Opcodes without comments are currently unused in the MIT client ++ * implementation. */ ++typedef enum kcm_opcode { ++ KCM_OP_NOOP, ++ KCM_OP_GET_NAME, ++ KCM_OP_RESOLVE, ++ KCM_OP_GEN_NEW, /* 0x3 () -> (name) */ ++ KCM_OP_INITIALIZE, /* 0x4 (name, princ) -> () */ ++ KCM_OP_DESTROY, /* 0x4 (name) -> () */ ++ KCM_OP_STORE, /* 0x6 (name, cred) -> () */ ++ KCM_OP_RETRIEVE, ++ KCM_OP_GET_PRINCIPAL, /* 0x8 (name) -> (princ) */ ++ KCM_OP_GET_CRED_UUID_LIST, /* 0x9 (name) -> (uuid, ...) */ ++ KCM_OP_GET_CRED_BY_UUID, /* 0xa (name, uuid) -> (cred) */ ++ KCM_OP_REMOVE_CRED, /* (name, flags, credtag) -> () */ ++ KCM_OP_SET_FLAGS, ++ KCM_OP_CHOWN, ++ KCM_OP_CHMOD, ++ KCM_OP_GET_INITIAL_TICKET, ++ KCM_OP_GET_TICKET, ++ KCM_OP_MOVE_CACHE, ++ KCM_OP_GET_CACHE_UUID_LIST, /* 0x12 () -> (uuid, ...) */ ++ KCM_OP_GET_CACHE_BY_UUID, /* 0x13 (uuid) -> (name) */ ++ KCM_OP_GET_DEFAULT_CACHE, /* 0x14 () -> (name) */ ++ KCM_OP_SET_DEFAULT_CACHE, /* 0x15 (name) -> () */ ++ KCM_OP_GET_KDC_OFFSET, /* 0x16 (name) -> (offset) */ ++ KCM_OP_SET_KDC_OFFSET, /* 0x17 (name, offset) -> () */ ++ KCM_OP_ADD_NTLM_CRED, ++ KCM_OP_HAVE_NTLM_CRED, ++ KCM_OP_DEL_NTLM_CRED, ++ KCM_OP_DO_NTLM_AUTH, ++ KCM_OP_GET_NTLM_USER_LIST, ++ ++ KCM_OP_SENTINEL, /* SSSD addition, not in the MIT header */ ++} kcm_opcode; ++ ++#endif /* KCM_H */ +diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c +new file mode 100644 +index 0000000000000000000000000000000000000000..e9a03cbd41169c93e00b0630dc1e05e205881ec9 +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_cmd.c +@@ -0,0 +1,65 @@ ++/* ++ SSSD ++ ++ KCM Server - the KCM server request and reply parsing and dispatching ++ ++ Copyright (C) Red Hat, 2016 ++ ++ 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 . ++*/ ++ ++#include "config.h" ++#include "util/util.h" ++#include "responder/common/responder.h" ++ ++struct kcm_proto_ctx { ++ void *unused; ++}; ++ ++static void kcm_fd_handler(struct tevent_context *ev, ++ struct tevent_fd *fde, ++ uint16_t flags, void *ptr) ++{ ++ errno_t ret; ++ struct cli_ctx *cctx = talloc_get_type(ptr, struct cli_ctx); ++ ++ /* Always reset the idle timer on any activity */ ++ ret = reset_client_idle_timer(cctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Could not create idle timer for client. " ++ "This connection may not auto-terminate\n"); ++ /* Non-fatal, continue */ ++ } ++} ++ ++int kcm_connection_setup(struct cli_ctx *cctx) ++{ ++ struct kcm_proto_ctx *protocol_ctx; ++ ++ protocol_ctx = talloc_zero(cctx, struct kcm_proto_ctx); ++ if (protocol_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ cctx->protocol_ctx = protocol_ctx; ++ cctx->cfd_handler = kcm_fd_handler; ++ return EOK; ++} ++ ++/* Dummy, not used here but required to link to other responder files */ ++struct cli_protocol_version *register_cli_protocol_version(void) ++{ ++ return NULL; ++} +diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h +new file mode 100644 +index 0000000000000000000000000000000000000000..a7c9d062c17f09986d894064176c3a461d396ac0 +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_pvt.h +@@ -0,0 +1,58 @@ ++/* ++ SSSD ++ ++ KCM Server - private header file ++ ++ Copyright (C) Red Hat, 2016 ++ ++ 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 . ++*/ ++ ++#ifndef __KCMSRV_PVT_H__ ++#define __KCMSRV_PVT_H__ ++ ++#include "config.h" ++ ++#include ++#include "responder/common/responder.h" ++ ++/* KCM IO structure */ ++struct kcm_data { ++ uint8_t *data; ++ size_t length; ++}; ++ ++/* To avoid leaking the sssd-specific responder data to other ++ * modules, the ccache databases and other KCM specific data ++ * are kept separately ++ */ ++struct kcm_resp_ctx { ++ krb5_context k5c; ++}; ++ ++/* responder context that contains both the responder data, ++ * like the ccaches and the sssd-specific stuff like the ++ * generic responder ctx ++ */ ++struct kcm_ctx { ++ struct resp_ctx *rctx; ++ int fd_limit; ++ char *socket_path; ++ ++ struct kcm_resp_ctx *kcm_data; ++}; ++ ++int kcm_connection_setup(struct cli_ctx *cctx); ++ ++#endif /* __KCMSRV_PVT_H__ */ +diff --git a/src/sysv/systemd/sssd-kcm.service.in b/src/sysv/systemd/sssd-kcm.service.in +new file mode 100644 +index 0000000000000000000000000000000000000000..1e2bee12dc3bedd17d41b86f91c9b2b52d985c40 +--- /dev/null ++++ b/src/sysv/systemd/sssd-kcm.service.in +@@ -0,0 +1,9 @@ ++[Unit] ++Description=SSSD Kerberos Cache Manager ++Documentation=man:sssd-kcm(5) ++ ++[Install] ++Also=sssd-kcm.socket ++ ++[Service] ++ExecStart=@libexecdir@/sssd/sssd_kcm --uid 0 --gid 0 --debug-to-files +diff --git a/src/sysv/systemd/sssd-kcm.socket.in b/src/sysv/systemd/sssd-kcm.socket.in +new file mode 100644 +index 0000000000000000000000000000000000000000..80ec1c0c8f190e83de0b603df8e90aa49d2ec181 +--- /dev/null ++++ b/src/sysv/systemd/sssd-kcm.socket.in +@@ -0,0 +1,10 @@ ++[Unit] ++Description=SSSD Secrets Service responder socket ++Documentation=man:sssd-kcm(8) ++Requires=sssd-secrets.socket ++ ++[Socket] ++ListenStream=@localstatedir@/run/.heim_org.h5l.kcm-socket ++ ++[Install] ++WantedBy=sockets.target +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index 17388c997db5315c2491af1021e75aff07632488..23cfdf9c6116a2c8e569a041e8289b65a112fd08 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -40,6 +40,7 @@ struct err_string error_to_str[] = { + { "Credentials are expired, old ccache was removed" }, /* ERR_CREDS_EXPIRED_CCACHE */ + { "Failure setting user credentials"}, /* ERR_CREDS_INVALID */ + { "No cached credentials available" }, /* ERR_NO_CACHED_CREDS */ ++ { "No matching credentials found" }, /* ERR_NO_MATCHING_CREDS */ + { "Cached credentials are expired" }, /* ERR_CACHED_CREDS_EXPIRED */ + { "Authentication Denied" }, /* ERR_AUTH_DENIED */ + { "Authentication Failed" }, /* ERR_AUTH_FAILED */ +@@ -104,6 +105,10 @@ struct err_string error_to_str[] = { + { "The secret payload size is too large" }, /* ERR_SEC_PAYLOAD_SIZE_IS_TOO_LARGE */ + { "No authentication methode available" }, /* ERR_NO_AUTH_METHOD_AVAILABLE */ + { "Smartcard authentication not supported" }, /* ERR_SC_AUTH_NOT_SUPPORTED */ ++ { "Malformed input KCM packet" }, /* ERR_KCM_MALFORMED_IN_PKT */ ++ { "KCM operation not implemented" }, /* ERR_KCM_OP_NOT_IMPLEMENTED */ ++ { "End of credential cache reached" }, /* ERR_KCM_CC_END */ ++ { "Credential cache name not allowed" }, /* ERR_KCM_WRONG_CCNAME_FORMAT */ + { "ERR_LAST" } /* ERR_LAST */ + }; + +diff --git a/src/util/util_errors.h b/src/util/util_errors.h +index 7aacad26084a3a2af6333988f07db865f6a4d299..387d481616db1ed5e22b73fae82632a582fae946 100644 +--- a/src/util/util_errors.h ++++ b/src/util/util_errors.h +@@ -62,6 +62,7 @@ enum sssd_errors { + ERR_CREDS_EXPIRED_CCACHE, + ERR_CREDS_INVALID, + ERR_NO_CACHED_CREDS, ++ ERR_NO_MATCHING_CREDS, + ERR_CACHED_CREDS_EXPIRED, + ERR_AUTH_DENIED, + ERR_AUTH_FAILED, +@@ -126,6 +127,10 @@ enum sssd_errors { + ERR_SEC_PAYLOAD_SIZE_IS_TOO_LARGE, + ERR_NO_AUTH_METHOD_AVAILABLE, + ERR_SC_AUTH_NOT_SUPPORTED, ++ ERR_KCM_MALFORMED_IN_PKT, ++ ERR_KCM_OP_NOT_IMPLEMENTED, ++ ERR_KCM_CC_END, ++ ERR_KCM_WRONG_CCNAME_FORMAT, + ERR_LAST /* ALWAYS LAST */ + }; + +-- +2.9.3 + diff --git a/SOURCES/0023-KCM-request-parsing-and-sending-a-reply.patch b/SOURCES/0023-KCM-request-parsing-and-sending-a-reply.patch new file mode 100644 index 0000000..5e59dc2 --- /dev/null +++ b/SOURCES/0023-KCM-request-parsing-and-sending-a-reply.patch @@ -0,0 +1,578 @@ +From aface2604c53db717299ac3dfe798dfd0c540f99 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 23 Sep 2016 14:00:10 +0200 +Subject: [PATCH 23/36] KCM: request parsing and sending a reply +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Implements parsing the KCM client request into per-client buffers and +sending a response for both the failure case and for success. + +The protocol is documented at: + http://k5wiki.kerberos.org/wiki/Projects/KCM_client + +Several places don't use the sss_iobuf structure, because they don't +parse variable-length data from the buffer and it's much more efficient +to just allocate the needed request and reply structure on the stack. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + src/responder/kcm/kcmsrv_cmd.c | 467 ++++++++++++++++++++++++++++++++++++++++- + src/responder/kcm/kcmsrv_pvt.h | 21 +- + 2 files changed, 474 insertions(+), 14 deletions(-) + +diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c +index e9a03cbd41169c93e00b0630dc1e05e205881ec9..cbf70353730d8a4e03d8f75c97395f4ef007e77f 100644 +--- a/src/responder/kcm/kcmsrv_cmd.c ++++ b/src/responder/kcm/kcmsrv_cmd.c +@@ -19,14 +19,430 @@ + along with this program. If not, see . + */ + ++#include ++ + #include "config.h" + #include "util/util.h" ++#include "util/sss_iobuf.h" + #include "responder/common/responder.h" ++#include "responder/kcm/kcmsrv_pvt.h" ++#include "responder/kcm/kcm.h" + +-struct kcm_proto_ctx { +- void *unused; ++/* The first four bytes of a message is always the size */ ++#define KCM_MSG_LEN_SIZE 4 ++ ++/* The return code is 32bits */ ++#define KCM_RETCODE_SIZE 4 ++ ++/* The maximum length of a request or reply as defined by the RPC ++ * protocol. This is the same constant size as MIT KRB5 uses ++ */ ++#define KCM_PACKET_MAX_SIZE 2048 ++ ++/* KCM operation, its raw input and raw output and result */ ++struct kcm_op_io { ++ struct kcm_op *op; ++ struct kcm_data request; ++ struct sss_iobuf *reply; ++}; ++ ++/** ++ * KCM IO-vector operations ++ */ ++struct kcm_iovec { ++ /* We don't use iovec b/c void pointers don't allow for ++ * pointer arithmetics and it's convenient to keep track ++ * of processed bytes ++ */ ++ uint8_t *kiov_base; ++ size_t kiov_len; ++ size_t nprocessed; ++}; ++ ++static errno_t kcm_iovec_op(int fd, struct kcm_iovec *kiov, bool do_read) ++{ ++ ssize_t len; ++ struct iovec iov[1]; ++ ++ iov[0].iov_base = kiov->kiov_base + kiov->nprocessed; ++ iov[0].iov_len = kiov->kiov_len - kiov->nprocessed; ++ if (iov[0].iov_len == 0) { ++ /* This iovec is full (read) or depleted (write), proceed to the next one */ ++ return EOK; ++ } ++ ++ if (do_read) { ++ len = readv(fd, iov, 1); ++ } else { ++ len = writev(fd, iov, 1); ++ } ++ ++ if (len == -1) { ++ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { ++ return EAGAIN; ++ } else { ++ return errno; ++ } ++ } ++ ++ if (len == 0) { ++ /* Read event on fd that doesn't yield data? error */ ++ return ENODATA; ++ } ++ ++ /* Decrease the amount of available free space in the iovec */ ++ kiov->nprocessed += len; ++ return EOK; ++} ++ ++static errno_t kcm_read_iovec(int fd, struct kcm_iovec *kiov) ++{ ++ return kcm_iovec_op(fd, kiov, true); ++} ++ ++static errno_t kcm_write_iovec(int fd, struct kcm_iovec *kiov) ++{ ++ return kcm_iovec_op(fd, kiov, false); ++} ++ ++/** ++ * Parsing KCM input ++ * ++ * The request is received as two IO vectors: ++ * ++ * first iovec: ++ * length 32-bit big-endian integer ++ * ++ * second iovec: ++ * major protocol number 8-bit big-endian integer ++ * minor protocol number 8-bit big-endian integer ++ * opcode 16-bit big-endian integer ++ * message payload buffer ++ */ ++struct kcm_reqbuf { ++ uint8_t lenbuf[KCM_MSG_LEN_SIZE]; ++ struct kcm_iovec v_len; ++ ++ /* Includes the major, minor versions etc */ ++ uint8_t msgbuf[KCM_PACKET_MAX_SIZE]; ++ struct kcm_iovec v_msg; ++}; ++ ++static errno_t kcm_input_parse(struct kcm_reqbuf *reqbuf, ++ struct kcm_op_io *op_io) ++{ ++ size_t lc = 0; ++ size_t mc = 0; ++ uint16_t opcode = 0; ++ uint16_t opcode_be = 0; ++ uint32_t len_be = 0; ++ uint32_t msglen; ++ uint8_t proto_maj = 0; ++ uint8_t proto_min = 0; ++ ++ /* The first 4 bytes before the payload is message length */ ++ SAFEALIGN_COPY_UINT32_CHECK(&len_be, ++ reqbuf->v_len.kiov_base, ++ reqbuf->v_len.kiov_len, ++ &lc); ++ msglen = be32toh(len_be); ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "Received message with length %"PRIu32"\n", msglen); ++ ++ if (msglen == 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Illegal zero-length message\n"); ++ return EBADMSG; ++ } ++ ++ if (msglen != reqbuf->v_msg.nprocessed) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Sender claims the message is %"PRIu32" bytes, " ++ "but received %zu\n", ++ msglen, reqbuf->v_msg.nprocessed); ++ return EBADMSG; ++ } ++ ++ /* First 16 bits are 8 bit major and 8bit major protocol version */ ++ SAFEALIGN_COPY_UINT8_CHECK(&proto_maj, ++ reqbuf->v_msg.kiov_base + mc, ++ reqbuf->v_msg.kiov_len, ++ &mc); ++ SAFEALIGN_COPY_UINT8_CHECK(&proto_min, ++ reqbuf->v_msg.kiov_base + mc, ++ reqbuf->v_msg.kiov_len, ++ &mc); ++ ++ if (proto_maj != KCM_PROTOCOL_VERSION_MAJOR) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Expected major version %d, got %"PRIu16"\n", ++ KCM_PROTOCOL_VERSION_MAJOR, (uint16_t) proto_maj); ++ return ERR_KCM_MALFORMED_IN_PKT; ++ } ++ ++ if (proto_min != KCM_PROTOCOL_VERSION_MINOR) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Expected minor version %d, got %"PRIu16"\n", ++ KCM_PROTOCOL_VERSION_MINOR, (uint16_t) proto_maj); ++ return ERR_KCM_MALFORMED_IN_PKT; ++ } ++ ++ SAFEALIGN_COPY_UINT16_CHECK(&opcode_be, ++ reqbuf->v_msg.kiov_base + mc, ++ reqbuf->v_msg.kiov_len, ++ &mc); ++ ++ opcode = be16toh(opcode_be); ++ DEBUG(SSSDBG_TRACE_LIBS, "Received operation code %"PRIu16"\n", opcode); ++ ++ return EOK; ++} ++ ++/** ++ * Constructing a reply for failure and success ++ * ++ * The reply consists of three IO vectors: ++ * 1) length iovec: ++ * length: 32-bit big-endian ++ * ++ * 2) return code iovec: ++ * retcode: 32-bit big-endian. Non-zero on failure in the KCM server, ++ * zero if the KCM operation ran (even if the operation itself ++ * failed) ++ * ++ * 3) reply iovec ++ * message: buffer, first 32-bits of the buffer is the return code of ++ * the KCM operation, the rest depends on the operation itself. ++ * The buffer's length is specified by the first integer in the ++ * reply (very intuitive, right?) ++ * ++ * The client always reads the length and return code iovectors. However, the ++ * client reads the reply iovec only if retcode is 0 in the return code iovector ++ * (see kcmio_unix_socket_read() in the MIT tree) ++ */ ++struct kcm_repbuf { ++ uint8_t lenbuf[KCM_MSG_LEN_SIZE]; ++ struct kcm_iovec v_len; ++ ++ uint8_t rcbuf[KCM_RETCODE_SIZE]; ++ struct kcm_iovec v_rc; ++ ++ uint8_t msgbuf[KCM_PACKET_MAX_SIZE]; ++ struct kcm_iovec v_msg; ++}; ++ ++static errno_t kcm_failbuf_construct(errno_t ret, ++ struct kcm_repbuf *repbuf) ++{ ++ size_t c; ++ ++ c = 0; ++ SAFEALIGN_SETMEM_UINT32(repbuf->lenbuf, 0, &c); ++ c = 0; ++ SAFEALIGN_SETMEM_UINT32(repbuf->rcbuf, htobe32(ret), &c); ++ ++ return EOK; ++} ++ ++/** ++ * Construct a reply buffer and send it to the KCM client ++ */ ++static void kcm_reply_error(struct cli_ctx *cctx, ++ errno_t retcode, ++ struct kcm_repbuf *repbuf) ++{ ++ errno_t ret; ++ krb5_error_code kerr; ++ ++ DEBUG(SSSDBG_OP_FAILURE, ++ "KCM operation returs failure [%d]: %s\n", ++ retcode, sss_strerror(retcode)); ++ kerr = sss2krb5_error(retcode); ++ ++ ret = kcm_failbuf_construct(kerr, repbuf); ++ if (ret != EOK) { ++ /* If we can't construct the reply buffer, just terminate the client */ ++ talloc_free(cctx); ++ return; ++ } ++ ++ TEVENT_FD_WRITEABLE(cctx->cfde); ++} ++ ++/** ++ * Request-reply dispatcher ++ */ ++struct kcm_req_ctx { ++ /* client context owns per-client buffers including this one */ ++ struct cli_ctx *cctx; ++ ++ /* raw IO buffers */ ++ struct kcm_reqbuf reqbuf; ++ struct kcm_repbuf repbuf; ++ ++ /* long-lived responder structures */ ++ struct kcm_ctx *kctx; ++ ++ struct kcm_op_io op_io; + }; + ++static errno_t kcm_recv_data(int fd, struct kcm_reqbuf *reqbuf) ++{ ++ errno_t ret; ++ ++ ret = kcm_read_iovec(fd, &reqbuf->v_len); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = kcm_read_iovec(fd, &reqbuf->v_msg); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ return EOK; ++} ++ ++static struct kcm_req_ctx *kcm_new_req(TALLOC_CTX *mem_ctx, ++ struct cli_ctx *cctx, ++ struct kcm_ctx *kctx) ++{ ++ struct kcm_req_ctx *req; ++ ++ req = talloc_zero(cctx, struct kcm_req_ctx); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ req->reqbuf.v_len.kiov_base = req->reqbuf.lenbuf; ++ req->reqbuf.v_len.kiov_len = KCM_MSG_LEN_SIZE; ++ ++ req->reqbuf.v_msg.kiov_base = req->reqbuf.msgbuf; ++ req->reqbuf.v_msg.kiov_len = KCM_PACKET_MAX_SIZE; ++ ++ req->repbuf.v_len.kiov_base = req->repbuf.lenbuf; ++ req->repbuf.v_len.kiov_len = KCM_MSG_LEN_SIZE; ++ ++ req->repbuf.v_rc.kiov_base = req->repbuf.rcbuf; ++ req->repbuf.v_rc.kiov_len = KCM_RETCODE_SIZE; ++ ++ req->repbuf.v_msg.kiov_base = req->repbuf.msgbuf; ++ /* Length of the msg iobuf will be adjusted later, so far use the full ++ * length so that constructing the reply can use that capacity ++ */ ++ req->repbuf.v_msg.kiov_len = KCM_PACKET_MAX_SIZE; ++ ++ req->cctx = cctx; ++ req->kctx = kctx; ++ ++ return req; ++} ++ ++static void kcm_recv(struct cli_ctx *cctx) ++{ ++ struct kcm_req_ctx *req; ++ struct kcm_ctx *kctx; ++ int ret; ++ ++ kctx = talloc_get_type(cctx->rctx->pvt_ctx, struct kcm_ctx); ++ req = talloc_get_type(cctx->state_ctx, struct kcm_req_ctx); ++ if (req == NULL) { ++ /* A new request comes in, setup data structures */ ++ req = kcm_new_req(cctx, cctx, kctx); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot set up client connection\n"); ++ talloc_free(cctx); ++ return; ++ } ++ ++ cctx->state_ctx = req; ++ } ++ ++ ret = kcm_recv_data(cctx->cfd, &req->reqbuf); ++ switch (ret) { ++ case ENODATA: ++ DEBUG(SSSDBG_TRACE_ALL, "Client closed connection.\n"); ++ talloc_free(cctx); ++ return; ++ case EAGAIN: ++ DEBUG(SSSDBG_TRACE_ALL, "Retry later\n"); ++ return; ++ case EOK: ++ /* all fine */ ++ break; ++ default: ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to receive data (%d, %s), aborting client\n", ++ ret, sss_strerror(ret)); ++ talloc_free(cctx); ++ return; ++ } ++ ++ ret = kcm_input_parse(&req->reqbuf, &req->op_io); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to parse data (%d, %s), aborting client\n", ++ ret, sss_strerror(ret)); ++ goto fail; ++ } ++ ++ /* do not read anymore, client is done sending */ ++ TEVENT_FD_NOT_READABLE(cctx->cfde); ++ ++ kcm_reply_error(cctx, ret, &req->repbuf); ++ return; ++ ++fail: ++ /* Fail with reply */ ++ kcm_reply_error(cctx, ret, &req->repbuf); ++} ++ ++static int kcm_send_data(struct cli_ctx *cctx) ++{ ++ struct kcm_req_ctx *req; ++ errno_t ret; ++ ++ req = talloc_get_type(cctx->state_ctx, struct kcm_req_ctx); ++ ++ ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_len); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_rc); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_msg); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ return EOK; ++} ++ ++static void kcm_send(struct cli_ctx *cctx) ++{ ++ errno_t ret; ++ ++ ret = kcm_send_data(cctx); ++ if (ret == EAGAIN) { ++ /* not all data was sent, loop again */ ++ return; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting client!\n"); ++ talloc_free(cctx); ++ return; ++ } ++ ++ /* ok all sent */ ++ TEVENT_FD_NOT_WRITEABLE(cctx->cfde); ++ TEVENT_FD_READABLE(cctx->cfde); ++ talloc_zfree(cctx->state_ctx); ++ return; ++} ++ + static void kcm_fd_handler(struct tevent_context *ev, + struct tevent_fd *fde, + uint16_t flags, void *ptr) +@@ -39,25 +455,54 @@ static void kcm_fd_handler(struct tevent_context *ev, + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not create idle timer for client. " +- "This connection may not auto-terminate\n"); ++ "This connection may not auto-terminate\n"); + /* Non-fatal, continue */ + } ++ ++ if (flags & TEVENT_FD_READ) { ++ kcm_recv(cctx); ++ return; ++ } ++ if (flags & TEVENT_FD_WRITE) { ++ kcm_send(cctx); ++ return; ++ } + } + + int kcm_connection_setup(struct cli_ctx *cctx) + { +- struct kcm_proto_ctx *protocol_ctx; +- +- protocol_ctx = talloc_zero(cctx, struct kcm_proto_ctx); +- if (protocol_ctx == NULL) { +- return ENOMEM; +- } +- +- cctx->protocol_ctx = protocol_ctx; + cctx->cfd_handler = kcm_fd_handler; + return EOK; + } + ++krb5_error_code sss2krb5_error(errno_t err) ++{ ++ switch (err) { ++ case EOK: ++ return 0; ++ case ENOMEM: ++ return KRB5_CC_NOMEM; ++ case EACCES: ++ return KRB5_FCC_PERM; ++ case ERR_KCM_OP_NOT_IMPLEMENTED: ++ return KRB5_CC_NOSUPP; ++ case ERR_WRONG_NAME_FORMAT: ++ return KRB5_CC_BADNAME; ++ case ERR_NO_MATCHING_CREDS: ++ return KRB5_FCC_NOFILE; ++ case ERR_NO_CREDS: ++ return KRB5_CC_NOTFOUND; ++ case ERR_KCM_CC_END: ++ return KRB5_CC_END; ++ case ERR_KCM_MALFORMED_IN_PKT: ++ case EINVAL: ++ case EIO: ++ return KRB5_CC_IO; ++ } ++ ++ return KRB5_FCC_INTERNAL; ++} ++ + /* Dummy, not used here but required to link to other responder files */ + struct cli_protocol_version *register_cli_protocol_version(void) + { +diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h +index a7c9d062c17f09986d894064176c3a461d396ac0..fd1fd9fa32d59a323d465def68999f24f84e3923 100644 +--- a/src/responder/kcm/kcmsrv_pvt.h ++++ b/src/responder/kcm/kcmsrv_pvt.h +@@ -27,13 +27,20 @@ + #include + #include "responder/common/responder.h" + +-/* KCM IO structure */ ++/* ++ * KCM IO structure ++ * ++ * In theory we cold use sss_iobuf there, but since iobuf was ++ * made opaque, this allows it to allocate the structures on ++ * the stack in one go. ++ * */ + struct kcm_data { + uint8_t *data; + size_t length; + }; + +-/* To avoid leaking the sssd-specific responder data to other ++/* ++ * To avoid leaking the sssd-specific responder data to other + * modules, the ccache databases and other KCM specific data + * are kept separately + */ +@@ -41,7 +48,8 @@ struct kcm_resp_ctx { + krb5_context k5c; + }; + +-/* responder context that contains both the responder data, ++/* ++ * responder context that contains both the responder data, + * like the ccaches and the sssd-specific stuff like the + * generic responder ctx + */ +@@ -55,4 +63,11 @@ struct kcm_ctx { + + int kcm_connection_setup(struct cli_ctx *cctx); + ++/* ++ * Internally in SSSD-KCM we use SSSD-internal error codes so that we ++ * can always the same sss_strerror() functions to format the errors ++ * nicely, but the client expects libkrb5 error codes. ++ */ ++krb5_error_code sss2krb5_error(errno_t err); ++ + #endif /* __KCMSRV_PVT_H__ */ +-- +2.9.3 + diff --git a/SOURCES/0023-sysdb-add-UPN-suffix-support-for-the-master-domain.patch b/SOURCES/0023-sysdb-add-UPN-suffix-support-for-the-master-domain.patch deleted file mode 100644 index f58a855..0000000 --- a/SOURCES/0023-sysdb-add-UPN-suffix-support-for-the-master-domain.patch +++ /dev/null @@ -1,277 +0,0 @@ -From 2ffd083501491a8ac3880dc834d01f7ee00fddfc Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 30 Jun 2016 13:48:58 +0200 -Subject: [PATCH 23/27] sysdb: add UPN suffix support for the master domain - -sysdb_master_domain_update() and sysdb_master_domain_add_info() are now -aware of the UPN suffix attribute. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 132b31fd5fb74a7627896cdceaf29c7601ed4795) ---- - src/confdb/confdb.h | 1 + - src/db/sysdb.h | 4 ++- - src/db/sysdb_subdomains.c | 49 ++++++++++++++++++++++++++++++-- - src/providers/ad/ad_id.c | 2 +- - src/providers/ad/ad_subdomains.c | 2 +- - src/providers/ipa/ipa_subdomains.c | 10 ++++++- - src/tests/cmocka/test_sysdb_subdomains.c | 18 ++++++++---- - 7 files changed, 74 insertions(+), 12 deletions(-) - -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index cc8f66f02eb5ac10ced826326f80bbf5eda82ee1..0265ccac5ee2e7b8baa05bf6b09df39ea5b4059a 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -315,6 +315,7 @@ struct sss_domain_info { - */ - char *forest; - struct sss_domain_info *forest_root; -+ char **upn_suffixes; - }; - - /** -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 609921fbb0f29561d7e52e8d1404a929af3c5b26..a8dcaa4a9ac5715150487f7efc9c35b778fa0163 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -147,6 +147,7 @@ - #define SYSDB_SUBDOMAIN_ENUM "enumerate" - #define SYSDB_SUBDOMAIN_FOREST "memberOfForest" - #define SYSDB_SUBDOMAIN_TRUST_DIRECTION "trustDirection" -+#define SYSDB_UPN_SUFFIXES "upnSuffixes" - - #define SYSDB_BASE_ID "baseID" - #define SYSDB_ID_RANGE_SIZE "idRangeSize" -@@ -475,7 +476,8 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain, - const char *realm, - const char *flat, - const char *id, -- const char* forest); -+ const char *forest, -+ struct ldb_message_element *alt_dom_suf); - - errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name); - -diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c -index 456e6621b3434a9dbf2e611ad880facbc171c174..c0a190f36d886325a5be1e5d1145b6aef6860ffc 100644 ---- a/src/db/sysdb_subdomains.c -+++ b/src/db/sysdb_subdomains.c -@@ -448,6 +448,7 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain) - errno_t ret; - TALLOC_CTX *tmp_ctx; - const char *tmp_str; -+ struct ldb_message_element **tmp_el; - struct ldb_dn *basedn; - struct ldb_result *res; - const char *attrs[] = {"cn", -@@ -455,6 +456,7 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain) - SYSDB_SUBDOMAIN_FLAT, - SYSDB_SUBDOMAIN_ID, - SYSDB_SUBDOMAIN_FOREST, -+ SYSDB_UPN_SUFFIXES, - NULL}; - char *view_name = NULL; - -@@ -539,6 +541,19 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain) - } - } - -+ tmp_el = ldb_msg_find_element(res->msgs[0], SYSDB_UPN_SUFFIXES); -+ if (tmp_el != NULL) { -+ talloc_free(domain->upn_suffixes); -+ domain->upn_suffixes = sss_ldb_el_to_string_list(domain, tmp_el); -+ if (domain->upn_suffixes == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "sss_ldb_el_to_string_list failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } else { -+ talloc_zfree(domain->upn_suffixes); -+ } -+ - ret = sysdb_get_view_name(tmp_ctx, domain->sysdb, &view_name); - if (ret != EOK && ret != ENOENT) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name failed.\n"); -@@ -633,7 +648,8 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain, - const char *realm, - const char *flat, - const char *id, -- const char* forest) -+ const char *forest, -+ struct ldb_message_element *upn_suffixes) - { - TALLOC_CTX *tmp_ctx; - struct ldb_message *msg; -@@ -720,7 +736,6 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain, - ret = sysdb_error_to_errno(ret); - goto done; - } -- - ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_REALM, realm); - if (ret != LDB_SUCCESS) { - ret = sysdb_error_to_errno(ret); -@@ -730,6 +745,36 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain, - do_update = true; - } - -+ if (upn_suffixes != NULL) { -+ talloc_free(discard_const(upn_suffixes->name)); -+ upn_suffixes->name = talloc_strdup(upn_suffixes, SYSDB_UPN_SUFFIXES); -+ if (upn_suffixes->name == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = ldb_msg_add(msg, upn_suffixes, LDB_FLAG_MOD_REPLACE); -+ if (ret != LDB_SUCCESS) { -+ ret = sysdb_error_to_errno(ret); -+ goto done; -+ } -+ -+ do_update = true; -+ } else { -+ /* Remove alternative_domain_suffixes from the cache */ -+ if (domain->upn_suffixes != NULL) { -+ ret = ldb_msg_add_empty(msg, SYSDB_UPN_SUFFIXES, -+ LDB_FLAG_MOD_DELETE, NULL); -+ if (ret != LDB_SUCCESS) { -+ ret = sysdb_error_to_errno(ret); -+ goto done; -+ } -+ } -+ -+ do_update = true; -+ } -+ - if (do_update == false) { - ret = EOK; - goto done; -diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c -index 92ac4ab6a13d7094f7a663b4a070feea3be09571..98915b4b966e2665dbd34257e4002d72b95d76b2 100644 ---- a/src/providers/ad/ad_id.c -+++ b/src/providers/ad/ad_id.c -@@ -631,7 +631,7 @@ ad_enumeration_master_done(struct tevent_req *subreq) - } - - ret = sysdb_master_domain_add_info(state->sdom->dom, state->realm, -- flat_name, master_sid, forest); -+ flat_name, master_sid, forest, NULL); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Cannot save master domain info\n"); - tevent_req_error(req, ret); -diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c -index 05dfc3085fb14a87b5703518d784056b71bf5de0..0a8d1f53cb005507abe4ac55d0fa1ccc9e32b173 100644 ---- a/src/providers/ad/ad_subdomains.c -+++ b/src/providers/ad/ad_subdomains.c -@@ -1131,7 +1131,7 @@ static void ad_subdomains_refresh_master_done(struct tevent_req *subreq) - } - - ret = sysdb_master_domain_add_info(state->be_ctx->domain, realm, -- flat_name, master_sid, forest); -+ flat_name, master_sid, forest, NULL); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Cannot save master domain info [%d]: %s\n", - ret, sss_strerror(ret)); -diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c -index 263d6207960c232d08114bd0163b3fd03a690685..62b8f65e5d29a4850f90ea7c19abd297becc96f5 100644 ---- a/src/providers/ipa/ipa_subdomains.c -+++ b/src/providers/ipa/ipa_subdomains.c -@@ -855,6 +855,7 @@ static void ipa_subdomains_master_done(struct tevent_req *subreq) - const char *flat = NULL; - const char *id = NULL; - const char *realm = NULL; -+ struct ldb_message_element *alternative_domain_suffixes = NULL; - errno_t ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); -@@ -879,6 +880,12 @@ static void ipa_subdomains_master_done(struct tevent_req *subreq) - if (ret != EOK) { - goto done; - } -+ -+ ret = sysdb_attrs_get_el_ext(reply[0], IPA_ADDITIONAL_SUFFIXES, false, -+ &alternative_domain_suffixes); -+ if (ret != EOK && ret != ENOENT) { -+ goto done; -+ } - } else { - /* All search paths are searched and no master domain record was - * found. -@@ -896,7 +903,8 @@ static void ipa_subdomains_master_done(struct tevent_req *subreq) - goto done; - } - -- ret = sysdb_master_domain_add_info(state->domain, realm, flat, id, NULL); -+ ret = sysdb_master_domain_add_info(state->domain, realm, flat, id, NULL, -+ alternative_domain_suffixes); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add master domain info " - "[%d]: %s\n", ret, sss_strerror(ret)); -diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c -index f55c2918015900351483e3471bf946ea60872dae..6d1ec884284487a12bcbfad77c00cd6c30f67707 100644 ---- a/src/tests/cmocka/test_sysdb_subdomains.c -+++ b/src/tests/cmocka/test_sysdb_subdomains.c -@@ -165,7 +165,8 @@ static void test_sysdb_master_domain_ops(void **state) - talloc_get_type(*state, struct subdom_test_ctx); - - ret = sysdb_master_domain_add_info(test_ctx->tctx->dom, -- "realm1", "flat1", "id1", "forest1"); -+ "realm1", "flat1", "id1", "forest1", -+ NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_master_domain_update(test_ctx->tctx->dom); -@@ -177,7 +178,8 @@ static void test_sysdb_master_domain_ops(void **state) - assert_string_equal(test_ctx->tctx->dom->forest, "forest1"); - - ret = sysdb_master_domain_add_info(test_ctx->tctx->dom, -- "realm2", "flat2", "id2", "forest2"); -+ "realm2", "flat2", "id2", "forest2", -+ NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_master_domain_update(test_ctx->tctx->dom); -@@ -298,7 +300,8 @@ static void test_sysdb_link_forest_root_ad(void **state) - TEST_REALM, - TEST_FLAT_NAME, - TEST_SID, -- TEST_FOREST); -+ TEST_FOREST, -+ NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, -@@ -374,7 +377,8 @@ static void test_sysdb_link_forest_member_ad(void **state) - child_dom[1], - child_dom[2], - child_dom[3], -- TEST_FOREST); -+ TEST_FOREST, -+ NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, -@@ -457,7 +461,8 @@ static void test_sysdb_link_ad_multidom(void **state) - TEST_REALM, - TEST_FLAT_NAME, - TEST_SID, -- TEST_FOREST); -+ TEST_FOREST, -+ NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_subdomain_store(main_dom1->sysdb, -@@ -477,7 +482,8 @@ static void test_sysdb_link_ad_multidom(void **state) - TEST_REALM2, - TEST_FLAT_NAME2, - TEST_SID2, -- TEST_FOREST2); -+ TEST_FOREST2, -+ NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_subdomain_store(main_dom2->sysdb, --- -2.4.11 - diff --git a/SOURCES/0024-KCM-Implement-an-internal-ccache-storage-and-retriev.patch b/SOURCES/0024-KCM-Implement-an-internal-ccache-storage-and-retriev.patch new file mode 100644 index 0000000..a5e0fc2 --- /dev/null +++ b/SOURCES/0024-KCM-Implement-an-internal-ccache-storage-and-retriev.patch @@ -0,0 +1,2153 @@ +From 79f6ccd2dc3f0c1369d5a93678c88ee76ec761e0 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 7 Mar 2017 13:49:21 +0100 +Subject: [PATCH 24/36] KCM: Implement an internal ccache storage and retrieval + API +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In order for the KCM server to work with ccaches stored in different +locations, implement a middle-man between the KCM server and the ccache +storage. + +This module has asynchronous API because we can't assume anything about +where the ccaches are stored. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + Makefile.am | 9 + + configure.ac | 1 + + contrib/sssd.spec.in | 1 + + src/external/libuuid.m4 | 17 + + src/responder/kcm/kcmsrv_ccache.c | 1423 +++++++++++++++++++++++++++++++++ + src/responder/kcm/kcmsrv_ccache.h | 306 +++++++ + src/responder/kcm/kcmsrv_ccache_be.h | 204 +++++ + src/responder/kcm/kcmsrv_ccache_pvt.h | 62 ++ + src/responder/kcm/kcmsrv_pvt.h | 1 + + 9 files changed, 2024 insertions(+) + create mode 100644 src/external/libuuid.m4 + create mode 100644 src/responder/kcm/kcmsrv_ccache.c + create mode 100644 src/responder/kcm/kcmsrv_ccache.h + create mode 100644 src/responder/kcm/kcmsrv_ccache_be.h + create mode 100644 src/responder/kcm/kcmsrv_ccache_pvt.h + +diff --git a/Makefile.am b/Makefile.am +index 4248536e90370c1aab59549a9c18408ef314e6d4..a2b9dc49e95fa2d025f5174d2902866fab180a78 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -711,6 +711,9 @@ dist_noinst_HEADERS = \ + src/responder/secrets/secsrv_proxy.h \ + src/responder/kcm/kcm.h \ + src/responder/kcm/kcmsrv_pvt.h \ ++ src/responder/kcm/kcmsrv_ccache.h \ ++ src/responder/kcm/kcmsrv_ccache_pvt.h \ ++ src/responder/kcm/kcmsrv_ccache_be.h \ + src/sbus/sbus_client.h \ + src/sbus/sssd_dbus.h \ + src/sbus/sssd_dbus_meta.h \ +@@ -1488,16 +1491,22 @@ if BUILD_KCM + sssd_kcm_SOURCES = \ + src/responder/kcm/kcm.c \ + src/responder/kcm/kcmsrv_cmd.c \ ++ src/responder/kcm/kcmsrv_ccache.c \ + src/util/sss_sockets.c \ ++ src/util/sss_krb5.c \ ++ src/util/sss_iobuf.c \ + $(SSSD_RESPONDER_OBJ) \ + $(NULL) + sssd_kcm_CFLAGS = \ + $(AM_CFLAGS) \ + $(KRB5_CFLAGS) \ ++ $(UUID_CFLAGS) \ + $(NULL) + sssd_kcm_LDADD = \ + $(KRB5_LIBS) \ + $(SSSD_LIBS) \ ++ $(UUID_LIBS) \ ++ $(SYSTEMD_DAEMON_LIBS) \ + $(SSSD_INTERNAL_LTLIBS) \ + $(NULL) + endif +diff --git a/configure.ac b/configure.ac +index c363d48a806cc1998e85779a92b6b59b0e2a5c9c..cf5e2557ef0a1bd6374200aa33abea6c509d03aa 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -202,6 +202,7 @@ fi + + if test x$with_kcm = xyes; then + m4_include([src/external/libcurl.m4]) ++ m4_include([src/external/libuuid.m4]) + fi + # This variable is defined by external/libcurl.m4, but conditionals + # must be always evaluated +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index 5c7c2af521a84ef2ca6cca7b2d6cd1f9b3057056..52d33b4de281dc1d91a9027ac1c8c878e66fb396 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -222,6 +222,7 @@ BuildRequires: systemtap-sdt-devel + %endif + BuildRequires: http-parser-devel + BuildRequires: jansson-devel ++BuildRequires: libuuid-devel + + %description + Provides a set of daemons to manage access to remote directories and +diff --git a/src/external/libuuid.m4 b/src/external/libuuid.m4 +new file mode 100644 +index 0000000000000000000000000000000000000000..55411a2118bd787c9d50ba61f9cb791e1c76088d +--- /dev/null ++++ b/src/external/libuuid.m4 +@@ -0,0 +1,17 @@ ++AC_SUBST(UUID_LIBS) ++AC_SUBST(UUID_CFLAGS) ++ ++PKG_CHECK_MODULES([UUID], [uuid], [found_uuid=yes], [found_uuid=no]) ++ ++SSS_AC_EXPAND_LIB_DIR() ++AS_IF([test x"$found_uuid" = xyes], ++ [AC_CHECK_HEADERS([uuid/uuid.h], ++ [AC_CHECK_LIB([uuid], ++ [uuid_generate], ++ [UUID_LIBS="-L$sss_extra_libdir -luuid"], ++ [AC_MSG_ERROR([libuuid missing uuid_generate])], ++ [-L$sss_extra_libdir -luuid])], ++ [AC_MSG_ERROR([ ++You must have the header file uuid.h installed to build sssd ++with KCM responder. If you want to build sssd without KCM responder ++then specify --without-kcm when running configure.])])]) +diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c +new file mode 100644 +index 0000000000000000000000000000000000000000..2c565b8378e3ec297faf655d3c48d7ab902713d3 +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_ccache.c +@@ -0,0 +1,1423 @@ ++/* ++ SSSD ++ ++ KCM Server - the KCM ccache operations ++ ++ Copyright (C) Red Hat, 2016 ++ ++ 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 . ++*/ ++ ++#include "config.h" ++ ++#include "util/crypto/sss_crypto.h" ++#include "util/util.h" ++#include "util/sss_krb5.h" ++#include "responder/kcm/kcmsrv_ccache.h" ++#include "responder/kcm/kcmsrv_ccache_pvt.h" ++#include "responder/kcm/kcmsrv_ccache_be.h" ++ ++static int kcm_cc_destructor(struct kcm_ccache *cc) ++{ ++ if (cc == NULL) { ++ return 0; ++ } ++ ++ krb5_free_principal(NULL, cc->client); ++ return 0; ++} ++ ++errno_t kcm_cc_new(TALLOC_CTX *mem_ctx, ++ krb5_context k5c, ++ struct cli_creds *owner, ++ const char *name, ++ krb5_principal princ, ++ struct kcm_ccache **_cc) ++{ ++ struct kcm_ccache *cc; ++ krb5_error_code kret; ++ errno_t ret; ++ ++ cc = talloc_zero(mem_ctx, struct kcm_ccache); ++ if (cc == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = kcm_check_name(name, owner); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Name %s is malformed\n", name); ++ return ret; ++ } ++ ++ cc->name = talloc_strdup(cc, name); ++ if (cc->name == NULL) { ++ talloc_free(cc); ++ return ENOMEM; ++ } ++ ++ uuid_generate(cc->uuid); ++ ++ kret = krb5_copy_principal(k5c, princ, &cc->client); ++ if (kret != 0) { ++ const char *err_msg = sss_krb5_get_error_message(k5c, kret); ++ DEBUG(SSSDBG_OP_FAILURE, ++ "krb5_copy_principal failed: [%d][%s]\n", kret, err_msg); ++ sss_krb5_free_error_message(k5c, err_msg); ++ talloc_free(cc); ++ return ERR_INTERNAL; ++ } ++ ++ cc->owner.uid = cli_creds_get_uid(owner); ++ cc->owner.gid = cli_creds_get_gid(owner); ++ cc->kdc_offset = INT32_MAX; ++ ++ talloc_set_destructor(cc, kcm_cc_destructor); ++ *_cc = cc; ++ return EOK; ++} ++ ++const char *kcm_cc_get_name(struct kcm_ccache *cc) ++{ ++ return cc ? cc->name : NULL; ++} ++ ++errno_t kcm_cc_get_uuid(struct kcm_ccache *cc, uuid_t _uuid) ++{ ++ if (cc == NULL) { ++ return EINVAL; ++ } ++ uuid_copy(_uuid, cc->uuid); ++ return EOK; ++} ++ ++krb5_principal kcm_cc_get_client_principal(struct kcm_ccache *cc) ++{ ++ return cc ? cc->client : NULL; ++} ++ ++bool kcm_cc_access(struct kcm_ccache *cc, ++ struct cli_creds *client) ++{ ++ bool ok; ++ uid_t uid = cli_creds_get_uid(client); ++ gid_t gid = cli_creds_get_gid(client); ++ ++ if (cc == NULL) { ++ return false; ++ } ++ ++ if (uid == 0 && gid == 0) { ++ /* root can access any ccache */ ++ return true; ++ } ++ ++ ok = ((cc->owner.uid == uid) && (cc->owner.gid == gid)); ++ if (!ok) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Client %"SPRIuid":%"SPRIgid" has no access to ccache %s\n", ++ cli_creds_get_uid(client), ++ cli_creds_get_gid(client), ++ cc->name); ++ } ++ return ok; ++} ++ ++int32_t kcm_cc_get_offset(struct kcm_ccache *cc) ++{ ++ return cc ? cc->kdc_offset : INT32_MAX; ++} ++ ++errno_t kcm_cc_store_cred_blob(struct kcm_ccache *cc, ++ struct sss_iobuf *cred_blob) ++{ ++ struct kcm_cred *kcreds; ++ uuid_t uuid; ++ errno_t ret; ++ ++ if (cc == NULL || cred_blob == NULL) { ++ return EINVAL; ++ } ++ ++ uuid_generate(uuid); ++ kcreds = kcm_cred_new(cc, uuid, cred_blob); ++ if (kcreds == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = kcm_cc_store_creds(cc, kcreds); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ return EOK; ++} ++ ++struct kcm_cred *kcm_cc_get_cred(struct kcm_ccache *cc) ++{ ++ if (cc == NULL) { ++ return NULL; ++ } ++ ++ return cc->creds; ++} ++ ++struct kcm_cred *kcm_cc_next_cred(struct kcm_cred *crd) ++{ ++ if (crd == NULL) { ++ return NULL; ++ } ++ ++ return crd->next; ++} ++ ++struct kcm_cred *kcm_cred_new(TALLOC_CTX *mem_ctx, ++ uuid_t uuid, ++ struct sss_iobuf *cred_blob) ++{ ++ struct kcm_cred *kcreds; ++ ++ kcreds = talloc_zero(mem_ctx, struct kcm_cred); ++ if (kcreds == NULL) { ++ return NULL; ++ } ++ ++ uuid_copy(kcreds->uuid, uuid); ++ kcreds->cred_blob = talloc_steal(kcreds, cred_blob); ++ return kcreds; ++} ++ ++/* Add a cred to ccache */ ++errno_t kcm_cc_store_creds(struct kcm_ccache *cc, ++ struct kcm_cred *crd) ++{ ++ DLIST_ADD(cc->creds, crd); ++ talloc_steal(cc, crd); ++ return EOK; ++} ++ ++errno_t kcm_cred_get_uuid(struct kcm_cred *crd, uuid_t _uuid) ++{ ++ if (crd == NULL) { ++ return EINVAL; ++ } ++ uuid_copy(_uuid, crd->uuid); ++ return EOK; ++} ++ ++struct sss_iobuf *kcm_cred_get_creds(struct kcm_cred *crd) ++{ ++ return crd ? crd->cred_blob : NULL; ++} ++ ++struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ enum kcm_ccdb_be cc_be) ++{ ++ errno_t ret; ++ struct kcm_ccdb *ccdb = NULL; ++ ++ if (ev == NULL) { ++ return NULL; ++ } ++ ++ ccdb = talloc_zero(mem_ctx, struct kcm_ccdb); ++ if (ccdb == NULL) { ++ return NULL; ++ } ++ ccdb->ev = ev; ++ ++ switch (cc_be) { ++ case CCDB_BE_MEMORY: ++ DEBUG(SSSDBG_FUNC_DATA, "KCM back end: memory\n"); ++ /* Not implemented yet */ ++ break; ++ case CCDB_BE_SECRETS: ++ DEBUG(SSSDBG_FUNC_DATA, "KCM back end: sssd-secrets\n"); ++ /* Not implemented yet */ ++ break; ++ default: ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unknown ccache database\n"); ++ break; ++ } ++ ++ if (ccdb->ops == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Ccache database not initialized\n"); ++ talloc_free(ccdb); ++ return NULL; ++ } ++ ++ ret = ccdb->ops->init(ccdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize ccache database\n"); ++ talloc_free(ccdb); ++ return NULL; ++ } ++ ++ return ccdb; ++} ++ ++struct kcm_ccdb_nextid_state { ++ char *next_cc; ++ struct kcm_ccdb *db; ++ struct cli_creds *client; ++}; ++ ++static void kcm_ccdb_nextid_done(struct tevent_req *subreq); ++ ++struct tevent_req *kcm_ccdb_nextid_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_ccdb_nextid_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_nextid_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->db = db; ++ state->client = client; ++ ++ if (ev == NULL || db == NULL || client == NULL) { ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ subreq = state->db->ops->nextid_send(mem_ctx, ev, state->db, client); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_nextid_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_ccdb_nextid_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_nextid_state *state = tevent_req_data(req, ++ struct kcm_ccdb_nextid_state); ++ errno_t ret; ++ unsigned int nextid; ++ ++ ret = state->db->ops->nextid_recv(subreq, &nextid); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to generate next UID [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->next_cc = talloc_asprintf(state, "%"SPRIuid":%u", ++ cli_creds_get_uid(state->client), ++ nextid); ++ if (state->next_cc == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed\n"); ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_LIBS, "generated %s\n", state->next_cc); ++ tevent_req_done(req); ++} ++ ++errno_t kcm_ccdb_nextid_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ char **_next_cc) ++{ ++ struct kcm_ccdb_nextid_state *state = tevent_req_data(req, ++ struct kcm_ccdb_nextid_state); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_next_cc = talloc_steal(mem_ctx, state->next_cc); ++ return EOK; ++} ++ ++struct kcm_ccdb_list_state { ++ struct kcm_ccdb *db; ++ struct cli_creds *client; ++ ++ uuid_t *uuid_list; ++}; ++ ++static void kcm_ccdb_list_done(struct tevent_req *subreq); ++ ++struct tevent_req *kcm_ccdb_list_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_ccdb_list_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_list_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->db = db; ++ state->client = client; ++ ++ if (ev == NULL || db == NULL || client == NULL) { ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ subreq = state->db->ops->list_send(mem_ctx, ++ ev, ++ state->db, ++ client); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_list_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_ccdb_list_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_list_state *state = tevent_req_data(req, ++ struct kcm_ccdb_list_state); ++ errno_t ret; ++ ++ ret = state->db->ops->list_recv(subreq, state, &state->uuid_list); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to list all ccaches [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t kcm_ccdb_list_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ uuid_t **_uuid_list) ++{ ++ struct kcm_ccdb_list_state *state = tevent_req_data(req, ++ struct kcm_ccdb_list_state); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_uuid_list = talloc_steal(mem_ctx, state->uuid_list); ++ return EOK; ++} ++ ++struct kcm_ccdb_get_default_state { ++ struct kcm_ccdb *db; ++ uuid_t uuid; ++}; ++ ++static void kcm_ccdb_get_default_done(struct tevent_req *subreq); ++ ++struct tevent_req *kcm_ccdb_get_default_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_ccdb_get_default_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_get_default_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->db = db; ++ ++ if (ev == NULL || db == NULL || client == NULL) { ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ subreq = db->ops->get_default_send(mem_ctx, ev, db, client); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_get_default_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_ccdb_get_default_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_get_default_state *state = tevent_req_data(req, ++ struct kcm_ccdb_get_default_state); ++ errno_t ret; ++ ++ ret = state->db->ops->get_default_recv(subreq, state->uuid); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to get the default ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t kcm_ccdb_get_default_recv(struct tevent_req *req, ++ uuid_t *uuid) ++{ ++ struct kcm_ccdb_get_default_state *state = tevent_req_data(req, ++ struct kcm_ccdb_get_default_state); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ if (uuid != NULL) { ++ /* The caller might supply a NULL dfl to just check if there is ++ * some default ccache ++ */ ++ uuid_copy(*uuid, state->uuid); ++ } ++ ++ return EOK; ++} ++ ++struct kcm_ccdb_set_default_state { ++ struct tevent_context *ev; ++ struct kcm_ccdb *db; ++ struct cli_creds *client; ++ uuid_t uuid; ++}; ++ ++static void kcm_ccdb_set_default_uuid_resolved(struct tevent_req *subreq); ++static void kcm_ccdb_set_default_done(struct tevent_req *subreq); ++ ++struct tevent_req *kcm_ccdb_set_default_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_ccdb_set_default_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_set_default_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->db = db; ++ state->ev = ev; ++ state->client = client; ++ uuid_copy(state->uuid, uuid); ++ ++ if (ev == NULL || db == NULL || client == NULL) { ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ if (uuid_is_null(uuid)) { ++ /* NULL UUID means to just reset the default to 'no default' */ ++ subreq = state->db->ops->set_default_send(state, ++ state->ev, ++ state->db, ++ state->client, ++ state->uuid); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_set_default_done, req); ++ } else { ++ /* Otherwise we need to check if the client can access the UUID ++ * about to be set as default ++ */ ++ subreq = db->ops->getbyuuid_send(state, ev, db, client, uuid); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_set_default_uuid_resolved, req); ++ } ++ ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_ccdb_set_default_uuid_resolved(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_set_default_state *state = tevent_req_data(req, ++ struct kcm_ccdb_set_default_state); ++ errno_t ret; ++ bool ok; ++ struct kcm_ccache *cc; ++ ++ ret = state->db->ops->getbyuuid_recv(subreq, state, &cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to get cache by UUID [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (cc == NULL) { ++ DEBUG(SSSDBG_TRACE_LIBS, "No cache found by UUID\n"); ++ tevent_req_error(req, ERR_KCM_CC_END); ++ return; ++ } ++ ++ ok = kcm_cc_access(cc, state->client); ++ if (!ok) { ++ tevent_req_error(req, EACCES); ++ return; ++ } ++ ++ subreq = state->db->ops->set_default_send(state, ++ state->ev, ++ state->db, ++ state->client, ++ state->uuid); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_set_default_done, req); ++} ++ ++static void kcm_ccdb_set_default_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_set_default_state *state = tevent_req_data(req, ++ struct kcm_ccdb_set_default_state); ++ errno_t ret; ++ ++ ret = state->db->ops->set_default_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to set the default ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t kcm_ccdb_set_default_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++struct kcm_ccdb_getbyname_state { ++ struct kcm_ccdb *db; ++ struct cli_creds *client; ++ ++ struct kcm_ccache *cc; ++}; ++ ++static void kcm_ccdb_getbyname_done(struct tevent_req *subreq); ++ ++struct tevent_req *kcm_ccdb_getbyname_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ const char *name) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_ccdb_getbyname_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_getbyname_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->db = db; ++ state->client = client; ++ ++ if (ev == NULL || db == NULL || client == NULL || name == NULL) { ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ subreq = db->ops->getbyname_send(state, ev, db, client, name); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_getbyname_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_ccdb_getbyname_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_getbyname_state *state = tevent_req_data(req, ++ struct kcm_ccdb_getbyname_state); ++ errno_t ret; ++ bool ok; ++ ++ ret = state->db->ops->getbyname_recv(subreq, state, &state->cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to get cache by name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (state->cc == NULL) { ++ DEBUG(SSSDBG_TRACE_LIBS, "No cache found by name\n"); ++ tevent_req_done(req); ++ return; ++ } ++ ++ ok = kcm_cc_access(state->cc, state->client); ++ if (!ok) { ++ tevent_req_error(req, EACCES); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t kcm_ccdb_getbyname_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ccache **_cc) ++{ ++ struct kcm_ccdb_getbyname_state *state = tevent_req_data(req, ++ struct kcm_ccdb_getbyname_state); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_cc = talloc_steal(mem_ctx, state->cc); ++ return EOK; ++} ++ ++struct kcm_ccdb_getbyuuid_state { ++ struct kcm_ccdb *db; ++ struct cli_creds *client; ++ ++ struct kcm_ccache *cc; ++}; ++ ++static void kcm_ccdb_getbyuuid_done(struct tevent_req *subreq); ++ ++struct tevent_req *kcm_ccdb_getbyuuid_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_ccdb_getbyuuid_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_getbyuuid_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->db = db; ++ state->client = client; ++ ++ if (ev == NULL || db == NULL || client == NULL) { ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ subreq = db->ops->getbyuuid_send(state, ev, db, client, uuid); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_getbyuuid_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_ccdb_getbyuuid_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_getbyuuid_state *state = tevent_req_data(req, ++ struct kcm_ccdb_getbyuuid_state); ++ errno_t ret; ++ bool ok; ++ ++ ret = state->db->ops->getbyuuid_recv(subreq, state, &state->cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to get cache by UUID [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (state->cc == NULL) { ++ DEBUG(SSSDBG_TRACE_LIBS, "No cache found by UUID\n"); ++ tevent_req_done(req); ++ return; ++ } ++ ++ ok = kcm_cc_access(state->cc, state->client); ++ if (!ok) { ++ tevent_req_error(req, EACCES); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t kcm_ccdb_getbyuuid_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ccache **_cc) ++{ ++ struct kcm_ccdb_getbyuuid_state *state = tevent_req_data(req, ++ struct kcm_ccdb_getbyuuid_state); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_cc = talloc_steal(mem_ctx, state->cc); ++ return EOK; ++} ++ ++struct kcm_ccdb_name_by_uuid_state { ++ struct kcm_ccdb *db; ++ struct cli_creds *client; ++ ++ const char *name; ++}; ++ ++static void kcm_ccdb_name_by_uuid_done(struct tevent_req *subreq); ++ ++struct tevent_req *kcm_ccdb_name_by_uuid_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_ccdb_name_by_uuid_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, ++ &state, ++ struct kcm_ccdb_name_by_uuid_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->db = db; ++ state->client = client; ++ ++ if (ev == NULL || db == NULL || client == NULL || uuid_is_null(uuid)) { ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ subreq = db->ops->name_by_uuid_send(state, ev, db, client, uuid); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_name_by_uuid_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_ccdb_name_by_uuid_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_name_by_uuid_state *state = tevent_req_data(req, ++ struct kcm_ccdb_name_by_uuid_state); ++ errno_t ret; ++ ++ ret = state->db->ops->name_by_uuid_recv(subreq, state, &state->name); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to resolve cache by UUID [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t kcm_ccdb_name_by_uuid_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ const char **_name) ++{ ++ struct kcm_ccdb_name_by_uuid_state *state = tevent_req_data(req, ++ struct kcm_ccdb_name_by_uuid_state); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_name = talloc_steal(mem_ctx, state->name); ++ return EOK; ++} ++ ++struct kcm_ccdb_uuid_by_name_state { ++ struct kcm_ccdb *db; ++ struct cli_creds *client; ++ ++ uuid_t uuid; ++}; ++ ++static void kcm_ccdb_uuid_by_name_done(struct tevent_req *subreq); ++ ++struct tevent_req *kcm_ccdb_uuid_by_name_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ const char *name) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_ccdb_uuid_by_name_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, ++ &state, ++ struct kcm_ccdb_uuid_by_name_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->db = db; ++ state->client = client; ++ ++ if (ev == NULL || db == NULL || client == NULL || name == NULL) { ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ subreq = db->ops->uuid_by_name_send(state, ev, db, client, name); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_uuid_by_name_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_ccdb_uuid_by_name_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_uuid_by_name_state *state = tevent_req_data(req, ++ struct kcm_ccdb_uuid_by_name_state); ++ errno_t ret; ++ ++ ret = state->db->ops->uuid_by_name_recv(subreq, state, state->uuid); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to resolve cache by UUID [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t kcm_ccdb_uuid_by_name_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ uuid_t _uuid) ++{ ++ struct kcm_ccdb_uuid_by_name_state *state = tevent_req_data(req, ++ struct kcm_ccdb_uuid_by_name_state); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ uuid_copy(_uuid, state->uuid); ++ return EOK; ++} ++ ++struct kcm_ccdb_create_cc_state { ++ struct kcm_ccdb *db; ++}; ++ ++static void kcm_ccdb_create_done(struct tevent_req *subreq); ++ ++struct tevent_req *kcm_ccdb_create_cc_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ struct kcm_ccache *cc) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_ccdb_create_cc_state *state = NULL; ++ errno_t ret; ++ bool ok; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_create_cc_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->db = db; ++ ++ if (ev == NULL || db == NULL || client == NULL || cc == NULL) { ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ ok = kcm_cc_access(cc, client); ++ if (!ok) { ++ ret = EACCES; ++ goto immediate; ++ } ++ ++ subreq = state->db->ops->create_send(mem_ctx, ++ ev, ++ state->db, ++ client, ++ cc); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_create_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_ccdb_create_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_create_cc_state *state = tevent_req_data(req, ++ struct kcm_ccdb_create_cc_state); ++ errno_t ret; ++ ++ ret = state->db->ops->create_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to create ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t kcm_ccdb_create_cc_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++void kcm_mod_ctx_clear(struct kcm_mod_ctx *mod_ctx) ++{ ++ if (mod_ctx == NULL) { ++ return; ++ } ++ ++ mod_ctx->kdc_offset = INT32_MAX; ++} ++ ++void kcm_mod_cc(struct kcm_ccache *cc, struct kcm_mod_ctx *mod_ctx) ++{ ++ if (cc == NULL || mod_ctx == NULL) { ++ return; ++ } ++ ++ if (mod_ctx->kdc_offset != INT32_MAX) { ++ cc->kdc_offset = mod_ctx->kdc_offset; ++ } ++ ++} ++ ++struct kcm_ccdb_mod_cc_state { ++ struct kcm_ccdb *db; ++}; ++ ++static void kcm_ccdb_mod_done(struct tevent_req *subreq); ++ ++struct tevent_req *kcm_ccdb_mod_cc_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid, ++ struct kcm_mod_ctx *mod_cc) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_ccdb_mod_cc_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_mod_cc_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->db = db; ++ ++ if (ev == NULL || db == NULL || client == NULL || mod_cc == NULL) { ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ subreq = state->db->ops->mod_send(mem_ctx, ++ ev, ++ state->db, ++ client, ++ uuid, ++ mod_cc); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_mod_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_ccdb_mod_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_mod_cc_state *state = tevent_req_data(req, ++ struct kcm_ccdb_mod_cc_state); ++ errno_t ret; ++ ++ ret = state->db->ops->mod_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to create ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t kcm_ccdb_mod_cc_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++struct kcm_ccdb_store_cred_blob_state { ++ struct kcm_ccdb *db; ++}; ++ ++static void kcm_ccdb_store_cred_blob_done(struct tevent_req *subreq); ++ ++struct tevent_req *kcm_ccdb_store_cred_blob_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid, ++ struct sss_iobuf *cred_blob) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_ccdb_store_cred_blob_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_store_cred_blob_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->db = db; ++ ++ if (ev == NULL || db == NULL || client == NULL || cred_blob == NULL) { ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ subreq = state->db->ops->store_cred_send(mem_ctx, ++ ev, ++ state->db, ++ client, ++ uuid, ++ cred_blob); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_store_cred_blob_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_ccdb_store_cred_blob_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_store_cred_blob_state *state = tevent_req_data(req, ++ struct kcm_ccdb_store_cred_blob_state); ++ errno_t ret; ++ ++ ret = state->db->ops->store_cred_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to create ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t kcm_ccdb_store_cred_blob_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++struct kcm_ccdb_delete_cc_state { ++ struct tevent_context *ev; ++ struct kcm_ccdb *db; ++ struct cli_creds *client; ++ uuid_t uuid; ++}; ++ ++static void kcm_ccdb_delete_done(struct tevent_req *subreq); ++static void kcm_ccdb_delete_get_default_done(struct tevent_req *subreq); ++static void kcm_ccdb_delete_default_reset_done(struct tevent_req *subreq); ++ ++struct tevent_req *kcm_ccdb_delete_cc_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_ccdb_delete_cc_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_delete_cc_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->db = db; ++ state->ev = ev; ++ state->client = client; ++ uuid_copy(state->uuid, uuid); ++ ++ if (ev == NULL || db == NULL || client == NULL) { ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ subreq = state->db->ops->delete_send(state, ++ state->ev, ++ state->db, ++ state->client, ++ state->uuid); ++ tevent_req_set_callback(subreq, kcm_ccdb_delete_done, req); ++ ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_ccdb_delete_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_delete_cc_state *state = tevent_req_data(req, ++ struct kcm_ccdb_delete_cc_state); ++ errno_t ret; ++ ++ ret = state->db->ops->delete_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to delete ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ /* The delete operation must also check if the deleted ccache was ++ * the default and reset the default if it was ++ */ ++ subreq = state->db->ops->get_default_send(state, ++ state->ev, ++ state->db, ++ state->client); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_delete_get_default_done, req); ++} ++ ++static void kcm_ccdb_delete_get_default_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_delete_cc_state *state = tevent_req_data(req, ++ struct kcm_ccdb_delete_cc_state); ++ errno_t ret; ++ uuid_t dfl_uuid; ++ uuid_t null_uuid; ++ ++ ret = state->db->ops->get_default_recv(subreq, dfl_uuid); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to get the default ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (uuid_compare(dfl_uuid, state->uuid) != 0) { ++ /* The ccache about to be deleted was not the default, quit */ ++ tevent_req_done(req); ++ return; ++ } ++ ++ /* If we deleted the default ccache, reset the default ccache to 'none' */ ++ uuid_clear(null_uuid); ++ ++ subreq = state->db->ops->set_default_send(state, ++ state->ev, ++ state->db, ++ state->client, ++ null_uuid); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_ccdb_delete_default_reset_done, req); ++} ++ ++static void kcm_ccdb_delete_default_reset_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_ccdb_delete_cc_state *state = tevent_req_data(req, ++ struct kcm_ccdb_delete_cc_state); ++ errno_t ret; ++ ++ ret = state->db->ops->set_default_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to NULL the default ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t kcm_ccdb_delete_cc_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++void kcm_debug_uuid(uuid_t uuid) ++{ ++ char dbgbuf[UUID_STR_SIZE]; ++ ++ if (!(debug_level & SSSDBG_TRACE_ALL) || uuid == NULL) { ++ return; ++ } ++ ++ uuid_unparse(uuid, dbgbuf); ++ DEBUG(SSSDBG_TRACE_ALL, "UUID: %s\n", dbgbuf); ++} ++ ++errno_t kcm_check_name(const char *name, struct cli_creds *client) ++{ ++ char prefix[64]; ++ size_t prefix_len; ++ ++ prefix_len = snprintf(prefix, sizeof(prefix), ++ "%"SPRIuid, cli_creds_get_uid(client)); ++ ++ if (strncmp(name, prefix, prefix_len) != 0) { ++ return ERR_KCM_WRONG_CCNAME_FORMAT; ++ } ++ return EOK; ++} +diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h +new file mode 100644 +index 0000000000000000000000000000000000000000..130ae48ae30d5e1e2ab238a647a9b9dc76cc4945 +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_ccache.h +@@ -0,0 +1,306 @@ ++/* ++ SSSD ++ ++ KCM Server - the KCM ccache operations ++ ++ Copyright (C) Red Hat, 2016 ++ ++ 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 . ++*/ ++#ifndef _KCMSRV_CCACHE_H_ ++#define _KCMSRV_CCACHE_H_ ++ ++#include "config.h" ++ ++#include ++#include ++ ++#include "util/util.h" ++#include "util/sss_iobuf.h" ++#include "util/util_creds.h" ++ ++#define UUID_BYTES 16 ++#define UUID_STR_SIZE 37 ++ ++/* ++ * Credentials are opaque to the KCM server ++ * ++ * Each ccache has a unique UUID. ++ */ ++struct kcm_cred; ++ ++/* ++ * An opaque ccache type and its operations ++ * ++ * Contains zero or some KCM credentials. One credential in the cache ++ * is marked as the default one. The client can set and get the default ++ * cache (e.g. with kswitch) but one cache is always the default -- we ++ * fall back to the one created first. ++ * ++ * Each cache has a name and a UUID. Heimdal allows the name to be changed, ++ * we don't (yet, because the MIT client doesn't allow that either) ++ * ++ * Each ccache also stores a client principal. ++ */ ++struct kcm_ccache; ++ ++/* ++ * Create a new KCM ccache owned by mem_ctx on the ++ * memory level. ++ * ++ * When created, the ccache contains no credendials ++ */ ++errno_t kcm_cc_new(TALLOC_CTX *mem_ctx, ++ krb5_context k5c, ++ struct cli_creds *owner, ++ const char *name, ++ krb5_principal princ, ++ struct kcm_ccache **_cc); ++ ++/* ++ * Returns true if a client can access a ccache. ++ * ++ * Note that root can access any ccache */ ++bool kcm_cc_access(struct kcm_ccache *cc, ++ struct cli_creds *client); ++ ++/* ++ * Since the kcm_ccache structure is opaque, the kcmsrv_ccache ++ * layer contains a number of getsetters to read and write ++ * properties of the kcm_ccache structure ++ */ ++const char *kcm_cc_get_name(struct kcm_ccache *cc); ++errno_t kcm_cc_get_uuid(struct kcm_ccache *cc, uuid_t _uuid); ++krb5_principal kcm_cc_get_client_principal(struct kcm_ccache *cc); ++int32_t kcm_cc_get_offset(struct kcm_ccache *cc); ++ ++/* Mainly useful for creating a cred structure from a persistent ++ * storage ++ */ ++struct kcm_cred *kcm_cred_new(TALLOC_CTX *mem_ctx, ++ uuid_t uuid, ++ struct sss_iobuf *cred_blob); ++ ++/* Add a cred to ccache */ ++errno_t kcm_cc_store_creds(struct kcm_ccache *cc, ++ struct kcm_cred *crd); ++ ++errno_t kcm_cred_get_uuid(struct kcm_cred *crd, uuid_t uuid); ++ ++/* ++ * At the moment, the credentials are stored without unmarshalling ++ * them, just as the clients sends the credentials. ++ */ ++struct sss_iobuf *kcm_cred_get_creds(struct kcm_cred *crd); ++errno_t kcm_cc_store_cred_blob(struct kcm_ccache *cc, ++ struct sss_iobuf *cred_blob); ++ /* ++ * The KCM server can call kcm_cred_get_creds to fetch the first ++ * credential, then iterate over the credentials with ++ * kcm_cc_next_cred until it returns NULL ++ */ ++struct kcm_cred *kcm_cc_get_cred(struct kcm_ccache *cc); ++struct kcm_cred *kcm_cc_next_cred(struct kcm_cred *crd); ++ ++enum kcm_ccdb_be { ++ CCDB_BE_MEMORY, ++ CCDB_BE_SECRETS, ++}; ++ ++/* An opaque database that contains all the ccaches */ ++struct kcm_ccdb; ++ ++/* ++ * Initialize a ccache database of type cc_be ++ */ ++struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ enum kcm_ccdb_be cc_be); ++ ++/* ++ * In KCM, each ccache name is usually in the form of "UID: ++ * ++ * The is generated by the KCM ccache database. Use this function ++ * to retrieve the next number ++ */ ++struct tevent_req *kcm_ccdb_nextid_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client); ++errno_t kcm_ccdb_nextid_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ char **_nextid); ++ ++/* ++ * List all ccaches that belong to a given client ++ * ++ * The cc_list the recv function returns is NULL-terminated. ++ * ++ * NOTE: Contrary to how Heimdal behaves, root CAN NOT list all ccaches ++ * of all users. This is a deliberate decision to treat root as any other ++ * user, except it can access a ccache of another user by name, just not ++ * list them. ++ * ++ * If a client has no ccaches, the function returns OK, but an empty list ++ * containing just the NULL sentinel. ++ */ ++struct tevent_req *kcm_ccdb_list_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client); ++errno_t kcm_ccdb_list_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ uuid_t **_uuid_list); ++ ++/* ++ * Retrieve a ccache by name. ++ * ++ * If there is no such ccache, return EOK, but a NULL _cc pointer ++ */ ++struct tevent_req *kcm_ccdb_getbyname_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ const char *name); ++errno_t kcm_ccdb_getbyname_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ccache **_cc); ++ ++/* ++ * Retrieve a ccache by UUID ++ * ++ * If there is no such ccache, return EOK, but a NULL _cc pointer ++ */ ++struct tevent_req *kcm_ccdb_getbyuuid_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid); ++errno_t kcm_ccdb_getbyuuid_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ccache **_cc); ++ ++/* ++ * Retrieve the default ccache. If there is no default cache, ++ * return EOK, but a NULL UUID. ++ */ ++struct tevent_req *kcm_ccdb_get_default_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client); ++errno_t kcm_ccdb_get_default_recv(struct tevent_req *req, ++ uuid_t *uuid); ++ ++/* ++ * Translating name to UUID is often considerably faster than doing a full ++ * CC retrieval, hence this function and the converse. If the UUID cannot ++ * be found in the database, return ERR_KCM_CC_END ++ */ ++struct tevent_req *kcm_ccdb_name_by_uuid_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid); ++errno_t kcm_ccdb_name_by_uuid_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ const char **_name); ++ ++/* ++ * Translating UUID to name is often considerably faster than doing a full ++ * CC retrieval, hence this function and the converse. If the UUID cannot ++ * be found in the database, return ERR_KCM_CC_END ++ */ ++struct tevent_req *kcm_ccdb_uuid_by_name_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ const char *name); ++errno_t kcm_ccdb_uuid_by_name_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ uuid_t _uuid); ++ ++/* ++ * Set the default ccache. Passing a NULL UUID is a legal operation ++ * that 'unsets' the default ccache. ++ */ ++struct tevent_req *kcm_ccdb_set_default_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid); ++errno_t kcm_ccdb_set_default_recv(struct tevent_req *req); ++ ++/* ++ * Add a ccache to the database. ++ */ ++struct tevent_req *kcm_ccdb_create_cc_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ struct kcm_ccache *cc); ++errno_t kcm_ccdb_create_cc_recv(struct tevent_req *req); ++ ++/* ++ * Modify cache properties in a db ++ */ ++struct kcm_mod_ctx { ++ int32_t kdc_offset; ++ /* More settable properties (like name, when we support renames ++ * will be added later ++ */ ++}; ++ ++void kcm_mod_ctx_clear(struct kcm_mod_ctx *mod_ctx); ++void kcm_mod_cc(struct kcm_ccache *cc, struct kcm_mod_ctx *mod_ctx); ++ ++struct tevent_req *kcm_ccdb_mod_cc_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid, ++ struct kcm_mod_ctx *mod_cc); ++errno_t kcm_ccdb_mod_cc_recv(struct tevent_req *req); ++ ++/* ++ * Store a credential in a cache ++ */ ++struct tevent_req *kcm_ccdb_store_cred_blob_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid, ++ struct sss_iobuf *cred_blob); ++errno_t kcm_ccdb_store_cred_blob_recv(struct tevent_req *req); ++ ++/* ++ * Delete a ccache from the database ++ */ ++struct tevent_req *kcm_ccdb_delete_cc_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid); ++errno_t kcm_ccdb_delete_cc_recv(struct tevent_req *req); ++ ++void kcm_debug_uuid(uuid_t uuid); ++ ++/* ++ * The KCM clients are not allowed (except root) to create ccaches ++ * with arbitrary names. Instead, we assert that the ccache name ++ * begins with UID where UID is the stringified representation of ++ * the client's UID number ++ */ ++errno_t kcm_check_name(const char *name, struct cli_creds *client); ++ ++#endif /* _KCMSRV_CCACHE_H_ */ +diff --git a/src/responder/kcm/kcmsrv_ccache_be.h b/src/responder/kcm/kcmsrv_ccache_be.h +new file mode 100644 +index 0000000000000000000000000000000000000000..1bd2b6981e227675866e82e0a5389445cac4df66 +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_ccache_be.h +@@ -0,0 +1,204 @@ ++/* ++ SSSD ++ ++ KCM Server - the KCM ccache database interface ++ ++ This file should only be included from the ccache.c module. ++ ++ Copyright (C) Red Hat, 2016 ++ ++ 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 . ++*/ ++ ++#ifndef _KCMSRV_CCACHE_BE_ ++#define _KCMSRV_CCACHE_BE_ ++ ++#include "config.h" ++ ++#include ++#include "responder/kcm/kcmsrv_ccache.h" ++ ++typedef errno_t ++(*ccdb_init_fn)(struct kcm_ccdb *db); ++ ++typedef struct tevent_req * ++(*ccdb_nextid_send_fn)(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client); ++typedef errno_t ++(*ccdb_nextid_recv_fn)(struct tevent_req *req, ++ unsigned int *_nextid); ++ ++typedef struct tevent_req * ++(*ccdb_set_default_send_fn)(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid); ++typedef errno_t ++(*ccdb_set_default_recv_fn)(struct tevent_req *req); ++ ++typedef struct tevent_req * ++(*ccdb_get_default_send_fn)(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client); ++typedef errno_t ++(*ccdb_get_default_recv_fn)(struct tevent_req *req, ++ uuid_t dfl); ++ ++ ++typedef struct tevent_req * ++(*ccdb_list_send_fn)(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client); ++typedef errno_t ++(*ccdb_list_recv_fn)(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ uuid_t **_uuid_list); ++ ++typedef struct tevent_req * ++(*ccdb_getbyname_send_fn)(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ const char *name); ++typedef errno_t ++(*ccdb_getbyname_recv_fn)(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ccache **_cc); ++ ++typedef struct tevent_req * ++(*ccdb_getbyuuid_send_fn)(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid); ++typedef errno_t ++(*ccdb_getbyuuid_recv_fn)(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ccache **_cc); ++ ++typedef struct tevent_req * ++(*ccdb_name_by_uuid_send_fn)(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid); ++typedef errno_t ++(*ccdb_name_by_uuid_recv_fn)(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ const char **_name); ++ ++typedef struct tevent_req * ++(*ccdb_uuid_by_name_send_fn)(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ const char *name); ++typedef errno_t ++(*ccdb_uuid_by_name_recv_fn)(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ uuid_t _uuid); ++ ++typedef struct tevent_req * ++(*ccdb_create_send_fn)(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ struct kcm_ccache *cc); ++typedef errno_t ++(*ccdb_create_recv_fn)(struct tevent_req *req); ++ ++typedef struct tevent_req * ++(*ccdb_mod_send_fn)(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid, ++ struct kcm_mod_ctx *mod_cc); ++typedef errno_t ++(*ccdb_mod_recv_fn)(struct tevent_req *req); ++ ++typedef struct tevent_req * ++(*kcm_ccdb_store_cred_blob_send_fn)(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid, ++ struct sss_iobuf *cred_blob); ++typedef errno_t ++(*kcm_ccdb_store_cred_blob_recv_fn)(struct tevent_req *req); ++ ++typedef struct tevent_req * ++(*ccdb_delete_send_fn)(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid); ++typedef errno_t ++(*ccdb_delete_recv_fn)(struct tevent_req *req); ++ ++/* ++ * Each ccache back end (for example memory or secrets) must implement ++ * all these functions. The functions are wrapped by the kcm_ccdb ++ * interface that performs additional sanity checks or contains shared ++ * logic such as access checks but in general doesn't assume anything ++ * about how the operations work. ++ */ ++struct kcm_ccdb_ops { ++ ccdb_init_fn init; ++ ++ ccdb_nextid_send_fn nextid_send; ++ ccdb_nextid_recv_fn nextid_recv; ++ ++ ccdb_set_default_send_fn set_default_send; ++ ccdb_set_default_recv_fn set_default_recv; ++ ++ ccdb_get_default_send_fn get_default_send; ++ ccdb_get_default_recv_fn get_default_recv; ++ ++ ccdb_list_send_fn list_send; ++ ccdb_list_recv_fn list_recv; ++ ++ ccdb_getbyname_send_fn getbyname_send; ++ ccdb_getbyname_recv_fn getbyname_recv; ++ ++ ccdb_getbyuuid_send_fn getbyuuid_send; ++ ccdb_getbyuuid_recv_fn getbyuuid_recv; ++ ++ ccdb_name_by_uuid_send_fn name_by_uuid_send; ++ ccdb_name_by_uuid_recv_fn name_by_uuid_recv; ++ ++ ccdb_uuid_by_name_send_fn uuid_by_name_send; ++ ccdb_uuid_by_name_recv_fn uuid_by_name_recv; ++ ++ ccdb_create_send_fn create_send; ++ ccdb_create_recv_fn create_recv; ++ ++ ccdb_mod_send_fn mod_send; ++ ccdb_mod_recv_fn mod_recv; ++ ++ kcm_ccdb_store_cred_blob_send_fn store_cred_send; ++ kcm_ccdb_store_cred_blob_recv_fn store_cred_recv; ++ ++ ccdb_delete_send_fn delete_send; ++ ccdb_delete_recv_fn delete_recv; ++}; ++ ++extern const struct kcm_ccdb_ops ccdb_mem_ops; ++ ++#endif /* _KCMSRV_CCACHE_BE_ */ +diff --git a/src/responder/kcm/kcmsrv_ccache_pvt.h b/src/responder/kcm/kcmsrv_ccache_pvt.h +new file mode 100644 +index 0000000000000000000000000000000000000000..0cc24c2b8cd4d44080d2aa4384f7b2a73520c5a0 +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_ccache_pvt.h +@@ -0,0 +1,62 @@ ++/* ++ SSSD ++ ++ KCM Server - the KCM ccache operations - private structures ++ ++ Should be accessed only from the ccache layer. ++ ++ Copyright (C) Red Hat, 2016 ++ ++ 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 . ++*/ ++#ifndef _KCMSRV_CCACHE_PVT_H ++#define _KCMSRV_CCACHE_PVT_H ++ ++#include "responder/kcm/kcmsrv_ccache.h" ++#include "responder/kcm/kcmsrv_ccache_be.h" ++ ++struct kcm_ccache_owner { ++ uid_t uid; ++ gid_t gid; ++}; ++ ++struct kcm_cred { ++ struct sss_iobuf *cred_blob; ++ /* Randomly generated 16 bytes */ ++ uuid_t uuid; ++ ++ struct kcm_cred *next; ++ struct kcm_cred *prev; ++}; ++ ++struct kcm_ccdb { ++ enum kcm_ccdb_be cc_be_type; ++ struct tevent_context *ev; ++ ++ void *db_handle; ++ const struct kcm_ccdb_ops *ops; ++}; ++ ++struct kcm_ccache { ++ const char *name; ++ struct kcm_ccache_owner owner; ++ uuid_t uuid; ++ ++ krb5_principal client; ++ int32_t kdc_offset; ++ ++ struct kcm_cred *creds; ++}; ++ ++#endif /* _KCMSRV_CCACHE_PVT_H */ +diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h +index fd1fd9fa32d59a323d465def68999f24f84e3923..a29680246c1e616da75e1bbff951ce2fad66fb65 100644 +--- a/src/responder/kcm/kcmsrv_pvt.h ++++ b/src/responder/kcm/kcmsrv_pvt.h +@@ -46,6 +46,7 @@ struct kcm_data { + */ + struct kcm_resp_ctx { + krb5_context k5c; ++ struct kcm_ccdb *db; + }; + + /* +-- +2.9.3 + diff --git a/SOURCES/0024-sysdb-make-subdomain-calls-aware-of-upn_suffixes.patch b/SOURCES/0024-sysdb-make-subdomain-calls-aware-of-upn_suffixes.patch deleted file mode 100644 index 4b900cf..0000000 --- a/SOURCES/0024-sysdb-make-subdomain-calls-aware-of-upn_suffixes.patch +++ /dev/null @@ -1,428 +0,0 @@ -From f3be4b46d39c1a0106b60d561bbdeee4c80961aa Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 1 Jul 2016 12:54:39 +0200 -Subject: [PATCH 24/27] sysdb: make subdomain calls aware of upn_suffixes - -sysdb_subdomain_store() and sysdb_update_subdomains() can now update -upn_suffixes as well. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 20348a30feb4be619b3b691c24c9be8131507c46) ---- - src/confdb/confdb.h | 2 +- - src/db/sysdb.h | 3 +- - src/db/sysdb_subdomains.c | 56 +++++++++++++++++++++++++-- - src/providers/ad/ad_subdomains.c | 2 +- - src/providers/ipa/ipa_subdomains.c | 9 ++++- - src/tests/cmocka/test_ipa_subdomains_server.c | 4 +- - src/tests/cmocka/test_nss_srv.c | 2 +- - src/tests/cmocka/test_sysdb_subdomains.c | 28 +++++++------- - src/tests/sysdb-tests.c | 6 +-- - 9 files changed, 85 insertions(+), 27 deletions(-) - -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index 0265ccac5ee2e7b8baa05bf6b09df39ea5b4059a..72adbd80ea534eb0becd3e517c00b0c26d00444c 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -315,7 +315,7 @@ struct sss_domain_info { - */ - char *forest; - struct sss_domain_info *forest_root; -- char **upn_suffixes; -+ const char **upn_suffixes; - }; - - /** -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index a8dcaa4a9ac5715150487f7efc9c35b778fa0163..407ce3c18a7077e8fe45c3c9c7576ae626105122 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -466,7 +466,8 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb, - const char *name, const char *realm, - const char *flat_name, const char *domain_id, - bool mpg, bool enumerate, const char *forest, -- uint32_t trust_direction); -+ uint32_t trust_direction, -+ struct ldb_message_element *upn_suffixes); - - errno_t sysdb_update_subdomains(struct sss_domain_info *domain); - -diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c -index c0a190f36d886325a5be1e5d1145b6aef6860ffc..02206e470e8e035cc05848137df6a1eb04806869 100644 ---- a/src/db/sysdb_subdomains.c -+++ b/src/db/sysdb_subdomains.c -@@ -237,6 +237,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain) - SYSDB_SUBDOMAIN_ENUM, - SYSDB_SUBDOMAIN_FOREST, - SYSDB_SUBDOMAIN_TRUST_DIRECTION, -+ SYSDB_UPN_SUFFIXES, - NULL}; - struct sss_domain_info *dom; - struct ldb_dn *basedn; -@@ -248,6 +249,8 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain) - bool mpg; - bool enumerate; - uint32_t trust_direction; -+ struct ldb_message_element *tmp_el; -+ const char **upn_suffixes; - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { -@@ -308,6 +311,17 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain) - forest = ldb_msg_find_attr_as_string(res->msgs[i], - SYSDB_SUBDOMAIN_FOREST, NULL); - -+ upn_suffixes = NULL; -+ tmp_el = ldb_msg_find_element(res->msgs[0], SYSDB_UPN_SUFFIXES); -+ if (tmp_el != NULL) { -+ upn_suffixes = sss_ldb_el_to_string_list(tmp_ctx, tmp_el); -+ if (upn_suffixes == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "sss_ldb_el_to_string_list failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ - trust_direction = ldb_msg_find_attr_as_int(res->msgs[i], - SYSDB_SUBDOMAIN_TRUST_DIRECTION, - 0); -@@ -382,6 +396,9 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain) - } - } - -+ talloc_zfree(dom->upn_suffixes); -+ dom->upn_suffixes = talloc_steal(dom, upn_suffixes); -+ - if (!dom->has_views && dom->view_name == NULL) { - /* maybe views are not initialized, copy from parent */ - dom->has_views = dom->parent->has_views; -@@ -448,7 +465,7 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain) - errno_t ret; - TALLOC_CTX *tmp_ctx; - const char *tmp_str; -- struct ldb_message_element **tmp_el; -+ struct ldb_message_element *tmp_el; - struct ldb_dn *basedn; - struct ldb_result *res; - const char *attrs[] = {"cn", -@@ -806,7 +823,8 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb, - const char *name, const char *realm, - const char *flat_name, const char *domain_id, - bool mpg, bool enumerate, const char *forest, -- uint32_t trust_direction) -+ uint32_t trust_direction, -+ struct ldb_message_element *upn_suffixes) - { - TALLOC_CTX *tmp_ctx; - struct ldb_message *msg; -@@ -820,8 +838,10 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb, - SYSDB_SUBDOMAIN_ENUM, - SYSDB_SUBDOMAIN_FOREST, - SYSDB_SUBDOMAIN_TRUST_DIRECTION, -+ SYSDB_UPN_SUFFIXES, - NULL}; - const char *tmp_str; -+ struct ldb_message_element *tmp_el; - bool tmp_bool; - bool store = false; - int realm_flags = 0; -@@ -831,6 +851,7 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb, - int enum_flags = 0; - int forest_flags = 0; - int td_flags = 0; -+ int upn_flags = 0; - uint32_t tmp_td; - int ret; - -@@ -864,6 +885,7 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb, - enum_flags = LDB_FLAG_MOD_ADD; - if (forest) forest_flags = LDB_FLAG_MOD_ADD; - if (trust_direction) td_flags = LDB_FLAG_MOD_ADD; -+ if (upn_suffixes) upn_flags = LDB_FLAG_MOD_ADD; - } else if (res->count != 1) { - ret = EINVAL; - goto done; -@@ -915,11 +937,21 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb, - if (tmp_td != trust_direction) { - td_flags = LDB_FLAG_MOD_REPLACE; - } -+ -+ if (upn_suffixes) { -+ tmp_el = ldb_msg_find_element(res->msgs[0], SYSDB_UPN_SUFFIXES); -+ /* Luckily ldb_msg_element_compare() only compares the values and -+ * not the name. */ -+ if (tmp_el == NULL -+ || ldb_msg_element_compare(upn_suffixes, tmp_el) != 0) { -+ upn_flags = LDB_FLAG_MOD_REPLACE; -+ } -+ } - } - - if (!store && realm_flags == 0 && flat_flags == 0 && id_flags == 0 - && mpg_flags == 0 && enum_flags == 0 && forest_flags == 0 -- && td_flags == 0) { -+ && td_flags == 0 && upn_flags == 0) { - ret = EOK; - goto done; - } -@@ -1048,6 +1080,24 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb, - } - } - -+ if (upn_flags) { -+ tmp_el = talloc_zero(tmp_ctx, struct ldb_message_element); -+ if (tmp_el == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ tmp_el->name = SYSDB_UPN_SUFFIXES; -+ tmp_el->num_values = upn_suffixes->num_values; -+ tmp_el->values = upn_suffixes->values; -+ ret = ldb_msg_add(msg, tmp_el, upn_flags); -+ if (ret != LDB_SUCCESS) { -+ ret = sysdb_error_to_errno(ret); -+ goto done; -+ } -+ } -+ - ret = ldb_modify(sysdb->ldb, msg); - if (ret != LDB_SUCCESS) { - DEBUG(SSSDBG_FATAL_FAILURE, "Failed to add subdomain attributes to " -diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c -index 0a8d1f53cb005507abe4ac55d0fa1ccc9e32b173..928c4fe93cc6afa5c3f69c14503896db820a4c0a 100644 ---- a/src/providers/ad/ad_subdomains.c -+++ b/src/providers/ad/ad_subdomains.c -@@ -252,7 +252,7 @@ ad_subdom_store(struct sdap_idmap_ctx *idmap_ctx, - mpg = sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, name, sid_str); - - ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str, -- mpg, enumerate, domain->forest, 0); -+ mpg, enumerate, domain->forest, 0, NULL); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_subdomain_store failed.\n"); - goto done; -diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c -index 62b8f65e5d29a4850f90ea7c19abd297becc96f5..925b1d8b133eb56724ee4f9133a2487090982a8b 100644 ---- a/src/providers/ipa/ipa_subdomains.c -+++ b/src/providers/ipa/ipa_subdomains.c -@@ -375,6 +375,7 @@ static errno_t ipa_subdom_store(struct sss_domain_info *parent, - bool mpg; - bool enumerate; - uint32_t direction; -+ struct ldb_message_element *alternative_domain_suffixes = NULL; - - tmp_ctx = talloc_new(parent); - if (tmp_ctx == NULL) { -@@ -405,6 +406,12 @@ static errno_t ipa_subdom_store(struct sss_domain_info *parent, - goto done; - } - -+ ret = sysdb_attrs_get_el_ext(attrs, IPA_ADDITIONAL_SUFFIXES, false, -+ &alternative_domain_suffixes); -+ if (ret != EOK && ret != ENOENT) { -+ goto done; -+ } -+ - mpg = sdap_idmap_domain_has_algorithmic_mapping(sdap_idmap_ctx, name, id); - - ret = ipa_subdom_get_forest(tmp_ctx, sysdb_ctx_get_ldb(parent->sysdb), -@@ -431,7 +438,7 @@ static errno_t ipa_subdom_store(struct sss_domain_info *parent, - "Trust direction of %s is %s\n", name, ipa_trust_dir2str(direction)); - ret = sysdb_subdomain_store(parent->sysdb, name, realm, flat, - id, mpg, enumerate, forest, -- direction); -+ direction, alternative_domain_suffixes); - if (ret) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_subdomain_store failed.\n"); - goto done; -diff --git a/src/tests/cmocka/test_ipa_subdomains_server.c b/src/tests/cmocka/test_ipa_subdomains_server.c -index 0fddc951894dee45658497851473b9bddbba0ef7..123cf11c01ef4687eecad31a9d73120a87c643e1 100644 ---- a/src/tests/cmocka/test_ipa_subdomains_server.c -+++ b/src/tests/cmocka/test_ipa_subdomains_server.c -@@ -253,14 +253,14 @@ static void add_test_subdomains(struct trust_test_ctx *test_ctx, - SUBDOM_NAME, SUBDOM_REALM, - NULL, SUBDOM_SID, - true, false, SUBDOM_REALM, -- direction); -+ direction, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, - CHILD_NAME, CHILD_REALM, - CHILD_FLAT, CHILD_SID, - true, false, SUBDOM_REALM, -- direction); -+ direction, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_update_subdomains(test_ctx->tctx->dom); -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index 4137e9151be561a57a8f2e674f385ecb37119255..82a304feed864b09168d0f3e06a4e1bb120df7e4 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -3089,7 +3089,7 @@ static int nss_subdom_test_setup(void **state) - - ret = sysdb_subdomain_store(nss_test_ctx->tctx->sysdb, - testdom[0], testdom[1], testdom[2], testdom[3], -- false, false, NULL, 0); -+ false, false, NULL, 0, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_update_subdomains(nss_test_ctx->tctx->dom); -diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c -index 6d1ec884284487a12bcbfad77c00cd6c30f67707..c9db56841e841472c81d00a79f475dbbd975ccb0 100644 ---- a/src/tests/cmocka/test_sysdb_subdomains.c -+++ b/src/tests/cmocka/test_sysdb_subdomains.c -@@ -103,7 +103,7 @@ static void test_sysdb_subdomain_create(void **state) - - ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, - dom1[0], dom1[1], dom1[2], dom1[3], -- false, false, NULL, 0); -+ false, false, NULL, 0, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_update_subdomains(test_ctx->tctx->dom); -@@ -115,7 +115,7 @@ static void test_sysdb_subdomain_create(void **state) - - ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, - dom2[0], dom2[1], dom2[2], dom2[3], -- false, false, NULL, 1); -+ false, false, NULL, 1, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_update_subdomains(test_ctx->tctx->dom); -@@ -128,12 +128,12 @@ static void test_sysdb_subdomain_create(void **state) - /* Reverse the trust directions */ - ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, - dom1[0], dom1[1], dom1[2], dom1[3], -- false, false, NULL, 1); -+ false, false, NULL, 1, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, - dom2[0], dom2[1], dom2[2], dom2[3], -- false, false, NULL, 0); -+ false, false, NULL, 0, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_update_subdomains(test_ctx->tctx->dom); -@@ -215,27 +215,27 @@ static void test_sysdb_link_forest_root_ipa(void **state) - - ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, - dom1[0], dom1[1], dom1[2], dom1[3], -- false, false, dom1[4], 0); -+ false, false, dom1[4], 0, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, - child_dom1[0], child_dom1[1], - child_dom1[2], child_dom1[3], - false, false, child_dom1[4], -- 0); -+ 0, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, - dom2[0], dom2[1], dom2[2], dom2[3], - false, false, dom2[4], -- 0); -+ 0, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, - child_dom2[0], child_dom2[1], - child_dom2[2], child_dom2[3], - false, false, child_dom2[4], -- 0); -+ 0, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_update_subdomains(test_ctx->tctx->dom); -@@ -308,14 +308,14 @@ static void test_sysdb_link_forest_root_ad(void **state) - child_dom[0], child_dom[1], - child_dom[2], child_dom[3], - false, false, child_dom[4], -- 0); -+ 0, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, - sub_dom[0], sub_dom[1], - sub_dom[2], sub_dom[3], - false, false, sub_dom[4], -- 0); -+ 0, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_update_subdomains(test_ctx->tctx->dom); -@@ -385,14 +385,14 @@ static void test_sysdb_link_forest_member_ad(void **state) - sub_dom[0], sub_dom[1], - sub_dom[2], sub_dom[3], - false, false, sub_dom[4], -- 0); -+ 0, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_subdomain_store(test_ctx->tctx->sysdb, - forest_root[0], forest_root[1], - forest_root[2], forest_root[3], - false, false, forest_root[4], -- 0); -+ 0, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_master_domain_update(test_ctx->tctx->dom); -@@ -469,7 +469,7 @@ static void test_sysdb_link_ad_multidom(void **state) - child_dom[0], child_dom[1], - child_dom[2], child_dom[3], - false, false, child_dom[4], -- 0); -+ 0, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_master_domain_update(main_dom1); -@@ -489,7 +489,7 @@ static void test_sysdb_link_ad_multidom(void **state) - ret = sysdb_subdomain_store(main_dom2->sysdb, - dom2_forest_root[0], dom2_forest_root[1], - dom2_forest_root[2], dom2_forest_root[3], -- false, false, dom2_forest_root[4], 0); -+ false, false, dom2_forest_root[4], 0, NULL); - assert_int_equal(ret, EOK); - - ret = sysdb_master_domain_update(main_dom2); -diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c -index bac8a8788b4fde0d6039121efead6fc20fa046f9..d1450015cb0f0b073045e7b6031423e3f5494d78 100644 ---- a/src/tests/sysdb-tests.c -+++ b/src/tests/sysdb-tests.c -@@ -5472,7 +5472,7 @@ START_TEST(test_sysdb_subdomain_store_user) - fail_unless(subdomain != NULL, "Failed to create new subdomin."); - ret = sysdb_subdomain_store(test_ctx->sysdb, - testdom[0], testdom[1], testdom[2], testdom[3], -- false, false, NULL, 0); -+ false, false, NULL, 0, NULL); - fail_if(ret != EOK, "Could not set up the test (test subdom)"); - - ret = sysdb_update_subdomains(test_ctx->domain); -@@ -5551,7 +5551,7 @@ START_TEST(test_sysdb_subdomain_user_ops) - fail_unless(subdomain != NULL, "Failed to create new subdomin."); - ret = sysdb_subdomain_store(test_ctx->sysdb, - testdom[0], testdom[1], testdom[2], testdom[3], -- false, false, NULL, 0); -+ false, false, NULL, 0, NULL); - fail_if(ret != EOK, "Could not set up the test (test subdom)"); - - ret = sysdb_update_subdomains(test_ctx->domain); -@@ -5624,7 +5624,7 @@ START_TEST(test_sysdb_subdomain_group_ops) - fail_unless(subdomain != NULL, "Failed to create new subdomin."); - ret = sysdb_subdomain_store(test_ctx->sysdb, - testdom[0], testdom[1], testdom[2], testdom[3], -- false, false, NULL, 0); -+ false, false, NULL, 0, NULL); - fail_if(ret != EOK, "Could not set up the test (test subdom)"); - - ret = sysdb_update_subdomains(test_ctx->domain); --- -2.4.11 - diff --git a/SOURCES/0025-DP-add-dp_get_module_data.patch b/SOURCES/0025-DP-add-dp_get_module_data.patch deleted file mode 100644 index bd41853..0000000 --- a/SOURCES/0025-DP-add-dp_get_module_data.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 5ce7c218a7bd34672bd19359dcbeed51cc237474 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 1 Jul 2016 17:57:31 +0200 -Subject: [PATCH 25/27] DP: add dp_get_module_data() - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 35fa5a83ce8badf6bc868937047f44c3f32b7c28) ---- - src/providers/data_provider/dp.h | 2 ++ - src/providers/data_provider/dp_targets.c | 5 +++++ - 2 files changed, 7 insertions(+) - -diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h -index 8cdbd7768a0b3f7f234b6bce6abab02419b3b9d1..5b36baf3489be4cce463dfb42c65a0b7f7ece9ef 100644 ---- a/src/providers/data_provider/dp.h -+++ b/src/providers/data_provider/dp.h -@@ -118,6 +118,8 @@ bool _dp_target_enabled(struct data_provider *provider, - struct dp_module *dp_target_module(struct data_provider *provider, - enum dp_targets target); - -+void *dp_get_module_data(struct dp_module *dp_module); -+ - void _dp_set_method(struct dp_method *methods, - enum dp_methods method, - dp_req_send_fn send_fn, -diff --git a/src/providers/data_provider/dp_targets.c b/src/providers/data_provider/dp_targets.c -index e19cf93a3693dede98567d2105021488380b5408..87ecfe55daa805eec0265795ef76751a1568c474 100644 ---- a/src/providers/data_provider/dp_targets.c -+++ b/src/providers/data_provider/dp_targets.c -@@ -88,6 +88,11 @@ struct dp_module *dp_target_module(struct data_provider *provider, - return provider->targets[target]->module; - } - -+void *dp_get_module_data(struct dp_module *dp_module) -+{ -+ return dp_module == NULL ? NULL : dp_module->module_data; -+} -+ - const char *dp_target_to_string(enum dp_targets target) - { - switch (target) { --- -2.4.11 - diff --git a/SOURCES/0025-KCM-Add-a-in-memory-credential-storage.patch b/SOURCES/0025-KCM-Add-a-in-memory-credential-storage.patch new file mode 100644 index 0000000..6bfffe6 --- /dev/null +++ b/SOURCES/0025-KCM-Add-a-in-memory-credential-storage.patch @@ -0,0 +1,907 @@ +From e7aa9061532b1ac139e155e7e9881c2447675e3c Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 7 Mar 2017 13:49:43 +0100 +Subject: [PATCH 25/36] KCM: Add a in-memory credential storage +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Implements a simple back end for the ccache module that lets the KCM +server store credentials directly in memory. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + Makefile.am | 1 + + src/responder/kcm/kcm.c | 13 +- + src/responder/kcm/kcmsrv_ccache.c | 2 +- + src/responder/kcm/kcmsrv_ccache_mem.c | 805 ++++++++++++++++++++++++++++++++++ + 4 files changed, 817 insertions(+), 4 deletions(-) + create mode 100644 src/responder/kcm/kcmsrv_ccache_mem.c + +diff --git a/Makefile.am b/Makefile.am +index a2b9dc49e95fa2d025f5174d2902866fab180a78..5605c1a53c44fd9e83394e80b7f71828df1d39b6 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1492,6 +1492,7 @@ sssd_kcm_SOURCES = \ + src/responder/kcm/kcm.c \ + src/responder/kcm/kcmsrv_cmd.c \ + src/responder/kcm/kcmsrv_ccache.c \ ++ src/responder/kcm/kcmsrv_ccache_mem.c \ + src/util/sss_sockets.c \ + src/util/sss_krb5.c \ + src/util/sss_iobuf.c \ +diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c +index 90a6999c5e39d48a1a2ea8168d171612a65077d5..2c12ef215ce3967df183e51c20590c5f439d278f 100644 +--- a/src/responder/kcm/kcm.c ++++ b/src/responder/kcm/kcm.c +@@ -22,9 +22,9 @@ + #include "config.h" + + #include +-#include + + #include "responder/kcm/kcm.h" ++#include "responder/kcm/kcmsrv_ccache.h" + #include "responder/kcm/kcmsrv_pvt.h" + #include "responder/common/responder.h" + #include "util/util.h" +@@ -110,7 +110,8 @@ static int kcm_data_destructor(void *ptr) + return 0; + } + +-static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx) ++static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev) + { + struct kcm_resp_ctx *kcm_data; + krb5_error_code kret; +@@ -121,6 +122,12 @@ static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx) + return NULL; + } + ++ kcm_data->db = kcm_ccdb_init(kcm_data, ev, CCDB_BE_MEMORY); ++ if (kcm_data->db == NULL) { ++ talloc_free(kcm_data); ++ return NULL; ++ } ++ + kret = krb5_init_context(&kcm_data->k5c); + if (kret != EOK) { + talloc_free(kcm_data); +@@ -169,7 +176,7 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx, + goto fail; + } + +- kctx->kcm_data = kcm_data_setup(kctx); ++ kctx->kcm_data = kcm_data_setup(kctx, ev); + if (kctx->kcm_data == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, + "fatal error initializing responder data\n"); +diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c +index 2c565b8378e3ec297faf655d3c48d7ab902713d3..2ae120269b0c62275ba2acdff6d6daa8b7077708 100644 +--- a/src/responder/kcm/kcmsrv_ccache.c ++++ b/src/responder/kcm/kcmsrv_ccache.c +@@ -240,7 +240,7 @@ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx, + switch (cc_be) { + case CCDB_BE_MEMORY: + DEBUG(SSSDBG_FUNC_DATA, "KCM back end: memory\n"); +- /* Not implemented yet */ ++ ccdb->ops = &ccdb_mem_ops; + break; + case CCDB_BE_SECRETS: + DEBUG(SSSDBG_FUNC_DATA, "KCM back end: sssd-secrets\n"); +diff --git a/src/responder/kcm/kcmsrv_ccache_mem.c b/src/responder/kcm/kcmsrv_ccache_mem.c +new file mode 100644 +index 0000000000000000000000000000000000000000..1c4f3df8d3b35b0428a143d4b545562d9cc0e574 +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_ccache_mem.c +@@ -0,0 +1,805 @@ ++/* ++ SSSD ++ ++ KCM Server - ccache in-memory storage ++ ++ Copyright (C) Red Hat, 2016 ++ ++ 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 . ++*/ ++ ++#include "config.h" ++ ++#include ++#include ++ ++#include "util/util.h" ++#include "responder/kcm/kcmsrv_ccache_pvt.h" ++#include "responder/kcm/kcmsrv_ccache_be.h" ++ ++struct ccdb_mem; ++ ++/* ++ * The KCM memory database is just a double-linked list of kcm_ccache structures ++ */ ++struct ccache_mem_wrap { ++ struct kcm_ccache *cc; ++ bool is_default; ++ ++ struct ccache_mem_wrap *next; ++ struct ccache_mem_wrap *prev; ++ ++ struct ccdb_mem *mem_be; ++}; ++ ++struct ccdb_mem { ++ /* Both ccaches and the next-id are kept in memory */ ++ struct ccache_mem_wrap *head; ++ unsigned int nextid; ++}; ++ ++/* In order to provide a consistent interface, we need to let the caller ++ * of getbyXXX own the ccache, therefore the memory back end returns a shallow ++ * copy of the ccache ++ */ ++static struct kcm_ccache *kcm_ccache_dup(TALLOC_CTX *mem_ctx, ++ struct kcm_ccache *in) ++{ ++ struct kcm_ccache *out; ++ ++ out = talloc_zero(mem_ctx, struct kcm_ccache); ++ if (out == NULL) { ++ return NULL; ++ } ++ memcpy(out, in, sizeof(struct kcm_ccache)); ++ ++ return out; ++} ++ ++static struct ccache_mem_wrap *memdb_get_by_uuid(struct ccdb_mem *memdb, ++ struct cli_creds *client, ++ uuid_t uuid) ++{ ++ uid_t uid; ++ struct ccache_mem_wrap *ccwrap = NULL; ++ struct ccache_mem_wrap *out = NULL; ++ ++ uid = cli_creds_get_uid(client); ++ ++ DLIST_FOR_EACH(ccwrap, memdb->head) { ++ if (ccwrap->cc == NULL) { ++ /* since KCM stores ccaches, better not crash.. */ ++ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n"); ++ continue; ++ } ++ ++ if (ccwrap->cc->owner.uid == uid) { ++ if (uuid_compare(uuid, ccwrap->cc->uuid) == 0) { ++ out = ccwrap; ++ break; ++ } ++ } ++ } ++ ++ return out; ++} ++ ++static struct ccache_mem_wrap *memdb_get_by_name(struct ccdb_mem *memdb, ++ struct cli_creds *client, ++ const char *name) ++{ ++ uid_t uid; ++ struct ccache_mem_wrap *ccwrap = NULL; ++ struct ccache_mem_wrap *out = NULL; ++ ++ uid = cli_creds_get_uid(client); ++ ++ DLIST_FOR_EACH(ccwrap, memdb->head) { ++ if (ccwrap->cc == NULL) { ++ /* since KCM stores ccaches, better not crash.. */ ++ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n"); ++ continue; ++ } ++ ++ if (ccwrap->cc->owner.uid == uid) { ++ if (strcmp(ccwrap->cc->name, name) == 0) { ++ out = ccwrap; ++ break; ++ } ++ } ++ } ++ ++ return out; ++} ++ ++/* Since with the in-memory database, the database operations are just ++ * fake-async wrappers around otherwise sync operations, we don't often ++ * need any state, so we use this empty structure instead ++ */ ++struct ccdb_mem_dummy_state { ++}; ++ ++static int ccwrap_destructor(void *ptr) ++{ ++ struct ccache_mem_wrap *ccwrap = talloc_get_type(ptr, struct ccache_mem_wrap); ++ ++ if (ccwrap == NULL) { ++ return 0; ++ } ++ ++ if (ccwrap->cc != NULL) { ++ if (ccwrap->cc->creds) { ++ safezero(sss_iobuf_get_data(ccwrap->cc->creds->cred_blob), ++ sss_iobuf_get_size(ccwrap->cc->creds->cred_blob)); ++ } ++ } ++ ++ ++ DLIST_REMOVE(ccwrap->mem_be->head, ccwrap); ++ ++ return 0; ++} ++ ++static errno_t ccdb_mem_init(struct kcm_ccdb *db) ++{ ++ struct ccdb_mem *memdb = NULL; ++ ++ memdb = talloc_zero(db, struct ccdb_mem); ++ if (memdb == NULL) { ++ return ENOMEM; ++ } ++ db->db_handle = memdb; ++ ++ return EOK; ++} ++ ++struct ccdb_mem_nextid_state { ++ unsigned int nextid; ++}; ++ ++static struct tevent_req *ccdb_mem_nextid_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client) ++{ ++ struct tevent_req *req = NULL; ++ struct ccdb_mem_nextid_state *state = NULL; ++ struct ccdb_mem *memdb = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_nextid_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ memdb = talloc_get_type(db->db_handle, struct ccdb_mem); ++ if (memdb == NULL) { ++ ret = EIO; ++ goto immediate; ++ } ++ ++ state->nextid = memdb->nextid++; ++ ++ ret = EOK; ++immediate: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static errno_t ccdb_mem_nextid_recv(struct tevent_req *req, ++ unsigned int *_nextid) ++{ ++ struct ccdb_mem_nextid_state *state = tevent_req_data(req, ++ struct ccdb_mem_nextid_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_nextid = state->nextid; ++ return EOK; ++} ++ ++struct ccdb_mem_list_state { ++ uuid_t *uuid_list; ++}; ++ ++static struct tevent_req *ccdb_mem_list_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client) ++{ ++ struct tevent_req *req = NULL; ++ struct ccache_mem_wrap *ccwrap = NULL; ++ struct ccdb_mem_list_state *state = NULL; ++ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); ++ size_t num_ccaches = 0; ++ size_t cc_index = 0; ++ errno_t ret; ++ uid_t uid; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_list_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ uid = cli_creds_get_uid(client); ++ ++ DLIST_FOR_EACH(ccwrap, memdb->head) { ++ if (ccwrap->cc->owner.uid == uid) { ++ num_ccaches++; ++ } ++ } ++ ++ state->uuid_list = talloc_zero_array(state, uuid_t, num_ccaches+1); ++ if (state->uuid_list == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ cc_index = 0; ++ DLIST_FOR_EACH(ccwrap, memdb->head) { ++ if (ccwrap->cc->owner.uid == uid) { ++ uuid_copy(state->uuid_list[cc_index], ccwrap->cc->uuid); ++ cc_index++; ++ } ++ } ++ uuid_clear(state->uuid_list[num_ccaches]); ++ ++ ret = EOK; ++immediate: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static errno_t ccdb_mem_list_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ uuid_t **_uuid_list) ++{ ++ struct ccdb_mem_list_state *state = tevent_req_data(req, ++ struct ccdb_mem_list_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_uuid_list = talloc_steal(mem_ctx, state->uuid_list); ++ return EOK; ++} ++ ++static struct tevent_req *ccdb_mem_set_default_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid) ++{ ++ struct tevent_req *req = NULL; ++ struct ccdb_mem_dummy_state *state = NULL; ++ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); ++ struct ccache_mem_wrap *ccwrap = NULL; ++ uid_t uid = cli_creds_get_uid(client); ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ /* Reset all ccache defaults first */ ++ DLIST_FOR_EACH(ccwrap, memdb->head) { ++ if (ccwrap->cc == NULL) { ++ /* since KCM stores ccaches, better not crash.. */ ++ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n"); ++ continue; ++ } ++ ++ if (ccwrap->cc->owner.uid == uid) { ++ ccwrap->is_default = false; ++ } ++ } ++ ++ /* Then set the default for the right ccache. This also allows to ++ * pass a null uuid to just reset the old ccache (for example after ++ * deleting the default ++ */ ++ ccwrap = memdb_get_by_uuid(memdb, client, uuid); ++ if (ccwrap != NULL) { ++ ccwrap->is_default = true; ++ } ++ ++ tevent_req_done(req); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static errno_t ccdb_mem_set_default_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++struct ccdb_mem_get_default_state { ++ uuid_t dfl_uuid; ++}; ++ ++static struct tevent_req *ccdb_mem_get_default_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client) ++{ ++ struct tevent_req *req = NULL; ++ struct ccdb_mem_get_default_state *state = NULL; ++ struct ccache_mem_wrap *ccwrap = NULL; ++ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); ++ uid_t uid = cli_creds_get_uid(client); ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_get_default_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ ++ /* Reset all ccache defaults first */ ++ DLIST_FOR_EACH(ccwrap, memdb->head) { ++ if (ccwrap->cc == NULL) { ++ /* since KCM stores ccaches, better not crash.. */ ++ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n"); ++ continue; ++ } ++ ++ if (ccwrap->cc->owner.uid == uid && ccwrap->is_default == true) { ++ break; ++ } ++ } ++ ++ if (ccwrap == NULL) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "No ccache marked as default, returning null ccache\n"); ++ uuid_clear(state->dfl_uuid); ++ } else { ++ uuid_copy(state->dfl_uuid, ccwrap->cc->uuid); ++ } ++ ++ tevent_req_done(req); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static errno_t ccdb_mem_get_default_recv(struct tevent_req *req, ++ uuid_t dfl) ++{ ++ struct ccdb_mem_get_default_state *state = tevent_req_data(req, ++ struct ccdb_mem_get_default_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ uuid_copy(dfl, state->dfl_uuid); ++ return EOK; ++} ++ ++struct ccdb_mem_getbyuuid_state { ++ struct kcm_ccache *cc; ++}; ++ ++static struct tevent_req *ccdb_mem_getbyuuid_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid) ++{ ++ struct tevent_req *req = NULL; ++ struct ccdb_mem_getbyuuid_state *state = NULL; ++ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); ++ struct ccache_mem_wrap *ccwrap = NULL; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_getbyuuid_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ ccwrap = memdb_get_by_uuid(memdb, client, uuid); ++ if (ccwrap != NULL) { ++ state->cc = kcm_ccache_dup(state, ccwrap->cc); ++ } ++ ++ tevent_req_done(req); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static errno_t ccdb_mem_getbyuuid_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ccache **_cc) ++{ ++ struct ccdb_mem_getbyuuid_state *state = tevent_req_data(req, ++ struct ccdb_mem_getbyuuid_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_cc = talloc_steal(mem_ctx, state->cc); ++ return EOK; ++} ++ ++struct ccdb_mem_getbyname_state { ++ struct kcm_ccache *cc; ++}; ++ ++static struct tevent_req *ccdb_mem_getbyname_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ const char *name) ++{ ++ struct tevent_req *req = NULL; ++ struct ccdb_mem_getbyname_state *state = NULL; ++ struct ccache_mem_wrap *ccwrap = NULL; ++ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_getbyname_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ ccwrap = memdb_get_by_name(memdb, client, name); ++ if (ccwrap != NULL) { ++ state->cc = kcm_ccache_dup(state, ccwrap->cc); ++ } ++ ++ tevent_req_done(req); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static errno_t ccdb_mem_getbyname_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ccache **_cc) ++{ ++ struct ccdb_mem_getbyname_state *state = tevent_req_data(req, ++ struct ccdb_mem_getbyname_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_cc = talloc_steal(mem_ctx, state->cc); ++ return EOK; ++} ++ ++struct ccdb_mem_name_by_uuid_state { ++ const char *name; ++}; ++ ++struct tevent_req *ccdb_mem_name_by_uuid_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid) ++{ ++ struct tevent_req *req = NULL; ++ struct ccdb_mem_name_by_uuid_state *state = NULL; ++ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); ++ struct ccache_mem_wrap *ccwrap = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_name_by_uuid_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ ccwrap = memdb_get_by_uuid(memdb, client, uuid); ++ if (ccwrap == NULL) { ++ ret = ERR_KCM_CC_END; ++ goto immediate; ++ } ++ ++ state->name = talloc_strdup(state, ccwrap->cc->name); ++ if (state->name == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ ret = EOK; ++immediate: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++errno_t ccdb_mem_name_by_uuid_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ const char **_name) ++{ ++ struct ccdb_mem_name_by_uuid_state *state = tevent_req_data(req, ++ struct ccdb_mem_name_by_uuid_state); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_name = talloc_steal(mem_ctx, state->name); ++ return EOK; ++} ++ ++struct ccdb_mem_uuid_by_name_state { ++ uuid_t uuid; ++}; ++ ++struct tevent_req *ccdb_mem_uuid_by_name_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ const char *name) ++{ ++ struct tevent_req *req = NULL; ++ struct ccdb_mem_uuid_by_name_state *state = NULL; ++ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); ++ struct ccache_mem_wrap *ccwrap = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_uuid_by_name_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ ccwrap = memdb_get_by_name(memdb, client, name); ++ if (ccwrap == NULL) { ++ ret = ERR_KCM_CC_END; ++ goto immediate; ++ } ++ ++ uuid_copy(state->uuid, ccwrap->cc->uuid); ++ ++ ret = EOK; ++immediate: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++errno_t ccdb_mem_uuid_by_name_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ uuid_t _uuid) ++{ ++ struct ccdb_mem_uuid_by_name_state *state = tevent_req_data(req, ++ struct ccdb_mem_uuid_by_name_state); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ uuid_copy(_uuid, state->uuid); ++ return EOK; ++} ++ ++static struct tevent_req *ccdb_mem_create_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ struct kcm_ccache *cc) ++{ ++ struct tevent_req *req = NULL; ++ struct ccdb_mem_dummy_state *state = NULL; ++ struct ccache_mem_wrap *ccwrap; ++ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ ccwrap = talloc_zero(memdb, struct ccache_mem_wrap); ++ if (ccwrap == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ccwrap->cc = cc; ++ ccwrap->mem_be = memdb; ++ talloc_steal(ccwrap, cc); ++ ++ DLIST_ADD(memdb->head, ccwrap); ++ talloc_set_destructor((TALLOC_CTX *) ccwrap, ccwrap_destructor); ++ ++ ret = EOK; ++immediate: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static errno_t ccdb_mem_create_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++static struct tevent_req *ccdb_mem_mod_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid, ++ struct kcm_mod_ctx *mod_cc) ++{ ++ errno_t ret; ++ struct tevent_req *req = NULL; ++ struct ccdb_mem_dummy_state *state = NULL; ++ struct ccache_mem_wrap *ccwrap = NULL; ++ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ /* UUID is immutable, so search by that */ ++ ccwrap = memdb_get_by_uuid(memdb, client, uuid); ++ if (ccwrap == NULL) { ++ ret = ERR_KCM_CC_END; ++ goto immediate; ++ } ++ ++ kcm_mod_cc(ccwrap->cc, mod_cc); ++ ++ ret = EOK; ++immediate: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static errno_t ccdb_mem_mod_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++static struct tevent_req *ccdb_mem_store_cred_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid, ++ struct sss_iobuf *cred_blob) ++{ ++ struct tevent_req *req = NULL; ++ struct ccdb_mem_dummy_state *state = NULL; ++ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); ++ struct ccache_mem_wrap *ccwrap = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ ccwrap = memdb_get_by_uuid(memdb, client, uuid); ++ if (ccwrap == NULL) { ++ ret = ERR_KCM_CC_END; ++ goto immediate; ++ } ++ ++ ret = kcm_cc_store_cred_blob(ccwrap->cc, cred_blob); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot store credentials to ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ ret = EOK; ++immediate: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static errno_t ccdb_mem_store_cred_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++static struct tevent_req *ccdb_mem_delete_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid) ++{ ++ struct tevent_req *req = NULL; ++ struct ccdb_mem_dummy_state *state = NULL; ++ struct ccache_mem_wrap *ccwrap; ++ struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem); ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ ccwrap = memdb_get_by_uuid(memdb, client, uuid); ++ if (ccwrap == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "BUG: Attempting to free unknown ccache\n"); ++ ret = ERR_KCM_CC_END; ++ goto immediate; ++ } ++ ++ ret = EOK; ++ /* Destructor takes care of everything */ ++ talloc_free(ccwrap); ++immediate: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static errno_t ccdb_mem_delete_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++const struct kcm_ccdb_ops ccdb_mem_ops = { ++ .init = ccdb_mem_init, ++ ++ .nextid_send = ccdb_mem_nextid_send, ++ .nextid_recv = ccdb_mem_nextid_recv, ++ ++ .set_default_send = ccdb_mem_set_default_send, ++ .set_default_recv = ccdb_mem_set_default_recv, ++ ++ .get_default_send = ccdb_mem_get_default_send, ++ .get_default_recv = ccdb_mem_get_default_recv, ++ ++ .list_send = ccdb_mem_list_send, ++ .list_recv = ccdb_mem_list_recv, ++ ++ .getbyname_send = ccdb_mem_getbyname_send, ++ .getbyname_recv = ccdb_mem_getbyname_recv, ++ ++ .getbyuuid_send = ccdb_mem_getbyuuid_send, ++ .getbyuuid_recv = ccdb_mem_getbyuuid_recv, ++ ++ .name_by_uuid_send = ccdb_mem_name_by_uuid_send, ++ .name_by_uuid_recv = ccdb_mem_name_by_uuid_recv, ++ ++ .uuid_by_name_send = ccdb_mem_uuid_by_name_send, ++ .uuid_by_name_recv = ccdb_mem_uuid_by_name_recv, ++ ++ .create_send = ccdb_mem_create_send, ++ .create_recv = ccdb_mem_create_recv, ++ ++ .mod_send = ccdb_mem_mod_send, ++ .mod_recv = ccdb_mem_mod_recv, ++ ++ .store_cred_send = ccdb_mem_store_cred_send, ++ .store_cred_recv = ccdb_mem_store_cred_recv, ++ ++ .delete_send = ccdb_mem_delete_send, ++ .delete_recv = ccdb_mem_delete_recv, ++}; +-- +2.9.3 + diff --git a/SOURCES/0026-IPA-add-ipa_init_get_krb5_auth_ctx.patch b/SOURCES/0026-IPA-add-ipa_init_get_krb5_auth_ctx.patch deleted file mode 100644 index 878d78e..0000000 --- a/SOURCES/0026-IPA-add-ipa_init_get_krb5_auth_ctx.patch +++ /dev/null @@ -1,60 +0,0 @@ -From ec460578800d850e5a4f9d522920db1d79147dd6 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 1 Jul 2016 17:58:02 +0200 -Subject: [PATCH 26/27] IPA: add ipa_init_get_krb5_auth_ctx() - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 17dccc24e4490dfda2820d46b62a029b14ba2359) ---- - src/providers/ipa/ipa_common.h | 5 +++++ - src/providers/ipa/ipa_init.c | 13 +++++++++++++ - 2 files changed, 18 insertions(+) - -diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h -index 939c898e1a690806abd37493aabfb7bdec3e87a9..add9df87692c732b3567eee5584e7698991c66ca 100644 ---- a/src/providers/ipa/ipa_common.h -+++ b/src/providers/ipa/ipa_common.h -@@ -34,6 +34,8 @@ struct ipa_service { - struct krb5_service *krb5_service; - }; - -+struct ipa_init_ctx; -+ - enum ipa_basic_opt { - IPA_DOMAIN = 0, - IPA_SERVER, -@@ -287,4 +289,7 @@ errno_t ipa_idmap_get_ranges_from_sysdb(struct sdap_idmap_ctx *idmap_ctx, - errno_t ipa_idmap_init(TALLOC_CTX *mem_ctx, - struct sdap_id_ctx *id_ctx, - struct sdap_idmap_ctx **_idmap_ctx); -+ -+ -+struct krb5_ctx *ipa_init_get_krb5_auth_ctx(void *data); - #endif /* _IPA_COMMON_H_ */ -diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c -index d3093b3b5d269e6acd29f35560cf8299017c72b5..959cdb4a7c40c1be03dd1e7c66dee6e65ca76607 100644 ---- a/src/providers/ipa/ipa_init.c -+++ b/src/providers/ipa/ipa_init.c -@@ -58,6 +58,19 @@ struct ipa_init_ctx { - struct ipa_auth_ctx *auth_ctx; - }; - -+ -+struct krb5_ctx *ipa_init_get_krb5_auth_ctx(void *data) -+{ -+ struct ipa_init_ctx *ipa_init_ctx; -+ -+ ipa_init_ctx = talloc_get_type(data, struct ipa_init_ctx); -+ if (ipa_init_ctx == NULL || ipa_init_ctx->auth_ctx == NULL) { -+ return NULL; -+ } -+ -+ return ipa_init_ctx->auth_ctx->krb5_auth_ctx; -+} -+ - static bool srv_in_server_list(const char *servers) - { - TALLOC_CTX *tmp_ctx; --- -2.4.11 - diff --git a/SOURCES/0026-KCM-Implement-KCM-server-operations.patch b/SOURCES/0026-KCM-Implement-KCM-server-operations.patch new file mode 100644 index 0000000..56f486a --- /dev/null +++ b/SOURCES/0026-KCM-Implement-KCM-server-operations.patch @@ -0,0 +1,2326 @@ +From 5287b672cbba97a5c30ca79954101bd134a30eca Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 23 Sep 2016 14:49:09 +0200 +Subject: [PATCH 26/36] KCM: Implement KCM server operations +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Implements the actual KCM server operations. On a high level, each +operation unmarhalls the needed data from the input buffer, calls into +the ccache db and marshalls a response. + +Only the operations that are also implemented by the MIT client are +implemented by our KCM server. + +Resolves: + https://pagure.io/SSSD/sssd/issue/2887 + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + Makefile.am | 2 + + src/responder/kcm/kcmsrv_cmd.c | 151 +++- + src/responder/kcm/kcmsrv_ops.c | 1954 ++++++++++++++++++++++++++++++++++++++++ + src/responder/kcm/kcmsrv_ops.h | 45 + + 4 files changed, 2143 insertions(+), 9 deletions(-) + create mode 100644 src/responder/kcm/kcmsrv_ops.c + create mode 100644 src/responder/kcm/kcmsrv_ops.h + +diff --git a/Makefile.am b/Makefile.am +index 5605c1a53c44fd9e83394e80b7f71828df1d39b6..49b4cabf9ee3ce1417f955c972376894f3709b33 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -714,6 +714,7 @@ dist_noinst_HEADERS = \ + src/responder/kcm/kcmsrv_ccache.h \ + src/responder/kcm/kcmsrv_ccache_pvt.h \ + src/responder/kcm/kcmsrv_ccache_be.h \ ++ src/responder/kcm/kcmsrv_ops.h \ + src/sbus/sbus_client.h \ + src/sbus/sssd_dbus.h \ + src/sbus/sssd_dbus_meta.h \ +@@ -1493,6 +1494,7 @@ sssd_kcm_SOURCES = \ + src/responder/kcm/kcmsrv_cmd.c \ + src/responder/kcm/kcmsrv_ccache.c \ + src/responder/kcm/kcmsrv_ccache_mem.c \ ++ src/responder/kcm/kcmsrv_ops.c \ + src/util/sss_sockets.c \ + src/util/sss_krb5.c \ + src/util/sss_iobuf.c \ +diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c +index cbf70353730d8a4e03d8f75c97395f4ef007e77f..537e88953fd1a190a9a73bcdd430d8e0db8f9291 100644 +--- a/src/responder/kcm/kcmsrv_cmd.c ++++ b/src/responder/kcm/kcmsrv_cmd.c +@@ -23,10 +23,10 @@ + + #include "config.h" + #include "util/util.h" +-#include "util/sss_iobuf.h" + #include "responder/common/responder.h" + #include "responder/kcm/kcmsrv_pvt.h" + #include "responder/kcm/kcm.h" ++#include "responder/kcm/kcmsrv_ops.h" + + /* The first four bytes of a message is always the size */ + #define KCM_MSG_LEN_SIZE 4 +@@ -133,7 +133,6 @@ static errno_t kcm_input_parse(struct kcm_reqbuf *reqbuf, + { + size_t lc = 0; + size_t mc = 0; +- uint16_t opcode = 0; + uint16_t opcode_be = 0; + uint32_t len_be = 0; + uint32_t msglen; +@@ -162,7 +161,7 @@ static errno_t kcm_input_parse(struct kcm_reqbuf *reqbuf, + return EBADMSG; + } + +- /* First 16 bits are 8 bit major and 8bit major protocol version */ ++ /* First 16 bits are 8 bit major and 8bit minor protocol version */ + SAFEALIGN_COPY_UINT8_CHECK(&proto_maj, + reqbuf->v_msg.kiov_base + mc, + reqbuf->v_msg.kiov_len, +@@ -191,8 +190,16 @@ static errno_t kcm_input_parse(struct kcm_reqbuf *reqbuf, + reqbuf->v_msg.kiov_len, + &mc); + +- opcode = be16toh(opcode_be); +- DEBUG(SSSDBG_TRACE_LIBS, "Received operation code %"PRIu16"\n", opcode); ++ op_io->op = kcm_get_opt(be16toh(opcode_be)); ++ if (op_io->op == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Did not find a KCM operation handler for the requested opcode\n"); ++ return ERR_KCM_MALFORMED_IN_PKT; ++ } ++ ++ /* The operation only receives the payload, not the opcode or the protocol info */ ++ op_io->request.data = reqbuf->v_msg.kiov_base + mc; ++ op_io->request.length = reqbuf->v_msg.nprocessed - mc; + + return EOK; + } +@@ -240,6 +247,46 @@ static errno_t kcm_failbuf_construct(errno_t ret, + c = 0; + SAFEALIGN_SETMEM_UINT32(repbuf->rcbuf, htobe32(ret), &c); + ++ DEBUG(SSSDBG_TRACE_LIBS, "Sent reply with error %d\n", ret); ++ return EOK; ++} ++ ++/* retcode is 0 if the operation at least ran, non-zero if there ++ * was some kind of internal KCM error, like input couldn't be parsed ++ */ ++static errno_t kcm_output_construct(struct kcm_op_io *op_io, ++ struct kcm_repbuf *repbuf) ++{ ++ size_t c; ++ size_t replen; ++ ++ replen = sss_iobuf_get_len(op_io->reply); ++ if (replen > KCM_PACKET_MAX_SIZE) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Reply exceeds the KCM protocol limit, aborting\n"); ++ return E2BIG; ++ } ++ ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "Sending a reply with %zu bytes of payload\n", replen); ++ c = 0; ++ SAFEALIGN_SETMEM_UINT32(repbuf->lenbuf, htobe32(replen), &c); ++ ++ c = 0; ++ SAFEALIGN_SETMEM_UINT32(repbuf->rcbuf, 0, &c); ++ ++ if (replen > 0) { ++ c = 0; ++ SAFEALIGN_MEMCPY_CHECK(repbuf->msgbuf, ++ sss_iobuf_get_data(op_io->reply), ++ replen, ++ repbuf->v_msg.kiov_len, ++ &c); ++ ++ /* Length of the buffer to send to KCM client */ ++ repbuf->v_msg.kiov_len = replen; ++ } ++ + return EOK; + } + +@@ -260,7 +307,8 @@ static void kcm_reply_error(struct cli_ctx *cctx, + + ret = kcm_failbuf_construct(kerr, repbuf); + if (ret != EOK) { +- /* If we can't construct the reply buffer, just terminate the client */ ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot construct the reply buffer, terminating client\n"); + talloc_free(cctx); + return; + } +@@ -268,6 +316,24 @@ static void kcm_reply_error(struct cli_ctx *cctx, + TEVENT_FD_WRITEABLE(cctx->cfde); + } + ++static void kcm_send_reply(struct cli_ctx *cctx, ++ struct kcm_op_io *op_io, ++ struct kcm_repbuf *repbuf) ++{ ++ errno_t ret; ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Sending a reply\n"); ++ ret = kcm_output_construct(op_io, repbuf); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot construct the reply buffer, terminating client\n"); ++ kcm_reply_error(cctx, ret, repbuf); ++ return; ++ } ++ ++ TEVENT_FD_WRITEABLE(cctx->cfde); ++} ++ + /** + * Request-reply dispatcher + */ +@@ -285,17 +351,67 @@ struct kcm_req_ctx { + struct kcm_op_io op_io; + }; + ++static void kcm_cmd_request_done(struct tevent_req *req); ++ ++static errno_t kcm_cmd_dispatch(struct kcm_req_ctx *req_ctx) ++{ ++ struct tevent_req *req; ++ struct cli_ctx *cctx; ++ ++ cctx = req_ctx->cctx; ++ ++ req = kcm_cmd_send(req_ctx, cctx->ev, req_ctx->kctx->kcm_data, ++ req_ctx->cctx->creds, ++ &req_ctx->op_io.request, ++ req_ctx->op_io.op); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to schedule KCM operation.\n"); ++ return ENOMEM; ++ } ++ ++ tevent_req_set_callback(req, kcm_cmd_request_done, req_ctx); ++ return EOK; ++} ++ ++static void kcm_cmd_request_done(struct tevent_req *req) ++{ ++ struct kcm_req_ctx *req_ctx; ++ struct cli_ctx *cctx; ++ errno_t ret; ++ ++ req_ctx = tevent_req_callback_data(req, struct kcm_req_ctx); ++ cctx = req_ctx->cctx; ++ ++ ret = kcm_cmd_recv(req_ctx, req, ++ &req_ctx->op_io.reply); ++ talloc_free(req); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "KCM operation failed [%d]: %s\n", ret, sss_strerror(ret)); ++ kcm_reply_error(cctx, ret, &req_ctx->repbuf); ++ return; ++ } ++ ++ kcm_send_reply(cctx, &req_ctx->op_io, &req_ctx->repbuf); ++} ++ + static errno_t kcm_recv_data(int fd, struct kcm_reqbuf *reqbuf) + { + errno_t ret; + + ret = kcm_read_iovec(fd, &reqbuf->v_len); + if (ret != EOK) { ++ /* Not all errors are fatal, hence we don't print DEBUG messages ++ * here, but in the caller ++ */ + return ret; + } + + ret = kcm_read_iovec(fd, &reqbuf->v_msg); + if (ret != EOK) { ++ /* Not all errors are fatal, hence we don't print DEBUG messages ++ * here, but in the caller ++ */ + return ret; + } + +@@ -389,7 +505,15 @@ static void kcm_recv(struct cli_ctx *cctx) + /* do not read anymore, client is done sending */ + TEVENT_FD_NOT_READABLE(cctx->cfde); + +- kcm_reply_error(cctx, ret, &req->repbuf); ++ ret = kcm_cmd_dispatch(req); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to dispatch KCM operation [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto fail; ++ } ++ ++ /* Dispatched request resumes in kcm_cmd_request_done */ + return; + + fail: +@@ -406,16 +530,25 @@ static int kcm_send_data(struct cli_ctx *cctx) + + ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_len); + if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to write the length iovec [%d]: %s\n", ++ ret, sss_strerror(ret)); + return ret; + } + + ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_rc); + if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to write the retcode iovec [%d]: %s\n", ++ ret, sss_strerror(ret)); + return ret; + } + + ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_msg); + if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to write the msg iovec [%d]: %s\n", ++ ret, sss_strerror(ret)); + return ret; + } + +@@ -428,7 +561,7 @@ static void kcm_send(struct cli_ctx *cctx) + + ret = kcm_send_data(cctx); + if (ret == EAGAIN) { +- /* not all data was sent, loop again */ ++ DEBUG(SSSDBG_TRACE_ALL, "Sending data again..\n"); + return; + } else if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting client!\n"); +@@ -436,7 +569,7 @@ static void kcm_send(struct cli_ctx *cctx) + return; + } + +- /* ok all sent */ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "All data sent!\n"); + TEVENT_FD_NOT_WRITEABLE(cctx->cfde); + TEVENT_FD_READABLE(cctx->cfde); + talloc_zfree(cctx->state_ctx); +diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c +new file mode 100644 +index 0000000000000000000000000000000000000000..50e8cc635424e15d53e3c8d122c5525044f59c8a +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_ops.c +@@ -0,0 +1,1954 @@ ++/* ++ SSSD ++ ++ KCM Server - the KCM server operations ++ ++ Copyright (C) Red Hat, 2016 ++ ++ 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 . ++*/ ++ ++#include "config.h" ++ ++#include ++ ++#include "util/sss_iobuf.h" ++#include "util/sss_krb5.h" ++#include "util/util_creds.h" ++#include "responder/kcm/kcm.h" ++#include "responder/kcm/kcmsrv_pvt.h" ++#include "responder/kcm/kcmsrv_ops.h" ++#include "responder/kcm/kcmsrv_ccache.h" ++ ++#define KCM_REPLY_MAX 2048 ++ ++struct kcm_op_ctx { ++ struct kcm_resp_ctx *kcm_data; ++ struct cli_creds *client; ++ ++ struct sss_iobuf *input; ++ struct sss_iobuf *reply; ++}; ++ ++/* Each operation follows the same pattern and is implemented using ++ * functions with this prototype. The operation receives an op_ctx ++ * that serves as a state of the operation and can be used to keep ++ * track of any temporary data. The operation writes its output data ++ * into the op_ctx reply IO buffer and returns the op_ret status code ++ * separately. ++ * ++ * The operation always returns EOK unless an internal error occurs, ++ * the result of the operation is stored in the op_ret variable ++ */ ++typedef struct tevent_req* ++(*kcm_srv_send_method)(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx); ++typedef errno_t ++(*kcm_srv_recv_method)(struct tevent_req *req, ++ uint32_t *_op_ret); ++ ++struct kcm_op { ++ const char *name; ++ kcm_srv_send_method fn_send; ++ kcm_srv_recv_method fn_recv; ++}; ++ ++struct kcm_cmd_state { ++ struct kcm_op *op; ++ ++ struct kcm_op_ctx *op_ctx; ++ struct sss_iobuf *reply; ++ ++ uint32_t op_ret; ++}; ++ ++static void kcm_cmd_done(struct tevent_req *subreq); ++ ++struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_resp_ctx *kcm_data, ++ struct cli_creds *client, ++ struct kcm_data *input, ++ struct kcm_op *op) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_cmd_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_cmd_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op = op; ++ ++ if (op == NULL) { ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "KCM operation %s\n", op->name); ++ DEBUG(SSSDBG_TRACE_LIBS, "%zu bytes on KCM input\n", input->length); ++ ++ state->reply = sss_iobuf_init_empty(state, ++ KCM_REPLY_MAX, ++ KCM_REPLY_MAX); ++ if (state->reply == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ if (op->fn_send == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "KCM op %s has no handler\n", kcm_opt_name(op)); ++ ret = ERR_KCM_OP_NOT_IMPLEMENTED; ++ goto immediate; ++ } ++ ++ /* Allocating op_ctx on the heap makes it possible for operations to use ++ * op_ctx as their temporary context and avoid tmp_ctx altogether ++ */ ++ state->op_ctx = talloc_zero(state, struct kcm_op_ctx); ++ if (state->op_ctx == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ state->op_ctx->kcm_data = kcm_data; ++ state->op_ctx->client = client; ++ ++ state->op_ctx->input = sss_iobuf_init_readonly(state->op_ctx, ++ input->data, ++ input->length); ++ if (state->op_ctx->input == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ /* ++ * The internal operation returns the opcode and the buffer separately. ++ * The KCM server reply to the client also always contains zero if the ++ * operation ran to completion, both are uint32_t. ++ * FIXME: ++ * Alternatively, we could extend iobuf API so that we can just pass ++ * the reply's buffer+sizeof(2*uint32_t) and avoid the useless allocations ++ */ ++ state->op_ctx->reply = sss_iobuf_init_empty( ++ state, ++ KCM_REPLY_MAX - 2*sizeof(uint32_t), ++ KCM_REPLY_MAX - 2*sizeof(uint32_t)); ++ if (state->reply == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ subreq = op->fn_send(state, ev, state->op_ctx); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_cmd_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_cmd_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); ++ struct kcm_cmd_state *state = tevent_req_data(req, struct kcm_cmd_state); ++ errno_t ret; ++ krb5_error_code kerr; ++ ++ ret = state->op->fn_recv(subreq, &state->op_ret); ++ talloc_free(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "op receive function failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "KCM operation %s returned [%d]: %s\n", ++ kcm_opt_name(state->op), state->op_ret, sss_strerror(state->op_ret)); ++ ++ kerr = sss2krb5_error(state->op_ret); ++ ++ /* The first four bytes of the reply is the operation status code */ ++ ret = sss_iobuf_write_uint32(state->reply, htobe32(kerr)); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ ret = sss_iobuf_write_len(state->reply, ++ sss_iobuf_get_data(state->op_ctx->reply), ++ sss_iobuf_get_len(state->op_ctx->reply)); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t kcm_cmd_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct sss_iobuf **_reply) ++{ ++ struct kcm_cmd_state *state = NULL; ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ state = tevent_req_data(req, struct kcm_cmd_state); ++ ++ *_reply = talloc_steal(mem_ctx, state->reply); ++ return EOK; ++} ++ ++/* ======= KCM operations ======= */ ++ ++/* Operations that don't return any extra information except for the op_ret ++ * can use this macro in the _recv function to avoid code duplication ++ */ ++#define KCM_OP_RET_FROM_TYPE(req, state_type, _op_ret_out) do { \ ++ state_type *state = NULL; \ ++ state = tevent_req_data(req, state_type); \ ++ TEVENT_REQ_RETURN_ON_ERROR(req); \ ++ *_op_ret_out = state->op_ret; \ ++ return EOK; \ ++} while(0); ++ ++struct kcm_op_common_state { ++ uint32_t op_ret; ++ struct kcm_op_ctx *op_ctx; ++ struct tevent_context *ev; ++}; ++ ++static errno_t kcm_op_common_recv(struct tevent_req *req, ++ uint32_t *_op_ret) ++{ ++ struct kcm_op_common_state *state = tevent_req_data(req, ++ struct kcm_op_common_state); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_op_ret = state->op_ret; ++ return EOK; ++} ++ ++/* () -> (name) */ ++static void kcm_op_gen_new_done(struct tevent_req *subreq); ++ ++static struct tevent_req *kcm_op_gen_new_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_op_common_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ ++ subreq = kcm_ccdb_nextid_send(state, ev, ++ op_ctx->kcm_data->db, ++ op_ctx->client); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_op_gen_new_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_op_gen_new_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ char *newid; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_common_state *state = tevent_req_data(req, ++ struct kcm_op_common_state); ++ ++ ret = kcm_ccdb_nextid_recv(subreq, state, &newid); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot generate a new ID [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_LIBS, "Generated a new ID %s\n", newid); ++ ++ ret = sss_iobuf_write_stringz(state->op_ctx->reply, newid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot write generated ID %d: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->op_ret = EOK; ++ tevent_req_done(req); ++} ++ ++/* (princ) -> () */ ++struct kcm_op_initialize_state { ++ uint32_t op_ret; ++ struct kcm_op_ctx *op_ctx; ++ struct tevent_context *ev; ++ ++ struct kcm_ccache *new_cc; ++ const char *name; ++ krb5_principal princ; ++}; ++ ++static void kcm_op_initialize_got_byname(struct tevent_req *subreq); ++static void kcm_op_initialize_cc_create_done(struct tevent_req *subreq); ++static void kcm_op_initialize_cc_delete_done(struct tevent_req *subreq); ++static void kcm_op_initialize_create_step(struct tevent_req *req); ++static void kcm_op_initialize_got_default(struct tevent_req *subreq); ++static void kcm_op_initialize_set_default_done(struct tevent_req *subreq); ++ ++static struct tevent_req *kcm_op_initialize_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_op_initialize_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_initialize_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ state->ev = ev; ++ ++ ret = sss_iobuf_read_stringz(op_ctx->input, &state->name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot read input name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ DEBUG(SSSDBG_TRACE_LIBS, "Initializing ccache %s\n", state->name); ++ ++ ret = kcm_check_name(state->name, op_ctx->client); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Name %s is malformed [%d]: %s\n", ++ state->name, ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ ret = sss_krb5_unmarshal_princ(op_ctx, op_ctx->input, &state->princ); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot unmarshal principal [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ subreq = kcm_ccdb_getbyname_send(state, ev, ++ op_ctx->kcm_data->db, ++ op_ctx->client, ++ state->name); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_op_initialize_got_byname, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_op_initialize_got_byname(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_initialize_state *state = tevent_req_data(req, ++ struct kcm_op_initialize_state); ++ bool ok; ++ uuid_t uuid; ++ ++ ret = kcm_ccdb_getbyname_recv(subreq, state, &state->new_cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get ccache by name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (state->new_cc != NULL) { ++ ok = kcm_cc_access(state->new_cc, state->op_ctx->client); ++ if (!ok) { ++ state->op_ret = EACCES; ++ tevent_req_done(req); ++ return; ++ } ++ ++ ret = kcm_cc_get_uuid(state->new_cc, uuid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get new ccache UUID [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return; ++ } ++ ++ /* Nuke any previous cache and its contents during initialization */ ++ subreq = kcm_ccdb_delete_cc_send(state, ++ state->ev, ++ state->op_ctx->kcm_data->db, ++ state->op_ctx->client, ++ uuid); ++ if (subreq == NULL) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_op_initialize_cc_delete_done, req); ++ return; ++ } ++ ++ kcm_op_initialize_create_step(req); ++} ++ ++static void kcm_op_initialize_cc_delete_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ errno_t ret; ++ ++ ret = kcm_ccdb_delete_cc_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot delete ccache from the db %d: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ kcm_op_initialize_create_step(req); ++} ++ ++static void kcm_op_initialize_create_step(struct tevent_req *req) ++{ ++ struct tevent_req *subreq; ++ struct kcm_op_initialize_state *state = tevent_req_data(req, ++ struct kcm_op_initialize_state); ++ errno_t ret; ++ ++ ret = kcm_cc_new(state->op_ctx, ++ state->op_ctx->kcm_data->k5c, ++ state->op_ctx->client, ++ state->name, ++ state->princ, ++ &state->new_cc); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot create new ccache %d: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ subreq = kcm_ccdb_create_cc_send(state, ++ state->ev, ++ state->op_ctx->kcm_data->db, ++ state->op_ctx->client, ++ state->new_cc); ++ if (subreq == NULL) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_op_initialize_cc_create_done, req); ++} ++ ++static void kcm_op_initialize_cc_create_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_initialize_state *state = tevent_req_data(req, ++ struct kcm_op_initialize_state); ++ errno_t ret; ++ ++ ret = kcm_ccdb_create_cc_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot add ccache to db %d: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ /* If there was no previous default ccache, set this one as default */ ++ subreq = kcm_ccdb_get_default_send(state, state->ev, ++ state->op_ctx->kcm_data->db, ++ state->op_ctx->client); ++ if (subreq == NULL) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_op_initialize_got_default, req); ++} ++ ++static void kcm_op_initialize_got_default(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_initialize_state *state = tevent_req_data(req, ++ struct kcm_op_initialize_state); ++ errno_t ret; ++ uuid_t dfl_uuid; ++ uuid_t old_dfl_uuid; ++ ++ ret = kcm_ccdb_get_default_recv(subreq, &old_dfl_uuid); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get default ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (uuid_is_null(old_dfl_uuid) == false) { ++ /* If there was a previous default ccache, switch to the initialized ++ * one by default ++ */ ++ ret = kcm_cc_get_uuid(state->new_cc, dfl_uuid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get new ccache UUID [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return; ++ } ++ ++ subreq = kcm_ccdb_set_default_send(state, ++ state->ev, ++ state->op_ctx->kcm_data->db, ++ state->op_ctx->client, ++ dfl_uuid); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_op_initialize_set_default_done, req); ++ return; ++ } ++ ++ /* ENOENT, done */ ++ state->op_ret = EOK; ++ tevent_req_done(req); ++} ++ ++static void kcm_op_initialize_set_default_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_initialize_state *state = tevent_req_data(req, ++ struct kcm_op_initialize_state); ++ errno_t ret; ++ ++ ret = kcm_ccdb_set_default_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot set default ccache %d: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->op_ret = EOK; ++ tevent_req_done(req); ++} ++ ++static errno_t kcm_op_initialize_recv(struct tevent_req *req, ++ uint32_t *_op_ret) ++{ ++ KCM_OP_RET_FROM_TYPE(req, struct kcm_op_initialize_state, _op_ret); ++} ++ ++/* (name) -> () */ ++static void kcm_op_destroy_getbyname_done(struct tevent_req *subreq); ++static void kcm_op_destroy_delete_done(struct tevent_req *subreq); ++ ++static struct tevent_req *kcm_op_destroy_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_op_common_state *state = NULL; ++ errno_t ret; ++ const char *name; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ state->ev = ev; ++ ++ ret = sss_iobuf_read_stringz(op_ctx->input, &name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot unmarshall input name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ DEBUG(SSSDBG_TRACE_LIBS, "Destroying credentials of %s\n", name); ++ ++ subreq = kcm_ccdb_uuid_by_name_send(state, ev, ++ op_ctx->kcm_data->db, ++ op_ctx->client, ++ name); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_op_destroy_getbyname_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_op_destroy_getbyname_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_common_state *state = tevent_req_data(req, ++ struct kcm_op_common_state); ++ uuid_t uuid; ++ ++ ret = kcm_ccdb_uuid_by_name_recv(subreq, state, uuid); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get matching ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ subreq = kcm_ccdb_delete_cc_send(state, ++ state->ev, ++ state->op_ctx->kcm_data->db, ++ state->op_ctx->client, ++ uuid); ++ if (subreq == NULL) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_op_destroy_delete_done, req); ++} ++ ++static void kcm_op_destroy_delete_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_common_state *state = tevent_req_data(req, ++ struct kcm_op_common_state); ++ ++ ret = kcm_ccdb_delete_cc_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot delete ccache from the db [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->op_ret = EOK; ++ tevent_req_done(req); ++} ++ ++/* (name, cred) -> () */ ++struct kcm_op_store_state { ++ uint32_t op_ret; ++ struct kcm_op_ctx *op_ctx; ++ struct tevent_context *ev; ++ ++ struct sss_iobuf *cred_blob; ++}; ++ ++static void kcm_op_store_getbyname_done(struct tevent_req *subreq); ++static void kcm_op_store_done(struct tevent_req *subreq); ++ ++static struct tevent_req *kcm_op_store_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_op_store_state *state = NULL; ++ errno_t ret; ++ const char *name; ++ size_t creds_len; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_store_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ state->ev = ev; ++ ++ ret = sss_iobuf_read_stringz(op_ctx->input, &name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot unmarshall input name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ DEBUG(SSSDBG_TRACE_LIBS, "Storing credentials for %s\n", name); ++ ++ creds_len = sss_iobuf_get_size(op_ctx->input) - strlen(name) -1; ++ if (creds_len > KCM_REPLY_MAX) { ++ /* Protects against underflows and in general adds sanity */ ++ ret = E2BIG; ++ goto immediate; ++ } ++ ++ state->cred_blob = sss_iobuf_init_empty(state, ++ creds_len, ++ creds_len); ++ if (state->cred_blob == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ ret = sss_iobuf_read(op_ctx->input, ++ creds_len, ++ sss_iobuf_get_data(state->cred_blob), ++ NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot unmarshall input cred blob [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ subreq = kcm_ccdb_uuid_by_name_send(state, ev, ++ op_ctx->kcm_data->db, ++ op_ctx->client, ++ name); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_op_store_getbyname_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_op_store_getbyname_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_store_state *state = tevent_req_data(req, ++ struct kcm_op_store_state); ++ uuid_t uuid; ++ ++ ret = kcm_ccdb_uuid_by_name_recv(subreq, state, uuid); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get ccache by name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ subreq = kcm_ccdb_store_cred_blob_send(state, state->ev, ++ state->op_ctx->kcm_data->db, ++ state->op_ctx->client, ++ uuid, ++ state->cred_blob); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_op_store_done, req); ++} ++ ++static void kcm_op_store_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_store_state *state = tevent_req_data(req, ++ struct kcm_op_store_state); ++ ++ ret = kcm_ccdb_store_cred_blob_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot store credentials [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->op_ret = EOK; ++ tevent_req_done(req); ++} ++ ++static errno_t kcm_op_store_recv(struct tevent_req *req, ++ uint32_t *_op_ret) ++{ ++ KCM_OP_RET_FROM_TYPE(req, struct kcm_op_store_state, _op_ret); ++} ++ ++/* (name) -> (princ) */ ++static void kcm_op_get_principal_getbyname_done(struct tevent_req *subreq); ++ ++static struct tevent_req *kcm_op_get_principal_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_op_common_state *state = NULL; ++ errno_t ret; ++ const char *name; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ ++ ret = sss_iobuf_read_stringz(op_ctx->input, &name); ++ if (ret != EOK) { ++ goto immediate; ++ } ++ DEBUG(SSSDBG_TRACE_LIBS, "Requested principal %s\n", name); ++ ++ subreq = kcm_ccdb_getbyname_send(state, ev, ++ op_ctx->kcm_data->db, ++ op_ctx->client, ++ name); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_op_get_principal_getbyname_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_op_get_principal_getbyname_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct kcm_ccache *cc; ++ krb5_principal princ; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_common_state *state = tevent_req_data(req, ++ struct kcm_op_common_state); ++ ++ ret = kcm_ccdb_getbyname_recv(subreq, state, &cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get ccache by name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (cc == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that name\n"); ++ state->op_ret = ERR_NO_MATCHING_CREDS; ++ tevent_req_done(req); ++ return; ++ } ++ ++ /* Marshall the principal to the reply */ ++ princ = kcm_cc_get_client_principal(cc); ++ if (princ == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Credentials with no principal?\n"); ++ tevent_req_error(req, EIO); ++ return; ++ } ++ ++ ret = sss_krb5_marshal_princ(princ, state->op_ctx->reply); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot marshall principal [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->op_ret = EOK; ++ tevent_req_done(req); ++} ++ ++/* (name) -> (uuid, ...) */ ++static void kcm_op_get_cred_uuid_getbyname_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++kcm_op_get_cred_uuid_list_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_op_common_state *state = NULL; ++ errno_t ret; ++ const char *name; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ ++ ret = sss_iobuf_read_stringz(op_ctx->input, &name); ++ if (ret != EOK) { ++ goto immediate; ++ } ++ ++ DEBUG(SSSDBG_TRACE_LIBS, "Returning UUID list for %s\n", name); ++ ++ subreq = kcm_ccdb_getbyname_send(state, ev, ++ op_ctx->kcm_data->db, ++ op_ctx->client, ++ name); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_op_get_cred_uuid_getbyname_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_op_get_cred_uuid_getbyname_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct kcm_ccache *cc; ++ struct kcm_cred *crd; ++ uuid_t uuid; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_common_state *state = tevent_req_data(req, ++ struct kcm_op_common_state); ++ ++ ret = kcm_ccdb_getbyname_recv(subreq, state, &cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get ccache by name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (cc == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that UUID\n"); ++ state->op_ret = ERR_NO_CREDS; ++ tevent_req_done(req); ++ return; ++ } ++ ++ for (crd = kcm_cc_get_cred(cc); ++ crd != NULL; ++ crd = kcm_cc_next_cred(crd)) { ++ ret = kcm_cred_get_uuid(crd, uuid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Credential has no UUID, skipping\n"); ++ continue; ++ } ++ ++ kcm_debug_uuid(uuid); ++ ++ ret = sss_iobuf_write_len(state->op_ctx->reply, ++ uuid, UUID_BYTES); ++ if (ret != EOK) { ++ char uuid_errbuf[UUID_STR_SIZE]; ++ uuid_parse(uuid_errbuf, uuid); ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot marshall UUID %s [%d]: %s\n", ++ uuid_errbuf, ret, sss_strerror(ret)); ++ continue; ++ } ++ } ++ state->op_ret = EOK; ++ tevent_req_done(req); ++} ++ ++/* (name, uuid) -> (cred) */ ++static void kcm_op_get_cred_by_uuid_getbyname_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++kcm_op_get_cred_by_uuid_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_op_common_state *state = NULL; ++ errno_t ret; ++ const char *name; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ ++ ret = sss_iobuf_read_stringz(op_ctx->input, &name); ++ if (ret != EOK) { ++ goto immediate; ++ } ++ DEBUG(SSSDBG_TRACE_LIBS, "Returning creds by UUID for %s\n", name); ++ ++ subreq = kcm_ccdb_getbyname_send(state, ev, ++ op_ctx->kcm_data->db, ++ op_ctx->client, ++ name); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_op_get_cred_by_uuid_getbyname_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_op_get_cred_by_uuid_getbyname_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_common_state *state = tevent_req_data(req, ++ struct kcm_op_common_state); ++ errno_t ret; ++ struct kcm_ccache *cc; ++ struct kcm_cred *crd; ++ uuid_t uuid_in; ++ uuid_t uuid; ++ struct sss_iobuf *cred_blob; ++ ++ ret = kcm_ccdb_getbyname_recv(subreq, state, &cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get ccache by name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (cc == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that name\n"); ++ state->op_ret = ERR_NO_MATCHING_CREDS; ++ tevent_req_done(req); ++ return; ++ } ++ ++ ret = sss_iobuf_read_len(state->op_ctx->input, ++ UUID_BYTES, uuid_in); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot read input UUID [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ for (crd = kcm_cc_get_cred(cc); ++ crd != NULL; ++ crd = kcm_cc_next_cred(crd)) { ++ ret = kcm_cred_get_uuid(crd, uuid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot get UUID from creds, skipping\n"); ++ continue; ++ } ++ ++ if (uuid_compare(uuid, uuid_in) == 0) { ++ break; ++ } ++ kcm_debug_uuid(uuid); ++ } ++ ++ if (crd == NULL) { ++ state->op_ret = ERR_KCM_CC_END; ++ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that UUID\n"); ++ tevent_req_done(req); ++ return; ++ } ++ ++ cred_blob = kcm_cred_get_creds(crd); ++ if (cred_blob == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Credentials lack the creds blob\n"); ++ state->op_ret = ERR_NO_CREDS; ++ tevent_req_done(req); ++ return; ++ } ++ ++ ret = sss_iobuf_write_len(state->op_ctx->reply, ++ sss_iobuf_get_data(cred_blob), ++ sss_iobuf_get_size(cred_blob)); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot write ccache blob [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->op_ret = EOK; ++ tevent_req_done(req); ++} ++ ++/* (name, flags, credtag) -> () */ ++/* FIXME */ ++static struct tevent_req * ++kcm_op_remove_cred_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct kcm_op_common_state *state = NULL; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ ++ state->op_ret = ERR_KCM_OP_NOT_IMPLEMENTED; ++ tevent_req_post(req, ev); ++ tevent_req_done(req); ++ return req; ++} ++ ++/* () -> (uuid, ...) */ ++static void kcm_op_get_cache_uuid_list_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++kcm_op_get_cache_uuid_list_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_op_common_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ ++ DEBUG(SSSDBG_TRACE_LIBS, "Returning full UUID list\n"); ++ ++ subreq = kcm_ccdb_list_send(state, ev, ++ op_ctx->kcm_data->db, ++ op_ctx->client); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_op_get_cache_uuid_list_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_op_get_cache_uuid_list_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_common_state *state = tevent_req_data(req, ++ struct kcm_op_common_state); ++ errno_t ret; ++ uuid_t *uuid_list; ++ ++ ret = kcm_ccdb_list_recv(subreq, state, &uuid_list); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot list the ccache DB [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (uuid_list == NULL || uuid_list[0] == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Nothing to list\n"); ++ state->op_ret = ERR_NO_MATCHING_CREDS; ++ tevent_req_done(req); ++ return; ++ } ++ ++ for (int i = 0; ++ uuid_is_null(uuid_list[i]) == false; ++ i++) { ++ kcm_debug_uuid(uuid_list[i]); ++ ++ ret = sss_iobuf_write_len(state->op_ctx->reply, ++ uuid_list[i], ++ UUID_BYTES); ++ if (ret != EOK) { ++ char uuid_errbuf[UUID_STR_SIZE]; ++ uuid_parse(uuid_errbuf, uuid_list[i]); ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot marshall UUID %s [%d]: %s\n", ++ uuid_errbuf, ret, sss_strerror(ret)); ++ tevent_req_done(req); ++ return; ++ } ++ } ++ ++ tevent_req_done(req); ++} ++ ++/* (uuid) -> (name) */ ++static void kcm_op_get_cache_by_uuid_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++kcm_op_get_cache_by_uuid_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_op_common_state *state = NULL; ++ errno_t ret; ++ uuid_t uuid_in; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ ++ DEBUG(SSSDBG_TRACE_LIBS, "Retrieving cache by UUID\n"); ++ ++ ret = sss_iobuf_read_len(op_ctx->input, ++ UUID_BYTES, uuid_in); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot read input UUID [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ kcm_debug_uuid(uuid_in); ++ ++ subreq = kcm_ccdb_getbyuuid_send(state, ev, ++ op_ctx->kcm_data->db, ++ op_ctx->client, ++ uuid_in); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_op_get_cache_by_uuid_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_op_get_cache_by_uuid_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct kcm_ccache *cc; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_common_state *state = tevent_req_data(req, ++ struct kcm_op_common_state); ++ const char *name; ++ ++ ret = kcm_ccdb_getbyuuid_recv(subreq, state, &cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get ccahe by UUID [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (cc == NULL) { ++ state->op_ret = ERR_KCM_CC_END; ++ tevent_req_done(req); ++ return; ++ } ++ ++ name = kcm_cc_get_name(cc); ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Found %s by UUID\n", name); ++ ++ ret = sss_iobuf_write_stringz(state->op_ctx->reply, ++ name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot write output name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->op_ret = EOK; ++ tevent_req_done(req); ++} ++ ++/* () -> (name) */ ++struct kcm_op_get_default_ccache_state { ++ uint32_t op_ret; ++ struct kcm_op_ctx *op_ctx; ++ struct tevent_context *ev; ++ ++ const char *name; ++}; ++ ++static void kcm_op_get_get_default_done(struct tevent_req *subreq); ++static void kcm_op_get_default_ccache_byuuid_done(struct tevent_req *subreq); ++static void kcm_op_get_default_ccache_list_done(struct tevent_req *subreq); ++static errno_t ++kcm_op_get_default_ccache_reply_step(struct kcm_op_get_default_ccache_state *state); ++ ++static struct tevent_req * ++kcm_op_get_default_ccache_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_op_get_default_ccache_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct kcm_op_get_default_ccache_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ state->ev = ev; ++ ++ DEBUG(SSSDBG_TRACE_LIBS, "Getting client's default ccache\n"); ++ ++ subreq = kcm_ccdb_get_default_send(state, ev, ++ state->op_ctx->kcm_data->db, ++ state->op_ctx->client); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_op_get_get_default_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_op_get_get_default_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); ++ struct kcm_op_get_default_ccache_state *state = tevent_req_data(req, ++ struct kcm_op_get_default_ccache_state); ++ errno_t ret; ++ uuid_t dfl_uuid; ++ ++ ret = kcm_ccdb_get_default_recv(subreq, &dfl_uuid); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get default ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (uuid_is_null(dfl_uuid) == true) { ++ /* No cache marked as default -- get an existing ccache for ID ++ * and treat the default as simply the first one ++ */ ++ subreq = kcm_ccdb_list_send(state, state->ev, ++ state->op_ctx->kcm_data->db, ++ state->op_ctx->client); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_op_get_default_ccache_list_done, req); ++ return; ++ } ++ ++ /* Existing default */ ++ subreq = kcm_ccdb_name_by_uuid_send(state, ++ state->ev, ++ state->op_ctx->kcm_data->db, ++ state->op_ctx->client, ++ dfl_uuid); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_op_get_default_ccache_byuuid_done, req); ++ return; ++} ++ ++static void kcm_op_get_default_ccache_byuuid_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); ++ struct kcm_op_get_default_ccache_state *state = tevent_req_data(req, ++ struct kcm_op_get_default_ccache_state); ++ errno_t ret; ++ ++ ret = kcm_ccdb_name_by_uuid_recv(subreq, state, &state->name); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get ccahe by UUID [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ ret = kcm_op_get_default_ccache_reply_step(state); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++static void kcm_op_get_default_ccache_list_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); ++ struct kcm_op_get_default_ccache_state *state = tevent_req_data(req, ++ struct kcm_op_get_default_ccache_state); ++ errno_t ret; ++ uuid_t *uuid_list; ++ ++ ret = kcm_ccdb_list_recv(subreq, state, &uuid_list); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot list ccaches [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (uuid_list == NULL || uuid_is_null(uuid_list[0])) { ++ /* No cache at all, just send back a reply */ ++ ret = kcm_op_get_default_ccache_reply_step(state); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++ return; ++ } ++ ++ /* Otherwise resolve the first cache and use it as a default */ ++ subreq = kcm_ccdb_name_by_uuid_send(state, ++ state->ev, ++ state->op_ctx->kcm_data->db, ++ state->op_ctx->client, ++ uuid_list[0]); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_op_get_default_ccache_byuuid_done, req); ++ return; ++} ++ ++static errno_t ++kcm_op_get_default_ccache_reply_step(struct kcm_op_get_default_ccache_state *state) ++{ ++ errno_t ret; ++ ++ if (state->name == NULL) { ++ state->name = talloc_asprintf(state, ++ "%"SPRIuid, ++ cli_creds_get_uid(state->op_ctx->client)); ++ if (state->name == NULL) { ++ return ENOMEM; ++ } ++ } ++ DEBUG(SSSDBG_TRACE_INTERNAL, "The default ccache is %s\n", state->name); ++ ++ ret = sss_iobuf_write_stringz(state->op_ctx->reply, state->name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot write output name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ return EOK; ++} ++ ++static errno_t kcm_op_get_default_ccache_recv(struct tevent_req *req, ++ uint32_t *_op_ret) ++{ ++ KCM_OP_RET_FROM_TYPE(req, struct kcm_op_get_default_ccache_state, _op_ret); ++} ++ ++/* (name) -> () */ ++static void kcm_op_set_default_ccache_getbyname_done(struct tevent_req *subreq); ++static void kcm_op_set_default_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++kcm_op_set_default_ccache_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_op_common_state *state = NULL; ++ errno_t ret; ++ const char *name; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ state->ev = ev; ++ ++ ret = sss_iobuf_read_stringz(op_ctx->input, &name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot read input name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ DEBUG(SSSDBG_TRACE_LIBS, "Setting default ccache %s\n", name); ++ ++ subreq = kcm_ccdb_uuid_by_name_send(state, ev, ++ op_ctx->kcm_data->db, ++ op_ctx->client, ++ name); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_op_set_default_ccache_getbyname_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_op_set_default_ccache_getbyname_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_common_state *state = tevent_req_data(req, ++ struct kcm_op_common_state); ++ uuid_t dfl_uuid; ++ ++ ret = kcm_ccdb_uuid_by_name_recv(subreq, state, dfl_uuid); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get ccache by name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ subreq = kcm_ccdb_set_default_send(state, ++ state->ev, ++ state->op_ctx->kcm_data->db, ++ state->op_ctx->client, ++ dfl_uuid); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_op_set_default_done, req); ++ return; ++} ++ ++static void kcm_op_set_default_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_common_state *state = tevent_req_data(req, ++ struct kcm_op_common_state); ++ ++ ret = kcm_ccdb_set_default_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot set default ccache %d: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->op_ret = EOK; ++ tevent_req_done(req); ++} ++ ++/* (name) -> (offset) */ ++static void kcm_op_get_kdc_offset_getbyname_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++kcm_op_get_kdc_offset_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_op_common_state *state = NULL; ++ errno_t ret; ++ const char *name; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ ++ ret = sss_iobuf_read_stringz(op_ctx->input, &name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot read input name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ DEBUG(SSSDBG_TRACE_LIBS, "Requested offset for principal %s\n", name); ++ ++ subreq = kcm_ccdb_getbyname_send(state, ev, ++ op_ctx->kcm_data->db, ++ op_ctx->client, ++ name); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_op_get_kdc_offset_getbyname_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_op_get_kdc_offset_getbyname_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct kcm_ccache *cc; ++ int32_t offset; ++ int32_t offset_be; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_common_state *state = tevent_req_data(req, ++ struct kcm_op_common_state); ++ ++ ret = kcm_ccdb_getbyname_recv(subreq, state, &cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get matching ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (cc == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "No matching credentials\n"); ++ state->op_ret = ERR_NO_MATCHING_CREDS; ++ tevent_req_done(req); ++ return; ++ } ++ ++ offset = kcm_cc_get_offset(cc); ++ DEBUG(SSSDBG_TRACE_LIBS, "KDC offset: %"PRIu32"\n", offset); ++ ++ offset_be = htobe32(offset); ++ ret = sss_iobuf_write_int32(state->op_ctx->reply, offset_be); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot write KDC offset [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->op_ret = EOK; ++ tevent_req_done(req); ++} ++ ++/* (name, offset) -> () */ ++/* () -> (name) */ ++struct kcm_op_set_kdc_offset_state { ++ uint32_t op_ret; ++ struct kcm_op_ctx *op_ctx; ++ struct tevent_context *ev; ++}; ++ ++static void kcm_op_set_kdc_offset_getbyname_done(struct tevent_req *subreq); ++static void kcm_op_set_kdc_offset_mod_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++kcm_op_set_kdc_offset_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_op_ctx *op_ctx) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct kcm_op_set_kdc_offset_state *state = NULL; ++ errno_t ret; ++ const char *name; ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_set_kdc_offset_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->op_ctx = op_ctx; ++ state->ev = ev; ++ ++ ret = sss_iobuf_read_stringz(op_ctx->input, &name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot read input name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ DEBUG(SSSDBG_TRACE_LIBS, "Setting offset for principal %s\n", name); ++ ++ subreq = kcm_ccdb_uuid_by_name_send(state, ev, ++ op_ctx->kcm_data->db, ++ op_ctx->client, ++ name); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, kcm_op_set_kdc_offset_getbyname_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_op_set_kdc_offset_getbyname_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct kcm_mod_ctx *mod_ctx; ++ int32_t offset_be; ++ uuid_t uuid; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_set_kdc_offset_state *state = tevent_req_data(req, ++ struct kcm_op_set_kdc_offset_state); ++ ++ ret = kcm_ccdb_uuid_by_name_recv(subreq, state, uuid); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get matching ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ ret = sss_iobuf_read_int32(state->op_ctx->input, &offset_be); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot read KDC offset [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ mod_ctx = talloc(state, struct kcm_mod_ctx); ++ if (mod_ctx == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ kcm_mod_ctx_clear(mod_ctx); ++ mod_ctx->kdc_offset = be32toh(offset_be); ++ ++ subreq = kcm_ccdb_mod_cc_send(state, ++ state->ev, ++ state->op_ctx->kcm_data->db, ++ state->op_ctx->client, ++ uuid, ++ mod_ctx); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, kcm_op_set_kdc_offset_mod_done, req); ++} ++ ++static void kcm_op_set_kdc_offset_mod_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct kcm_op_set_kdc_offset_state *state = tevent_req_data(req, ++ struct kcm_op_set_kdc_offset_state); ++ ++ ret = kcm_ccdb_mod_cc_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot modify ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->op_ret = EOK; ++ tevent_req_done(req); ++} ++ ++static errno_t kcm_op_set_kdc_offset_recv(struct tevent_req *req, ++ uint32_t *_op_ret) ++{ ++ KCM_OP_RET_FROM_TYPE(req, struct kcm_op_set_kdc_offset_state, _op_ret); ++} ++ ++static struct kcm_op kcm_optable[] = { ++ { "NOOP", NULL, NULL }, ++ { "GET_NAME", NULL, NULL }, ++ { "RESOLVE", NULL, NULL }, ++ { "GEN_NEW", kcm_op_gen_new_send, NULL }, ++ { "INITIALIZE", kcm_op_initialize_send, kcm_op_initialize_recv }, ++ { "DESTROY", kcm_op_destroy_send, NULL }, ++ { "STORE", kcm_op_store_send, kcm_op_store_recv }, ++ { "RETRIEVE", NULL, NULL }, ++ { "GET_PRINCIPAL", kcm_op_get_principal_send, NULL }, ++ { "GET_CRED_UUID_LIST", kcm_op_get_cred_uuid_list_send, NULL }, ++ { "GET_CRED_BY_UUID", kcm_op_get_cred_by_uuid_send, NULL }, ++ { "REMOVE_CRED", kcm_op_remove_cred_send, NULL }, ++ { "SET_FLAGS", NULL, NULL }, ++ { "CHOWN", NULL, NULL }, ++ { "CHMOD", NULL, NULL }, ++ { "GET_INITIAL_TICKET", NULL, NULL }, ++ { "GET_TICKET", NULL, NULL }, ++ { "MOVE_CACHE", NULL, NULL }, ++ { "GET_CACHE_UUID_LIST", kcm_op_get_cache_uuid_list_send, NULL }, ++ { "GET_CACHE_BY_UUID", kcm_op_get_cache_by_uuid_send, NULL }, ++ { "GET_DEFAULT_CACHE", kcm_op_get_default_ccache_send, kcm_op_get_default_ccache_recv }, ++ { "SET_DEFAULT_CACHE", kcm_op_set_default_ccache_send, NULL }, ++ { "GET_KDC_OFFSET", kcm_op_get_kdc_offset_send, NULL }, ++ { "SET_KDC_OFFSET", kcm_op_set_kdc_offset_send, kcm_op_set_kdc_offset_recv }, ++ { "ADD_NTLM_CRED", NULL, NULL }, ++ { "HAVE_NTLM_CRED", NULL, NULL }, ++ { "DEL_NTLM_CRED", NULL, NULL }, ++ { "DO_NTLM_AUTH", NULL, NULL }, ++ { "GET_NTLM_USER_LIST", NULL, NULL }, ++ ++ { NULL, NULL, NULL } ++}; ++ ++struct kcm_op *kcm_get_opt(uint16_t opcode) ++{ ++ struct kcm_op *op; ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, ++ "The client requested operation %"PRIu16"\n", opcode); ++ ++ if (opcode >= KCM_OP_SENTINEL) { ++ return NULL; ++ } ++ ++ op = &kcm_optable[opcode]; ++ if (op->fn_recv == NULL) { ++ op->fn_recv = kcm_op_common_recv; ++ } ++ return op; ++} ++ ++const char *kcm_opt_name(struct kcm_op *op) ++{ ++ if (op == NULL || op->name == NULL) { ++ return "Unknown operation"; ++ } ++ ++ return op->name; ++} +diff --git a/src/responder/kcm/kcmsrv_ops.h b/src/responder/kcm/kcmsrv_ops.h +new file mode 100644 +index 0000000000000000000000000000000000000000..8e6feaf56a10b73c8b6375aea9ef26c392b5b492 +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_ops.h +@@ -0,0 +1,45 @@ ++/* ++ SSSD ++ ++ KCM Server - private header file ++ ++ Copyright (C) Red Hat, 2016 ++ ++ 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 . ++*/ ++ ++#ifndef __KCMSRV_OPS_H__ ++#define __KCMSRV_OPS_H__ ++ ++#include "config.h" ++ ++#include ++#include "util/sss_iobuf.h" ++#include "responder/kcm/kcmsrv_pvt.h" ++ ++struct kcm_op; ++struct kcm_op *kcm_get_opt(uint16_t opcode); ++const char *kcm_opt_name(struct kcm_op *op); ++ ++struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_resp_ctx *kcm_data, ++ struct cli_creds *client, ++ struct kcm_data *input, ++ struct kcm_op *op); ++errno_t kcm_cmd_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct sss_iobuf **_reply); ++ ++#endif /* __KCMSRV_OPS_H__ */ +-- +2.9.3 + diff --git a/SOURCES/0027-IPA-enable-enterprise-principals-if-server-supports-.patch b/SOURCES/0027-IPA-enable-enterprise-principals-if-server-supports-.patch deleted file mode 100644 index 8589359..0000000 --- a/SOURCES/0027-IPA-enable-enterprise-principals-if-server-supports-.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 6b5b0732b7f4fab195a6205e1046a8402f5d3040 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 1 Jul 2016 18:18:14 +0200 -Subject: [PATCH 27/27] IPA: enable enterprise principals if server supports - them - -If there are alternative UPN suffixes found on the server we can safely -assume that the IPA server supports enterprise principals. - -Resolves https://fedorahosted.org/sssd/ticket/3018 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 70673115c03c37ddc64c951b53d92df9d3310762) ---- - src/man/sssd-krb5.5.xml | 6 +++ - src/providers/ipa/ipa_subdomains.c | 86 ++++++++++++++++++++++++++++++++++++++ - 2 files changed, 92 insertions(+) - -diff --git a/src/man/sssd-krb5.5.xml b/src/man/sssd-krb5.5.xml -index e7fdd19e07db99314a9491faff9974d7d5e617e6..60b7dfb508c0d054a421fd46957574f52e0333d7 100644 ---- a/src/man/sssd-krb5.5.xml -+++ b/src/man/sssd-krb5.5.xml -@@ -513,6 +513,12 @@ - - Default: false (AD provider: true) - -+ -+ The IPA provider will set to option to 'true' if it -+ detects that the server is capable of handling -+ enterprise principals and the option is not set -+ explicitly in the config file. -+ - - - -diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c -index 925b1d8b133eb56724ee4f9133a2487090982a8b..4e5bceb8c761bf4476928168d620baf2beb62ad5 100644 ---- a/src/providers/ipa/ipa_subdomains.c -+++ b/src/providers/ipa/ipa_subdomains.c -@@ -28,6 +28,7 @@ - #include "providers/ipa/ipa_subdomains.h" - #include "providers/ipa/ipa_common.h" - #include "providers/ipa/ipa_id.h" -+#include "providers/ipa/ipa_opts.h" - - #include - -@@ -999,6 +1000,84 @@ immediately: - return req; - } - -+static errno_t ipa_enable_enterprise_principals(struct be_ctx *be_ctx) -+{ -+ int ret; -+ struct sss_domain_info *d; -+ TALLOC_CTX *tmp_ctx; -+ char **vals = NULL; -+ struct dp_module *auth; -+ struct krb5_ctx *krb5_auth_ctx; -+ -+ d = get_domains_head(be_ctx->domain); -+ -+ while (d != NULL) { -+ DEBUG(SSSDBG_TRACE_ALL, "checking [%s].\n", d->name); -+ if (d->upn_suffixes != NULL) { -+ break; -+ } -+ d = get_next_domain(d, SSS_GND_DESCEND); -+ } -+ -+ if (d == NULL) { -+ DEBUG(SSSDBG_TRACE_ALL, -+ "No UPN suffixes found, " -+ "no need to enable enterprise principals.\n"); -+ return EOK; -+ } -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); -+ return ENOMEM; -+ } -+ -+ ret = confdb_get_param(be_ctx->cdb, tmp_ctx, be_ctx->conf_path, -+ ipa_def_krb5_opts[KRB5_USE_ENTERPRISE_PRINCIPAL].opt_name, -+ &vals); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "confdb_get_param failed.\n"); -+ goto done; -+ } -+ -+ if (vals[0]) { -+ DEBUG(SSSDBG_CONF_SETTINGS, -+ "Parameter [%s] set in config file and will not be changed.\n", -+ ipa_def_krb5_opts[KRB5_USE_ENTERPRISE_PRINCIPAL].opt_name); -+ return EOK; -+ } -+ -+ auth = dp_target_module(be_ctx->provider, DPT_AUTH); -+ if (auth == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "Unable to find auth proivder.\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ krb5_auth_ctx = ipa_init_get_krb5_auth_ctx(dp_get_module_data(auth)); -+ if (krb5_auth_ctx == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "Unable to find auth proivder data.\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ ret = dp_opt_set_bool(krb5_auth_ctx->opts, -+ KRB5_USE_ENTERPRISE_PRINCIPAL, true); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "dp_opt_set_bool failed.\n"); -+ goto done; -+ } -+ -+ DEBUG(SSSDBG_CONF_SETTINGS, "Enterprise principals enabled.\n"); -+ -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ -+ return ret; -+} -+ - static void ipa_subdomains_slave_search_done(struct tevent_req *subreq) - { - struct ipa_subdomains_slave_state *state; -@@ -1037,6 +1116,13 @@ static void ipa_subdomains_slave_search_done(struct tevent_req *subreq) - goto done; - } - -+ ret = ipa_enable_enterprise_principals(state->sd_ctx->be_ctx); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "ipa_enable_enterprise_principals failed. " -+ "Enterprise principals might not work as " -+ "expected.\n"); -+ } -+ - if (state->sd_ctx->ipa_id_ctx->server_mode == NULL) { - ret = EOK; - goto done; --- -2.4.11 - diff --git a/SOURCES/0027-MAN-Add-a-manual-page-for-sssd-kcm.patch b/SOURCES/0027-MAN-Add-a-manual-page-for-sssd-kcm.patch new file mode 100644 index 0000000..39a1629 --- /dev/null +++ b/SOURCES/0027-MAN-Add-a-manual-page-for-sssd-kcm.patch @@ -0,0 +1,278 @@ +From 14d42e26c2050c1941874e83761fae69585ddc27 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 8 Mar 2017 17:46:09 +0100 +Subject: [PATCH 27/36] MAN: Add a manual page for sssd-kcm +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + contrib/sssd.spec.in | 1 + + src/man/Makefile.am | 9 ++- + src/man/po/po4a.cfg | 1 + + src/man/sssd-kcm.8.xml | 193 +++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 203 insertions(+), 1 deletion(-) + create mode 100644 src/man/sssd-kcm.8.xml + +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index 52d33b4de281dc1d91a9027ac1c8c878e66fb396..1d4d020415ee28292bb4d88c78de205465d812f1 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -1206,6 +1206,7 @@ done + %config(noreplace) %{_sysconfdir}/krb5.conf.d/kcm_default_ccache + %{_unitdir}/sssd-kcm.socket + %{_unitdir}/sssd-kcm.service ++%{_mandir}/man8/sssd-kcm.8* + %endif + + %pre common +diff --git a/src/man/Makefile.am b/src/man/Makefile.am +index 142d6e2743f814294e3d92c8342070b8230bb3e5..3a063614f085691652db32d76315375466e0d3de 100644 +--- a/src/man/Makefile.am ++++ b/src/man/Makefile.am +@@ -27,6 +27,9 @@ endif + if BUILD_SECRETS + SEC_CONDS = ;with_secrets + endif ++if BUILD_SECRETS ++KCM_CONDS = ;with_kcm ++endif + if GPO_DEFAULT_ENFORCING + GPO_CONDS = ;gpo_default_enforcing + else +@@ -40,7 +43,7 @@ FILES_CONDS = ;enable_files_domain + else + FILES_CONDS = ;no_enable_files_domain + endif +-CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(PAC_RESPONDER_CONDS)$(IFP_CONDS)$(GPO_CONDS)$(SEC_CONDS)$(SYSTEMD_CONDS)$(FILES_CONDS) ++CONDS = with_false$(SUDO_CONDS)$(AUTOFS_CONDS)$(SSH_CONDS)$(PAC_RESPONDER_CONDS)$(IFP_CONDS)$(GPO_CONDS)$(SEC_CONDS)$(SYSTEMD_CONDS)$(FILES_CONDS)$(KCM_CONDS) + + + #Special Rules: +@@ -85,6 +88,10 @@ if BUILD_SECRETS + man_MANS += sssd-secrets.5 + endif + ++if BUILD_KCM ++man_MANS += sssd-kcm.8 ++endif ++ + if BUILD_NFS_IDMAP + man_MANS += sss_rpcidmapd.5 + endif +diff --git a/src/man/po/po4a.cfg b/src/man/po/po4a.cfg +index d1f6ac39f841c61ae3d2393fb3402dc21b9cbd69..a02f97e777fa76615e4d5cbcfc788956706d8cd0 100644 +--- a/src/man/po/po4a.cfg ++++ b/src/man/po/po4a.cfg +@@ -31,6 +31,7 @@ + [type:docbook] sssctl.8.xml $lang:$(builddir)/$lang/sssctl.8.xml + [type:docbook] sssd-files.5.xml $lang:$(builddir)/$lang/sssd-files.5.xml + [type:docbook] sssd-secrets.5.xml $lang:$(builddir)/$lang/sssd-secrets.5.xml ++[type:docbook] sssd-kcm.8.xml $lang:$(builddir)/$lang/sssd-kcm.8.xml + [type:docbook] include/service_discovery.xml $lang:$(builddir)/$lang/include/service_discovery.xml opt:"-k 0" + [type:docbook] include/upstream.xml $lang:$(builddir)/$lang/include/upstream.xml opt:"-k 0" + [type:docbook] include/failover.xml $lang:$(builddir)/$lang/include/failover.xml opt:"-k 0" +diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml +new file mode 100644 +index 0000000000000000000000000000000000000000..5dc93838e48723bdb470c0a9c8575bd17c7593e8 +--- /dev/null ++++ b/src/man/sssd-kcm.8.xml +@@ -0,0 +1,193 @@ ++ ++ ++ ++SSSD Manual pages ++ ++ ++ ++ ++ sssd-kcm ++ 8 ++ File Formats and Conventions ++ ++ ++ ++ sssd-kcm ++ SSSD Kerberos Cache Manager ++ ++ ++ ++ DESCRIPTION ++ ++ This manual page describes the configuration of the SSSD Kerberos ++ Cache Manager (KCM). KCM is a process that stores, tracks and ++ manages Kerberos credential caches. It originates in the Heimdal ++ Kerberos project, although the MIT Kerberos library also provides ++ client side (more details on that below) support for the KCM ++ credential cache. ++ ++ ++ In a setup where Kerberos caches are managed by KCM, the ++ Kerberos library (typically used through an application, like ++ e.g., ++ ++ kinit1 ++ , ++ is a "KCM client" and the KCM daemon ++ is being referred to as a "KCM server". The client ++ and server communicate over a UNIX socket. ++ ++ ++ The KCM server keeps track of each credential caches's owner and ++ performs access check control based on the UID and GID of the ++ KCM client. The root user has access to all credential caches. ++ ++ ++ The KCM credential cache has several interesting properties: ++ ++ ++ ++ since the process runs in userspace, it is subject to UID namespacing, ulike the kernel keyring ++ ++ ++ ++ ++ unlike the kernel keyring-based cache, which is shared between all containers, the KCM server is a separate process whose entry point is a UNIX socket ++ ++ ++ ++ ++ the SSSD implementation stores the ccaches in the SSSD ++ ++ sssd-secrets5 ++ ++ secrets store, allowing the ccaches to survive KCM server restarts or machine reboots. ++ ++ ++ ++ This allows the system to use a collection-aware credential ++ cache, yet share the credential cache between some or no ++ containers by bind-mounting the socket. ++ ++ ++ ++ ++ USING THE KCM CREDENTIAL CACHE ++ ++ In order to use KCM credential cache, it must be selected as the default ++ credential type in ++ ++ krb5.conf5 ++ , ++ The credentials cache name must be only KCM: ++ without any template expansions. For example: ++ ++[libdefaults] ++ default_ccache_name = KCM: ++ ++ ++ ++ Next, make sure the Kerberos client libraries and the KCM server must agree ++ on the UNIX socket path. By default, both use the same path ++ /var/run/.heim_org.h5l.kcm-socket. To configure ++ the Kerberos library, change its kcm_socket option which ++ is described in the ++ ++ krb5.conf5 ++ ++ manual page. ++ ++ ++ Finally, make sure the SSSD KCM server can be contacted. ++ The KCM service is typically socket-activated by ++ ++ systemd ++ 1 ++ . ++ Unlike ++ other SSSD services, it cannot be started by adding the ++ kcm string to the service ++ directive. ++ ++systemctl start sssd-kcm.socket ++systemctl enable sssd-kcm.socket ++systemctl enable sssd-kcm.service ++ ++ Please note your distribution may already configure the units ++ for you. ++ ++ ++ ++ ++ THE CREDENTIAL CACHE STORAGE ++ ++ The credential caches are stored in the SSSD secrets service (see ++ ++ sssd-secrets5 ++ ++ for more details). Therefore it is important that also the sssd-secrets ++ service is enabled and its socket is started: ++ ++systemctl start sssd-secrets.socket ++systemctl enable sssd-secrets.socket ++systemctl enable sssd-secrets.service ++ ++ Your distribution should already set the dependencies between the services. ++ ++ ++ ++ ++ CONFIGURATION OPTIONS ++ ++ The KCM service is configured in the kcm ++ section of the sssd.conf file. Please note that currently, ++ is it not sufficient to restart the sssd-kcm service, because ++ the sssd configuration is only parsed and read to an internal ++ configuration database by the sssd service. Therefore you ++ must restart the sssd service if you change anything in the ++ kcm section of sssd.conf. ++ For a detailed syntax reference, refer to the FILE FORMAT section of the ++ ++ sssd.conf ++ 5 ++ manual page. ++ ++ ++ The generic SSSD service options such as ++ debug_level or fd_limit are ++ accepted by the kcm service. Please refer to the ++ ++ sssd.conf ++ 5 ++ manual page for a complete list. In addition, ++ there are some KCM-specific options as well. ++ ++ ++ ++ socket_path (string) ++ ++ ++ The socket the KCM service will listen on. ++ ++ ++ Default: /var/run/.heim_org.h5l.kcm-socket ++ ++ ++ ++ ++ ++ ++ ++ SEE ALSO ++ ++ ++ sssd8 ++ , ++ ++ sssd.conf5 ++ , ++ ++ ++ ++ +-- +2.9.3 + diff --git a/SOURCES/0028-TESTS-Add-integration-tests-for-the-KCM-responder.patch b/SOURCES/0028-TESTS-Add-integration-tests-for-the-KCM-responder.patch new file mode 100644 index 0000000..776bf94 --- /dev/null +++ b/SOURCES/0028-TESTS-Add-integration-tests-for-the-KCM-responder.patch @@ -0,0 +1,799 @@ +From ad820beebae89c886f1ba4f0d2ddac4ca36857b7 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 13 Dec 2016 17:17:16 +0100 +Subject: [PATCH 28/36] TESTS: Add integration tests for the KCM responder +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +Reviewed-by: Lukáš Slebodník +--- + contrib/ci/configure.sh | 7 + + contrib/ci/deps.sh | 6 + + src/tests/intg/Makefile.am | 4 + + src/tests/intg/kdc.py | 175 +++++++++++++++++++++ + src/tests/intg/krb5utils.py | 156 +++++++++++++++++++ + src/tests/intg/test_kcm.py | 361 ++++++++++++++++++++++++++++++++++++++++++++ + 6 files changed, 709 insertions(+) + create mode 100644 src/tests/intg/kdc.py + create mode 100644 src/tests/intg/krb5utils.py + create mode 100644 src/tests/intg/test_kcm.py + +diff --git a/contrib/ci/configure.sh b/contrib/ci/configure.sh +index 8e779cfe634a7555e0e8e3b52f42c07e62980fbc..7590743c2aa5fe31bcdf1a3e92a3f482dbec699b 100644 +--- a/contrib/ci/configure.sh ++++ b/contrib/ci/configure.sh +@@ -38,6 +38,13 @@ if [[ "$DISTRO_BRANCH" == -redhat-redhatenterprise*-6.*- || + "--disable-cifs-idmap-plugin" + "--with-syslog=syslog" + "--without-python3-bindings" ++ "--without-kcm" ++ ) ++fi ++ ++if [[ "$DISTRO_BRANCH" == -redhat-fedora-2[0-2]* ]]; then ++ CONFIGURE_ARG_LIST+=( ++ "--without-kcm" + ) + fi + +diff --git a/contrib/ci/deps.sh b/contrib/ci/deps.sh +index c525e62e8c1d5b9fa042dee4ad03790dbceba242..4467e117c3a896a7f01ef7cb9e94fe28c2ea2838 100644 +--- a/contrib/ci/deps.sh ++++ b/contrib/ci/deps.sh +@@ -47,6 +47,8 @@ if [[ "$DISTRO_BRANCH" == -redhat-* ]]; then + uid_wrapper + python-requests + curl-devel ++ krb5-server ++ krb5-workstation + ) + _DEPS_LIST_SPEC=` + sed -e 's/@PACKAGE_VERSION@/0/g' \ +@@ -122,6 +124,10 @@ if [[ "$DISTRO_BRANCH" == -debian-* ]]; then + libhttp-parser-dev + libjansson-dev + libcurl4-openssl-dev ++ krb5-kdc ++ krb5-admin-server ++ krb5-user ++ uuid-dev + ) + DEPS_INTGCHECK_SATISFIED=true + fi +diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am +index 1d36fa0d2d50307fbc871f5b2a6f0cb1cc95db81..8526beace09b15c99aa27ac98d5038d1980f6a71 100644 +--- a/src/tests/intg/Makefile.am ++++ b/src/tests/intg/Makefile.am +@@ -26,6 +26,9 @@ dist_noinst_DATA = \ + files_ops.py \ + test_files_ops.py \ + test_files_provider.py \ ++ kdc.py \ ++ krb5utils.py \ ++ test_kcm.py \ + $(NULL) + + config.py: config.py.m4 +@@ -80,5 +83,6 @@ intgcheck-installed: config.py passwd group + NSS_WRAPPER_MODULE_FN_PREFIX="sss" \ + UID_WRAPPER=1 \ + UID_WRAPPER_ROOT=1 \ ++ NON_WRAPPED_UID=$$(echo $$UID) \ + fakeroot $(PYTHON2) $(PYTEST) -v --tb=native $(INTGCHECK_PYTEST_ARGS) . + rm -f $(DESTDIR)$(logpath)/* +diff --git a/src/tests/intg/kdc.py b/src/tests/intg/kdc.py +new file mode 100644 +index 0000000000000000000000000000000000000000..dec33a979916c0979561afb22dc39d6eb8894ff3 +--- /dev/null ++++ b/src/tests/intg/kdc.py +@@ -0,0 +1,175 @@ ++# ++# MIT Kerberos server class ++# ++# Copyright (c) 2016 Red Hat, Inc. ++# ++# This 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; version 2 only ++# ++# 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 . ++# ++import os ++import signal ++import shutil ++import subprocess ++ ++from util import * ++ ++ ++class KDC(object): ++ """ ++ MIT Kerberos KDC instance ++ """ ++ ++ def __init__(self, basedir, realm, ++ includedir=None, ++ kdc_port=10088, ++ kadmin_port=10749, ++ master_key='master'): ++ self.basedir = basedir ++ self.realm = realm ++ self.kdc_port = kdc_port ++ self.kadmin_port = kadmin_port ++ self.master_key = master_key ++ ++ self.kdc_basedir = self.basedir + "/var/krb5kdc" ++ self.includedir = includedir or (self.kdc_basedir + "/include") ++ self.kdc_logdir = self.kdc_basedir + "/log" ++ self.kdc_conf_path = self.kdc_basedir + "/kdc.conf" ++ self.krb5_conf_path = self.kdc_basedir + "/krb5.conf" ++ ++ self.kdc_pid_file = self.kdc_basedir + "/kdc.pid" ++ ++ self.acl_file = self.kdc_basedir + "/kadm5.acl" ++ ++ self.admin_princ = "admin/admin@" + self.realm ++ ++ def start_kdc(self, extra_args=[]): ++ args = ["krb5kdc", '-P', self.kdc_pid_file] + extra_args ++ return self._run_in_env(args, self.get_krb5_env()) ++ ++ def stop_kdc(self): ++ try: ++ with open(self.kdc_pid_file, "r") as pid_file: ++ os.kill(int(pid_file.read()), signal.SIGTERM) ++ except IOError as ioex: ++ if ioex.errno == 2: ++ pass ++ else: ++ raise ioex ++ ++ def teardown(self): ++ self.stop_kdc() ++ shutil.rmtree(self.kdc_basedir) ++ ++ def set_up(self): ++ self._create_config() ++ self._create_acl() ++ self._create_kdb() ++ ++ def get_krb5_env(self): ++ my_env = os.environ ++ my_env['KRB5_CONFIG'] = self.krb5_conf_path ++ my_env['KRB5_KDC_PROFILE'] = self.kdc_conf_path ++ return my_env ++ ++ def add_config(self, include_files): ++ for name, contents in include_files.items(): ++ include_fpath = os.path.join(self.includedir, name) ++ with open(include_fpath, 'w') as include_file: ++ include_file.write(contents) ++ ++ def add_principal(self, princ, password=None): ++ args = ["kadmin.local", "-q"] ++ if password is None: ++ args += ["addprinc -randkey %s" % (princ)] ++ else: ++ args += ["addprinc -pw %s %s" % (password, princ)] ++ return self._run_in_env(args, self.get_krb5_env()) ++ ++ def _run_in_env(self, args, env): ++ cmd = subprocess.Popen(args, env=env) ++ out, err = cmd.communicate() ++ return cmd.returncode, out, err ++ ++ def _create_config(self): ++ try: ++ os.makedirs(self.kdc_basedir) ++ os.makedirs(self.kdc_logdir) ++ os.makedirs(self.includedir) ++ except OSError as osex: ++ if osex.errno == 17: ++ pass ++ ++ kdc_conf = self._format_kdc_conf() ++ with open(self.kdc_conf_path, 'w') as kdc_conf_file: ++ kdc_conf_file.write(kdc_conf) ++ ++ krb5_conf = self._format_krb5_conf() ++ with open(self.krb5_conf_path, 'w') as krb5_conf_file: ++ krb5_conf_file.write(krb5_conf) ++ ++ def _create_acl(self): ++ with open(self.acl_file, 'w') as acl_fobject: ++ acl_fobject.write(self.admin_princ) ++ ++ def _create_kdb(self): ++ self._run_in_env( ++ ['kdb5_util', 'create', '-W', '-s', '-P', self.master_key], ++ self.get_krb5_env() ++ ) ++ ++ def _format_kdc_conf(self): ++ database_path = self.kdc_basedir + "/principal" ++ key_stash = self.kdc_basedir + "/stash." + self.realm ++ ++ kdc_logfile = "FILE:" + self.kdc_logdir + "/krb5kdc.log" ++ kadmin_logfile = "FILE:" + self.kdc_logdir + "/kadmin.log" ++ libkrb5_logfile = "FILE:" + self.kdc_logdir + "/libkrb5.log" ++ ++ kdc_conf = unindent(""" ++ [kdcdefaults] ++ kdc_ports = {self.kdc_port} ++ kdc_tcp_ports = {self.kdc_port} ++ ++ [realms] ++ {self.realm} = {{ ++ kadmind_port = {self.kadmin_port} ++ database_name = {database_path} ++ key_stash_file = {key_stash} ++ acl_file = {self.acl_file} ++ }} ++ ++ [logging] ++ kdc = {kdc_logfile} ++ admin_server = {kadmin_logfile} ++ default = {libkrb5_logfile} ++ """).format(**locals()) ++ return kdc_conf ++ ++ def _format_krb5_conf(self): ++ kdc_uri = "localhost:%d" % self.kdc_port ++ kadmin_uri = "localhost:%d" % self.kadmin_port ++ ++ krb5_conf = unindent(""" ++ includedir {self.includedir} ++ ++ [libdefaults] ++ default_realm = {self.realm} ++ dns_lookup_kdc = false ++ dns_lookup_realm = false ++ ++ [realms] ++ {self.realm} = {{ ++ kdc = {kdc_uri} ++ admin_server = {kadmin_uri} ++ }} ++ """).format(**locals()) ++ return krb5_conf +diff --git a/src/tests/intg/krb5utils.py b/src/tests/intg/krb5utils.py +new file mode 100644 +index 0000000000000000000000000000000000000000..775cffd0bbfa011f2d8ffc1169dccfef96d78fab +--- /dev/null ++++ b/src/tests/intg/krb5utils.py +@@ -0,0 +1,156 @@ ++# ++# MIT Kerberos server class ++# ++# Copyright (c) 2016 Red Hat, Inc. ++# ++# This 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; version 2 only ++# ++# 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 . ++# ++import os ++import subprocess ++ ++ ++class NoPrincipals(Exception): ++ def __init__(self): ++ Exception.__init__(self, 'No principals in the collection') ++ ++ ++class PrincNotFound(Exception): ++ def __init__(self, principal): ++ Exception.__init__(self, 'Principal %s not found' % principal) ++ ++ ++class Krb5Utils(object): ++ """ ++ Helper class to test Kerberos command line utilities ++ """ ++ def __init__(self, krb5_conf_path): ++ self.krb5_conf_path = krb5_conf_path ++ ++ def _run_in_env(self, args, stdin=None, extra_env=None): ++ my_env = os.environ ++ my_env['KRB5_CONFIG'] = self.krb5_conf_path ++ ++ if 'KRB5CCNAME' in my_env: ++ del my_env['KRB5CCNAME'] ++ if extra_env is not None: ++ my_env.update(extra_env) ++ ++ cmd = subprocess.Popen(args, ++ env=my_env, ++ stdin=subprocess.PIPE, ++ stdout=subprocess.PIPE, ++ stderr=subprocess.PIPE) ++ out, err = cmd.communicate(stdin) ++ return cmd.returncode, out.decode('utf-8'), err.decode('utf-8') ++ ++ def kinit(self, principal, password, env=None): ++ args = ["kinit", principal] ++ return self._run_in_env(args, password.encode('utf-8'), env) ++ ++ def kvno(self, principal, env=None): ++ args = ["kvno", principal] ++ return self._run_in_env(args, env) ++ ++ def kdestroy(self, all_ccaches=False, env=None): ++ args = ["kdestroy"] ++ if all_ccaches is True: ++ args += ["-A"] ++ retval, _, _ = self._run_in_env(args, env) ++ return retval ++ ++ def kswitch(self, principal, env=None): ++ args = ["kswitch", '-p', principal] ++ retval, _, _ = self._run_in_env(args, env) ++ return retval ++ ++ def _check_klist_l(self, line, exp_principal, exp_cache): ++ try: ++ princ, cache = line.split() ++ except ValueError: ++ return False ++ ++ if exp_cache is not None and cache != exp_cache: ++ return False ++ ++ if exp_principal != princ: ++ return False ++ ++ return True ++ ++ def num_princs(self, env=None): ++ args = ["klist", "-l"] ++ retval, out, err = self._run_in_env(args, extra_env=env) ++ if retval != 0: ++ return 0 ++ ++ outlines = [l for l in out.split('\n') if len(l) > 1] ++ return len(outlines) - 2 ++ ++ def list_princs(self, env=None): ++ args = ["klist", "-l"] ++ retval, out, err = self._run_in_env(args, extra_env=env) ++ if retval == 1: ++ raise NoPrincipals ++ elif retval != 0: ++ raise Exception("klist failed: %d: %s\n", retval, err) ++ ++ outlines = out.split('\n') ++ if len(outlines) < 2: ++ raise Exception("Not enough output from klist -l") ++ ++ return [l for l in outlines[2:] if len(l) > 0] ++ ++ def has_principal(self, exp_principal, exp_cache=None, env=None): ++ try: ++ princlist = self.list_princs(env) ++ except NoPrincipals: ++ return False ++ ++ for line in princlist: ++ matches = self._check_klist_l(line, exp_principal, exp_cache) ++ if matches is True: ++ return True ++ ++ return False ++ ++ def default_principal(self, env=None): ++ principals = self.list_princs(env) ++ return principals[0].split()[0] ++ ++ def _parse_klist_a(self, out): ++ dflprinc = None ++ thisrealm = None ++ ccache_dict = dict() ++ ++ for line in [l for l in out.split('\n') if len(l) > 0]: ++ if line.startswith("Default principal"): ++ dflprinc = line.split()[2] ++ thisrealm = '@' + dflprinc.split('@')[1] ++ elif thisrealm is not None and line.endswith(thisrealm): ++ svc = line.split()[-1] ++ if dflprinc in ccache_dict: ++ ccache_dict[dflprinc].append(svc) ++ else: ++ ccache_dict[dflprinc] = [svc] ++ ++ return ccache_dict ++ ++ def list_all_princs(self, env=None): ++ args = ["klist", "-A"] ++ retval, out, err = self._run_in_env(args, extra_env=env) ++ if retval == 1: ++ raise NoPrincipals ++ elif retval != 0: ++ raise Exception("klist -A failed: %d: %s\n", retval, err) ++ ++ return self._parse_klist_a(out) +diff --git a/src/tests/intg/test_kcm.py b/src/tests/intg/test_kcm.py +new file mode 100644 +index 0000000000000000000000000000000000000000..ad1e4923bfe339cb040464757431d2ef3bf57ce1 +--- /dev/null ++++ b/src/tests/intg/test_kcm.py +@@ -0,0 +1,361 @@ ++# ++# KCM responder integration tests ++# ++# Copyright (c) 2016 Red Hat, Inc. ++# ++# This 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; version 2 only ++# ++# 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 . ++# ++import os ++import os.path ++import stat ++import subprocess ++import pytest ++import socket ++import time ++import signal ++ ++import kdc ++import krb5utils ++import config ++from util import unindent, run_shell ++ ++class KcmTestEnv(object): ++ def __init__(self, k5kdc, k5util): ++ self.k5kdc = k5kdc ++ self.k5util = k5util ++ self.counter = 0 ++ ++ def my_uid(self): ++ s_myuid = os.environ['NON_WRAPPED_UID'] ++ return int(s_myuid) ++ ++ def ccname(self, my_uid=None): ++ if my_uid is None: ++ my_uid = self.my_uid() ++ ++ return "KCM:%d" % my_uid ++ ++ ++@pytest.fixture(scope="module") ++def kdc_instance(request): ++ """Kerberos server instance fixture""" ++ kdc_instance = kdc.KDC(config.PREFIX, "KCMTEST") ++ try: ++ kdc_instance.set_up() ++ kdc_instance.start_kdc() ++ except: ++ kdc_instance.teardown() ++ raise ++ request.addfinalizer(kdc_instance.teardown) ++ return kdc_instance ++ ++ ++def create_conf_fixture(request, contents): ++ """Generate sssd.conf and add teardown for removing it""" ++ with open(config.CONF_PATH, "w") as conf: ++ conf.write(contents) ++ os.chmod(config.CONF_PATH, stat.S_IRUSR | stat.S_IWUSR) ++ request.addfinalizer(lambda: os.unlink(config.CONF_PATH)) ++ ++ ++def create_sssd_kcm_fixture(sock_path, request): ++ if subprocess.call(['sssd', "--genconf"]) != 0: ++ raise Exception("failed to regenerate confdb") ++ ++ resp_path = os.path.join(config.LIBEXEC_PATH, "sssd", "sssd_kcm") ++ if not os.access(resp_path, os.X_OK): ++ # It would be cleaner to use pytest.mark.skipif on the package level ++ # but upstream insists on supporting RHEL-6.. ++ pytest.skip("No KCM responder, skipping") ++ ++ kcm_pid = os.fork() ++ assert kcm_pid >= 0 ++ ++ if kcm_pid == 0: ++ if subprocess.call([resp_path, "--uid=0", "--gid=0"]) != 0: ++ print("sssd_kcm failed to start") ++ sys.exit(99) ++ else: ++ abs_sock_path = os.path.join(config.RUNSTATEDIR, sock_path) ++ sck = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) ++ for _ in range(1, 10): ++ try: ++ sck.connect(abs_sock_path) ++ except: ++ time.sleep(0.1) ++ else: ++ break ++ sck.close() ++ assert os.path.exists(abs_sock_path) ++ ++ def kcm_teardown(): ++ if kcm_pid == 0: ++ return ++ os.kill(kcm_pid, signal.SIGTERM) ++ ++ request.addfinalizer(kcm_teardown) ++ return kcm_pid ++ ++ ++@pytest.fixture ++def setup_for_kcm(request, kdc_instance): ++ """ ++ Just set up the local provider for tests and enable the KCM ++ responder ++ """ ++ kcm_path = os.path.join(config.RUNSTATEDIR, "kcm.socket") ++ ++ sssd_conf = unindent("""\ ++ [sssd] ++ domains = local ++ services = nss ++ ++ [domain/local] ++ id_provider = local ++ ++ [kcm] ++ socket_path = {kcm_path} ++ """).format(**locals()) ++ ++ kcm_socket_include = unindent(""" ++ [libdefaults] ++ default_ccache_name = KCM: ++ kcm_socket = {kcm_path} ++ """).format(**locals()) ++ kdc_instance.add_config({'kcm_socket': kcm_socket_include}) ++ ++ create_conf_fixture(request, sssd_conf) ++ create_sssd_kcm_fixture(kcm_path, request) ++ ++ k5util = krb5utils.Krb5Utils(kdc_instance.krb5_conf_path) ++ ++ return KcmTestEnv(kdc_instance, k5util) ++ ++ ++def test_kcm_init_list_destroy(setup_for_kcm): ++ """ ++ Test that kinit, kdestroy and klist work with KCM ++ """ ++ testenv = setup_for_kcm ++ testenv.k5kdc.add_principal("kcmtest", "Secret123") ++ ++ ok = testenv.k5util.has_principal("kcmtest@KCMTEST") ++ assert ok is False ++ nprincs = testenv.k5util.num_princs() ++ assert nprincs == 0 ++ ++ out, _, _ = testenv.k5util.kinit("kcmtest", "Secret123") ++ assert out == 0 ++ nprincs = testenv.k5util.num_princs() ++ assert nprincs == 1 ++ ++ exp_ccname = testenv.ccname() ++ ok = testenv.k5util.has_principal("kcmtest@KCMTEST", exp_ccname) ++ assert ok is True ++ ++ out = testenv.k5util.kdestroy() ++ assert out == 0 ++ ++ ok = testenv.k5util.has_principal("kcmtest@KCMTEST") ++ assert ok is False ++ nprincs = testenv.k5util.num_princs() ++ assert nprincs == 0 ++ ++ ++def test_kcm_overwrite(setup_for_kcm): ++ """ ++ That that reusing a ccache reinitializes the cache and doesn't ++ add the same principal twice ++ """ ++ testenv = setup_for_kcm ++ testenv.k5kdc.add_principal("kcmtest", "Secret123") ++ exp_ccache = {'kcmtest@KCMTEST': ['krbtgt/KCMTEST@KCMTEST']} ++ ++ assert testenv.k5util.num_princs() == 0 ++ ++ out, _, _ = testenv.k5util.kinit("kcmtest", "Secret123") ++ assert out == 0 ++ assert exp_ccache == testenv.k5util.list_all_princs() ++ ++ out, _, _ = testenv.k5util.kinit("kcmtest", "Secret123") ++ assert out == 0 ++ assert exp_ccache == testenv.k5util.list_all_princs() ++ ++ ++def test_collection_init_list_destroy(setup_for_kcm): ++ """ ++ Test that multiple principals and service tickets can be stored ++ in a collection. ++ """ ++ testenv = setup_for_kcm ++ testenv.k5kdc.add_principal("alice", "alicepw") ++ testenv.k5kdc.add_principal("bob", "bobpw") ++ testenv.k5kdc.add_principal("carol", "carolpw") ++ testenv.k5kdc.add_principal("host/somehostname") ++ ++ assert testenv.k5util.num_princs() == 0 ++ ++ out, _, _ = testenv.k5util.kinit("alice", "alicepw") ++ assert out == 0 ++ assert testenv.k5util.default_principal() == 'alice@KCMTEST' ++ cc_coll = testenv.k5util.list_all_princs() ++ assert len(cc_coll) == 1 ++ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] ++ assert 'bob@KCMTEST' not in cc_coll ++ assert 'carol@KCMTEST' not in cc_coll ++ ++ out, _, _ = testenv.k5util.kinit("bob", "bobpw") ++ assert out == 0 ++ assert testenv.k5util.default_principal() == 'bob@KCMTEST' ++ cc_coll = testenv.k5util.list_all_princs() ++ assert len(cc_coll) == 2 ++ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] ++ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] ++ assert 'carol@KCMTEST' not in cc_coll ++ ++ out, _, _ = testenv.k5util.kinit("carol", "carolpw") ++ assert out == 0 ++ assert testenv.k5util.default_principal() == 'carol@KCMTEST' ++ cc_coll = testenv.k5util.list_all_princs() ++ assert len(cc_coll) == 3 ++ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] ++ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] ++ assert cc_coll['carol@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] ++ ++ out, _, _ = testenv.k5util.kvno('host/somehostname') ++ assert out == 0 ++ cc_coll = testenv.k5util.list_all_princs() ++ assert len(cc_coll) == 3 ++ assert set(cc_coll['carol@KCMTEST']) == set(['krbtgt/KCMTEST@KCMTEST', ++ 'host/somehostname@KCMTEST']) ++ ++ out = testenv.k5util.kdestroy() ++ assert out == 0 ++ assert testenv.k5util.default_principal() == 'bob@KCMTEST' ++ cc_coll = testenv.k5util.list_all_princs() ++ assert len(cc_coll) == 2 ++ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] ++ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] ++ assert 'carol@KCMTEST' not in cc_coll ++ ++ # FIXME - a bug in libkrb5? ++ #out = testenv.k5util.kdestroy(all_ccaches=True) ++ #assert out == 0 ++ #cc_coll = testenv.k5util.list_all_princs() ++ #assert len(cc_coll) == 0 ++ ++ ++def test_kswitch(setup_for_kcm): ++ """ ++ Test switching between principals ++ """ ++ testenv = setup_for_kcm ++ testenv.k5kdc.add_principal("alice", "alicepw") ++ testenv.k5kdc.add_principal("bob", "bobpw") ++ testenv.k5kdc.add_principal("host/somehostname") ++ testenv.k5kdc.add_principal("host/differenthostname") ++ ++ out, _, _ = testenv.k5util.kinit("alice", "alicepw") ++ assert out == 0 ++ assert testenv.k5util.default_principal() == 'alice@KCMTEST' ++ ++ out, _, _ = testenv.k5util.kinit("bob", "bobpw") ++ assert out == 0 ++ assert testenv.k5util.default_principal() == 'bob@KCMTEST' ++ ++ cc_coll = testenv.k5util.list_all_princs() ++ assert len(cc_coll) == 2 ++ assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] ++ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] ++ ++ out = testenv.k5util.kswitch("alice@KCMTEST") ++ assert testenv.k5util.default_principal() == 'alice@KCMTEST' ++ out, _, _ = testenv.k5util.kvno('host/somehostname') ++ assert out == 0 ++ cc_coll = testenv.k5util.list_all_princs() ++ assert len(cc_coll) == 2 ++ assert set(cc_coll['alice@KCMTEST']) == set(['krbtgt/KCMTEST@KCMTEST', ++ 'host/somehostname@KCMTEST']) ++ assert cc_coll['bob@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] ++ ++ out = testenv.k5util.kswitch("bob@KCMTEST") ++ assert testenv.k5util.default_principal() == 'bob@KCMTEST' ++ out, _, _ = testenv.k5util.kvno('host/differenthostname') ++ assert out == 0 ++ cc_coll = testenv.k5util.list_all_princs() ++ assert len(cc_coll) == 2 ++ assert set(cc_coll['alice@KCMTEST']) == set(['krbtgt/KCMTEST@KCMTEST', ++ 'host/somehostname@KCMTEST']) ++ assert set(cc_coll['bob@KCMTEST']) == set([ ++ 'krbtgt/KCMTEST@KCMTEST', ++ 'host/differenthostname@KCMTEST']) ++ ++ ++def test_subsidiaries(setup_for_kcm): ++ """ ++ Test that subsidiary caches are usable and KCM: without specifying UID ++ can be used to identify the collection ++ """ ++ testenv = setup_for_kcm ++ testenv.k5kdc.add_principal("alice", "alicepw") ++ testenv.k5kdc.add_principal("bob", "bobpw") ++ testenv.k5kdc.add_principal("host/somehostname") ++ testenv.k5kdc.add_principal("host/differenthostname") ++ ++ out, _, _ = testenv.k5util.kinit("alice", "alicepw") ++ assert out == 0 ++ out, _, _ = testenv.k5util.kvno('host/somehostname') ++ ++ out, _, _ = testenv.k5util.kinit("bob", "bobpw") ++ assert out == 0 ++ out, _, _ = testenv.k5util.kvno('host/differenthostname') ++ ++ exp_cc_coll = dict() ++ exp_cc_coll['alice@KCMTEST'] = 'host/somehostname@KCMTEST' ++ exp_cc_coll['bob@KCMTEST'] = 'host/differenthostname@KCMTEST' ++ ++ klist_l = testenv.k5util.list_princs() ++ princ_ccache = dict() ++ for line in klist_l: ++ princ, subsidiary = line.split() ++ princ_ccache[princ] = subsidiary ++ ++ for princ, subsidiary in princ_ccache.items(): ++ env = {'KRB5CCNAME': subsidiary} ++ cc_coll = testenv.k5util.list_all_princs(env=env) ++ assert len(cc_coll) == 1 ++ assert princ in cc_coll ++ assert exp_cc_coll[princ] in cc_coll[princ] ++ ++ cc_coll = testenv.k5util.list_all_princs(env={'KRB5CCNAME': 'KCM:'}) ++ assert len(cc_coll) == 2 ++ assert set(cc_coll['alice@KCMTEST']) == set(['krbtgt/KCMTEST@KCMTEST', ++ 'host/somehostname@KCMTEST']) ++ assert set(cc_coll['bob@KCMTEST']) == set([ ++ 'krbtgt/KCMTEST@KCMTEST', ++ 'host/differenthostname@KCMTEST']) ++ ++ ++def test_kdestroy_nocache(setup_for_kcm): ++ """ ++ Destroying a non-existing ccache should not throw an error ++ """ ++ testenv = setup_for_kcm ++ testenv.k5kdc.add_principal("alice", "alicepw") ++ out, _, _ = testenv.k5util.kinit("alice", "alicepw") ++ assert out == 0 ++ ++ testenv.k5util.kdestroy() ++ assert out == 0 ++ out = testenv.k5util.kdestroy() ++ assert out == 0 +-- +2.9.3 + diff --git a/SOURCES/0028-views-allow-override-added-for-non-default-views-at-.patch b/SOURCES/0028-views-allow-override-added-for-non-default-views-at-.patch deleted file mode 100644 index fb5707c..0000000 --- a/SOURCES/0028-views-allow-override-added-for-non-default-views-at-.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 845e3a3acea6f83b15ed3d887fcc4ed42cb3eb5a Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 11 Jul 2016 15:04:32 +0200 -Subject: [PATCH 28/31] views: allow override added for non-default views at - runtime -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Currently a new override for a non-default view cannot be displayed at -run-time. It even does not only require a restart but the view must be -un-applied and applied again to make the changes visible. - -This patch fixes this and makes non-default view behave like the default -view where the data from a newly added override are displayed after the -cached entry of the related object is expired. - -Resolves https://fedorahosted.org/sssd/ticket/3092 - -Reviewed-by: Pavel Březina -(cherry picked from commit 26a3d4f2ef35a088e4c5fc928290052c89a2ff43) ---- - src/db/sysdb_views.c | 26 ++++++++++++++++++-------- - 1 file changed, 18 insertions(+), 8 deletions(-) - -diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c -index 7adc1523050243b8936cb98be3c71ce4364a03db..2b89e5ca41f719e1217ef3b9e0fd683656e05d42 100644 ---- a/src/db/sysdb_views.c -+++ b/src/db/sysdb_views.c -@@ -454,15 +454,23 @@ errno_t sysdb_store_override(struct sss_domain_info *domain, - obj_override_dn = ldb_msg_find_attr_as_string(msgs[0], SYSDB_OVERRIDE_DN, - NULL); - if (obj_override_dn != NULL) { -+ /* obj_override_dn can either point to the object itself, i.e there is -+ * no override, or to a overide object. This means it can change from -+ * the object DN to a override DN and back but not from one override -+ * DN to a different override DN. If the new and the old DN are the -+ * same we do not need to update the original object. */ - if (strcmp(obj_override_dn, override_dn_str) != 0) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Existing [%s] and new [%s] override DN do not match.\n", -- obj_override_dn, override_dn_str); -- ret = EINVAL; -- goto done; -+ if (strcmp(obj_override_dn, obj_dn_str) != 0 -+ && strcmp(override_dn_str, obj_dn_str) != 0) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Existing [%s] and new [%s] override DN do not match.\n", -+ obj_override_dn, override_dn_str); -+ ret = EINVAL; -+ goto done; -+ } -+ } else { -+ add_ref = false; - } -- -- add_ref = false; - } - - ret = ldb_transaction_start(domain->sysdb->ldb); -@@ -580,7 +588,9 @@ errno_t sysdb_store_override(struct sss_domain_info *domain, - - msg->dn = obj_dn; - -- ret = ldb_msg_add_empty(msg, SYSDB_OVERRIDE_DN, LDB_FLAG_MOD_ADD, -+ ret = ldb_msg_add_empty(msg, SYSDB_OVERRIDE_DN, -+ obj_override_dn == NULL ? LDB_FLAG_MOD_ADD -+ : LDB_FLAG_MOD_REPLACE, - NULL); - if (ret != LDB_SUCCESS) { - DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n"); --- -2.4.11 - diff --git a/SOURCES/0029-SECRETS-Create-DB-path-before-the-operation-itself.patch b/SOURCES/0029-SECRETS-Create-DB-path-before-the-operation-itself.patch new file mode 100644 index 0000000..3b1bee7 --- /dev/null +++ b/SOURCES/0029-SECRETS-Create-DB-path-before-the-operation-itself.patch @@ -0,0 +1,405 @@ +From 27e11e8f03e1bad5d1be276efaf1406b16b11625 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 3 Jan 2017 16:00:38 +0100 +Subject: [PATCH 29/36] SECRETS: Create DB path before the operation itself +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is a refactoring where instead of creating the ldb path in the +operation itself, we create the ldb path when creating the local db request +and pass the path to the operation. + +This would allow us to store different kind of objects in the secrets +storage later. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + src/responder/secrets/local.c | 170 +++++++++++++++++++++--------------------- + 1 file changed, 84 insertions(+), 86 deletions(-) + +diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c +index ed70193bcb27d84eaf449f6f7571c94f466c9896..9dcdd9925e542499d3a962b4998103b07c26a5ab 100644 +--- a/src/responder/secrets/local.c ++++ b/src/responder/secrets/local.c +@@ -199,39 +199,36 @@ static char *local_dn_to_path(TALLOC_CTX *mem_ctx, + return path; + } + ++struct local_db_req { ++ char *path; ++ struct ldb_dn *basedn; ++}; ++ + #define LOCAL_SIMPLE_FILTER "(type=simple)" + #define LOCAL_CONTAINER_FILTER "(type=container)" + + static int local_db_get_simple(TALLOC_CTX *mem_ctx, + struct local_context *lctx, +- const char *req_path, ++ struct local_db_req *lc_req, + char **secret) + { + TALLOC_CTX *tmp_ctx; + static const char *attrs[] = { "secret", "enctype", NULL }; + struct ldb_result *res; +- struct ldb_dn *dn; + const char *attr_secret; + const char *attr_enctype; + int ret; + +- DEBUG(SSSDBG_TRACE_FUNC, "Retrieving a secret from [%s]\n", req_path); ++ DEBUG(SSSDBG_TRACE_FUNC, "Retrieving a secret from [%s]\n", lc_req->path); + + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) return ENOMEM; + +- ret = local_db_dn(tmp_ctx, lctx->ldb, req_path, &dn); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret)); +- goto done; +- } +- + DEBUG(SSSDBG_TRACE_INTERNAL, + "Searching for [%s] at [%s] with scope=base\n", +- LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(dn)); ++ LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(lc_req->basedn)); + +- ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, ++ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_BASE, + attrs, "%s", LOCAL_SIMPLE_FILTER); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_LIBS, +@@ -278,34 +275,26 @@ done: + + static int local_db_list_keys(TALLOC_CTX *mem_ctx, + struct local_context *lctx, +- const char *req_path, ++ struct local_db_req *lc_req, + char ***_keys, + int *num_keys) + { + TALLOC_CTX *tmp_ctx; + static const char *attrs[] = { "secret", NULL }; + struct ldb_result *res; +- struct ldb_dn *dn; + char **keys; + int ret; + + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) return ENOMEM; + +- DEBUG(SSSDBG_TRACE_FUNC, "Listing keys at [%s]\n", req_path); +- +- ret = local_db_dn(tmp_ctx, lctx->ldb, req_path, &dn); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret)); +- goto done; +- } ++ DEBUG(SSSDBG_TRACE_FUNC, "Listing keys at [%s]\n", lc_req->path); + + DEBUG(SSSDBG_TRACE_INTERNAL, + "Searching for [%s] at [%s] with scope=subtree\n", +- LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(dn)); ++ LOCAL_SIMPLE_FILTER, ldb_dn_get_linearized(lc_req->basedn)); + +- ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE, ++ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_SUBTREE, + attrs, "%s", LOCAL_SIMPLE_FILTER); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_LIBS, +@@ -327,7 +316,7 @@ static int local_db_list_keys(TALLOC_CTX *mem_ctx, + } + + for (unsigned i = 0; i < res->count; i++) { +- keys[i] = local_dn_to_path(keys, dn, res->msgs[i]->dn); ++ keys[i] = local_dn_to_path(keys, lc_req->basedn, res->msgs[i]->dn); + if (!keys[i]) { + ret = ENOMEM; + goto done; +@@ -474,7 +463,7 @@ static int local_check_max_payload_size(struct local_context *lctx, + + static int local_db_put_simple(TALLOC_CTX *mem_ctx, + struct local_context *lctx, +- const char *req_path, ++ struct local_db_req *lc_req, + const char *secret) + { + struct ldb_message *msg; +@@ -482,20 +471,14 @@ static int local_db_put_simple(TALLOC_CTX *mem_ctx, + char *enc_secret; + int ret; + ++ DEBUG(SSSDBG_TRACE_FUNC, "Adding a secret to [%s]\n", lc_req->path); ++ + msg = ldb_msg_new(mem_ctx); + if (!msg) { + ret = ENOMEM; + goto done; + } +- +- DEBUG(SSSDBG_TRACE_FUNC, "Adding a secret to [%s]\n", req_path); +- +- ret = local_db_dn(msg, lctx->ldb, req_path, &msg->dn); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret)); +- goto done; +- } ++ msg->dn = lc_req->basedn; + + /* make sure containers exist */ + ret = local_db_check_containers(msg, lctx, msg->dn); +@@ -585,32 +568,24 @@ done: + + static int local_db_delete(TALLOC_CTX *mem_ctx, + struct local_context *lctx, +- const char *req_path) ++ struct local_db_req *lc_req) + { + TALLOC_CTX *tmp_ctx; +- struct ldb_dn *dn; + static const char *attrs[] = { NULL }; + struct ldb_result *res; + int ret; + +- DEBUG(SSSDBG_TRACE_FUNC, "Removing a secret from [%s]\n", req_path); ++ DEBUG(SSSDBG_TRACE_FUNC, "Removing a secret from [%s]\n", lc_req->path); + + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) return ENOMEM; + +- ret = local_db_dn(mem_ctx, lctx->ldb, req_path, &dn); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret)); +- goto done; +- } +- + DEBUG(SSSDBG_TRACE_INTERNAL, + "Searching for [%s] at [%s] with scope=base\n", +- LOCAL_CONTAINER_FILTER, ldb_dn_get_linearized(dn)); ++ LOCAL_CONTAINER_FILTER, ldb_dn_get_linearized(lc_req->basedn)); + +- ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, +- attrs, LOCAL_CONTAINER_FILTER); ++ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_BASE, ++ attrs, LOCAL_CONTAINER_FILTER); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_LIBS, + "ldb_search returned %d: %s\n", ret, ldb_strerror(ret)); +@@ -619,8 +594,8 @@ static int local_db_delete(TALLOC_CTX *mem_ctx, + + if (res->count == 1) { + DEBUG(SSSDBG_TRACE_INTERNAL, +- "Searching for children of [%s]\n", ldb_dn_get_linearized(dn)); +- ret = ldb_search(lctx->ldb, tmp_ctx, &res, dn, LDB_SCOPE_ONELEVEL, ++ "Searching for children of [%s]\n", ldb_dn_get_linearized(lc_req->basedn)); ++ ret = ldb_search(lctx->ldb, tmp_ctx, &res, lc_req->basedn, LDB_SCOPE_ONELEVEL, + attrs, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_LIBS, +@@ -632,13 +607,13 @@ static int local_db_delete(TALLOC_CTX *mem_ctx, + ret = EEXIST; + DEBUG(SSSDBG_OP_FAILURE, + "Failed to remove '%s': Container is not empty\n", +- ldb_dn_get_linearized(dn)); ++ ldb_dn_get_linearized(lc_req->basedn)); + + goto done; + } + } + +- ret = ldb_delete(lctx->ldb, dn); ++ ret = ldb_delete(lctx->ldb, lc_req->basedn); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_LIBS, + "ldb_delete returned %d: %s\n", ret, ldb_strerror(ret)); +@@ -653,25 +628,19 @@ done: + + static int local_db_create(TALLOC_CTX *mem_ctx, + struct local_context *lctx, +- const char *req_path) ++ struct local_db_req *lc_req) + { + struct ldb_message *msg; + int ret; + ++ DEBUG(SSSDBG_TRACE_FUNC, "Creating a container at [%s]\n", lc_req->path); ++ + msg = ldb_msg_new(mem_ctx); + if (!msg) { + ret = ENOMEM; + goto done; + } +- +- DEBUG(SSSDBG_TRACE_FUNC, "Creating a container at [%s]\n", req_path); +- +- ret = local_db_dn(msg, lctx->ldb, req_path, &msg->dn); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "local_db_dn failed [%d]: %s\n", ret, sss_strerror(ret)); +- goto done; +- } ++ msg->dn = lc_req->basedn; + + /* make sure containers exist */ + ret = local_db_check_containers(msg, lctx, msg->dn); +@@ -724,10 +693,13 @@ done: + } + + static int local_secrets_map_path(TALLOC_CTX *mem_ctx, ++ struct ldb_context *ldb, + struct sec_req_ctx *secreq, +- char **local_db_path) ++ struct local_db_req **_lc_req) + { + int ret; ++ struct local_db_req *lc_req; ++ const char *basedn; + + /* be strict for now */ + if (secreq->parsed_url.fragment != NULL) { +@@ -755,20 +727,46 @@ static int local_secrets_map_path(TALLOC_CTX *mem_ctx, + } + } + +- /* drop SEC_BASEPATH prefix */ +- *local_db_path = +- talloc_strdup(mem_ctx, &secreq->mapped_path[sizeof(SEC_BASEPATH) - 1]); +- if (!*local_db_path) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to map request to local db path\n"); ++ lc_req = talloc(mem_ctx, struct local_db_req); ++ if (lc_req == NULL) { + return ENOMEM; + } + +- DEBUG(SSSDBG_TRACE_LIBS, "Local DB path is %s\n", *local_db_path); +- return EOK; ++ /* drop the prefix and select a basedn instead */ ++ if (strncmp(secreq->mapped_path, ++ SEC_BASEPATH, sizeof(SEC_BASEPATH) - 1) == 0) { ++ lc_req->path = talloc_strdup(lc_req, ++ secreq->mapped_path + (sizeof(SEC_BASEPATH) - 1)); ++ basedn = SECRETS_BASEDN; ++ } else { ++ ret = EINVAL; ++ goto done; ++ } ++ ++ if (lc_req->path == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to map request to local db path\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = local_db_dn(mem_ctx, ldb, basedn, lc_req->path, &lc_req->basedn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to map request to local db DN\n"); ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_LIBS, "Local DB path is %s\n", lc_req->path); ++ ret = EOK; ++ *_lc_req = lc_req; ++done: ++ if (ret != EOK) { ++ talloc_free(lc_req); ++ } ++ return ret; + } + +- + struct local_secret_state { + struct tevent_context *ev; + struct sec_req_ctx *secreq; +@@ -785,7 +783,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, + struct sec_data body = { 0 }; + const char *content_type; + bool body_is_json; +- char *req_path; ++ struct local_db_req *lc_req; + char *secret; + char **keys; + int nkeys; +@@ -821,14 +819,14 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, + } + DEBUG(SSSDBG_TRACE_LIBS, "Content-Type: %s\n", content_type); + +- ret = local_secrets_map_path(state, secreq, &req_path); ++ ret = local_secrets_map_path(state, lctx->ldb, secreq, &lc_req); + if (ret) goto done; + + switch (secreq->method) { + case HTTP_GET: +- DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP GET at [%s]\n", req_path); +- if (req_path[strlen(req_path) - 1] == '/') { +- ret = local_db_list_keys(state, lctx, req_path, &keys, &nkeys); ++ DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP GET at [%s]\n", lc_req->path); ++ if (lc_req->path[strlen(lc_req->path) - 1] == '/') { ++ ret = local_db_list_keys(state, lctx, lc_req, &keys, &nkeys); + if (ret) goto done; + + ret = sec_array_to_json(state, keys, nkeys, &body.data); +@@ -838,7 +836,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, + break; + } + +- ret = local_db_get_simple(state, lctx, req_path, &secret); ++ ret = local_db_get_simple(state, lctx, lc_req, &secret); + if (ret) goto done; + + if (body_is_json) { +@@ -855,7 +853,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, + break; + + case HTTP_PUT: +- DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP PUT at [%s]\n", req_path); ++ DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP PUT at [%s]\n", lc_req->path); + if (body_is_json) { + ret = sec_json_to_simple_secret(state, secreq->body.data, + &secret); +@@ -866,27 +864,27 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, + } + if (ret) goto done; + +- ret = local_db_put_simple(state, lctx, req_path, secret); ++ ret = local_db_put_simple(state, lctx, lc_req, secret); + if (ret) goto done; + break; + + case HTTP_DELETE: +- ret = local_db_delete(state, lctx, req_path); ++ ret = local_db_delete(state, lctx, lc_req); + if (ret) goto done; + break; + + case HTTP_POST: +- DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP POST at [%s]\n", req_path); +- plen = strlen(req_path); ++ DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP POST at [%s]\n", lc_req->path); ++ plen = strlen(lc_req->path); + +- if (req_path[plen - 1] != '/') { ++ if (lc_req->path[plen - 1] != '/') { + ret = EINVAL; + goto done; + } + +- req_path[plen - 1] = '\0'; ++ lc_req->path[plen - 1] = '\0'; + +- ret = local_db_create(state, lctx, req_path); ++ ret = local_db_create(state, lctx, lc_req); + if (ret) goto done; + break; + +-- +2.9.3 + diff --git a/SOURCES/0029-sssctl-move-filter-creation-to-separate-function.patch b/SOURCES/0029-sssctl-move-filter-creation-to-separate-function.patch deleted file mode 100644 index 6abaf60..0000000 --- a/SOURCES/0029-sssctl-move-filter-creation-to-separate-function.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 634311d9250903599a61b2f5e205e2568ae92497 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Tue, 12 Jul 2016 12:59:48 +0200 -Subject: [PATCH 29/31] sssctl: move filter creation to separate function -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit 3c6e15e8aa38d9dfa02a7255fad56149bdfb35a6) ---- - src/tools/sssctl/sssctl_cache.c | 81 +++++++++++++++++++++++------------------ - 1 file changed, 46 insertions(+), 35 deletions(-) - -diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c -index e23bb89db95217e66a441b7e4d6d32e668486cc8..3e7644e327eb3e5a0e33023e7a3f5f0f15e03cf6 100644 ---- a/src/tools/sssctl/sssctl_cache.c -+++ b/src/tools/sssctl/sssctl_cache.c -@@ -285,27 +285,16 @@ done: - return ret; - } - --static errno_t sssctl_find_object(TALLOC_CTX *mem_ctx, -- struct sss_domain_info *domains, -- struct sss_domain_info *domain, -- sssctl_basedn_fn basedn_fn, -- enum cache_object obj_type, -- const char *attr_name, -- const char *attr_value, -- const char **attrs, -- struct sysdb_attrs **_entry, -- struct sss_domain_info **_dom) -+static const char *sssctl_create_filter(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *dom, -+ enum cache_object obj_type, -+ const char *attr_name, -+ const char *attr_value) - { -- TALLOC_CTX *tmp_ctx; -- struct sss_domain_info *dom; -- struct sysdb_attrs *entry; -- struct ldb_dn *base_dn; -- bool fqn_provided; -- bool qualify_attr = false; -- char *filter; -- errno_t ret; - const char *class; -+ const char *filter; - char *filter_value; -+ bool qualify_attr = false; - - if (strcmp(attr_name, SYSDB_NAME) == 0 && - (obj_type == CACHED_USER || -@@ -326,9 +315,44 @@ static errno_t sssctl_find_object(TALLOC_CTX *mem_ctx, - default: - DEBUG(SSSDBG_FATAL_FAILURE, - "sssctl doesn't handle this object type (type=%d)\n", obj_type); -- return EINVAL; -+ return NULL; - } - -+ if (qualify_attr) { -+ filter_value = sss_create_internal_fqname(NULL, attr_value, dom->name); -+ } else { -+ filter_value = talloc_strdup(NULL, attr_value); -+ } -+ if (filter_value == NULL) { -+ return NULL; -+ } -+ -+ filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(%s=%s))", -+ class, attr_name, filter_value); -+ talloc_free(filter_value); -+ -+ return filter; -+} -+ -+static errno_t sssctl_find_object(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domains, -+ struct sss_domain_info *domain, -+ sssctl_basedn_fn basedn_fn, -+ enum cache_object obj_type, -+ const char *attr_name, -+ const char *attr_value, -+ const char **attrs, -+ struct sysdb_attrs **_entry, -+ struct sss_domain_info **_dom) -+{ -+ TALLOC_CTX *tmp_ctx; -+ struct sss_domain_info *dom; -+ struct sysdb_attrs *entry; -+ struct ldb_dn *base_dn; -+ bool fqn_provided; -+ const char *filter; -+ errno_t ret; -+ - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); -@@ -349,23 +373,10 @@ static errno_t sssctl_find_object(TALLOC_CTX *mem_ctx, - goto done; - } - -- if (qualify_attr) { -- filter_value = sss_create_internal_fqname(tmp_ctx, -- attr_value, -- dom->name); -- } else { -- filter_value = talloc_strdup(tmp_ctx, attr_value); -- } -- if (filter_value == NULL) { -- ret = ENOMEM; -- goto done; -- } -- -- filter = talloc_asprintf(tmp_ctx, "(&(objectClass=%s)(%s=%s))", -- class, attr_name, filter_value); -- talloc_free(filter_value); -+ filter = sssctl_create_filter(tmp_ctx, dom, obj_type, -+ attr_name, attr_value); - if (filter == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n"); -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create filter\n"); - ret = ENOMEM; - goto done; - } --- -2.4.11 - diff --git a/SOURCES/0030-SECRETS-Return-a-nicer-error-message-on-request-with.patch b/SOURCES/0030-SECRETS-Return-a-nicer-error-message-on-request-with.patch new file mode 100644 index 0000000..2c596dc --- /dev/null +++ b/SOURCES/0030-SECRETS-Return-a-nicer-error-message-on-request-with.patch @@ -0,0 +1,40 @@ +From ddda18a37ac4b732ad109dbb129255dc3edd8fbb Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 3 Feb 2017 14:33:47 +0100 +Subject: [PATCH 30/36] SECRETS: Return a nicer error message on request with + no PUT data +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +I managed to create this pathological situation with the tcurl tool +which didn't send any PUT data. The error in sssd-secrets was quite +strange (ENOMEM). This patch just adds a safeguard sooner so that we +return a graceful error. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + src/responder/secrets/local.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c +index 9dcdd9925e542499d3a962b4998103b07c26a5ab..26c97a2849febbf0ac482d526cf927bfc103b4f2 100644 +--- a/src/responder/secrets/local.c ++++ b/src/responder/secrets/local.c +@@ -853,6 +853,12 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, + break; + + case HTTP_PUT: ++ if (secreq->body.length == 0) { ++ DEBUG(SSSDBG_OP_FAILURE, "PUT with no data\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ + DEBUG(SSSDBG_TRACE_LIBS, "Processing HTTP PUT at [%s]\n", lc_req->path); + if (body_is_json) { + ret = sec_json_to_simple_secret(state, secreq->body.data, +-- +2.9.3 + diff --git a/SOURCES/0030-sssctl-improve-readability-of-a-condition.patch b/SOURCES/0030-sssctl-improve-readability-of-a-condition.patch deleted file mode 100644 index 88e259d..0000000 --- a/SOURCES/0030-sssctl-improve-readability-of-a-condition.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 5ff189fbc8135d5900ac97120c587128a35f56eb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Wed, 13 Jul 2016 10:41:00 +0200 -Subject: [PATCH 30/31] sssctl: improve readability of a condition -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Fabiano Fidêncio -(cherry picked from commit aa691837a2fa2fe2e38a55d576644074e0f45bd8) ---- - src/tools/sssctl/sssctl_cache.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c -index 3e7644e327eb3e5a0e33023e7a3f5f0f15e03cf6..22e3fad89e3c1bbfce48439b43acd2346da3e56f 100644 ---- a/src/tools/sssctl/sssctl_cache.c -+++ b/src/tools/sssctl/sssctl_cache.c -@@ -296,10 +296,10 @@ static const char *sssctl_create_filter(TALLOC_CTX *mem_ctx, - char *filter_value; - bool qualify_attr = false; - -- if (strcmp(attr_name, SYSDB_NAME) == 0 && -- (obj_type == CACHED_USER || -- obj_type == CACHED_GROUP)) { -- qualify_attr = true; -+ if (strcmp(attr_name, SYSDB_NAME) == 0) { -+ if (obj_type == CACHED_USER || obj_type == CACHED_GROUP) { -+ qualify_attr = true; -+ } - } - - switch (obj_type) { --- -2.4.11 - diff --git a/SOURCES/0031-SECRETS-Store-ccaches-in-secrets-for-the-KCM-respond.patch b/SOURCES/0031-SECRETS-Store-ccaches-in-secrets-for-the-KCM-respond.patch new file mode 100644 index 0000000..09d388a --- /dev/null +++ b/SOURCES/0031-SECRETS-Store-ccaches-in-secrets-for-the-KCM-respond.patch @@ -0,0 +1,206 @@ +From 91c099a993252680f103084431b1d0f5798d8a24 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 21 Mar 2017 14:14:42 +0100 +Subject: [PATCH 31/36] SECRETS: Store ccaches in secrets for the KCM responder +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Adds a new "hive" to the secrets responder whose base path is /kcm. Only +root can contact the /kcm hive, because the KCM responder only runs as +root and it must impersonate other users and store ccaches on their behalf. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + src/responder/secrets/local.c | 16 +++++++- + src/responder/secrets/providers.c | 71 ++++++++++++++++++++++++++++++---- + src/responder/secrets/secsrv_private.h | 10 ++++- + 3 files changed, 86 insertions(+), 11 deletions(-) + +diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c +index 26c97a2849febbf0ac482d526cf927bfc103b4f2..02007ada8b673071ecba033df0eb3f81af93fcbd 100644 +--- a/src/responder/secrets/local.c ++++ b/src/responder/secrets/local.c +@@ -26,6 +26,9 @@ + + #define MKEY_SIZE (256 / 8) + ++#define SECRETS_BASEDN "cn=secrets" ++#define KCM_BASEDN "cn=kcm" ++ + struct local_context { + struct ldb_context *ldb; + struct sec_data master_key; +@@ -119,6 +122,7 @@ static int local_encrypt(struct local_context *lctx, TALLOC_CTX *mem_ctx, + + static int local_db_dn(TALLOC_CTX *mem_ctx, + struct ldb_context *ldb, ++ const char *basedn, + const char *req_path, + struct ldb_dn **req_dn) + { +@@ -126,7 +130,7 @@ static int local_db_dn(TALLOC_CTX *mem_ctx, + const char *s, *e; + int ret; + +- dn = ldb_dn_new(mem_ctx, ldb, "cn=secrets"); ++ dn = ldb_dn_new(mem_ctx, ldb, basedn); + if (!dn) { + ret = ENOMEM; + goto done; +@@ -738,6 +742,11 @@ static int local_secrets_map_path(TALLOC_CTX *mem_ctx, + lc_req->path = talloc_strdup(lc_req, + secreq->mapped_path + (sizeof(SEC_BASEPATH) - 1)); + basedn = SECRETS_BASEDN; ++ } else if (strncmp(secreq->mapped_path, ++ SEC_KCM_BASEPATH, sizeof(SEC_KCM_BASEPATH) - 1) == 0) { ++ lc_req->path = talloc_strdup(lc_req, ++ secreq->mapped_path + (sizeof(SEC_KCM_BASEPATH) - 1)); ++ basedn = KCM_BASEDN; + } else { + ret = EINVAL; + goto done; +@@ -820,7 +829,10 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, + DEBUG(SSSDBG_TRACE_LIBS, "Content-Type: %s\n", content_type); + + ret = local_secrets_map_path(state, lctx->ldb, secreq, &lc_req); +- if (ret) goto done; ++ if (ret) { ++ DEBUG(SSSDBG_OP_FAILURE, "Cannot map request path to local path\n"); ++ goto done; ++ } + + switch (secreq->method) { + case HTTP_GET: +diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c +index eba555d2e422d08db211979422a2957e48b51589..94831c73036d269addca45c0117811a2c68873fd 100644 +--- a/src/responder/secrets/providers.c ++++ b/src/responder/secrets/providers.c +@@ -24,6 +24,14 @@ + #include "responder/secrets/secsrv_proxy.h" + #include + ++typedef int (*url_mapper_fn)(struct sec_req_ctx *secreq, ++ char **mapped_path); ++ ++struct url_pfx_router { ++ const char *prefix; ++ url_mapper_fn mapper_fn; ++}; ++ + static int sec_map_url_to_user_path(struct sec_req_ctx *secreq, + char **mapped_path) + { +@@ -42,10 +50,43 @@ static int sec_map_url_to_user_path(struct sec_req_ctx *secreq, + return ENOMEM; + } + +- DEBUG(SSSDBG_TRACE_LIBS, "User-specific path is [%s]\n", *mapped_path); ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "User-specific secrets path is [%s]\n", *mapped_path); + return EOK; + } + ++static int kcm_map_url_to_path(struct sec_req_ctx *secreq, ++ char **mapped_path) ++{ ++ uid_t c_euid; ++ ++ c_euid = client_euid(secreq->cctx->creds); ++ if (c_euid != KCM_PEER_UID) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "UID %"SPRIuid" is not allowed to access " ++ "the "SEC_KCM_BASEPATH" hive\n", ++ c_euid); ++ return EPERM; ++ } ++ ++ *mapped_path = talloc_strdup(secreq, secreq->parsed_url.path ); ++ if (!*mapped_path) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to map request to user specific url\n"); ++ return ENOMEM; ++ } ++ ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "User-specific KCM path is [%s]\n", *mapped_path); ++ return EOK; ++} ++ ++static struct url_pfx_router secrets_url_mapping[] = { ++ { SEC_BASEPATH, sec_map_url_to_user_path }, ++ { SEC_KCM_BASEPATH, kcm_map_url_to_path }, ++ { NULL, NULL }, ++}; ++ + int sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq, + struct provider_handle **handle) + { +@@ -55,21 +96,35 @@ int sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq, + char *provider; + int num_sections; + int ret; ++ url_mapper_fn mapper_fn = NULL; + + sctx = talloc_get_type(secreq->cctx->rctx->pvt_ctx, struct sec_ctx); + +- /* patch must start with /secrets/ for now */ +- ret = strncasecmp(secreq->parsed_url.path, +- SEC_BASEPATH, sizeof(SEC_BASEPATH) - 1); +- if (ret != 0) { ++ for (int i = 0; secrets_url_mapping[i].prefix != NULL; i++) { ++ if (strncasecmp(secreq->parsed_url.path, ++ secrets_url_mapping[i].prefix, ++ strlen(secrets_url_mapping[i].prefix)) == 0) { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "Mapping prefix %s\n", secrets_url_mapping[i].prefix); ++ mapper_fn = secrets_url_mapping[i].mapper_fn; ++ break; ++ } ++ } ++ ++ if (mapper_fn == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "Path [%s] does not start with "SEC_BASEPATH"\n", ++ "Path [%s] does not start with any allowed prefix\n", + secreq->parsed_url.path); + return EPERM; + } + +- ret = sec_map_url_to_user_path(secreq, &secreq->mapped_path); +- if (ret) return ret; ++ ret = mapper_fn(secreq, &secreq->mapped_path); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to map the user path [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return ret; ++ } + + /* source default provider */ + ret = confdb_get_string(secreq->cctx->rctx->cdb, mem_ctx, +diff --git a/src/responder/secrets/secsrv_private.h b/src/responder/secrets/secsrv_private.h +index 1c3fbd8eadb237551233f048503ddc01b4ba00ae..a8544f656517a17fe4576247779bff4850beaf97 100644 +--- a/src/responder/secrets/secsrv_private.h ++++ b/src/responder/secrets/secsrv_private.h +@@ -101,7 +101,15 @@ int sec_get_provider(struct sec_ctx *sctx, const char *name, + struct provider_handle **out_handle); + int sec_add_provider(struct sec_ctx *sctx, struct provider_handle *handle); + +-#define SEC_BASEPATH "/secrets/" ++#define SEC_BASEPATH "/secrets/" ++#define SEC_KCM_BASEPATH "/kcm/" ++ ++/* The KCM responder must "impersonate" the owner of the credentials. ++ * Only a trusted UID can do that -- root by default, but unit ++ * tests might choose otherwise */ ++#ifndef KCM_PEER_UID ++#define KCM_PEER_UID 0 ++#endif /* KCM_PEER_UID */ + + /* providers.c */ + int sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq, +-- +2.9.3 + diff --git a/SOURCES/0031-sssctl-Use-localtime-for-time-stamps.patch b/SOURCES/0031-sssctl-Use-localtime-for-time-stamps.patch deleted file mode 100644 index d94a0eb..0000000 --- a/SOURCES/0031-sssctl-Use-localtime-for-time-stamps.patch +++ /dev/null @@ -1,34 +0,0 @@ -From e6cfc113e6f3f7cc1c941d12e0ac7032f19affb9 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Thu, 14 Jul 2016 15:33:19 +0200 -Subject: [PATCH 31/31] sssctl: Use localtime for time stamps -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: -https://fedorahosted.org/sssd/ticket/3096 - -Signed-off-by: Fabiano Fidêncio -Reviewed-by: Pavel Březina -(cherry picked from commit f316e5446313bbf61c96b6763badc21604bff4a3) ---- - src/tools/sssctl/sssctl_cache.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c -index 22e3fad89e3c1bbfce48439b43acd2346da3e56f..4a1f3558ed7064ca40ccf9313d99fbab36e6e4c9 100644 ---- a/src/tools/sssctl/sssctl_cache.c -+++ b/src/tools/sssctl/sssctl_cache.c -@@ -67,7 +67,7 @@ static errno_t time_to_string(TALLOC_CTX *mem_ctx, - char str[255]; - size_t ret; - -- tm = gmtime(×tamp); -+ tm = localtime(×tamp); - if (tm == NULL) { - return ENOMEM; - } --- -2.4.11 - diff --git a/SOURCES/0032-SECRETS-Log-message-for-failures-with-removing-file.patch b/SOURCES/0032-SECRETS-Log-message-for-failures-with-removing-file.patch deleted file mode 100644 index 10627ef..0000000 --- a/SOURCES/0032-SECRETS-Log-message-for-failures-with-removing-file.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 38b3bd9bde495d44283de2b837ab0239140edb3d Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Fri, 22 Jul 2016 09:53:40 +0200 -Subject: [PATCH 32/44] SECRETS: Log message for failures with removing file -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Type: Unchecked return value -Reported by coverity - -Reviewed-by: Petr Čech ---- - src/responder/secrets/local.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c -index 620134ea6b45629114ba795d0e232f414f6e5009..2a85ac06945322265fbd1012c9697728c37b77a0 100644 ---- a/src/responder/secrets/local.c -+++ b/src/responder/secrets/local.c -@@ -624,7 +624,13 @@ int generate_master_key(const char *filename, size_t size) - rsize = sss_atomic_io_s(fd, buf, size, false); - close(fd); - if (rsize != size) { -- unlink(filename); -+ ret = unlink(filename); -+ /* non-fatal failure */ -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Failed to remove file: %s - %d [%s]!\n", -+ filename, ret, sss_strerror(ret)); -+ } - return EFAULT; - } - --- -2.4.11 - diff --git a/SOURCES/0032-TCURL-Support-HTTP-POST-for-creating-containers.patch b/SOURCES/0032-TCURL-Support-HTTP-POST-for-creating-containers.patch new file mode 100644 index 0000000..c94fe07 --- /dev/null +++ b/SOURCES/0032-TCURL-Support-HTTP-POST-for-creating-containers.patch @@ -0,0 +1,129 @@ +From 2777ccdcc9038d8f62be81a24ae885639fe6ea9a Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 14 Mar 2017 15:34:57 +0100 +Subject: [PATCH 32/36] TCURL: Support HTTP POST for creating containers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The curl integration must allow us to create containers, therefore we +also add support of the POST HTTP request type. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + src/tests/intg/test_secrets.py | 28 ++++++++++++++++++++++++++++ + src/tests/tcurl_test_tool.c | 5 +++++ + src/util/tev_curl.c | 7 +++++++ + src/util/tev_curl.h | 1 + + 4 files changed, 41 insertions(+) + +diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py +index cbc1a1f06d2abb826bc0a880cb5a842f577657ea..d71c1904558cc6f8a6eee36c4049582705bc30ac 100644 +--- a/src/tests/intg/test_secrets.py ++++ b/src/tests/intg/test_secrets.py +@@ -271,6 +271,34 @@ def test_curlwrap_crd_ops(setup_for_secrets, + 'http://localhost/secrets/foo'], + 404) + ++ # Create a container ++ run_curlwrap_tool([curlwrap_tool, '-o', ++ '-v', '-s', sock_path, ++ 'http://localhost/secrets/cont/'], ++ 200) ++ ++ # set a secret foo:bar ++ run_curlwrap_tool([curlwrap_tool, '-p', ++ '-v', '-s', sock_path, ++ 'http://localhost/secrets/cont/cfoo', ++ 'foo_under_cont'], ++ 200) ++ ++ # list secrets ++ output = run_curlwrap_tool([curlwrap_tool, ++ '-v', '-s', sock_path, ++ 'http://localhost/secrets/cont/'], ++ 200) ++ assert "cfoo" in output ++ ++ # get the foo secret ++ output = run_curlwrap_tool([curlwrap_tool, ++ '-v', '-s', sock_path, ++ 'http://localhost/secrets/cont/cfoo'], ++ 200) ++ assert "foo_under_cont" in output ++ ++ + + def test_curlwrap_parallel(setup_for_secrets, + curlwrap_tool): +diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c +index 38cea432885c97ca3827c8f158bf7e3ebfc67b31..2af950ebb76a22bdf4a6dfd58442b10486e64293 100644 +--- a/src/tests/tcurl_test_tool.c ++++ b/src/tests/tcurl_test_tool.c +@@ -88,6 +88,7 @@ int main(int argc, const char *argv[]) + { "get", 'g', POPT_ARG_NONE, NULL, 'g', "Perform a HTTP GET (default)", NULL }, + { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL }, + { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, ++ { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL }, + { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "Print response code and body", NULL }, + POPT_TABLEEND + }; +@@ -118,6 +119,9 @@ int main(int argc, const char *argv[]) + case 'd': + req_type = TCURL_HTTP_DELETE; + break; ++ case 'o': ++ req_type = TCURL_HTTP_POST; ++ break; + case 'v': + pc_verbose = 1; + break; +@@ -145,6 +149,7 @@ int main(int argc, const char *argv[]) + switch (req_type) { + case TCURL_HTTP_GET: + case TCURL_HTTP_DELETE: ++ case TCURL_HTTP_POST: + urls[n_reqs++] = extra_arg_ptr; + break; + case TCURL_HTTP_PUT: +diff --git a/src/util/tev_curl.c b/src/util/tev_curl.c +index fd436653b5aeb611a9648a8b81a330fd3fcfe875..645d1182d10f825f209f48e0ba7e6804dde1971c 100644 +--- a/src/util/tev_curl.c ++++ b/src/util/tev_curl.c +@@ -154,6 +154,8 @@ static const char *http_req2str(enum tcurl_http_request req) + return "PUT"; + case TCURL_HTTP_DELETE: + return "DELETE"; ++ case TCURL_HTTP_POST: ++ return "POST"; + } + + return "Uknown request type"; +@@ -815,6 +817,11 @@ static errno_t tcurl_set_options(struct tcurl_http_state *state, + } + + switch (req_type) { ++ case TCURL_HTTP_POST: ++ crv = curl_easy_setopt(state->http_handle, ++ CURLOPT_CUSTOMREQUEST, ++ "POST"); ++ break; + case TCURL_HTTP_PUT: + /* CURLOPT_UPLOAD enables HTTP_PUT */ + crv = curl_easy_setopt(state->http_handle, +diff --git a/src/util/tev_curl.h b/src/util/tev_curl.h +index de0601df4327d97001a8a825cd4709936f6c8466..444eb286e09d189b4588e2b2152b5202df3914d8 100644 +--- a/src/util/tev_curl.h ++++ b/src/util/tev_curl.h +@@ -34,6 +34,7 @@ enum tcurl_http_request { + TCURL_HTTP_GET, + TCURL_HTTP_PUT, + TCURL_HTTP_DELETE, ++ TCURL_HTTP_POST, + }; + + /** +-- +2.9.3 + diff --git a/SOURCES/0033-IPA-fix-capaths-output.patch b/SOURCES/0033-IPA-fix-capaths-output.patch deleted file mode 100644 index f5b2f92..0000000 --- a/SOURCES/0033-IPA-fix-capaths-output.patch +++ /dev/null @@ -1,67 +0,0 @@ -From cf161fe0317fd37e1c5ad826cb783905aaf1f048 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 18 Jul 2016 17:19:36 +0200 -Subject: [PATCH 33/44] IPA: fix [capaths] output - -the capaths for a single domain should be collected in a single -sub-section in the MIT Kerberos configuration not spread over multiple -one. See the capaths section of the krb5.conf man page for details. - -Resolves: -https://fedorahosted.org/sssd/ticket/3103 - -Reviewed-by: Jakub Hrozek ---- - src/util/domain_info_utils.c | 29 ++++++++++++++++++++++++++--- - 1 file changed, 26 insertions(+), 3 deletions(-) - -diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c -index 360f70376c472466168d93d45b6c547d51dd18c6..8cdd50d8d521d734e9ffd9b4e81cd6fbd7d158c7 100644 ---- a/src/util/domain_info_utils.c -+++ b/src/util/domain_info_utils.c -@@ -280,6 +280,7 @@ sss_write_domain_mappings(struct sss_domain_info *domain) - bool capaths_started = false; - char *uc_forest; - char *uc_parent; -+ char *parent_capaths = NULL; - - if (domain == NULL || domain->name == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "No domain name provided\n"); -@@ -399,9 +400,31 @@ sss_write_domain_mappings(struct sss_domain_info *domain) - capaths_started = true; - } - -- ret = fprintf(fstream, "%s = {\n %s = %s\n}\n%s = {\n %s = %s\n}\n", -- dom->realm, uc_parent, uc_forest, -- uc_parent, dom->realm, uc_forest); -+ ret = fprintf(fstream, "%s = {\n %s = %s\n}\n", -+ dom->realm, uc_parent, uc_forest); -+ if (ret < 0) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "fprintf failed\n"); -+ goto done; -+ } -+ -+ if (parent_capaths == NULL) { -+ parent_capaths = talloc_asprintf(tmp_ctx, " %s = %s\n", dom->realm, -+ uc_forest); -+ } else { -+ parent_capaths = talloc_asprintf_append(parent_capaths, -+ " %s = %s\n", dom->realm, -+ uc_forest); -+ } -+ if (parent_capaths == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "talloc_asprintf/talloc_asprintf_append failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ -+ if (parent_capaths != NULL) { -+ ret = fprintf(fstream, "%s = {\n%s}\n", uc_parent, parent_capaths); - if (ret < 0) { - DEBUG(SSSDBG_CRIT_FAILURE, "fprintf failed\n"); - goto done; --- -2.4.11 - diff --git a/SOURCES/0033-KCM-Store-ccaches-in-secrets.patch b/SOURCES/0033-KCM-Store-ccaches-in-secrets.patch new file mode 100644 index 0000000..d08a786 --- /dev/null +++ b/SOURCES/0033-KCM-Store-ccaches-in-secrets.patch @@ -0,0 +1,3787 @@ +From 8c30024303436d98818977288e28511ed74c018a Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 20 Mar 2017 11:49:43 +0100 +Subject: [PATCH 33/36] KCM: Store ccaches in secrets +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Adds a new KCM responder ccache back end that forwards all requests to +sssd-secrets. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + Makefile.am | 40 +- + contrib/sssd.spec.in | 1 + + src/responder/kcm/kcmsrv_ccache.h | 49 + + src/responder/kcm/kcmsrv_ccache_json.c | 921 +++++++++++ + src/responder/kcm/kcmsrv_ccache_secrets.c | 2169 ++++++++++++++++++++++++++ + src/tests/cmocka/test_kcm_json_marshalling.c | 234 +++ + src/tests/intg/test_kcm.py | 132 +- + src/util/util_errors.c | 2 + + src/util/util_errors.h | 2 + + 9 files changed, 3525 insertions(+), 25 deletions(-) + create mode 100644 src/responder/kcm/kcmsrv_ccache_json.c + create mode 100644 src/responder/kcm/kcmsrv_ccache_secrets.c + create mode 100644 src/tests/cmocka/test_kcm_json_marshalling.c + +diff --git a/Makefile.am b/Makefile.am +index 49b4cabf9ee3ce1417f955c972376894f3709b33..e9eaa312c91e3aee40bcf13c90a0ad8c683045d5 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -303,6 +303,10 @@ if HAVE_INOTIFY + non_interactive_cmocka_based_tests += test_inotify + endif # HAVE_INOTIFY + ++if BUILD_KCM ++non_interactive_cmocka_based_tests += test_kcm_json ++endif # BUILD_KCM ++ + if BUILD_SAMBA + non_interactive_cmocka_based_tests += \ + ad_access_filter_tests \ +@@ -1494,19 +1498,26 @@ sssd_kcm_SOURCES = \ + src/responder/kcm/kcmsrv_cmd.c \ + src/responder/kcm/kcmsrv_ccache.c \ + src/responder/kcm/kcmsrv_ccache_mem.c \ ++ src/responder/kcm/kcmsrv_ccache_json.c \ ++ src/responder/kcm/kcmsrv_ccache_secrets.c \ + src/responder/kcm/kcmsrv_ops.c \ + src/util/sss_sockets.c \ + src/util/sss_krb5.c \ + src/util/sss_iobuf.c \ ++ src/util/tev_curl.c \ + $(SSSD_RESPONDER_OBJ) \ + $(NULL) + sssd_kcm_CFLAGS = \ + $(AM_CFLAGS) \ + $(KRB5_CFLAGS) \ + $(UUID_CFLAGS) \ ++ $(CURL_CFLAGS) \ ++ $(JANSSON_CFLAGS) \ + $(NULL) + sssd_kcm_LDADD = \ + $(KRB5_LIBS) \ ++ $(CURL_LIBS) \ ++ $(JANSSON_LIBS) \ + $(SSSD_LIBS) \ + $(UUID_LIBS) \ + $(SYSTEMD_DAEMON_LIBS) \ +@@ -3369,6 +3380,30 @@ sss_certmap_test_LDADD = \ + libsss_certmap.la \ + $(NULL) + endif ++ ++if BUILD_KCM ++test_kcm_json_SOURCES = \ ++ src/tests/cmocka/test_kcm_json_marshalling.c \ ++ src/responder/kcm/kcmsrv_ccache_json.c \ ++ src/responder/kcm/kcmsrv_ccache.c \ ++ src/util/sss_krb5.c \ ++ src/util/sss_iobuf.c \ ++ $(NULL) ++test_kcm_json_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(UUID_CFLAGS) \ ++ $(NULL) ++test_kcm_json_LDADD = \ ++ $(JANSSON_LIBS) \ ++ $(UUID_LIBS) \ ++ $(KRB5_LIBS) \ ++ $(CMOCKA_LIBS) \ ++ $(SSSD_LIBS) \ ++ $(SSSD_INTERNAL_LTLIBS) \ ++ libsss_test_common.la \ ++ $(NULL) ++endif # BUILD_KCM ++ + endif # HAVE_CMOCKA + + noinst_PROGRAMS = pam_test_client +@@ -3431,8 +3466,9 @@ intgcheck-prepare: + --enable-intgcheck-reqs \ + --without-semanage \ + --enable-files-domain \ +- $(INTGCHECK_CONFIGURE_FLAGS); \ +- $(MAKE) $(AM_MAKEFLAGS); \ ++ $(INTGCHECK_CONFIGURE_FLAGS) \ ++ CFLAGS="$$CFLAGS $(AM_CFLAGS) -DKCM_PEER_UID=$$(id -u)"; \ ++ $(MAKE) $(AM_MAKEFLAGS) ; \ + : Force single-thread install to workaround concurrency issues; \ + $(MAKE) $(AM_MAKEFLAGS) -j1 install; \ + : Remove .la files from LDB module directory to avoid loader warnings; \ +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index 1d4d020415ee28292bb4d88c78de205465d812f1..af14d4e3d6b9ffeb4696f1517113b8daa575cb99 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -223,6 +223,7 @@ BuildRequires: systemtap-sdt-devel + BuildRequires: http-parser-devel + BuildRequires: jansson-devel + BuildRequires: libuuid-devel ++BuildRequires: libcurl-devel + + %description + Provides a set of daemons to manage access to remote directories and +diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h +index 130ae48ae30d5e1e2ab238a647a9b9dc76cc4945..18c8c47ad4ecb24521a85a1833b239c7a2a8bb45 100644 +--- a/src/responder/kcm/kcmsrv_ccache.h ++++ b/src/responder/kcm/kcmsrv_ccache.h +@@ -303,4 +303,53 @@ void kcm_debug_uuid(uuid_t uuid); + */ + errno_t kcm_check_name(const char *name, struct cli_creds *client); + ++/* ++ * ccahe marshalling to and from JSON. This is used when the ccaches ++ * are stored in the secrets store ++ */ ++ ++/* ++ * The secrets store is a key-value store at heart. We store the UUID ++ * and the name in the key to allow easy lookups be either key ++ */ ++bool sec_key_match_name(const char *sec_key, ++ const char *name); ++ ++bool sec_key_match_uuid(const char *sec_key, ++ uuid_t uuid); ++ ++const char *sec_key_get_name(const char *sec_key); ++ ++errno_t sec_key_get_uuid(const char *sec_key, ++ uuid_t uuid); ++ ++/* Create a URL for the default client's ccache */ ++const char *sec_dfl_url_create(TALLOC_CTX *mem_ctx, ++ struct cli_creds *client); ++ ++/* Create a URL for the client's ccache container */ ++const char *sec_container_url_create(TALLOC_CTX *mem_ctx, ++ struct cli_creds *client); ++ ++const char *sec_cc_url_create(TALLOC_CTX *mem_ctx, ++ struct cli_creds *client, ++ const char *sec_key); ++ ++/* ++ * sec_key is a concatenation of the ccache's UUID and name ++ * sec_value is the JSON dump of the ccache contents ++ */ ++errno_t sec_kv_to_ccache(TALLOC_CTX *mem_ctx, ++ const char *sec_key, ++ const char *sec_value, ++ struct cli_creds *client, ++ struct kcm_ccache **_cc); ++ ++/* Convert a kcm_ccache to a key-value pair to be stored in secrets */ ++errno_t kcm_ccache_to_sec_input(TALLOC_CTX *mem_ctx, ++ struct kcm_ccache *cc, ++ struct cli_creds *client, ++ const char **_url, ++ struct sss_iobuf **_payload); ++ + #endif /* _KCMSRV_CCACHE_H_ */ +diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c +new file mode 100644 +index 0000000000000000000000000000000000000000..40b64861c209206d6f60ccd0843857edee24a844 +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_ccache_json.c +@@ -0,0 +1,921 @@ ++/* ++ SSSD ++ ++ KCM Server - ccache JSON (un)marshalling for storing ccaches in ++ sssd-secrets ++ ++ Copyright (C) Red Hat, 2017 ++ ++ 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 . ++*/ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++ ++#include "util/util.h" ++#include "util/util_creds.h" ++#include "util/crypto/sss_crypto.h" ++#include "responder/kcm/kcmsrv_ccache_pvt.h" ++ ++/* The base for storing secrets is: ++ * http://localhost/kcm/persistent/$uid ++ * ++ * Under $base, there are two containers: ++ * /ccache - stores the ccaches ++ * /ntlm - stores NTLM creds [Not implement yet] ++ * ++ * There is also a special entry that contains the UUID of the default ++ * cache for this UID: ++ * /default - stores the UUID of the default ccache for this UID ++ * ++ * Each ccache has a name and an UUID. On the secrets level, the 'secret' ++ * is a concatenation of the stringified UUID and the name separated ++ * by a plus-sign. ++ */ ++#define KCM_SEC_URL "http://localhost/kcm/persistent" ++#define KCM_SEC_BASE_FMT KCM_SEC_URL"/%"SPRIuid"/" ++#define KCM_SEC_CCACHE_FMT KCM_SEC_BASE_FMT"ccache/" ++#define KCM_SEC_DFL_FMT KCM_SEC_BASE_FMT"default" ++ ++ ++/* ++ * We keep the JSON representation of the ccache versioned to allow ++ * us to modify the format in a future version ++ */ ++#define KS_JSON_VERSION 1 ++ ++/* ++ * The secrets store is a key-value store at heart. We store the UUID ++ * and the name in the key to allow easy lookups be either key ++ */ ++#define SEC_KEY_SEPARATOR '-' ++ ++/* Compat definition of json_array_foreach for older systems */ ++#ifndef json_array_foreach ++#define json_array_foreach(array, idx, value) \ ++ for(idx = 0; \ ++ idx < json_array_size(array) && (value = json_array_get(array, idx)); \ ++ idx++) ++#endif ++ ++const char *sec_container_url_create(TALLOC_CTX *mem_ctx, ++ struct cli_creds *client) ++{ ++ return talloc_asprintf(mem_ctx, ++ KCM_SEC_CCACHE_FMT, ++ cli_creds_get_uid(client)); ++} ++ ++const char *sec_cc_url_create(TALLOC_CTX *mem_ctx, ++ struct cli_creds *client, ++ const char *sec_key) ++{ ++ return talloc_asprintf(mem_ctx, ++ KCM_SEC_CCACHE_FMT"%s", ++ cli_creds_get_uid(client), ++ sec_key); ++} ++ ++const char *sec_dfl_url_create(TALLOC_CTX *mem_ctx, ++ struct cli_creds *client) ++{ ++ return talloc_asprintf(mem_ctx, ++ KCM_SEC_DFL_FMT, ++ cli_creds_get_uid(client)); ++} ++ ++static const char *sec_key_create(TALLOC_CTX *mem_ctx, ++ const char *name, ++ uuid_t uuid) ++{ ++ char uuid_str[UUID_STR_SIZE]; ++ ++ uuid_unparse(uuid, uuid_str); ++ return talloc_asprintf(mem_ctx, ++ "%s%c%s", uuid_str, SEC_KEY_SEPARATOR, name); ++} ++ ++static errno_t sec_key_parse(TALLOC_CTX *mem_ctx, ++ const char *sec_key, ++ const char **_name, ++ uuid_t uuid) ++{ ++ char uuid_str[UUID_STR_SIZE]; ++ ++ if (strlen(sec_key) < UUID_STR_SIZE + 2) { ++ /* One char for separator and at least one for the name */ ++ DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); ++ return EINVAL; ++ } ++ ++ strncpy(uuid_str, sec_key, sizeof(uuid_str)-1); ++ if (sec_key[UUID_STR_SIZE - 1] != SEC_KEY_SEPARATOR) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n"); ++ return EINVAL; ++ } ++ uuid_str[UUID_STR_SIZE-1] = '\0'; ++ ++ *_name = talloc_strdup(mem_ctx, sec_key + UUID_STR_SIZE); ++ if (*_name == NULL) { ++ return ENOMEM; ++ } ++ uuid_parse(uuid_str, uuid); ++ ++ return EOK; ++} ++ ++errno_t sec_key_get_uuid(const char *sec_key, ++ uuid_t uuid) ++{ ++ char uuid_str[UUID_STR_SIZE]; ++ ++ if (strlen(sec_key) < UUID_STR_SIZE + 2) { ++ /* One char for separator and at least one for the name */ ++ DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); ++ return EINVAL; ++ } ++ ++ if (sec_key[UUID_STR_SIZE-1] != SEC_KEY_SEPARATOR) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n"); ++ return EINVAL; ++ } ++ ++ strncpy(uuid_str, sec_key, UUID_STR_SIZE-1); ++ uuid_str[UUID_STR_SIZE-1] = '\0'; ++ uuid_parse(uuid_str, uuid); ++ return EOK; ++} ++ ++const char *sec_key_get_name(const char *sec_key) ++{ ++ if (strlen(sec_key) < UUID_STR_SIZE + 2) { ++ /* One char for separator and at least one for the name */ ++ DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); ++ return NULL; ++ } ++ ++ return sec_key + UUID_STR_SIZE; ++} ++ ++bool sec_key_match_name(const char *sec_key, ++ const char *name) ++{ ++ if (strlen(sec_key) < UUID_STR_SIZE + 2) { ++ /* One char for separator and at least one for the name */ ++ DEBUG(SSSDBG_MINOR_FAILURE, "Key %s is too short\n", sec_key); ++ return false; ++ } ++ ++ return strcmp(sec_key + UUID_STR_SIZE, name) == 0; ++} ++ ++bool sec_key_match_uuid(const char *sec_key, ++ uuid_t uuid) ++{ ++ errno_t ret; ++ uuid_t key_uuid; ++ ++ ret = sec_key_get_uuid(sec_key, key_uuid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot convert key to UUID\n"); ++ return false; ++ } ++ ++ return uuid_compare(key_uuid, uuid) == 0; ++} ++ ++/* ++ * Creates an array of principal elements that will be used later ++ * in the form of: ++ * "componenets": [ "elem1", "elem2", ...] ++ */ ++static json_t *princ_data_to_json(TALLOC_CTX *mem_ctx, ++ krb5_principal princ) ++{ ++ json_t *jdata = NULL; ++ json_t *data_array = NULL; ++ int ret; ++ char *str_princ_data; ++ ++ data_array = json_array(); ++ if (data_array == NULL) { ++ return NULL; ++ } ++ ++ for (ssize_t i = 0; i < princ->length; i++) { ++ /* FIXME - it might be cleaner to use stringn here, but the libjansson ++ * version on RHEL-7 doesn't support that ++ */ ++ str_princ_data = talloc_zero_array(mem_ctx, ++ char, ++ princ->data[i].length + 1); ++ if (str_princ_data == NULL) { ++ return NULL; ++ } ++ memcpy(str_princ_data, princ->data[i].data, princ->data[i].length); ++ str_princ_data[princ->data[i].length] = '\0'; ++ ++ jdata = json_string(str_princ_data); ++ talloc_free(str_princ_data); ++ if (jdata == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot convert principal data to string\n"); ++ json_decref(data_array); ++ return NULL; ++ } ++ ++ ret = json_array_append_new(data_array, jdata); ++ if (ret != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot append principal data to array\n"); ++ json_decref(jdata); ++ json_decref(data_array); ++ return NULL; ++ } ++ /* data_array now owns the reference to jdata */ ++ } ++ ++ return data_array; ++} ++ ++/* Creates: ++ * { ++ * "type": "number", ++ * "realm": "string", ++ * "componenents": [ "elem1", "elem2", ...] ++ * } ++ */ ++static json_t *princ_to_json(TALLOC_CTX *mem_ctx, ++ krb5_principal princ) ++{ ++ json_t *jprinc = NULL; ++ json_t *components = NULL; ++ json_error_t error; ++ char *str_realm_data; ++ ++ components = princ_data_to_json(mem_ctx, princ); ++ if (components == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot convert principal data to JSON\n"); ++ return NULL; ++ } ++ ++ /* FIXME - it might be cleaner to use the s% specifier here, but the libjansson ++ * version on RHEL-7 doesn't support that ++ */ ++ str_realm_data = talloc_zero_array(mem_ctx, ++ char, ++ princ->realm.length + 1); ++ if (str_realm_data == NULL) { ++ return NULL; ++ } ++ memcpy(str_realm_data, princ->realm.data, princ->realm.length); ++ str_realm_data[princ->realm.length] = '\0'; ++ ++ jprinc = json_pack_ex(&error, ++ JSON_STRICT, ++ "{s:i, s:s, s:o}", ++ "type", princ->type, ++ "realm", str_realm_data, ++ "components", components); ++ talloc_free(str_realm_data); ++ if (jprinc == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to pack JSON princ structure on line %d: %s\n", ++ error.line, error.text); ++ json_decref(components); ++ return NULL; ++ } ++ ++ return jprinc; ++} ++ ++/* Creates: ++ * { ++ * "uuid": , ++ * "payload": , ++ * }, ++ */ ++static json_t *cred_to_json(struct kcm_cred *crd) ++{ ++ char uuid_str[UUID_STR_SIZE]; ++ uint8_t *cred_blob_data; ++ size_t cred_blob_size; ++ json_t *jcred; ++ json_error_t error; ++ char *base64_cred_blob; ++ ++ uuid_unparse(crd->uuid, uuid_str); ++ cred_blob_data = sss_iobuf_get_data(crd->cred_blob); ++ cred_blob_size = sss_iobuf_get_size(crd->cred_blob); ++ ++ base64_cred_blob = sss_base64_encode(crd, cred_blob_data, cred_blob_size); ++ if (base64_cred_blob == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot base64 encode the certificate blob\n"); ++ return NULL; ++ } ++ ++ jcred = json_pack_ex(&error, ++ JSON_STRICT, ++ "{s:s, s:s}", ++ "uuid", uuid_str, ++ "payload", base64_cred_blob); ++ talloc_free(base64_cred_blob); ++ if (jcred == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to pack JSON cred structure on line %d: %s\n", ++ error.line, error.text); ++ return NULL; ++ } ++ return jcred; ++} ++ ++/* ++ * Creates: ++ * [ ++ * { ++ * "uuid": , ++ * "payload": , ++ * }, ++ * ... ++ * ] ++ */ ++static json_t *creds_to_json_array(struct kcm_cred *creds) ++{ ++ struct kcm_cred *crd; ++ json_t *array; ++ json_t *jcred; ++ ++ array = json_array(); ++ if (array == NULL) { ++ return NULL; ++ } ++ ++ DLIST_FOR_EACH(crd, creds) { ++ jcred = cred_to_json(crd); ++ if (jcred == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot convert credentials to JSON\n"); ++ json_decref(array); ++ return NULL; ++ } ++ ++ json_array_append_new(array, jcred); ++ /* array now owns jcred */ ++ jcred = NULL; ++ } ++ ++ return array; ++} ++ ++/* ++ * The ccache is formatted in JSON as: ++ * { ++ * version: number ++ * kdc_offset: number ++ * principal : { ++ * "type": "number", ++ * "realm": "string", ++ * "componenents": [ "elem1", "elem2", ...] ++ * } ++ * creds : [ ++ * { ++ * "uuid": , ++ * "payload": , ++ * }, ++ * { ++ * ... ++ * } ++ * ] ++ * } ++ * } ++ */ ++static json_t *ccache_to_json(struct kcm_ccache *cc) ++{ ++ json_t *princ = NULL; ++ json_t *creds = NULL; ++ json_t *jcc = NULL; ++ json_error_t error; ++ ++ princ = princ_to_json(cc, cc->client); ++ if (princ == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot convert princ to JSON\n"); ++ return NULL; ++ } ++ ++ creds = creds_to_json_array(cc->creds); ++ if (creds == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot convert creds to JSON array\n"); ++ json_decref(princ); ++ return NULL; ++ } ++ ++ jcc = json_pack_ex(&error, ++ JSON_STRICT, ++ "{s:i, s:i, s:o, s:o}", ++ "version", KS_JSON_VERSION, ++ "kdc_offset", cc->kdc_offset, ++ "principal", princ, ++ "creds", creds); ++ if (jcc == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to pack JSON ccache structure on line %d: %s\n", ++ error.line, error.text); ++ json_decref(creds); ++ json_decref(princ); ++ return NULL; ++ } ++ ++ return jcc; ++} ++ ++static errno_t ccache_to_sec_kv(TALLOC_CTX *mem_ctx, ++ struct kcm_ccache *cc, ++ const char **_sec_key, ++ const char **_sec_value) ++{ ++ json_t *jcc = NULL; ++ char *jdump; ++ ++ jcc = ccache_to_json(cc); ++ if (jcc == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot convert ccache to JSON\n"); ++ return ERR_JSON_ENCODING; ++ } ++ ++ /* it would be more efficient to learn the size with json_dumpb and ++ * a NULL buffer, but that's only available since 2.10 ++ */ ++ jdump = json_dumps(jcc, JSON_INDENT(4) | JSON_ENSURE_ASCII); ++ if (jdump == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot dump JSON\n"); ++ return ERR_JSON_ENCODING; ++ } ++ ++ *_sec_key = sec_key_create(mem_ctx, cc->name, cc->uuid); ++ *_sec_value = talloc_strdup(mem_ctx, jdump); ++ free(jdump); ++ json_decref(jcc); ++ if (*_sec_key == NULL || *_sec_value == NULL) { ++ return ENOMEM; ++ } ++ ++ return EOK; ++} ++ ++errno_t kcm_ccache_to_sec_input(TALLOC_CTX *mem_ctx, ++ struct kcm_ccache *cc, ++ struct cli_creds *client, ++ const char **_url, ++ struct sss_iobuf **_payload) ++{ ++ errno_t ret; ++ const char *key; ++ const char *value; ++ const char *url; ++ struct sss_iobuf *payload; ++ TALLOC_CTX *tmp_ctx; ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = ccache_to_sec_kv(mem_ctx, cc, &key, &value); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot convert cache %s to JSON [%d]: %s\n", ++ cc->name, ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ url = sec_cc_url_create(tmp_ctx, client, key); ++ if (url == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ payload = sss_iobuf_init_readonly(tmp_ctx, ++ (const uint8_t *) value, ++ strlen(value)+1); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot create payload buffer\n"); ++ goto done; ++ } ++ ++ ret = EOK; ++ *_url = talloc_steal(mem_ctx, url); ++ *_payload = talloc_steal(mem_ctx, payload); ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t sec_value_to_json(const char *input, ++ json_t **_root) ++{ ++ json_t *root = NULL; ++ json_error_t error; ++ int ok; ++ ++ root = json_loads(input, 0, &error); ++ if (root == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to parse JSON payload on line %d: %s\n", ++ error.line, error.text); ++ return ERR_JSON_DECODING; ++ } ++ ++ ok = json_is_object(root); ++ if (!ok) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Json data is not an object.\n"); ++ json_decref(root); ++ return ERR_JSON_DECODING; ++ } ++ ++ *_root = root; ++ return EOK; ++} ++ ++/* ++ * ccache unmarshalling from JSON ++ */ ++static errno_t json_element_to_krb5_data(TALLOC_CTX *mem_ctx, ++ json_t *element, ++ krb5_data *data) ++{ ++ const char *str_value; ++ size_t str_len; ++ ++ /* FIXME - it might be cleaner to use stringn here, but the libjansson ++ * version on RHEL-7 doesn't support that ++ */ ++ str_value = json_string_value(element); ++ if (str_value == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "JSON element not a string\n"); ++ return EINVAL; ++ } ++ str_len = strlen(str_value); ++ ++ data->data = talloc_strndup(mem_ctx, str_value, str_len); ++ if (data->data == NULL) { ++ return ENOMEM; ++ } ++ data->length = str_len; ++ ++ return EOK; ++} ++ ++static errno_t json_array_to_krb5_data(TALLOC_CTX *mem_ctx, ++ json_t *array, ++ krb5_data **_data, ++ size_t *_len) ++{ ++ errno_t ret; ++ int ok; ++ size_t len; ++ size_t idx; ++ json_t *element; ++ krb5_data *data; ++ ++ ok = json_is_array(array); ++ if (!ok) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Json object is not an array.\n"); ++ return ERR_JSON_DECODING; ++ } ++ ++ len = json_array_size(array); ++ if (len == 0) { ++ *_data = NULL; ++ *_len = 0; ++ return EOK; ++ } ++ ++ data = talloc_zero_array(mem_ctx, krb5_data, len); ++ if (data == NULL) { ++ return ENOMEM; ++ } ++ ++ json_array_foreach(array, idx, element) { ++ ret = json_element_to_krb5_data(data, element, &data[idx]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot convert krb5 data element from JSON"); ++ talloc_free(data); ++ return ret; ++ } ++ } ++ ++ *_data = data; ++ *_len = len; ++ return EOK; ++} ++ ++static errno_t json_to_princ(TALLOC_CTX *mem_ctx, ++ json_t *js_princ, ++ krb5_principal *_princ) ++{ ++ errno_t ret; ++ json_t *components = NULL; ++ int ok; ++ krb5_principal princ = NULL; ++ TALLOC_CTX *tmp_ctx = NULL; ++ char *realm_str; ++ size_t realm_size; ++ json_error_t error; ++ ++ ok = json_is_object(js_princ); ++ if (!ok) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Json principal is not an object.\n"); ++ ret = ERR_JSON_DECODING; ++ goto done; ++ } ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ princ = talloc_zero(tmp_ctx, struct krb5_principal_data); ++ if (princ == NULL) { ++ return ENOMEM; ++ } ++ princ->magic = KV5M_PRINCIPAL; ++ ++ /* FIXME - it might be cleaner to use the s% specifier here, but the libjansson ++ * version on RHEL-7 doesn't support that ++ */ ++ ret = json_unpack_ex(js_princ, ++ &error, ++ JSON_STRICT, ++ "{s:i, s:s, s:o}", ++ "type", &princ->type, ++ "realm", &realm_str, ++ "components", &components); ++ if (ret != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to unpack JSON princ structure on line %d: %s\n", ++ error.line, error.text); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ realm_size = strlen(realm_str); ++ ++ princ->realm.data = talloc_strndup(mem_ctx, realm_str, realm_size); ++ if (princ->realm.data == NULL) { ++ return ENOMEM; ++ } ++ princ->realm.length = realm_size; ++ princ->realm.magic = 0; ++ ++ ret = json_array_to_krb5_data(princ, components, ++ &princ->data, ++ (size_t *) &princ->length); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot convert principal from JSON"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ *_princ = talloc_steal(mem_ctx, princ); ++ ret = EOK; ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t json_elem_to_cred(TALLOC_CTX *mem_ctx, ++ json_t *element, ++ struct kcm_cred **_crd) ++{ ++ errno_t ret; ++ char *uuid_str; ++ json_error_t error; ++ uuid_t uuid; ++ struct sss_iobuf *cred_blob; ++ const char *base64_cred_blob; ++ struct kcm_cred *crd; ++ uint8_t *outbuf; ++ size_t outbuf_size; ++ TALLOC_CTX *tmp_ctx = NULL; ++ ++ ret = json_unpack_ex(element, ++ &error, ++ JSON_STRICT, ++ "{s:s, s:s}", ++ "uuid", &uuid_str, ++ "payload", &base64_cred_blob); ++ if (ret != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to unpack JSON cred structure on line %d: %s\n", ++ error.line, error.text); ++ return EINVAL; ++ } ++ ++ uuid_parse(uuid_str, uuid); ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ outbuf = sss_base64_decode(tmp_ctx, base64_cred_blob, &outbuf_size); ++ if (outbuf == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot decode cred blob\n"); ++ ret = EIO; ++ goto done; ++ } ++ ++ cred_blob = sss_iobuf_init_readonly(tmp_ctx, outbuf, outbuf_size); ++ if (cred_blob == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ crd = kcm_cred_new(tmp_ctx, uuid, cred_blob); ++ if (crd == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = EOK; ++ *_crd = talloc_steal(mem_ctx, crd); ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t json_to_creds(struct kcm_ccache *cc, ++ json_t *jcreds) ++{ ++ errno_t ret; ++ int ok; ++ size_t idx; ++ json_t *value; ++ struct kcm_cred *crd; ++ ++ ok = json_is_array(jcreds); ++ if (!ok) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Json creds object is not an array.\n"); ++ return ERR_JSON_DECODING; ++ } ++ ++ json_array_foreach(jcreds, idx, value) { ++ ret = json_elem_to_cred(cc, value, &crd); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot convert JSON cred element [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ ret = kcm_cc_store_creds(cc, crd); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot store creds in ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return ret; ++ } ++ } ++ ++ return EOK; ++} ++ ++static errno_t sec_json_value_to_ccache(struct kcm_ccache *cc, ++ json_t *root) ++{ ++ errno_t ret; ++ json_t *princ = NULL; ++ json_t *creds = NULL; ++ json_error_t error; ++ int version; ++ ++ ret = json_unpack_ex(root, ++ &error, ++ JSON_STRICT, ++ "{s:i, s:i, s:o, s:o}", ++ "version", &version, ++ "kdc_offset", &cc->kdc_offset, ++ "principal", &princ, ++ "creds", &creds); ++ if (ret != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to unpack JSON creds structure on line %d: %s\n", ++ error.line, error.text); ++ return EINVAL; ++ } ++ ++ if (version != KS_JSON_VERSION) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Expected version %d, received version %d\n", ++ KS_JSON_VERSION, version); ++ return EINVAL; ++ } ++ ++ ret = json_to_princ(cc, princ, &cc->client); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot store JSON to principal [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ ret = json_to_creds(cc, creds); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot store JSON to creds [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return EOK; ++ } ++ ++ return EOK; ++} ++ ++/* ++ * sec_key is a concatenation of the ccache's UUID and name ++ * sec_value is the JSON dump of the ccache contents ++ */ ++errno_t sec_kv_to_ccache(TALLOC_CTX *mem_ctx, ++ const char *sec_key, ++ const char *sec_value, ++ struct cli_creds *client, ++ struct kcm_ccache **_cc) ++{ ++ errno_t ret; ++ json_t *root = NULL; ++ struct kcm_ccache *cc = NULL; ++ TALLOC_CTX *tmp_ctx = NULL; ++ ++ ret = sec_value_to_json(sec_value, &root); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot store secret to JSN [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ cc = talloc_zero(tmp_ctx, struct kcm_ccache); ++ if (cc == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* We rely on sssd-secrets only searching the user's subtree so we ++ * set the ownership to the client ++ */ ++ cc->owner.uid = cli_creds_get_uid(client); ++ cc->owner.gid = cli_creds_get_gid(client); ++ ++ ret = sec_key_parse(cc, sec_key, &cc->name, cc->uuid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannt parse secret key [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sec_json_value_to_ccache(cc, root); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannt parse secret value [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = EOK; ++ *_cc = talloc_steal(mem_ctx, cc); ++done: ++ talloc_free(tmp_ctx); ++ json_decref(root); ++ return ret; ++} +diff --git a/src/responder/kcm/kcmsrv_ccache_secrets.c b/src/responder/kcm/kcmsrv_ccache_secrets.c +new file mode 100644 +index 0000000000000000000000000000000000000000..8be7daea59bd6e04ab8393aae9f8adc29df11c21 +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_ccache_secrets.c +@@ -0,0 +1,2169 @@ ++/* ++ SSSD ++ ++ KCM Server - ccache storage in sssd-secrets ++ ++ Copyright (C) Red Hat, 2016 ++ ++ 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 . ++*/ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++ ++#include "util/util.h" ++#include "util/crypto/sss_crypto.h" ++#include "util/tev_curl.h" ++#include "responder/kcm/kcmsrv_ccache_pvt.h" ++#include "responder/kcm/kcmsrv_ccache_be.h" ++ ++#ifndef SSSD_SECRETS_SOCKET ++#define SSSD_SECRETS_SOCKET VARDIR"/run/secrets.socket" ++#endif /* SSSD_SECRETS_SOCKET */ ++ ++#ifndef SEC_TIMEOUT ++#define SEC_TIMEOUT 5 ++#endif /* SEC_TIMEOUT */ ++ ++/* Just to keep the name of the ccache readable */ ++#define MAX_CC_NUM 99999 ++ ++/* Compat definition of json_array_foreach for older systems */ ++#ifndef json_array_foreach ++#define json_array_foreach(array, idx, value) \ ++ for(idx = 0; \ ++ idx < json_array_size(array) && (value = json_array_get(array, idx)); \ ++ idx++) ++#endif ++ ++static const char *find_by_name(const char **sec_key_list, ++ const char *name) ++{ ++ const char *sec_name = NULL; ++ ++ if (sec_key_list == NULL) { ++ return NULL; ++ } ++ ++ for (int i = 0; sec_key_list[i]; i++) { ++ if (sec_key_match_name(sec_key_list[i], name)) { ++ sec_name = sec_key_list[i]; ++ break; ++ } ++ } ++ ++ return sec_name; ++} ++ ++static const char *find_by_uuid(const char **sec_key_list, ++ uuid_t uuid) ++{ ++ const char *sec_name = NULL; ++ ++ if (sec_key_list == NULL) { ++ return NULL; ++ } ++ ++ for (int i = 0; sec_key_list[i]; i++) { ++ if (sec_key_match_uuid(sec_key_list[i], uuid)) { ++ sec_name = sec_key_list[i]; ++ break; ++ } ++ } ++ ++ return sec_name; ++} ++ ++static const char *sec_headers[] = { ++ "Content-type: application/octet-stream", ++ NULL, ++}; ++ ++struct ccdb_sec { ++ struct tcurl_ctx *tctx; ++}; ++ ++static errno_t http2errno(int http_code) ++{ ++ if (http_code != 200) { ++ DEBUG(SSSDBG_OP_FAILURE, "HTTP request returned %d\n", http_code); ++ } ++ ++ switch (http_code) { ++ case 200: ++ return EOK; ++ case 404: ++ return ERR_NO_CREDS; ++ case 400: ++ return ERR_INPUT_PARSE; ++ case 403: ++ return EACCES; ++ case 409: ++ return EEXIST; ++ case 413: ++ return E2BIG; ++ case 507: ++ return ENOSPC; ++ } ++ ++ return EIO; ++} ++ ++/* ++ * Helper request to list all UUID+name pairs ++ */ ++struct sec_list_state { ++ const char **sec_key_list; ++ size_t sec_key_list_len; ++}; ++ ++static void sec_list_done(struct tevent_req *subreq); ++static errno_t sec_list_parse(struct sss_iobuf *outbuf, ++ TALLOC_CTX *mem_ctx, ++ const char ***_list, ++ size_t *_list_len); ++ ++static struct tevent_req *sec_list_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ccdb_sec *secdb, ++ struct cli_creds *client) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct sec_list_state *state = NULL; ++ errno_t ret; ++ const char *container_url; ++ ++ req = tevent_req_create(mem_ctx, &state, struct sec_list_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Listing all ccaches in the secrets store\n"); ++ container_url = sec_container_url_create(state, client); ++ if (container_url == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ subreq = tcurl_http_send(state, ev, secdb->tctx, ++ TCURL_HTTP_GET, ++ SSSD_SECRETS_SOCKET, ++ container_url, ++ sec_headers, ++ NULL, ++ SEC_TIMEOUT); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, sec_list_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void sec_list_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); ++ struct sec_list_state *state = tevent_req_data(req, ++ struct sec_list_state); ++ struct sss_iobuf *outbuf; ++ int http_code; ++ ++ ret = tcurl_http_recv(state, subreq, &http_code, &outbuf); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "list HTTP request failed [%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (http_code == 404) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Nothing to list\n"); ++ /* If no ccaches are found, return an empty list */ ++ state->sec_key_list = talloc_zero_array(state, const char *, 1); ++ if (state->sec_key_list == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ } else if (http_code == 200) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Found %zu items\n", state->sec_key_list_len); ++ ret = sec_list_parse(outbuf, state, ++ &state->sec_key_list, ++ &state->sec_key_list_len); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ } else { ++ tevent_req_error(req, http2errno(http_code)); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "list done\n"); ++ tevent_req_done(req); ++} ++ ++static errno_t sec_list_parse(struct sss_iobuf *outbuf, ++ TALLOC_CTX *mem_ctx, ++ const char ***_list, ++ size_t *_list_len) ++{ ++ json_t *root; ++ uint8_t *sec_http_list; ++ json_error_t error; ++ json_t *element; ++ errno_t ret; ++ int ok; ++ size_t idx; ++ const char **list = NULL; ++ size_t list_len; ++ ++ sec_http_list = sss_iobuf_get_data(outbuf); ++ if (sec_http_list == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "No data in output buffer?\n"); ++ return EINVAL; ++ } ++ ++ root = json_loads((const char *) sec_http_list, 0, &error); ++ if (root == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to parse JSON payload on line %d: %s\n", ++ error.line, error.text); ++ return ERR_JSON_DECODING; ++ } ++ ++ ok = json_is_array(root); ++ if (!ok) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "list reply is not an object.\n"); ++ ret = ERR_JSON_DECODING; ++ goto done; ++ } ++ ++ list_len = json_array_size(root); ++ list = talloc_zero_array(mem_ctx, const char *, list_len + 1); ++ if (list == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ json_array_foreach(root, idx, element) { ++ list[idx] = talloc_strdup(list, json_string_value(element)); ++ if (list[idx] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ ret = EOK; ++ *_list = list; ++ *_list_len = list_len; ++done: ++ if (ret != EOK) { ++ talloc_free(list); ++ } ++ json_decref(root); ++ return ret; ++} ++ ++static errno_t sec_list_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ const char ***_sec_key_list, ++ size_t *_sec_key_list_len) ++ ++{ ++ struct sec_list_state *state = tevent_req_data(req, ++ struct sec_list_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ if (_sec_key_list != NULL) { ++ *_sec_key_list = talloc_steal(mem_ctx, state->sec_key_list); ++ } ++ if (_sec_key_list_len != NULL) { ++ *_sec_key_list_len = state->sec_key_list_len; ++ } ++ return EOK; ++} ++ ++/* ++ * Helper request to get a ccache by key ++ */ ++struct sec_get_state { ++ const char *sec_key; ++ struct cli_creds *client; ++ ++ struct kcm_ccache *cc; ++}; ++ ++static void sec_get_done(struct tevent_req *subreq); ++ ++static struct tevent_req *sec_get_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ccdb_sec *secdb, ++ struct cli_creds *client, ++ const char *sec_key) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct sec_get_state *state = NULL; ++ errno_t ret; ++ const char *cc_url; ++ ++ req = tevent_req_create(mem_ctx, &state, struct sec_get_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->sec_key = sec_key; ++ state->client = client; ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Retrieving ccache %s\n", sec_key); ++ ++ cc_url = sec_cc_url_create(state, state->client, state->sec_key); ++ if (cc_url == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ subreq = tcurl_http_send(state, ++ ev, ++ secdb->tctx, ++ TCURL_HTTP_GET, ++ SSSD_SECRETS_SOCKET, ++ cc_url, ++ sec_headers, ++ NULL, ++ SEC_TIMEOUT); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, sec_get_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void sec_get_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); ++ struct sec_get_state *state = tevent_req_data(req, ++ struct sec_get_state); ++ struct sss_iobuf *outbuf; ++ const char *sec_value; ++ int http_code; ++ ++ ret = tcurl_http_recv(state, subreq, &http_code, &outbuf); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "GET HTTP request failed [%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (http_code != 200) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "GET operation returned HTTP error %d\n", http_code); ++ ret = http2errno(http_code); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ sec_value = (const char *) sss_iobuf_get_data(outbuf); ++ if (sec_value == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "No data in output buffer\n"); ++ tevent_req_error(req, EINVAL); ++ return; ++ } ++ ++ ret = sec_kv_to_ccache(state, ++ state->sec_key, ++ sec_value, ++ state->client, ++ &state->cc); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot convert JSON keyval to ccache blob [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "GET done\n"); ++ tevent_req_done(req); ++} ++ ++static errno_t sec_get_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ccache **_cc) ++{ ++ struct sec_get_state *state = tevent_req_data(req, struct sec_get_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_cc = talloc_steal(mem_ctx, state->cc); ++ return EOK; ++} ++ ++/* ++ * Helper request to get a ccache name or ID ++ */ ++struct sec_get_ccache_state { ++ struct tevent_context *ev; ++ struct ccdb_sec *secdb; ++ struct cli_creds *client; ++ const char *name; ++ uuid_t uuid; ++ ++ const char *sec_key; ++ ++ struct kcm_ccache *cc; ++}; ++ ++static void sec_get_ccache_list_done(struct tevent_req *subreq); ++static void sec_get_ccache_done(struct tevent_req *subreq); ++ ++static struct tevent_req *sec_get_ccache_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ccdb_sec *secdb, ++ struct cli_creds *client, ++ const char *name, ++ uuid_t uuid) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct sec_get_ccache_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct sec_get_ccache_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->ev = ev; ++ state->secdb = secdb; ++ state->client = client; ++ state->name = name; ++ uuid_copy(state->uuid, uuid); ++ ++ if ((name == NULL && uuid_is_null(uuid)) ++ || (name != NULL && !uuid_is_null(uuid))) { ++ DEBUG(SSSDBG_OP_FAILURE, "Expected one of name, uuid to be set\n"); ++ ret = EINVAL; ++ goto immediate; ++ } ++ ++ subreq = sec_list_send(state, ev, secdb, client); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, sec_get_ccache_list_done, req); ++ return req; ++ ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void sec_get_ccache_list_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); ++ struct sec_get_ccache_state *state = tevent_req_data(req, ++ struct sec_get_ccache_state); ++ const char **sec_key_list; ++ ++ ret = sec_list_recv(subreq, state, &sec_key_list, NULL); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot list keys [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (state->name != NULL) { ++ state->sec_key = find_by_name(sec_key_list, state->name); ++ } else { ++ state->sec_key = find_by_uuid(sec_key_list, state->uuid); ++ } ++ ++ if (state->sec_key == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot find item in the ccache list\n"); ++ /* Don't error out, just return an empty list */ ++ tevent_req_done(req); ++ return; ++ } ++ ++ subreq = sec_get_send(state, ++ state->ev, ++ state->secdb, ++ state->client, ++ state->sec_key); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, sec_get_ccache_done, req); ++} ++ ++static void sec_get_ccache_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct sec_get_ccache_state *state = tevent_req_data(req, ++ struct sec_get_ccache_state); ++ ++ ret = sec_get_recv(subreq, state, &state->cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot resolve key to ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++static errno_t sec_get_ccache_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ccache **_cc) ++{ ++ struct sec_get_ccache_state *state = tevent_req_data(req, ++ struct sec_get_ccache_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_cc = talloc_steal(mem_ctx, state->cc); ++ return EOK; ++} ++ ++/* ++ * The actual sssd-secrets back end ++ */ ++static errno_t ccdb_sec_init(struct kcm_ccdb *db) ++{ ++ struct ccdb_sec *secdb = NULL; ++ ++ secdb = talloc_zero(db, struct ccdb_sec); ++ if (secdb == NULL) { ++ return ENOMEM; ++ } ++ ++ secdb->tctx = tcurl_init(secdb, db->ev); ++ if (secdb->tctx == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Cannot initialize tcurl\n"); ++ talloc_zfree(secdb); ++ return ENOMEM; ++ } ++ ++ /* We just need the random numbers to generate pseudo-random ccache names ++ * and avoid conflicts */ ++ srand(time(NULL)); ++ ++ db->db_handle = secdb; ++ return EOK; ++} ++ ++/* ++ * Helper request to get a ccache by key ++ */ ++struct sec_patch_state { ++ struct tevent_context *ev; ++ struct ccdb_sec *secdb; ++ struct cli_creds *client; ++ ++ const char *sec_key_url; ++ struct sss_iobuf *sec_value; ++}; ++ ++static void sec_patch_del_done(struct tevent_req *subreq); ++static void sec_patch_put_done(struct tevent_req *subreq); ++ ++static struct tevent_req *sec_patch_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ccdb_sec *secdb, ++ struct cli_creds *client, ++ const char *sec_key_url, ++ struct sss_iobuf *sec_value) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct sec_patch_state *state = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct sec_patch_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->ev = ev; ++ state->secdb = secdb; ++ state->client = client; ++ state->sec_key_url = sec_key_url; ++ state->sec_value = sec_value; ++ ++ subreq = tcurl_http_send(state, state->ev, ++ state->secdb->tctx, ++ TCURL_HTTP_DELETE, ++ SSSD_SECRETS_SOCKET, ++ state->sec_key_url, ++ sec_headers, ++ NULL, ++ SEC_TIMEOUT); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, sec_patch_del_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void sec_patch_del_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct sec_patch_state *state = tevent_req_data(req, ++ struct sec_patch_state); ++ int http_code; ++ ++ ret = tcurl_http_recv(state, subreq, &http_code, NULL); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot delete key [%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (http_code == 404) { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "Key %s does not exist, moving on\n", state->sec_key_url); ++ } else if (http_code != 200) { ++ ret = http2errno(http_code); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Adding new payload\n"); ++ ++ subreq = tcurl_http_send(state, ++ state->ev, ++ state->secdb->tctx, ++ TCURL_HTTP_PUT, ++ SSSD_SECRETS_SOCKET, ++ state->sec_key_url, ++ sec_headers, ++ state->sec_value, ++ SEC_TIMEOUT); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, sec_patch_put_done, req); ++} ++ ++static void sec_patch_put_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct sec_patch_state *state = tevent_req_data(req, ++ struct sec_patch_state); ++ int http_code; ++ ++ ret = tcurl_http_recv(state, subreq, &http_code, NULL); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot put new value [%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (http_code != 200) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to add the payload\n"); ++ ret = http2errno(http_code); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "payload created\n"); ++ tevent_req_done(req); ++} ++ ++ ++static errno_t sec_patch_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++/* The operations between the KCM and sssd-secrets */ ++ ++struct ccdb_sec_nextid_state { ++ struct tevent_context *ev; ++ struct ccdb_sec *secdb; ++ struct cli_creds *client; ++ ++ unsigned int nextid; ++ char *nextid_name; ++ ++ int maxtries; ++ int numtry; ++}; ++ ++static errno_t ccdb_sec_nextid_generate(struct tevent_req *req); ++static void ccdb_sec_nextid_list_done(struct tevent_req *subreq); ++ ++/* Generate a unique ID */ ++/* GET the name from secrets, if doesn't exist, OK, if exists, try again */ ++static struct tevent_req *ccdb_sec_nextid_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client) ++{ ++ struct tevent_req *req = NULL; ++ struct ccdb_sec_nextid_state *state = NULL; ++ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_nextid_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->ev = ev; ++ state->secdb = secdb; ++ state->client = client; ++ ++ state->maxtries = 3; ++ state->numtry = 0; ++ ++ ret = ccdb_sec_nextid_generate(req); ++ if (ret != EOK) { ++ goto immediate; ++ } ++ ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static errno_t ccdb_sec_nextid_generate(struct tevent_req *req) ++{ ++ struct tevent_req *subreq = NULL; ++ struct ccdb_sec_nextid_state *state = tevent_req_data(req, ++ struct ccdb_sec_nextid_state); ++ ++ if (state->numtry >= state->maxtries) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to find a random ccache in %d tries\n", state->numtry); ++ return EBUSY; ++ } ++ ++ state->nextid = rand() % MAX_CC_NUM; ++ state->nextid_name = talloc_asprintf(state, "%"SPRIuid":%u", ++ cli_creds_get_uid(state->client), ++ state->nextid); ++ if (state->nextid_name == NULL) { ++ return ENOMEM; ++ } ++ ++ subreq = sec_list_send(state, state->ev, state->secdb, state->client); ++ if (subreq == NULL) { ++ return ENOMEM; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_nextid_list_done, req); ++ ++ state->numtry++; ++ return EOK; ++} ++ ++static void ccdb_sec_nextid_list_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ccdb_sec_nextid_state *state = tevent_req_data(req, ++ struct ccdb_sec_nextid_state); ++ const char **sec_key_list; ++ size_t sec_key_list_len; ++ size_t i; ++ ++ ret = sec_list_recv(subreq, state, &sec_key_list, &sec_key_list_len); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot list keys [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ for (i = 0; i < sec_key_list_len; i++) { ++ if (sec_key_match_name(sec_key_list[i], state->nextid_name) == true) { ++ break; ++ } ++ } ++ ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Failed to find a random key, trying again..\n"); ++ if (i < sec_key_list_len) { ++ /* Try again */ ++ ret = ccdb_sec_nextid_generate(req); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, ++ "Generated new ccache name %u\n", state->nextid); ++ tevent_req_done(req); ++} ++ ++static errno_t ccdb_sec_nextid_recv(struct tevent_req *req, ++ unsigned int *_nextid) ++{ ++ struct ccdb_sec_nextid_state *state = tevent_req_data(req, ++ struct ccdb_sec_nextid_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_nextid = state->nextid; ++ return EOK; ++} ++ ++/* IN: HTTP PUT $base/default -d 'uuid' */ ++/* We chose only UUID here to avoid issues later with renaming */ ++struct ccdb_sec_set_default_state { ++}; ++ ++static void ccdb_sec_set_default_done(struct tevent_req *subreq); ++ ++static struct tevent_req *ccdb_sec_set_default_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct ccdb_sec_set_default_state *state = NULL; ++ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); ++ struct sss_iobuf *uuid_iobuf; ++ errno_t ret; ++ const char *url; ++ char uuid_str[UUID_STR_SIZE]; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_set_default_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ uuid_unparse(uuid, uuid_str); ++ DEBUG(SSSDBG_TRACE_INTERNAL, ++ "Setting the default ccache to %s\n", uuid_str); ++ ++ url = sec_dfl_url_create(state, client); ++ if (url == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ uuid_iobuf = sss_iobuf_init_readonly(state, ++ (uint8_t *) uuid_str, ++ UUID_STR_SIZE); ++ if (uuid_iobuf == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ subreq = sec_patch_send(state, ev, secdb, client, url, uuid_iobuf); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_set_default_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void ccdb_sec_set_default_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); ++ ++ ret = sec_patch_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sec_patch request failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Set the default ccache\n"); ++ tevent_req_done(req); ++} ++ ++static errno_t ccdb_sec_set_default_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++/* IN: HTTP GET $base/default */ ++/* OUT: uuid */ ++struct ccdb_sec_get_default_state { ++ uuid_t uuid; ++}; ++ ++static void ccdb_sec_get_default_done(struct tevent_req *subreq); ++ ++static struct tevent_req *ccdb_sec_get_default_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct ccdb_sec_get_default_state *state = NULL; ++ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); ++ const char *url; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_get_default_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Getting the default ccache\n"); ++ url = sec_dfl_url_create(state, client); ++ if (url == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ subreq = tcurl_http_send(state, ev, secdb->tctx, ++ TCURL_HTTP_GET, ++ SSSD_SECRETS_SOCKET, ++ url, ++ sec_headers, ++ NULL, ++ SEC_TIMEOUT); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_get_default_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void ccdb_sec_get_default_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ int http_code; ++ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); ++ struct ccdb_sec_get_default_state *state = tevent_req_data(req, ++ struct ccdb_sec_get_default_state); ++ struct sss_iobuf *outbuf; ++ size_t uuid_size; ++ ++ ret = tcurl_http_recv(state, subreq, &http_code, &outbuf); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Communication with the secrets responder failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (http_code == 404) { ++ /* Return a NULL uuid */ ++ uuid_clear(state->uuid); ++ tevent_req_done(req); ++ return; ++ } else if (http_code != 200) { ++ ret = http2errno(http_code); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ uuid_size = sss_iobuf_get_len(outbuf); ++ if (uuid_size != UUID_STR_SIZE) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unexpected UUID size %zu\n", uuid_size); ++ tevent_req_error(req, EIO); ++ return; ++ } ++ ++ uuid_parse((const char *) sss_iobuf_get_data(outbuf), state->uuid); ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Got the default ccache\n"); ++ tevent_req_done(req); ++} ++ ++static errno_t ccdb_sec_get_default_recv(struct tevent_req *req, ++ uuid_t uuid) ++{ ++ struct ccdb_sec_get_default_state *state = tevent_req_data(req, ++ struct ccdb_sec_get_default_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ uuid_copy(uuid, state->uuid); ++ return EOK; ++} ++ ++/* HTTP GET $base/ccache/ */ ++/* OUT: a list of */ ++struct ccdb_sec_list_state { ++ uuid_t *uuid_list; ++}; ++ ++static void ccdb_sec_list_done(struct tevent_req *subreq); ++ ++static struct tevent_req *ccdb_sec_list_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct ccdb_sec_list_state *state = NULL; ++ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_list_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Listing all ccaches\n"); ++ ++ subreq = sec_list_send(state, ev, secdb, client); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_list_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void ccdb_sec_list_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ccdb_sec_list_state *state = tevent_req_data(req, ++ struct ccdb_sec_list_state); ++ const char **sec_key_list; ++ size_t sec_key_list_len; ++ ++ ret = sec_list_recv(subreq, state, &sec_key_list, &sec_key_list_len); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Communication with the secrets responder failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Found %zu ccaches\n", sec_key_list_len); ++ ++ state->uuid_list = talloc_array(state, uuid_t, sec_key_list_len + 1); ++ if (state->uuid_list == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ for (size_t i = 0; i < sec_key_list_len; i++) { ++ ret = sec_key_get_uuid(sec_key_list[i], ++ state->uuid_list[i]); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ } ++ /* Sentinel */ ++ uuid_clear(state->uuid_list[sec_key_list_len]); ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Listing all caches done\n"); ++ tevent_req_done(req); ++} ++ ++static errno_t ccdb_sec_list_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ uuid_t **_uuid_list) ++{ ++ struct ccdb_sec_list_state *state = tevent_req_data(req, ++ struct ccdb_sec_list_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_uuid_list = talloc_steal(mem_ctx, state->uuid_list); ++ return EOK; ++} ++ ++struct ccdb_sec_getbyuuid_state { ++ struct kcm_ccache *cc; ++}; ++ ++ ++/* HTTP GET $base/ccache/ */ ++/* OUT: a list of */ ++/* for each item in list, compare with the uuid: portion */ ++/* HTTP GET $base/ccache/uuid:name */ ++/* return result */ ++static void ccdb_sec_getbyuuid_done(struct tevent_req *subreq); ++ ++static struct tevent_req *ccdb_sec_getbyuuid_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid) ++{ ++ errno_t ret; ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct ccdb_sec_getbyuuid_state *state = NULL; ++ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_getbyuuid_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Getting ccache by UUID\n"); ++ ++ subreq = sec_get_ccache_send(state, ev, secdb, client, NULL, uuid); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_getbyuuid_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void ccdb_sec_getbyuuid_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ccdb_sec_getbyuuid_state *state = tevent_req_data(req, ++ struct ccdb_sec_getbyuuid_state); ++ ++ ret = sec_get_ccache_recv(subreq, state, &state->cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot retrieve the ccache [%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Got ccache by UUID\n"); ++ tevent_req_done(req); ++} ++ ++static errno_t ccdb_sec_getbyuuid_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ccache **_cc) ++{ ++ struct ccdb_sec_getbyuuid_state *state = tevent_req_data(req, ++ struct ccdb_sec_getbyuuid_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_cc = talloc_steal(mem_ctx, state->cc); ++ return EOK; ++} ++ ++/* HTTP GET $base/ccache/ */ ++/* OUT: a list of */ ++/* for each item in list, compare with the :name portion */ ++/* HTTP GET $base/ccache/uuid:name */ ++/* return result */ ++struct ccdb_sec_getbyname_state { ++ struct kcm_ccache *cc; ++}; ++ ++static void ccdb_sec_getbyname_done(struct tevent_req *subreq); ++ ++static struct tevent_req *ccdb_sec_getbyname_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ const char *name) ++{ ++ errno_t ret; ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct ccdb_sec_getbyname_state *state = NULL; ++ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); ++ uuid_t null_uuid; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_getbyname_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ uuid_clear(null_uuid); ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Getting ccache by name\n"); ++ ++ subreq = sec_get_ccache_send(state, ev, secdb, client, name, null_uuid); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_getbyname_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void ccdb_sec_getbyname_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ccdb_sec_getbyname_state *state = tevent_req_data(req, ++ struct ccdb_sec_getbyname_state); ++ ++ ret = sec_get_ccache_recv(subreq, state, &state->cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot retrieve the ccache [%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Got ccache by UUID\n"); ++ tevent_req_done(req); ++} ++ ++static errno_t ccdb_sec_getbyname_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ccache **_cc) ++{ ++ struct ccdb_sec_getbyname_state *state = tevent_req_data(req, ++ struct ccdb_sec_getbyname_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_cc = talloc_steal(mem_ctx, state->cc); ++ return EOK; ++} ++ ++struct ccdb_sec_name_by_uuid_state { ++ struct tevent_context *ev; ++ struct ccdb_sec *secdb; ++ struct cli_creds *client; ++ ++ uuid_t uuid; ++ ++ const char *name; ++}; ++ ++static void ccdb_sec_name_by_uuid_done(struct tevent_req *subreq); ++ ++struct tevent_req *ccdb_sec_name_by_uuid_send(TALLOC_CTX *sec_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct ccdb_sec_name_by_uuid_state *state = NULL; ++ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); ++ errno_t ret; ++ ++ req = tevent_req_create(sec_ctx, &state, struct ccdb_sec_name_by_uuid_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->ev = ev; ++ state->secdb = secdb; ++ state->client = client; ++ uuid_copy(state->uuid, uuid); ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Translating UUID to name\n"); ++ ++ subreq = sec_list_send(state, state->ev, state->secdb, state->client); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_name_by_uuid_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void ccdb_sec_name_by_uuid_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ccdb_sec_name_by_uuid_state *state = tevent_req_data(req, ++ struct ccdb_sec_name_by_uuid_state); ++ const char **sec_key_list; ++ const char *name; ++ size_t sec_key_list_len; ++ size_t i; ++ ++ ret = sec_list_recv(subreq, state, &sec_key_list, &sec_key_list_len); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ for (i = 0; i < sec_key_list_len; i++) { ++ if (sec_key_match_uuid(sec_key_list[i], state->uuid) == true) { ++ /* Match, copy name */ ++ name = sec_key_get_name(sec_key_list[i]); ++ if (name == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Malformed key, cannot get name\n"); ++ tevent_req_error(req, EINVAL); ++ return; ++ } ++ ++ state->name = talloc_strdup(state, name); ++ if (state->name == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Got ccache by UUID\n"); ++ tevent_req_done(req); ++ return; ++ } ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "No such UUID\n"); ++ tevent_req_error(req, ERR_NO_CREDS); ++ return; ++} ++ ++errno_t ccdb_sec_name_by_uuid_recv(struct tevent_req *req, ++ TALLOC_CTX *sec_ctx, ++ const char **_name) ++{ ++ struct ccdb_sec_name_by_uuid_state *state = tevent_req_data(req, ++ struct ccdb_sec_name_by_uuid_state); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_name = talloc_steal(sec_ctx, state->name); ++ return EOK; ++} ++ ++struct ccdb_sec_uuid_by_name_state { ++ struct tevent_context *ev; ++ struct ccdb_sec *secdb; ++ struct cli_creds *client; ++ ++ const char *name; ++ ++ uuid_t uuid; ++}; ++ ++static void ccdb_sec_uuid_by_name_done(struct tevent_req *subreq); ++ ++struct tevent_req *ccdb_sec_uuid_by_name_send(TALLOC_CTX *sec_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ const char *name) ++{ ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct ccdb_sec_uuid_by_name_state *state = NULL; ++ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); ++ errno_t ret; ++ ++ req = tevent_req_create(sec_ctx, &state, struct ccdb_sec_uuid_by_name_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->ev = ev; ++ state->secdb = secdb; ++ state->client = client; ++ state->name = name; ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Translating name to UUID\n"); ++ ++ subreq = sec_list_send(state, state->ev, state->secdb, state->client); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_uuid_by_name_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void ccdb_sec_uuid_by_name_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ccdb_sec_uuid_by_name_state *state = tevent_req_data(req, ++ struct ccdb_sec_uuid_by_name_state); ++ const char **sec_key_list; ++ size_t sec_key_list_len; ++ size_t i; ++ ++ ret = sec_list_recv(subreq, state, &sec_key_list, &sec_key_list_len); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ for (i = 0; i < sec_key_list_len; i++) { ++ if (sec_key_match_name(sec_key_list[i], state->name) == true) { ++ /* Match, copy UUID */ ++ ret = sec_key_get_uuid(sec_key_list[i], state->uuid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Malformed key, cannot get UUID\n"); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Got ccache by name\n"); ++ tevent_req_done(req); ++ return; ++ } ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "No such name\n"); ++ tevent_req_error(req, ERR_NO_CREDS); ++ return; ++} ++ ++errno_t ccdb_sec_uuid_by_name_recv(struct tevent_req *req, ++ TALLOC_CTX *sec_ctx, ++ uuid_t _uuid) ++{ ++ struct ccdb_sec_uuid_by_name_state *state = tevent_req_data(req, ++ struct ccdb_sec_uuid_by_name_state); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ uuid_copy(_uuid, state->uuid); ++ return EOK; ++} ++ ++/* HTTP POST $base to create the container */ ++/* HTTP PUT $base to create the container. Since PUT errors out on duplicates, at least ++ * we fail consistently here and don't overwrite the ccache on concurrent requests ++ */ ++struct ccdb_sec_create_state { ++ struct tevent_context *ev; ++ struct ccdb_sec *secdb; ++ ++ const char *key_url; ++ struct sss_iobuf *ccache_payload; ++}; ++ ++static void ccdb_sec_container_done(struct tevent_req *subreq); ++static void ccdb_sec_ccache_done(struct tevent_req *subreq); ++ ++static struct tevent_req *ccdb_sec_create_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ struct kcm_ccache *cc) ++{ ++ struct tevent_req *subreq = NULL; ++ struct tevent_req *req = NULL; ++ struct ccdb_sec_create_state *state = NULL; ++ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); ++ errno_t ret; ++ const char *container_url; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_create_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->ev = ev; ++ state->secdb = secdb; ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Creating ccache storage for %s\n", cc->name); ++ ++ /* Do the encoding asap so that if we fail, we don't even attempt any ++ * writes */ ++ ret = kcm_ccache_to_sec_input(state, cc, client, &state->key_url, &state->ccache_payload); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot convert cache %s to JSON [%d]: %s\n", ++ cc->name, ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ container_url = sec_container_url_create(state, client); ++ if (container_url == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Creating the ccache container\n"); ++ subreq = tcurl_http_send(state, ev, secdb->tctx, ++ TCURL_HTTP_POST, ++ SSSD_SECRETS_SOCKET, ++ container_url, ++ sec_headers, ++ NULL, ++ SEC_TIMEOUT); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_container_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void ccdb_sec_container_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ int http_code; ++ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); ++ struct ccdb_sec_create_state *state = tevent_req_data(req, ++ struct ccdb_sec_create_state); ++ ++ ret = tcurl_http_recv(state, subreq, &http_code, NULL); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Communication with the secrets responder failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ /* Conflict is not an error as multiple ccaches are under the same ++ * container */ ++ if (http_code == 409) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Container already exists, ignoring\n"); ++ } else if (http_code != 200) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to create the ccache container\n"); ++ ret = http2errno(http_code); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "ccache container created\n"); ++ DEBUG(SSSDBG_TRACE_INTERNAL, "creating empty ccache payload\n"); ++ ++ subreq = tcurl_http_send(state, ++ state->ev, ++ state->secdb->tctx, ++ TCURL_HTTP_PUT, ++ SSSD_SECRETS_SOCKET, ++ state->key_url, ++ sec_headers, ++ state->ccache_payload, ++ SEC_TIMEOUT); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_ccache_done, req); ++} ++ ++static void ccdb_sec_ccache_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ int http_code; ++ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); ++ struct ccdb_sec_create_state *state = tevent_req_data(req, ++ struct ccdb_sec_create_state); ++ ++ ret = tcurl_http_recv(state, subreq, &http_code, NULL); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Communication with the secrets responder failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (http_code != 200) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to add the payload\n"); ++ ret = http2errno(http_code); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "payload created\n"); ++ tevent_req_done(req); ++} ++ ++static errno_t ccdb_sec_create_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++struct ccdb_sec_mod_cred_state { ++ struct tevent_context *ev; ++ struct kcm_ccdb *db; ++ struct cli_creds *client; ++ struct kcm_mod_ctx *mod_cc; ++ ++ struct ccdb_sec *secdb; ++}; ++ ++static void ccdb_sec_mod_cred_get_done(struct tevent_req *subreq); ++static void ccdb_sec_mod_cred_patch_done(struct tevent_req *subreq); ++ ++static struct tevent_req *ccdb_sec_mod_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid, ++ struct kcm_mod_ctx *mod_cc) ++{ ++ errno_t ret; ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct ccdb_sec_mod_cred_state *state = NULL; ++ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_mod_cred_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->ev = ev; ++ state->db =db; ++ state->client = client; ++ state->secdb = secdb; ++ state->mod_cc = mod_cc; ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Modifying ccache\n"); ++ ++ subreq = sec_get_ccache_send(state, ev, secdb, client, NULL, uuid); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, *ccdb_sec_mod_cred_get_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void ccdb_sec_mod_cred_get_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ccdb_sec_mod_cred_state *state = tevent_req_data(req, ++ struct ccdb_sec_mod_cred_state); ++ struct kcm_ccache *cc; ++ const char *url; ++ struct sss_iobuf *payload; ++ ++ ret = sec_get_ccache_recv(subreq, state, &cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot retrieve the ccache [%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (cc == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "No such ccache\n"); ++ tevent_req_error(req, ERR_NO_CREDS); ++ return; ++ } ++ ++ kcm_mod_cc(cc, state->mod_cc); ++ ++ ret = kcm_ccache_to_sec_input(state, cc, state->client, &url, &payload); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to marshall modified ccache to payload [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ subreq = sec_patch_send(state, ++ state->ev, ++ state->secdb, ++ state->client, ++ url, ++ payload); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_mod_cred_patch_done, req); ++} ++ ++static void ccdb_sec_mod_cred_patch_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ ++ ret = sec_patch_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sec_patch request failed [%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "ccache modified\n"); ++ tevent_req_done(req); ++} ++ ++static errno_t ccdb_sec_mod_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++struct ccdb_sec_store_cred_state { ++ struct tevent_context *ev; ++ struct kcm_ccdb *db; ++ struct cli_creds *client; ++ struct sss_iobuf *cred_blob; ++ ++ struct ccdb_sec *secdb; ++}; ++ ++static void ccdb_sec_store_cred_get_done(struct tevent_req *subreq); ++static void ccdb_sec_store_cred_patch_done(struct tevent_req *subreq); ++ ++/* HTTP DEL/PUT $base/ccache/uuid:name */ ++static struct tevent_req *ccdb_sec_store_cred_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid, ++ struct sss_iobuf *cred_blob) ++{ ++ errno_t ret; ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct ccdb_sec_store_cred_state *state = NULL; ++ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_store_cred_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->ev = ev; ++ state->db =db; ++ state->client = client; ++ state->cred_blob = cred_blob; ++ state->secdb = secdb; ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Storing creds in ccache\n"); ++ ++ subreq = sec_get_ccache_send(state, ev, secdb, client, NULL, uuid); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, *ccdb_sec_store_cred_get_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void ccdb_sec_store_cred_get_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ccdb_sec_store_cred_state *state = tevent_req_data(req, ++ struct ccdb_sec_store_cred_state); ++ struct kcm_ccache *cc; ++ const char *url; ++ struct sss_iobuf *payload; ++ ++ ret = sec_get_ccache_recv(subreq, state, &cc); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ ret = kcm_cc_store_cred_blob(cc, state->cred_blob); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot store credentials to ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ ret = kcm_ccache_to_sec_input(state, cc, state->client, &url, &payload); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to marshall modified ccache to payload [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ subreq = sec_patch_send(state, ++ state->ev, ++ state->secdb, ++ state->client, ++ url, ++ payload); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_store_cred_patch_done, req); ++} ++ ++static void ccdb_sec_store_cred_patch_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ ++ ret = sec_patch_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sec_patch request failed [%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "ccache creds stored\n"); ++ tevent_req_done(req); ++} ++ ++static errno_t ccdb_sec_store_cred_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++/* HTTP DELETE $base/ccache/uuid:name */ ++struct ccdb_sec_delete_state { ++ struct tevent_context *ev; ++ struct ccdb_sec *secdb; ++ struct cli_creds *client; ++ uuid_t uuid; ++ ++ size_t sec_key_list_len; ++}; ++ ++static void ccdb_sec_delete_list_done(struct tevent_req *subreq); ++static void ccdb_sec_delete_cc_done(struct tevent_req *subreq); ++static void ccdb_sec_delete_container_done(struct tevent_req *subreq); ++ ++static struct tevent_req *ccdb_sec_delete_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ccdb *db, ++ struct cli_creds *client, ++ uuid_t uuid) ++{ ++ errno_t ret; ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ struct ccdb_sec_delete_state *state = NULL; ++ struct ccdb_sec *secdb = talloc_get_type(db->db_handle, struct ccdb_sec); ++ ++ req = tevent_req_create(mem_ctx, &state, struct ccdb_sec_delete_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->ev = ev; ++ state->secdb = secdb; ++ state->client = client; ++ uuid_copy(state->uuid, uuid); ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Deleting ccache\n"); ++ ++ subreq = sec_list_send(state, ev, secdb, client); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_delete_list_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void ccdb_sec_delete_list_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ccdb_sec_delete_state *state = tevent_req_data(req, ++ struct ccdb_sec_delete_state); ++ const char **sec_key_list; ++ const char *sec_key; ++ const char *cc_url; ++ ++ ret = sec_list_recv(subreq, ++ state, ++ &sec_key_list, ++ &state->sec_key_list_len); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (sec_key_list == 0) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "No ccaches to delete\n"); ++ tevent_req_done(req); ++ return; ++ } ++ ++ sec_key = find_by_uuid(sec_key_list, state->uuid); ++ if (sec_key == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot find ccache by UUID\n"); ++ tevent_req_done(req); ++ return; ++ } ++ ++ cc_url = sec_cc_url_create(state, state->client, sec_key); ++ if (cc_url == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ subreq = tcurl_http_send(state, state->ev, ++ state->secdb->tctx, ++ TCURL_HTTP_DELETE, ++ SSSD_SECRETS_SOCKET, ++ cc_url, ++ sec_headers, ++ NULL, ++ SEC_TIMEOUT); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_delete_cc_done, req); ++} ++ ++static void ccdb_sec_delete_cc_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ccdb_sec_delete_state *state = tevent_req_data(req, ++ struct ccdb_sec_delete_state); ++ int http_code; ++ const char *container_url; ++ ++ ret = tcurl_http_recv(state, subreq, &http_code, NULL); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot delete ccache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (http_code != 200) { ++ ret = http2errno(http_code); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (state->sec_key_list_len != 1) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, "There are other ccaches, done\n"); ++ tevent_req_done(req); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Removing ccache container\n"); ++ ++ container_url = sec_container_url_create(state, state->client); ++ if (container_url == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ subreq = tcurl_http_send(state, state->ev, ++ state->secdb->tctx, ++ TCURL_HTTP_DELETE, ++ SSSD_SECRETS_SOCKET, ++ container_url, ++ sec_headers, ++ NULL, ++ SEC_TIMEOUT); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, ccdb_sec_delete_container_done, req); ++} ++ ++static void ccdb_sec_delete_container_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct ccdb_sec_delete_state *state = tevent_req_data(req, ++ struct ccdb_sec_delete_state); ++ int http_code; ++ ++ ret = tcurl_http_recv(state, subreq, &http_code, NULL); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot delete ccache container [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (http_code != 200) { ++ ret = http2errno(http_code); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Removed ccache container\n"); ++ tevent_req_done(req); ++} ++ ++static errno_t ccdb_sec_delete_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ return EOK; ++} ++ ++const struct kcm_ccdb_ops ccdb_sec_ops = { ++ .init = ccdb_sec_init, ++ ++ .nextid_send = ccdb_sec_nextid_send, ++ .nextid_recv = ccdb_sec_nextid_recv, ++ ++ .set_default_send = ccdb_sec_set_default_send, ++ .set_default_recv = ccdb_sec_set_default_recv, ++ ++ .get_default_send = ccdb_sec_get_default_send, ++ .get_default_recv = ccdb_sec_get_default_recv, ++ ++ .list_send = ccdb_sec_list_send, ++ .list_recv = ccdb_sec_list_recv, ++ ++ .getbyname_send = ccdb_sec_getbyname_send, ++ .getbyname_recv = ccdb_sec_getbyname_recv, ++ ++ .getbyuuid_send = ccdb_sec_getbyuuid_send, ++ .getbyuuid_recv = ccdb_sec_getbyuuid_recv, ++ ++ .name_by_uuid_send = ccdb_sec_name_by_uuid_send, ++ .name_by_uuid_recv = ccdb_sec_name_by_uuid_recv, ++ ++ .uuid_by_name_send = ccdb_sec_uuid_by_name_send, ++ .uuid_by_name_recv = ccdb_sec_uuid_by_name_recv, ++ ++ .create_send = ccdb_sec_create_send, ++ .create_recv = ccdb_sec_create_recv, ++ ++ .mod_send = ccdb_sec_mod_send, ++ .mod_recv = ccdb_sec_mod_recv, ++ ++ .store_cred_send = ccdb_sec_store_cred_send, ++ .store_cred_recv = ccdb_sec_store_cred_recv, ++ ++ .delete_send = ccdb_sec_delete_send, ++ .delete_recv = ccdb_sec_delete_recv, ++}; +diff --git a/src/tests/cmocka/test_kcm_json_marshalling.c b/src/tests/cmocka/test_kcm_json_marshalling.c +new file mode 100644 +index 0000000000000000000000000000000000000000..8eff2f501066c70a8730cd3d4dc41b92d7a03e4c +--- /dev/null ++++ b/src/tests/cmocka/test_kcm_json_marshalling.c +@@ -0,0 +1,234 @@ ++/* ++ Copyright (C) 2017 Red Hat ++ ++ SSSD tests: Test KCM JSON marshalling ++ ++ 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 . ++*/ ++ ++#include "config.h" ++ ++#include ++#include ++ ++#include "util/util_creds.h" ++#include "responder/kcm/kcmsrv_ccache.h" ++#include "responder/kcm/kcmsrv_ccache_be.h" ++#include "tests/cmocka/common_mock.h" ++ ++#define TEST_REALM "TESTREALM" ++#define TEST_PRINC_COMPONENT "PRINC_NAME" ++ ++#define TEST_CREDS "TESTCREDS" ++ ++const struct kcm_ccdb_ops ccdb_mem_ops; ++const struct kcm_ccdb_ops ccdb_sec_ops; ++ ++struct kcm_marshalling_test_ctx { ++ krb5_context kctx; ++ krb5_principal princ; ++}; ++ ++static int setup_kcm_marshalling(void **state) ++{ ++ struct kcm_marshalling_test_ctx *test_ctx; ++ krb5_error_code kerr; ++ ++ test_ctx = talloc_zero(NULL, struct kcm_marshalling_test_ctx); ++ assert_non_null(test_ctx); ++ ++ kerr = krb5_init_context(&test_ctx->kctx); ++ assert_int_equal(kerr, 0); ++ ++ kerr = krb5_build_principal(test_ctx->kctx, ++ &test_ctx->princ, ++ sizeof(TEST_REALM)-1, TEST_REALM, ++ TEST_PRINC_COMPONENT, NULL); ++ assert_int_equal(kerr, 0); ++ ++ *state = test_ctx; ++ return 0; ++} ++ ++static int teardown_kcm_marshalling(void **state) ++{ ++ struct kcm_marshalling_test_ctx *test_ctx = talloc_get_type(*state, ++ struct kcm_marshalling_test_ctx); ++ assert_non_null(test_ctx); ++ ++ krb5_free_principal(test_ctx->kctx, test_ctx->princ); ++ krb5_free_context(test_ctx->kctx); ++ talloc_free(test_ctx); ++ return 0; ++} ++ ++static void assert_cc_name_equal(struct kcm_ccache *cc1, ++ struct kcm_ccache *cc2) ++{ ++ const char *name1, *name2; ++ ++ name1 = kcm_cc_get_name(cc1); ++ name2 = kcm_cc_get_name(cc2); ++ assert_string_equal(name1, name2); ++} ++ ++static void assert_cc_uuid_equal(struct kcm_ccache *cc1, ++ struct kcm_ccache *cc2) ++{ ++ uuid_t u1, u2; ++ errno_t ret; ++ ++ ret = kcm_cc_get_uuid(cc1, u1); ++ assert_int_equal(ret, EOK); ++ ret = kcm_cc_get_uuid(cc2, u2); ++ assert_int_equal(ret, EOK); ++ ret = uuid_compare(u1, u2); ++ assert_int_equal(ret, 0); ++} ++ ++static void assert_cc_princ_equal(struct kcm_ccache *cc1, ++ struct kcm_ccache *cc2) ++{ ++ krb5_principal p1; ++ krb5_principal p2; ++ char *name1; ++ char *name2; ++ krb5_error_code kerr; ++ ++ p1 = kcm_cc_get_client_principal(cc1); ++ p2 = kcm_cc_get_client_principal(cc1); ++ ++ kerr = krb5_unparse_name(NULL, p1, &name1); ++ assert_int_equal(kerr, 0); ++ kerr = krb5_unparse_name(NULL, p2, &name2); ++ assert_int_equal(kerr, 0); ++ ++ assert_string_equal(name1, name2); ++ krb5_free_unparsed_name(NULL, name1); ++ krb5_free_unparsed_name(NULL, name2); ++} ++ ++static void assert_cc_offset_equal(struct kcm_ccache *cc1, ++ struct kcm_ccache *cc2) ++{ ++ int32_t off1; ++ int32_t off2; ++ ++ off1 = kcm_cc_get_offset(cc1); ++ off2 = kcm_cc_get_offset(cc2); ++ assert_int_equal(off1, off2); ++} ++ ++static void assert_cc_equal(struct kcm_ccache *cc1, ++ struct kcm_ccache *cc2) ++{ ++ assert_cc_name_equal(cc1, cc2); ++ assert_cc_uuid_equal(cc1, cc2); ++ assert_cc_princ_equal(cc1, cc2); ++ assert_cc_offset_equal(cc1, cc2); ++} ++ ++static void test_kcm_ccache_marshall_unmarshall(void **state) ++{ ++ struct kcm_marshalling_test_ctx *test_ctx = talloc_get_type(*state, ++ struct kcm_marshalling_test_ctx); ++ errno_t ret; ++ struct cli_creds owner; ++ struct kcm_ccache *cc; ++ struct kcm_ccache *cc2; ++ const char *url; ++ struct sss_iobuf *payload; ++ const char *name; ++ const char *key; ++ uint8_t *data; ++ ++ owner.ucred.uid = getuid(); ++ owner.ucred.gid = getuid(); ++ ++ name = talloc_asprintf(test_ctx, "%"SPRIuid, getuid()); ++ assert_non_null(name); ++ ++ ret = kcm_cc_new(test_ctx, ++ test_ctx->kctx, ++ &owner, ++ name, ++ test_ctx->princ, ++ &cc); ++ assert_int_equal(ret, EOK); ++ ++ ret = kcm_ccache_to_sec_input(test_ctx, ++ cc, ++ &owner, ++ &url, ++ &payload); ++ assert_int_equal(ret, EOK); ++ ++ key = strrchr(url, '/') + 1; ++ assert_non_null(key); ++ ++ data = sss_iobuf_get_data(payload); ++ assert_non_null(data); ++ ++ ret = sec_kv_to_ccache(test_ctx, ++ key, ++ (const char *) data, ++ &owner, ++ &cc2); ++ assert_int_equal(ret, EOK); ++ ++ assert_cc_equal(cc, cc2); ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ poptContext pc; ++ int opt; ++ int rv; ++ struct poptOption long_options[] = { ++ POPT_AUTOHELP ++ SSSD_DEBUG_OPTS ++ POPT_TABLEEND ++ }; ++ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall, ++ setup_kcm_marshalling, ++ teardown_kcm_marshalling), ++ }; ++ ++ /* Set debug level to invalid value so we can deside if -d 0 was used. */ ++ debug_level = SSSDBG_INVALID; ++ ++ pc = poptGetContext(argv[0], argc, argv, long_options, 0); ++ while((opt = poptGetNextOpt(pc)) != -1) { ++ switch(opt) { ++ default: ++ fprintf(stderr, "\nInvalid option %s: %s\n\n", ++ poptBadOption(pc, 0), poptStrerror(opt)); ++ poptPrintUsage(pc, stderr, 0); ++ return 1; ++ } ++ } ++ poptFreeContext(pc); ++ ++ DEBUG_CLI_INIT(debug_level); ++ ++ /* Even though normally the tests should clean up after themselves ++ * they might not after a failed run. Remove the old db to be sure */ ++ tests_set_cwd(); ++ ++ rv = cmocka_run_group_tests(tests, NULL, NULL); ++ ++ return rv; ++} +diff --git a/src/tests/intg/test_kcm.py b/src/tests/intg/test_kcm.py +index ad1e4923bfe339cb040464757431d2ef3bf57ce1..11f80a1803b4ad9b8e8857bf9a8a244d4816f0a2 100644 +--- a/src/tests/intg/test_kcm.py ++++ b/src/tests/intg/test_kcm.py +@@ -27,7 +27,8 @@ import signal + import kdc + import krb5utils + import config +-from util import unindent, run_shell ++from util import unindent ++from test_secrets import create_sssd_secrets_fixture + + class KcmTestEnv(object): + def __init__(self, k5kdc, k5util): +@@ -107,15 +108,8 @@ def create_sssd_kcm_fixture(sock_path, request): + return kcm_pid + + +-@pytest.fixture +-def setup_for_kcm(request, kdc_instance): +- """ +- Just set up the local provider for tests and enable the KCM +- responder +- """ +- kcm_path = os.path.join(config.RUNSTATEDIR, "kcm.socket") +- +- sssd_conf = unindent("""\ ++def create_sssd_conf(kcm_path, ccache_storage): ++ return unindent("""\ + [sssd] + domains = local + services = nss +@@ -125,8 +119,11 @@ def setup_for_kcm(request, kdc_instance): + + [kcm] + socket_path = {kcm_path} ++ ccache_storage = {ccache_storage} + """).format(**locals()) + ++ ++def common_setup_for_kcm_mem(request, kdc_instance, kcm_path, sssd_conf): + kcm_socket_include = unindent(""" + [libdefaults] + default_ccache_name = KCM: +@@ -142,11 +139,35 @@ def setup_for_kcm(request, kdc_instance): + return KcmTestEnv(kdc_instance, k5util) + + +-def test_kcm_init_list_destroy(setup_for_kcm): ++@pytest.fixture ++def setup_for_kcm_mem(request, kdc_instance): ++ """ ++ Just set up the local provider for tests and enable the KCM ++ responder ++ """ ++ kcm_path = os.path.join(config.RUNSTATEDIR, "kcm.socket") ++ sssd_conf = create_sssd_conf(kcm_path, "memory") ++ return common_setup_for_kcm_mem(request, kdc_instance, kcm_path, sssd_conf) ++ ++@pytest.fixture ++def setup_secrets(request): ++ create_sssd_secrets_fixture(request) ++ ++@pytest.fixture ++def setup_for_kcm_sec(request, kdc_instance): ++ """ ++ Just set up the local provider for tests and enable the KCM ++ responder ++ """ ++ kcm_path = os.path.join(config.RUNSTATEDIR, "kcm.socket") ++ sssd_conf = create_sssd_conf(kcm_path, "secrets") ++ return common_setup_for_kcm_mem(request, kdc_instance, kcm_path, sssd_conf) ++ ++ ++def kcm_init_list_destroy(testenv): + """ + Test that kinit, kdestroy and klist work with KCM + """ +- testenv = setup_for_kcm + testenv.k5kdc.add_principal("kcmtest", "Secret123") + + ok = testenv.k5util.has_principal("kcmtest@KCMTEST") +@@ -172,12 +193,22 @@ def test_kcm_init_list_destroy(setup_for_kcm): + assert nprincs == 0 + + +-def test_kcm_overwrite(setup_for_kcm): ++def test_kcm_mem_init_list_destroy(setup_for_kcm_mem): ++ testenv = setup_for_kcm_mem ++ kcm_init_list_destroy(testenv) ++ ++ ++def test_kcm_sec_init_list_destroy(setup_for_kcm_sec, ++ setup_secrets): ++ testenv = setup_for_kcm_sec ++ kcm_init_list_destroy(testenv) ++ ++ ++def kcm_overwrite(testenv): + """ + That that reusing a ccache reinitializes the cache and doesn't + add the same principal twice + """ +- testenv = setup_for_kcm + testenv.k5kdc.add_principal("kcmtest", "Secret123") + exp_ccache = {'kcmtest@KCMTEST': ['krbtgt/KCMTEST@KCMTEST']} + +@@ -192,12 +223,22 @@ def test_kcm_overwrite(setup_for_kcm): + assert exp_ccache == testenv.k5util.list_all_princs() + + +-def test_collection_init_list_destroy(setup_for_kcm): ++def test_kcm_mem_overwrite(setup_for_kcm_mem): ++ testenv = setup_for_kcm_mem ++ kcm_overwrite(testenv) ++ ++ ++def test_kcm_sec_overwrite(setup_for_kcm_sec, ++ setup_secrets): ++ testenv = setup_for_kcm_sec ++ kcm_overwrite(testenv) ++ ++ ++def collection_init_list_destroy(testenv): + """ + Test that multiple principals and service tickets can be stored + in a collection. + """ +- testenv = setup_for_kcm + testenv.k5kdc.add_principal("alice", "alicepw") + testenv.k5kdc.add_principal("bob", "bobpw") + testenv.k5kdc.add_principal("carol", "carolpw") +@@ -241,7 +282,11 @@ def test_collection_init_list_destroy(setup_for_kcm): + + out = testenv.k5util.kdestroy() + assert out == 0 +- assert testenv.k5util.default_principal() == 'bob@KCMTEST' ++ # If the default is removed, KCM just uses whetever is the first entry ++ # in the collection as the default. And sine the KCM back ends don't ++ # guarantee if they are FIFO or LIFO, just check for either alice or bob ++ assert testenv.k5util.default_principal() in \ ++ ['alice@KCMTEST', 'bob@KCMTEST'] + cc_coll = testenv.k5util.list_all_princs() + assert len(cc_coll) == 2 + assert cc_coll['alice@KCMTEST'] == ['krbtgt/KCMTEST@KCMTEST'] +@@ -255,11 +300,21 @@ def test_collection_init_list_destroy(setup_for_kcm): + #assert len(cc_coll) == 0 + + +-def test_kswitch(setup_for_kcm): ++def test_kcm_mem_collection_init_list_destroy(setup_for_kcm_mem): ++ testenv = setup_for_kcm_mem ++ collection_init_list_destroy(testenv) ++ ++ ++def test_kcm_sec_collection_init_list_destroy(setup_for_kcm_sec, ++ setup_secrets): ++ testenv = setup_for_kcm_sec ++ collection_init_list_destroy(testenv) ++ ++ ++def exercise_kswitch(testenv): + """ + Test switching between principals + """ +- testenv = setup_for_kcm + testenv.k5kdc.add_principal("alice", "alicepw") + testenv.k5kdc.add_principal("bob", "bobpw") + testenv.k5kdc.add_principal("host/somehostname") +@@ -301,12 +356,22 @@ def test_kswitch(setup_for_kcm): + 'host/differenthostname@KCMTEST']) + + +-def test_subsidiaries(setup_for_kcm): ++def test_kcm_mem_kswitch(setup_for_kcm_mem): ++ testenv = setup_for_kcm_mem ++ exercise_kswitch(testenv) ++ ++ ++def test_kcm_sec_kswitch(setup_for_kcm_sec, ++ setup_secrets): ++ testenv = setup_for_kcm_sec ++ exercise_kswitch(testenv) ++ ++ ++def exercise_subsidiaries(testenv): + """ + Test that subsidiary caches are usable and KCM: without specifying UID + can be used to identify the collection + """ +- testenv = setup_for_kcm + testenv.k5kdc.add_principal("alice", "alicepw") + testenv.k5kdc.add_principal("bob", "bobpw") + testenv.k5kdc.add_principal("host/somehostname") +@@ -346,11 +411,21 @@ def test_subsidiaries(setup_for_kcm): + 'host/differenthostname@KCMTEST']) + + +-def test_kdestroy_nocache(setup_for_kcm): ++def test_kcm_mem_subsidiaries(setup_for_kcm_mem): ++ testenv = setup_for_kcm_mem ++ exercise_subsidiaries(testenv) ++ ++ ++def test_kcm_sec_subsidiaries(setup_for_kcm_sec, ++ setup_secrets): ++ testenv = setup_for_kcm_sec ++ exercise_subsidiaries(testenv) ++ ++ ++def kdestroy_nocache(testenv): + """ + Destroying a non-existing ccache should not throw an error + """ +- testenv = setup_for_kcm + testenv.k5kdc.add_principal("alice", "alicepw") + out, _, _ = testenv.k5util.kinit("alice", "alicepw") + assert out == 0 +@@ -359,3 +434,14 @@ def test_kdestroy_nocache(setup_for_kcm): + assert out == 0 + out = testenv.k5util.kdestroy() + assert out == 0 ++ ++ ++def test_kcm_mem_kdestroy_nocache(setup_for_kcm_mem): ++ testenv = setup_for_kcm_mem ++ exercise_subsidiaries(testenv) ++ ++ ++def test_kcm_sec_kdestroy_nocache(setup_for_kcm_sec, ++ setup_secrets): ++ testenv = setup_for_kcm_sec ++ exercise_subsidiaries(testenv) +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index 23cfdf9c6116a2c8e569a041e8289b65a112fd08..60c2f439b3e39b1dbff353e429114cb5a3070052 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -109,6 +109,8 @@ struct err_string error_to_str[] = { + { "KCM operation not implemented" }, /* ERR_KCM_OP_NOT_IMPLEMENTED */ + { "End of credential cache reached" }, /* ERR_KCM_CC_END */ + { "Credential cache name not allowed" }, /* ERR_KCM_WRONG_CCNAME_FORMAT */ ++ { "Cannot encode a JSON object to string" }, /* ERR_JSON_ENCODING */ ++ { "Cannot decode a JSON object from string" }, /* ERR_JSON_DECODING */ + { "ERR_LAST" } /* ERR_LAST */ + }; + +diff --git a/src/util/util_errors.h b/src/util/util_errors.h +index 387d481616db1ed5e22b73fae82632a582fae946..4e9da814702e2cd46edc52fd5c2ae5f640602609 100644 +--- a/src/util/util_errors.h ++++ b/src/util/util_errors.h +@@ -131,6 +131,8 @@ enum sssd_errors { + ERR_KCM_OP_NOT_IMPLEMENTED, + ERR_KCM_CC_END, + ERR_KCM_WRONG_CCNAME_FORMAT, ++ ERR_JSON_ENCODING, ++ ERR_JSON_DECODING, + ERR_LAST /* ALWAYS LAST */ + }; + +-- +2.9.3 + diff --git a/SOURCES/0034-KCM-Make-the-secrets-ccache-back-end-configurable-ma.patch b/SOURCES/0034-KCM-Make-the-secrets-ccache-back-end-configurable-ma.patch new file mode 100644 index 0000000..2d65a32 --- /dev/null +++ b/SOURCES/0034-KCM-Make-the-secrets-ccache-back-end-configurable-ma.patch @@ -0,0 +1,219 @@ +From 6236b14d20151053f5ccad1fc8ee9b669d4b0ffb Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 14 Mar 2017 11:17:05 +0100 +Subject: [PATCH 34/36] KCM: Make the secrets ccache back end configurable, + make secrets the default +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Adds a new option 'ccache_storage' that allows to select either the +memory back end or the secrets back end. The secrets back end is the +default one and this option is even undocumented. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + src/confdb/confdb.h | 1 + + src/config/cfg_rules.ini | 1 + + src/responder/kcm/kcm.c | 49 ++++++++++++++++++++++++++++++++---- + src/responder/kcm/kcmsrv_ccache.c | 2 +- + src/responder/kcm/kcmsrv_ccache.h | 6 +---- + src/responder/kcm/kcmsrv_ccache_be.h | 1 + + src/responder/kcm/kcmsrv_pvt.h | 7 ++++++ + 7 files changed, 56 insertions(+), 11 deletions(-) + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index c443e869a7a6782265b42c4ad122867c4e3dd8e0..fb60675ca8beb2c2a157bf021ed9cad362742988 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -234,6 +234,7 @@ + /* KCM Service */ + #define CONFDB_KCM_CONF_ENTRY "config/kcm" + #define CONFDB_KCM_SOCKET "socket_path" ++#define CONFDB_KCM_DB "ccache_storage" /* Undocumented on purpose */ + + struct confdb_ctx; + struct config_file_ctx; +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 5e789c51658c51c0af1338d23d6c0f30f40bf119..67a5d1f5ad447a942b437ffd04a7f5d7cfe77d7f 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -280,6 +280,7 @@ option = fd_limit + option = client_idle_timeout + option = description + option = socket_path ++option = ccache_storage + + [rule/allowed_domain_options] + validator = ini_allowed_options +diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c +index 2c12ef215ce3967df183e51c20590c5f439d278f..063c27b915b4b92f6259496feee891aa94a498b6 100644 +--- a/src/responder/kcm/kcm.c ++++ b/src/responder/kcm/kcm.c +@@ -47,6 +47,37 @@ static int kcm_responder_ctx_destructor(void *ptr) + return 0; + } + ++static errno_t kcm_get_ccdb_be(struct kcm_ctx *kctx) ++{ ++ errno_t ret; ++ char *str_db; ++ ++ ret = confdb_get_string(kctx->rctx->cdb, ++ kctx->rctx, ++ kctx->rctx->confdb_service_path, ++ CONFDB_KCM_DB, ++ "secrets", ++ &str_db); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get the KCM database type [%d]: %s\n", ++ ret, strerror(ret)); ++ return ret; ++ } ++ ++ DEBUG(SSSDBG_CONF_SETTINGS, "KCM database type: %s\n", str_db); ++ if (strcasecmp(str_db, "memory") == 0) { ++ kctx->cc_be = CCDB_BE_MEMORY; ++ return EOK; ++ } else if (strcasecmp(str_db, "secrets") == 0) { ++ kctx->cc_be = CCDB_BE_SECRETS; ++ return EOK; ++ } ++ ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unexpected KCM database type %s\n", str_db); ++ return EOK; ++} ++ + static int kcm_get_config(struct kcm_ctx *kctx) + { + int ret; +@@ -88,14 +119,21 @@ static int kcm_get_config(struct kcm_ctx *kctx) + &sock_name); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +- "Cannot get the client idle timeout [%d]: %s\n", ++ "Cannot get KCM socket path [%d]: %s\n", + ret, strerror(ret)); + goto done; + } + kctx->rctx->sock_name = sock_name; + ++ ret = kcm_get_ccdb_be(kctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get KCM ccache DB [%d]: %s\n", ++ ret, strerror(ret)); ++ goto done; ++ } ++ + ret = EOK; +- + done: + return ret; + } +@@ -111,7 +149,8 @@ static int kcm_data_destructor(void *ptr) + } + + static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx, +- struct tevent_context *ev) ++ struct tevent_context *ev, ++ enum kcm_ccdb_be cc_be) + { + struct kcm_resp_ctx *kcm_data; + krb5_error_code kret; +@@ -122,7 +161,7 @@ static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx, + return NULL; + } + +- kcm_data->db = kcm_ccdb_init(kcm_data, ev, CCDB_BE_MEMORY); ++ kcm_data->db = kcm_ccdb_init(kcm_data, ev, cc_be); + if (kcm_data->db == NULL) { + talloc_free(kcm_data); + return NULL; +@@ -176,7 +215,7 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx, + goto fail; + } + +- kctx->kcm_data = kcm_data_setup(kctx, ev); ++ kctx->kcm_data = kcm_data_setup(kctx, ev, kctx->cc_be); + if (kctx->kcm_data == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, + "fatal error initializing responder data\n"); +diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c +index 2ae120269b0c62275ba2acdff6d6daa8b7077708..a22184e0f2b1300f3678bb343b6a110bf144a36b 100644 +--- a/src/responder/kcm/kcmsrv_ccache.c ++++ b/src/responder/kcm/kcmsrv_ccache.c +@@ -244,7 +244,7 @@ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx, + break; + case CCDB_BE_SECRETS: + DEBUG(SSSDBG_FUNC_DATA, "KCM back end: sssd-secrets\n"); +- /* Not implemented yet */ ++ ccdb->ops = &ccdb_sec_ops; + break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, "Unknown ccache database\n"); +diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h +index 18c8c47ad4ecb24521a85a1833b239c7a2a8bb45..36c481c5335d557318f0ed0204d93e533b4b6c41 100644 +--- a/src/responder/kcm/kcmsrv_ccache.h ++++ b/src/responder/kcm/kcmsrv_ccache.h +@@ -29,6 +29,7 @@ + #include "util/util.h" + #include "util/sss_iobuf.h" + #include "util/util_creds.h" ++#include "responder/kcm/kcmsrv_pvt.h" + + #define UUID_BYTES 16 + #define UUID_STR_SIZE 37 +@@ -113,11 +114,6 @@ errno_t kcm_cc_store_cred_blob(struct kcm_ccache *cc, + struct kcm_cred *kcm_cc_get_cred(struct kcm_ccache *cc); + struct kcm_cred *kcm_cc_next_cred(struct kcm_cred *crd); + +-enum kcm_ccdb_be { +- CCDB_BE_MEMORY, +- CCDB_BE_SECRETS, +-}; +- + /* An opaque database that contains all the ccaches */ + struct kcm_ccdb; + +diff --git a/src/responder/kcm/kcmsrv_ccache_be.h b/src/responder/kcm/kcmsrv_ccache_be.h +index 1bd2b6981e227675866e82e0a5389445cac4df66..a0796c298bae15a01adf612a6195a494ba6b4d23 100644 +--- a/src/responder/kcm/kcmsrv_ccache_be.h ++++ b/src/responder/kcm/kcmsrv_ccache_be.h +@@ -200,5 +200,6 @@ struct kcm_ccdb_ops { + }; + + extern const struct kcm_ccdb_ops ccdb_mem_ops; ++extern const struct kcm_ccdb_ops ccdb_sec_ops; + + #endif /* _KCMSRV_CCACHE_BE_ */ +diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h +index a29680246c1e616da75e1bbff951ce2fad66fb65..74f30c00014105ed533744779b02c5d42523722d 100644 +--- a/src/responder/kcm/kcmsrv_pvt.h ++++ b/src/responder/kcm/kcmsrv_pvt.h +@@ -49,6 +49,12 @@ struct kcm_resp_ctx { + struct kcm_ccdb *db; + }; + ++/* Supported ccache back ends */ ++enum kcm_ccdb_be { ++ CCDB_BE_MEMORY, ++ CCDB_BE_SECRETS, ++}; ++ + /* + * responder context that contains both the responder data, + * like the ccaches and the sssd-specific stuff like the +@@ -58,6 +64,7 @@ struct kcm_ctx { + struct resp_ctx *rctx; + int fd_limit; + char *socket_path; ++ enum kcm_ccdb_be cc_be; + + struct kcm_resp_ctx *kcm_data; + }; +-- +2.9.3 + diff --git a/SOURCES/0034-UTIL-make-domain-mapping-content-testable.patch b/SOURCES/0034-UTIL-make-domain-mapping-content-testable.patch deleted file mode 100644 index c3dcc69..0000000 --- a/SOURCES/0034-UTIL-make-domain-mapping-content-testable.patch +++ /dev/null @@ -1,286 +0,0 @@ -From 9d02728f8d64742e28f32fdf5bfdf083dc15a5c8 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 18 Jul 2016 17:37:49 +0200 -Subject: [PATCH 34/44] UTIL: make domain mapping content testable - -Reviewed-by: Jakub Hrozek ---- - src/util/domain_info_utils.c | 216 +++++++++++++++++++++++++++---------------- - src/util/util.h | 4 + - 2 files changed, 138 insertions(+), 82 deletions(-) - -diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c -index 8cdd50d8d521d734e9ffd9b4e81cd6fbd7d158c7..587a6b993d2bd70662df8e0b0d5963fa00c84cf8 100644 ---- a/src/util/domain_info_utils.c -+++ b/src/util/domain_info_utils.c -@@ -262,11 +262,135 @@ sss_krb5_touch_config(void) - return EOK; - } - -+errno_t sss_get_domain_mappings_content(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domain, -+ char **content) -+{ -+ int ret; -+ char *o = NULL; -+ struct sss_domain_info *dom; -+ struct sss_domain_info *parent_dom; -+ char *uc_parent = NULL; -+ char *uc_forest = NULL; -+ char *parent_capaths = NULL; -+ bool capaths_started = false; -+ -+ if (domain == NULL || content == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing parameter.\n"); -+ return EINVAL; -+ } -+ -+ o = talloc_strdup(mem_ctx, "[domain_realm]\n"); -+ if (o == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ /* This loops skips the starting parent and start rigth with the first -+ * subdomain. Although in all the interesting cases (AD and IPA) the -+ * default is that realm and DNS domain are the same strings (expect case) -+ * and no domain_realm mapping is needed we might consider to add this -+ * domain here as well to cover corner cases? */ -+ for (dom = get_next_domain(domain, SSS_GND_DESCEND); -+ dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */ -+ dom = get_next_domain(dom, 0)) { -+ o = talloc_asprintf_append(o, ".%s = %s\n%s = %s\n", -+ dom->name, dom->realm, dom->name, dom->realm); -+ if (o == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf_append failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ -+ parent_dom = domain; -+ uc_parent = get_uppercase_realm(mem_ctx, parent_dom->name); -+ if (uc_parent == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "get_uppercase_realm failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ for (dom = get_next_domain(domain, SSS_GND_DESCEND); -+ dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */ -+ dom = get_next_domain(dom, 0)) { -+ -+ if (dom->forest == NULL) { -+ continue; -+ } -+ -+ talloc_free(uc_forest); -+ uc_forest = get_uppercase_realm(mem_ctx, dom->forest); -+ if (uc_forest == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "get_uppercase_realm failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ if (!capaths_started) { -+ o = talloc_asprintf_append(o, "[capaths]\n"); -+ if (o == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf_append failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ capaths_started = true; -+ } -+ -+ o = talloc_asprintf_append(o, "%s = {\n %s = %s\n}\n", -+ dom->realm, uc_parent, uc_forest); -+ if (o == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf_append failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ if (parent_capaths == NULL) { -+ parent_capaths = talloc_asprintf(mem_ctx, " %s = %s\n", dom->realm, -+ uc_forest); -+ } else { -+ parent_capaths = talloc_asprintf_append(parent_capaths, -+ " %s = %s\n", dom->realm, -+ uc_forest); -+ } -+ if (parent_capaths == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "talloc_asprintf/talloc_asprintf_append failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ -+ if (parent_capaths != NULL) { -+ o = talloc_asprintf_append(o, "%s = {\n%s}\n", uc_parent, -+ parent_capaths); -+ if (o == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf_append failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ -+ ret = EOK; -+ -+done: -+ talloc_free(parent_capaths); -+ talloc_free(uc_parent); -+ talloc_free(uc_forest); -+ -+ if (ret == EOK) { -+ *content = o; -+ } else { -+ talloc_free(o); -+ } -+ -+ return ret; -+} -+ - errno_t - sss_write_domain_mappings(struct sss_domain_info *domain) - { -- struct sss_domain_info *dom; -- struct sss_domain_info *parent_dom; - errno_t ret; - errno_t err; - TALLOC_CTX *tmp_ctx; -@@ -277,10 +401,7 @@ sss_write_domain_mappings(struct sss_domain_info *domain) - mode_t old_mode; - FILE *fstream = NULL; - int i; -- bool capaths_started = false; -- char *uc_forest; -- char *uc_parent; -- char *parent_capaths = NULL; -+ char *content = NULL; - - if (domain == NULL || domain->name == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "No domain name provided\n"); -@@ -290,6 +411,12 @@ sss_write_domain_mappings(struct sss_domain_info *domain) - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) return ENOMEM; - -+ ret = sss_get_domain_mappings_content(tmp_ctx, domain, &content); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sss_get_domain_mappings_content failed.\n"); -+ goto done; -+ } -+ - sanitized_domain = talloc_strdup(tmp_ctx, domain->name); - if (sanitized_domain == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); -@@ -349,88 +476,13 @@ sss_write_domain_mappings(struct sss_domain_info *domain) - goto done; - } - -- ret = fprintf(fstream, "[domain_realm]\n"); -+ ret = fprintf(fstream, "%s", content); - if (ret < 0) { - DEBUG(SSSDBG_OP_FAILURE, "fprintf failed\n"); - ret = EIO; - goto done; - } - -- for (dom = get_next_domain(domain, SSS_GND_DESCEND); -- dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */ -- dom = get_next_domain(dom, 0)) { -- ret = fprintf(fstream, ".%s = %s\n%s = %s\n", -- dom->name, dom->realm, dom->name, dom->realm); -- if (ret < 0) { -- DEBUG(SSSDBG_CRIT_FAILURE, "fprintf failed\n"); -- goto done; -- } -- } -- -- parent_dom = domain; -- uc_parent = get_uppercase_realm(tmp_ctx, parent_dom->name); -- if (uc_parent == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "get_uppercase_realm failed.\n"); -- ret = ENOMEM; -- goto done; -- } -- -- for (dom = get_next_domain(domain, SSS_GND_DESCEND); -- dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */ -- dom = get_next_domain(dom, 0)) { -- -- if (dom->forest == NULL) { -- continue; -- } -- -- uc_forest = get_uppercase_realm(tmp_ctx, dom->forest); -- if (uc_forest == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "get_uppercase_realm failed.\n"); -- ret = ENOMEM; -- goto done; -- } -- -- if (!capaths_started) { -- ret = fprintf(fstream, "[capaths]\n"); -- if (ret < 0) { -- DEBUG(SSSDBG_OP_FAILURE, "fprintf failed\n"); -- ret = EIO; -- goto done; -- } -- capaths_started = true; -- } -- -- ret = fprintf(fstream, "%s = {\n %s = %s\n}\n", -- dom->realm, uc_parent, uc_forest); -- if (ret < 0) { -- DEBUG(SSSDBG_CRIT_FAILURE, "fprintf failed\n"); -- goto done; -- } -- -- if (parent_capaths == NULL) { -- parent_capaths = talloc_asprintf(tmp_ctx, " %s = %s\n", dom->realm, -- uc_forest); -- } else { -- parent_capaths = talloc_asprintf_append(parent_capaths, -- " %s = %s\n", dom->realm, -- uc_forest); -- } -- if (parent_capaths == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, -- "talloc_asprintf/talloc_asprintf_append failed.\n"); -- ret = ENOMEM; -- goto done; -- } -- } -- -- if (parent_capaths != NULL) { -- ret = fprintf(fstream, "%s = {\n%s}\n", uc_parent, parent_capaths); -- if (ret < 0) { -- DEBUG(SSSDBG_CRIT_FAILURE, "fprintf failed\n"); -- goto done; -- } -- } -- - ret = fclose(fstream); - fstream = NULL; - if (ret != 0) { -diff --git a/src/util/util.h b/src/util/util.h -index 8a5caa52c2dc5243c3ae51c5a38fd65a949f4ac4..122be90b967fb7793adaff95f3754d7a199fcf48 100644 ---- a/src/util/util.h -+++ b/src/util/util.h -@@ -540,6 +540,10 @@ errno_t sssd_domain_init(TALLOC_CTX *mem_ctx, - * written to */ - #define KRB5_MAPPING_DIR PUBCONF_PATH"/krb5.include.d" - -+errno_t sss_get_domain_mappings_content(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domain, -+ char **content); -+ - errno_t sss_write_domain_mappings(struct sss_domain_info *domain); - - errno_t sss_write_krb5_conf_snippet(const char *path, bool canonicalize); --- -2.4.11 - diff --git a/SOURCES/0035-KCM-Queue-requests-by-the-same-UID.patch b/SOURCES/0035-KCM-Queue-requests-by-the-same-UID.patch new file mode 100644 index 0000000..338c394 --- /dev/null +++ b/SOURCES/0035-KCM-Queue-requests-by-the-same-UID.patch @@ -0,0 +1,909 @@ +From 688e8d8ffe331a1dd75a78002bf212277f2d7664 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 21 Mar 2017 13:25:11 +0100 +Subject: [PATCH 35/36] KCM: Queue requests by the same UID +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In order to avoid race conditions, we queue requests towards the KCM +responder coming from the same client UID. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +Reviewed-by: Lukáš Slebodník +--- + Makefile.am | 21 ++- + src/responder/kcm/kcm.c | 7 + + src/responder/kcm/kcmsrv_cmd.c | 10 +- + src/responder/kcm/kcmsrv_op_queue.c | 264 ++++++++++++++++++++++++++ + src/responder/kcm/kcmsrv_ops.c | 44 ++++- + src/responder/kcm/kcmsrv_ops.h | 1 + + src/responder/kcm/kcmsrv_pvt.h | 20 ++ + src/tests/cmocka/test_kcm_queue.c | 365 ++++++++++++++++++++++++++++++++++++ + 8 files changed, 721 insertions(+), 11 deletions(-) + create mode 100644 src/responder/kcm/kcmsrv_op_queue.c + create mode 100644 src/tests/cmocka/test_kcm_queue.c + +diff --git a/Makefile.am b/Makefile.am +index e9eaa312c91e3aee40bcf13c90a0ad8c683045d5..91afdd669aa11a3cc316588d3b51d7e8e9c91cb8 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -304,7 +304,10 @@ non_interactive_cmocka_based_tests += test_inotify + endif # HAVE_INOTIFY + + if BUILD_KCM +-non_interactive_cmocka_based_tests += test_kcm_json ++non_interactive_cmocka_based_tests += \ ++ test_kcm_json \ ++ test_kcm_queue \ ++ $(NULL) + endif # BUILD_KCM + + if BUILD_SAMBA +@@ -1501,6 +1504,7 @@ sssd_kcm_SOURCES = \ + src/responder/kcm/kcmsrv_ccache_json.c \ + src/responder/kcm/kcmsrv_ccache_secrets.c \ + src/responder/kcm/kcmsrv_ops.c \ ++ src/responder/kcm/kcmsrv_op_queue.c \ + src/util/sss_sockets.c \ + src/util/sss_krb5.c \ + src/util/sss_iobuf.c \ +@@ -3402,6 +3406,21 @@ test_kcm_json_LDADD = \ + $(SSSD_INTERNAL_LTLIBS) \ + libsss_test_common.la \ + $(NULL) ++ ++test_kcm_queue_SOURCES = \ ++ src/tests/cmocka/test_kcm_queue.c \ ++ src/responder/kcm/kcmsrv_op_queue.c \ ++ $(NULL) ++test_kcm_queue_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(NULL) ++test_kcm_queue_LDADD = \ ++ $(CMOCKA_LIBS) \ ++ $(SSSD_LIBS) \ ++ $(SSSD_INTERNAL_LTLIBS) \ ++ libsss_test_common.la \ ++ $(NULL) ++ + endif # BUILD_KCM + + endif # HAVE_CMOCKA +diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c +index 063c27b915b4b92f6259496feee891aa94a498b6..3ee978066c589a5cc38b0ae358f741d389d00e7a 100644 +--- a/src/responder/kcm/kcm.c ++++ b/src/responder/kcm/kcm.c +@@ -133,6 +133,13 @@ static int kcm_get_config(struct kcm_ctx *kctx) + goto done; + } + ++ kctx->qctx = kcm_ops_queue_create(kctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot create KCM request queue [%d]: %s\n", ++ ret, strerror(ret)); ++ goto done; ++ } + ret = EOK; + done: + return ret; +diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c +index 537e88953fd1a190a9a73bcdd430d8e0db8f9291..81015de4a91617de3dca444cde95b636c8d5c0d1 100644 +--- a/src/responder/kcm/kcmsrv_cmd.c ++++ b/src/responder/kcm/kcmsrv_cmd.c +@@ -353,14 +353,18 @@ struct kcm_req_ctx { + + static void kcm_cmd_request_done(struct tevent_req *req); + +-static errno_t kcm_cmd_dispatch(struct kcm_req_ctx *req_ctx) ++static errno_t kcm_cmd_dispatch(struct kcm_ctx *kctx, ++ struct kcm_req_ctx *req_ctx) + { + struct tevent_req *req; + struct cli_ctx *cctx; + + cctx = req_ctx->cctx; + +- req = kcm_cmd_send(req_ctx, cctx->ev, req_ctx->kctx->kcm_data, ++ req = kcm_cmd_send(req_ctx, ++ cctx->ev, ++ kctx->qctx, ++ req_ctx->kctx->kcm_data, + req_ctx->cctx->creds, + &req_ctx->op_io.request, + req_ctx->op_io.op); +@@ -505,7 +509,7 @@ static void kcm_recv(struct cli_ctx *cctx) + /* do not read anymore, client is done sending */ + TEVENT_FD_NOT_READABLE(cctx->cfde); + +- ret = kcm_cmd_dispatch(req); ++ ret = kcm_cmd_dispatch(kctx, req); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to dispatch KCM operation [%d]: %s\n", +diff --git a/src/responder/kcm/kcmsrv_op_queue.c b/src/responder/kcm/kcmsrv_op_queue.c +new file mode 100644 +index 0000000000000000000000000000000000000000..f6c425dd5b64877c8b7401e488dd6565157fc9b5 +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_op_queue.c +@@ -0,0 +1,264 @@ ++/* ++ SSSD ++ ++ KCM Server - the KCM operations wait queue ++ ++ Copyright (C) Red Hat, 2017 ++ ++ 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 . ++*/ ++ ++#include "util/util.h" ++#include "util/util_creds.h" ++#include "responder/kcm/kcmsrv_pvt.h" ++ ++#define QUEUE_HASH_SIZE 32 ++ ++struct kcm_ops_queue_entry { ++ struct tevent_req *req; ++ uid_t uid; ++ ++ hash_table_t *wait_queue_hash; ++ ++ struct kcm_ops_queue_entry *head; ++ struct kcm_ops_queue_entry *next; ++ struct kcm_ops_queue_entry *prev; ++}; ++ ++struct kcm_ops_queue_ctx { ++ /* UID: dlist of kcm_ops_queue_entry */ ++ hash_table_t *wait_queue_hash; ++}; ++ ++/* ++ * Per-UID wait queue ++ * ++ * They key in the hash table is the UID of the peer. The value of each ++ * hash table entry is a linked list of kcm_ops_queue_entry structures ++ * which primarily hold the tevent request being queued. ++ */ ++struct kcm_ops_queue_ctx *kcm_ops_queue_create(TALLOC_CTX *mem_ctx) ++{ ++ errno_t ret; ++ struct kcm_ops_queue_ctx *queue_ctx; ++ ++ queue_ctx = talloc_zero(mem_ctx, struct kcm_ops_queue_ctx); ++ if (queue_ctx == NULL) { ++ return NULL; ++ } ++ ++ ret = sss_hash_create_ex(mem_ctx, QUEUE_HASH_SIZE, ++ &queue_ctx->wait_queue_hash, 0, 0, 0, 0, ++ NULL, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_hash_create failed [%d]: %s\n", ret, sss_strerror(ret)); ++ talloc_free(queue_ctx); ++ return NULL; ++ } ++ ++ return queue_ctx; ++} ++ ++static int kcm_op_queue_entry_destructor(struct kcm_ops_queue_entry *entry) ++{ ++ int ret; ++ struct kcm_ops_queue_entry *next_entry; ++ hash_key_t key; ++ ++ if (entry == NULL) { ++ return 1; ++ } ++ ++ /* Take the next entry from the queue */ ++ next_entry = entry->next; ++ ++ /* Remove the current entry from the queue */ ++ DLIST_REMOVE(entry->head, entry); ++ ++ if (next_entry == NULL) { ++ key.type = HASH_KEY_ULONG; ++ key.ul = entry->uid; ++ ++ /* If this was the last entry, remove the key (the UID) from the ++ * hash table to signal the queue is empty ++ */ ++ ret = hash_delete(entry->wait_queue_hash, &key); ++ if (ret != HASH_SUCCESS) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to remove wait queue for user %"SPRIuid"\n", ++ entry->uid); ++ return 1; ++ } ++ return 0; ++ } ++ ++ /* Otherwise, mark the current head as done to run the next request */ ++ tevent_req_done(next_entry->req); ++ return 0; ++} ++ ++static errno_t kcm_op_queue_add(hash_table_t *wait_queue_hash, ++ struct kcm_ops_queue_entry *entry, ++ uid_t uid) ++{ ++ errno_t ret; ++ hash_key_t key; ++ hash_value_t value; ++ struct kcm_ops_queue_entry *head = NULL; ++ ++ key.type = HASH_KEY_ULONG; ++ key.ul = uid; ++ ++ ret = hash_lookup(wait_queue_hash, &key, &value); ++ switch (ret) { ++ case HASH_SUCCESS: ++ /* The key with this UID already exists. Its value is request queue ++ * for the UID, so let's just add the current request to the end ++ * of the queue and wait for the previous requests to finish ++ */ ++ if (value.type != HASH_VALUE_PTR) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected hash value type.\n"); ++ return EINVAL; ++ } ++ ++ head = talloc_get_type(value.ptr, struct kcm_ops_queue_entry); ++ if (head == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid queue pointer\n"); ++ return EINVAL; ++ } ++ ++ entry->head = head; ++ DLIST_ADD_END(head, entry, struct kcm_ops_queue_entry *); ++ ++ DEBUG(SSSDBG_TRACE_LIBS, "Waiting in queue\n"); ++ ret = EAGAIN; ++ break; ++ ++ case HASH_ERROR_KEY_NOT_FOUND: ++ /* No request for this UID yet. Enqueue this request in case ++ * another one comes in and return EOK to run the current request ++ * immediatelly ++ */ ++ entry->head = entry; ++ ++ value.type = HASH_VALUE_PTR; ++ value.ptr = entry; ++ ++ ret = hash_enter(wait_queue_hash, &key, &value); ++ if (ret != HASH_SUCCESS) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "hash_enter failed.\n"); ++ return EIO; ++ } ++ ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "Added a first request to the queue, running immediately\n"); ++ ret = EOK; ++ break; ++ ++ default: ++ DEBUG(SSSDBG_CRIT_FAILURE, "hash_lookup failed.\n"); ++ return EIO; ++ } ++ ++ talloc_steal(wait_queue_hash, entry); ++ talloc_set_destructor(entry, kcm_op_queue_entry_destructor); ++ return ret; ++} ++ ++struct kcm_op_queue_state { ++ struct kcm_ops_queue_entry *entry; ++}; ++ ++/* ++ * Enqueue a request. ++ * ++ * If the request queue /for the given ID/ is empty, that is, if this ++ * request is the first one in the queue, run the request immediatelly. ++ * ++ * Otherwise just add it to the queue and wait until the previous request ++ * finishes and only at that point mark the current request as done, which ++ * will trigger calling the recv function and allow the request to continue. ++ */ ++struct tevent_req *kcm_op_queue_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ops_queue_ctx *qctx, ++ struct cli_creds *client) ++{ ++ errno_t ret; ++ struct tevent_req *req; ++ struct kcm_op_queue_state *state; ++ uid_t uid; ++ ++ uid = cli_creds_get_uid(client); ++ ++ req = tevent_req_create(mem_ctx, &state, struct kcm_op_queue_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ state->entry = talloc_zero(state, struct kcm_ops_queue_entry); ++ if (state->entry == NULL) { ++ ret = ENOMEM; ++ goto immediate; ++ } ++ state->entry->req = req; ++ state->entry->uid = uid; ++ state->entry->wait_queue_hash = qctx->wait_queue_hash; ++ ++ DEBUG(SSSDBG_FUNC_DATA, ++ "Adding request by %"SPRIuid" to the wait queue\n", uid); ++ ++ ret = kcm_op_queue_add(qctx->wait_queue_hash, state->entry, uid); ++ if (ret == EOK) { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "Wait queue was empty, running immediately\n"); ++ goto immediate; ++ } else if (ret != EAGAIN) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot enqueue request [%d]: %s\n", ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ DEBUG(SSSDBG_TRACE_LIBS, "Waiting our turn in the queue\n"); ++ return req; ++ ++immediate: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++/* ++ * The queue recv function is called when this request is 'activated'. The queue ++ * entry should be allocated on the same memory context as the enqueued request ++ * to trigger freeing the kcm_ops_queue_entry structure destructor when the ++ * parent request is done and its tevent_req freed. This would in turn unblock ++ * the next request in the queue ++ */ ++errno_t kcm_op_queue_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ops_queue_entry **_entry) ++{ ++ struct kcm_op_queue_state *state = tevent_req_data(req, ++ struct kcm_op_queue_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_entry = talloc_steal(mem_ctx, state->entry); ++ return EOK; ++} +diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c +index 50e8cc635424e15d53e3c8d122c5525044f59c8a..2feaf51f227ce9d90f706229ce7ac201b282dc6f 100644 +--- a/src/responder/kcm/kcmsrv_ops.c ++++ b/src/responder/kcm/kcmsrv_ops.c +@@ -67,17 +67,21 @@ struct kcm_op { + + struct kcm_cmd_state { + struct kcm_op *op; ++ struct tevent_context *ev; + ++ struct kcm_ops_queue_entry *queue_entry; + struct kcm_op_ctx *op_ctx; + struct sss_iobuf *reply; + + uint32_t op_ret; + }; + ++static void kcm_cmd_queue_done(struct tevent_req *subreq); + static void kcm_cmd_done(struct tevent_req *subreq); + + struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, ++ struct kcm_ops_queue_ctx *qctx, + struct kcm_resp_ctx *kcm_data, + struct cli_creds *client, + struct kcm_data *input, +@@ -93,6 +97,7 @@ struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx, + return NULL; + } + state->op = op; ++ state->ev = ev; + + if (op == NULL) { + ret = EINVAL; +@@ -154,18 +159,43 @@ struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx, + goto immediate; + } + +- subreq = op->fn_send(state, ev, state->op_ctx); ++ subreq = kcm_op_queue_send(state, ev, qctx, client); + if (subreq == NULL) { + ret = ENOMEM; + goto immediate; + } ++ tevent_req_set_callback(subreq, kcm_cmd_queue_done, req); ++ return req; ++ ++immediate: ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static void kcm_cmd_queue_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); ++ struct kcm_cmd_state *state = tevent_req_data(req, struct kcm_cmd_state); ++ errno_t ret; ++ ++ /* When this request finishes, it frees the queue_entry which unblocks ++ * other requests by the same UID ++ */ ++ ret = kcm_op_queue_recv(subreq, state, &state->queue_entry); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot acquire queue slot\n"); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ subreq = state->op->fn_send(state, state->ev, state->op_ctx); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } + tevent_req_set_callback(subreq, kcm_cmd_done, req); +- return req; +- +-immediate: +- tevent_req_error(req, ret); +- tevent_req_post(req, ev); +- return req; + } + + static void kcm_cmd_done(struct tevent_req *subreq) +diff --git a/src/responder/kcm/kcmsrv_ops.h b/src/responder/kcm/kcmsrv_ops.h +index 8e6feaf56a10b73c8b6375aea9ef26c392b5b492..67d9f86026bf949548471f2280c130ebefd2f865 100644 +--- a/src/responder/kcm/kcmsrv_ops.h ++++ b/src/responder/kcm/kcmsrv_ops.h +@@ -34,6 +34,7 @@ const char *kcm_opt_name(struct kcm_op *op); + + struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, ++ struct kcm_ops_queue_ctx *qctx, + struct kcm_resp_ctx *kcm_data, + struct cli_creds *client, + struct kcm_data *input, +diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h +index 74f30c00014105ed533744779b02c5d42523722d..f081a6bf0c6e40d2f8a83b07f9bbc2abacff359d 100644 +--- a/src/responder/kcm/kcmsrv_pvt.h ++++ b/src/responder/kcm/kcmsrv_pvt.h +@@ -25,6 +25,7 @@ + #include "config.h" + + #include ++#include + #include "responder/common/responder.h" + + /* +@@ -65,6 +66,7 @@ struct kcm_ctx { + int fd_limit; + char *socket_path; + enum kcm_ccdb_be cc_be; ++ struct kcm_ops_queue_ctx *qctx; + + struct kcm_resp_ctx *kcm_data; + }; +@@ -78,4 +80,22 @@ int kcm_connection_setup(struct cli_ctx *cctx); + */ + krb5_error_code sss2krb5_error(errno_t err); + ++/* We enqueue all requests by the same UID to avoid concurrency issues ++ * especially when performing multiple round-trips to sssd-secrets. In ++ * future, we should relax the queue to allow multiple read-only operations ++ * if no write operations are in progress. ++ */ ++struct kcm_ops_queue_entry; ++ ++struct kcm_ops_queue_ctx *kcm_ops_queue_create(TALLOC_CTX *mem_ctx); ++ ++struct tevent_req *kcm_op_queue_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ops_queue_ctx *qctx, ++ struct cli_creds *client); ++ ++errno_t kcm_op_queue_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ struct kcm_ops_queue_entry **_entry); ++ + #endif /* __KCMSRV_PVT_H__ */ +diff --git a/src/tests/cmocka/test_kcm_queue.c b/src/tests/cmocka/test_kcm_queue.c +new file mode 100644 +index 0000000000000000000000000000000000000000..ba0d2405629960df5c623848f3207b7c80fa948d +--- /dev/null ++++ b/src/tests/cmocka/test_kcm_queue.c +@@ -0,0 +1,365 @@ ++/* ++ Copyright (C) 2017 Red Hat ++ ++ SSSD tests: Test KCM wait queue ++ ++ 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 . ++*/ ++ ++#include "config.h" ++ ++#include ++#include ++ ++#include "util/util.h" ++#include "util/util_creds.h" ++#include "tests/cmocka/common_mock.h" ++#include "responder/kcm/kcmsrv_pvt.h" ++ ++#define INVALID_ID -1 ++#define FAST_REQ_ID 0 ++#define SLOW_REQ_ID 1 ++ ++#define FAST_REQ_DELAY 1 ++#define SLOW_REQ_DELAY 2 ++ ++struct timed_request_state { ++ struct tevent_context *ev; ++ struct kcm_ops_queue_ctx *qctx; ++ struct cli_creds *client; ++ int delay; ++ int req_id; ++ ++ struct kcm_ops_queue_entry *queue_entry; ++}; ++ ++static void timed_request_start(struct tevent_req *subreq); ++static void timed_request_done(struct tevent_context *ev, ++ struct tevent_timer *te, ++ struct timeval current_time, ++ void *pvt); ++ ++static struct tevent_req *timed_request_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct kcm_ops_queue_ctx *qctx, ++ struct cli_creds *client, ++ int delay, ++ int req_id) ++{ ++ struct tevent_req *req; ++ struct tevent_req *subreq; ++ struct timed_request_state *state; ++ ++ req = tevent_req_create(mem_ctx, &state, struct timed_request_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ state->ev = ev; ++ state->qctx = qctx; ++ state->client = client; ++ state->delay = delay; ++ state->req_id = req_id; ++ ++ DEBUG(SSSDBG_TRACE_ALL, "Request %p with delay %d\n", req, delay); ++ ++ subreq = kcm_op_queue_send(state, ev, qctx, client); ++ if (subreq == NULL) { ++ return NULL; ++ } ++ tevent_req_set_callback(subreq, timed_request_start, req); ++ ++ return req; ++} ++ ++static void timed_request_start(struct tevent_req *subreq) ++{ ++ struct timeval tv; ++ struct tevent_timer *timeout = NULL; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct timed_request_state *state = tevent_req_data(req, ++ struct timed_request_state); ++ errno_t ret; ++ ++ ret = kcm_op_queue_recv(subreq, state, &state->queue_entry); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tv = tevent_timeval_current_ofs(state->delay, 0); ++ timeout = tevent_add_timer(state->ev, state, tv, timed_request_done, req); ++ if (timeout == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ return; ++} ++ ++static void timed_request_done(struct tevent_context *ev, ++ struct tevent_timer *te, ++ struct timeval current_time, ++ void *pvt) ++{ ++ struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); ++ DEBUG(SSSDBG_TRACE_ALL, "Request %p done\n", req); ++ tevent_req_done(req); ++} ++ ++static errno_t timed_request_recv(struct tevent_req *req, ++ int *req_id) ++{ ++ struct timed_request_state *state = tevent_req_data(req, ++ struct timed_request_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *req_id = state->req_id; ++ return EOK; ++} ++ ++struct test_ctx { ++ struct kcm_ops_queue_ctx *qctx; ++ struct tevent_context *ev; ++ ++ int *req_ids; ++ ++ int num_requests; ++ int finished_requests; ++ bool done; ++ errno_t error; ++}; ++ ++static int setup_kcm_queue(void **state) ++{ ++ struct test_ctx *tctx; ++ ++ tctx = talloc_zero(NULL, struct test_ctx); ++ assert_non_null(tctx); ++ ++ tctx->ev = tevent_context_init(tctx); ++ assert_non_null(tctx->ev); ++ ++ tctx->qctx = kcm_ops_queue_create(tctx); ++ assert_non_null(tctx->qctx); ++ ++ *state = tctx; ++ return 0; ++} ++ ++static int teardown_kcm_queue(void **state) ++{ ++ struct test_ctx *tctx = talloc_get_type(*state, struct test_ctx); ++ talloc_free(tctx); ++ return 0; ++} ++ ++static void test_kcm_queue_done(struct tevent_req *req) ++{ ++ struct test_ctx *test_ctx = tevent_req_callback_data(req, ++ struct test_ctx); ++ int req_id = INVALID_ID; ++ ++ test_ctx->error = timed_request_recv(req, &req_id); ++ talloc_zfree(req); ++ if (test_ctx->error != EOK) { ++ test_ctx->done = true; ++ return; ++ } ++ ++ if (test_ctx->req_ids[test_ctx->finished_requests] != req_id) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Request %d finished, expected %d\n", ++ req_id, test_ctx->req_ids[test_ctx->finished_requests]); ++ test_ctx->error = EIO; ++ test_ctx->done = true; ++ return; ++ } ++ ++ test_ctx->finished_requests++; ++ if (test_ctx->finished_requests == test_ctx->num_requests) { ++ test_ctx->done = true; ++ return; ++ } ++} ++ ++/* ++ * Just make sure that a single pass through the queue works ++ */ ++static void test_kcm_queue_single(void **state) ++{ ++ struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx); ++ struct tevent_req *req; ++ struct cli_creds client; ++ static int req_ids[] = { 0 }; ++ ++ client.ucred.uid = getuid(); ++ client.ucred.gid = getgid(); ++ ++ req = timed_request_send(test_ctx, ++ test_ctx->ev, ++ test_ctx->qctx, ++ &client, 1, 0); ++ assert_non_null(req); ++ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx); ++ ++ test_ctx->num_requests = 1; ++ test_ctx->req_ids = req_ids; ++ ++ while (test_ctx->done == false) { ++ tevent_loop_once(test_ctx->ev); ++ } ++ assert_int_equal(test_ctx->error, EOK); ++} ++ ++/* ++ * Test that multiple requests from the same ID wait for one another ++ */ ++static void test_kcm_queue_multi_same_id(void **state) ++{ ++ struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx); ++ struct tevent_req *req; ++ struct cli_creds client; ++ /* The slow request will finish first because request from ++ * the same ID are serialized ++ */ ++ static int req_ids[] = { SLOW_REQ_ID, FAST_REQ_ID }; ++ ++ client.ucred.uid = getuid(); ++ client.ucred.gid = getgid(); ++ ++ req = timed_request_send(test_ctx, ++ test_ctx->ev, ++ test_ctx->qctx, ++ &client, ++ SLOW_REQ_DELAY, ++ SLOW_REQ_ID); ++ assert_non_null(req); ++ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx); ++ ++ req = timed_request_send(test_ctx, ++ test_ctx->ev, ++ test_ctx->qctx, ++ &client, ++ FAST_REQ_DELAY, ++ FAST_REQ_ID); ++ assert_non_null(req); ++ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx); ++ ++ test_ctx->num_requests = 2; ++ test_ctx->req_ids = req_ids; ++ ++ while (test_ctx->done == false) { ++ tevent_loop_once(test_ctx->ev); ++ } ++ assert_int_equal(test_ctx->error, EOK); ++} ++ ++/* ++ * Test that multiple requests from different IDs don't wait for one ++ * another and can run concurrently ++ */ ++static void test_kcm_queue_multi_different_id(void **state) ++{ ++ struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx); ++ struct tevent_req *req; ++ struct cli_creds client; ++ /* In this test, the fast request will finish sooner because ++ * both requests are from different IDs, allowing them to run ++ * concurrently ++ */ ++ static int req_ids[] = { FAST_REQ_ID, SLOW_REQ_ID }; ++ ++ client.ucred.uid = getuid(); ++ client.ucred.gid = getgid(); ++ ++ req = timed_request_send(test_ctx, ++ test_ctx->ev, ++ test_ctx->qctx, ++ &client, ++ SLOW_REQ_DELAY, ++ SLOW_REQ_ID); ++ assert_non_null(req); ++ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx); ++ ++ client.ucred.uid = getuid() + 1; ++ client.ucred.gid = getgid() + 1; ++ ++ req = timed_request_send(test_ctx, ++ test_ctx->ev, ++ test_ctx->qctx, ++ &client, ++ FAST_REQ_DELAY, ++ FAST_REQ_ID); ++ assert_non_null(req); ++ tevent_req_set_callback(req, test_kcm_queue_done, test_ctx); ++ ++ test_ctx->num_requests = 2; ++ test_ctx->req_ids = req_ids; ++ ++ while (test_ctx->done == false) { ++ tevent_loop_once(test_ctx->ev); ++ } ++ assert_int_equal(test_ctx->error, EOK); ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ poptContext pc; ++ int opt; ++ int rv; ++ struct poptOption long_options[] = { ++ POPT_AUTOHELP ++ SSSD_DEBUG_OPTS ++ POPT_TABLEEND ++ }; ++ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test_setup_teardown(test_kcm_queue_single, ++ setup_kcm_queue, ++ teardown_kcm_queue), ++ cmocka_unit_test_setup_teardown(test_kcm_queue_multi_same_id, ++ setup_kcm_queue, ++ teardown_kcm_queue), ++ cmocka_unit_test_setup_teardown(test_kcm_queue_multi_different_id, ++ setup_kcm_queue, ++ teardown_kcm_queue), ++ }; ++ ++ /* Set debug level to invalid value so we can deside if -d 0 was used. */ ++ debug_level = SSSDBG_INVALID; ++ ++ pc = poptGetContext(argv[0], argc, argv, long_options, 0); ++ while((opt = poptGetNextOpt(pc)) != -1) { ++ switch(opt) { ++ default: ++ fprintf(stderr, "\nInvalid option %s: %s\n\n", ++ poptBadOption(pc, 0), poptStrerror(opt)); ++ poptPrintUsage(pc, stderr, 0); ++ return 1; ++ } ++ } ++ poptFreeContext(pc); ++ ++ DEBUG_CLI_INIT(debug_level); ++ ++ /* Even though normally the tests should clean up after themselves ++ * they might not after a failed run. Remove the old db to be sure */ ++ tests_set_cwd(); ++ ++ rv = cmocka_run_group_tests(tests, NULL, NULL); ++ ++ return rv; ++} +-- +2.9.3 + diff --git a/SOURCES/0035-tests-add-tests-for-sss_get_domain_mappings_content.patch b/SOURCES/0035-tests-add-tests-for-sss_get_domain_mappings_content.patch deleted file mode 100644 index d2d75a0..0000000 --- a/SOURCES/0035-tests-add-tests-for-sss_get_domain_mappings_content.patch +++ /dev/null @@ -1,201 +0,0 @@ -From 16495f6aca6fb1a3f0cdb30b4a50493453e8ca0f Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 20 Jul 2016 12:03:48 +0200 -Subject: [PATCH 35/44] tests: add tests for sss_get_domain_mappings_content() - -Reviewed-by: Jakub Hrozek ---- - src/tests/cmocka/test_utils.c | 163 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 163 insertions(+) - -diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c -index b08b19708bb59a076a79805fa37a15924152b8e2..4c72a59437105e683cec2d39c36951aeff63767b 100644 ---- a/src/tests/cmocka/test_utils.c -+++ b/src/tests/cmocka/test_utils.c -@@ -55,6 +55,95 @@ struct dom_list_test_ctx { - struct sss_domain_info *dom_list; - }; - -+static int setup_dom_list_with_subdomains(void **state) -+{ -+ struct dom_list_test_ctx *test_ctx; -+ struct sss_domain_info *dom = NULL; -+ struct sss_domain_info *c = NULL; -+ -+ assert_true(leak_check_setup()); -+ -+ test_ctx = talloc_zero(global_talloc_context, struct dom_list_test_ctx); -+ assert_non_null(test_ctx); -+ -+ dom = talloc_zero(test_ctx, struct sss_domain_info); -+ assert_non_null(dom); -+ -+ dom->name = talloc_asprintf(dom, "configured.dom"); -+ assert_non_null(dom->name); -+ -+ dom->realm = talloc_asprintf(dom, "CONFIGURED.DOM"); -+ assert_non_null(dom->realm); -+ -+ dom->flat_name = talloc_asprintf(dom, "CONFIGURED"); -+ assert_non_null(dom->flat_name); -+ -+ dom->domain_id = talloc_asprintf(dom, "S-1-5-21-1-2-1"); -+ assert_non_null(dom->domain_id); -+ -+ DLIST_ADD(test_ctx->dom_list, dom); -+ -+ c = talloc_zero(test_ctx, struct sss_domain_info); -+ assert_non_null(c); -+ -+ c->name = talloc_asprintf(c, "subdom1.dom"); -+ assert_non_null(c->name); -+ -+ c->realm = talloc_asprintf(c, "SUBDOM1.DOM"); -+ assert_non_null(c->realm); -+ -+ c->flat_name = talloc_asprintf(c, "subdom1"); -+ assert_non_null(c->flat_name); -+ -+ c->domain_id = talloc_asprintf(c, "S-1-5-21-1-2-2"); -+ assert_non_null(c->domain_id); -+ -+ c->parent = dom; -+ -+ DLIST_ADD_END(test_ctx->dom_list, c, struct sss_domain_info *); -+ -+ c = talloc_zero(test_ctx, struct sss_domain_info); -+ assert_non_null(c); -+ -+ c->name = talloc_asprintf(c, "subdom2.dom"); -+ assert_non_null(c->name); -+ -+ c->realm = talloc_asprintf(c, "SUBDOM2.DOM"); -+ assert_non_null(c->realm); -+ -+ c->flat_name = talloc_asprintf(c, "subdom2"); -+ assert_non_null(c->flat_name); -+ -+ c->domain_id = talloc_asprintf(c, "S-1-5-21-1-2-3"); -+ assert_non_null(c->domain_id); -+ -+ c->parent = dom; -+ -+ DLIST_ADD_END(test_ctx->dom_list, c, struct sss_domain_info *); -+ -+ c = talloc_zero(test_ctx, struct sss_domain_info); -+ assert_non_null(c); -+ -+ c->name = talloc_asprintf(c, "subdom3.dom"); -+ assert_non_null(c->name); -+ -+ c->realm = talloc_asprintf(c, "SUBDOM3.DOM"); -+ assert_non_null(c->realm); -+ -+ c->flat_name = talloc_asprintf(c, "subdom3"); -+ assert_non_null(c->flat_name); -+ -+ c->domain_id = talloc_asprintf(c, "S-1-5-21-1-2-4"); -+ assert_non_null(c->domain_id); -+ -+ c->parent = dom; -+ -+ DLIST_ADD_END(test_ctx->dom_list, c, struct sss_domain_info *); -+ -+ check_leaks_push(test_ctx); -+ *state = test_ctx; -+ return 0; -+} - - static int setup_dom_list(void **state) - { -@@ -1682,6 +1771,77 @@ static void test_sss_output_name(void **state) - assert_true(check_leaks_pop(global_talloc_context) == true); - } - -+static void test_sss_get_domain_mappings_content(void **state) -+{ -+ struct dom_list_test_ctx *test_ctx; -+ int ret; -+ struct sss_domain_info *dom; -+ char *content; -+ struct sss_domain_info *c; -+ -+ ret = sss_get_domain_mappings_content(NULL, NULL, NULL); -+ assert_int_equal(ret, EINVAL); -+ -+ test_ctx = talloc_get_type(*state, struct dom_list_test_ctx); -+ assert_non_null(test_ctx); -+ -+ dom = get_domains_head(test_ctx->dom_list); -+ assert_non_null(dom); -+ -+ /* no forest */ -+ ret = sss_get_domain_mappings_content(test_ctx, dom, &content); -+ assert_int_equal(ret, EOK); -+ assert_string_equal(content, -+ "[domain_realm]\n" -+ ".subdom1.dom = SUBDOM1.DOM\n" -+ "subdom1.dom = SUBDOM1.DOM\n" -+ ".subdom2.dom = SUBDOM2.DOM\n" -+ "subdom2.dom = SUBDOM2.DOM\n" -+ ".subdom3.dom = SUBDOM3.DOM\n" -+ "subdom3.dom = SUBDOM3.DOM\n"); -+ talloc_free(content); -+ -+ /* IPA with forest */ -+ c = find_domain_by_name(dom, "subdom2.dom", true); -+ assert_non_null(c); -+ c->forest_root = find_domain_by_name(dom, "subdom1.dom", true); -+ assert_non_null(c->forest_root); -+ c->forest = "subdom1.dom"; -+ -+ c = find_domain_by_name(dom, "subdom3.dom", true); -+ assert_non_null(c); -+ c->forest_root = find_domain_by_name(dom, "subdom1.dom", true); -+ assert_non_null(c->forest_root); -+ c->forest = "subdom1.dom"; -+ -+ ret = sss_get_domain_mappings_content(test_ctx, dom, &content); -+ assert_int_equal(ret, EOK); -+ assert_string_equal(content, -+ "[domain_realm]\n" -+ ".subdom1.dom = SUBDOM1.DOM\n" -+ "subdom1.dom = SUBDOM1.DOM\n" -+ ".subdom2.dom = SUBDOM2.DOM\n" -+ "subdom2.dom = SUBDOM2.DOM\n" -+ ".subdom3.dom = SUBDOM3.DOM\n" -+ "subdom3.dom = SUBDOM3.DOM\n" -+ "[capaths]\n" -+ "SUBDOM2.DOM = {\n" -+ " CONFIGURED.DOM = SUBDOM1.DOM\n" -+ "}\n" -+ "SUBDOM3.DOM = {\n" -+ " CONFIGURED.DOM = SUBDOM1.DOM\n" -+ "}\n" -+ "CONFIGURED.DOM = {\n" -+ " SUBDOM2.DOM = SUBDOM1.DOM\n" -+ " SUBDOM3.DOM = SUBDOM1.DOM\n" -+ "}\n"); -+ talloc_free(content); -+ -+ /* Next steps, test AD domain setup. If we join a child domain we have a -+ * similar case as with IPA but if we join the forest root the generate -+ * capaths might not be as expected. */ -+} -+ - int main(int argc, const char *argv[]) - { - poptContext pc; -@@ -1773,6 +1933,9 @@ int main(int argc, const char *argv[]) - cmocka_unit_test_setup_teardown(test_sss_output_name, - setup_leak_tests, - teardown_leak_tests), -+ cmocka_unit_test_setup_teardown(test_sss_get_domain_mappings_content, -+ setup_dom_list_with_subdomains, -+ teardown_dom_list), - }; - - /* Set debug level to invalid value so we can deside if -d 0 was used. */ --- -2.4.11 - diff --git a/SOURCES/0036-Amend-debug-messages-after-failure-of-unlink.patch b/SOURCES/0036-Amend-debug-messages-after-failure-of-unlink.patch deleted file mode 100644 index 5a2a303..0000000 --- a/SOURCES/0036-Amend-debug-messages-after-failure-of-unlink.patch +++ /dev/null @@ -1,151 +0,0 @@ -From ce5063550ef45f7abb3ec2ec3cb52a190bb38af5 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Mon, 25 Jul 2016 09:11:08 +0200 -Subject: [PATCH 36/44] Amend debug messages after failure of unlink -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Some messages did not have errno or name of problematic file. -There was also improper use of negative value. -The function strerror was called with -1 instead of errno - -Reviewed-by: Petr Čech ---- - src/providers/ipa/ipa_init.c | 5 +++-- - src/responder/common/responder_common.c | 3 ++- - src/responder/secrets/local.c | 1 + - src/sbus/sssd_dbus_server.c | 9 +++++---- - src/tools/files.c | 3 ++- - src/tools/tools_mc_util.c | 7 ++++--- - src/util/util.c | 6 ++++-- - 7 files changed, 21 insertions(+), 13 deletions(-) - -diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c -index 959cdb4a7c40c1be03dd1e7c66dee6e65ca76607..c31e195f48b2f369de1b78b38a0f3522d73d8dce 100644 ---- a/src/providers/ipa/ipa_init.c -+++ b/src/providers/ipa/ipa_init.c -@@ -440,9 +440,10 @@ static void cleanup_ipa_preauth_indicator(void) - - ret = unlink(PAM_PREAUTH_INDICATOR); - if (ret != EOK) { -+ ret = errno; - DEBUG(SSSDBG_OP_FAILURE, -- "Failed to remove preauth indicator file [%s].\n", -- PAM_PREAUTH_INDICATOR); -+ "Failed to remove preauth indicator file [%s] %d [%s].\n", -+ PAM_PREAUTH_INDICATOR, ret, sss_strerror(ret)); - } - } - -diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c -index 02a64368cad60990436497865aa0c772a39cde5a..7f6264ae70e5073063b5cfcd73098eefad2ce653 100644 ---- a/src/responder/common/responder_common.c -+++ b/src/responder/common/responder_common.c -@@ -629,7 +629,8 @@ int create_pipe_fd(const char *sock_name, int *_fd, mode_t umaskval) - if (ret != 0 && errno != ENOENT) { - ret = errno; - DEBUG(SSSDBG_MINOR_FAILURE, -- "Cannot remove old socket (errno=%d), bind might fail!\n", ret); -+ "Cannot remove old socket (errno=%d [%s]), bind might fail!\n", -+ ret, sss_strerror(ret)); - } - - if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { -diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c -index 2a85ac06945322265fbd1012c9697728c37b77a0..470aec0e195a54dd2af2b929ff1b7a304331a214 100644 ---- a/src/responder/secrets/local.c -+++ b/src/responder/secrets/local.c -@@ -627,6 +627,7 @@ int generate_master_key(const char *filename, size_t size) - ret = unlink(filename); - /* non-fatal failure */ - if (ret != EOK) { -+ ret = errno; - DEBUG(SSSDBG_MINOR_FAILURE, - "Failed to remove file: %s - %d [%s]!\n", - filename, ret, sss_strerror(ret)); -diff --git a/src/sbus/sssd_dbus_server.c b/src/sbus/sssd_dbus_server.c -index 0a1cace415b3514a6904e92a2d879538ce51a593..6cc4172a07118ff99bb6f122c3a1de25cee18c8c 100644 ---- a/src/sbus/sssd_dbus_server.c -+++ b/src/sbus/sssd_dbus_server.c -@@ -103,8 +103,9 @@ create_socket_symlink(const char *filename, const char *symlink_filename) - ret = unlink(symlink_filename); - if (ret != 0) { - ret = errno; -- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot remove old symlink: [%d][%s].\n", -- ret, strerror(ret)); -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot remove old symlink '%s': [%d][%s].\n", -+ symlink_filename, ret, strerror(ret)); - return EIO; - } - errno = 0; -@@ -351,8 +352,8 @@ done: - if (tmp_ret != EOK) { - tmp_ret = errno; - DEBUG(SSSDBG_MINOR_FAILURE, -- "Failed to remove symbolic link: %d [%s]!\n", -- tmp_ret, sss_strerror(tmp_ret)); -+ "Failed to remove symbolic link '%s': %d [%s]!\n", -+ symlink_filename, tmp_ret, sss_strerror(tmp_ret)); - } - } - talloc_free(tmp_ctx); -diff --git a/src/tools/files.c b/src/tools/files.c -index 5364f5c0dd53aad71452e18b8d7f1f04532132a4..8f1aa68beeb2676b56733f49550de170b404c789 100644 ---- a/src/tools/files.c -+++ b/src/tools/files.c -@@ -225,7 +225,8 @@ static int remove_tree_with_ctx(TALLOC_CTX *mem_ctx, - if (ret != 0) { - ret = errno; - DEBUG(SSSDBG_CRIT_FAILURE, -- "Removing file failed: [%d][%s]\n", ret, strerror(ret)); -+ "Removing file failed '%s': [%d][%s]\n", -+ result->d_name, ret, strerror(ret)); - goto fail; - } - } -diff --git a/src/tools/tools_mc_util.c b/src/tools/tools_mc_util.c -index ce899eb3c674afe8271be526dc83aa909cbecf89..2516a1981ddd965d4cae8c469ed79aaef8fa7193 100644 ---- a/src/tools/tools_mc_util.c -+++ b/src/tools/tools_mc_util.c -@@ -117,10 +117,11 @@ done: - if (ret == EOK) { - pret = unlink(mc_filename); - if (pret == -1) { -+ pret = errno; - DEBUG(SSSDBG_MINOR_FAILURE, -- "Failed to unlink file %s. " -- "Will be unlinked later by sssd_nss.\n", -- mc_filename); -+ "Failed to unlink file %s, %d [%s]. " -+ "Will be unlinked later by sssd_nss.\n", -+ mc_filename, pret, strerror(pret)); - } - } - } -diff --git a/src/util/util.c b/src/util/util.c -index 89abfe734873161008dc9a7a42e7a87364f8074a..d4878bfaf4f0e92672756f12137d79ec65ef48f6 100644 ---- a/src/util/util.c -+++ b/src/util/util.c -@@ -990,13 +990,15 @@ static int unlink_dbg(const char *filename) - - ret = unlink(filename); - if (ret != 0) { -- if (errno == 2) { -+ ret = errno; -+ if (ret == ENOENT) { - DEBUG(SSSDBG_TRACE_INTERNAL, - "File already removed: [%s]\n", filename); - return 0; - } else { - DEBUG(SSSDBG_CRIT_FAILURE, -- "Cannot remove temporary file [%s]\n", filename); -+ "Cannot remove temporary file [%s] %d [%s]\n", -+ filename, ret, strerror(ret)); - return -1; - } - } --- -2.4.11 - diff --git a/SOURCES/0036-KCM-Idle-terminate-the-responder-if-the-secrets-back.patch b/SOURCES/0036-KCM-Idle-terminate-the-responder-if-the-secrets-back.patch new file mode 100644 index 0000000..a466a17 --- /dev/null +++ b/SOURCES/0036-KCM-Idle-terminate-the-responder-if-the-secrets-back.patch @@ -0,0 +1,55 @@ +From 7e6a8e7a6c37122fce8781e5f8e82458905960b3 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 21 Mar 2017 14:26:54 +0100 +Subject: [PATCH 36/36] KCM: Idle-terminate the responder if the secrets back + end is used +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Existing with memory database would be fatal as we keep the ccaches in +memory then, but if the ccaches are stored in sssd-secrets, we can just +exit on idle. + +Reviewed-by: Michal Židek +Reviewed-by: Simo Sorce +--- + src/config/cfg_rules.ini | 1 + + src/responder/kcm/kcm.c | 9 +++++++++ + 2 files changed, 10 insertions(+) + +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 67a5d1f5ad447a942b437ffd04a7f5d7cfe77d7f..933ebccd828189d923d2186753dfbc0b5c0814ce 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -281,6 +281,7 @@ option = client_idle_timeout + option = description + option = socket_path + option = ccache_storage ++option = responder_idle_timeout + + [rule/allowed_domain_options] + validator = ini_allowed_options +diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c +index 3ee978066c589a5cc38b0ae358f741d389d00e7a..2202f96381a2622a2c5433e281172287b325f960 100644 +--- a/src/responder/kcm/kcm.c ++++ b/src/responder/kcm/kcm.c +@@ -133,6 +133,15 @@ static int kcm_get_config(struct kcm_ctx *kctx) + goto done; + } + ++ if (kctx->cc_be == CCDB_BE_SECRETS) { ++ ret = responder_setup_idle_timeout_config(kctx->rctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot set up idle responder timeout\n"); ++ /* Not fatal */ ++ } ++ } ++ + kctx->qctx = kcm_ops_queue_create(kctx); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +-- +2.9.3 + diff --git a/SOURCES/0037-CONFIGURE-Fix-fallback-if-pkg-config-for-uuid-is-mis.patch b/SOURCES/0037-CONFIGURE-Fix-fallback-if-pkg-config-for-uuid-is-mis.patch new file mode 100644 index 0000000..bdf9ef7 --- /dev/null +++ b/SOURCES/0037-CONFIGURE-Fix-fallback-if-pkg-config-for-uuid-is-mis.patch @@ -0,0 +1,30 @@ +From bb7c93869d53a412ce2537180752158861755ac4 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 27 Mar 2017 11:59:01 +0200 +Subject: [PATCH 37/54] CONFIGURE: Fix fallback if pkg-config for uuid is + missing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +--- + src/external/libuuid.m4 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/external/libuuid.m4 b/src/external/libuuid.m4 +index 55411a2118bd787c9d50ba61f9cb791e1c76088d..323521c9224e443f40a15b417038d2dcea9b66f3 100644 +--- a/src/external/libuuid.m4 ++++ b/src/external/libuuid.m4 +@@ -4,7 +4,7 @@ AC_SUBST(UUID_CFLAGS) + PKG_CHECK_MODULES([UUID], [uuid], [found_uuid=yes], [found_uuid=no]) + + SSS_AC_EXPAND_LIB_DIR() +-AS_IF([test x"$found_uuid" = xyes], ++AS_IF([test x"$found_uuid" != xyes], + [AC_CHECK_HEADERS([uuid/uuid.h], + [AC_CHECK_LIB([uuid], + [uuid_generate], +-- +2.9.3 + diff --git a/SOURCES/0037-SYSDB-Do-not-try-to-modify-ts-cache-for-unsupported-.patch b/SOURCES/0037-SYSDB-Do-not-try-to-modify-ts-cache-for-unsupported-.patch deleted file mode 100644 index ca36fa7..0000000 --- a/SOURCES/0037-SYSDB-Do-not-try-to-modify-ts-cache-for-unsupported-.patch +++ /dev/null @@ -1,40 +0,0 @@ -From af7accb9071ca5f73632e2b47c13f2ce7d26995e Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Mon, 25 Jul 2016 08:31:17 +0200 -Subject: [PATCH 37/44] SYSDB: Do not try to modify ts cache for unsupported - DNs -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Only users and groups have timestamp data in separate cache. -It caused false positive warnings for autofs, netgroup ... - -Reviewed-by: Petr Čech ---- - src/db/sysdb_ops.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 4755ea3427b99a51d73b7b9134e357cf2b987613..19d6be03ede1bcec3bc7a4ed777e326460d80591 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -1198,9 +1198,14 @@ int sysdb_set_entry_attr(struct sysdb_ctx *sysdb, - sysdb_write = sysdb_entry_attrs_diff(sysdb, entry_dn, attrs, mod_op); - if (sysdb_write == true) { - ret = sysdb_set_cache_entry_attr(sysdb->ldb, entry_dn, attrs, mod_op); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Cannot set attrs for %s, %d [%s]\n", -+ ldb_dn_get_linearized(entry_dn), ret, sss_strerror(ret)); -+ } - } - -- if (ret == EOK) { -+ if (ret == EOK && is_ts_ldb_dn(entry_dn)) { - tret = sysdb_set_ts_entry_attr(sysdb, entry_dn, attrs, mod_op); - if (tret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, --- -2.4.11 - diff --git a/SOURCES/0038-AD-avoid-memory-leak-in-netlogon_get_domain_info-and.patch b/SOURCES/0038-AD-avoid-memory-leak-in-netlogon_get_domain_info-and.patch deleted file mode 100644 index d92dc85..0000000 --- a/SOURCES/0038-AD-avoid-memory-leak-in-netlogon_get_domain_info-and.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 83f4fbf2cb3f9318aedfa03e526671e3c444c40b Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 12 Jul 2016 13:16:43 +0200 -Subject: [PATCH 38/44] AD: avoid memory leak in netlogon_get_domain_info() and - make it public - -Reviewed-by: Jakub Hrozek ---- - src/providers/ad/ad_common.h | 6 ++++++ - src/providers/ad/ad_domain_info.c | 29 ++++++++++++++++++++--------- - 2 files changed, 26 insertions(+), 9 deletions(-) - -diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h -index ce363c5a4122aa5e48ca83b0b2bdf63ff4372d91..f4a90e4f0a3fe5910071d5fe690d0a356e2a0bd1 100644 ---- a/src/providers/ad/ad_common.h -+++ b/src/providers/ad/ad_common.h -@@ -185,4 +185,10 @@ errno_t ad_autofs_init(TALLOC_CTX *mem_ctx, - errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx, - struct ad_options *ad_opts); - -+errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx, -+ struct sysdb_attrs *reply, -+ char **_flat_name, -+ char **_site, -+ char **_forest); -+ - #endif /* AD_COMMON_H_ */ -diff --git a/src/providers/ad/ad_domain_info.c b/src/providers/ad/ad_domain_info.c -index 5f17ae5427b1206af3ad03dccce9452aefc2e6e2..a06379c263878aa95741055636d0a12764f3ad8c 100644 ---- a/src/providers/ad/ad_domain_info.c -+++ b/src/providers/ad/ad_domain_info.c -@@ -35,12 +35,11 @@ - #include "providers/ad/ad_common.h" - #include "util/util.h" - --static errno_t --netlogon_get_domain_info(TALLOC_CTX *mem_ctx, -- struct sysdb_attrs *reply, -- char **_flat_name, -- char **_site, -- char **_forest) -+errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx, -+ struct sysdb_attrs *reply, -+ char **_flat_name, -+ char **_site, -+ char **_forest) - { - errno_t ret; - struct ldb_message_element *el; -@@ -51,6 +50,7 @@ netlogon_get_domain_info(TALLOC_CTX *mem_ctx, - const char *flat_name; - const char *site; - const char *forest; -+ TALLOC_CTX *tmp_ctx; - - ret = sysdb_attrs_get_el(reply, AD_AT_NETLOGON, &el); - if (ret != EOK) { -@@ -66,13 +66,24 @@ netlogon_get_domain_info(TALLOC_CTX *mem_ctx, - return EIO; - } - -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); -+ return ENOMEM; -+ } -+ - blob.data = el->values[0].data; - blob.length = el->values[0].length; - -- ndr_pull = ndr_pull_init_blob(&blob, mem_ctx); -+ /* The ndr_pull_* calls do not use ndr_pull as a talloc context to -+ * allocate memory but the second argument of ndr_pull_init_blob(). To -+ * make sure no memory is leaked here a temporary talloc context is -+ * needed. */ -+ ndr_pull = ndr_pull_init_blob(&blob, tmp_ctx); - if (ndr_pull == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_init_blob() failed.\n"); -- return ENOMEM; -+ ret = ENOMEM; -+ goto done; - } - - ndr_err = ndr_pull_netlogon_samlogon_response(ndr_pull, NDR_SCALARS, -@@ -146,7 +157,7 @@ netlogon_get_domain_info(TALLOC_CTX *mem_ctx, - - ret = EOK; - done: -- talloc_free(ndr_pull); -+ talloc_free(tmp_ctx); - return ret; - } - --- -2.4.11 - diff --git a/SOURCES/0038-intg-fix-configure-failure-with-strict-cflags.patch b/SOURCES/0038-intg-fix-configure-failure-with-strict-cflags.patch new file mode 100644 index 0000000..5c7c3be --- /dev/null +++ b/SOURCES/0038-intg-fix-configure-failure-with-strict-cflags.patch @@ -0,0 +1,52 @@ +From 076bd32668f7ea194389ddd526ea81f9bf12fb0e Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 28 Mar 2017 12:18:13 +0200 +Subject: [PATCH 38/54] intg: fix configure failure with strict cflags +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The warning -Wstrict-prototypes is a part of AM_CFLAGS which was appended +for CFLAGS in make target intgcheck-prepare. And combination with +strict CFLAGS in environment variable (e.g. -Werror) caused failures. + +sh$ CFLAGS="-Werror" make intgcheck-prepare + +checking for gcc... gcc +checking whether the C compiler works... no +configure: error: in `/home/build/sssd/ci-build-debug/intg/bld': +configure: error: C compiler cannot create executables + +configure:3719: checking whether the C compiler works +configure:3741: gcc -g3 -O2 -Werror -D_FILE_OFFSET_BITS=64 + -D_LARGEFILE_SOURCE -Wall -Wshadow -Wstrict-prototypes + -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings + -Wundef -Werror-implicit-function-declaration + -Winit-self -Wmissing-include-dirs -fno-strict-aliasing + -std=gnu99 -DKCM_PEER_UID=1000 conftest.c >&5 +conftest.c:11:1: error: function declaration isn't a prototype [-Werror=strict-prototypes] + main () + ^~~~ +cc1: all warnings being treated as errors + +Reviewed-by: Pavel Březina +--- + Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index 91afdd669aa11a3cc316588d3b51d7e8e9c91cb8..359feddef298b0013c726409b7ba8b86504abf09 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3486,7 +3486,7 @@ intgcheck-prepare: + --without-semanage \ + --enable-files-domain \ + $(INTGCHECK_CONFIGURE_FLAGS) \ +- CFLAGS="$$CFLAGS $(AM_CFLAGS) -DKCM_PEER_UID=$$(id -u)"; \ ++ CFLAGS="$$CFLAGS -DKCM_PEER_UID=$$(id -u)"; \ + $(MAKE) $(AM_MAKEFLAGS) ; \ + : Force single-thread install to workaround concurrency issues; \ + $(MAKE) $(AM_MAKEFLAGS) -j1 install; \ +-- +2.9.3 + diff --git a/SOURCES/0039-AD-netlogon_get_domain_info-allow-missing-arguments-.patch b/SOURCES/0039-AD-netlogon_get_domain_info-allow-missing-arguments-.patch deleted file mode 100644 index f81ee20..0000000 --- a/SOURCES/0039-AD-netlogon_get_domain_info-allow-missing-arguments-.patch +++ /dev/null @@ -1,217 +0,0 @@ -From df00f0d33874381fc36ee59eaf28a4918ae5dc56 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 12 Jul 2016 13:29:33 +0200 -Subject: [PATCH 39/44] AD: netlogon_get_domain_info() allow missing arguments - and empty results - -netlogon_get_domain_info() should not fail if not all parameters can be -retrieved. It should be the responsibility of the caller to see if the -needed data is available and act accordingly. - -Resolves: -https://fedorahosted.org/sssd/ticket/3104 - -Reviewed-by: Jakub Hrozek ---- - src/providers/ad/ad_common.h | 1 + - src/providers/ad/ad_domain_info.c | 108 +++++++++++++++++++++----------------- - src/providers/ad/ad_gpo.c | 2 +- - src/providers/ad/ad_subdomains.c | 3 +- - 4 files changed, 64 insertions(+), 50 deletions(-) - -diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h -index f4a90e4f0a3fe5910071d5fe690d0a356e2a0bd1..7e86faf1142d7be49eef01e1ddd7bfafea2fcedc 100644 ---- a/src/providers/ad/ad_common.h -+++ b/src/providers/ad/ad_common.h -@@ -187,6 +187,7 @@ errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx, - - errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx, - struct sysdb_attrs *reply, -+ bool check_next_nearest_site_as_well, - char **_flat_name, - char **_site, - char **_forest); -diff --git a/src/providers/ad/ad_domain_info.c b/src/providers/ad/ad_domain_info.c -index a06379c263878aa95741055636d0a12764f3ad8c..5302c8083bd832d0772829d9f3a4b8e9537d34b9 100644 ---- a/src/providers/ad/ad_domain_info.c -+++ b/src/providers/ad/ad_domain_info.c -@@ -37,6 +37,7 @@ - - errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx, - struct sysdb_attrs *reply, -+ bool check_next_nearest_site_as_well, - char **_flat_name, - char **_site, - char **_forest) -@@ -47,9 +48,6 @@ errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx, - struct ndr_pull *ndr_pull = NULL; - enum ndr_err_code ndr_err; - struct netlogon_samlogon_response response; -- const char *flat_name; -- const char *site; -- const char *forest; - TALLOC_CTX *tmp_ctx; - - ret = sysdb_attrs_get_el(reply, AD_AT_NETLOGON, &el); -@@ -102,57 +100,73 @@ errno_t netlogon_get_domain_info(TALLOC_CTX *mem_ctx, - goto done; - } - -- /* get flat name */ -- if (response.data.nt5_ex.domain_name != NULL && -- *response.data.nt5_ex.domain_name != '\0') { -- flat_name = response.data.nt5_ex.domain_name; -- } else { -- DEBUG(SSSDBG_MINOR_FAILURE, -- "No netlogon domain name data available\n"); -- ret = ENOENT; -- goto done; -+ /* get flat domain name */ -+ if (_flat_name != NULL) { -+ if (response.data.nt5_ex.domain_name != NULL && -+ *response.data.nt5_ex.domain_name != '\0') { -+ *_flat_name = talloc_strdup(mem_ctx, -+ response.data.nt5_ex.domain_name); -+ if (*_flat_name == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } else { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "No netlogon flat domain name data available.\n"); -+ *_flat_name = NULL; -+ } - } - -- *_flat_name = talloc_strdup(mem_ctx, flat_name); -- if (*_flat_name == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -- ret = ENOMEM; -- goto done; -- } - - /* get forest */ -- if (response.data.nt5_ex.forest != NULL && -- *response.data.nt5_ex.forest != '\0') { -- forest = response.data.nt5_ex.forest; -- } else { -- DEBUG(SSSDBG_MINOR_FAILURE, "No netlogon forest data available\n"); -- ret = ENOENT; -- goto done; -- } -- -- *_forest = talloc_strdup(mem_ctx, forest); -- if (*_forest == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -- ret = ENOMEM; -- goto done; -+ if (_forest != NULL) { -+ if (response.data.nt5_ex.forest != NULL && -+ *response.data.nt5_ex.forest != '\0') { -+ *_forest = talloc_strdup(mem_ctx, response.data.nt5_ex.forest); -+ if (*_forest == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } else { -+ DEBUG(SSSDBG_MINOR_FAILURE, "No netlogon forest data available.\n"); -+ *_forest = NULL; -+ } - } - - /* get site name */ -- if (response.data.nt5_ex.client_site != NULL -- && response.data.nt5_ex.client_site[0] != '\0') { -- site = response.data.nt5_ex.client_site; -- } else { -- DEBUG(SSSDBG_MINOR_FAILURE, -- "No netlogon site name data available\n"); -- ret = ENOENT; -- goto done; -- } -+ if (_site != NULL) { -+ if (response.data.nt5_ex.client_site != NULL -+ && response.data.nt5_ex.client_site[0] != '\0') { -+ *_site = talloc_strdup(mem_ctx, response.data.nt5_ex.client_site); -+ if (*_site == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } else { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "No netlogon site name data available.\n"); -+ *_site = NULL; - -- *_site = talloc_strdup(mem_ctx, site); -- if (*_site == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -- ret = ENOMEM; -- goto done; -+ if (check_next_nearest_site_as_well) { -+ if (response.data.nt5_ex.next_closest_site != NULL -+ && response.data.nt5_ex.next_closest_site[0] != '\0') { -+ *_site = talloc_strdup(mem_ctx, -+ response.data.nt5_ex.next_closest_site); -+ if (*_site == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } else { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "No netlogon next closest site name data " -+ "available.\n"); -+ } -+ } -+ } - } - - ret = EOK; -@@ -388,7 +402,7 @@ ad_master_domain_netlogon_done(struct tevent_req *subreq) - - /* Exactly one flat name. Carry on */ - -- ret = netlogon_get_domain_info(state, reply[0], &state->flat, -+ ret = netlogon_get_domain_info(state, reply[0], false, &state->flat, - &state->site, &state->forest); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, -diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c -index 3e54fd8b5932a97779e178c7d3c5b9f6d3b3277c..f609d28136918adfe6a8d5e95319b27ffcab79c0 100644 ---- a/src/providers/ad/ad_gpo.c -+++ b/src/providers/ad/ad_gpo.c -@@ -2801,7 +2801,7 @@ ad_gpo_site_name_retrieval_done(struct tevent_req *subreq) - ret = ad_master_domain_recv(subreq, state, NULL, NULL, &site, NULL); - talloc_zfree(subreq); - -- if (ret != EOK) { -+ if (ret != EOK || site == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve master domain info\n"); - tevent_req_error(req, ENOENT); - return; -diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c -index 928c4fe93cc6afa5c3f69c14503896db820a4c0a..e9da04e384e598927f9c8c203a751bcccd29e895 100644 ---- a/src/providers/ad/ad_subdomains.c -+++ b/src/providers/ad/ad_subdomains.c -@@ -1108,14 +1108,13 @@ static void ad_subdomains_refresh_master_done(struct tevent_req *subreq) - char *master_sid; - char *flat_name; - char *forest; -- char *site; - errno_t ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct ad_subdomains_refresh_state); - - ret = ad_master_domain_recv(subreq, state, &flat_name, &master_sid, -- &site, &forest); -+ NULL, &forest); - talloc_zfree(subreq); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get master domain information " --- -2.4.11 - diff --git a/SOURCES/0039-intg-Remove-bashism-from-intgcheck-prepare.patch b/SOURCES/0039-intg-Remove-bashism-from-intgcheck-prepare.patch new file mode 100644 index 0000000..d10c770 --- /dev/null +++ b/SOURCES/0039-intg-Remove-bashism-from-intgcheck-prepare.patch @@ -0,0 +1,54 @@ +From c49fc8fded9ed87e37189bf877f04ef462974420 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 27 Mar 2017 14:44:29 +0200 +Subject: [PATCH 39/54] intg: Remove bashism from intgcheck-prepare + +env variable UID is not defined in all shells (eg. dash) +We also need to move invocation of "id -u" before nss_wraper +is enabled otherwise we would get root instead of real user. + +=================================== FAILURES =================================== +________________________ test_kcm_mem_init_list_destroy ________________________ +Traceback (most recent call last): + File "/home/build/sssd/src/tests/intg/test_kcm.py", line 198, in test_kcm_mem_init_list_destroy + kcm_init_list_destroy(testenv) + File "/home/build/sssd/src/tests/intg/test_kcm.py", line 183, in kcm_init_list_destroy + exp_ccname = testenv.ccname() + File "/home/build/sssd/src/tests/intg/test_kcm.py", line 45, in ccname + my_uid = self.my_uid() + File "/home/build/sssd/src/tests/intg/test_kcm.py", line 41, in my_uid + return int(s_myuid) +ValueError: invalid literal for int() with base 10: '' + +And we already use different approach in top level Makefile.am +3488) $(INTGCHECK_CONFIGURE_FLAGS) \ +3489) CFLAGS="$$CFLAGS $(AM_CFLAGS) -DKCM_PEER_UID=$$(id -u)"; \ +3490) $(MAKE) $(AM_MAKEFLAGS) ; \ + +Reviewed-by: Jakub Hrozek +--- + src/tests/intg/Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am +index 8526beace09b15c99aa27ac98d5038d1980f6a71..8566106e9017a8d3c9e7a3898a3a886e2966e346 100644 +--- a/src/tests/intg/Makefile.am ++++ b/src/tests/intg/Makefile.am +@@ -76,6 +76,7 @@ intgcheck-installed: config.py passwd group + PATH="$(abs_builddir):$(abs_srcdir):$$PATH" \ + PYTHONPATH="$(abs_builddir):$(abs_srcdir)" \ + LDB_MODULES_PATH="$(DESTDIR)$(ldblibdir)" \ ++ NON_WRAPPED_UID=$$(id -u) \ + LD_PRELOAD="$$nss_wrapper $$uid_wrapper" \ + NSS_WRAPPER_PASSWD="$(abs_builddir)/passwd" \ + NSS_WRAPPER_GROUP="$(abs_builddir)/group" \ +@@ -83,6 +84,5 @@ intgcheck-installed: config.py passwd group + NSS_WRAPPER_MODULE_FN_PREFIX="sss" \ + UID_WRAPPER=1 \ + UID_WRAPPER_ROOT=1 \ +- NON_WRAPPED_UID=$$(echo $$UID) \ + fakeroot $(PYTHON2) $(PYTEST) -v --tb=native $(INTGCHECK_PYTEST_ARGS) . + rm -f $(DESTDIR)$(logpath)/* +-- +2.9.3 + diff --git a/SOURCES/0040-UTIL-Introduce-subdomain_create_conf_path.patch b/SOURCES/0040-UTIL-Introduce-subdomain_create_conf_path.patch new file mode 100644 index 0000000..0dc6e0c --- /dev/null +++ b/SOURCES/0040-UTIL-Introduce-subdomain_create_conf_path.patch @@ -0,0 +1,127 @@ +From ddfa743159541de498816764c06bf4b13fb923f7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Tue, 28 Mar 2017 18:33:46 +0200 +Subject: [PATCH 40/54] UTIL: Introduce subdomain_create_conf_path() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is a utility function that replaces the create_subdom_conf_path(). +Differently than the latter, it only takes one parameter and is going to +be used in a few different places (thus adding it to util.h). + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukas Slebodnik +--- + src/providers/ad/ad_common.c | 7 ------- + src/providers/ad/ad_common.h | 4 ---- + src/providers/ad/ad_subdomains.c | 4 +--- + src/providers/ipa/ipa_subdomains_server.c | 4 +--- + src/util/domain_info_utils.c | 15 +++++++++++++++ + src/util/util.h | 3 +++ + 6 files changed, 20 insertions(+), 17 deletions(-) + +diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c +index ec952d3bb4587516ea26fd27c212d5620e2f3dda..f893b748a2ddcff1eab6e8d919d2aa950b825446 100644 +--- a/src/providers/ad/ad_common.c ++++ b/src/providers/ad/ad_common.c +@@ -33,13 +33,6 @@ errno_t ad_set_search_bases(struct sdap_options *id_opts); + static errno_t ad_set_sdap_options(struct ad_options *ad_opts, + struct sdap_options *id_opts); + +-char *create_subdom_conf_path(TALLOC_CTX *mem_ctx, +- const char *conf_path, +- const char *subdom_name) +-{ +- return talloc_asprintf(mem_ctx, "%s/%s", conf_path, subdom_name); +-} +- + static struct sdap_options * + ad_create_default_sdap_options(TALLOC_CTX *mem_ctx) + { +diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h +index e02b932cd2da737254de8417d5c82fcdcf14e8d7..2981550f6c390929501ec8942e861b16ea0a5cb0 100644 +--- a/src/providers/ad/ad_common.h ++++ b/src/providers/ad/ad_common.h +@@ -99,10 +99,6 @@ struct ad_options { + struct be_nsupdate_ctx *dyndns_ctx; + }; + +-char *create_subdom_conf_path(TALLOC_CTX *mem_ctx, +- const char *conf_path, +- const char *subdom_name); +- + errno_t + ad_get_common_options(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 156ecab4272029d69c8b596eff041498a7524ce4..eecae9c9ca82ad67874c13a3c7b7c617d6232d5c 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -171,9 +171,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, + return EINVAL; + } + +- subdom_conf_path = create_subdom_conf_path(id_ctx, +- be_ctx->conf_path, +- subdom->name); ++ subdom_conf_path = subdomain_create_conf_path(id_ctx, subdom); + if (subdom_conf_path == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "subdom_conf_path failed\n"); + return ENOMEM; +diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c +index ae3baf036e4278fb67d86b42742fb7e80b46724e..e8ee30392d84f84e30bcdaa3d2110ba130b1ad73 100644 +--- a/src/providers/ipa/ipa_subdomains_server.c ++++ b/src/providers/ipa/ipa_subdomains_server.c +@@ -176,9 +176,7 @@ static struct ad_options *ipa_ad_options_new(struct be_ctx *be_ctx, + forest_realm = subdom->forest_root->realm; + forest = subdom->forest_root->forest; + +- subdom_conf_path = create_subdom_conf_path(id_ctx, +- be_ctx->conf_path, +- subdom->name); ++ subdom_conf_path = subdomain_create_conf_path(id_ctx, subdom); + if (subdom_conf_path == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "subdom_conf_path failed\n"); + return NULL; +diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c +index 6ef6bcfb8c078a360673b6bdd2364fc2918cb324..a7f118842aa8ba870143b2f2b425a3e3c0ea5a78 100644 +--- a/src/util/domain_info_utils.c ++++ b/src/util/domain_info_utils.c +@@ -870,3 +870,18 @@ bool is_email_from_domain(const char *email, struct sss_domain_info *dom) + + return false; + } ++ ++char *subdomain_create_conf_path(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *subdomain) ++{ ++ if (!IS_SUBDOMAIN(subdomain)) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "The domain \"%s\" is not a subdomain.\n", ++ subdomain->name); ++ return NULL; ++ } ++ ++ return talloc_asprintf(mem_ctx, CONFDB_DOMAIN_PATH_TMPL "/%s", ++ subdomain->parent->name, ++ subdomain->name); ++} +diff --git a/src/util/util.h b/src/util/util.h +index a2dc89b8ddb999437eda551ac17af28672d8759c..82760940269ad8883e725e3a5cf463486c9cfd36 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -551,6 +551,9 @@ find_domain_by_object_name(struct sss_domain_info *domain, + bool subdomain_enumerates(struct sss_domain_info *parent, + const char *sd_name); + ++char *subdomain_create_conf_path(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *subdomain); ++ + errno_t sssd_domain_init(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *domain_name, +-- +2.9.3 + diff --git a/SOURCES/0040-tests-add-tests-for-netlogon_get_domain_info.patch b/SOURCES/0040-tests-add-tests-for-netlogon_get_domain_info.patch deleted file mode 100644 index b429a27..0000000 --- a/SOURCES/0040-tests-add-tests-for-netlogon_get_domain_info.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 4319dabb39ea91d1c1cd9fe5294e17706045bd48 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 11 Jul 2016 17:05:29 +0200 -Subject: [PATCH 40/44] tests: add tests for netlogon_get_domain_info - -Reviewed-by: Jakub Hrozek ---- - Makefile.am | 1 + - src/tests/cmocka/test_ad_common.c | 81 +++++++++++++++++++++++++++++++++++++++ - 2 files changed, 82 insertions(+) - -diff --git a/Makefile.am b/Makefile.am -index d05919705910fa565ff954224ce40feb5d7ff39f..cefd9a43442fc19933f1e373d4f2ed4bb3ba3201 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -2470,6 +2470,7 @@ ad_common_tests_SOURCES = \ - src/providers/ad/ad_opts.c \ - src/providers/ad/ad_pac.c \ - src/providers/ad/ad_pac_common.c \ -+ src/providers/ad/ad_domain_info.c \ - src/providers/ldap/sdap_async_initgroups_ad.c \ - $(NULL) - ad_common_tests_CFLAGS = \ -diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c -index b7a5838de04e1a788bb9a61e84df00fc9bcc784b..7987330e2d0f5df93b62e4a68f34bc4ae23bd79b 100644 ---- a/src/tests/cmocka/test_ad_common.c -+++ b/src/tests/cmocka/test_ad_common.c -@@ -802,6 +802,84 @@ void test_user_conn_list(void **state) - talloc_free(conn_list); - } - -+void test_netlogon_get_domain_info(void **state) -+{ -+ int ret; -+ struct sysdb_attrs *attrs; -+ struct ldb_val val = { 0 }; -+ char *flat_name; -+ char *site; -+ char *forest; -+ -+ struct ad_common_test_ctx *test_ctx = talloc_get_type(*state, -+ struct ad_common_test_ctx); -+ assert_non_null(test_ctx); -+ -+ attrs = sysdb_new_attrs(test_ctx); -+ assert_non_null(attrs); -+ -+ ret = netlogon_get_domain_info(test_ctx, attrs, false, NULL, NULL, NULL); -+ assert_int_equal(ret, ENOENT); -+ -+ ret = sysdb_attrs_add_val(attrs, AD_AT_NETLOGON, &val); -+ assert_int_equal(ret, EOK); -+ -+ ret = netlogon_get_domain_info(test_ctx, attrs, false, NULL, NULL, NULL); -+ assert_int_equal(ret, EBADMSG); -+ -+ talloc_free(attrs); -+ attrs = sysdb_new_attrs(test_ctx); -+ assert_non_null(attrs); -+ -+ val.data = sss_base64_decode(test_ctx, "FwAAAP0zAABsGcIYI7j2TL97Rd+TvpATAmFkBWRldmVsAMAYCWFkLXNlcnZlcsAYAkFEAAlBRC1TRVJWRVIAABdEZWZhdWx0LUZpcnN0LVNpdGUtTmFtZQDAQAUAAAD/////", &val.length); -+ assert_non_null(val.data); -+ -+ ret = sysdb_attrs_add_val(attrs, AD_AT_NETLOGON, &val); -+ assert_int_equal(ret, EOK); -+ -+ ret = netlogon_get_domain_info(test_ctx, attrs, false, &flat_name, &site, &forest); -+ assert_int_equal(ret, EOK); -+ assert_string_equal(flat_name, "AD"); -+ assert_string_equal(site, "Default-First-Site-Name"); -+ assert_string_equal(forest, "ad.devel"); -+ -+ /* missing site */ -+ talloc_free(flat_name); -+ talloc_free(site); -+ talloc_free(forest); -+ talloc_free(val.data); -+ talloc_free(attrs); -+ attrs = sysdb_new_attrs(test_ctx); -+ assert_non_null(attrs); -+ -+ val.data = sss_base64_decode(test_ctx, "FwAAAH0zAABsGcIYI7j2TL97Rd+TvpATAmFkBWRldmVsAMAYCWFkLXNlcnZlcsAYAkFEAAlBRC1TRVJWRVIAABdEZWZhdWx0LUZpcnN0LVNpdGUtTmFtZQAABQAAAP////8=", &val.length); -+ assert_non_null(val.data); -+ -+ ret = sysdb_attrs_add_val(attrs, AD_AT_NETLOGON, &val); -+ assert_int_equal(ret, EOK); -+ -+ ret = netlogon_get_domain_info(test_ctx, attrs, false, &flat_name, &site, &forest); -+ assert_int_equal(ret, EOK); -+ assert_string_equal(flat_name, "AD"); -+ assert_null(site); -+ assert_string_equal(forest, "ad.devel"); -+ -+ talloc_free(flat_name); -+ talloc_free(site); -+ talloc_free(forest); -+ ret = netlogon_get_domain_info(test_ctx, attrs, true, &flat_name, &site, &forest); -+ assert_int_equal(ret, EOK); -+ assert_string_equal(flat_name, "AD"); -+ assert_null(site); -+ assert_string_equal(forest, "ad.devel"); -+ -+ talloc_free(flat_name); -+ talloc_free(site); -+ talloc_free(forest); -+ talloc_free(val.data); -+ talloc_free(attrs); -+} -+ - int main(int argc, const char *argv[]) - { - poptContext pc; -@@ -845,6 +923,9 @@ int main(int argc, const char *argv[]) - cmocka_unit_test_setup_teardown(test_ad_get_pac_data_from_user_entry, - test_ad_common_setup, - test_ad_common_teardown), -+ cmocka_unit_test_setup_teardown(test_netlogon_get_domain_info, -+ test_ad_common_setup, -+ test_ad_common_teardown), - }; - - /* Set debug level to invalid value so we can deside if -d 0 was used. */ --- -2.4.11 - diff --git a/SOURCES/0041-AD-replace-ad_get_client_site_parse_ndr-with-netlogo.patch b/SOURCES/0041-AD-replace-ad_get_client_site_parse_ndr-with-netlogo.patch deleted file mode 100644 index 28bfa38..0000000 --- a/SOURCES/0041-AD-replace-ad_get_client_site_parse_ndr-with-netlogo.patch +++ /dev/null @@ -1,217 +0,0 @@ -From b0873f4a99f44eabae11e1cc62f6ec49c07466f0 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 18 Jul 2016 11:25:47 +0200 -Subject: [PATCH 41/44] AD: replace ad_get_client_site_parse_ndr() with - netlogon_get_domain_info() - -netlogon_get_domain_info() does not fail if only the site is missing in -the CLDAP ping respond. If the site is not available a Global Catalog -can still be looked up with the forest name. Only if the forest name is -missing as well we fall back to the configured domain name. - -Resolves: -https://fedorahosted.org/sssd/ticket/3104 - -Reviewed-by: Jakub Hrozek ---- - src/providers/ad/ad_srv.c | 153 ++++++++++------------------------------------ - 1 file changed, 33 insertions(+), 120 deletions(-) - -diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c -index 9602945e66aa0529938bdd63067f00971dbcbe89..ff01ee95c4d2c6875a989394489f1a0495cc3003 100644 ---- a/src/providers/ad/ad_srv.c -+++ b/src/providers/ad/ad_srv.c -@@ -405,93 +405,10 @@ done: - return; - } - --static errno_t ad_get_client_site_parse_ndr(TALLOC_CTX *mem_ctx, -- uint8_t *data, -- size_t length, -- char **_site_name, -- char **_forest_name) --{ -- TALLOC_CTX *tmp_ctx = NULL; -- struct ndr_pull *ndr_pull = NULL; -- struct netlogon_samlogon_response response; -- enum ndr_err_code ndr_err; -- char *site = NULL; -- char *forest = NULL; -- DATA_BLOB blob; -- errno_t ret; -- -- tmp_ctx = talloc_new(NULL); -- if (tmp_ctx == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); -- return ENOMEM; -- } -- -- blob.data = data; -- blob.length = length; -- -- ndr_pull = ndr_pull_init_blob(&blob, mem_ctx); -- if (ndr_pull == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_init_blob() failed.\n"); -- ret = ENOMEM; -- goto done; -- } -- -- ndr_err = ndr_pull_netlogon_samlogon_response(ndr_pull, NDR_SCALARS, -- &response); -- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { -- DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_netlogon_samlogon_response() " -- "failed [%d]\n", ndr_err); -- ret = EBADMSG; -- goto done; -- } -- -- if (!(response.ntver & NETLOGON_NT_VERSION_5EX)) { -- DEBUG(SSSDBG_OP_FAILURE, "This NT version does not provide site " -- "information [%x]\n", response.ntver); -- ret = EBADMSG; -- goto done; -- } -- -- if (response.data.nt5_ex.client_site != NULL -- && response.data.nt5_ex.client_site[0] != '\0') { -- site = talloc_strdup(tmp_ctx, response.data.nt5_ex.client_site); -- } else if (response.data.nt5_ex.next_closest_site != NULL -- && response.data.nt5_ex.next_closest_site[0] != '\0') { -- site = talloc_strdup(tmp_ctx, response.data.nt5_ex.next_closest_site); -- } else { -- ret = ENOENT; -- goto done; -- } -- -- if (response.data.nt5_ex.forest != NULL -- && response.data.nt5_ex.forest[0] != '\0') { -- forest = talloc_strdup(tmp_ctx, response.data.nt5_ex.forest); -- } else { -- ret = ENOENT; -- goto done; -- } -- -- -- if (site == NULL || forest == NULL) { -- ret = ENOMEM; -- goto done; -- } -- -- *_site_name = talloc_steal(mem_ctx, site); -- *_forest_name = talloc_steal(mem_ctx, forest); -- -- ret = EOK; -- --done: -- talloc_free(tmp_ctx); -- return ret; --} -- - static void ad_get_client_site_done(struct tevent_req *subreq) - { - struct ad_get_client_site_state *state = NULL; - struct tevent_req *req = NULL; -- struct ldb_message_element *el = NULL; - struct sysdb_attrs **reply = NULL; - size_t reply_count; - errno_t ret; -@@ -520,25 +437,8 @@ static void ad_get_client_site_done(struct tevent_req *subreq) - goto done; - } - -- ret = sysdb_attrs_get_el(reply[0], AD_AT_NETLOGON, &el); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n"); -- goto done; -- } -- -- if (el->num_values == 0) { -- DEBUG(SSSDBG_OP_FAILURE, "netlogon has no value\n"); -- ret = ENOENT; -- goto done; -- } else if (el->num_values > 1) { -- DEBUG(SSSDBG_OP_FAILURE, "More than one netlogon value?\n"); -- ret = EIO; -- goto done; -- } -- -- ret = ad_get_client_site_parse_ndr(state, el->values[0].data, -- el->values[0].length, &state->site, -- &state->forest); -+ ret = netlogon_get_domain_info(state, reply[0], true, NULL, &state->site, -+ &state->forest); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve site name [%d]: %s\n", - ret, strerror(ret)); -@@ -547,6 +447,7 @@ static void ad_get_client_site_done(struct tevent_req *subreq) - } - - DEBUG(SSSDBG_TRACE_FUNC, "Found site: %s\n", state->site); -+ DEBUG(SSSDBG_TRACE_FUNC, "Found forest: %s\n", state->forest); - - done: - if (ret != EOK) { -@@ -803,30 +704,42 @@ static void ad_srv_plugin_site_done(struct tevent_req *subreq) - - ret = EOK; - } -+ -+ primary_domain = state->discovery_domain; -+ backup_domain = NULL; -+ - if (ret == EOK) { - if (strcmp(state->service, "gc") == 0) { -- primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT, -- state->site, state->forest); -- if (primary_domain == NULL) { -- ret = ENOMEM; -- goto done; -- } -+ if (state->forest != NULL) { -+ if (state->site != NULL) { -+ primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT, -+ state->site, -+ state->forest); -+ if (primary_domain == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } - -- backup_domain = state->forest; -+ backup_domain = state->forest; -+ } else { -+ primary_domain = state->forest; -+ backup_domain = NULL; -+ } -+ } - } else { -- primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT, -- state->site, state->discovery_domain); -- if (primary_domain == NULL) { -- ret = ENOMEM; -- goto done; -- } -+ if (state->site != NULL) { -+ primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT, -+ state->site, -+ state->discovery_domain); -+ if (primary_domain == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } - -- backup_domain = state->discovery_domain; -+ backup_domain = state->discovery_domain; -+ } - } -- } else if (ret == ENOENT) { -- primary_domain = state->discovery_domain; -- backup_domain = NULL; -- } else { -+ } else if (ret != ENOENT && ret != EOK) { - goto done; - } - --- -2.4.11 - diff --git a/SOURCES/0041-SUBDOMAINS-Allow-use_fully_qualified_names-for-subdo.patch b/SOURCES/0041-SUBDOMAINS-Allow-use_fully_qualified_names-for-subdo.patch new file mode 100644 index 0000000..f9a0fe3 --- /dev/null +++ b/SOURCES/0041-SUBDOMAINS-Allow-use_fully_qualified_names-for-subdo.patch @@ -0,0 +1,531 @@ +From 887b53d8833ab91835cb3afbdadcbf9d091dafcd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Thu, 23 Mar 2017 13:14:56 +0100 +Subject: [PATCH 41/54] SUBDOMAINS: Allow use_fully_qualified_names for + subdomains +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Allow option use_fully_qualified_names in subdomain section. +This option was recently added to subdomain_inherit. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3337 + +Reviewed-by: Fabiano Fidêncio +--- + src/db/sysdb.h | 3 +- + src/db/sysdb_private.h | 3 +- + src/db/sysdb_subdomains.c | 63 +++++++++++++++++++++++++-- + src/man/sssd.conf.5.xml | 3 +- + src/providers/ad/ad_subdomains.c | 3 +- + src/providers/ipa/ipa_subdomains.c | 10 +++-- + src/responder/common/responder_get_domains.c | 9 ++-- + src/tests/cmocka/test_fqnames.c | 2 +- + src/tests/cmocka/test_ipa_subdomains_server.c | 2 +- + src/tests/cmocka/test_nss_srv.c | 6 ++- + src/tests/cmocka/test_sysdb_subdomains.c | 25 ++++++----- + src/tests/sysdb-tests.c | 14 +++--- + src/tools/common/sss_tools.c | 2 +- + src/tools/sss_cache.c | 2 +- + 14 files changed, 107 insertions(+), 40 deletions(-) + +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 0cbb2c5c02355e9e9a4e73b075f92d16e4855045..6762b51bee02911fb97d5d393fad2495504ee5ad 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -494,7 +494,8 @@ errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb, + uint32_t trust_direction, + struct ldb_message_element *upn_suffixes); + +-errno_t sysdb_update_subdomains(struct sss_domain_info *domain); ++errno_t sysdb_update_subdomains(struct sss_domain_info *domain, ++ struct confdb_ctx *confdb); + + errno_t sysdb_master_domain_update(struct sss_domain_info *domain); + +diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h +index bfd24799950ab3b31d57df11b8f91c0b2572f13a..dfddd2dda9e593bd02d52dee7d06f520a11bbdf6 100644 +--- a/src/db/sysdb_private.h ++++ b/src/db/sysdb_private.h +@@ -191,7 +191,8 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, + bool enumerate, + const char *forest, + const char **upn_suffixes, +- uint32_t trust_direction); ++ uint32_t trust_direction, ++ struct confdb_ctx *confdb); + + /* Helper functions to deal with the timestamp cache should not be used + * outside the sysdb itself. The timestamp cache should be completely +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index 01f49763b712769f4f74df47961526e5b1514cd4..916dbba153d8c08837425f6fd29a20f5a6aa9fc9 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -23,6 +23,10 @@ + #include "util/util.h" + #include "db/sysdb_private.h" + ++static errno_t ++check_subdom_config_file(struct confdb_ctx *confdb, ++ struct sss_domain_info *subdomain); ++ + struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, + struct sss_domain_info *parent, + const char *name, +@@ -33,10 +37,12 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, + bool enumerate, + const char *forest, + const char **upn_suffixes, +- uint32_t trust_direction) ++ uint32_t trust_direction, ++ struct confdb_ctx *confdb) + { + struct sss_domain_info *dom; + bool inherit_option; ++ errno_t ret; + + DEBUG(SSSDBG_TRACE_FUNC, + "Creating [%s] as subdomain of [%s]!\n", name, parent->name); +@@ -160,6 +166,17 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, + } + dom->sysdb = parent->sysdb; + ++ if (confdb != NULL) { ++ /* If confdb was provided, also check for sssd.conf */ ++ ret = check_subdom_config_file(confdb, dom); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to read subdomain configuration [%d]: %s", ++ ret, sss_strerror(ret)); ++ goto fail; ++ } ++ } ++ + return dom; + + fail: +@@ -167,6 +184,45 @@ fail: + return NULL; + } + ++static errno_t ++check_subdom_config_file(struct confdb_ctx *confdb, ++ struct sss_domain_info *subdomain) ++{ ++ char *sd_conf_path; ++ TALLOC_CTX *tmp_ctx; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ sd_conf_path = subdomain_create_conf_path(tmp_ctx, subdomain); ++ if (sd_conf_path == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* use_fully_qualified_names */ ++ ret = confdb_get_bool(confdb, sd_conf_path, CONFDB_DOMAIN_FQ, ++ true, &subdomain->fqnames); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to get %s option for the subdomain: %s\n", ++ CONFDB_DOMAIN_FQ, subdomain->name); ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_CONF_SETTINGS, "%s/%s has value %s\n", ++ sd_conf_path, CONFDB_DOMAIN_FQ, ++ subdomain->fqnames ? "TRUE" : "FALSE"); ++ ++ ret = EOK; ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + static bool is_forest_root(struct sss_domain_info *d) + { + if (d->forest == NULL) { +@@ -232,7 +288,8 @@ static void link_forest_roots(struct sss_domain_info *domain) + } + } + +-errno_t sysdb_update_subdomains(struct sss_domain_info *domain) ++errno_t sysdb_update_subdomains(struct sss_domain_info *domain, ++ struct confdb_ctx *confdb) + { + int i; + errno_t ret; +@@ -451,7 +508,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain) + if (dom == NULL) { + dom = new_subdomain(domain, domain, name, realm, + flat, id, mpg, enumerate, forest, +- upn_suffixes, trust_direction); ++ upn_suffixes, trust_direction, confdb); + if (dom == NULL) { + ret = ENOMEM; + goto done; +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 284402bc00d37c6c33bf195d2bd719300f265851..1c27742cf0c1b6ffad23ab5b044bf4a168ed8f69 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -2780,7 +2780,8 @@ subdomain_inherit = ldap_purge_cache_timeout + ldap_service_search_base, + ad_server, + ad_backup_server, +- ad_site. ++ ad_site, ++ use_fully_qualified_names + + For more details about these options see their individual description + in the manual page. +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index eecae9c9ca82ad67874c13a3c7b7c617d6232d5c..bc659b2cb0a02723437d24d0021ec3592381e84c 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -656,7 +656,8 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *subdoms_ctx) + /* Just continue */ + } + +- ret = sysdb_update_subdomains(subdoms_ctx->be_ctx->domain); ++ ret = sysdb_update_subdomains(subdoms_ctx->be_ctx->domain, ++ subdoms_ctx->be_ctx->cdb); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n"); + return ret; +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index 7537550606ef09c0b87a80932c75aa4f93c0efab..a07b88fe2f499353293ba90345552413c9792f4b 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -126,7 +126,7 @@ ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx) + return ret; + } + +- ret = sysdb_update_subdomains(ctx->be_ctx->domain); ++ ret = sysdb_update_subdomains(ctx->be_ctx->domain, ctx->be_ctx->cdb); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n"); + return ret; +@@ -780,7 +780,8 @@ done: + static errno_t ipa_apply_view(struct sss_domain_info *domain, + struct ipa_id_ctx *ipa_id_ctx, + const char *view_name, +- bool read_at_init) ++ bool read_at_init, ++ struct confdb_ctx *confdb) + { + const char *current = ipa_id_ctx->view_name; + struct sysdb_ctx *sysdb = domain->sysdb; +@@ -876,7 +877,7 @@ static errno_t ipa_apply_view(struct sss_domain_info *domain, + goto done; + } + +- ret = sysdb_update_subdomains(domain); ++ ret = sysdb_update_subdomains(domain, confdb); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed " + "[%d]: %s\n", ret, sss_strerror(ret)); +@@ -1654,7 +1655,8 @@ static void ipa_subdomains_view_name_done(struct tevent_req *subreq) + + ret = ipa_apply_view(state->sd_ctx->be_ctx->domain, + state->sd_ctx->ipa_id_ctx, view_name, +- state->sd_ctx->view_read_at_init); ++ state->sd_ctx->view_read_at_init, ++ state->sd_ctx->be_ctx->cdb); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set view [%d]: %s\n", + ret, sss_strerror(ret)); +diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c +index 0f39d107dad6c458785b1b8d708e60d7c34e3901..0f9c01214631200f9687635f6302fa5c07e8a1fe 100644 +--- a/src/responder/common/responder_get_domains.c ++++ b/src/responder/common/responder_get_domains.c +@@ -126,7 +126,8 @@ get_next_domain_recv(TALLOC_CTX *mem_ctx, + } + + /* ====== Iterate over all domains, searching for their subdomains ======= */ +-static errno_t process_subdomains(struct sss_domain_info *dom); ++static errno_t process_subdomains(struct sss_domain_info *dom, ++ struct confdb_ctx *confdb); + static void set_time_of_last_request(struct resp_ctx *rctx); + static errno_t check_last_request(struct resp_ctx *rctx, const char *hint); + +@@ -234,7 +235,7 @@ sss_dp_get_domains_process(struct tevent_req *subreq) + goto fail; + } + +- ret = process_subdomains(state->dom); ++ ret = process_subdomains(state->dom, state->rctx->cdb); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "process_subdomains failed, " + "trying next domain.\n"); +@@ -270,7 +271,7 @@ fail: + } + + static errno_t +-process_subdomains(struct sss_domain_info *domain) ++process_subdomains(struct sss_domain_info *domain, struct confdb_ctx *confdb) + { + int ret; + +@@ -288,7 +289,7 @@ process_subdomains(struct sss_domain_info *domain) + /* Retrieve all subdomains of this domain from sysdb + * and create their struct sss_domain_info representations + */ +- ret = sysdb_update_subdomains(domain); ++ ret = sysdb_update_subdomains(domain, confdb); + if (ret != EOK) { + DEBUG(SSSDBG_FUNC_DATA, "sysdb_update_subdomains failed.\n"); + goto done; +diff --git a/src/tests/cmocka/test_fqnames.c b/src/tests/cmocka/test_fqnames.c +index 19788248a39774bb4509363145ac4ce0815b7d28..0ed42a597b7787635c4971b4f1c3d9976949ccd2 100644 +--- a/src/tests/cmocka/test_fqnames.c ++++ b/src/tests/cmocka/test_fqnames.c +@@ -309,7 +309,7 @@ static int parse_name_test_setup(void **state) + * discovered + */ + test_ctx->subdom = new_subdomain(dom, dom, SUBDOMNAME, NULL, SUBFLATNAME, +- NULL, false, false, NULL, NULL, 0); ++ NULL, false, false, NULL, NULL, 0, NULL); + assert_non_null(test_ctx->subdom); + + check_leaks_push(test_ctx); +diff --git a/src/tests/cmocka/test_ipa_subdomains_server.c b/src/tests/cmocka/test_ipa_subdomains_server.c +index 123cf11c01ef4687eecad31a9d73120a87c643e1..ca48425aca69e58358f5fd37e4b8238bfa9efe15 100644 +--- a/src/tests/cmocka/test_ipa_subdomains_server.c ++++ b/src/tests/cmocka/test_ipa_subdomains_server.c +@@ -263,7 +263,7 @@ static void add_test_subdomains(struct trust_test_ctx *test_ctx, + direction, NULL); + assert_int_equal(ret, EOK); + +- ret = sysdb_update_subdomains(test_ctx->tctx->dom); ++ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + + } +diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c +index 50714715cc80338640f2a77ecbe17bd5e0d6e911..3d7e0382197401cb2264671712152fe0709296b6 100644 +--- a/src/tests/cmocka/test_nss_srv.c ++++ b/src/tests/cmocka/test_nss_srv.c +@@ -3206,7 +3206,8 @@ static int nss_subdom_test_setup(void **state) + + subdomain = new_subdomain(nss_test_ctx, nss_test_ctx->tctx->dom, + testdom[0], testdom[1], testdom[2], testdom[3], +- false, false, NULL, NULL, 0); ++ false, false, NULL, NULL, 0, ++ nss_test_ctx->tctx->confdb); + assert_non_null(subdomain); + + ret = sysdb_subdomain_store(nss_test_ctx->tctx->sysdb, +@@ -3214,7 +3215,8 @@ static int nss_subdom_test_setup(void **state) + false, false, NULL, 0, NULL); + assert_int_equal(ret, EOK); + +- ret = sysdb_update_subdomains(nss_test_ctx->tctx->dom); ++ ret = sysdb_update_subdomains(nss_test_ctx->tctx->dom, ++ nss_test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + + nss_test_ctx->subdom = subdomain; +diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c +index 49f44998a06740d1df70ac354ee741824acd8f50..84bcdc17b39dbc8822097c2006f157a09ea5e466 100644 +--- a/src/tests/cmocka/test_sysdb_subdomains.c ++++ b/src/tests/cmocka/test_sysdb_subdomains.c +@@ -103,7 +103,7 @@ static void test_sysdb_subdomain_create(void **state) + false, false, NULL, 0, NULL); + assert_int_equal(ret, EOK); + +- ret = sysdb_update_subdomains(test_ctx->tctx->dom); ++ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + + assert_non_null(test_ctx->tctx->dom->subdomains); +@@ -115,7 +115,7 @@ static void test_sysdb_subdomain_create(void **state) + false, false, NULL, 1, NULL); + assert_int_equal(ret, EOK); + +- ret = sysdb_update_subdomains(test_ctx->tctx->dom); ++ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + + assert_non_null(test_ctx->tctx->dom->subdomains->next); +@@ -133,7 +133,7 @@ static void test_sysdb_subdomain_create(void **state) + false, false, NULL, 0, NULL); + assert_int_equal(ret, EOK); + +- ret = sysdb_update_subdomains(test_ctx->tctx->dom); ++ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + + assert_int_equal(test_ctx->tctx->dom->subdomains->trust_direction, 1); +@@ -145,7 +145,7 @@ static void test_sysdb_subdomain_create(void **state) + ret = sysdb_subdomain_delete(test_ctx->tctx->sysdb, dom1[0]); + assert_int_equal(ret, EOK); + +- ret = sysdb_update_subdomains(test_ctx->tctx->dom); ++ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + + assert_int_equal(sss_domain_get_state(test_ctx->tctx->dom->subdomains), +@@ -235,11 +235,11 @@ static void test_sysdb_link_forest_root_ipa(void **state) + 0, NULL); + assert_int_equal(ret, EOK); + +- ret = sysdb_update_subdomains(test_ctx->tctx->dom); ++ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + + /* Also update dom2 */ +- ret = sysdb_update_subdomains(test_ctx->tctx->dom->next); ++ ret = sysdb_update_subdomains(test_ctx->tctx->dom->next, test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + + sub = find_domain_by_name(test_ctx->tctx->dom, dom1[0], true); +@@ -315,11 +315,11 @@ static void test_sysdb_link_forest_root_ad(void **state) + 0, NULL); + assert_int_equal(ret, EOK); + +- ret = sysdb_update_subdomains(test_ctx->tctx->dom); ++ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + + /* Also update dom2 */ +- ret = sysdb_update_subdomains(test_ctx->tctx->dom->next); ++ ret = sysdb_update_subdomains(test_ctx->tctx->dom->next, test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + + assert_non_null(test_ctx->tctx->dom->forest_root); +@@ -395,14 +395,15 @@ static void test_sysdb_link_forest_member_ad(void **state) + ret = sysdb_master_domain_update(test_ctx->tctx->dom); + assert_int_equal(ret, EOK); + +- ret = sysdb_update_subdomains(test_ctx->tctx->dom); ++ ret = sysdb_update_subdomains(test_ctx->tctx->dom, test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + + /* Also update dom2 */ + ret = sysdb_master_domain_update(test_ctx->tctx->dom->next); + assert_int_equal(ret, EOK); + +- ret = sysdb_update_subdomains(test_ctx->tctx->dom->next); ++ ret = sysdb_update_subdomains(test_ctx->tctx->dom->next, ++ test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + + /* Checks */ +@@ -472,7 +473,7 @@ static void test_sysdb_link_ad_multidom(void **state) + ret = sysdb_master_domain_update(main_dom1); + assert_int_equal(ret, EOK); + +- ret = sysdb_update_subdomains(main_dom1); ++ ret = sysdb_update_subdomains(main_dom1, NULL); + assert_int_equal(ret, EOK); + + ret = sysdb_master_domain_add_info(main_dom2, +@@ -492,7 +493,7 @@ static void test_sysdb_link_ad_multidom(void **state) + ret = sysdb_master_domain_update(main_dom2); + assert_int_equal(ret, EOK); + +- ret = sysdb_update_subdomains(main_dom2); ++ ret = sysdb_update_subdomains(main_dom2, NULL); + assert_int_equal(ret, EOK); + + main_dom1 = find_domain_by_name(test_ctx->tctx->dom, TEST_DOM1_NAME, true); +diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c +index 5bdd631fbfa1b4463fb169e5f07b65fb2c784096..1767dc3c734c6b2e5f74564debd603e2442f491b 100644 +--- a/src/tests/sysdb-tests.c ++++ b/src/tests/sysdb-tests.c +@@ -1395,7 +1395,7 @@ START_TEST (test_sysdb_get_user_attr_subdomain) + /* Create subdomain */ + subdomain = new_subdomain(test_ctx, test_ctx->domain, + "test.sub", "TEST.SUB", "test", "S-3", +- false, false, NULL, NULL, 0); ++ false, false, NULL, NULL, 0, NULL); + fail_if(subdomain == NULL, "Failed to create new subdomain."); + + ret = sss_names_init_from_args(test_ctx, +@@ -5821,14 +5821,14 @@ START_TEST(test_sysdb_subdomain_store_user) + + subdomain = new_subdomain(test_ctx, test_ctx->domain, + testdom[0], testdom[1], testdom[2], testdom[3], +- false, false, NULL, NULL, 0); ++ false, false, NULL, NULL, 0, NULL); + fail_unless(subdomain != NULL, "Failed to create new subdomin."); + ret = sysdb_subdomain_store(test_ctx->sysdb, + testdom[0], testdom[1], testdom[2], testdom[3], + false, false, NULL, 0, NULL); + fail_if(ret != EOK, "Could not set up the test (test subdom)"); + +- ret = sysdb_update_subdomains(test_ctx->domain); ++ ret = sysdb_update_subdomains(test_ctx->domain, NULL); + fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]", + ret, strerror(ret)); + +@@ -5900,14 +5900,14 @@ START_TEST(test_sysdb_subdomain_user_ops) + + subdomain = new_subdomain(test_ctx, test_ctx->domain, + testdom[0], testdom[1], testdom[2], testdom[3], +- false, false, NULL, NULL, 0); ++ false, false, NULL, NULL, 0, NULL); + fail_unless(subdomain != NULL, "Failed to create new subdomin."); + ret = sysdb_subdomain_store(test_ctx->sysdb, + testdom[0], testdom[1], testdom[2], testdom[3], + false, false, NULL, 0, NULL); + fail_if(ret != EOK, "Could not set up the test (test subdom)"); + +- ret = sysdb_update_subdomains(test_ctx->domain); ++ ret = sysdb_update_subdomains(test_ctx->domain, NULL); + fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]", + ret, strerror(ret)); + +@@ -5973,14 +5973,14 @@ START_TEST(test_sysdb_subdomain_group_ops) + + subdomain = new_subdomain(test_ctx, test_ctx->domain, + testdom[0], testdom[1], testdom[2], testdom[3], +- false, false, NULL, NULL, 0); ++ false, false, NULL, NULL, 0, NULL); + fail_unless(subdomain != NULL, "Failed to create new subdomin."); + ret = sysdb_subdomain_store(test_ctx->sysdb, + testdom[0], testdom[1], testdom[2], testdom[3], + false, false, NULL, 0, NULL); + fail_if(ret != EOK, "Could not set up the test (test subdom)"); + +- ret = sysdb_update_subdomains(test_ctx->domain); ++ ret = sysdb_update_subdomains(test_ctx->domain, NULL); + fail_unless(ret == EOK, "sysdb_update_subdomains failed with [%d][%s]", + ret, strerror(ret)); + +diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c +index 0f4f46894130daf722641f25a4cdfaae220252cc..97a3caab3bec88c5727eea2f08b200f1d3b23f0c 100644 +--- a/src/tools/common/sss_tools.c ++++ b/src/tools/common/sss_tools.c +@@ -154,7 +154,7 @@ static errno_t sss_tool_domains_init(TALLOC_CTX *mem_ctx, + } + + /* Update list of subdomains for this domain */ +- ret = sysdb_update_subdomains(dom); ++ ret = sysdb_update_subdomains(dom, confdb); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Failed to update subdomains for domain %s.\n", +diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c +index 59e49a8aa92e3a08ec80e0597304f1a4af0a02be..8a40b38c07f7e76cde5b98e5916816581fea7973 100644 +--- a/src/tools/sss_cache.c ++++ b/src/tools/sss_cache.c +@@ -158,7 +158,7 @@ int main(int argc, const char *argv[]) + dinfo = get_next_domain(dinfo, SSS_GND_DESCEND)) { + if (!IS_SUBDOMAIN(dinfo)) { + /* Update list of subdomains for this domain */ +- ret = sysdb_update_subdomains(dinfo); ++ ret = sysdb_update_subdomains(dinfo, tctx->confdb); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Failed to update subdomains for domain %s.\n", dinfo->name); +-- +2.9.3 + diff --git a/SOURCES/0042-CACHE_REQ-Descend-into-subdomains-on-lookups.patch b/SOURCES/0042-CACHE_REQ-Descend-into-subdomains-on-lookups.patch new file mode 100644 index 0000000..583b606 --- /dev/null +++ b/SOURCES/0042-CACHE_REQ-Descend-into-subdomains-on-lookups.patch @@ -0,0 +1,172 @@ +From 73b3b167e86a87263563aa8aac2b45cdf3668765 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 1 Mar 2017 08:34:57 +0000 +Subject: [PATCH 42/54] 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 + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +--- + 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 2c4917cde750c9063d898c16d3a58ca8c179bc70..28dea33c601f500b9c7af0de3eb9e1c342f03522 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 88e1137a3976308aaf404b684c6d88cc43708bca..6ce6ae0d63967ac50b813a47ac938251619948da 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 be1eb9bd8552156d777e934b0be397b0e66df7cc..af6f23ccfd68f952027462ba3e74ed7219d04651 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 10fb67cbf6e78cfae33bc7208585cb80ea6a9bc4..307b65a24282838b99c472b50a71f06865aed3f0 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 bc6fc9a8f476f97cc4bc5004bc19ba35258a2b6d..e49d6d84a41ce8dabf18c87373826f8e7b684bda 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 2b2caeea172b23b1b1b226def5d926e26c5c0090..74d2b3dea287e890b38e4d5bb176ad2dc6337b7e 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 cbb186df04c7ca7c02dceb98bd5700c984285a4d..ef13f097a8ae78ec9db5b7f6e14924b511578b34 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 1da23d4505a1dad3b2425a996134f8298c03518a..afa2eeeda12794de26e798aee4b88900bc87ed93 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 ee7e69399e318b9835f1623bddc635bf09aa7a1c..eb71b42dad3a805298df0c8425409d571befb31b 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 4289f5fd4c79f0e512f0249abe4422589fa800a0..0670febdce2d51e0373045570dd07f56255db7bc 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, +-- +2.9.3 + diff --git a/SOURCES/0042-sysdb_master_domain_add_info-properly-set-do_update.patch b/SOURCES/0042-sysdb_master_domain_add_info-properly-set-do_update.patch deleted file mode 100644 index 15f9cbc..0000000 --- a/SOURCES/0042-sysdb_master_domain_add_info-properly-set-do_update.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 9899507b2da55a374baef13c4dc3914fe853cf87 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 25 Jul 2016 17:37:51 +0200 -Subject: [PATCH 42/44] sysdb_master_domain_add_info: properly set do_update -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -do_update should be only set if there is a change, i.e if something was -added to the ldb_message. - -Reviewed-by: Lukáš Slebodník ---- - src/db/sysdb_subdomains.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c -index 02206e470e8e035cc05848137df6a1eb04806869..ff83f914f31d566e050c74a3ef5f5745f8c93add 100644 ---- a/src/db/sysdb_subdomains.c -+++ b/src/db/sysdb_subdomains.c -@@ -787,9 +787,9 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain, - ret = sysdb_error_to_errno(ret); - goto done; - } -- } - -- do_update = true; -+ do_update = true; -+ } - } - - if (do_update == false) { --- -2.4.11 - diff --git a/SOURCES/0043-NSS-TESTS-Fix-subdomains-attribution.patch b/SOURCES/0043-NSS-TESTS-Fix-subdomains-attribution.patch new file mode 100644 index 0000000..e142203 --- /dev/null +++ b/SOURCES/0043-NSS-TESTS-Fix-subdomains-attribution.patch @@ -0,0 +1,35 @@ +From 5e3ea50bba1fee75cc0788bcd77ae4991828608e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 1 Mar 2017 13:21:19 +0000 +Subject: [PATCH 43/54] 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 + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + 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 3d7e0382197401cb2264671712152fe0709296b6..cbe0dccdc1d883eae1a9621f12997ef43d05178e 100644 +--- a/src/tests/cmocka/test_nss_srv.c ++++ b/src/tests/cmocka/test_nss_srv.c +@@ -3219,7 +3219,7 @@ static int nss_subdom_test_setup(void **state) + nss_test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + +- nss_test_ctx->subdom = subdomain; ++ nss_test_ctx->subdom = nss_test_ctx->tctx->dom->subdomains; + return 0; + } + +-- +2.9.3 + diff --git a/SOURCES/0043-SYSDB-Removing-of-duplication-of-sysdb_ts_cache_attr.patch b/SOURCES/0043-SYSDB-Removing-of-duplication-of-sysdb_ts_cache_attr.patch deleted file mode 100644 index 20883fd..0000000 --- a/SOURCES/0043-SYSDB-Removing-of-duplication-of-sysdb_ts_cache_attr.patch +++ /dev/null @@ -1,30 +0,0 @@ -From bfbafa51da5e407659c924eed5970f17510ae913 Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Tue, 19 Jul 2016 14:28:35 +0200 -Subject: [PATCH 43/44] SYSDB: Removing of duplication of sysdb_ts_cache_attrs -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Fabiano Fidêncio ---- - src/db/sysdb.h | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 407ce3c18a7077e8fe45c3c9c7576ae626105122..0cc550a4c389b4a1a2b78aff760f4b5cbf94e17f 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -315,9 +315,6 @@ struct range_info { - /* These attributes are stored in the timestamp cache */ - extern const char *sysdb_ts_cache_attrs[]; - --/* These attributes are stored in the timestamp cache */ --extern const char *sysdb_ts_cache_attrs[]; -- - /* values are copied in the structure, allocated on "attrs" */ - int sysdb_attrs_add_val(struct sysdb_attrs *attrs, - const char *name, const struct ldb_val *val); --- -2.4.11 - diff --git a/SOURCES/0044-NSS-TESTS-Improve-setup-teardown-for-subdomains-test.patch b/SOURCES/0044-NSS-TESTS-Improve-setup-teardown-for-subdomains-test.patch new file mode 100644 index 0000000..9eb42a4 --- /dev/null +++ b/SOURCES/0044-NSS-TESTS-Improve-setup-teardown-for-subdomains-test.patch @@ -0,0 +1,274 @@ +From f318eff5277d783972ef0d585ff05c473db44714 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 1 Mar 2017 20:46:10 +0000 +Subject: [PATCH 44/54] 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 + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + 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 cbe0dccdc1d883eae1a9621f12997ef43d05178e..b468204fb1729618830513322f0d901c4c801e94 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); +@@ -3220,6 +3277,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; + } + +@@ -3241,6 +3327,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, +@@ -3904,16 +4022,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, +-- +2.9.3 + diff --git a/SOURCES/0044-test_utils-Fixing-assignment-discards-const-qualifie.patch b/SOURCES/0044-test_utils-Fixing-assignment-discards-const-qualifie.patch deleted file mode 100644 index 053dc43..0000000 --- a/SOURCES/0044-test_utils-Fixing-assignment-discards-const-qualifie.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 2af91b3728470b9831a748d51d081b117648ae91 Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Tue, 26 Jul 2016 10:37:19 +0200 -Subject: [PATCH 44/44] test_utils: Fixing assignment discards 'const' - qualifier -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Lukáš Slebodník ---- - src/tests/cmocka/test_utils.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c -index 4c72a59437105e683cec2d39c36951aeff63767b..5349accc5c6b55f7d725bfdeaf318b90289880dd 100644 ---- a/src/tests/cmocka/test_utils.c -+++ b/src/tests/cmocka/test_utils.c -@@ -1806,13 +1806,13 @@ static void test_sss_get_domain_mappings_content(void **state) - assert_non_null(c); - c->forest_root = find_domain_by_name(dom, "subdom1.dom", true); - assert_non_null(c->forest_root); -- c->forest = "subdom1.dom"; -+ c->forest = discard_const_p(char, "subdom1.dom"); - - c = find_domain_by_name(dom, "subdom3.dom", true); - assert_non_null(c); - c->forest_root = find_domain_by_name(dom, "subdom1.dom", true); - assert_non_null(c->forest_root); -- c->forest = "subdom1.dom"; -+ c->forest = discard_const_p(char, "subdom1.dom"); - - ret = sss_get_domain_mappings_content(test_ctx, dom, &content); - assert_int_equal(ret, EOK); --- -2.4.11 - diff --git a/SOURCES/0045-IPA-make-ipa_resolve_user_list_-send-recv-public-and.patch b/SOURCES/0045-IPA-make-ipa_resolve_user_list_-send-recv-public-and.patch deleted file mode 100644 index bd9f1d8..0000000 --- a/SOURCES/0045-IPA-make-ipa_resolve_user_list_-send-recv-public-and.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 9812095cc83c7258584235528d355c301c492b92 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 12 Jul 2016 17:09:00 +0200 -Subject: [PATCH 45/62] IPA: make ipa_resolve_user_list_{send|recv} public and - allow AD users - -Reviewed-by: Jakub Hrozek -(cherry picked from commit f2e8a7c3230fac11175c0bd17c14c66a8e9b25ad) ---- - src/providers/ipa/ipa_id.c | 20 ++++++++++++++++---- - src/providers/ipa/ipa_id.h | 8 ++++++++ - 2 files changed, 24 insertions(+), 4 deletions(-) - -diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c -index e092cd2f80d3c102f88a9bc48a352e1a140b14e8..7cc79f92b5dcd481706353d403125c46d587e7f6 100644 ---- a/src/providers/ipa/ipa_id.c -+++ b/src/providers/ipa/ipa_id.c -@@ -71,7 +71,7 @@ struct ipa_resolve_user_list_state { - static errno_t ipa_resolve_user_list_get_user_step(struct tevent_req *req); - static void ipa_resolve_user_list_get_user_done(struct tevent_req *subreq); - --static struct tevent_req * -+struct tevent_req * - ipa_resolve_user_list_send(TALLOC_CTX *memctx, struct tevent_context *ev, - struct ipa_id_ctx *ipa_ctx, - const char *domain_name, -@@ -132,7 +132,14 @@ static errno_t ipa_resolve_user_list_get_user_step(struct tevent_req *req) - - DEBUG(SSSDBG_TRACE_ALL, "Trying to resolve user [%s].\n", ar->filter_value); - -- subreq = ipa_id_get_account_info_send(state, state->ev, state->ipa_ctx, ar); -+ if (strcasecmp(state->domain_name, -+ state->ipa_ctx->sdap_id_ctx->be->domain->name) != 0) { -+ subreq = ipa_subdomain_account_send(state, state->ev, state->ipa_ctx, -+ ar); -+ } else { -+ subreq = ipa_id_get_account_info_send(state, state->ev, state->ipa_ctx, -+ ar); -+ } - if (subreq == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "sdap_handle_acct_req_send failed.\n"); - return ENOMEM; -@@ -151,7 +158,12 @@ static void ipa_resolve_user_list_get_user_done(struct tevent_req *subreq) - struct ipa_resolve_user_list_state); - int ret; - -- ret = ipa_id_get_account_info_recv(subreq, &state->dp_error); -+ if (strcasecmp(state->domain_name, -+ state->ipa_ctx->sdap_id_ctx->be->domain->name) != 0) { -+ ret = ipa_subdomain_account_recv(subreq, &state->dp_error); -+ } else { -+ ret = ipa_id_get_account_info_recv(subreq, &state->dp_error); -+ } - talloc_zfree(subreq); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sdap_handle_acct request failed: %d\n", ret); -@@ -182,7 +194,7 @@ done: - return; - } - --static int ipa_resolve_user_list_recv(struct tevent_req *req, int *dp_error) -+int ipa_resolve_user_list_recv(struct tevent_req *req, int *dp_error) - { - struct ipa_resolve_user_list_state *state = tevent_req_data(req, - struct ipa_resolve_user_list_state); -diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h -index 17db5226a29a54485f7b26eb9853ef2380426bdf..485fa3f8e6af48ddcf1178c3486456753035c948 100644 ---- a/src/providers/ipa/ipa_id.h -+++ b/src/providers/ipa/ipa_id.h -@@ -135,4 +135,12 @@ struct tevent_req *ipa_get_subdom_acct_process_pac_send(TALLOC_CTX *mem_ctx, - struct ldb_message *user_msg); - - errno_t ipa_get_subdom_acct_process_pac_recv(struct tevent_req *req); -+ -+struct tevent_req * -+ipa_resolve_user_list_send(TALLOC_CTX *memctx, struct tevent_context *ev, -+ struct ipa_id_ctx *ipa_ctx, -+ const char *domain_name, -+ struct ldb_message_element *users); -+int ipa_resolve_user_list_recv(struct tevent_req *req, int *dp_error); -+ - #endif --- -2.4.11 - diff --git a/SOURCES/0045-NSS-TESTS-Include-searches-for-non-fqnames-members-o.patch b/SOURCES/0045-NSS-TESTS-Include-searches-for-non-fqnames-members-o.patch new file mode 100644 index 0000000..08acdce --- /dev/null +++ b/SOURCES/0045-NSS-TESTS-Include-searches-for-non-fqnames-members-o.patch @@ -0,0 +1,355 @@ +From 510971d2abc3b76799048cd608511d693f5c3edc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 1 Mar 2017 08:33:06 +0000 +Subject: [PATCH 45/54] 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 + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + src/tests/cmocka/test_nss_srv.c | 246 ++++++++++++++++++++++++++++++++++------ + 1 file changed, 211 insertions(+), 35 deletions(-) + +diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c +index b468204fb1729618830513322f0d901c4c801e94..ede72b341b60842ad470df2794aa90ea9797e999 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]); ++ 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]); + +- 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); ++ 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]); ++ 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); ++ 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"), +@@ -4023,15 +4187,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, +-- +2.9.3 + diff --git a/SOURCES/0046-IPA-expand-ghost-members-of-AD-groups-in-server-mode.patch b/SOURCES/0046-IPA-expand-ghost-members-of-AD-groups-in-server-mode.patch deleted file mode 100644 index 9b41801..0000000 --- a/SOURCES/0046-IPA-expand-ghost-members-of-AD-groups-in-server-mode.patch +++ /dev/null @@ -1,115 +0,0 @@ -From c17e7bc80adf9741054e53dc6e8d8f6afa273e18 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 12 Jul 2016 17:09:40 +0200 -Subject: [PATCH 46/62] IPA: expand ghost members of AD groups in server-mode - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 160ba891ec483c5b7d2a3fcca5bd992fc790efe0) ---- - src/providers/ipa/ipa_subdomains_id.c | 79 ++++++++++++++++++++++++++++++++++- - 1 file changed, 78 insertions(+), 1 deletion(-) - -diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c -index 65bfd33765d5799037075e599049761f18466bb2..542c596a983bcb48f4eac699f78eb956326cefa2 100644 ---- a/src/providers/ipa/ipa_subdomains_id.c -+++ b/src/providers/ipa/ipa_subdomains_id.c -@@ -1201,6 +1201,67 @@ fail: - return; - } - -+static void ipa_check_ghost_members_done(struct tevent_req *subreq); -+static errno_t ipa_check_ghost_members(struct tevent_req *req) -+{ -+ struct ipa_get_ad_acct_state *state = tevent_req_data(req, -+ struct ipa_get_ad_acct_state); -+ errno_t ret; -+ struct tevent_req *subreq; -+ struct ldb_message_element *ghosts = NULL; -+ -+ -+ if (state->obj_msg == NULL) { -+ ret = get_object_from_cache(state, state->obj_dom, state->ar, -+ &state->obj_msg); -+ if (ret == ENOENT) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Object not found, ending request\n"); -+ return EOK; -+ } else if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "get_object_from_cache failed.\n"); -+ return ret; -+ } -+ } -+ -+ ghosts = ldb_msg_find_element(state->obj_msg, SYSDB_GHOST); -+ -+ if (ghosts != NULL) { -+ /* Resolve ghost members */ -+ subreq = ipa_resolve_user_list_send(state, state->ev, -+ state->ipa_ctx, -+ state->obj_dom->name, -+ ghosts); -+ if (subreq == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "ipa_resolve_user_list_send failed.\n"); -+ return ENOMEM; -+ } -+ tevent_req_set_callback(subreq, ipa_check_ghost_members_done, req); -+ return EAGAIN; -+ } -+ -+ return EOK; -+} -+ -+static void ipa_check_ghost_members_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ int ret; -+ -+ ret = ipa_resolve_user_list_recv(subreq, NULL); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "ipa_resolve_user_list request failed [%d]\n", -+ ret); -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+ return; -+} -+ - static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req) - { - struct ipa_get_ad_acct_state *state = tevent_req_data(req, -@@ -1228,11 +1289,27 @@ static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req) - entry_type = (state->ar->entry_type & BE_REQ_TYPE_MASK); - if (entry_type != BE_REQ_INITGROUPS - && entry_type != BE_REQ_USER -- && entry_type != BE_REQ_BY_SECID) { -+ && entry_type != BE_REQ_BY_SECID -+ && entry_type != BE_REQ_GROUP) { - tevent_req_done(req); - return EOK; - } - -+ /* expand ghost members, if any, to get group members with overrides -+ * right. */ -+ if (entry_type == BE_REQ_GROUP) { -+ ret = ipa_check_ghost_members(req); -+ if (ret == EOK) { -+ tevent_req_done(req); -+ return EOK; -+ } else if (ret == EAGAIN) { -+ return EOK; -+ } else { -+ DEBUG(SSSDBG_OP_FAILURE, "ipa_check_ghost_members failed.\n"); -+ return ret; -+ } -+ } -+ - /* Replace ID with name in search filter */ - if ((entry_type == BE_REQ_USER && state->ar->filter_type == BE_FILTER_IDNUM) - || (entry_type == BE_REQ_INITGROUPS --- -2.4.11 - diff --git a/SOURCES/0046-SYSDB-Add-methods-to-deal-with-the-domain-s-resoluti.patch b/SOURCES/0046-SYSDB-Add-methods-to-deal-with-the-domain-s-resoluti.patch new file mode 100644 index 0000000..b2a6305 --- /dev/null +++ b/SOURCES/0046-SYSDB-Add-methods-to-deal-with-the-domain-s-resoluti.patch @@ -0,0 +1,289 @@ +From b601cae66c441163a00f73c64d00a29e0840d44e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Fri, 24 Mar 2017 15:29:23 +0100 +Subject: [PATCH 46/54] SYSDB: Add methods to deal with the domain's resolution + order +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In the following-up patches those newly introduced methods will be used +to deal with the domainResolutionOrder attribute. + +The sysdb_update_domain_resolution_order() method is purposely not +checking whether a value has changed or not before writing to sysdb and +while may not be optimal, the readability of the code has increased a +lot by keeping it as simple as possible. + +Tests for these new methods are part of the next commit. + +Related: +https://pagure.io/SSSD/sssd/issue/3001 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + Makefile.am | 2 + + src/db/sysdb.h | 2 + + src/db/sysdb_domain_resolution_order.c | 169 +++++++++++++++++++++++++++++++++ + src/db/sysdb_domain_resolution_order.h | 37 ++++++++ + 4 files changed, 210 insertions(+) + create mode 100644 src/db/sysdb_domain_resolution_order.c + create mode 100644 src/db/sysdb_domain_resolution_order.h + +diff --git a/Makefile.am b/Makefile.am +index 359feddef298b0013c726409b7ba8b86504abf09..8052150be32d89813764e9bc436dfcb211a738d6 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -736,6 +736,7 @@ dist_noinst_HEADERS = \ + src/db/sysdb_private.h \ + src/db/sysdb_services.h \ + src/db/sysdb_ssh.h \ ++ src/db/sysdb_domain_resolution_order.h \ + src/confdb/confdb.h \ + src/confdb/confdb_private.h \ + src/confdb/confdb_setup.h \ +@@ -995,6 +996,7 @@ libsss_util_la_SOURCES = \ + src/db/sysdb_idmap.c \ + src/db/sysdb_gpo.c \ + src/db/sysdb_certmap.c \ ++ src/db/sysdb_domain_resolution_order.c \ + src/monitor/monitor_sbus.c \ + src/providers/dp_auth_util.c \ + src/providers/dp_pam_data_util.c \ +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 6762b51bee02911fb97d5d393fad2495504ee5ad..42d2857ed7765c17e7d84b0da93ed07758fbe012 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -184,6 +184,8 @@ + #define SYSDB_OVERRIDE_GROUP_CLASS "groupOverride" + #define SYSDB_OVERRIDE_DN "overrideDN" + #define SYSDB_OVERRIDE_OBJECT_DN "overrideObjectDN" ++#define SYSDB_USE_DOMAIN_RESOLUTION_ORDER "useDomainResolutionOrder" ++#define SYSDB_DOMAIN_RESOLUTION_ORDER "domainResolutionOrder" + + #define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)" + +diff --git a/src/db/sysdb_domain_resolution_order.c b/src/db/sysdb_domain_resolution_order.c +new file mode 100644 +index 0000000000000000000000000000000000000000..63774461a1e9f3dc863220d418e29e06d6e6e6df +--- /dev/null ++++ b/src/db/sysdb_domain_resolution_order.c +@@ -0,0 +1,169 @@ ++/* ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++#include ++ ++#include "db/sysdb.h" ++#include "db/sysdb_private.h" ++ ++static errno_t ++sysdb_get_domain_resolution_order_string_attr(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ struct ldb_dn *dn, ++ const char *const *attrs, ++ const char **_attr) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_result *res; ++ const char *attr; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = ldb_search(sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, ++ NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = EIO; ++ goto done; ++ } ++ ++ if (res->count > 1) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Base search returned [%d] results, expected 1.\n", res->count); ++ ret = EINVAL; ++ goto done; ++ } else if (res->count == 0) { ++ ret = ENOENT; ++ goto done; ++ } else { ++ /* res->count == 1 */ ++ attr = ldb_msg_find_attr_as_string(res->msgs[0], attrs[0], NULL); ++ if (attr == NULL) { ++ ret = ENOENT; ++ goto done; ++ } ++ } ++ ++ *_attr = talloc_steal(mem_ctx, attr); ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++errno_t ++sysdb_get_domain_resolution_order(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ struct ldb_dn *dn, ++ const char **_domain_resolution_order) ++{ ++ TALLOC_CTX *tmp_ctx; ++ const char *domain_resolution_order = NULL; ++ const char *attrs[] = { SYSDB_DOMAIN_RESOLUTION_ORDER, NULL }; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sysdb_get_domain_resolution_order_string_attr( ++ tmp_ctx, sysdb, dn, attrs, &domain_resolution_order); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_get_domain_resolution_order_string_attr() failed " ++ "[%d]: [%s]", ++ ret, sss_strerror(ret)); ++ goto done; ++ } else if (ret == ENOENT) { ++ *_domain_resolution_order = NULL; ++ goto done; ++ } else { ++ /* ret == EOK */ ++ *_domain_resolution_order = talloc_steal(mem_ctx, ++ domain_resolution_order); ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++errno_t ++sysdb_update_domain_resolution_order(struct sysdb_ctx *sysdb, ++ struct ldb_dn *dn, ++ const char *domain_resolution_order) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_message *msg; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ msg = ldb_msg_new(tmp_ctx); ++ if (msg == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ msg->dn = dn; ++ ++ ret = ldb_msg_add_empty(msg, SYSDB_DOMAIN_RESOLUTION_ORDER, ++ LDB_FLAG_MOD_REPLACE, NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ if (domain_resolution_order != NULL) { ++ ret = ldb_msg_add_string(msg, SYSDB_DOMAIN_RESOLUTION_ORDER, ++ domain_resolution_order); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ } ++ ++ ret = ldb_modify(sysdb->ldb, msg); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "ldb_modify()_failed: [%s][%d][%s]\n", ++ ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb)); ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} +diff --git a/src/db/sysdb_domain_resolution_order.h b/src/db/sysdb_domain_resolution_order.h +new file mode 100644 +index 0000000000000000000000000000000000000000..45d2ea63f6bc14cd3184994530846ee6f762d4d0 +--- /dev/null ++++ b/src/db/sysdb_domain_resolution_order.h +@@ -0,0 +1,37 @@ ++/* ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++#ifndef _SYSDB_DOMAIN_RESOLUTION_ORDER_H_ ++#define _SYSDB_DOMAIN_RESOLUTION_ORDER_H_ ++ ++#include "db/sysdb.h" ++ ++errno_t ++sysdb_get_domain_resolution_order(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ struct ldb_dn *dn, ++ const char **_domain_resolution_order); ++ ++errno_t ++sysdb_update_domain_resolution_order(struct sysdb_ctx *sysdb, ++ struct ldb_dn *dn, ++ const char *domain_resolution_order); ++ ++#endif /* _SYSDB_DOMAIN_RESOLUTION_ORDER_H_ */ +-- +2.9.3 + diff --git a/SOURCES/0047-SYSDB-TESTS-Add-tests-for-the-domain-s-resolution-or.patch b/SOURCES/0047-SYSDB-TESTS-Add-tests-for-the-domain-s-resolution-or.patch new file mode 100644 index 0000000..459a50f --- /dev/null +++ b/SOURCES/0047-SYSDB-TESTS-Add-tests-for-the-domain-s-resolution-or.patch @@ -0,0 +1,259 @@ +From 22a10ea2b6b8a56fc040d852867040dce067548a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Fri, 24 Mar 2017 23:15:04 +0100 +Subject: [PATCH 47/54] SYSDB/TESTS: Add tests for the domain's resolution + order methods +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduce a new and small set of tests for these new helper methods that +are going to be used in different parts of the code in the follow-up +patches. + +Related: +https://pagure.io/SSSD/sssd/issue/3001 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + Makefile.am | 16 ++ + .../cmocka/test_sysdb_domain_resolution_order.c | 190 +++++++++++++++++++++ + 2 files changed, 206 insertions(+) + create mode 100644 src/tests/cmocka/test_sysdb_domain_resolution_order.c + +diff --git a/Makefile.am b/Makefile.am +index 8052150be32d89813764e9bc436dfcb211a738d6..450785bf4c482cce1e1440f1336879150537888e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -263,6 +263,7 @@ if HAVE_CMOCKA + test_sysdb_certmap \ + test_sysdb_sudo \ + test_sysdb_utils \ ++ test_sysdb_domain_resolution_order \ + test_wbc_calls \ + test_be_ptask \ + test_copy_ccache \ +@@ -2875,6 +2876,21 @@ test_sysdb_utils_LDADD = \ + libsss_test_common.la \ + $(NULL) + ++test_sysdb_domain_resolution_order_SOURCES = \ ++ src/tests/cmocka/test_sysdb_domain_resolution_order.c \ ++ $(NULL) ++test_sysdb_domain_resolution_order_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(NULL) ++test_sysdb_domain_resolution_order_LDADD = \ ++ $(CMOCKA_LIBS) \ ++ $(LDB_LIBS) \ ++ $(POPT_LIBS) \ ++ $(TALLOC_LIBS) \ ++ $(SSSD_INTERNAL_LTLIBS) \ ++ libsss_test_common.la \ ++ $(NULL) ++ + test_wbc_calls_SOURCES = \ + src/tests/cmocka/test_wbc_calls.c \ + src/sss_client/idmap/sss_nss_idmap.c \ +diff --git a/src/tests/cmocka/test_sysdb_domain_resolution_order.c b/src/tests/cmocka/test_sysdb_domain_resolution_order.c +new file mode 100644 +index 0000000000000000000000000000000000000000..59a85ce431be9ac27c1e8e6b5e4e5f8300af549e +--- /dev/null ++++ b/src/tests/cmocka/test_sysdb_domain_resolution_order.c +@@ -0,0 +1,190 @@ ++/* ++ SSSD ++ ++ sysdb_domain_resolution_order - Tests for domain resolution order calls ++ ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "tests/cmocka/common_mock.h" ++#include "tests/common.h" ++#include "db/sysdb_domain_resolution_order.h" ++#include "db/sysdb_private.h" /* for sysdb->ldb member */ ++ ++#define TESTS_PATH "tp_" BASE_FILE_STEM ++#define TEST_CONF_DB "test_sysdb_domain_resolution_order.ldb" ++ ++#define TEST_DOM_NAME "test_sysdb_domain_resolution_order" ++ ++#define TEST_ID_PROVIDER "ldap" ++ ++struct domain_resolution_order_test_ctx { ++ struct sss_test_ctx *tctx; ++}; ++ ++static int test_sysdb_domain_resolution_order_setup(void **state) ++{ ++ struct domain_resolution_order_test_ctx *test_ctx; ++ ++ assert_true(leak_check_setup()); ++ ++ test_ctx = talloc_zero(global_talloc_context, ++ struct domain_resolution_order_test_ctx); ++ assert_non_null(test_ctx); ++ ++ test_dom_suite_setup(TESTS_PATH); ++ ++ test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, ++ TEST_CONF_DB, TEST_DOM_NAME, ++ TEST_ID_PROVIDER, NULL); ++ assert_non_null(test_ctx->tctx); ++ ++ *state = test_ctx; ++ return 0; ++} ++ ++static int test_sysdb_domain_resolution_order_teardown(void **state) ++{ ++ struct domain_resolution_order_test_ctx *test_ctx = ++ talloc_get_type(*state, struct domain_resolution_order_test_ctx); ++ ++ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME); ++ talloc_free(test_ctx); ++ assert_true(leak_check_teardown()); ++ return 0; ++} ++ ++static void test_sysdb_domain_resolution_order_ops(void **state) ++{ ++ errno_t ret; ++ struct domain_resolution_order_test_ctx *test_ctx = ++ talloc_get_type(*state, struct domain_resolution_order_test_ctx); ++ const char *domains_in = NULL; ++ const char *domains_out = NULL; ++ struct ldb_dn *dn; ++ ++ dn = ldb_dn_new_fmt(test_ctx, test_ctx->tctx->dom->sysdb->ldb, ++ SYSDB_DOM_BASE, test_ctx->tctx->dom->name); ++ ++ /* Adding domainResolutionOrder for the first time */ ++ domains_in = "foo:bar:foobar"; ++ ret = sysdb_update_domain_resolution_order(test_ctx->tctx->dom->sysdb, ++ dn, domains_in); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_get_domain_resolution_order(test_ctx, ++ test_ctx->tctx->dom->sysdb, dn, ++ &domains_out); ++ assert_int_equal(ret, EOK); ++ assert_true(strcmp(domains_in, domains_out) == 0); ++ ++ /* Setting the domainResolutionOrder to ":" ... ++ * ++ * It means, the domainResolutionOrder is set, but if there's another ++ * domainResolutionOrder with lower precedence those must be ignored. ++ */ ++ domains_in = ":"; ++ ret = sysdb_update_domain_resolution_order(test_ctx->tctx->dom->sysdb, ++ dn, domains_in); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_get_domain_resolution_order(test_ctx, ++ test_ctx->tctx->dom->sysdb, dn, ++ &domains_out); ++ assert_int_equal(ret, EOK); ++ assert_true(strcmp(domains_in, domains_out) == 0); ++ ++ /* Changing the domainResolutionOrder */ ++ domains_in = "bar:foobar:foo"; ++ ret = sysdb_update_domain_resolution_order(test_ctx->tctx->dom->sysdb, ++ dn, domains_in); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_get_domain_resolution_order(test_ctx, ++ test_ctx->tctx->dom->sysdb, dn, ++ &domains_out); ++ assert_int_equal(ret, EOK); ++ assert_true(strcmp(domains_out, domains_out) == 0); ++ ++ /* Removing the domainResolutionOrder attribute */ ++ domains_in = NULL; ++ ret = sysdb_update_domain_resolution_order(test_ctx->tctx->dom->sysdb, ++ dn, domains_in); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_get_domain_resolution_order(test_ctx, ++ test_ctx->tctx->dom->sysdb, dn, ++ &domains_out); ++ assert_int_equal(ret, ENOENT); ++ assert_true(domains_out == NULL); ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ int rv; ++ int no_cleanup = 0; ++ poptContext pc; ++ int opt; ++ struct poptOption long_options[] = { ++ POPT_AUTOHELP ++ SSSD_DEBUG_OPTS ++ {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0, ++ _("Do not delete the test database after a test run"), NULL }, ++ POPT_TABLEEND ++ }; ++ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test_setup_teardown(test_sysdb_domain_resolution_order_ops, ++ test_sysdb_domain_resolution_order_setup, ++ test_sysdb_domain_resolution_order_teardown), ++ }; ++ ++ /* Set debug level to invalid value so we can deside if -d 0 was used. */ ++ debug_level = SSSDBG_INVALID; ++ ++ pc = poptGetContext(argv[0], argc, argv, long_options, 0); ++ while((opt = poptGetNextOpt(pc)) != -1) { ++ switch(opt) { ++ default: ++ fprintf(stderr, "\nInvalid option %s: %s\n\n", ++ poptBadOption(pc, 0), poptStrerror(opt)); ++ poptPrintUsage(pc, stderr, 0); ++ return 1; ++ } ++ } ++ poptFreeContext(pc); ++ ++ DEBUG_CLI_INIT(debug_level); ++ ++ tests_set_cwd(); ++ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, LOCAL_SYSDB_FILE); ++ test_dom_suite_setup(TESTS_PATH); ++ rv = cmocka_run_group_tests(tests, NULL, NULL); ++ ++ if (rv == 0 && no_cleanup == 0) { ++ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, LOCAL_SYSDB_FILE); ++ } ++ return rv; ++} +-- +2.9.3 + diff --git a/SOURCES/0047-sysdb-add-sysdb_get_user_members_recursively.patch b/SOURCES/0047-sysdb-add-sysdb_get_user_members_recursively.patch deleted file mode 100644 index 037cdd0..0000000 --- a/SOURCES/0047-sysdb-add-sysdb_get_user_members_recursively.patch +++ /dev/null @@ -1,103 +0,0 @@ -From a1e606d051c54dd603bf09adb2bd6d0d7db2663f Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 20 Jul 2016 18:42:27 +0200 -Subject: [PATCH 47/62] sysdb: add sysdb_get_user_members_recursively() - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 17bfd9f69251781140e4b2b55ffeb649d7a79e86) ---- - src/db/sysdb.h | 5 +++++ - src/db/sysdb_ops.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 66 insertions(+) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 0cc550a4c389b4a1a2b78aff760f4b5cbf94e17f..405f89e2f1ac6fabc06e77c345de8693845f9d92 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -1257,6 +1257,11 @@ errno_t sysdb_get_sids_of_members(TALLOC_CTX *mem_ctx, - const char ***_dns, - size_t *_n); - -+errno_t sysdb_get_user_members_recursively(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *dom, -+ struct ldb_dn *group_dn, -+ struct ldb_result **members); -+ - errno_t sysdb_handle_original_uuid(const char *orig_name, - struct sysdb_attrs *src_attrs, - const char *src_name, -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 19d6be03ede1bcec3bc7a4ed777e326460d80591..9a8a55ed8aa69e1638d0ab6f636e43baa3d0bfea 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -4711,6 +4711,67 @@ done: - return ret; - } - -+errno_t sysdb_get_user_members_recursively(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *dom, -+ struct ldb_dn *group_dn, -+ struct ldb_result **members) -+{ -+ TALLOC_CTX *tmp_ctx; -+ int ret; -+ size_t count; -+ struct ldb_result *res; -+ struct ldb_dn *base_dn; -+ char *filter; -+ const char *attrs[] = SYSDB_PW_ATTRS; -+ struct ldb_message **msgs; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ base_dn = sysdb_base_dn(dom->sysdb, tmp_ctx); -+ if (base_dn == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_base_dn failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ filter = talloc_asprintf(tmp_ctx, "(&("SYSDB_UC")("SYSDB_MEMBEROF"=%s))", -+ ldb_dn_get_linearized(group_dn)); -+ if (filter == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = sysdb_search_entry(tmp_ctx, dom->sysdb, base_dn, LDB_SCOPE_SUBTREE, -+ filter, attrs, &count, &msgs); -+ -+ res = talloc_zero(tmp_ctx, struct ldb_result); -+ if (res == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ res->count = count; -+ res->msgs = talloc_steal(res, msgs); -+ -+ ret = EOK; -+ -+done: -+ if (ret == EOK) { -+ *members = talloc_steal(mem_ctx, res); -+ } else if (ret == ENOENT) { -+ DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n"); -+ } else { -+ DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret)); -+ } -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ - errno_t sysdb_handle_original_uuid(const char *orig_name, - struct sysdb_attrs *src_attrs, - const char *src_name, --- -2.4.11 - diff --git a/SOURCES/0048-IPA-Get-ipaDomainsResolutionOrder-from-ipaConfig.patch b/SOURCES/0048-IPA-Get-ipaDomainsResolutionOrder-from-ipaConfig.patch new file mode 100644 index 0000000..3dcbc82 --- /dev/null +++ b/SOURCES/0048-IPA-Get-ipaDomainsResolutionOrder-from-ipaConfig.patch @@ -0,0 +1,369 @@ +From 4ff821a9a37cb43f9c34faef4b5ccbdc8dc6a7e8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 22 Mar 2017 13:40:20 +0100 +Subject: [PATCH 48/54] IPA: Get ipaDomainsResolutionOrder from ipaConfig +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +ipaDomainsResolutionOrder provides a list of domains that have to be +looked up firstly during cache_req searches. + +This commit only fetches this list from the server and stores its value +at sysdb so we can make use of it later on this patch series. + +There are no tests for newly introduced sysdb methods are those are +basically only calling sysdb_update_domain_resolution_order(), +sysdb_get_domain_resolution_order() and +sysdb_get_use_domain_resolution_order() which are have tests written +for. + +Related: +https://pagure.io/SSSD/sssd/issue/3001 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + src/db/sysdb.h | 11 +++ + src/db/sysdb_subdomains.c | 67 +++++++++++++++ + src/providers/ipa/ipa_subdomains.c | 168 ++++++++++++++++++++++++++++++++++--- + 3 files changed, 234 insertions(+), 12 deletions(-) + +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 42d2857ed7765c17e7d84b0da93ed07758fbe012..75a07d4d2effb028ec654342113f8478e1eba10e 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -489,6 +489,17 @@ int sysdb_transaction_cancel(struct sysdb_ctx *sysdb); + /* functions related to subdomains */ + errno_t sysdb_domain_create(struct sysdb_ctx *sysdb, const char *domain_name); + ++errno_t sysdb_domain_get_domain_resolution_order( ++ TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ const char *domain_name, ++ const char **_domain_resolution_order); ++ ++errno_t sysdb_domain_update_domain_resolution_order( ++ struct sysdb_ctx *sysdb, ++ const char *domain_name, ++ const char *domain_resolution_order); ++ + errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb, + const char *name, const char *realm, + const char *flat_name, const char *domain_id, +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index 916dbba153d8c08837425f6fd29a20f5a6aa9fc9..e2a4f7bb1fcdf20b6b7e04efc7f396d1c3d08f0f 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -22,6 +22,7 @@ + + #include "util/util.h" + #include "db/sysdb_private.h" ++#include "db/sysdb_domain_resolution_order.h" + + static errno_t + check_subdom_config_file(struct confdb_ctx *confdb, +@@ -1210,3 +1211,69 @@ done: + talloc_free(tmp_ctx); + return ret; + } ++ ++errno_t ++sysdb_domain_get_domain_resolution_order(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ const char *domain_name, ++ const char **_domain_resolution_order) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_dn *dn; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_DOM_BASE, domain_name); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_get_domain_resolution_order(mem_ctx, sysdb, dn, ++ _domain_resolution_order); ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++errno_t ++sysdb_domain_update_domain_resolution_order(struct sysdb_ctx *sysdb, ++ const char *domain_name, ++ const char *domain_resolution_order) ++{ ++ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_dn *dn; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_DOM_BASE, domain_name); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_update_domain_resolution_order(sysdb, dn, ++ domain_resolution_order); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_update_domain_resolution_order() failed [%d]: [%s].\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index a07b88fe2f499353293ba90345552413c9792f4b..01a0ce812d861b24565d2f71f27d6b8ceb2965bc 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -29,6 +29,7 @@ + #include "providers/ipa/ipa_common.h" + #include "providers/ipa/ipa_id.h" + #include "providers/ipa/ipa_opts.h" ++#include "providers/ipa/ipa_config.h" + + #include + +@@ -51,6 +52,8 @@ + + #define IPA_ASSIGNED_ID_VIEW "ipaAssignedIDView" + ++#define IPA_DOMAIN_RESOLUTION_ORDER "ipaDomainResolutionOrder" ++ + /* do not refresh more often than every 5 seconds for now */ + #define IPA_SUBDOMAIN_REFRESH_LIMIT 5 + +@@ -1681,6 +1684,117 @@ static errno_t ipa_subdomains_view_name_recv(struct tevent_req *req) + return EOK; + } + ++struct ipa_domain_resolution_order_state { ++ struct sss_domain_info *domain; ++}; ++ ++static void ipa_domain_resolution_order_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++ipa_domain_resolution_order_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ipa_subdomains_ctx *sd_ctx, ++ struct sdap_handle *sh) ++{ ++ struct ipa_domain_resolution_order_state *state; ++ struct tevent_req *subreq; ++ struct tevent_req *req; ++ const char *attrs[] = {IPA_DOMAIN_RESOLUTION_ORDER, NULL}; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct ipa_domain_resolution_order_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ state->domain = sd_ctx->be_ctx->domain; ++ ++ subreq = ipa_get_config_send(state, ev, sh, sd_ctx->sdap_id_ctx->opts, ++ state->domain->name, attrs); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_domain_resolution_order_done, req); ++ ++ return req; ++ ++immediately: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ ++ return req; ++} ++ ++static void ipa_domain_resolution_order_done(struct tevent_req *subreq) ++{ ++ struct ipa_domain_resolution_order_state *state; ++ struct tevent_req *req; ++ struct sysdb_attrs *config = NULL; ++ const char *domain_resolution_order = NULL; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_domain_resolution_order_state); ++ ++ ret = ipa_get_config_recv(subreq, state, &config); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to get the domains' resolution order configuration " ++ "from the server [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ if (config != NULL) { ++ ret = sysdb_attrs_get_string(config, IPA_DOMAIN_RESOLUTION_ORDER, ++ &domain_resolution_order); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to get the domains' resolution order configuration " ++ "value [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } else if (ret == ENOENT) { ++ domain_resolution_order = NULL; ++ } ++ } ++ ++ ret = sysdb_domain_update_domain_resolution_order( ++ state->domain->sysdb, state->domain->name, ++ domain_resolution_order); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_domain_update_resolution_order() [%d]: [%s].\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++static errno_t ipa_domain_resolution_order_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} + + struct ipa_subdomains_refresh_state { + struct tevent_context *ev; +@@ -1695,6 +1809,7 @@ static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq); + static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq); + static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq); + static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq); ++static void ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq); + + static struct tevent_req * + ipa_subdomains_refresh_send(TALLOC_CTX *mem_ctx, +@@ -1916,7 +2031,6 @@ static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq) + { + struct ipa_subdomains_refresh_state *state; + struct tevent_req *req; +- int dp_error; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); +@@ -1924,24 +2038,55 @@ static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq) + + ret = ipa_subdomains_view_name_recv(subreq); + talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unable to get view name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ subreq = ipa_domain_resolution_order_send(state, state->ev, state->sd_ctx, ++ sdap_id_op_handle(state->sdap_op)); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ tevent_req_set_callback(subreq, ++ ipa_domain_refresh_resolution_order_done, ++ req); ++} ++ ++static void ++ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq) ++{ ++ struct ipa_subdomains_refresh_state *state; ++ struct tevent_req *req; ++ int dp_error; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_subdomains_refresh_state); ++ ++ ret = ipa_domain_resolution_order_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Unable to get the domains order resolution [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ + ret = sdap_id_op_done(state->sdap_op, ret, &dp_error); + if (dp_error == DP_ERR_OK && ret != EOK) { + /* retry */ + ret = ipa_subdomains_refresh_retry(req); +- if (ret != EOK) { +- goto done; +- } +- return; + } else if (dp_error == DP_ERR_OFFLINE) { + ret = ERR_OFFLINE; +- goto done; +- } else if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get view name " +- "[%d]: %s\n", ret, sss_strerror(ret)); +- goto done; + } + +-done: + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_FUNC, "Unable to refresh subdomains [%d]: %s\n", + ret, sss_strerror(ret)); +@@ -1949,7 +2094,6 @@ done: + return; + } + +- DEBUG(SSSDBG_TRACE_FUNC, "Subdomains refreshed.\n"); + tevent_req_done(req); + } + +-- +2.9.3 + diff --git a/SOURCES/0048-views-properly-override-group-member-names.patch b/SOURCES/0048-views-properly-override-group-member-names.patch deleted file mode 100644 index c86debf..0000000 --- a/SOURCES/0048-views-properly-override-group-member-names.patch +++ /dev/null @@ -1,455 +0,0 @@ -From 11f6fcedb0ac04528dd319fcf95d1fbaa4ea8bd1 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 7 Jul 2016 18:54:02 +0200 -Subject: [PATCH 48/62] views: properly override group member names - -Resolves https://fedorahosted.org/sssd/ticket/2948 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 1594701fbdc341069e11cff9a85e7a795e52db3d) ---- - src/db/sysdb.h | 3 +- - src/db/sysdb_search.c | 99 ++++++++++++++++------------- - src/db/sysdb_views.c | 136 ++++++++++++++++++---------------------- - src/responder/nss/nsssrv_cmd.c | 7 ++- - src/tests/cmocka/test_nss_srv.c | 18 +++--- - 5 files changed, 134 insertions(+), 129 deletions(-) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 405f89e2f1ac6fabc06e77c345de8693845f9d92..a27552224bb40bd07c7dee4dfe35bfb7a0b4f2c3 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -572,7 +572,8 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain, - const char **req_attrs); - - errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain, -- struct ldb_message *obj); -+ struct ldb_message *obj, -+ bool expect_override_dn); - - errno_t sysdb_getpwnam_with_views(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, -diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c -index e40b36c38e28992e185447497d1bf69cabc09821..cfee5784dbadd692f30d0758e7e5c3c9fb2814cb 100644 ---- a/src/db/sysdb_search.c -+++ b/src/db/sysdb_search.c -@@ -771,28 +771,33 @@ int sysdb_getgrnam_with_views(TALLOC_CTX *mem_ctx, - - /* If there are views we have to check if override values must be added to - * the original object. */ -- if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) { -- if (!is_local_view(domain->view_name)) { -- el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST); -- if (el != NULL && el->num_values != 0) { -- DEBUG(SSSDBG_TRACE_ALL, "Group object [%s], contains ghost " -- "entries which must be resolved before overrides can be " -- "applied.\n", -- ldb_dn_get_linearized(orig_obj->msgs[0]->dn)); -- ret = ENOENT; -+ if (orig_obj->count == 1) { -+ if (DOM_HAS_VIEWS(domain)) { -+ if (!is_local_view(domain->view_name)) { -+ el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST); -+ if (el != NULL && el->num_values != 0) { -+ DEBUG(SSSDBG_TRACE_ALL, "Group object [%s], contains ghost " -+ "entries which must be resolved before overrides can be " -+ "applied.\n", -+ ldb_dn_get_linearized(orig_obj->msgs[0]->dn)); -+ ret = ENOENT; -+ goto done; -+ } -+ } -+ -+ ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0], -+ override_obj == NULL ? NULL : override_obj ->msgs[0], -+ NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n"); - goto done; - } - } - -- ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0], -- override_obj == NULL ? NULL : override_obj ->msgs[0], -- NULL); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n"); -- goto done; -- } -- -- ret = sysdb_add_group_member_overrides(domain, orig_obj->msgs[0]); -+ /* Must be called even without views to check to -+ * SYSDB_DEFAULT_OVERRIDE_NAME */ -+ ret = sysdb_add_group_member_overrides(domain, orig_obj->msgs[0], -+ DOM_HAS_VIEWS(domain)); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "sysdb_add_group_member_overrides failed.\n"); -@@ -922,28 +927,33 @@ int sysdb_getgrgid_with_views(TALLOC_CTX *mem_ctx, - - /* If there are views we have to check if override values must be added to - * the original object. */ -- if (DOM_HAS_VIEWS(domain) && orig_obj->count == 1) { -- if (!is_local_view(domain->view_name)) { -- el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST); -- if (el != NULL && el->num_values != 0) { -- DEBUG(SSSDBG_TRACE_ALL, "Group object [%s], contains ghost " -- "entries which must be resolved before overrides can be " -- "applied.\n", -- ldb_dn_get_linearized(orig_obj->msgs[0]->dn)); -- ret = ENOENT; -+ if (orig_obj->count == 1) { -+ if (DOM_HAS_VIEWS(domain)) { -+ if (!is_local_view(domain->view_name)) { -+ el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_GHOST); -+ if (el != NULL && el->num_values != 0) { -+ DEBUG(SSSDBG_TRACE_ALL, "Group object [%s], contains ghost " -+ "entries which must be resolved before overrides can be " -+ "applied.\n", -+ ldb_dn_get_linearized(orig_obj->msgs[0]->dn)); -+ ret = ENOENT; -+ goto done; -+ } -+ } -+ -+ ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0], -+ override_obj == NULL ? NULL : override_obj ->msgs[0], -+ NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n"); - goto done; - } - } - -- ret = sysdb_add_overrides_to_object(domain, orig_obj->msgs[0], -- override_obj == NULL ? NULL : override_obj ->msgs[0], -- NULL); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n"); -- goto done; -- } -- -- ret = sysdb_add_group_member_overrides(domain, orig_obj->msgs[0]); -+ /* Must be called even without views to check to -+ * SYSDB_DEFAULT_OVERRIDE_NAME */ -+ ret = sysdb_add_group_member_overrides(domain, orig_obj->msgs[0], -+ DOM_HAS_VIEWS(domain)); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "sysdb_add_group_member_overrides failed.\n"); -@@ -1157,8 +1167,8 @@ int sysdb_enumgrent_filter_with_views(TALLOC_CTX *mem_ctx, - goto done; - } - -- if (DOM_HAS_VIEWS(domain)) { -- for (c = 0; c < res->count; c++) { -+ for (c = 0; c < res->count; c++) { -+ if (DOM_HAS_VIEWS(domain)) { - ret = sysdb_add_overrides_to_object(domain, res->msgs[c], NULL, - NULL); - /* enumeration assumes that the cache is up-to-date, hence we do not -@@ -1167,13 +1177,14 @@ int sysdb_enumgrent_filter_with_views(TALLOC_CTX *mem_ctx, - DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_overrides_to_object failed.\n"); - goto done; - } -+ } - -- ret = sysdb_add_group_member_overrides(domain, res->msgs[c]); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "sysdb_add_group_member_overrides failed.\n"); -- goto done; -- } -+ ret = sysdb_add_group_member_overrides(domain, res->msgs[c], -+ DOM_HAS_VIEWS(domain)); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_add_group_member_overrides failed.\n"); -+ goto done; - } - } - -diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c -index 2b89e5ca41f719e1217ef3b9e0fd683656e05d42..79f513d13ba41212a6cd84e1d9e609df6acba29c 100644 ---- a/src/db/sysdb_views.c -+++ b/src/db/sysdb_views.c -@@ -1348,14 +1348,13 @@ done: - } - - errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain, -- struct ldb_message *obj) -+ struct ldb_message *obj, -+ bool expect_override_dn) - { - int ret; - size_t c; -- struct ldb_message_element *members; -+ struct ldb_result *res_members; - TALLOC_CTX *tmp_ctx; -- struct ldb_dn *member_dn; -- struct ldb_result *member_obj; - struct ldb_result *override_obj; - static const char *member_attrs[] = SYSDB_PW_ATTRS; - const char *override_dn_str; -@@ -1366,12 +1365,6 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain, - char *val; - struct sss_domain_info *orig_dom; - -- members = ldb_msg_find_element(obj, SYSDB_MEMBER); -- if (members == NULL || members->num_values == 0) { -- DEBUG(SSSDBG_TRACE_ALL, "Group has no members.\n"); -- return EOK; -- } -- - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); -@@ -1379,38 +1372,30 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain, - goto done; - } - -- for (c = 0; c < members->num_values; c++) { -- member_dn = ldb_dn_from_ldb_val(tmp_ctx, domain->sysdb->ldb, -- &members->values[c]); -- if (member_dn == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_from_ldb_val failed.\n"); -- ret = ENOMEM; -- goto done; -- } -+ ret = sysdb_get_user_members_recursively(tmp_ctx, domain, obj->dn, -+ &res_members); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_get_user_members_recursively failed.\n"); -+ goto done; -+ } - -- ret = ldb_search(domain->sysdb->ldb, member_dn, &member_obj, member_dn, -- LDB_SCOPE_BASE, member_attrs, NULL); -- if (ret != LDB_SUCCESS) { -- ret = sysdb_error_to_errno(ret); -- goto done; -- } -+ for (c = 0; c < res_members->count; c++) { - -- if (member_obj->count != 1) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Base search for member object returned [%d] results.\n", -- member_obj->count); -- ret = EINVAL; -- goto done; -- } -- -- if (ldb_msg_find_attr_as_uint64(member_obj->msgs[0], -+ if (ldb_msg_find_attr_as_uint64(res_members->msgs[c], - SYSDB_UIDNUM, 0) == 0) { - /* Skip non-POSIX-user members i.e. groups and non-POSIX users */ - continue; - } - -- override_dn_str = ldb_msg_find_attr_as_string(member_obj->msgs[0], -- SYSDB_OVERRIDE_DN, NULL); -+ if (expect_override_dn) { -+ override_dn_str = ldb_msg_find_attr_as_string(res_members->msgs[c], -+ SYSDB_OVERRIDE_DN, -+ NULL); -+ } else { -+ override_dn_str = ldb_dn_get_linearized(res_members->msgs[c]->dn); -+ } -+ - if (override_dn_str == NULL) { - if (is_local_view(domain->view_name)) { - /* LOCAL view doesn't have to have overrideDN specified. */ -@@ -1420,12 +1405,12 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain, - - DEBUG(SSSDBG_CRIT_FAILURE, - "Missing override DN for object [%s].\n", -- ldb_dn_get_linearized(member_obj->msgs[0]->dn)); -+ ldb_dn_get_linearized(res_members->msgs[c]->dn)); - ret = ENOENT; - goto done; - } - -- override_dn = ldb_dn_new(member_obj, domain->sysdb->ldb, -+ override_dn = ldb_dn_new(res_members, domain->sysdb->ldb, - override_dn_str); - if (override_dn == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n"); -@@ -1433,22 +1418,27 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain, - goto done; - } - -- orig_name = ldb_msg_find_attr_as_string(member_obj->msgs[0], -+ orig_name = ldb_msg_find_attr_as_string(res_members->msgs[c], - SYSDB_NAME, - NULL); - if (orig_name == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Object [%s] has no name.\n", -- ldb_dn_get_linearized(member_obj->msgs[0]->dn)); -+ ldb_dn_get_linearized(res_members->msgs[c]->dn)); - ret = EINVAL; - goto done; - } - -- memberuid = NULL; -- if (ldb_dn_compare(member_obj->msgs[0]->dn, override_dn) != 0) { -+ /* start with default view name, if it exists or use NULL */ -+ memberuid = ldb_msg_find_attr_as_string(res_members->msgs[c], -+ SYSDB_DEFAULT_OVERRIDE_NAME, -+ NULL); -+ -+ /* If there is an override object, check if the name is overridden */ -+ if (ldb_dn_compare(res_members->msgs[c]->dn, override_dn) != 0) { - DEBUG(SSSDBG_TRACE_ALL, "Checking override for object [%s].\n", -- ldb_dn_get_linearized(member_obj->msgs[0]->dn)); -+ ldb_dn_get_linearized(res_members->msgs[c]->dn)); - -- ret = ldb_search(domain->sysdb->ldb, member_obj, &override_obj, -+ ret = ldb_search(domain->sysdb->ldb, res_members, &override_obj, - override_dn, LDB_SCOPE_BASE, member_attrs, NULL); - if (ret != LDB_SUCCESS) { - ret = sysdb_error_to_errno(ret); -@@ -1458,43 +1448,44 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain, - if (override_obj->count != 1) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Base search for override object returned [%d] results.\n", -- member_obj->count); -+ override_obj->count); - ret = EINVAL; - goto done; - } - - memberuid = ldb_msg_find_attr_as_string(override_obj->msgs[0], - SYSDB_NAME, -- NULL); -+ memberuid); -+ } - -- if (memberuid != NULL) { -- ret = sss_parse_internal_fqname(tmp_ctx, orig_name, -- NULL, &orig_domain); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "sss_parse_internal_fqname failed to split [%s].\n", -- orig_name); -+ /* add domain name if memberuid is a short name */ -+ if (memberuid != NULL && strchr(memberuid, '@') == NULL) { -+ ret = sss_parse_internal_fqname(tmp_ctx, orig_name, -+ NULL, &orig_domain); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sss_parse_internal_fqname failed to split [%s].\n", -+ orig_name); -+ goto done; -+ } -+ -+ if (orig_domain != NULL) { -+ orig_dom = find_domain_by_name(get_domains_head(domain), -+ orig_domain, true); -+ if (orig_dom == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot find domain with name [%s].\n", -+ orig_domain); -+ ret = ERR_DOMAIN_NOT_FOUND; - goto done; - } -- -- if (orig_domain != NULL) { -- orig_dom = find_domain_by_name(get_domains_head(domain), -- orig_domain, true); -- if (orig_dom == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Cannot find domain with name [%s].\n", -- orig_domain); -- ret = ERR_DOMAIN_NOT_FOUND; -- goto done; -- } -- memberuid = sss_create_internal_fqname(tmp_ctx, memberuid, -- orig_dom->name); -- if (memberuid == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, -- "sss_create_internal_fqname failed.\n"); -- ret = ENOMEM; -- goto done; -- } -+ memberuid = sss_create_internal_fqname(tmp_ctx, memberuid, -+ orig_dom->name); -+ if (memberuid == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sss_create_internal_fqname failed.\n"); -+ ret = ENOMEM; -+ goto done; - } - } - } -@@ -1521,9 +1512,6 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain, - DEBUG(SSSDBG_TRACE_ALL, "Added [%s] to [%s].\n", memberuid, - OVERRIDE_PREFIX SYSDB_MEMBERUID); - -- /* Free all temporary data of the current member to avoid memory usage -- * spikes. All temporary data should be allocated below member_dn. */ -- talloc_free(member_dn); - } - - ret = EOK; -diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c -index 1ae17969688fa29734ca14fd2b152decef1fdbca..4e84b3202cbf367e70a47a3c7edb06e357657538 100644 ---- a/src/responder/nss/nsssrv_cmd.c -+++ b/src/responder/nss/nsssrv_cmd.c -@@ -2976,7 +2976,12 @@ static int fill_grent(struct sss_packet *packet, - - memnum = 0; - if (!dom->ignore_group_members) { -- el = sss_view_ldb_msg_find_element(dom, msg, SYSDB_MEMBERUID); -+ /* unconditionally prefer OVERRIDE_PREFIX SYSDB_MEMBERUID, it -+ * might contain override names from the default view */ -+ el = ldb_msg_find_element(msg, OVERRIDE_PREFIX SYSDB_MEMBERUID); -+ if (el == NULL) { -+ el = ldb_msg_find_element(msg, SYSDB_MEMBERUID); -+ } - if (el) { - ret = fill_members(packet, nctx->rctx, dom, nctx, el, - &rzero, &rsize, &memnum); -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index 82a304feed864b09168d0f3e06a4e1bb120df7e4..41425e76f3b76fafa917f33fcfef0946f2f71c7d 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -1619,11 +1619,11 @@ 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] = testmember1.pw_name; -- exp_members[1] = testmember2.pw_name; -- exp_members[2] = sss_tc_fqname(tmp_ctx, nss_test_ctx->subdom->names, -+ 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[2]); -+ assert_non_null(exp_members[0]); -+ exp_members[1] = testmember1.pw_name; -+ exp_members[2] = testmember2.pw_name; - - assert_int_equal(status, EOK); - -@@ -1682,14 +1682,14 @@ 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->tctx->dom->names, -- nss_test_ctx->tctx->dom, testmember1.pw_name); -+ 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, testmember2.pw_name); -+ 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->subdom->names, -- nss_test_ctx->subdom, submember1.pw_name); -+ 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, --- -2.4.11 - diff --git a/SOURCES/0049-IPA-fix-lookup-by-UPN-for-subdomains.patch b/SOURCES/0049-IPA-fix-lookup-by-UPN-for-subdomains.patch deleted file mode 100644 index abd98c4..0000000 --- a/SOURCES/0049-IPA-fix-lookup-by-UPN-for-subdomains.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 196e4a16c32e2f5d7e63f2dacd4f3cf4128f6814 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 22 Jul 2016 17:35:43 +0200 -Subject: [PATCH 49/62] IPA: fix lookup by UPN for subdomains - -Currently the user name used in the extdom exop request is -unconditionally set to the short name. While this is correct for the -general name based lookups it breaks UPN/email based lookups where the -name part after the @-sign might not match to domain name. I guess this -was introduce during the sysdb refactoring. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 530458a4ef7cd8429d1db2f3dfae92d9c44e38ef) ---- - src/providers/ipa/ipa_subdomains_id.c | 16 ++++++++++++---- - 1 file changed, 12 insertions(+), 4 deletions(-) - -diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c -index 542c596a983bcb48f4eac699f78eb956326cefa2..002857699b65c86a6ed0c912a2a7ae06a8f9e507 100644 ---- a/src/providers/ipa/ipa_subdomains_id.c -+++ b/src/providers/ipa/ipa_subdomains_id.c -@@ -344,6 +344,7 @@ struct ipa_get_subdom_acct { - int entry_type; - const char *filter; - int filter_type; -+ const char *extra_value; - bool use_pac; - struct ldb_message *user_msg; - -@@ -393,6 +394,7 @@ struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx, - state->entry_type = (ar->entry_type & BE_REQ_TYPE_MASK); - state->filter = ar->filter_value; - state->filter_type = ar->filter_type; -+ state->extra_value = ar->extra_value; - - switch (state->entry_type) { - case BE_REQ_USER: -@@ -499,10 +501,16 @@ static void ipa_get_subdom_acct_connected(struct tevent_req *subreq) - switch (state->filter_type) { - case BE_FILTER_NAME: - req_input->type = REQ_INP_NAME; -- /* The extdom plugin expects the shortname and domain separately */ -- ret = sss_parse_internal_fqname(req_input, state->filter, -- &shortname, NULL); -- req_input->inp.name = talloc_steal(req_input, shortname); -+ /* The extdom plugin expects the shortname and domain separately, -+ * but for UPN/email lookup we need to send the raw name */ -+ if (state->extra_value != NULL -+ && strcmp(state->extra_value, EXTRA_NAME_IS_UPN) == 0) { -+ req_input->inp.name = talloc_strdup(req_input, state->filter); -+ } else { -+ ret = sss_parse_internal_fqname(req_input, state->filter, -+ &shortname, NULL); -+ req_input->inp.name = talloc_steal(req_input, shortname); -+ } - if (req_input->inp.name == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); - tevent_req_error(req, ENOMEM); --- -2.4.11 - diff --git a/SOURCES/0049-IPA_SUBDOMAINS-Rename-_refresh_view-to-_refresh_view.patch b/SOURCES/0049-IPA_SUBDOMAINS-Rename-_refresh_view-to-_refresh_view.patch new file mode 100644 index 0000000..71624c8 --- /dev/null +++ b/SOURCES/0049-IPA_SUBDOMAINS-Rename-_refresh_view-to-_refresh_view.patch @@ -0,0 +1,54 @@ +From 33190863b66f90cac410b7a9b9cc95e4f9891013 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Fri, 24 Mar 2017 08:08:58 +0100 +Subject: [PATCH 49/54] IPA_SUBDOMAINS: Rename _refresh_view() to + _refresh_view_name() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This method got renamed in order to match better with what it does +currently. + +Related: +https://pagure.io/SSSD/sssd/issue/3001 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + src/providers/ipa/ipa_subdomains.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index 01a0ce812d861b24565d2f71f27d6b8ceb2965bc..bf6f6ab1fa8bfff7ea102dd219c9ddbbab065b2b 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -1808,7 +1808,7 @@ static void ipa_subdomains_refresh_ranges_done(struct tevent_req *subreq); + static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq); + static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq); + static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq); +-static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq); ++static void ipa_subdomains_refresh_view_name_done(struct tevent_req *subreq); + static void ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq); + + static struct tevent_req * +@@ -2023,11 +2023,12 @@ static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq) + return; + } + +- tevent_req_set_callback(subreq, ipa_subdomains_refresh_view_done, req); ++ tevent_req_set_callback(subreq, ipa_subdomains_refresh_view_name_done, ++ req); + return; + } + +-static void ipa_subdomains_refresh_view_done(struct tevent_req *subreq) ++static void ipa_subdomains_refresh_view_name_done(struct tevent_req *subreq) + { + struct ipa_subdomains_refresh_state *state; + struct tevent_req *req; +-- +2.9.3 + diff --git a/SOURCES/0050-IPA-Get-ipaDomainsResolutionOrder-from-IPA-ID-View.patch b/SOURCES/0050-IPA-Get-ipaDomainsResolutionOrder-from-IPA-ID-View.patch new file mode 100644 index 0000000..a1da431 --- /dev/null +++ b/SOURCES/0050-IPA-Get-ipaDomainsResolutionOrder-from-IPA-ID-View.patch @@ -0,0 +1,347 @@ +From d36c2acde1f29865c2cefedebc214ba48bb227e7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Fri, 24 Mar 2017 17:46:04 +0100 +Subject: [PATCH 50/54] IPA: Get ipaDomainsResolutionOrder from IPA ID View +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +ipaDomainsResolutionOrder provides a list of domains that have to be +looked up firstly during cache_req searches. + +This commit only fetches this list from the server and stores its value +at sysdb so we can make use of it later on this patch series. + +There are no tests for newly introduced sysdb methods are those are +basically only calling sysdb_update_domain_resolution_order(), +sysdb_get_domain_resolution_order() and +sysdb_get_use_domain_resolution_order() which are have tests written +for. + +Related: +https://pagure.io/SSSD/sssd/issue/3001 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + src/db/sysdb.h | 9 ++ + src/db/sysdb_views.c | 66 ++++++++++++++ + src/providers/ipa/ipa_subdomains.c | 182 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 257 insertions(+) + +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 75a07d4d2effb028ec654342113f8478e1eba10e..62c561be9452a284a8ddf8ebb45720265852c8b0 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -533,6 +533,15 @@ errno_t sysdb_update_view_name(struct sysdb_ctx *sysdb, const char *view_name); + errno_t sysdb_get_view_name(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, + char **view_name); + ++errno_t sysdb_update_view_domain_resolution_order( ++ struct sysdb_ctx *sysdb, ++ const char *domain_resolution_order); ++ ++errno_t sysdb_get_view_domain_resolution_order( ++ TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ const char **_domain_resolution_order); ++ + static inline bool is_default_view(const char *view_name) + { + /* NULL is treated as default */ +diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c +index 1c416dd14049237e9f35d52f154035e3ff861469..20db9b06183d68b33bb19f498513d7f5cf84b1cf 100644 +--- a/src/db/sysdb_views.c ++++ b/src/db/sysdb_views.c +@@ -22,6 +22,9 @@ + #include "util/util.h" + #include "util/cert.h" + #include "db/sysdb_private.h" ++#include "db/sysdb_domain_resolution_order.h" ++ ++#define SYSDB_VIEWS_BASE "cn=views,cn=sysdb" + + /* In general is should not be possible that there is a view container without + * a view name set. But to be on the safe side we return both information +@@ -179,6 +182,69 @@ done: + return ret; + } + ++errno_t ++sysdb_get_view_domain_resolution_order(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ const char **_domain_resolution_order) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_dn *dn; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_VIEWS_BASE); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_get_domain_resolution_order(mem_ctx, sysdb, dn, ++ _domain_resolution_order); ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++errno_t ++sysdb_update_view_domain_resolution_order(struct sysdb_ctx *sysdb, ++ const char *domain_resolution_order) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_dn *dn; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_VIEWS_BASE); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_update_domain_resolution_order(sysdb, dn, ++ domain_resolution_order); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_update_domain_resolution_order() failed [%d]: [%s].\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + errno_t sysdb_delete_view_tree(struct sysdb_ctx *sysdb, const char *view_name) + { + struct ldb_dn *dn; +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index bf6f6ab1fa8bfff7ea102dd219c9ddbbab065b2b..ef348adf4a36e870f44387bd700f5c2beea3bfd6 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -1684,6 +1684,151 @@ static errno_t ipa_subdomains_view_name_recv(struct tevent_req *req) + return EOK; + } + ++struct ipa_subdomains_view_domain_resolution_order_state { ++ struct sss_domain_info *domain; ++ const char *view_name; ++}; ++ ++static void ++ipa_subdomains_view_domain_resolution_order_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++ipa_subdomains_view_domain_resolution_order_send( ++ TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ipa_subdomains_ctx *sd_ctx, ++ struct sdap_handle *sh) ++{ ++ struct ipa_subdomains_view_domain_resolution_order_state *state; ++ struct tevent_req *subreq; ++ struct tevent_req *req; ++ const char *attrs[] = { IPA_DOMAIN_RESOLUTION_ORDER, NULL }; ++ char *ldap_basedn; ++ char *base; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct ipa_subdomains_view_domain_resolution_order_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ state->domain = sd_ctx->be_ctx->domain; ++ state->view_name = sd_ctx->ipa_id_ctx->view_name; ++ ++ ret = domain_to_basedn(state, sd_ctx->be_ctx->domain->name, &ldap_basedn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "domain_to_basedn failed.\n"); ++ goto immediately; ++ } ++ ++ base = talloc_asprintf(state, "cn=%s,cn=views,cn=accounts,%s", ++ sd_ctx->ipa_id_ctx->view_name, ldap_basedn); ++ if (base == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ subreq = sdap_get_generic_send( ++ state, ev, sd_ctx->sdap_id_ctx->opts, sh, ++ base, LDAP_SCOPE_BASE, NULL, attrs, NULL, 0, ++ dp_opt_get_int(sd_ctx->sdap_id_ctx->opts->basic, ++ SDAP_ENUM_SEARCH_TIMEOUT), ++ false); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_subdomains_view_domain_resolution_order_done, ++ req); ++ ++ return req; ++ ++immediately: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ ++ return req; ++} ++ ++static void ++ipa_subdomains_view_domain_resolution_order_done(struct tevent_req *subreq) ++{ ++ struct ipa_subdomains_view_domain_resolution_order_state *state; ++ struct tevent_req *req; ++ size_t reply_count; ++ struct sysdb_attrs **reply; ++ const char *domain_resolution_order; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, ++ struct ipa_subdomains_view_domain_resolution_order_state); ++ ++ ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to get view name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ if (reply_count > 1) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "More than one object returned.\n"); ++ ret = EINVAL; ++ goto done; ++ } else if (reply_count == 0) { ++ domain_resolution_order = NULL; ++ } else { ++ /* reply_count == 1 */ ++ ret = sysdb_attrs_get_string(reply[0], IPA_DOMAIN_RESOLUTION_ORDER, ++ &domain_resolution_order); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to get the view domains' resolution order " ++ "configuration value for view [%s] [%d]: %s\n", ++ state->view_name, ret, sss_strerror(ret)); ++ goto done; ++ } else if (ret == ENOENT) { ++ domain_resolution_order = NULL; ++ } ++ } ++ ++ ret = sysdb_update_view_domain_resolution_order(state->domain->sysdb, ++ domain_resolution_order); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_update_view_domain_resolution_order() [%d]: [%s].\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++static errno_t ++ipa_subdomains_view_domain_resolution_order_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} ++ + struct ipa_domain_resolution_order_state { + struct sss_domain_info *domain; + }; +@@ -1809,6 +1954,8 @@ static void ipa_subdomains_refresh_certmap_done(struct tevent_req *subreq); + static void ipa_subdomains_refresh_master_done(struct tevent_req *subreq); + static void ipa_subdomains_refresh_slave_done(struct tevent_req *subreq); + static void ipa_subdomains_refresh_view_name_done(struct tevent_req *subreq); ++static void ipa_subdomains_refresh_view_domain_resolution_order_done( ++ struct tevent_req *subreq); + static void ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq); + + static struct tevent_req * +@@ -2047,6 +2194,41 @@ static void ipa_subdomains_refresh_view_name_done(struct tevent_req *subreq) + return; + } + ++ subreq = ipa_subdomains_view_domain_resolution_order_send( ++ state, ++ state->ev, ++ state->sd_ctx, ++ sdap_id_op_handle(state->sdap_op)); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ tevent_req_set_callback(subreq, ++ ipa_subdomains_refresh_view_domain_resolution_order_done, ++ req); ++} ++ ++static void ++ipa_subdomains_refresh_view_domain_resolution_order_done(struct tevent_req *subreq) ++{ ++ struct ipa_subdomains_refresh_state *state; ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_subdomains_refresh_state); ++ ++ ret = ipa_subdomains_view_domain_resolution_order_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unable to get view domain_resolution order [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ + subreq = ipa_domain_resolution_order_send(state, state->ev, state->sd_ctx, + sdap_id_op_handle(state->sdap_op)); + if (subreq == NULL) { +-- +2.9.3 + diff --git a/SOURCES/0050-LDAP-allow-multiple-user-principals.patch b/SOURCES/0050-LDAP-allow-multiple-user-principals.patch deleted file mode 100644 index de62b4a..0000000 --- a/SOURCES/0050-LDAP-allow-multiple-user-principals.patch +++ /dev/null @@ -1,70 +0,0 @@ -From f1eb45c3e8a198615c6731dfe9d965ab421723e8 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 22 Jul 2016 12:19:26 +0200 -Subject: [PATCH 50/62] LDAP: allow multiple user principals - -In general a user can have multiple principals and recent IPA version -added support to defined multiple principals. With this patch SSSD does -not only store the first but all principals read by LDAP from a server. - -Resolves https://fedorahosted.org/sssd/ticket/2958 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 0d5d490fb5ec685fd8ef7a75e612e6ec7ef6bde3) ---- - src/providers/ldap/sdap_async_users.c | 32 ++++++++++++++++++-------------- - 1 file changed, 18 insertions(+), 14 deletions(-) - -diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c -index e44c045b3f8ff6aed33a42cf2919bc01aa41a243..28101a2d8a38f97d09d50a9f7e071a030b4f9719 100644 ---- a/src/providers/ldap/sdap_async_users.c -+++ b/src/providers/ldap/sdap_async_users.c -@@ -142,6 +142,7 @@ int sdap_save_user(TALLOC_CTX *memctx, - char *sid_str; - char *dom_sid_str = NULL; - struct sss_domain_info *subdomain; -+ size_t c; - - DEBUG(SSSDBG_TRACE_FUNC, "Save user\n"); - -@@ -440,20 +441,23 @@ int sdap_save_user(TALLOC_CTX *memctx, - DEBUG(SSSDBG_TRACE_FUNC, - "User principal is not available for [%s].\n", user_name); - } else { -- upn = talloc_strdup(user_attrs, (const char*) el->values[0].data); -- if (!upn) { -- ret = ENOMEM; -- goto done; -- } -- if (dp_opt_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) { -- make_realm_upper_case(upn); -- } -- DEBUG(SSSDBG_TRACE_FUNC, -- "Adding user principal [%s] to attributes of [%s].\n", -- upn, user_name); -- ret = sysdb_attrs_add_string(user_attrs, SYSDB_UPN, upn); -- if (ret) { -- goto done; -+ for (c = 0; c < el->num_values; c++) { -+ upn = talloc_strdup(tmpctx, (const char*) el->values[c].data); -+ if (!upn) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ if (dp_opt_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) { -+ make_realm_upper_case(upn); -+ } -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Adding user principal [%s] to attributes of [%s].\n", -+ upn, user_name); -+ ret = sysdb_attrs_add_string(user_attrs, SYSDB_UPN, upn); -+ if (ret) { -+ goto done; -+ } - } - } - --- -2.4.11 - diff --git a/SOURCES/0051-DLINKLIST-Add-DLIST_FOR_EACH_SAFE-macro.patch b/SOURCES/0051-DLINKLIST-Add-DLIST_FOR_EACH_SAFE-macro.patch new file mode 100644 index 0000000..b75b73d --- /dev/null +++ b/SOURCES/0051-DLINKLIST-Add-DLIST_FOR_EACH_SAFE-macro.patch @@ -0,0 +1,37 @@ +From 8c7c97d1b3af8c99af43dcaff7ae1d9315a03835 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 21 Mar 2017 20:56:38 +0100 +Subject: [PATCH 51/54] DLINKLIST: Add DLIST_FOR_EACH_SAFE macro +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This macro, as DLIST_FOR_EACH, iterates over the whole list. The main +difference between both is that in the _SAFE version the pointer to the +next list node is stored, allowing us to delete the current node safely. + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + src/util/dlinklist.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/util/dlinklist.h b/src/util/dlinklist.h +index 4f6aef830e914c22654970081263d43461c1750f..017c60468e66dbec15724d5f4832da412f42136b 100644 +--- a/src/util/dlinklist.h ++++ b/src/util/dlinklist.h +@@ -147,4 +147,9 @@ do { \ + #define DLIST_FOR_EACH(p, list) \ + for ((p) = (list); (p) != NULL; (p) = (p)->next) + ++#define DLIST_FOR_EACH_SAFE(p, q, list) \ ++ for ((p) = (list), (q) = (p) != NULL ? (p)->next : NULL; \ ++ (p) != NULL; \ ++ (p) = (q), (q) = (p) != NULL ? (p)->next : NULL) ++ + #endif /* _DLINKLIST_H */ +-- +2.9.3 + diff --git a/SOURCES/0051-LDAP-new-attribute-option-ldap_user_email.patch b/SOURCES/0051-LDAP-new-attribute-option-ldap_user_email.patch deleted file mode 100644 index 85b5898..0000000 --- a/SOURCES/0051-LDAP-new-attribute-option-ldap_user_email.patch +++ /dev/null @@ -1,171 +0,0 @@ -From 03d7bda082c8719bfb4ea63c9126442c98a27be1 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Sat, 18 Jun 2016 18:24:50 +0200 -Subject: [PATCH 51/62] LDAP: new attribute option ldap_user_email - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 83a796ec8de4bde65b11cc8032675406950641fa) ---- - src/config/SSSDConfig/__init__.py.in | 1 + - src/config/etc/sssd.api.d/sssd-ad.conf | 1 + - src/config/etc/sssd.api.d/sssd-ipa.conf | 1 + - src/config/etc/sssd.api.d/sssd-ldap.conf | 1 + - src/db/sysdb.h | 1 + - src/man/sssd-ldap.5.xml | 13 +++++++++++++ - src/providers/ad/ad_opts.c | 1 + - src/providers/ipa/ipa_opts.c | 1 + - src/providers/ldap/ldap_opts.c | 3 +++ - src/providers/ldap/sdap.h | 1 + - 10 files changed, 24 insertions(+) - -diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in -index b5e078d0118a15c10b43fbe050176943ec90e0ee..7856c4c6b2d675b7f7f0f5f2048086044e8fb5ea 100644 ---- a/src/config/SSSDConfig/__init__.py.in -+++ b/src/config/SSSDConfig/__init__.py.in -@@ -325,6 +325,7 @@ option_strings = { - 'ldap_user_ssh_public_key' : _('SSH public key attribute'), - 'ldap_user_auth_type' : _('attribute listing allowed authentication types for a user'), - 'ldap_user_certificate' : _('attribute containing the X509 certificate of the user'), -+ 'ldap_user_email' : _('attribute containing the email address of the user'), - - 'ldap_user_extra_attrs' : _('A list of extra attributes to download along with the user entry'), - -diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf -index 23006d26ca6fe7ca2b912ef091b4c73d5d23bee1..87a74f4af0770874c71baaea02d2313721db78bf 100644 ---- a/src/config/etc/sssd.api.d/sssd-ad.conf -+++ b/src/config/etc/sssd.api.d/sssd-ad.conf -@@ -98,6 +98,7 @@ ldap_pwd_attribute = str, None, false - ldap_user_ssh_public_key = str, None, false - ldap_user_auth_type = str, None, false - ldap_user_certificate = str, None, false -+ldap_user_email = str, None, false - ldap_group_search_base = str, None, false - ldap_group_search_scope = str, None, false - ldap_group_search_filter = str, None, false -diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf -index 67a46102b4e8dfff2b44b21ac18c0ad8822d7f3a..88da36ef4a0a067530dfd44b7a231f4f74c800f2 100644 ---- a/src/config/etc/sssd.api.d/sssd-ipa.conf -+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf -@@ -92,6 +92,7 @@ ldap_pwd_attribute = str, None, false - ldap_user_ssh_public_key = str, None, false - ldap_user_auth_type = str, None, false - ldap_user_certificate = str, None, false -+ldap_user_email = str, None, false - ldap_group_search_base = str, None, false - ldap_group_search_scope = str, None, false - ldap_group_search_filter = str, None, false -diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf -index 8b52f268af195bc68d45389cda52a0ad0aba1aa3..c2ad3463d26cd73b8146604c8060224449421fe6 100644 ---- a/src/config/etc/sssd.api.d/sssd-ldap.conf -+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf -@@ -86,6 +86,7 @@ ldap_user_nds_login_allowed_time_map = str, None, false - ldap_user_ssh_public_key = str, None, false - ldap_user_auth_type = str, None, false - ldap_user_certificate = str, None, false -+ldap_user_email = str, None, false - ldap_group_search_base = str, None, false - ldap_group_search_scope = str, None, false - ldap_group_search_filter = str, None, false -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index a27552224bb40bd07c7dee4dfe35bfb7a0b4f2c3..f3952f8a56f1c9f26f2167b64abdf3e9794af17e 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -139,6 +139,7 @@ - - #define SYSDB_AUTH_TYPE "authType" - #define SYSDB_USER_CERT "userCertificate" -+#define SYSDB_USER_EMAIL "mail" - - #define SYSDB_SUBDOMAIN_REALM "realmName" - #define SYSDB_SUBDOMAIN_FLAT "flatName" -diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml -index ce2051d9d3c7df51e26e54abf49e8a20bf5ba3d3..6009dd8dfa787874c085c293b2d1f8aac6d95714 100644 ---- a/src/man/sssd-ldap.5.xml -+++ b/src/man/sssd-ldap.5.xml -@@ -828,6 +828,19 @@ - - - -+ ldap_user_email (string) -+ -+ -+ Name of the LDAP attribute containing the email -+ address of the user. -+ -+ -+ Default: mail -+ -+ -+ -+ -+ - ldap_group_object_class (string) - - -diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c -index 57dfcca6b998083c7cf9ac0bcb142ff7736cc8b9..829f9d9556bc3fa74a95eb76db0e31b19befe8fe 100644 ---- a/src/providers/ad/ad_opts.c -+++ b/src/providers/ad/ad_opts.c -@@ -218,6 +218,7 @@ struct sdap_attr_map ad_2008r2_user_map[] = { - { "ldap_user_ssh_public_key", NULL, SYSDB_SSH_PUBKEY, NULL }, - { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL }, - { "ldap_user_certificate", "userCertificate;binary", SYSDB_USER_CERT, NULL }, -+ { "ldap_user_email", "mail", SYSDB_USER_EMAIL, NULL }, - SDAP_ATTR_MAP_TERMINATOR - }; - -diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c -index a0c318a511693d884f03f0372c592d633ebdcbae..cd3fe9ae4302ff4837a500b9a0c834dadb11f87d 100644 ---- a/src/providers/ipa/ipa_opts.c -+++ b/src/providers/ipa/ipa_opts.c -@@ -204,6 +204,7 @@ struct sdap_attr_map ipa_user_map[] = { - { "ldap_user_ssh_public_key", "ipaSshPubKey", SYSDB_SSH_PUBKEY, NULL }, - { "ldap_user_auth_type", "ipaUserAuthType", SYSDB_AUTH_TYPE, NULL }, - { "ldap_user_certificate", "userCertificate;binary", SYSDB_USER_CERT, NULL }, -+ { "ldap_user_email", "mail", SYSDB_USER_EMAIL, NULL }, - SDAP_ATTR_MAP_TERMINATOR - }; - -diff --git a/src/providers/ldap/ldap_opts.c b/src/providers/ldap/ldap_opts.c -index 524579d4fcd478f20678bebf2c3ce18f61ed0cb9..c6efe332f53c04f3cdc80875d5ca339ad90cb7ee 100644 ---- a/src/providers/ldap/ldap_opts.c -+++ b/src/providers/ldap/ldap_opts.c -@@ -180,6 +180,7 @@ struct sdap_attr_map rfc2307_user_map[] = { - { "ldap_user_ssh_public_key", "sshPublicKey", SYSDB_SSH_PUBKEY, NULL }, - { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL }, - { "ldap_user_certificate", NULL, SYSDB_USER_CERT, NULL }, -+ { "ldap_user_email", "mail", SYSDB_USER_EMAIL, NULL }, - SDAP_ATTR_MAP_TERMINATOR - }; - -@@ -237,6 +238,7 @@ struct sdap_attr_map rfc2307bis_user_map[] = { - { "ldap_user_ssh_public_key", "sshPublicKey", SYSDB_SSH_PUBKEY, NULL }, - { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL }, - { "ldap_user_certificate", NULL, SYSDB_USER_CERT, NULL }, -+ { "ldap_user_email", "mail", SYSDB_USER_EMAIL, NULL }, - SDAP_ATTR_MAP_TERMINATOR - }; - -@@ -294,6 +296,7 @@ struct sdap_attr_map gen_ad2008r2_user_map[] = { - { "ldap_user_ssh_public_key", NULL, SYSDB_SSH_PUBKEY, NULL }, - { "ldap_user_auth_type", NULL, SYSDB_AUTH_TYPE, NULL }, - { "ldap_user_certificate", NULL, SYSDB_USER_CERT, NULL }, -+ { "ldap_user_email", "mail", SYSDB_USER_EMAIL, NULL }, - SDAP_ATTR_MAP_TERMINATOR - }; - -diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h -index 81da1144c657cb71ac860bbe82127a18759e0439..e3cb8464ff40538e1e7f1ba853ed71d9a5cc3c98 100644 ---- a/src/providers/ldap/sdap.h -+++ b/src/providers/ldap/sdap.h -@@ -284,6 +284,7 @@ enum sdap_user_attrs { - SDAP_AT_USER_SSH_PUBLIC_KEY, - SDAP_AT_USER_AUTH_TYPE, - SDAP_AT_USER_CERT, -+ SDAP_AT_USER_EMAIL, - - SDAP_OPTS_USER /* attrs counter */ - }; --- -2.4.11 - diff --git a/SOURCES/0052-CACHE_REQ-Make-use-of-domainResolutionOrder.patch b/SOURCES/0052-CACHE_REQ-Make-use-of-domainResolutionOrder.patch new file mode 100644 index 0000000..4086ace --- /dev/null +++ b/SOURCES/0052-CACHE_REQ-Make-use-of-domainResolutionOrder.patch @@ -0,0 +1,795 @@ +From 5091507c13dfdbde29aa75d6e90eda9ddaa89cff Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Sun, 26 Mar 2017 00:27:50 +0100 +Subject: [PATCH 52/54] CACHE_REQ: Make use of domainResolutionOrder +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +domainResolutionOrder has been introduced in the previous commits and +allows the admin to set up a specific order which the domains will be +resolved during a lookup and with this patch we can take advantage of +this. + +In order to have it working a new structure has been added +(struct domain_resolution_order) to the responder context and will be +used by the cache_req to perform the lookups based on this list. + +As the ipaDomainResolutionOrder may be set globally on IPA or per View, +SSSD does respect the following precedence order: View > Globally. + +The way the list is built is quite simple, basically having the domains +present on ipaDomainResolutionOrder as the first domains (in that +specific order) and then appending the remaining domains to this list. +The final result is a completely flat list with all the domains +respecting the specified order (it's important to remember that the +domains not specified won't follow any specific order, they're just +"random" based on the domains list present in the responder context. + +Related: +https://pagure.io/SSSD/sssd/issue/3001 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + Makefile.am | 3 + + src/responder/common/cache_req/cache_req.c | 89 +++++++----- + src/responder/common/cache_req/cache_req_domain.c | 166 ++++++++++++++++++++++ + src/responder/common/cache_req/cache_req_domain.h | 46 ++++++ + src/responder/common/responder.h | 5 + + src/responder/common/responder_common.c | 153 ++++++++++++++++++++ + src/responder/common/responder_get_domains.c | 14 ++ + src/tests/cmocka/common_mock_resp.c | 6 + + src/tests/cmocka/common_mock_resp_dp.c | 7 + + src/tests/cmocka/test_nss_srv.c | 4 + + src/tests/cwrap/Makefile.am | 1 + + 11 files changed, 457 insertions(+), 37 deletions(-) + create mode 100644 src/responder/common/cache_req/cache_req_domain.c + create mode 100644 src/responder/common/cache_req/cache_req_domain.h + +diff --git a/Makefile.am b/Makefile.am +index 450785bf4c482cce1e1440f1336879150537888e..573b37c52fdeab1add4ea057e1e1844ea4d348a5 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -528,6 +528,7 @@ SSSD_CACHE_REQ_OBJ = \ + src/responder/common/cache_req/cache_req_result.c \ + src/responder/common/cache_req/cache_req_search.c \ + src/responder/common/cache_req/cache_req_data.c \ ++ src/responder/common/cache_req/cache_req_domain.c \ + src/responder/common/cache_req/plugins/cache_req_common.c \ + src/responder/common/cache_req/plugins/cache_req_enum_users.c \ + src/responder/common/cache_req/plugins/cache_req_enum_groups.c \ +@@ -689,6 +690,7 @@ dist_noinst_HEADERS = \ + src/responder/common/iface/responder_iface.h \ + src/responder/common/iface/responder_iface_generated.h \ + src/responder/common/cache_req/cache_req.h \ ++ src/responder/common/cache_req/cache_req_domain.h \ + src/responder/common/cache_req/cache_req_plugin.h \ + src/responder/common/cache_req/cache_req_private.h \ + src/responder/common/data_provider/rdp.h \ +@@ -2199,6 +2201,7 @@ responder_socket_access_tests_SOURCES = \ + src/responder/common/responder_common.c \ + src/responder/common/responder_packet.c \ + src/responder/common/responder_cmd.c \ ++ src/responder/common/cache_req/cache_req_domain.c \ + src/responder/common/data_provider/rdp_message.c \ + src/responder/common/data_provider/rdp_client.c \ + $(SSSD_RESPONDER_IFACE_OBJ) \ +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index aca150d69b398ceb1a52e5cd6a87d35dbc87020b..483126396f8addbad744ae03bfc739801cd0c18b 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -24,6 +24,7 @@ + #include + + #include "util/util.h" ++#include "responder/common/responder.h" + #include "responder/common/cache_req/cache_req_private.h" + #include "responder/common/cache_req/cache_req_plugin.h" + +@@ -316,7 +317,7 @@ struct cache_req_search_domains_state { + struct cache_req *cr; + + /* work data */ +- struct sss_domain_info *domain; ++ struct cache_req_domain *cr_domain; + struct sss_domain_info *selected_domain; + struct cache_req_result **results; + size_t num_results; +@@ -330,13 +331,14 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req); + + static void cache_req_search_domains_done(struct tevent_req *subreq); + +-struct tevent_req *cache_req_search_domains_send(TALLOC_CTX *mem_ctx, +- struct tevent_context *ev, +- struct cache_req *cr, +- struct sss_domain_info *domain, +- bool check_next, +- bool bypass_cache, +- bool bypass_dp) ++struct tevent_req * ++cache_req_search_domains_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct cache_req *cr, ++ struct cache_req_domain *cr_domain, ++ bool check_next, ++ bool bypass_cache, ++ bool bypass_dp) + { + struct tevent_req *req; + struct cache_req_search_domains_state *state = NULL; +@@ -352,7 +354,7 @@ struct tevent_req *cache_req_search_domains_send(TALLOC_CTX *mem_ctx, + state->ev = ev; + state->cr = cr; + +- state->domain = domain; ++ state->cr_domain = cr_domain; + state->check_next = check_next; + state->dp_success = true; + state->bypass_cache = bypass_cache; +@@ -378,6 +380,7 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req) + struct cache_req_search_domains_state *state; + struct tevent_req *subreq; + struct cache_req *cr; ++ struct sss_domain_info *domain; + uint32_t next_domain_flag; + bool is_domain_valid; + bool allow_no_fqn; +@@ -389,11 +392,21 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req) + next_domain_flag = cr->plugin->get_next_domain_flags; + allow_no_fqn = cr->plugin->allow_missing_fqn; + +- while (state->domain != NULL) { ++ while (state->cr_domain != NULL) { ++ domain = state->cr_domain->domain; ++ /* As the cr_domain list is a flatten version of the domains ++ * list, we have to ensure to only go through the subdomains in ++ * case it's specified in the plugin to do so. ++ */ ++ if (next_domain_flag == 0 && IS_SUBDOMAIN(domain)) { ++ state->cr_domain = state->cr_domain->next; ++ continue; ++ } ++ + /* Check if this domain is valid for this request. */ +- is_domain_valid = cache_req_validate_domain(cr, state->domain); ++ is_domain_valid = cache_req_validate_domain(cr, domain); + if (!is_domain_valid) { +- state->domain = get_next_domain(state->domain, next_domain_flag); ++ state->cr_domain = state->cr_domain->next; + continue; + } + +@@ -401,18 +414,18 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req) + * qualified names on domain less search. We do not descend into + * subdomains here since those are implicitly qualified. + */ +- if (state->check_next && !allow_no_fqn && state->domain->fqnames) { +- state->domain = get_next_domain(state->domain, 0); ++ if (state->check_next && !allow_no_fqn && domain->fqnames) { ++ state->cr_domain = state->cr_domain->next; + continue; + } + +- state->selected_domain = state->domain; ++ state->selected_domain = domain; + +- if (state->domain == NULL) { ++ if (domain == NULL) { + break; + } + +- ret = cache_req_set_domain(cr, state->domain); ++ ret = cache_req_set_domain(cr, domain); + if (ret != EOK) { + return ret; + } +@@ -427,8 +440,7 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req) + + /* we will continue with the following domain the next time */ + if (state->check_next) { +- state->domain = get_next_domain(state->domain, +- cr->plugin->get_next_domain_flags); ++ state->cr_domain = state->cr_domain->next; + } + + return EAGAIN; +@@ -625,11 +637,12 @@ static void cache_req_input_parsed(struct tevent_req *subreq); + static errno_t cache_req_select_domains(struct tevent_req *req, + const char *domain_name); + +-static errno_t cache_req_search_domains(struct tevent_req *req, +- struct sss_domain_info *domain, +- bool check_next, +- bool bypass_cache, +- bool bypass_dp); ++static errno_t ++cache_req_search_domains(struct tevent_req *req, ++ struct cache_req_domain *oredered_domain, ++ bool check_next, ++ bool bypass_cache, ++ bool bypass_dp); + + static void cache_req_done(struct tevent_req *subreq); + +@@ -778,7 +791,7 @@ static errno_t cache_req_select_domains(struct tevent_req *req, + const char *domain_name) + { + struct cache_req_state *state = NULL; +- struct sss_domain_info *domain; ++ struct cache_req_domain *cr_domain; + bool check_next; + bool bypass_cache; + bool bypass_dp; +@@ -798,29 +811,30 @@ static errno_t cache_req_select_domains(struct tevent_req *req, + CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, + "Performing a single domain search\n"); + +- domain = responder_get_domain(state->cr->rctx, domain_name); +- if (domain == NULL) { ++ cr_domain = cache_req_domain_get_domain_by_name( ++ state->cr->rctx->cr_domains, domain_name); ++ if (cr_domain == NULL) { + return ERR_DOMAIN_NOT_FOUND; + } +- + check_next = false; + } else { + CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, + "Performing a multi-domain search\n"); + +- domain = state->cr->rctx->domains; ++ cr_domain = state->cr->rctx->cr_domains; + check_next = true; + } + +- return cache_req_search_domains(req, domain, check_next, ++ return cache_req_search_domains(req, cr_domain, check_next, + bypass_cache, bypass_dp); + } + +-static errno_t cache_req_search_domains(struct tevent_req *req, +- struct sss_domain_info *domain, +- bool check_next, +- bool bypass_cache, +- bool bypass_dp) ++static errno_t ++cache_req_search_domains(struct tevent_req *req, ++ struct cache_req_domain *cr_domain, ++ bool check_next, ++ bool bypass_cache, ++ bool bypass_dp) + { + struct tevent_req *subreq; + struct cache_req_state *state = NULL; +@@ -832,8 +846,9 @@ static errno_t cache_req_search_domains(struct tevent_req *req, + bypass_cache ? "bypass" : "check", + bypass_dp ? "bypass" : "check"); + +- subreq = cache_req_search_domains_send(state, state->ev, state->cr, domain, +- check_next, bypass_cache, bypass_dp); ++ subreq = cache_req_search_domains_send(state, state->ev, state->cr, ++ cr_domain, check_next, ++ bypass_cache, bypass_dp); + if (subreq == NULL) { + return ENOMEM; + } +diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c +new file mode 100644 +index 0000000000000000000000000000000000000000..bbabd695f1c6b6c29b7e61f571382ab9adfb0ea2 +--- /dev/null ++++ b/src/responder/common/cache_req/cache_req_domain.c +@@ -0,0 +1,166 @@ ++/* ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++#include "responder/common/cache_req/cache_req_domain.h" ++ ++struct cache_req_domain * ++cache_req_domain_get_domain_by_name(struct cache_req_domain *domains, ++ const char *name) ++{ ++ struct cache_req_domain *dom; ++ struct cache_req_domain *ret = NULL; ++ ++ DLIST_FOR_EACH(dom, domains) { ++ if (sss_domain_get_state(dom->domain) == DOM_DISABLED) { ++ continue; ++ } ++ ++ if (strcasecmp(dom->domain->name, name) == 0 || ++ (dom->domain->flat_name != NULL && ++ strcasecmp(dom->domain->flat_name, name) == 0)) { ++ ret = dom; ++ break; ++ } ++ } ++ ++ if (ret == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unknown domains [%s].\n", name); ++ } ++ ++ return ret; ++} ++ ++void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains) ++{ ++ struct cache_req_domain *p, *q, *r; ++ ++ DLIST_FOR_EACH_SAFE(p, q, *cr_domains) { ++ r = p; ++ DLIST_REMOVE(*cr_domains, p); ++ talloc_zfree(r); ++ } ++ ++ *cr_domains = NULL; ++} ++ ++static struct cache_req_domain * ++cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domains, ++ char **resolution_order) ++{ ++ struct cache_req_domain *cr_domains = NULL; ++ struct cache_req_domain *cr_domain; ++ struct sss_domain_info *dom; ++ char *name; ++ int flag = SSS_GND_ALL_DOMAINS; ++ int i; ++ errno_t ret; ++ ++ if (resolution_order != NULL) { ++ for (i = 0; resolution_order[i] != NULL; i++) { ++ name = resolution_order[i]; ++ for (dom = domains; dom; dom = get_next_domain(dom, flag)) { ++ if (strcasecmp(name, dom->name) != 0) { ++ continue; ++ } ++ ++ cr_domain = talloc_zero(mem_ctx, struct cache_req_domain); ++ if (cr_domain == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ cr_domain->domain = dom; ++ ++ DLIST_ADD_END(cr_domains, cr_domain, ++ struct cache_req_domain *); ++ break; ++ } ++ } ++ } ++ ++ for (dom = domains; dom; dom = get_next_domain(dom, flag)) { ++ if (string_in_list(dom->name, resolution_order, false)) { ++ continue; ++ } ++ ++ cr_domain = talloc_zero(mem_ctx, struct cache_req_domain); ++ if (cr_domain == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ cr_domain->domain = dom; ++ ++ DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *); ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ cache_req_domain_list_zfree(&cr_domains); ++ } ++ ++ return cr_domains; ++} ++ ++struct cache_req_domain * ++cache_req_domain_new_list_from_domain_resolution_order( ++ TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domains, ++ const char *domain_resolution_order) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct cache_req_domain *cr_domains = NULL; ++ char **list = NULL; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return NULL; ++ } ++ ++ if (domain_resolution_order != NULL) { ++ if (strcmp(domain_resolution_order, ":") != 0) { ++ ret = split_on_separator(tmp_ctx, domain_resolution_order, ':', ++ true, true, &list, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "split_on_separator() failed [%d]: [%s].\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ } ++ } ++ ++ cr_domains = cache_req_domain_new_list_from_string_list(mem_ctx, domains, ++ list); ++ if (cr_domains == NULL) { ++ ret = ENOMEM; ++ DEBUG(SSSDBG_OP_FAILURE, ++ "cache_req_domain_new_list_from_domain_resolution_order() " ++ "failed [%d]: [%s].\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++done: ++ talloc_free(tmp_ctx); ++ return cr_domains; ++} +diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h +new file mode 100644 +index 0000000000000000000000000000000000000000..41c50e8c293d7b032cb2f05482c40e93e4f723dc +--- /dev/null ++++ b/src/responder/common/cache_req/cache_req_domain.h +@@ -0,0 +1,46 @@ ++/* ++ Authors: ++ Fabiano Fidêncio ++ ++ Copyright (C) 2017 Red Hat ++ ++ 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 . ++*/ ++ ++#ifndef _CACHE_REQ_DOMAIN_H_ ++#define _CACHE_REQ_DOMAIN_H_ ++ ++#include "responder/common/responder.h" ++ ++struct cache_req_domain { ++ struct sss_domain_info *domain; ++ ++ struct cache_req_domain *prev; ++ struct cache_req_domain *next; ++}; ++ ++struct cache_req_domain * ++cache_req_domain_get_domain_by_name(struct cache_req_domain *domains, ++ const char *name); ++ ++struct cache_req_domain * ++cache_req_domain_new_list_from_domain_resolution_order( ++ TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domains, ++ const char *domain_resolution_order); ++ ++void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains); ++ ++ ++#endif /* _CACHE_REQ_DOMAIN_H_ */ +diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h +index 4d1048a1e0c9be2cad91317d51baf670ecb3307e..29e3f95caf484f43307c9c28d4abd3f50f360a95 100644 +--- a/src/responder/common/responder.h ++++ b/src/responder/common/responder.h +@@ -37,6 +37,7 @@ + #include "sbus/sssd_dbus.h" + #include "responder/common/negcache.h" + #include "sss_client/sss_cli.h" ++#include "responder/common/cache_req/cache_req_domain.h" + + extern hash_table_t *dp_requests; + +@@ -113,6 +114,8 @@ struct resp_ctx { + int domains_timeout; + int client_idle_timeout; + ++ struct cache_req_domain *cr_domains; ++ + time_t last_request_time; + int idle_timeout; + struct tevent_timer *idle; +@@ -387,4 +390,6 @@ char *sss_resp_create_fqname(TALLOC_CTX *mem_ctx, + bool name_is_upn, + const char *orig_name); + ++errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx); ++ + #endif /* __SSS_RESPONDER_H__ */ +diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c +index 76f43609651217e537ffa515aaf5b5caa98a2e90..1792a4c3771fa326c7cca31e1981dce315c03758 100644 +--- a/src/responder/common/responder_common.c ++++ b/src/responder/common/responder_common.c +@@ -1453,3 +1453,156 @@ fail: + return ret; + + } ++ ++/* ====== Helper functions for the domain resolution order ======= */ ++static struct cache_req_domain * ++sss_resp_new_cr_domains_from_ipa_id_view(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domains, ++ struct sysdb_ctx *sysdb) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct cache_req_domain *cr_domains = NULL; ++ const char *domain_resolution_order = NULL; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return NULL; ++ } ++ ++ ret = sysdb_get_view_domain_resolution_order(tmp_ctx, sysdb, ++ &domain_resolution_order); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "sysdb_get_view_cache_req_domain() failed [%d]: [%s].\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ /* Using mem_ctx (which is rctx) directly here to avoid copying ++ * this memory around. */ ++ cr_domains = cache_req_domain_new_list_from_domain_resolution_order( ++ mem_ctx, domains, domain_resolution_order); ++ if (cr_domains == NULL) { ++ ret = ENOMEM; ++ DEBUG(SSSDBG_DEFAULT, ++ "cache_req_domain_new_list_from_domain_resolution_order() " ++ "failed [%d]: [%s].\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++done: ++ talloc_free(tmp_ctx); ++ return cr_domains; ++} ++ ++static struct cache_req_domain * ++sss_resp_new_cr_domains_from_ipa_config(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domains, ++ struct sysdb_ctx *sysdb, ++ const char *domain) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct cache_req_domain *cr_domains = NULL; ++ const char *domain_resolution_order = NULL; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return NULL; ++ } ++ ++ ret = sysdb_domain_get_domain_resolution_order(tmp_ctx, sysdb, domain, ++ &domain_resolution_order); ++ ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "sysdb_domain_get_cache_req_domain() failed [%d]: [%s].\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ /* Using mem_ctx (which is rctx) directly here to avoid copying ++ * this memory around. */ ++ cr_domains = cache_req_domain_new_list_from_domain_resolution_order( ++ mem_ctx, domains, domain_resolution_order); ++ if (cr_domains == NULL) { ++ DEBUG(SSSDBG_DEFAULT, ++ "cache_req_domain_new_list_from_domain_resolution_order() " ++ "failed [%d]: [%s].\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++done: ++ talloc_free(tmp_ctx); ++ return cr_domains; ++} ++ ++errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) ++{ ++ struct cache_req_domain *cr_domains = NULL; ++ struct sss_domain_info *dom; ++ errno_t ret; ++ ++ for (dom = rctx->domains; dom != NULL; dom = dom->next) { ++ if (dom->provider != NULL && strcmp(dom->provider, "ipa") == 0) { ++ break; ++ } ++ } ++ ++ if (dom == NULL) { ++ cr_domains = cache_req_domain_new_list_from_domain_resolution_order( ++ rctx, rctx->domains, NULL); ++ if (cr_domains == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to flatten the list of domains.\n"); ++ } ++ goto done; ++ } ++ ++ if (dom->has_views) { ++ cr_domains = sss_resp_new_cr_domains_from_ipa_id_view(rctx, ++ rctx->domains, ++ dom->sysdb); ++ if (cr_domains == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Failed to use ipaDomainResolutionOrder set for the " ++ "view \"%s\".\n" ++ "Trying to fallback to use ipaDomainOrderResolution " ++ "set in ipaConfig for the domain: %s.\n", ++ dom->view_name, dom->name); ++ } else { ++ goto done; ++ } ++ } ++ ++ cr_domains = sss_resp_new_cr_domains_from_ipa_config(rctx, rctx->domains, ++ dom->sysdb, ++ dom->name); ++ if (cr_domains == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Failed to use ipaDomainResolutionOrder set in ipaConfig " ++ "for the domain: \"%s\".\n" ++ "No ipaDomainResolutionOrder will be followed.\n", ++ dom->name); ++ } else { ++ goto done; ++ } ++ ++ cr_domains = cache_req_domain_new_list_from_domain_resolution_order( ++ rctx, rctx->domains, NULL); ++ if (cr_domains == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to flatten the list of domains.\n"); ++ goto done; ++ } ++ ++done: ++ ret = cr_domains != NULL ? EOK : ENOMEM; ++ ++ cache_req_domain_list_zfree(&rctx->cr_domains); ++ rctx->cr_domains = cr_domains; ++ ++ return ret; ++} +diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c +index 0f9c01214631200f9687635f6302fa5c07e8a1fe..8c90b7773e248e1dd6d846c5050e1931fc50c786 100644 +--- a/src/responder/common/responder_get_domains.c ++++ b/src/responder/common/responder_get_domains.c +@@ -192,6 +192,13 @@ struct tevent_req *sss_dp_get_domains_send(TALLOC_CTX *mem_ctx, + + if (state->dom == NULL) { + /* All domains were local */ ++ ret = sss_resp_populate_cr_domains(state->rctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_resp_populate_cr_domains() failed [%d]: [%s]\n", ++ ret, sss_strerror(ret)); ++ goto immediately; ++ } + ret = EOK; + goto immediately; + } +@@ -253,6 +260,13 @@ sss_dp_get_domains_process(struct tevent_req *subreq) + if (state->dom == NULL) { + /* All domains were local */ + set_time_of_last_request(state->rctx); ++ ret = sss_resp_populate_cr_domains(state->rctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_resp_populate_cr_domains() failed [%d]: [%s]\n", ++ ret, sss_strerror(ret)); ++ goto fail; ++ } + tevent_req_done(req); + return; + } +diff --git a/src/tests/cmocka/common_mock_resp.c b/src/tests/cmocka/common_mock_resp.c +index 88808b1b9394b7a9ee7e58b30b4fbd9d467493d3..175101fc51fd395d792b1fccaecdb327caef2b64 100644 +--- a/src/tests/cmocka/common_mock_resp.c ++++ b/src/tests/cmocka/common_mock_resp.c +@@ -51,6 +51,12 @@ mock_rctx(TALLOC_CTX *mem_ctx, + rctx->ev = ev; + rctx->domains = domains; + rctx->pvt_ctx = pvt_ctx; ++ if (domains != NULL) { ++ ret = sss_resp_populate_cr_domains(rctx); ++ if (ret != EOK) { ++ return NULL; ++ } ++ } + return rctx; + } + +diff --git a/src/tests/cmocka/common_mock_resp_dp.c b/src/tests/cmocka/common_mock_resp_dp.c +index 5db5255ab61231870982c4b78a39504ae8954bcd..4b38a38e6f53499132f9fe14a0ec0af157cf85ca 100644 +--- a/src/tests/cmocka/common_mock_resp_dp.c ++++ b/src/tests/cmocka/common_mock_resp_dp.c +@@ -21,6 +21,7 @@ + */ + + #include "util/util.h" ++#include "responder/common/responder.h" + #include "tests/cmocka/common_mock_resp.h" + + /* Mock DP requests that finish immediatelly and return +@@ -165,6 +166,12 @@ sss_dp_get_domains_send(TALLOC_CTX *mem_ctx, + bool force, + const char *hint) + { ++ errno_t ret; ++ ret = sss_resp_populate_cr_domains(rctx); ++ if (ret != EOK) { ++ return NULL; ++ } ++ + return test_req_succeed_send(mem_ctx, rctx->ev); + } + +diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c +index ede72b341b60842ad470df2794aa90ea9797e999..2f526660cbbbf2443dbae4e213c1336feb6c661e 100644 +--- a/src/tests/cmocka/test_nss_srv.c ++++ b/src/tests/cmocka/test_nss_srv.c +@@ -3440,6 +3440,10 @@ static int nss_subdom_test_setup(void **state) + nss_test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + ++ ret = sss_resp_populate_cr_domains(nss_test_ctx->rctx); ++ assert_int_equal(ret, EOK); ++ assert_non_null(nss_test_ctx->rctx->cr_domains); ++ + nss_test_ctx->subdom = nss_test_ctx->tctx->dom->subdomains; + + ret = store_group(nss_test_ctx, nss_test_ctx->subdom, +diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am +index 4a4090df9296aadde308249f533e7ba246e92f93..c99ebde5f0fc18d1283392cbb307434579d5d811 100644 +--- a/src/tests/cwrap/Makefile.am ++++ b/src/tests/cwrap/Makefile.am +@@ -41,6 +41,7 @@ SSSD_CACHE_REQ_OBJ = \ + ../../../src/responder/common/cache_req/cache_req_result.c \ + ../../../src/responder/common/cache_req/cache_req_search.c \ + ../../../src/responder/common/cache_req/cache_req_data.c \ ++ ../../../src/responder/common/cache_req/cache_req_domain.c \ + ../../../src/responder/common/cache_req/plugins/cache_req_common.c \ + ../../../src/responder/common/cache_req/plugins/cache_req_enum_users.c \ + ../../../src/responder/common/cache_req/plugins/cache_req_enum_groups.c \ +-- +2.9.3 + diff --git a/SOURCES/0052-sysdb-include-email-in-UPN-searches.patch b/SOURCES/0052-sysdb-include-email-in-UPN-searches.patch deleted file mode 100644 index 4dd7f04..0000000 --- a/SOURCES/0052-sysdb-include-email-in-UPN-searches.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 2e9ea4e5c12c0d50509904415beda6b841b91f65 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 20 Jun 2016 12:57:43 +0200 -Subject: [PATCH 52/62] sysdb: include email in UPN searches - -Email addresses and Kerberos user principals names (UPNs) do not only -look similar they also can be used to identify a user uniquely. - -In future this approach should be replace by a more generic one where -the attributes which can uniquely identifies a user can be configured to -support even a wider range of login names. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 78677495a7762469002b0976809fa20ac2196f42) ---- - src/db/sysdb.h | 2 +- - src/db/sysdb_ops.c | 4 ++-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index f3952f8a56f1c9f26f2167b64abdf3e9794af17e..c2f58ccb97c37d93391e72ee2d77835283a6c12f 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -185,7 +185,7 @@ - #define SYSDB_PWNAM_FILTER "(&("SYSDB_UC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))" - #define SYSDB_PWUID_FILTER "(&("SYSDB_UC")("SYSDB_UIDNUM"=%lu))" - #define SYSDB_PWSID_FILTER "(&("SYSDB_UC")("SYSDB_SID_STR"=%s))" --#define SYSDB_PWUPN_FILTER "(&("SYSDB_UC")(|("SYSDB_UPN"=%s)("SYSDB_CANONICAL_UPN"=%s)))" -+#define SYSDB_PWUPN_FILTER "(&("SYSDB_UC")(|("SYSDB_UPN"=%s)("SYSDB_CANONICAL_UPN"=%s)("SYSDB_USER_EMAIL"=%s)))" - #define SYSDB_PWENT_FILTER "("SYSDB_UC")" - - #define SYSDB_GRNAM_FILTER "(&("SYSDB_GC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))" -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 9a8a55ed8aa69e1638d0ab6f636e43baa3d0bfea..ed177d1730723a61e01167a75a0baca6d81252f8 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -537,7 +537,7 @@ int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx, - struct ldb_dn *base_dn; - int ret; - const char *def_attrs[] = { SYSDB_NAME, SYSDB_UPN, SYSDB_CANONICAL_UPN, -- NULL }; -+ SYSDB_USER_EMAIL, NULL }; - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { -@@ -553,7 +553,7 @@ int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx, - - ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, - base_dn, LDB_SCOPE_SUBTREE, attrs ? attrs : def_attrs, -- SYSDB_PWUPN_FILTER, upn, upn); -+ SYSDB_PWUPN_FILTER, upn, upn, upn); - if (ret != EOK) { - ret = sysdb_error_to_errno(ret); - goto done; --- -2.4.11 - diff --git a/SOURCES/0053-LDAP-include-email-in-UPN-searches.patch b/SOURCES/0053-LDAP-include-email-in-UPN-searches.patch deleted file mode 100644 index 878b42a..0000000 --- a/SOURCES/0053-LDAP-include-email-in-UPN-searches.patch +++ /dev/null @@ -1,115 +0,0 @@ -From c333512b85f979ae0694055a36d8dafcf4105248 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 20 Jun 2016 12:58:16 +0200 -Subject: [PATCH 53/62] LDAP: include email in UPN searches - -Reviewed-by: Jakub Hrozek -(cherry picked from commit ba9ebfc49ab3bacb96213c8620411128c09f39da) ---- - src/providers/ldap/ldap_id.c | 18 +++++++++++++---- - src/providers/ldap/sdap_async_initgroups.c | 32 ++++++++++++++++++++++++------ - 2 files changed, 40 insertions(+), 10 deletions(-) - -diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c -index 0106a7b965b8d7debbefe82f60088df9ef8c608b..5b303ddbd46fd44646cdd50856c784640426ee25 100644 ---- a/src/providers/ldap/ldap_id.c -+++ b/src/providers/ldap/ldap_id.c -@@ -127,12 +127,22 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, - break; - case BE_FILTER_NAME: - if (extra_value && strcmp(extra_value, EXTRA_NAME_IS_UPN) == 0) { -- attr_name = ctx->opts->user_map[SDAP_AT_USER_PRINC].name; -- - ret = sss_filter_sanitize(state, filter_value, &clean_value); - if (ret != EOK) { - goto done; - } -+ /* TODO: Do we have to check the attribute names more carefully? */ -+ user_filter = talloc_asprintf(state, "(|(%s=%s)(%s=%s))", -+ ctx->opts->user_map[SDAP_AT_USER_PRINC].name, -+ clean_value, -+ ctx->opts->user_map[SDAP_AT_USER_EMAIL].name, -+ clean_value); -+ talloc_zfree(clean_value); -+ if (user_filter == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } - } else { - attr_name = ctx->opts->user_map[SDAP_AT_USER_NAME].name; - -@@ -242,8 +252,8 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, - goto done; - } - -- if (attr_name == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "Missing search attribute name.\n"); -+ if (attr_name == NULL && user_filter == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "Missing search attribute name or filter.\n"); - ret = EINVAL; - goto done; - } -diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c -index 17593f0a268813662d6c7fbf658b1eb4599ce3c3..0a42b18662a8fe12cf048aadfef257b5d9cb48a3 100644 ---- a/src/providers/ldap/sdap_async_initgroups.c -+++ b/src/providers/ldap/sdap_async_initgroups.c -@@ -2736,13 +2736,25 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, - break; - case BE_FILTER_NAME: - if (extra_value && strcmp(extra_value, EXTRA_NAME_IS_UPN) == 0) { -- search_attr = state->opts->user_map[SDAP_AT_USER_PRINC].name; - - ret = sss_filter_sanitize(state, state->filter_value, &clean_name); - if (ret != EOK) { - talloc_zfree(req); - return NULL; - } -+ -+ state->user_base_filter = -+ talloc_asprintf(state, -+ "(&(|(%s=%s)(%s=%s))(objectclass=%s)", -+ state->opts->user_map[SDAP_AT_USER_PRINC].name, -+ clean_name, -+ state->opts->user_map[SDAP_AT_USER_EMAIL].name, -+ clean_name, -+ state->opts->user_map[SDAP_OC_USER].name); -+ if (state->user_base_filter == NULL) { -+ talloc_zfree(req); -+ return NULL; -+ } - } else { - search_attr = state->opts->user_map[SDAP_AT_USER_NAME].name; - -@@ -2766,15 +2778,23 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, - return NULL; - } - -- state->user_base_filter = -- talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)", -- search_attr, clean_name, -- state->opts->user_map[SDAP_OC_USER].name); -- if (!state->user_base_filter) { -+ if (search_attr == NULL && state->user_base_filter == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "Missing search attribute name or filter.\n"); - talloc_zfree(req); - return NULL; - } - -+ if (state->user_base_filter == NULL) { -+ state->user_base_filter = -+ talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)", -+ search_attr, clean_name, -+ state->opts->user_map[SDAP_OC_USER].name); -+ if (!state->user_base_filter) { -+ talloc_zfree(req); -+ return NULL; -+ } -+ } -+ - if (use_id_mapping) { - /* When mapping IDs or looking for SIDs, we don't want to limit - * ourselves to users with a UID value. But there must be a SID to map --- -2.4.11 - diff --git a/SOURCES/0053-UTIL-Expose-replace_char-as-sss_replace_char.patch b/SOURCES/0053-UTIL-Expose-replace_char-as-sss_replace_char.patch new file mode 100644 index 0000000..0db08c7 --- /dev/null +++ b/SOURCES/0053-UTIL-Expose-replace_char-as-sss_replace_char.patch @@ -0,0 +1,81 @@ +From 3a3b761bc89aa860ca7e6af323c3e0425306014c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Sun, 26 Mar 2017 01:49:53 +0100 +Subject: [PATCH 53/54] UTIL: Expose replace_char() as sss_replace_char() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This method is going to be used in the follow-up patch for replacing ',' +by ':' so we can keep the domain resolution order option consitent with +the way it's set on IPA side and still keep consistent with the way +lists are represented on sssd.conf file. + +Related: +https://pagure.io/SSSD/sssd/issue/3001 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + src/util/string_utils.c | 12 ++++++------ + src/util/util.h | 5 +++++ + 2 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/src/util/string_utils.c b/src/util/string_utils.c +index 872b7e29e55e8628085affd07f3363019aae5ee9..1215ec96a57089a13f455812adf5a0b0812afa6d 100644 +--- a/src/util/string_utils.c ++++ b/src/util/string_utils.c +@@ -22,10 +22,10 @@ + + #include "util/util.h" + +-static char *replace_char(TALLOC_CTX *mem_ctx, +- const char *in, +- const char match, +- const char sub) ++char *sss_replace_char(TALLOC_CTX *mem_ctx, ++ const char *in, ++ const char match, ++ const char sub) + { + char *p; + char *out; +@@ -63,7 +63,7 @@ char * sss_replace_space(TALLOC_CTX *mem_ctx, + return talloc_strdup(mem_ctx, orig_name); + } + +- return replace_char(mem_ctx, orig_name, ' ', subst); ++ return sss_replace_char(mem_ctx, orig_name, ' ', subst); + } + + char * sss_reverse_replace_space(TALLOC_CTX *mem_ctx, +@@ -81,7 +81,7 @@ char * sss_reverse_replace_space(TALLOC_CTX *mem_ctx, + return talloc_strdup(mem_ctx, orig_name); + } + +- return replace_char(mem_ctx, orig_name, subst, ' '); ++ return sss_replace_char(mem_ctx, orig_name, subst, ' '); + } + + errno_t guid_blob_to_string_buf(const uint8_t *blob, char *str_buf, +diff --git a/src/util/util.h b/src/util/util.h +index 82760940269ad8883e725e3a5cf463486c9cfd36..2170c5fb7cffda3910d2b58e33ec7abe3ec4a7d4 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -600,6 +600,11 @@ errno_t name_to_well_known_sid(const char *dom, const char *name, + const char **sid); + + /* from string_utils.c */ ++char *sss_replace_char(TALLOC_CTX *mem_ctx, ++ const char *in, ++ const char match, ++ const char sub); ++ + char * sss_replace_space(TALLOC_CTX *mem_ctx, + const char *orig_name, + const char replace_char); +-- +2.9.3 + diff --git a/SOURCES/0054-Add-domain_resolution_order-config-option.patch b/SOURCES/0054-Add-domain_resolution_order-config-option.patch new file mode 100644 index 0000000..e91960d --- /dev/null +++ b/SOURCES/0054-Add-domain_resolution_order-config-option.patch @@ -0,0 +1,205 @@ +From 26b838f2229483952aeec92a3446acef828244c4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Sun, 26 Mar 2017 03:00:14 +0200 +Subject: [PATCH 54/54] Add domain_resolution_order config option +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is the local equivalent of option of ipaDomainResolutionOrder and +has precedence over the ones set on IPA side making the precedence order +to be like: Local > View > Globally. + +As done for the IPA side configurations, the domains which were not +explicitly set up will be apennded to the final of the +domain_resolution_order list in the very same order they're presented in +the "domains" option of [sssd] section in the config file. There's no +guarantee of order for the subdomains though. + +It's also important to mention that no expansion magic is performed on +our side. It means that if 'example.com' is set it does *not* stand for +all its subdomains DNS wise (like 'foo.example.com', 'bar.example.com', +etc). + +Related: +https://pagure.io/SSSD/sssd/issue/3001 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + 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/responder.h | 1 + + src/responder/common/responder_common.c | 27 +++++++++++++++++++++++++++ + 8 files changed, 58 insertions(+), 1 deletion(-) + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index fb60675ca8beb2c2a157bf021ed9cad362742988..56a603652d6c8256735e7f8b125300ff7b254645 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_DOMAIN_RESOLUTION_ORDER "domain_resolution_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 03a1a43336604bb815626e64cb54052bdf87acf2..e7fb7673d393d4f12910f355d3edf33f4390c1f1 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'), ++ 'domain_resolution_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 457a6f0a09e7139a05f29f8bef7e475fe3b58ec2..6899bf8ae04bf210546c8cbdba8235f094e23dc0 100755 +--- a/src/config/SSSDConfigTest.py ++++ b/src/config/SSSDConfigTest.py +@@ -94,6 +94,10 @@ class SSSDConfigTestValid(unittest.TestCase): + self.assertTrue('default_domain_suffix' in new_options) + self.assertEquals(new_options['default_domain_suffix'][0], str) + ++ self.assertTrue('domain_resolution_order' in new_options) ++ self.assertEquals(new_options['domain_resolution_order'][0], list) ++ self.assertEquals(new_options['domain_resolution_order'][1], str) ++ + del sssdconfig + + def testDomains(self): +@@ -314,7 +318,8 @@ class SSSDConfigTestSSSDService(unittest.TestCase): + 'certificate_verification', + 'override_space', + 'disable_netlink', +- 'enable_files_domain'] ++ 'enable_files_domain', ++ 'domain_resolution_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 933ebccd828189d923d2186753dfbc0b5c0814ce..41efcea552a82c5492a0d21a8d0797ee42cdc8c7 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -43,6 +43,7 @@ option = override_space + option = config_file_version + option = disable_netlink + option = enable_files_domain ++option = domain_resolution_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 08cecf00367aaaab3794a48bd1e728421a996e49..6965028e1ca748f8b6677d9fc1faa66d5c307a0c 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 ++domain_resolution_order = list, str, false + + [nss] + # Name service +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 1c27742cf0c1b6ffad23ab5b044bf4a168ed8f69..4fe13b85d511fb6a2ccc9b4de956710b05bc898c 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -542,6 +542,26 @@ + + + ++ ++ domain_resolution_order ++ ++ ++ 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 ++ domains configuration option. ++ The subdomains which are not listed as part of ++ lookup_order will be looked up ++ in a random order for each parent domain. ++ ++ ++ Default: Not set ++ ++ ++ + + + +diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h +index 29e3f95caf484f43307c9c28d4abd3f50f360a95..4210307489fe25829a1674f254ecc7d185029698 100644 +--- a/src/responder/common/responder.h ++++ b/src/responder/common/responder.h +@@ -115,6 +115,7 @@ struct resp_ctx { + int client_idle_timeout; + + struct cache_req_domain *cr_domains; ++ const char *domain_resolution_order; + + time_t last_request_time; + int idle_timeout; +diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c +index 1792a4c3771fa326c7cca31e1981dce315c03758..154d7dc7718c437d10e152fcba98161e2034fb14 100644 +--- a/src/responder/common/responder_common.c ++++ b/src/responder/common/responder_common.c +@@ -1163,6 +1163,19 @@ int sss_process_init(TALLOC_CTX *mem_ctx, + rctx->override_space = tmp[0]; + } + ++ ret = confdb_get_string(rctx->cdb, rctx, ++ CONFDB_MONITOR_CONF_ENTRY, ++ CONFDB_MONITOR_DOMAIN_RESOLUTION_ORDER, NULL, ++ &tmp); ++ if (ret == EOK) { ++ rctx->domain_resolution_order = sss_replace_char(rctx, tmp, ',', ':'); ++ } else { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot get the \"domain_resolution_order\" option.\n" ++ "The set up lookup_order won't be followed [%d]: %s.\n", ++ ret, sss_strerror(ret)); ++ } ++ + ret = sss_monitor_init(rctx, rctx->ev, monitor_intf, + svc_name, svc_version, MT_SVC_SERVICE, + rctx, &rctx->last_request_time, +@@ -1546,6 +1559,20 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) + struct sss_domain_info *dom; + errno_t ret; + ++ if (rctx->domain_resolution_order != NULL) { ++ cr_domains = cache_req_domain_new_list_from_domain_resolution_order( ++ rctx, rctx->domains, rctx->domain_resolution_order); ++ ++ if (cr_domains == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Failed to use domain_resolution_order set in the config file.\n" ++ "Trying to fallback to use ipaDomainOrderResolution setup by " ++ "IPA.\n"); ++ } else { ++ goto done; ++ } ++ } ++ + for (dom = rctx->domains; dom != NULL; dom = dom->next) { + if (dom->provider != NULL && strcmp(dom->provider, "ipa") == 0) { + break; +-- +2.9.3 + diff --git a/SOURCES/0054-NSS-add-user-email-to-fill_orig.patch b/SOURCES/0054-NSS-add-user-email-to-fill_orig.patch deleted file mode 100644 index b748512..0000000 --- a/SOURCES/0054-NSS-add-user-email-to-fill_orig.patch +++ /dev/null @@ -1,50 +0,0 @@ -From ac8bc2cbea5081f1f0a9395fbaf76616fe5b6fb9 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 20 Jun 2016 13:37:56 +0200 -Subject: [PATCH 54/62] NSS: add user email to fill_orig() - -The IPA server must send the email address of a user to the clients to -allow login by email. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 91767924bdf9b5a28e8902206a40348d6c83a139) ---- - src/db/sysdb.h | 1 + - src/responder/nss/nsssrv_cmd.c | 2 ++ - 2 files changed, 3 insertions(+) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index c2f58ccb97c37d93391e72ee2d77835283a6c12f..8713efa6e8fcc6fb620340fe152989a5dae58434 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -220,6 +220,7 @@ - SYSDB_SID_STR, \ - SYSDB_UPN, \ - SYSDB_USER_CERT, \ -+ SYSDB_USER_EMAIL, \ - SYSDB_OVERRIDE_DN, \ - SYSDB_OVERRIDE_OBJECT_DN, \ - SYSDB_DEFAULT_OVERRIDE_NAME, \ -diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c -index 4e84b3202cbf367e70a47a3c7edb06e357657538..77e540d8da969614e4ab40c62e6ae1f271962f31 100644 ---- a/src/responder/nss/nsssrv_cmd.c -+++ b/src/responder/nss/nsssrv_cmd.c -@@ -4421,6 +4421,7 @@ static errno_t nss_cmd_getsidby_search(struct nss_dom_ctx *dctx) - SYSDB_AD_USER_ACCOUNT_CONTROL, - SYSDB_SSH_PUBKEY, - SYSDB_USER_CERT, -+ SYSDB_USER_EMAIL, - SYSDB_ORIG_DN, - SYSDB_ORIG_MEMBEROF, - SYSDB_DEFAULT_ATTRS, NULL}; -@@ -4977,6 +4978,7 @@ static errno_t fill_orig(struct sss_packet *packet, - SYSDB_AD_USER_ACCOUNT_CONTROL, - SYSDB_SSH_PUBKEY, - SYSDB_USER_CERT, -+ SYSDB_USER_EMAIL, - SYSDB_ORIG_DN, - SYSDB_ORIG_MEMBEROF, - NULL}; --- -2.4.11 - diff --git a/SOURCES/0055-ssh-handle-binary-keys-correctly.patch b/SOURCES/0055-ssh-handle-binary-keys-correctly.patch new file mode 100644 index 0000000..05f87b1 --- /dev/null +++ b/SOURCES/0055-ssh-handle-binary-keys-correctly.patch @@ -0,0 +1,48 @@ +From 3ba9f82ac428f509df33e509a39eb783480f5d19 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 16 Mar 2017 12:38:08 +0100 +Subject: [PATCH 55/60] ssh: handle binary keys correctly + +Related to https://pagure.io/SSSD/sssd/issue/3332 + +Reviewed-by: Jakub Hrozek +--- + src/responder/ssh/ssh_reply.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/responder/ssh/ssh_reply.c b/src/responder/ssh/ssh_reply.c +index 807f4ee079128b4a3f1719de890ffac6e0d5b2e0..7093e47253b5687bab387feed5299c2d0841d43c 100644 +--- a/src/responder/ssh/ssh_reply.c ++++ b/src/responder/ssh/ssh_reply.c +@@ -32,6 +32,11 @@ + #include "responder/common/cache_req/cache_req.h" + #include "responder/ssh/ssh_private.h" + ++/* Locally used flag for libldb's ldb_message_element structure to indicate ++ * binary data. Since the related data is only used in memory it is safe. If ++ * should be used with care if libldb's I/O operations are involved. */ ++#define SSS_EL_FLAG_BIN_DATA (1<<4) ++ + static errno_t get_valid_certs_keys(TALLOC_CTX *mem_ctx, + struct ssh_ctx *ssh_ctx, + struct ldb_message_element *el_cert, +@@ -148,7 +153,7 @@ static errno_t decode_and_add_base64_data(struct sss_packet *packet, + } + + for (d = 0; d < el->num_values; d++) { +- if (skip_base64_decode) { ++ if (skip_base64_decode || (el->flags & SSS_EL_FLAG_BIN_DATA)) { + key = el->values[d].data; + key_len = el->values[d].length; + } else { +@@ -233,6 +238,7 @@ ssh_get_output_keys(TALLOC_CTX *mem_ctx, + } + + if (elements[i] != NULL) { ++ elements[i]->flags |= SSS_EL_FLAG_BIN_DATA; + num_keys += elements[i]->num_values; + i++; + } +-- +2.9.3 + diff --git a/SOURCES/0055-utils-add-is_email_from_domain.patch b/SOURCES/0055-utils-add-is_email_from_domain.patch deleted file mode 100644 index e75ddfc..0000000 --- a/SOURCES/0055-utils-add-is_email_from_domain.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 3f7b69c3af7b810443a94a1004d41b87e5ca79d8 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 20 Jun 2016 16:11:11 +0200 -Subject: [PATCH 55/62] utils: add is_email_from_domain() - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 04d4c4d45f3942a813b7f772737f801f877f4e64) ---- - src/tests/cmocka/test_utils.c | 21 +++++++++++++++++++++ - src/util/domain_info_utils.c | 27 +++++++++++++++++++++++++++ - src/util/util.h | 1 + - 3 files changed, 49 insertions(+) - -diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c -index 5349accc5c6b55f7d725bfdeaf318b90289880dd..09273692968b544aed88de00c747e85ff0b6695c 100644 ---- a/src/tests/cmocka/test_utils.c -+++ b/src/tests/cmocka/test_utils.c -@@ -1842,6 +1842,25 @@ static void test_sss_get_domain_mappings_content(void **state) - * capaths might not be as expected. */ - } - -+static void test_is_email_from_domain(void **state) -+{ -+ struct dom_list_test_ctx *test_ctx = talloc_get_type(*state, -+ struct dom_list_test_ctx); -+ struct sss_domain_info *d; -+ -+ d = find_domain_by_name(test_ctx->dom_list, "name_0.dom", false); -+ assert_non_null(d); -+ -+ assert_false(is_email_from_domain(NULL, NULL)); -+ assert_false(is_email_from_domain("hello", NULL)); -+ assert_false(is_email_from_domain(NULL, d)); -+ assert_false(is_email_from_domain("hello", d)); -+ assert_false(is_email_from_domain("hello@hello", d)); -+ -+ assert_true(is_email_from_domain("hello@name_0.dom", d)); -+ assert_true(is_email_from_domain("hello@NaMe_0.DoM", d)); -+} -+ - int main(int argc, const char *argv[]) - { - poptContext pc; -@@ -1870,6 +1889,8 @@ int main(int argc, const char *argv[]) - setup_dom_list, teardown_dom_list), - cmocka_unit_test_setup_teardown(test_find_domain_by_name_disabled, - setup_dom_list, teardown_dom_list), -+ cmocka_unit_test_setup_teardown(test_is_email_from_domain, -+ setup_dom_list, teardown_dom_list), - - cmocka_unit_test_setup_teardown(test_sss_names_init, - confdb_test_setup, -diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c -index 587a6b993d2bd70662df8e0b0d5963fa00c84cf8..0feda148bd44b9cefc43c094ddc5a72820412322 100644 ---- a/src/util/domain_info_utils.c -+++ b/src/util/domain_info_utils.c -@@ -824,3 +824,30 @@ void sss_domain_set_state(struct sss_domain_info *dom, - { - dom->state = state; - } -+ -+bool is_email_from_domain(const char *email, struct sss_domain_info *dom) -+{ -+ const char *p; -+ -+ if (email == NULL || dom == NULL) { -+ return false; -+ } -+ -+ p = strchr(email, '@'); -+ if (p == NULL) { -+ DEBUG(SSSDBG_TRACE_ALL, -+ "Input [%s] does not look like an email address.\n", email); -+ return false; -+ } -+ -+ if (strcasecmp(p+1, dom->name) == 0) { -+ DEBUG(SSSDBG_TRACE_ALL, "Email [%s] is from domain [%s].\n", email, -+ dom->name); -+ return true; -+ } -+ -+ DEBUG(SSSDBG_TRACE_ALL, "Email [%s] is not from domain [%s].\n", email, -+ dom->name); -+ -+ return false; -+} -diff --git a/src/util/util.h b/src/util/util.h -index 122be90b967fb7793adaff95f3754d7a199fcf48..4449315f8b1a79ec915bc340b46188c440a27fa3 100644 ---- a/src/util/util.h -+++ b/src/util/util.h -@@ -514,6 +514,7 @@ struct sss_domain_info *find_domain_by_sid(struct sss_domain_info *domain, - enum sss_domain_state sss_domain_get_state(struct sss_domain_info *dom); - void sss_domain_set_state(struct sss_domain_info *dom, - enum sss_domain_state state); -+bool is_email_from_domain(const char *email, struct sss_domain_info *dom); - - struct sss_domain_info* - sss_get_domain_by_sid_ldap_fallback(struct sss_domain_info *domain, --- -2.4.11 - diff --git a/SOURCES/0056-LDAP-IPA-add-local-email-address-to-aliases.patch b/SOURCES/0056-LDAP-IPA-add-local-email-address-to-aliases.patch deleted file mode 100644 index 51ebcba..0000000 --- a/SOURCES/0056-LDAP-IPA-add-local-email-address-to-aliases.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 24ed6bff6cf81c7ba732a5515a2194d9e32cf354 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 20 Jun 2016 16:30:03 +0200 -Subject: [PATCH 56/62] LDAP/IPA: add local email address to aliases - -Adding email-addresses from the local domain to the alias names is -strictly not needed by might help to speed up lookups in the NSS -responder. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 9a310913d696d190db14c625080678db853a33fd) ---- - src/providers/ipa/ipa_s2n_exop.c | 49 ++++++++++++++++++++++++++++++++++++++++ - src/providers/ldap/sdap_utils.c | 22 ++++++++++++++++++ - 2 files changed, 71 insertions(+) - -diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c -index b28cc415b1c6dfcf06e0cb9769a36135da01b991..255dad45037a6cb8f399bf2df500215f6fb25b59 100644 ---- a/src/providers/ipa/ipa_s2n_exop.c -+++ b/src/providers/ipa/ipa_s2n_exop.c -@@ -1885,6 +1885,49 @@ done: - return ret; - } - -+static errno_t add_emails_to_aliases(struct sysdb_attrs *attrs, -+ struct sss_domain_info *dom) -+{ -+ int ret; -+ const char **emails; -+ size_t c; -+ TALLOC_CTX *tmp_ctx; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); -+ return ENOMEM; -+ } -+ -+ ret = sysdb_attrs_get_string_array(attrs, SYSDB_USER_EMAIL, tmp_ctx, -+ &emails); -+ if (ret == EOK) { -+ for (c = 0; emails[c] != NULL; c++) { -+ if (is_email_from_domain(emails[c], dom)) { -+ ret = sysdb_attrs_add_lc_name_alias_safe(attrs, emails[c]); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to add lower-cased version of email [%s] " -+ "into the alias list\n", emails[c]); -+ goto done; -+ } -+ } -+ } -+ } else if (ret == ENOENT) { -+ DEBUG(SSSDBG_TRACE_ALL, "No email addresses available.\n"); -+ } else { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_attrs_get_string_array failed, skipping ...\n"); -+ } -+ -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ -+ return ret; -+} -+ - static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, - struct req_input *req_input, - struct resp_attrs *attrs, -@@ -2030,6 +2073,12 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, - goto done; - } - -+ ret = add_emails_to_aliases(attrs->sysdb_attrs, dom); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "add_emails_to_aliases failed, skipping ...\n"); -+ } -+ - if (upn == NULL) { - /* We also have to store a fake UPN here, because otherwise the - * krb5 child later won't be able to properly construct one as -diff --git a/src/providers/ldap/sdap_utils.c b/src/providers/ldap/sdap_utils.c -index 696af51d66e279d718e9af142ce5ed871eae7727..a3a9642171ca057be5a59dfae192803b84c501c8 100644 ---- a/src/providers/ldap/sdap_utils.c -+++ b/src/providers/ldap/sdap_utils.c -@@ -87,6 +87,7 @@ sdap_save_all_names(const char *name, - int i; - bool lowercase = !dom->case_sensitive; - bool store_as_fqdn; -+ const char **emails; - - switch (entry_type) { - case SYSDB_MEMBER_USER: -@@ -143,6 +144,27 @@ sdap_save_all_names(const char *name, - - } - -+ ret = sysdb_attrs_get_string_array(ldap_attrs, SYSDB_USER_EMAIL, tmp_ctx, -+ &emails); -+ if (ret == EOK) { -+ for (i = 0; emails[i] != NULL; i++) { -+ if (is_email_from_domain(emails[i], dom)) { -+ ret = sysdb_attrs_add_lc_name_alias_safe(attrs, emails[i]); -+ if (ret) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Failed to add lower-cased version of email [%s] " -+ "into the alias list\n", emails[i]); -+ goto done; -+ } -+ } -+ } -+ } else if (ret == ENOENT) { -+ DEBUG(SSSDBG_TRACE_ALL, "No email addresses available.\n"); -+ } else { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_attrs_get_string_array failed, skipping ...\n"); -+ } -+ - ret = EOK; - done: - talloc_free(tmp_ctx); --- -2.4.11 - diff --git a/SOURCES/0056-ssh-add-support-for-certificates-from-non-default-vi.patch b/SOURCES/0056-ssh-add-support-for-certificates-from-non-default-vi.patch new file mode 100644 index 0000000..cbeb244 --- /dev/null +++ b/SOURCES/0056-ssh-add-support-for-certificates-from-non-default-vi.patch @@ -0,0 +1,52 @@ +From 61c2661fe7445531f53ef298a98a21ae0278397c Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 16 Mar 2017 13:00:48 +0100 +Subject: [PATCH 56/60] ssh: add support for certificates from non-default + views + +Reviewed-by: Jakub Hrozek +--- + src/responder/ssh/ssh_reply.c | 20 +++++++++++++++++++- + 1 file changed, 19 insertions(+), 1 deletion(-) + +diff --git a/src/responder/ssh/ssh_reply.c b/src/responder/ssh/ssh_reply.c +index 7093e47253b5687bab387feed5299c2d0841d43c..1bb9d331868cc18488718c24fd82f32af780b525 100644 +--- a/src/responder/ssh/ssh_reply.c ++++ b/src/responder/ssh/ssh_reply.c +@@ -204,7 +204,7 @@ ssh_get_output_keys(TALLOC_CTX *mem_ctx, + uint32_t i = 0; + errno_t ret; + +- elements = talloc_zero_array(mem_ctx, struct ldb_message_element *, 5); ++ elements = talloc_zero_array(mem_ctx, struct ldb_message_element *, 6); + if (elements == NULL) { + return ENOMEM; + } +@@ -244,6 +244,24 @@ ssh_get_output_keys(TALLOC_CTX *mem_ctx, + } + } + ++ if (DOM_HAS_VIEWS(domain)) { ++ user_cert = ldb_msg_find_element(msg, OVERRIDE_PREFIX SYSDB_USER_CERT); ++ if (user_cert != NULL) { ++ ret = get_valid_certs_keys(elements, ssh_ctx, user_cert, ++ &elements[i]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "get_valid_certs_keys failed.\n"); ++ goto done; ++ } ++ ++ if (elements[i] != NULL) { ++ elements[i]->flags |= SSS_EL_FLAG_BIN_DATA; ++ num_keys += elements[i]->num_values; ++ i++; ++ } ++ } ++ } ++ + *_elements = elements; + *_num_keys = num_keys; + +-- +2.9.3 + diff --git a/SOURCES/0057-NSS-continue-with-UPN-email-search-if-name-was-not-f.patch b/SOURCES/0057-NSS-continue-with-UPN-email-search-if-name-was-not-f.patch deleted file mode 100644 index 0155ae1..0000000 --- a/SOURCES/0057-NSS-continue-with-UPN-email-search-if-name-was-not-f.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 481bd8fd5db7a92954ff351ab64ab32b4249bf19 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 21 Jun 2016 11:06:19 +0200 -Subject: [PATCH 57/62] NSS: continue with UPN/email search if name was not - found - -Currently we only search for UPNs if the domain part of the name was not -know, with Kerberos aliases and email addresses we have to do this even -if the domain name is a know domain. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 447b1da857368678990b54cd6b9cfed940357c44) ---- - src/responder/nss/nsssrv_cmd.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c -index 77e540d8da969614e4ab40c62e6ae1f271962f31..cd15b41886ad046d1d70dbd8ad54af5a4eccee5d 100644 ---- a/src/responder/nss/nsssrv_cmd.c -+++ b/src/responder/nss/nsssrv_cmd.c -@@ -980,6 +980,7 @@ done: - - static void nss_cmd_getby_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); -+static int nss_cmd_assume_upn(struct nss_dom_ctx *dctx); - - /* search for a user. - * Returns: -@@ -1051,6 +1052,7 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx) - /* There are no further domains or this was a - * fully-qualified user request. - */ -+ - return ENOENT; - } - -@@ -1144,8 +1146,6 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx) - if (dom) continue; - } - -- DEBUG(SSSDBG_OP_FAILURE, "No results for getpwnam call\n"); -- - /* User not found in ldb -> delete user from memory cache. */ - ret = delete_entry_from_memcache(dctx->domain, name, nctx->rctx, - nctx->pwd_mc_ctx, SSS_MC_PASSWD); -@@ -1163,6 +1163,8 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx) - "Deleting user from memcache failed.\n"); - } - -+ DEBUG(SSSDBG_OP_FAILURE, "No results for getpwnam call\n"); -+ - return ENOENT; - } - -@@ -1215,7 +1217,7 @@ static int nss_cmd_assume_upn(struct nss_dom_ctx *dctx) - { - int ret; - -- if (dctx->domain == NULL) { -+ if (dctx->cmdctx->name_is_upn == false) { - dctx->domain = dctx->cmdctx->cctx->rctx->domains; - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - dctx->cmdctx->check_next = true; -@@ -1563,6 +1565,7 @@ static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx) - - rawname = (const char *)body; - dctx->mc_name = rawname; -+ dctx->rawname = rawname; - - DEBUG(SSSDBG_TRACE_FUNC, "Running command [%d][%s] with input [%s].\n", - cmd, sss_cmd2str(dctx->cmdctx->cmd), rawname); -@@ -1588,7 +1591,6 @@ static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx) - if (req == NULL) { - ret = ENOMEM; - } else { -- dctx->rawname = rawname; - tevent_req_set_callback(req, nss_cmd_getbynam_done, dctx); - ret = EAGAIN; - } -@@ -1604,7 +1606,6 @@ static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx) - if (req == NULL) { - ret = ENOMEM; - } else { -- dctx->rawname = rawname; - tevent_req_set_callback(req, nss_cmd_getbynam_done, dctx); - ret = EAGAIN; - } -@@ -1626,7 +1627,6 @@ static int nss_cmd_getbynam(enum sss_cli_command cmd, struct cli_ctx *cctx) - } - } else { - /* this is a multidomain search */ -- dctx->rawname = rawname; - dctx->domain = cctx->rctx->domains; - cmdctx->check_next = true; - if (cctx->rctx->get_domains_last_call.tv_sec == 0) { --- -2.4.11 - diff --git a/SOURCES/0057-krb5-return-to-responder-that-pkinit-is-not-availabl.patch b/SOURCES/0057-krb5-return-to-responder-that-pkinit-is-not-availabl.patch new file mode 100644 index 0000000..db56ae9 --- /dev/null +++ b/SOURCES/0057-krb5-return-to-responder-that-pkinit-is-not-availabl.patch @@ -0,0 +1,60 @@ +From 01ed8c7d7fcd9090d0953f85ef0604cbcad4f48b Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 16 Mar 2017 20:43:08 +0100 +Subject: [PATCH 57/60] krb5: return to responder that pkinit is not available +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If pkinit is not available for a user but other authentication methods +are SSSD should still fall back to local certificate based +authentication if Smartcard credentials are provided. + +Resolves https://pagure.io/SSSD/sssd/issue/3343 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +--- + src/providers/krb5/krb5_child.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index 777a25f2a0ea434dde12d2396f6a35c2a1b86cd0..a4128dda6b0861a95dba223047d66c4158b1afb6 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -42,6 +42,10 @@ + + #define SSSD_KRB5_CHANGEPW_PRINCIPAL "kadmin/changepw" + ++#define IS_SC_AUTHTOK(tok) ( \ ++ sss_authtok_get_type((tok)) == SSS_AUTHTOK_TYPE_SC_PIN \ ++ || sss_authtok_get_type((tok)) == SSS_AUTHTOK_TYPE_SC_KEYPAD) ++ + enum k5c_fast_opt { + K5C_FAST_NEVER, + K5C_FAST_TRY, +@@ -1529,12 +1533,17 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, + * pre-auth module is missing or no Smartcard is inserted and only + * pkinit is available KRB5_PREAUTH_FAILED is returned. + * ERR_NO_AUTH_METHOD_AVAILABLE is used to indicate to the +- * frontend that local authentication might be tried. */ ++ * frontend that local authentication might be tried. ++ * Same is true if Smartcard credentials are given but only other ++ * authentication methods are available. */ + if (kr->pd->cmd == SSS_PAM_AUTHENTICATE + && kerr == KRB5_PREAUTH_FAILED +- && kr->password_prompting == false +- && kr->otp == false +- && kr->pkinit_prompting == false) { ++ && kr->pkinit_prompting == false ++ && (( kr->password_prompting == false ++ && kr->otp == false) ++ || ((kr->otp == true ++ || kr->password_prompting == true) ++ && IS_SC_AUTHTOK(kr->pd->authtok))) ) { + return ERR_NO_AUTH_METHOD_AVAILABLE; + } + return kerr; +-- +2.9.3 + diff --git a/SOURCES/0058-IPA-add-mapped-attributes-to-user-from-trusted-domai.patch b/SOURCES/0058-IPA-add-mapped-attributes-to-user-from-trusted-domai.patch new file mode 100644 index 0000000..2b6616e --- /dev/null +++ b/SOURCES/0058-IPA-add-mapped-attributes-to-user-from-trusted-domai.patch @@ -0,0 +1,153 @@ +From b8a36e1be5cdd2c61ddf8e40970270bb878d26a3 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 22 Mar 2017 14:13:05 +0100 +Subject: [PATCH 58/60] IPA: add mapped attributes to user from trusted domains + +Allow the usage of the mapped attribute for the lookup of AD users on +IPA clients as already used for the normal LDAP lookup. + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_s2n_exop.c | 33 ++++++++++++++++++++++++--------- + 1 file changed, 24 insertions(+), 9 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index c99312274073858e5e03f3e82c069dafc839eb61..05c32a24d61947e62884f460069083fb81f40fe0 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -761,6 +761,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + struct resp_attrs *simple_attrs, + const char *view_name, + struct sysdb_attrs *override_attrs, ++ struct sysdb_attrs *mapped_attrs, + bool update_initgr_timeout); + + static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, +@@ -1009,6 +1010,7 @@ struct ipa_s2n_get_list_state { + struct resp_attrs *attrs; + struct sss_domain_info *obj_domain; + struct sysdb_attrs *override_attrs; ++ struct sysdb_attrs *mapped_attrs; + }; + + static errno_t ipa_s2n_get_list_step(struct tevent_req *req); +@@ -1025,7 +1027,8 @@ static struct tevent_req *ipa_s2n_get_list_send(TALLOC_CTX *mem_ctx, + int entry_type, + enum request_types request_type, + enum req_input_type list_type, +- char **list) ++ char **list, ++ struct sysdb_attrs *mapped_attrs) + { + int ret; + struct ipa_s2n_get_list_state *state; +@@ -1057,6 +1060,7 @@ static struct tevent_req *ipa_s2n_get_list_send(TALLOC_CTX *mem_ctx, + state->request_type = request_type; + state->attrs = NULL; + state->override_attrs = NULL; ++ state->mapped_attrs = mapped_attrs; + + ret = ipa_s2n_get_list_step(req); + if (ret != EOK) { +@@ -1288,7 +1292,8 @@ static errno_t ipa_s2n_get_list_save_step(struct tevent_req *req) + + ret = ipa_s2n_save_objects(state->dom, &state->req_input, state->attrs, + NULL, state->ipa_ctx->view_name, +- state->override_attrs, false); ++ state->override_attrs, state->mapped_attrs, ++ false); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n"); + return ret; +@@ -1704,7 +1709,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + BE_REQ_GROUP, + REQ_FULL_WITH_MEMBERS, + REQ_INP_NAME, +- missing_list); ++ missing_list, NULL); + if (subreq == NULL) { + DEBUG(SSSDBG_OP_FAILURE, + "ipa_s2n_get_list_send failed.\n"); +@@ -1732,7 +1737,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + BE_REQ_USER, + REQ_FULL_WITH_MEMBERS, + REQ_INP_NAME, +- missing_list); ++ missing_list, NULL); + if (subreq == NULL) { + DEBUG(SSSDBG_OP_FAILURE, + "ipa_s2n_get_list_send failed.\n"); +@@ -1810,7 +1815,7 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + + if (ret == ENOENT || is_default_view(state->ipa_ctx->view_name)) { + ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs, +- state->simple_attrs, NULL, NULL, true); ++ state->simple_attrs, NULL, NULL, NULL, true); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n"); + goto done; +@@ -1978,6 +1983,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + struct resp_attrs *simple_attrs, + const char *view_name, + struct sysdb_attrs *override_attrs, ++ struct sysdb_attrs *mapped_attrs, + bool update_initgr_timeout) + { + int ret; +@@ -2305,6 +2311,15 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + goto done; + } + ++ if (mapped_attrs != NULL) { ++ ret = sysdb_set_user_attr(dom, name, mapped_attrs, ++ SYSDB_MOD_ADD); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_user_attr failed.\n"); ++ goto done; ++ } ++ } ++ + if (gid_override_attrs != NULL) { + ret = sysdb_set_user_attr(dom, name, gid_override_attrs, + SYSDB_MOD_REP); +@@ -2487,7 +2502,7 @@ static void ipa_s2n_get_list_done(struct tevent_req *subreq) + &sid_str); + if (ret == ENOENT) { + ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs, +- state->simple_attrs, NULL, NULL, true); ++ state->simple_attrs, NULL, NULL, NULL, true); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n"); + goto fail; +@@ -2525,7 +2540,7 @@ static void ipa_s2n_get_list_done(struct tevent_req *subreq) + ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs, + state->simple_attrs, + state->ipa_ctx->view_name, +- state->override_attrs, true); ++ state->override_attrs, NULL, true); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n"); + tevent_req_error(req, ret); +@@ -2561,7 +2576,7 @@ static void ipa_s2n_get_user_get_override_done(struct tevent_req *subreq) + + ret = ipa_s2n_save_objects(state->dom, state->req_input, state->attrs, + state->simple_attrs, state->ipa_ctx->view_name, +- override_attrs, true); ++ override_attrs, NULL, true); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_save_objects failed.\n"); + tevent_req_error(req, ret); +@@ -2662,7 +2677,7 @@ struct tevent_req *ipa_get_subdom_acct_process_pac_send(TALLOC_CTX *mem_ctx, + dp_opt_get_int(ipa_ctx->sdap_id_ctx->opts->basic, + SDAP_SEARCH_TIMEOUT), + BE_REQ_BY_SECID, REQ_FULL, REQ_INP_SECID, +- state->missing_sids); ++ state->missing_sids, NULL); + if (subreq == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "ipa_s2n_get_list_send failed.\n"); + ret = ENOMEM; +-- +2.9.3 + diff --git a/SOURCES/0058-PAM-continue-with-UPN-email-search-if-name-was-not-f.patch b/SOURCES/0058-PAM-continue-with-UPN-email-search-if-name-was-not-f.patch deleted file mode 100644 index 3910eb3..0000000 --- a/SOURCES/0058-PAM-continue-with-UPN-email-search-if-name-was-not-f.patch +++ /dev/null @@ -1,90 +0,0 @@ -From d8c0b5421934cae887a44be42250d5df5631d3de Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 22 Jun 2016 18:21:11 +0200 -Subject: [PATCH 58/62] PAM: continue with UPN/email search if name was not - found - -Currently we only search for UPNs if the domain part of the name was not -know, with Kerberos aliases and email addresses we have to do this even -if the domain name is a know domain. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 3381d9736b698d6111d10e219a0b5b898a4c757c) ---- - src/responder/pam/pamsrv_cmd.c | 39 +++++++++++++++++++++++++++++++++++++++ - 1 file changed, 39 insertions(+) - -diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c -index 3a35c3f08821aa23051989599d45b8b7b0677da4..1c759f009321cbb322fce624b506ed07f93f997b 100644 ---- a/src/responder/pam/pamsrv_cmd.c -+++ b/src/responder/pam/pamsrv_cmd.c -@@ -924,6 +924,39 @@ static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min, - static int pam_check_user_search(struct pam_auth_req *preq); - static int pam_check_user_done(struct pam_auth_req *preq, int ret); - -+static errno_t pam_cmd_assume_upn(struct pam_auth_req *preq) -+{ -+ int ret; -+ -+ if (!preq->pd->name_is_upn -+ && preq->pd->logon_name != NULL -+ && strchr(preq->pd->logon_name, '@') != NULL) { -+ DEBUG(SSSDBG_TRACE_ALL, -+ "No entry found so far, trying UPN/email lookup with [%s].\n", -+ preq->pd->logon_name); -+ /* Assuming Kerberos principal */ -+ preq->domain = preq->cctx->rctx->domains; -+ preq->check_provider = -+ NEED_CHECK_PROVIDER(preq->domain->provider); -+ preq->pd->user = talloc_strdup(preq->pd, preq->pd->logon_name); -+ if (preq->pd->user == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); -+ return ENOMEM; -+ } -+ preq->pd->name_is_upn = true; -+ preq->pd->domain = NULL; -+ -+ ret = pam_check_user_search(preq); -+ if (ret == EOK) { -+ pam_dom_forwarder(preq); -+ } -+ return EOK; -+ } -+ -+ return ENOENT; -+} -+ -+ - /* TODO: we should probably return some sort of cookie that is set in the - * PAM_ENVIRONMENT, so that we can save performing some calls and cache - * data. */ -@@ -1220,6 +1253,8 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) - ret = pam_check_user_search(preq); - if (ret == EOK) { - pam_dom_forwarder(preq); -+ } else if (ret == ENOENT) { -+ ret = pam_cmd_assume_upn(preq); - } - - done: -@@ -1417,6 +1452,8 @@ static void pam_forwarder_cb(struct tevent_req *req) - ret = pam_check_user_search(preq); - if (ret == EOK) { - pam_dom_forwarder(preq); -+ } else if (ret == ENOENT) { -+ ret = pam_cmd_assume_upn(preq); - } - - done: -@@ -1694,6 +1731,8 @@ static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min, - } - - pam_dom_forwarder(preq); -+ } else if (ret == ENOENT) { -+ ret = pam_cmd_assume_upn(preq); - } - - ret = pam_check_user_done(preq, ret); --- -2.4.11 - diff --git a/SOURCES/0059-IPA-lookup-AD-users-by-certificates-on-IPA-clients.patch b/SOURCES/0059-IPA-lookup-AD-users-by-certificates-on-IPA-clients.patch new file mode 100644 index 0000000..1440219 --- /dev/null +++ b/SOURCES/0059-IPA-lookup-AD-users-by-certificates-on-IPA-clients.patch @@ -0,0 +1,209 @@ +From 537e057ef3bd140e418381f2ce74397ab8c34a73 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 24 Mar 2017 15:40:41 +0100 +Subject: [PATCH 59/60] IPA: lookup AD users by certificates on IPA clients + +Get a list of users mapped to a certificate back from the IPA server, +look them up and store them together with the certificate used for the +search as mapped attribute to the cache. + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_s2n_exop.c | 109 +++++++++++++++++++++++++++++++++++++-- + 1 file changed, 105 insertions(+), 4 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index 05c32a24d61947e62884f460069083fb81f40fe0..8a3391b4093f1547d84fe44a0f24b1d063d1e28c 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -52,7 +52,8 @@ enum response_types { + RESP_USER, + RESP_GROUP, + RESP_USER_GROUPLIST, +- RESP_GROUP_MEMBERS ++ RESP_GROUP_MEMBERS, ++ RESP_NAME_LIST + }; + + /* ==Sid2Name Extended Operation============================================= */ +@@ -366,8 +367,8 @@ static errno_t s2n_encode_request(TALLOC_CTX *mem_ctx, + break; + case BE_REQ_BY_CERT: + if (req_input->type == REQ_INP_CERT) { +- ret = ber_printf(ber, "{ees}", INP_CERT, request_type, +- req_input->inp.cert); ++ ret = ber_printf(ber, "{ees}", INP_CERT, request_type, ++ req_input->inp.cert); + } else { + DEBUG(SSSDBG_OP_FAILURE, "Unexpected input type [%d].\n", + req_input->type); +@@ -463,6 +464,11 @@ done: + * GroupMemberList ::= SEQUENCE OF OCTET STRING + */ + ++struct name_list { ++ char *domain_name; ++ char *name; ++}; ++ + struct resp_attrs { + enum response_types response_type; + char *domain_name; +@@ -475,6 +481,7 @@ struct resp_attrs { + size_t ngroups; + char **groups; + struct sysdb_attrs *sysdb_attrs; ++ char **name_list; + }; + + static errno_t get_extra_attrs(BerElement *ber, struct resp_attrs *resp_attrs) +@@ -782,6 +789,9 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, + struct resp_attrs *attrs = NULL; + char *sid_str; + bool is_v1 = false; ++ char **name_list = NULL; ++ ber_len_t ber_len; ++ char *fq_name = NULL; + + if (retoid == NULL || retdata == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Missing OID or data.\n"); +@@ -947,6 +957,53 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, + goto done; + } + break; ++ case RESP_NAME_LIST: ++ tag = ber_scanf(ber, "{"); ++ if (tag == LBER_ERROR) { ++ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ while (ber_peek_tag(ber, &ber_len) == LBER_SEQUENCE) { ++ tag = ber_scanf(ber, "{aa}", &domain_name, &name); ++ if (tag == LBER_ERROR) { ++ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ fq_name = sss_create_internal_fqname(attrs, name, domain_name); ++ if (fq_name == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sss_create_internal_fqname failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_ALL, "[%s][%s][%s].\n", domain_name, name, ++ fq_name); ++ ++ ret = add_string_to_list(attrs, fq_name, &name_list); ++ ber_memfree(domain_name); ++ ber_memfree(name); ++ talloc_free(fq_name); ++ domain_name = NULL; ++ name = NULL; ++ fq_name = NULL; ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "add_to_name_list failed.\n"); ++ goto done; ++ } ++ } ++ ++ tag = ber_scanf(ber, "}}"); ++ if (tag == LBER_ERROR) { ++ DEBUG(SSSDBG_OP_FAILURE, "ber_scanf failed.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ attrs->name_list = name_list; ++ break; + default: + DEBUG(SSSDBG_OP_FAILURE, "Unexpected response type [%d].\n", + type); +@@ -955,7 +1012,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, + } + + attrs->response_type = type; +- if (type != RESP_SID) { ++ if (type != RESP_SID && type != RESP_NAME_LIST) { + attrs->domain_name = talloc_strdup(attrs, domain_name); + if (attrs->domain_name == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); +@@ -969,6 +1026,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, + done: + ber_memfree(domain_name); + ber_memfree(name); ++ talloc_free(fq_name); + ber_free(ber, 1); + + if (ret == EOK) { +@@ -1332,6 +1390,7 @@ struct ipa_s2n_get_user_state { + struct resp_attrs *attrs; + struct resp_attrs *simple_attrs; + struct sysdb_attrs *override_attrs; ++ struct sysdb_attrs *mapped_attrs; + int exop_timeout; + }; + +@@ -1384,6 +1443,11 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx, + goto fail; + } + ++ if (entry_type == BE_REQ_BY_CERT) { ++ /* Only REQ_SIMPLE is supported for BE_REQ_BY_CERT */ ++ state->request_type = REQ_SIMPLE; ++ } ++ + ret = s2n_encode_request(state, dom->name, entry_type, state->request_type, + req_input, &bv_req); + if (ret != EOK) { +@@ -1785,6 +1849,43 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + goto done; + } + ++ if (state->simple_attrs->response_type == RESP_NAME_LIST ++ && state->req_input->type == REQ_INP_CERT) { ++ state->mapped_attrs = sysdb_new_attrs(state); ++ if (state->mapped_attrs == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_attrs_add_base64_blob(state->mapped_attrs, ++ SYSDB_USER_MAPPED_CERT, ++ state->req_input->inp.cert); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_base64_blob failed.\n"); ++ goto done; ++ } ++ ++ subreq = ipa_s2n_get_list_send(state, state->ev, ++ state->ipa_ctx, state->dom, ++ state->sh, state->exop_timeout, ++ BE_REQ_USER, ++ REQ_FULL_WITH_MEMBERS, ++ REQ_INP_NAME, ++ state->simple_attrs->name_list, ++ state->mapped_attrs); ++ if (subreq == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "ipa_s2n_get_list_send failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ tevent_req_set_callback(subreq, ipa_s2n_get_list_done, ++ req); ++ ++ return; ++ } ++ + break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected request type.\n"); +-- +2.9.3 + diff --git a/SOURCES/0059-NSS-use-different-neg-cache-name-for-UPN-searches.patch b/SOURCES/0059-NSS-use-different-neg-cache-name-for-UPN-searches.patch deleted file mode 100644 index e77eb21..0000000 --- a/SOURCES/0059-NSS-use-different-neg-cache-name-for-UPN-searches.patch +++ /dev/null @@ -1,59 +0,0 @@ -From e5b8922062e127d1014609df16f1909da49850bf Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 22 Jul 2016 16:01:38 +0200 -Subject: [PATCH 59/62] NSS: use different neg cache name for UPN searches - -If Kerberos principals or email address have the same domain suffix as -the domain itself the first user lookup by name might have already added -the name to the negative cache and the second lookup by UPN/email will -skip the domain because of the neg cache entry. To avoid this a special -name with a '@' prefix is used here. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 62df78512145db94b51c5573d4df1737197e368a) ---- - src/responder/nss/nsssrv_cmd.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c -index cd15b41886ad046d1d70dbd8ad54af5a4eccee5d..f3b6ac4afb5d1571f283933b48e0256b91c56391 100644 ---- a/src/responder/nss/nsssrv_cmd.c -+++ b/src/responder/nss/nsssrv_cmd.c -@@ -1002,6 +1002,7 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx) - struct ldb_message *msg; - const char *extra_flag = NULL; - const char *sysdb_name; -+ char *neg_cache_name; - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - -@@ -1031,9 +1032,15 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx) - return ENOMEM; - } - -+ if (cmdctx->name_is_upn) { -+ neg_cache_name = talloc_asprintf(name, "@%s", name); -+ } else { -+ neg_cache_name = name; -+ } -+ - /* verify this user has not yet been negatively cached, - * or has been permanently filtered */ -- ret = sss_ncache_check_user(nctx->rctx->ncache, dom, name); -+ ret = sss_ncache_check_user(nctx->rctx->ncache, dom, neg_cache_name); - - /* if neg cached, return we didn't find it */ - if (ret == EEXIST) { -@@ -1130,7 +1137,8 @@ static int nss_cmd_getpwnam_search(struct nss_dom_ctx *dctx) - - if (dctx->res->count == 0 && !dctx->check_provider) { - /* set negative cache only if not result of cache check */ -- ret = sss_ncache_set_user(nctx->rctx->ncache, false, dom, name); -+ ret = sss_ncache_set_user(nctx->rctx->ncache, false, dom, -+ neg_cache_name); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set negcache for %s\n", - name); --- -2.4.11 - diff --git a/SOURCES/0060-IPA-enable-AD-user-lookup-by-certificate.patch b/SOURCES/0060-IPA-enable-AD-user-lookup-by-certificate.patch new file mode 100644 index 0000000..e6ed62e --- /dev/null +++ b/SOURCES/0060-IPA-enable-AD-user-lookup-by-certificate.patch @@ -0,0 +1,30 @@ +From 1f29c3d5302dc4ca9f5f9c6fe64dc8de5381041f Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 24 Mar 2017 15:41:37 +0100 +Subject: [PATCH 60/60] IPA: enable AD user lookup by certificate + +Without this the lookup by certificate for AD users on an IPA client +will just error out. + +Related to https://pagure.io/SSSD/sssd/issue/3050 + +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_subdomains_id.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c +index 4777d7cfd97fed39b807a659fd1f9000c7ff8625..3530af94ef59397db72465fcb0c4a03117a4d8bd 100644 +--- a/src/providers/ipa/ipa_subdomains_id.c ++++ b/src/providers/ipa/ipa_subdomains_id.c +@@ -399,6 +399,7 @@ struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx, + case BE_REQ_USER: + case BE_REQ_GROUP: + case BE_REQ_BY_SECID: ++ case BE_REQ_BY_CERT: + case BE_REQ_USER_AND_GROUP: + ret = EOK; + break; +-- +2.9.3 + diff --git a/SOURCES/0060-PAM-Fix-domain-for-UPN-based-lookups.patch b/SOURCES/0060-PAM-Fix-domain-for-UPN-based-lookups.patch deleted file mode 100644 index ca64d2b..0000000 --- a/SOURCES/0060-PAM-Fix-domain-for-UPN-based-lookups.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 3467754b1e32e648b3013244dcbac51677a089eb Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 22 Jul 2016 17:34:20 +0200 -Subject: [PATCH 60/62] PAM: Fix domain for UPN based lookups - -Since sysdb_search_user_by_upn() searches the whole cache we have to set -the domain so that it matches the result. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 9b8fcf685c5ca70a5067a621385bcdc8d9fd6469) ---- - src/responder/pam/pamsrv_cmd.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c -index 1c759f009321cbb322fce624b506ed07f93f997b..66564f5d301a53dcdb5967f43ef4afdb897e9974 100644 ---- a/src/responder/pam/pamsrv_cmd.c -+++ b/src/responder/pam/pamsrv_cmd.c -@@ -1474,6 +1474,7 @@ static int pam_check_user_search(struct pam_auth_req *preq) - static const char *user_attrs[] = SYSDB_PW_ATTRS; - struct ldb_message *msg; - struct ldb_result *res; -+ const char *sysdb_name; - - while (dom) { - /* if it is a domainless search, skip domains that require fully -@@ -1533,6 +1534,22 @@ static int pam_check_user_search(struct pam_auth_req *preq) - - if (preq->pd->name_is_upn) { - ret = sysdb_search_user_by_upn(preq, dom, name, user_attrs, &msg); -+ -+ /* Since sysdb_search_user_by_upn() searches the whole cache we -+ * have to set the domain so that it matches the result. */ -+ sysdb_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); -+ if (sysdb_name == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Cached entry has no name.\n"); -+ return EINVAL; -+ } -+ preq->domain = find_domain_by_object_name(get_domains_head(dom), -+ sysdb_name); -+ if (preq->domain == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot find matching domain for [%s].\n", -+ sysdb_name); -+ return EINVAL; -+ } - } else { - ret = sysdb_getpwnam_with_views(preq, dom, name, &res); - if (res->count > 1) { --- -2.4.11 - diff --git a/SOURCES/0061-CONFDB-Introduce-SSSD-domain-type-to-distinguish-POS.patch b/SOURCES/0061-CONFDB-Introduce-SSSD-domain-type-to-distinguish-POS.patch new file mode 100644 index 0000000..31f541e --- /dev/null +++ b/SOURCES/0061-CONFDB-Introduce-SSSD-domain-type-to-distinguish-POS.patch @@ -0,0 +1,242 @@ +From 75a8d8e7996c35fd9bef504f2f4d3e308b7553c8 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 22 Mar 2017 12:53:17 +0100 +Subject: [PATCH 61/72] CONFDB: Introduce SSSD domain type to distinguish POSIX + and application domains +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related to: +https://pagure.io/SSSD/sssd/issue/3310 + +Adds a new option that allows to distinguish domains that do contain +POSIX users and groups and those that don't. The POSIX domains are the +default. The non-POSIX domains are selected by selecting an +"application" type domain. + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + src/confdb/confdb.c | 18 +++++++++++++++++- + src/confdb/confdb.h | 15 +++++++++++++++ + src/config/SSSDConfig/__init__.py.in | 1 + + src/config/SSSDConfigTest.py | 2 ++ + src/config/cfg_rules.ini | 1 + + src/config/etc/sssd.api.conf | 1 + + src/man/sssd.conf.5.xml | 33 +++++++++++++++++++++++++++++++++ + src/util/domain_info_utils.c | 14 ++++++++++++++ + src/util/util.h | 1 + + 9 files changed, 85 insertions(+), 1 deletion(-) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index d82fd98ee02928b3c20df014528bd869ec946f92..70a1eb7b2c7e83dfa9d217a15c7d3d4c8580b891 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -1367,6 +1367,22 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, + } + } + ++ domain->type = DOM_TYPE_POSIX; ++ tmp = ldb_msg_find_attr_as_string(res->msgs[0], ++ CONFDB_DOMAIN_TYPE, ++ CONFDB_DOMAIN_TYPE_POSIX); ++ if (tmp != NULL) { ++ if (strcasecmp(tmp, CONFDB_DOMAIN_TYPE_POSIX) == 0) { ++ domain->type = DOM_TYPE_POSIX; ++ } else if (strcasecmp(tmp, CONFDB_DOMAIN_TYPE_APP) == 0) { ++ domain->type = DOM_TYPE_APPLICATION; ++ } else { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Invalid value %s for [%s]\n", tmp, CONFDB_DOMAIN_TYPE); ++ goto done; ++ } ++ } ++ + ret = get_entry_as_uint32(res->msgs[0], &domain->subdomain_refresh_interval, + CONFDB_DOMAIN_SUBDOMAIN_REFRESH, 14400); + if (ret != EOK || domain->subdomain_refresh_interval == 0) { +@@ -1444,7 +1460,7 @@ int confdb_get_domains(struct confdb_ctx *cdb, + if (ret) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Error (%d [%s]) retrieving domain [%s], skipping!\n", +- ret, sss_strerror(ret), domlist[i]); ++ ret, sss_strerror(ret), domlist[i]); + continue; + } + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 56a603652d6c8256735e7f8b125300ff7b254645..a4046610f3cdbdb832de8924bf4397fb0018f2db 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -209,6 +209,9 @@ + #define CONFDB_DOMAIN_OFFLINE_TIMEOUT "offline_timeout" + #define CONFDB_DOMAIN_SUBDOMAIN_INHERIT "subdomain_inherit" + #define CONFDB_DOMAIN_CACHED_AUTH_TIMEOUT "cached_auth_timeout" ++#define CONFDB_DOMAIN_TYPE "domain_type" ++#define CONFDB_DOMAIN_TYPE_POSIX "posix" ++#define CONFDB_DOMAIN_TYPE_APP "application" + + /* Local Provider */ + #define CONFDB_LOCAL_DEFAULT_SHELL "default_shell" +@@ -261,11 +264,23 @@ enum sss_domain_state { + DOM_INCONSISTENT, + }; + ++/** Whether the domain only supports looking up POSIX entries */ ++enum sss_domain_type { ++ /** This is the default domain type. It resolves only entries ++ * with the full POSIX set of attributes ++ */ ++ DOM_TYPE_POSIX, ++ /** In this mode, entries are typically resolved only by name */ ++ DOM_TYPE_APPLICATION, ++}; ++ + /** + * Data structure storing all of the basic features + * of a domain. + */ + struct sss_domain_info { ++ enum sss_domain_type type; ++ + char *name; + char *conn_name; + char *provider; +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index e7fb7673d393d4f12910f355d3edf33f4390c1f1..806611b6076048c08ce08c772dbd3cea5fdd656c 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -148,6 +148,7 @@ option_strings = { + 'selinux_provider' : _('SELinux provider'), + + # [domain] ++ 'domain_type' : _('Whether the domain is usable by the OS or by applications'), + 'min_id' : _('Minimum user ID'), + 'max_id' : _('Maximum user ID'), + 'enumerate' : _('Enable enumerating all users/groups'), +diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py +index 6899bf8ae04bf210546c8cbdba8235f094e23dc0..9b3175962c697e314b3d5d94c2bc5beda537b66e 100755 +--- a/src/config/SSSDConfigTest.py ++++ b/src/config/SSSDConfigTest.py +@@ -510,6 +510,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 'debug', + 'debug_level', + 'debug_timestamps', ++ 'domain_type', + 'min_id', + 'max_id', + 'timeout', +@@ -878,6 +879,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 'debug', + 'debug_level', + 'debug_timestamps', ++ 'domain_type', + 'min_id', + 'max_id', + 'timeout', +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 41efcea552a82c5492a0d21a8d0797ee42cdc8c7..3c857236eaa55b313d176bc4bb479918163b60d5 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -311,6 +311,7 @@ option = subdomains_provider + option = selinux_provider + + # Options available to all domains ++option = domain_type + option = min_id + option = max_id + option = timeout +diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf +index 6965028e1ca748f8b6677d9fc1faa66d5c307a0c..a38b24208f89e4502e41625c540ea9958d5bbffe 100644 +--- a/src/config/etc/sssd.api.conf ++++ b/src/config/etc/sssd.api.conf +@@ -129,6 +129,7 @@ selinux_provider = str, None, false + [domain] + # Options available to all domains + description = str, None, false ++domain_type = str, None, false + debug = int, None, false + debug_level = int, None, false + debug_timestamps = bool, None, false +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 4fe13b85d511fb6a2ccc9b4de956710b05bc898c..9abcff84a95ea1b27e36845e830cc125fdc89f90 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -1512,6 +1512,39 @@ pam_account_locked_message = Account locked, please contact help desk. + [domain/NAME] + + ++ domain_type (string) ++ ++ ++ Specifies whether the domain is meant to be used ++ by POSIX-aware clients such as the Name Service Switch ++ or by applications that do not need POSIX data to be ++ present or generated. Only objects from POSIX domains ++ are available to the operating system interfaces and ++ utilities. ++ ++ ++ Allowed values for this option are posix ++ and application. ++ ++ ++ POSIX domains are reachable by all services. Application ++ domains are only reachable from the InfoPipe responder (see ++ ++ sssd-ifp ++ 5 ++ ) and the PAM responder. ++ ++ ++ NOTE: The application domains are currently well tested with ++ id_provider=ldap only. ++ ++ ++ Default: posix ++ ++ ++ ++ ++ + min_id,max_id (integer) + + +diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c +index a7f118842aa8ba870143b2f2b425a3e3c0ea5a78..2af7852f03f89b61f5b9fd8a244e98fb27b7e6a2 100644 +--- a/src/util/domain_info_utils.c ++++ b/src/util/domain_info_utils.c +@@ -885,3 +885,17 @@ char *subdomain_create_conf_path(TALLOC_CTX *mem_ctx, + subdomain->parent->name, + subdomain->name); + } ++ ++const char *sss_domain_type_str(struct sss_domain_info *dom) ++{ ++ if (dom == NULL) { ++ return "BUG: Invalid domain"; ++ } ++ switch (dom->type) { ++ case DOM_TYPE_POSIX: ++ return "POSIX"; ++ case DOM_TYPE_APPLICATION: ++ return "Application"; ++ } ++ return "Unknown"; ++} +diff --git a/src/util/util.h b/src/util/util.h +index 2170c5fb7cffda3910d2b58e33ec7abe3ec4a7d4..436550f5078cc173b8ed8cb58836d366f813146b 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -539,6 +539,7 @@ enum sss_domain_state sss_domain_get_state(struct sss_domain_info *dom); + void sss_domain_set_state(struct sss_domain_info *dom, + enum sss_domain_state state); + bool is_email_from_domain(const char *email, struct sss_domain_info *dom); ++const char *sss_domain_type_str(struct sss_domain_info *dom); + + struct sss_domain_info* + sss_get_domain_by_sid_ldap_fallback(struct sss_domain_info *domain, +-- +2.9.3 + diff --git a/SOURCES/0061-SDAP-add-special-handling-for-IPA-Kerberos-enterpris.patch b/SOURCES/0061-SDAP-add-special-handling-for-IPA-Kerberos-enterpris.patch deleted file mode 100644 index 13145e0..0000000 --- a/SOURCES/0061-SDAP-add-special-handling-for-IPA-Kerberos-enterpris.patch +++ /dev/null @@ -1,56 +0,0 @@ -From c2fe77b2277513d01b56dc26391e8e7cfcbe7429 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 22 Jul 2016 12:20:33 +0200 -Subject: [PATCH 61/62] SDAP: add special handling for IPA Kerberos enterprise - principal strings - -Unfortunately principal aliases with an alternative realm are stored in -IPA as the string representation of an enterprise principal, i.e. -name\@alt.realm@IPA.REALM. To allow searches with the plain alias -'name@alt.realm' the returned value is converted before it is saved to -the cache. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 15694ca762f61a414f0017c57ed97a8d57456b80) ---- - src/providers/ldap/sdap_async_users.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c -index 28101a2d8a38f97d09d50a9f7e071a030b4f9719..cccd2506b3e1849101a8a06c39fe6cab263777b6 100644 ---- a/src/providers/ldap/sdap_async_users.c -+++ b/src/providers/ldap/sdap_async_users.c -@@ -143,6 +143,8 @@ int sdap_save_user(TALLOC_CTX *memctx, - char *dom_sid_str = NULL; - struct sss_domain_info *subdomain; - size_t c; -+ char *p1; -+ char *p2; - - DEBUG(SSSDBG_TRACE_FUNC, "Save user\n"); - -@@ -448,6 +450,21 @@ int sdap_save_user(TALLOC_CTX *memctx, - goto done; - } - -+ /* Check for IPA Kerberos enterprise principal strings -+ * 'user\@my.realm@IPA.REALM' and use 'user@my.realm' */ -+ if ( (p1 = strchr(upn,'\\')) != NULL -+ && *(p1 + 1) == '@' -+ && (p2 = strchr(p1 + 2, '@')) != NULL) { -+ *p1 = '\0'; -+ *p2 = '\0'; -+ upn = talloc_asprintf(tmpctx, "%s%s", upn, p1 + 1); -+ if (upn == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } -+ - if (dp_opt_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) { - make_realm_upper_case(upn); - } --- -2.4.11 - diff --git a/SOURCES/0062-CONFDB-Allow-configuring-application-sections-as-non.patch b/SOURCES/0062-CONFDB-Allow-configuring-application-sections-as-non.patch new file mode 100644 index 0000000..24ecd56 --- /dev/null +++ b/SOURCES/0062-CONFDB-Allow-configuring-application-sections-as-non.patch @@ -0,0 +1,531 @@ +From 05ae58c86eae80c7e69fb809dc3cd89d0b7418f4 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 27 Mar 2017 09:48:46 +0200 +Subject: [PATCH 62/72] CONFDB: Allow configuring [application] sections as + non-POSIX domains +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related to: +https://pagure.io/SSSD/sssd/issue/3310 + +Allows to add a new section: + [application/$name] + +This section internally (on the confdb level) expands to: + [domain/$name] + domain_type = application + +The reasons to add this new section is two-fold. One, to make the +configuration of application domains more explicit and two, to make it +possible to share configuration between two domains, one POSIX and one +non-POSIX by application domain's inherit_from option: + [application/$name] + inherit_from = posix_domain_name + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + src/confdb/confdb.c | 288 ++++++++++++++++++++++++++++++++++++++++++++--- + src/confdb/confdb.h | 4 + + src/config/cfg_rules.ini | 9 +- + src/man/sssd.conf.5.xml | 77 +++++++++++++ + src/monitor/monitor.c | 8 ++ + 5 files changed, 368 insertions(+), 18 deletions(-) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index 70a1eb7b2c7e83dfa9d217a15c7d3d4c8580b891..88e114457deac3ca50c291a131122624fb6f6fe4 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -813,6 +813,50 @@ done: + return ret; + } + ++static int confdb_get_domain_section(TALLOC_CTX *mem_ctx, ++ struct confdb_ctx *cdb, ++ const char *section, ++ const char *name, ++ struct ldb_result **_res) ++{ ++ TALLOC_CTX *tmp_ctx; ++ int ret; ++ struct ldb_result *res; ++ struct ldb_dn *dn; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb, "cn=%s,%s", name, section); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, ++ LDB_SCOPE_BASE, NULL, NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ if (res->count == 0) { ++ ret = ENOENT; ++ goto done; ++ } else if (res->count > 1) { ++ ret = E2BIG; ++ goto done; ++ } ++ ++ *_res = talloc_steal(mem_ctx, res); ++ ret = EOK; ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + static int confdb_get_domain_internal(struct confdb_ctx *cdb, + TALLOC_CTX *mem_ctx, + const char *name, +@@ -821,7 +865,6 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, + struct sss_domain_info *domain; + struct ldb_result *res; + TALLOC_CTX *tmp_ctx; +- struct ldb_dn *dn; + const char *tmp; + int ret, val; + uint32_t entry_cache_timeout; +@@ -833,23 +876,15 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) return ENOMEM; + +- dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb, +- "cn=%s,%s", name, CONFDB_DOMAIN_BASEDN); +- if (!dn) { +- ret = ENOMEM; +- goto done; +- } +- +- ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, +- LDB_SCOPE_BASE, NULL, NULL); +- if (ret != LDB_SUCCESS) { +- ret = EIO; +- goto done; +- } +- +- if (res->count != 1) { ++ ret = confdb_get_domain_section(tmp_ctx, cdb, CONFDB_DOMAIN_BASEDN, ++ name, &res); ++ if (ret == ENOENT) { + DEBUG(SSSDBG_FATAL_FAILURE, "Unknown domain [%s]\n", name); +- ret = ENOENT; ++ goto done; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Error %d: %s while retrieving %s\n", ++ ret, sss_strerror(ret), name); + goto done; + } + +@@ -1841,3 +1876,222 @@ int confdb_ensure_files_domain(struct confdb_ctx *cdb, + return activate_files_domain(cdb, implicit_files_dom_name); + #endif /* ADD_FILES_DOMAIN */ + } ++ ++static int confdb_get_parent_domain(TALLOC_CTX *mem_ctx, ++ const char *name, ++ struct confdb_ctx *cdb, ++ struct ldb_result *app_dom, ++ struct ldb_result **_parent_dom) ++{ ++ const char *inherit_from; ++ ++ inherit_from = ldb_msg_find_attr_as_string(app_dom->msgs[0], ++ CONFDB_DOMAIN_INHERIT_FROM, NULL); ++ if (inherit_from == NULL) { ++ DEBUG(SSSDBG_CONF_SETTINGS, ++ "%s does not inherit from any POSIX domain\n", name); ++ *_parent_dom = NULL; ++ return EOK; ++ } ++ ++ return confdb_get_domain_section(mem_ctx, cdb, ++ CONFDB_DOMAIN_BASEDN, inherit_from, ++ _parent_dom); ++} ++ ++static int confdb_add_app_domain(TALLOC_CTX *mem_ctx, ++ struct confdb_ctx *cdb, ++ const char *name) ++{ ++ char *cdb_path = NULL; ++ const char *val[2] = { NULL, NULL }; ++ int ret; ++ ++ cdb_path = talloc_asprintf(mem_ctx, CONFDB_DOMAIN_PATH_TMPL, name); ++ if (cdb_path == NULL) { ++ return ENOMEM; ++ } ++ ++ val[0] = CONFDB_DOMAIN_TYPE_APP; ++ ret = confdb_add_param(cdb, true, cdb_path, CONFDB_DOMAIN_TYPE, val); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add id_provider [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ return EOK; ++} ++ ++static int confdb_merge_parent_domain(const char *name, ++ struct confdb_ctx *cdb, ++ struct ldb_result *app_section) ++{ ++ int ret; ++ int ldb_flag; ++ struct ldb_result *parent_domain = NULL; ++ struct ldb_message *replace_msg = NULL; ++ struct ldb_message *app_msg = NULL; ++ struct ldb_dn *domain_dn; ++ TALLOC_CTX *tmp_ctx = NULL; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); ++ return ENOMEM; ++ } ++ ++ domain_dn = ldb_dn_new_fmt(tmp_ctx, ++ cdb->ldb, ++ "%s=%s,%s", ++ CONFDB_DOMAIN_ATTR, ++ name, ++ CONFDB_DOMAIN_BASEDN); ++ if (domain_dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* Copy the parent domain parameters */ ++ ret = confdb_get_parent_domain(tmp_ctx, name, cdb, ++ app_section, &parent_domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot retrieve the parent domain [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ if (parent_domain != NULL) { ++ replace_msg = ldb_msg_copy(tmp_ctx, parent_domain->msgs[0]); ++ if (replace_msg == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ replace_msg->dn = domain_dn; ++ ++ for (unsigned i = 0; i < replace_msg->num_elements; i++) { ++ replace_msg->elements[i].flags = LDB_FLAG_MOD_ADD; ++ } ++ ++ ret = ldb_modify(cdb->ldb, replace_msg); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Inheriting options from parent domain failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ } ++ ++ /* Finally, add any app-domain specific overrides */ ++ app_msg = ldb_msg_new(tmp_ctx); ++ if (app_msg == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ app_msg->dn = domain_dn; ++ ++ for (unsigned i = 0; i < app_section->msgs[0]->num_elements; i++) { ++ struct ldb_message_element *el = NULL; ++ ++ if (replace_msg != NULL) { ++ el = ldb_msg_find_element(replace_msg, ++ app_section->msgs[0]->elements[i].name); ++ if (el == NULL) { ++ /* Adding an element */ ++ ldb_flag = LDB_FLAG_MOD_ADD; ++ } else { ++ /* Overriding an element */ ++ ldb_flag = LDB_FLAG_MOD_REPLACE; ++ } ++ } else { ++ /* If there was no domain to inherit from, just add all */ ++ ldb_flag = LDB_FLAG_MOD_ADD; ++ } ++ ++ ret = ldb_msg_add(app_msg, ++ &app_section->msgs[0]->elements[i], ++ ldb_flag); ++ if (ret != EOK) { ++ continue; ++ } ++ } ++ ++ ret = ldb_modify(cdb->ldb, app_msg); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Adding app-specific options failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_LIBS, "Added a domain section for %s\n", name); ++ ret = EOK; ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++int confdb_expand_app_domains(struct confdb_ctx *cdb) ++{ ++ int ret; ++ char **domlist; ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_result *app_domain = NULL; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = confdb_get_string_as_list(cdb, tmp_ctx, ++ CONFDB_MONITOR_CONF_ENTRY, ++ CONFDB_MONITOR_ACTIVE_DOMAINS, ++ &domlist); ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "No domains configured, fatal error!\n"); ++ goto done; ++ } else if (ret != EOK ) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Fatal error retrieving domains list!\n"); ++ goto done; ++ } ++ ++ for (int i = 0; domlist[i]; i++) { ++ ret = confdb_get_domain_section(tmp_ctx, cdb, ++ CONFDB_APP_DOMAIN_BASEDN, domlist[i], ++ &app_domain); ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, ++ "%s is not an app domain\n", domlist[i]); ++ continue; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Error %d: %s while retrieving %s\n", ++ ret, sss_strerror(ret), domlist[i]); ++ goto done; ++ } ++ ++ ret = confdb_add_app_domain(tmp_ctx, cdb, domlist[i]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot add the app domain section [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = confdb_merge_parent_domain(domlist[i], cdb, app_domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot add options into the app domain section [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ } ++ ++ ret = EOK; ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index a4046610f3cdbdb832de8924bf4397fb0018f2db..5a8d377c312f641f544b1c7cf38826192462ea3c 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -164,6 +164,7 @@ + /* Domains */ + #define CONFDB_DOMAIN_PATH_TMPL "config/domain/%s" + #define CONFDB_DOMAIN_BASEDN "cn=domain,cn=config" ++#define CONFDB_APP_DOMAIN_BASEDN "cn=application,cn=config" + #define CONFDB_DOMAIN_ID_PROVIDER "id_provider" + #define CONFDB_DOMAIN_AUTH_PROVIDER "auth_provider" + #define CONFDB_DOMAIN_ACCESS_PROVIDER "access_provider" +@@ -212,6 +213,7 @@ + #define CONFDB_DOMAIN_TYPE "domain_type" + #define CONFDB_DOMAIN_TYPE_POSIX "posix" + #define CONFDB_DOMAIN_TYPE_APP "application" ++#define CONFDB_DOMAIN_INHERIT_FROM "inherit_from" + + /* Local Provider */ + #define CONFDB_LOCAL_DEFAULT_SHELL "default_shell" +@@ -398,6 +400,8 @@ int confdb_get_domains(struct confdb_ctx *cdb, + int confdb_ensure_files_domain(struct confdb_ctx *cdb, + const char *implicit_files_dom_name); + ++int confdb_expand_app_domains(struct confdb_ctx *cdb); ++ + /** + * Get a null-terminated linked-list of all domain names + * @param[in] mem_ctx The parent memory context for the value list +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 3c857236eaa55b313d176bc4bb479918163b60d5..8fd2d2c5236246394353a88c50d1510bd6233f77 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -12,6 +12,7 @@ section = secrets + section = kcm + section_re = ^secrets/users/[0-9]\+$ + section_re = ^domain/.*$ ++section_re = ^application/.*$ + + [rule/allowed_sssd_options] + validator = ini_allowed_options +@@ -286,7 +287,7 @@ option = responder_idle_timeout + + [rule/allowed_domain_options] + validator = ini_allowed_options +-section_re = ^domain/.*$ ++section_re = ^(domain|application)/.*$ + + option = debug + option = debug_level +@@ -684,3 +685,9 @@ option = ldap_user_ssh_public_key + option = ldap_user_uid_number + option = ldap_user_uuid + option = ldap_use_tokengroups ++ ++[rule/allowed_application_options] ++validator = ini_allowed_options ++section_re = ^application/.*$ ++ ++option = inherit_from +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 9abcff84a95ea1b27e36845e830cc125fdc89f90..8294793c765bfa6bf481693c7d7f206950454681 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -1539,6 +1539,10 @@ pam_account_locked_message = Account locked, please contact help desk. + id_provider=ldap only. + + ++ For an easy way to configure a non-POSIX domains, please ++ see the Application domains section. ++ ++ + Default: posix + + +@@ -2692,6 +2696,79 @@ subdomain_inherit = ldap_purge_cache_timeout + + + ++ ++ Application domains ++ ++ SSSD, with its D-Bus interface (see ++ ++ sssd-ifp ++ 5 ++ ) is appealing to applications ++ as a gateway to an LDAP directory where users and groups ++ are stored. However, contrary to the traditional SSSD ++ deployment where all users and groups either have POSIX ++ attributes or those attributes can be inferred from the ++ Windows SIDs, in many cases the users and groups in the ++ application support scenario have no POSIX attributes. ++ Instead of setting a ++ [domain/NAME] ++ section, the administrator can set up an ++ [application/NAME] ++ section that internally represents a domain with type ++ application optionally inherits settings ++ from a tradition SSSD domain. ++ ++ ++ Please note that the application domain must still be ++ explicitly enabled in the domains parameter ++ so that the lookup order between the application domain ++ and its POSIX sibling domain is set correctly. ++ ++ ++ Application domain parameters ++ ++ inherit_from (string) ++ ++ ++ The SSSD POSIX-type domain the application ++ domain inherits all settings from. The ++ application domain can moreover add its own ++ settings to the application settings that augment ++ or override the sibling ++ domain settings. ++ ++ ++ Default: Not set ++ ++ ++ ++ ++ ++ The following example illustrates the use of an application ++ domain. In this setup, the POSIX domain is connected to an LDAP ++ server and is used by the OS through the NSS responder. In addition, ++ the application domains also requests the telephoneNumber attribute, ++ stores it as the phone attribute in the cache and makes the phone ++ attribute reachable through the D-Bus interface. ++ ++ ++[sssd] ++domains = appdom, posixdom ++ ++[ifp] ++user_attributes = +phone ++ ++[domain/posixdom] ++id_provider = ldap ++ldap_uri = ldap://ldap.example.com ++ldap_search_base = dc=example,dc=com ++ ++[application/appdom] ++inherit_from = posixdom ++ldap_user_extra_attrs = phone:telephoneNumber ++ ++ ++ + + The local domain section + +diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c +index 7e7b5a07d11aecf1c0b11592213b90d385fd5076..2753b46667f7ae0b022776862c67a327d3356d6d 100644 +--- a/src/monitor/monitor.c ++++ b/src/monitor/monitor.c +@@ -1064,6 +1064,14 @@ static int get_monitor_config(struct mt_ctx *ctx) + /* Not fatal */ + } + ++ ret = confdb_expand_app_domains(ctx->cdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to expand application domains\n"); ++ /* This must not be fatal so that SSSD keeps running and lets ++ * admin correct the error. ++ */ ++ } ++ + ret = confdb_get_domains(ctx->cdb, &ctx->domains); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "No domains configured.\n"); +-- +2.9.3 + diff --git a/SOURCES/0062-SDAP-add-enterprise-principal-strings-for-user-searc.patch b/SOURCES/0062-SDAP-add-enterprise-principal-strings-for-user-searc.patch deleted file mode 100644 index 2077c69..0000000 --- a/SOURCES/0062-SDAP-add-enterprise-principal-strings-for-user-searc.patch +++ /dev/null @@ -1,201 +0,0 @@ -From 0274cb7aa22e388e46580b288a7dd957ad955e04 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 22 Jul 2016 20:10:42 +0200 -Subject: [PATCH 62/62] SDAP: add enterprise principal strings for user - searches - -Unfortunately principal aliases with an alternative realm are stored in -IPA as the string representation of an enterprise principal, i.e. -name\@alt.realm@IPA.REALM. To be able to lookup the alternative -principal in LDAP properly the UPN search filter is extended to search -for this type of name as well. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 50a7a92f92e1584702bf25e61a50cb1c09c7e260) ---- - src/providers/ldap/ldap_common.h | 5 +++++ - src/providers/ldap/ldap_id.c | 10 +++++++-- - src/providers/ldap/sdap_async_initgroups.c | 9 ++++++-- - src/providers/ldap/sdap_utils.c | 28 ++++++++++++++++++++++++ - src/tests/cmocka/test_nested_groups.c | 34 ++++++++++++++++++++++++++++++ - 5 files changed, 82 insertions(+), 4 deletions(-) - -diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h -index b39f6789275cf49dd69068ae3de0628b582e4cc5..acdcf47cc5992609cdbf73e4ed9655eade55e214 100644 ---- a/src/providers/ldap/ldap_common.h -+++ b/src/providers/ldap/ldap_common.h -@@ -300,6 +300,11 @@ char *sdap_combine_filters(TALLOC_CTX *mem_ctx, - const char *base_filter, - const char *extra_filter); - -+char *get_enterprise_principal_string_filter(TALLOC_CTX *mem_ctx, -+ const char *attr_name, -+ const char *princ, -+ struct dp_option *sdap_basic_opts); -+ - char *sdap_get_access_filter(TALLOC_CTX *mem_ctx, - const char *base_filter); - -diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c -index 5b303ddbd46fd44646cdd50856c784640426ee25..beb31fba16be76ba2ac01f99b87ee6362704f417 100644 ---- a/src/providers/ldap/ldap_id.c -+++ b/src/providers/ldap/ldap_id.c -@@ -89,6 +89,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, - enum idmap_error_code err; - char *sid; - char *user_filter = NULL; -+ char *ep_filter; - - req = tevent_req_create(memctx, &state, struct users_get_state); - if (!req) return NULL; -@@ -131,12 +132,17 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, - if (ret != EOK) { - goto done; - } -+ -+ ep_filter = get_enterprise_principal_string_filter(state, -+ ctx->opts->user_map[SDAP_AT_USER_PRINC].name, -+ clean_value, ctx->opts->basic); - /* TODO: Do we have to check the attribute names more carefully? */ -- user_filter = talloc_asprintf(state, "(|(%s=%s)(%s=%s))", -+ user_filter = talloc_asprintf(state, "(|(%s=%s)(%s=%s)%s)", - ctx->opts->user_map[SDAP_AT_USER_PRINC].name, - clean_value, - ctx->opts->user_map[SDAP_AT_USER_EMAIL].name, -- clean_value); -+ clean_value, -+ ep_filter == NULL ? "" : ep_filter); - talloc_zfree(clean_value); - if (user_filter == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); -diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c -index 0a42b18662a8fe12cf048aadfef257b5d9cb48a3..7029427724cc37a4508e11ef5448b421e94dc787 100644 ---- a/src/providers/ldap/sdap_async_initgroups.c -+++ b/src/providers/ldap/sdap_async_initgroups.c -@@ -2682,7 +2682,8 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, - int ret; - char *clean_name; - bool use_id_mapping; -- const char *search_attr; -+ const char *search_attr = NULL; -+ char *ep_filter; - - DEBUG(SSSDBG_TRACE_ALL, "Retrieving info for initgroups call\n"); - -@@ -2743,13 +2744,17 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, - return NULL; - } - -+ ep_filter = get_enterprise_principal_string_filter(state, -+ state->opts->user_map[SDAP_AT_USER_PRINC].name, -+ clean_name, state->opts->basic); - state->user_base_filter = - talloc_asprintf(state, -- "(&(|(%s=%s)(%s=%s))(objectclass=%s)", -+ "(&(|(%s=%s)(%s=%s)%s)(objectclass=%s)", - state->opts->user_map[SDAP_AT_USER_PRINC].name, - clean_name, - state->opts->user_map[SDAP_AT_USER_EMAIL].name, - clean_name, -+ ep_filter == NULL ? "" : ep_filter, - state->opts->user_map[SDAP_OC_USER].name); - if (state->user_base_filter == NULL) { - talloc_zfree(req); -diff --git a/src/providers/ldap/sdap_utils.c b/src/providers/ldap/sdap_utils.c -index a3a9642171ca057be5a59dfae192803b84c501c8..0ac3ab2e416d887d00480b5123859c611f514274 100644 ---- a/src/providers/ldap/sdap_utils.c -+++ b/src/providers/ldap/sdap_utils.c -@@ -227,3 +227,31 @@ char *sdap_combine_filters(TALLOC_CTX *mem_ctx, - { - return sdap_combine_filters_ex(mem_ctx, '&', base_filter, extra_filter); - } -+ -+char *get_enterprise_principal_string_filter(TALLOC_CTX *mem_ctx, -+ const char *attr_name, -+ const char *princ, -+ struct dp_option *sdap_basic_opts) -+{ -+ const char *realm; -+ char *p; -+ -+ if (attr_name == NULL || princ == NULL || sdap_basic_opts == NULL) { -+ return NULL; -+ } -+ -+ realm = dp_opt_get_cstring(sdap_basic_opts, SDAP_KRB5_REALM); -+ if (realm == NULL) { -+ return NULL; -+ } -+ -+ p = strchr(princ, '@'); -+ if (p == NULL) { -+ return NULL; -+ } -+ -+ return talloc_asprintf(mem_ctx, "(%s=%.*s\\\\@%s@%s)", attr_name, -+ (int) (p - princ), -+ princ, -+ p + 1, realm); -+} -diff --git a/src/tests/cmocka/test_nested_groups.c b/src/tests/cmocka/test_nested_groups.c -index 6af7e1f4393992e7f16d72b86e40664487896ea1..c8e80f29fb65f8f8935fea32cd4bf3e16de7d06f 100644 ---- a/src/tests/cmocka/test_nested_groups.c -+++ b/src/tests/cmocka/test_nested_groups.c -@@ -31,6 +31,7 @@ - #include "providers/ldap/sdap.h" - #include "providers/ldap/sdap_idmap.h" - #include "providers/ldap/sdap_async_private.h" -+#include "providers/ldap/ldap_opts.h" - - #define TESTS_PATH "tp_" BASE_FILE_STEM - #define TEST_CONF_DB "test_ldap_nested_groups_conf.ldb" -@@ -1242,6 +1243,38 @@ static void nested_group_external_member_test(void **state) - nested_group.gr_name); - } - -+static void test_get_enterprise_principal_string_filter(void **state) -+{ -+ int ret; -+ char *ep_filter; -+ struct dp_option *no_krb5_realm_opt = default_basic_opts; -+ -+ struct dp_option *krb5_realm_opt; -+ -+ ret = dp_copy_defaults(NULL, default_basic_opts, SDAP_OPTS_BASIC, -+ &krb5_realm_opt); -+ assert_int_equal(ret, EOK); -+ -+ ret = dp_opt_set_string(krb5_realm_opt, SDAP_KRB5_REALM, "TEST.DOM"); -+ assert_int_equal(ret, EOK); -+ -+ ep_filter = get_enterprise_principal_string_filter(NULL, NULL, NULL, NULL); -+ assert_null(ep_filter); -+ -+ ep_filter = get_enterprise_principal_string_filter(NULL, "aBC", "p@d.c", -+ no_krb5_realm_opt); -+ assert_null(ep_filter); -+ -+ ep_filter = get_enterprise_principal_string_filter(NULL, "aBC", "p", -+ krb5_realm_opt); -+ assert_null(ep_filter); -+ -+ ep_filter = get_enterprise_principal_string_filter(NULL, "aBC", "p@d.c", -+ krb5_realm_opt); -+ assert_non_null(ep_filter); -+ assert_string_equal(ep_filter, "(aBC=p\\\\@d.c@TEST.DOM)"); -+ talloc_free(ep_filter); -+} - - int main(int argc, const char *argv[]) - { -@@ -1268,6 +1301,7 @@ int main(int argc, const char *argv[]) - cmocka_unit_test_setup_teardown(nested_group_external_member_test, - nested_group_external_member_setup, - nested_group_external_member_teardown), -+ cmocka_unit_test(test_get_enterprise_principal_string_filter), - }; - - /* Set debug level to invalid value so we can deside if -d 0 was used. */ --- -2.4.11 - diff --git a/SOURCES/0063-CACHE_REQ-Domain-type-selection-in-cache_req.patch b/SOURCES/0063-CACHE_REQ-Domain-type-selection-in-cache_req.patch new file mode 100644 index 0000000..86b6c73 --- /dev/null +++ b/SOURCES/0063-CACHE_REQ-Domain-type-selection-in-cache_req.patch @@ -0,0 +1,976 @@ +From 5519295726bb2a0e88475e1d8deff0b8c0f65119 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 24 Mar 2017 10:39:12 +0100 +Subject: [PATCH 63/72] CACHE_REQ: Domain type selection in cache_req +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related to: + https://pagure.io/SSSD/sssd/issue/3310 + +Adds a new enumeration cache_req_dom_type. It is a tri-state that +allows the caller to select which domains can be contacted - either only +POSIX, only application domains or any type. + +Not all plugins of cache_req have the new parameter added -- only those +that are usable/useful in a non-POSIX environment. For example, it makes +no sense to allow the selection for calls by ID because those are +inherently POSIX-specific. Also, services or netgroups are supported +only coming from POSIX domains. + +At the moment, the patch should not change any behaviour as all calls +default to contacting POSIX domains only. + +Reviewed-by: Pavel Březina +--- + src/responder/common/cache_req/cache_req.c | 80 ++++++++++++++++++++-- + src/responder/common/cache_req/cache_req.h | 19 +++++ + src/responder/common/cache_req/cache_req_private.h | 3 + + .../cache_req/plugins/cache_req_enum_groups.c | 4 +- + .../common/cache_req/plugins/cache_req_enum_svc.c | 3 +- + .../cache_req/plugins/cache_req_enum_users.c | 4 +- + .../cache_req/plugins/cache_req_group_by_filter.c | 5 +- + .../cache_req/plugins/cache_req_group_by_id.c | 4 +- + .../cache_req/plugins/cache_req_group_by_name.c | 5 +- + .../cache_req/plugins/cache_req_host_by_name.c | 4 +- + .../plugins/cache_req_initgroups_by_name.c | 5 +- + .../cache_req/plugins/cache_req_netgroup_by_name.c | 4 +- + .../cache_req/plugins/cache_req_object_by_id.c | 4 +- + .../cache_req/plugins/cache_req_object_by_name.c | 4 +- + .../cache_req/plugins/cache_req_object_by_sid.c | 4 +- + .../cache_req/plugins/cache_req_svc_by_name.c | 4 +- + .../cache_req/plugins/cache_req_svc_by_port.c | 4 +- + .../cache_req/plugins/cache_req_user_by_cert.c | 4 +- + .../cache_req/plugins/cache_req_user_by_filter.c | 5 +- + .../cache_req/plugins/cache_req_user_by_id.c | 4 +- + .../cache_req/plugins/cache_req_user_by_name.c | 9 ++- + src/responder/ifp/ifp_groups.c | 14 +++- + src/responder/ifp/ifp_users.c | 19 +++-- + src/responder/ifp/ifpsrv_cmd.c | 3 +- + src/responder/nss/nss_enum.c | 2 +- + src/responder/nss/nss_get_object.c | 3 +- + src/responder/pam/pamsrv_cmd.c | 5 +- + src/responder/sudo/sudosrv_get_sudorules.c | 3 +- + src/tests/cmocka/test_responder_cache_req.c | 62 ++++++++++++++--- + 29 files changed, 246 insertions(+), 47 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index 483126396f8addbad744ae03bfc739801cd0c18b..3a5fecf34427437bbf95317e05c5bd8b07b4537d 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -89,12 +89,31 @@ static errno_t cache_req_set_plugin(struct cache_req *cr, + return EOK; + } + ++static const char * ++cache_req_dom_type_as_str(struct cache_req *cr) ++{ ++ if (cr == NULL) { ++ return "BUG: Invalid cache_req pointer\n"; ++ } ++ switch (cr->req_dom_type) { ++ case CACHE_REQ_POSIX_DOM: ++ return "POSIX-only"; ++ case CACHE_REQ_APPLICATION_DOM: ++ return "Application-only"; ++ case CACHE_REQ_ANY_DOM: ++ return "Any"; ++ } ++ ++ return "Unknown"; ++} ++ + static struct cache_req * + cache_req_create(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct cache_req_data *data, + struct sss_nc_ctx *ncache, +- int midpoint) ++ int midpoint, ++ enum cache_req_dom_type req_dom_type) + { + struct cache_req *cr; + errno_t ret; +@@ -108,6 +127,7 @@ cache_req_create(TALLOC_CTX *mem_ctx, + cr->data = data; + cr->ncache = ncache; + cr->midpoint = midpoint; ++ cr->req_dom_type = req_dom_type; + cr->req_start = time(NULL); + + /* It is perfectly fine to just overflow here. */ +@@ -145,8 +165,8 @@ cache_req_set_name(struct cache_req *cr, const char *name) + } + + static bool +-cache_req_validate_domain(struct cache_req *cr, +- struct sss_domain_info *domain) ++cache_req_validate_domain_enumeration(struct cache_req *cr, ++ struct sss_domain_info *domain) + { + if (!cr->plugin->require_enumeration) { + return true; +@@ -164,6 +184,52 @@ cache_req_validate_domain(struct cache_req *cr, + return true; + } + ++static bool ++cache_req_validate_domain_type(struct cache_req *cr, ++ struct sss_domain_info *domain) ++{ ++ bool valid = false; ++ ++ switch (cr->req_dom_type) { ++ case CACHE_REQ_POSIX_DOM: ++ valid = domain->type == DOM_TYPE_POSIX ? true : false; ++ break; ++ case CACHE_REQ_APPLICATION_DOM: ++ valid = domain->type == DOM_TYPE_APPLICATION ? true : false; ++ break; ++ case CACHE_REQ_ANY_DOM: ++ valid = true; ++ break; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, ++ "Request type %s for domain %s type %s is %svalid\n", ++ cache_req_dom_type_as_str(cr), ++ domain->name, ++ sss_domain_type_str(domain), ++ valid ? "" : "not "); ++ return valid; ++} ++ ++static bool ++cache_req_validate_domain(struct cache_req *cr, ++ struct sss_domain_info *domain) ++{ ++ bool ok; ++ ++ ok = cache_req_validate_domain_enumeration(cr, domain); ++ if (ok == false) { ++ return false; ++ } ++ ++ ok = cache_req_validate_domain_type(cr, domain); ++ if (ok == false) { ++ return false; ++ } ++ ++ return true; ++} ++ + static errno_t + cache_req_is_well_known_object(TALLOC_CTX *mem_ctx, + struct cache_req *cr, +@@ -651,6 +717,7 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int midpoint, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + struct cache_req_data *data) + { +@@ -667,7 +734,8 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, + } + + state->ev = ev; +- state->cr = cr = cache_req_create(state, rctx, data, ncache, midpoint); ++ state->cr = cr = cache_req_create(state, rctx, data, ++ ncache, midpoint, req_dom_type); + if (state->cr == NULL) { + ret = ENOMEM; + goto done; +@@ -952,13 +1020,15 @@ cache_req_steal_data_and_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int cache_refresh_percent, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + struct cache_req_data *data) + { + struct tevent_req *req; + + req = cache_req_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ req_dom_type, domain, data); + if (req == NULL) { + talloc_zfree(data); + return NULL; +diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h +index d0e5ff43921467fc191fd5cc7d5b49cc039b7f67..c04b2fba6f0445dcfcc9cfe1b5963ac975c39118 100644 +--- a/src/responder/common/cache_req/cache_req.h ++++ b/src/responder/common/cache_req/cache_req.h +@@ -57,6 +57,18 @@ enum cache_req_type { + CACHE_REQ_SENTINEL + }; + ++/* Whether to limit the request type to a certain domain type ++ * (POSIX/non-POSIX) ++ */ ++enum cache_req_dom_type { ++ /* Only look up data in POSIX domains */ ++ CACHE_REQ_POSIX_DOM, ++ /* Only look up data in application domains */ ++ CACHE_REQ_APPLICATION_DOM, ++ /* Look up data in any domain type */ ++ CACHE_REQ_ANY_DOM ++}; ++ + /* Input data. */ + + struct cache_req_data; +@@ -172,6 +184,7 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int midpoint, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + struct cache_req_data *data); + +@@ -191,6 +204,7 @@ cache_req_user_by_name_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int cache_refresh_percent, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + const char *name); + +@@ -228,6 +242,7 @@ cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int cache_refresh_percent, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + const char *pem_cert); + +@@ -240,6 +255,7 @@ cache_req_group_by_name_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int cache_refresh_percent, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + const char *name); + +@@ -264,6 +280,7 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int cache_refresh_percent, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + const char *name); + +@@ -274,6 +291,7 @@ struct tevent_req * + cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct resp_ctx *rctx, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + const char *filter); + +@@ -284,6 +302,7 @@ struct tevent_req * + cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct resp_ctx *rctx, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + const char *filter); + +diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h +index 2d3c1870795e4fd5667f603280edcee24f926220..851005c389f994b1bd2d04cda9b68df8b18492cc 100644 +--- a/src/responder/common/cache_req/cache_req_private.h ++++ b/src/responder/common/cache_req/cache_req_private.h +@@ -42,6 +42,8 @@ struct cache_req { + struct sss_domain_info *domain; + bool cache_first; + bool bypass_cache; ++ /* Only contact domains with this type */ ++ enum cache_req_dom_type req_dom_type; + + /* Debug information */ + uint32_t reqid; +@@ -108,6 +110,7 @@ cache_req_steal_data_and_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int cache_refresh_percent, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + struct cache_req_data *data); + +diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c +index dbb40c98339cc9295e3678e05340396aff51ac78..49ce3508e678862e4389657187b9659ce90fbd1c 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c ++++ b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c +@@ -96,5 +96,7 @@ cache_req_enum_groups_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, domain, ++ data); + } +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 28dea33c601f500b9c7af0de3eb9e1c342f03522..499b994738d62707b4e86d5a8383e3e2b82e8c57 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 +@@ -97,5 +97,6 @@ cache_req_enum_svc_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, domain, data); + } +diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_users.c b/src/responder/common/cache_req/plugins/cache_req_enum_users.c +index 3b1a85841e3ed853cd329dfa9d762cb7a05cbd43..b635354be6e9d2e2e2af1a6f867ac68e6cf7f085 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_enum_users.c ++++ b/src/responder/common/cache_req/plugins/cache_req_enum_users.c +@@ -96,5 +96,7 @@ cache_req_enum_users_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, domain, ++ data); + } +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 6ce6ae0d63967ac50b813a47ac938251619948da..4377a476c36e5e03c8533bc62335b84fa1cee3ff 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 +@@ -140,6 +140,7 @@ struct tevent_req * + cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct resp_ctx *rctx, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + const char *filter) + { +@@ -151,5 +152,7 @@ cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, NULL, +- 0, domain, data); ++ 0, ++ req_dom_type, domain, ++ data); + } +diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +index e98f76f8cd20742b81ae247df61db159d2584a17..ad5b7d890a42f29b586ab8e0943fef3dfab1162d 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +@@ -166,5 +166,7 @@ cache_req_group_by_id_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, 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 af6f23ccfd68f952027462ba3e74ed7219d04651..de1e8f9442273acf386a2278b06f28ee63a7e3c6 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 +@@ -205,6 +205,7 @@ cache_req_group_by_name_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int cache_refresh_percent, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + const char *name) + { +@@ -216,5 +217,7 @@ cache_req_group_by_name_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ req_dom_type, domain, ++ data); + } +diff --git a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c +index 77b46831fec3abc4126ef9d9be67221469801094..1171cd63fac5cc1d36b31bf8a069f059705cae90 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c +@@ -117,5 +117,7 @@ cache_req_host_by_name_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, 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 307b65a24282838b99c472b50a71f06865aed3f0..f100aefe5c92279cde7e3209c7f48f5e2b35f135 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 +@@ -220,6 +220,7 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int cache_refresh_percent, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + const char *name) + { +@@ -231,5 +232,7 @@ cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ req_dom_type, 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 e49d6d84a41ce8dabf18c87373826f8e7b684bda..ab3e553d3ecb8ae09094dcfc938ed0ac01925327 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 +@@ -150,5 +150,7 @@ cache_req_netgroup_by_name_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, domain, ++ data); + } +diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +index 046e313c83d1d4c75237b047be779201b8a5d3c0..9557bd15270b2eb1a0671f9ef91033efac29c3ac 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +@@ -134,5 +134,7 @@ cache_req_object_by_id_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, 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 74d2b3dea287e890b38e4d5bb176ad2dc6337b7e..e236d1fa4aadcd87b192d34ebaf5f9ad8908b6c2 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 +@@ -228,5 +228,7 @@ cache_req_object_by_name_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, domain, ++ data); + } +diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c +index ab577663111cfd424e7f46308b2621af7f1ca264..dfec79da07d669165205a767cab22c2254686134 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c ++++ b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c +@@ -143,5 +143,7 @@ cache_req_object_by_sid_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, 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 ef13f097a8ae78ec9db5b7f6e14924b511578b34..b2bfb26ffed1a60ed8389fa89b0e728c8c6cf76c 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 +@@ -175,5 +175,7 @@ cache_req_svc_by_name_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, 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 afa2eeeda12794de26e798aee4b88900bc87ed93..0e48437f4b64d26112be88af1eebc20f012b70fd 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 +@@ -149,5 +149,7 @@ cache_req_svc_by_port_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, domain, ++ data); + } +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c +index f237c8d0fe3faf5aea553480f3f92eb279209a20..286a34db276e0098060982c572e2a68ceceebf60 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c +@@ -105,6 +105,7 @@ cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int cache_refresh_percent, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + const char *pem_cert) + { +@@ -117,5 +118,6 @@ cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx, + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, + cache_refresh_percent, +- domain, data); ++ req_dom_type, 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 eb71b42dad3a805298df0c8425409d571befb31b..c476814373cd784bf8dbbea1da7b010afe5bb4e4 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 +@@ -140,6 +140,7 @@ struct tevent_req * + cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct resp_ctx *rctx, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + const char *filter) + { +@@ -151,5 +152,7 @@ cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, NULL, +- 0, domain, data); ++ 0, ++ req_dom_type, domain, ++ data); + } +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +index fa783714b7c67ca029d18a223b64a3a69e3e6929..9ba73292e5dc518e86c6e00e7e493d6871f28e70 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +@@ -166,5 +166,7 @@ cache_req_user_by_id_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, 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 0670febdce2d51e0373045570dd07f56255db7bc..15da7d0d20b1ac97511a226daecc8ef7e7d2e7e4 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 +@@ -210,6 +210,7 @@ cache_req_user_by_name_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_nc_ctx *ncache, + int cache_refresh_percent, ++ enum cache_req_dom_type req_dom_type, + const char *domain, + const char *name) + { +@@ -221,7 +222,9 @@ cache_req_user_by_name_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ req_dom_type, domain, ++ data); + } + + struct tevent_req * +@@ -243,5 +246,7 @@ cache_req_user_by_name_attrs_send(TALLOC_CTX *mem_ctx, + } + + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, +- cache_refresh_percent, domain, data); ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, domain, ++ data); + } +diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c +index 94d1e84cc9de75727d3c47c0a5a24790d21ce132..99908e96bd971bce4b4e9064a77d8413f837d743 100644 +--- a/src/responder/ifp/ifp_groups.c ++++ b/src/responder/ifp/ifp_groups.c +@@ -118,7 +118,9 @@ int ifp_groups_find_by_name(struct sbus_request *sbus_req, + } + + req = cache_req_group_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, +- ctx->rctx->ncache, 0, NULL, name); ++ ctx->rctx->ncache, 0, ++ CACHE_REQ_POSIX_DOM, NULL, ++ name); + if (req == NULL) { + return ENOMEM; + } +@@ -271,6 +273,7 @@ static int ifp_groups_list_by_name_step(struct ifp_list_ctx *list_ctx) + req = cache_req_group_by_filter_send(list_ctx, + list_ctx->ctx->rctx->ev, + list_ctx->ctx->rctx, ++ CACHE_REQ_POSIX_DOM, + list_ctx->dom->name, + list_ctx->filter); + if (req == NULL) { +@@ -355,7 +358,8 @@ int ifp_groups_list_by_domain_and_name(struct sbus_request *sbus_req, + } + + req = cache_req_group_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx, +- domain, filter); ++ CACHE_REQ_POSIX_DOM, ++ domain, filter); + if (req == NULL) { + return ENOMEM; + } +@@ -522,7 +526,10 @@ static struct tevent_req *resolv_ghosts_send(TALLOC_CTX *mem_ctx, + } + + subreq = cache_req_group_by_name_send(state, ev, ctx->rctx, +- ctx->rctx->ncache, 0, domain->name, name); ++ ctx->rctx->ncache, 0, ++ CACHE_REQ_POSIX_DOM, ++ domain->name, ++ name); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; +@@ -601,6 +608,7 @@ errno_t resolv_ghosts_step(struct tevent_req *req) + + subreq = cache_req_user_by_name_send(state, state->ev, state->ctx->rctx, + state->ctx->rctx->ncache, 0, ++ CACHE_REQ_POSIX_DOM, + state->domain->name, + state->ghosts[state->index]); + if (subreq == NULL) { +diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c +index cc78300f31e863fcb5366e18a14abc597c6f7ddb..436bb268fa9c78d72fb744e0d338aa561a7d8764 100644 +--- a/src/responder/ifp/ifp_users.c ++++ b/src/responder/ifp/ifp_users.c +@@ -99,7 +99,9 @@ int ifp_users_find_by_name(struct sbus_request *sbus_req, + } + + req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, +- ctx->rctx->ncache, 0, NULL, name); ++ ctx->rctx->ncache, 0, ++ CACHE_REQ_POSIX_DOM, ++ NULL, name); + if (req == NULL) { + return ENOMEM; + } +@@ -253,7 +255,9 @@ int ifp_users_find_by_cert(struct sbus_request *sbus_req, void *data, + } + + req = cache_req_user_by_cert_send(sbus_req, ctx->rctx->ev, ctx->rctx, +- ctx->rctx->ncache, 0, NULL, derb64); ++ ctx->rctx->ncache, 0, ++ CACHE_REQ_POSIX_DOM, NULL, ++ derb64); + if (req == NULL) { + return ENOMEM; + } +@@ -367,6 +371,7 @@ static int ifp_users_list_by_cert_step(struct ifp_list_ctx *list_ctx) + list_ctx->ctx->rctx, + list_ctx->ctx->rctx->ncache, + 0, ++ CACHE_REQ_POSIX_DOM, + list_ctx->dom->name, + list_ctx->filter); + if (req == NULL) { +@@ -532,7 +537,9 @@ int ifp_users_find_by_name_and_cert(struct sbus_request *sbus_req, void *data, + + if (name_and_cert_ctx->name != NULL) { + req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, +- ctx->rctx->ncache, 0, NULL, ++ ctx->rctx->ncache, 0, ++ CACHE_REQ_POSIX_DOM, ++ NULL, + name_and_cert_ctx->name); + if (req == NULL) { + return ENOMEM; +@@ -614,6 +621,7 @@ static int ifp_users_find_by_name_and_cert_step( + list_ctx->ctx->rctx, + list_ctx->ctx->rctx->ncache, + 0, ++ CACHE_REQ_POSIX_DOM, + list_ctx->dom->name, + list_ctx->filter); + if (req == NULL) { +@@ -774,6 +782,7 @@ static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx) + req = cache_req_user_by_filter_send(list_ctx, + list_ctx->ctx->rctx->ev, + list_ctx->ctx->rctx, ++ CACHE_REQ_POSIX_DOM, + list_ctx->dom->name, + list_ctx->filter); + if (req == NULL) { +@@ -858,6 +867,7 @@ int ifp_users_list_by_domain_and_name(struct sbus_request *sbus_req, + } + + req = cache_req_user_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx, ++ CACHE_REQ_POSIX_DOM, + domain, filter); + if (req == NULL) { + return ENOMEM; +@@ -1102,7 +1112,8 @@ int ifp_users_user_update_groups_list(struct sbus_request *sbus_req, + } + + req = cache_req_initgr_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, +- ctx->rctx->ncache, 0, domain->name, ++ ctx->rctx->ncache, 0, ++ CACHE_REQ_POSIX_DOM, domain->name, + username); + if (req == NULL) { + return ENOMEM; +diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c +index 07edcddffa1091f8bbcf79a25962aadc791bb890..118b5083b14bf5692c6fdd7ba90668fe514aa89d 100644 +--- a/src/responder/ifp/ifpsrv_cmd.c ++++ b/src/responder/ifp/ifpsrv_cmd.c +@@ -509,7 +509,8 @@ ifp_user_get_attr_lookup(struct tevent_req *subreq) + } + + subreq = cache_req_send(state, state->rctx->ev, state->rctx, +- state->ncache, 0, state->domname, data); ++ state->ncache, 0, CACHE_REQ_POSIX_DOM, ++ state->domname, data); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; +diff --git a/src/responder/nss/nss_enum.c b/src/responder/nss/nss_enum.c +index b1cce2cde43ece735285c132d0127c142ee83cb0..aa7d8428f37e943a6b5904495c40ad4b8011b767 100644 +--- a/src/responder/nss/nss_enum.c ++++ b/src/responder/nss/nss_enum.c +@@ -93,7 +93,7 @@ nss_setent_internal_send(TALLOC_CTX *mem_ctx, + /* Create new object. */ + state->enum_ctx->is_ready = false; + subreq = cache_req_send(req, ev, cli_ctx->rctx, cli_ctx->rctx->ncache, +- 0, NULL, data); ++ 0, CACHE_REQ_POSIX_DOM, NULL, data); + if (subreq == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send cache request!\n"); + ret = ENOMEM; +diff --git a/src/responder/nss/nss_get_object.c b/src/responder/nss/nss_get_object.c +index f83dd393c0e333d8914802e005672a15a51d5939..9058793ea2d72b57003a7219414af6a0f0c5b89e 100644 +--- a/src/responder/nss/nss_get_object.c ++++ b/src/responder/nss/nss_get_object.c +@@ -190,7 +190,8 @@ nss_get_object_send(TALLOC_CTX *mem_ctx, + } + + subreq = cache_req_send(req, ev, cli_ctx->rctx, cli_ctx->rctx->ncache, +- state->nss_ctx->cache_refresh_percent, NULL, data); ++ state->nss_ctx->cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, NULL, data); + if (subreq == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send cache request!\n"); + ret = ENOMEM; +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index ba2563c11885ff39681c2ef432acaedf26702b64..fa6d2cc10fe1404196f9d9221a469d7a9a768211 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1315,7 +1315,9 @@ static void pam_forwarder_cert_cb(struct tevent_req *req) + + + req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx, +- pctx->rctx->ncache, 0, NULL, cert); ++ pctx->rctx->ncache, 0, ++ CACHE_REQ_POSIX_DOM, NULL, ++ cert); + if (req == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n"); + ret = ENOMEM; +@@ -1507,6 +1509,7 @@ static int pam_check_user_search(struct pam_auth_req *preq) + preq->cctx->rctx, + preq->cctx->rctx->ncache, + 0, ++ CACHE_REQ_POSIX_DOM, + preq->pd->domain, + data); + if (!dpreq) { +diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c +index 52dfd5c709e48f0d4610a4b384962fbc2869312b..cfdbfc9c9c66d96f774822d6a4d4aaaf1327abe3 100644 +--- a/src/responder/sudo/sudosrv_get_sudorules.c ++++ b/src/responder/sudo/sudosrv_get_sudorules.c +@@ -644,7 +644,8 @@ struct tevent_req *sudosrv_get_rules_send(TALLOC_CTX *mem_ctx, + DEBUG(SSSDBG_TRACE_FUNC, "Running initgroups for [%s]\n", username); + + subreq = cache_req_initgr_by_name_send(state, ev, sudo_ctx->rctx, +- sudo_ctx->rctx->ncache, 0, NULL, ++ sudo_ctx->rctx->ncache, 0, ++ CACHE_REQ_POSIX_DOM, NULL, + username); + if (subreq == NULL) { + ret = ENOMEM; +diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c +index 5f1e5350eaf1d85de376c94731f0bd678f884a1d..80086232fd437876c2b190fb972c2ee3194d9efd 100644 +--- a/src/tests/cmocka/test_responder_cache_req.c ++++ b/src/tests/cmocka/test_responder_cache_req.c +@@ -84,6 +84,28 @@ struct test_group { + talloc_free(req_mem_ctx); \ + } while (0) + ++#define run_cache_req_domtype(ctx, send_fn, done_fn, dom, crp, domtype, lookup, expret) do { \ ++ TALLOC_CTX *req_mem_ctx; \ ++ struct tevent_req *req; \ ++ errno_t ret; \ ++ \ ++ req_mem_ctx = talloc_new(global_talloc_context); \ ++ check_leaks_push(req_mem_ctx); \ ++ \ ++ req = send_fn(req_mem_ctx, ctx->tctx->ev, ctx->rctx, \ ++ ctx->ncache, crp, \ ++ domtype, \ ++ (dom == NULL ? NULL : dom->name), lookup); \ ++ assert_non_null(req); \ ++ tevent_req_set_callback(req, done_fn, ctx); \ ++ \ ++ ret = test_ev_loop(ctx->tctx); \ ++ assert_int_equal(ret, expret); \ ++ assert_true(check_leaks_pop(req_mem_ctx)); \ ++ \ ++ talloc_free(req_mem_ctx); \ ++} while (0) ++ + struct cache_req_test_ctx { + struct sss_test_ctx *tctx; + struct resp_ctx *rctx; +@@ -211,9 +233,11 @@ static void run_user_by_name(struct cache_req_test_ctx *test_ctx, + int cache_refresh_percent, + errno_t exp_ret) + { +- run_cache_req(test_ctx, cache_req_user_by_name_send, +- cache_req_user_by_name_test_done, domain, +- cache_refresh_percent, users[0].short_name, exp_ret); ++ run_cache_req_domtype(test_ctx, cache_req_user_by_name_send, ++ cache_req_user_by_name_test_done, domain, ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, ++ users[0].short_name, exp_ret); + } + + static void run_user_by_upn(struct cache_req_test_ctx *test_ctx, +@@ -221,9 +245,11 @@ static void run_user_by_upn(struct cache_req_test_ctx *test_ctx, + int cache_refresh_percent, + errno_t exp_ret) + { +- run_cache_req(test_ctx, cache_req_user_by_name_send, +- cache_req_user_by_name_test_done, domain, +- cache_refresh_percent, users[0].upn, exp_ret); ++ run_cache_req_domtype(test_ctx, cache_req_user_by_name_send, ++ cache_req_user_by_name_test_done, domain, ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, ++ users[0].upn, exp_ret); + } + + static void run_user_by_id(struct cache_req_test_ctx *test_ctx, +@@ -318,9 +344,11 @@ static void run_group_by_name(struct cache_req_test_ctx *test_ctx, + int cache_refresh_percent, + errno_t exp_ret) + { +- run_cache_req(test_ctx, cache_req_group_by_name_send, +- cache_req_group_by_name_test_done, domain, +- cache_refresh_percent, groups[0].short_name, exp_ret); ++ run_cache_req_domtype(test_ctx, cache_req_group_by_name_send, ++ cache_req_group_by_name_test_done, domain, ++ cache_refresh_percent, ++ CACHE_REQ_POSIX_DOM, ++ groups[0].short_name, exp_ret); + } + + static void run_group_by_id(struct cache_req_test_ctx *test_ctx, +@@ -605,7 +633,9 @@ void test_user_by_name_multiple_domains_parse(void **state) + check_leaks_push(req_mem_ctx); + + req = cache_req_user_by_name_send(req_mem_ctx, test_ctx->tctx->ev, +- test_ctx->rctx, test_ctx->ncache, 0, ++ test_ctx->rctx, test_ctx->ncache, ++ CACHE_REQ_POSIX_DOM, ++ 0, + NULL, input_fqn); + assert_non_null(req); + tevent_req_set_callback(req, cache_req_user_by_name_test_done, test_ctx); +@@ -1119,7 +1149,8 @@ void test_group_by_name_multiple_domains_parse(void **state) + + req = cache_req_group_by_name_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, test_ctx->ncache, 0, +- NULL, input_fqn); ++ CACHE_REQ_POSIX_DOM, NULL, ++ input_fqn); + assert_non_null(req); + tevent_req_set_callback(req, cache_req_group_by_name_test_done, test_ctx); + +@@ -1421,6 +1452,7 @@ void test_user_by_recent_filter_valid(void **state) + /* User TEST_USER is created with a DP callback. */ + req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, ++ CACHE_REQ_POSIX_DOM, + test_ctx->tctx->dom->name, + TEST_USER_PREFIX); + assert_non_null(req); +@@ -1463,6 +1495,7 @@ void test_users_by_recent_filter_valid(void **state) + /* User TEST_USER1 and TEST_USER2 are created with a DP callback. */ + req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, ++ CACHE_REQ_POSIX_DOM, + test_ctx->tctx->dom->name, + TEST_USER_PREFIX); + assert_non_null(req); +@@ -1524,6 +1557,7 @@ void test_users_by_filter_filter_old(void **state) + + req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, ++ CACHE_REQ_POSIX_DOM, + test_ctx->tctx->dom->name, + TEST_USER_PREFIX); + assert_non_null(req); +@@ -1559,6 +1593,7 @@ void test_users_by_filter_notfound(void **state) + + req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, ++ CACHE_REQ_POSIX_DOM, + test_ctx->tctx->dom->name, + "nosuchuser*"); + assert_non_null(req); +@@ -1592,6 +1627,7 @@ static void test_users_by_filter_multiple_domains_notfound(void **state) + + req = cache_req_user_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, ++ CACHE_REQ_POSIX_DOM, + domain->name, + "nosuchuser*"); + assert_non_null(req); +@@ -1636,6 +1672,7 @@ void test_group_by_recent_filter_valid(void **state) + /* Group TEST_GROUP is created with a DP callback. */ + req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, ++ CACHE_REQ_POSIX_DOM, + test_ctx->tctx->dom->name, + TEST_USER_PREFIX); + assert_non_null(req); +@@ -1680,6 +1717,7 @@ void test_groups_by_recent_filter_valid(void **state) + /* Group TEST_GROUP1 and TEST_GROUP2 are created with a DP callback. */ + req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, ++ CACHE_REQ_POSIX_DOM, + test_ctx->tctx->dom->name, + TEST_USER_PREFIX); + assert_non_null(req); +@@ -1738,6 +1776,7 @@ void test_groups_by_filter_notfound(void **state) + + req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, ++ CACHE_REQ_POSIX_DOM, + test_ctx->tctx->dom->name, + "nosuchgroup*"); + assert_non_null(req); +@@ -1770,6 +1809,7 @@ void test_groups_by_filter_multiple_domains_notfound(void **state) + + req = cache_req_group_by_filter_send(req_mem_ctx, test_ctx->tctx->ev, + test_ctx->rctx, ++ CACHE_REQ_POSIX_DOM, + domain->name, + "nosuchgroup*"); + assert_non_null(req); +-- +2.9.3 + diff --git a/SOURCES/0063-LDAP-Fix-storing-initgroups-for-users-with-no-supple.patch b/SOURCES/0063-LDAP-Fix-storing-initgroups-for-users-with-no-supple.patch deleted file mode 100644 index ea50e9c..0000000 --- a/SOURCES/0063-LDAP-Fix-storing-initgroups-for-users-with-no-supple.patch +++ /dev/null @@ -1,70 +0,0 @@ -From e84b8e754f007cd94d9b535d562d8d315f692e8f Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Fri, 8 Jul 2016 13:19:31 +0200 -Subject: [PATCH 63/74] LDAP: Fix storing initgroups for users with no - supplementary groups -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If there are no supplementary groups, we tried to qualify a NULL pointer -to an array which resulted in an error. - -Reviewed-by: Lukáš Slebodník ---- - src/providers/ldap/sdap_async_initgroups.c | 32 +++++++++++++++++------------- - 1 file changed, 18 insertions(+), 14 deletions(-) - -diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c -index 7029427724cc37a4508e11ef5448b421e94dc787..cc63dff781338e33a9802f97d98174fce2167b4b 100644 ---- a/src/providers/ldap/sdap_async_initgroups.c -+++ b/src/providers/ldap/sdap_async_initgroups.c -@@ -301,13 +301,15 @@ int sdap_initgr_common_store(struct sysdb_ctx *sysdb, - /* Find the differences between the sysdb and LDAP lists - * Groups in the sysdb only must be removed. - */ -- ldap_fqdnlist = sss_create_internal_fqname_list( -- tmp_ctx, -- (const char * const *) ldap_grouplist, -- domain->name); -- if (ldap_fqdnlist == NULL) { -- ret = ENOMEM; -- goto done; -+ if (ldap_grouplist != NULL) { -+ ldap_fqdnlist = sss_create_internal_fqname_list( -+ tmp_ctx, -+ (const char * const *) ldap_grouplist, -+ domain->name); -+ if (ldap_fqdnlist == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } - } - - ret = diff_string_lists(tmp_ctx, ldap_fqdnlist, sysdb_grouplist, -@@ -1288,13 +1290,15 @@ sdap_initgr_store_user_memberships(struct sdap_initgr_nested_state *state) - } - } - -- ldap_fqdnlist = sss_create_internal_fqname_list( -- tmp_ctx, -- (const char * const *) ldap_parent_name_list, -- state->dom->name); -- if (ldap_fqdnlist == NULL) { -- ret = ENOMEM; -- goto done; -+ if (ldap_parent_name_list) { -+ ldap_fqdnlist = sss_create_internal_fqname_list( -+ tmp_ctx, -+ (const char * const *) ldap_parent_name_list, -+ state->dom->name); -+ if (ldap_fqdnlist == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } - } - - ret = sysdb_get_direct_parents(tmp_ctx, state->dom, SYSDB_MEMBER_USER, --- -2.4.11 - diff --git a/SOURCES/0064-IFP-Search-both-POSIX-and-non-POSIX-domains.patch b/SOURCES/0064-IFP-Search-both-POSIX-and-non-POSIX-domains.patch new file mode 100644 index 0000000..c956b23 --- /dev/null +++ b/SOURCES/0064-IFP-Search-both-POSIX-and-non-POSIX-domains.patch @@ -0,0 +1,705 @@ +From bab9c21c9ec7ad39555db52511f0f2e425decd94 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 24 Mar 2017 12:44:09 +0100 +Subject: [PATCH 64/72] IFP: Search both POSIX and non-POSIX domains +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related to: +https://pagure.io/SSSD/sssd/issue/3310 + +Changes the behaviour of the InfoPipe responder so that both application +and POSIX domains are searched. In general, the IFP responder uses the +CACHE_REQ_ANY_DOM lookup type because we can't presume the intention of +the caller. Therefore, deployments that combine both POSIX and non-POSIX +domains must use fully qualified names or select the right domain order +manually. + +There is one change between the POSIX and non-POSIX users or groups - +the object path. For the POSIX users, the object path includes the UID +or GID. Because we don't have that for the non-POSIX objects, the object +name is used in the path instead. + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + src/responder/ifp/ifp_groups.c | 135 ++++++++++++++++++++++------------- + src/responder/ifp/ifp_users.c | 158 ++++++++++++++++++++++++++--------------- + src/responder/ifp/ifpsrv_cmd.c | 6 +- + 3 files changed, 194 insertions(+), 105 deletions(-) + +diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c +index 99908e96bd971bce4b4e9064a77d8413f837d743..c568c62009cd4b777919dea048fd381a91bd3460 100644 +--- a/src/responder/ifp/ifp_groups.c ++++ b/src/responder/ifp/ifp_groups.c +@@ -35,25 +35,33 @@ char * ifp_groups_build_path_from_msg(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + struct ldb_message *msg) + { +- const char *gid; ++ const char *key = NULL; + +- gid = ldb_msg_find_attr_as_string(msg, SYSDB_GIDNUM, NULL); ++ switch (domain->type) { ++ case DOM_TYPE_APPLICATION: ++ key = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); ++ break; ++ case DOM_TYPE_POSIX: ++ key = ldb_msg_find_attr_as_string(msg, SYSDB_GIDNUM, NULL); ++ break; ++ } + +- if (gid == NULL) { ++ ++ if (key == NULL) { + return NULL; + } + +- return sbus_opath_compose(mem_ctx, IFP_PATH_GROUPS, domain->name, gid); ++ return sbus_opath_compose(mem_ctx, IFP_PATH_GROUPS, domain->name, key); + } + +-static errno_t ifp_groups_decompose_path(struct sss_domain_info *domains, ++static errno_t ifp_groups_decompose_path(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domains, + const char *path, + struct sss_domain_info **_domain, +- gid_t *_gid) ++ char **_key) + { + char **parts = NULL; + struct sss_domain_info *domain; +- gid_t gid; + errno_t ret; + + ret = sbus_opath_decompose_exact(NULL, path, IFP_PATH_GROUPS, 2, &parts); +@@ -67,14 +75,8 @@ static errno_t ifp_groups_decompose_path(struct sss_domain_info *domains, + goto done; + } + +- gid = strtouint32(parts[1], NULL, 10); +- ret = errno; +- if (ret != EOK) { +- goto done; +- } +- + *_domain = domain; +- *_gid = gid; ++ *_key = talloc_steal(mem_ctx, parts[1]); + + done: + talloc_free(parts); +@@ -119,7 +121,7 @@ int ifp_groups_find_by_name(struct sbus_request *sbus_req, + + req = cache_req_group_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, + ctx->rctx->ncache, 0, +- CACHE_REQ_POSIX_DOM, NULL, ++ CACHE_REQ_ANY_DOM, NULL, + name); + if (req == NULL) { + return ENOMEM; +@@ -273,7 +275,7 @@ static int ifp_groups_list_by_name_step(struct ifp_list_ctx *list_ctx) + req = cache_req_group_by_filter_send(list_ctx, + list_ctx->ctx->rctx->ev, + list_ctx->ctx->rctx, +- CACHE_REQ_POSIX_DOM, ++ CACHE_REQ_ANY_DOM, + list_ctx->dom->name, + list_ctx->filter); + if (req == NULL) { +@@ -358,7 +360,7 @@ int ifp_groups_list_by_domain_and_name(struct sbus_request *sbus_req, + } + + req = cache_req_group_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx, +- CACHE_REQ_POSIX_DOM, ++ CACHE_REQ_ANY_DOM, + domain, filter); + if (req == NULL) { + return ENOMEM; +@@ -412,16 +414,65 @@ done: + } + + static errno_t ++ifp_groups_get_from_cache(struct sbus_request *sbus_req, ++ struct sss_domain_info *domain, ++ const char *key, ++ struct ldb_message **_group) ++{ ++ struct ldb_result *group_res; ++ errno_t ret; ++ gid_t gid; ++ ++ switch (domain->type) { ++ case DOM_TYPE_POSIX: ++ gid = strtouint32(key, NULL, 10); ++ ret = errno; ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid UID value\n"); ++ return ret; ++ } ++ ++ ret = sysdb_getgrgid_with_views(sbus_req, domain, gid, &group_res); ++ if (ret == EOK && group_res->count == 0) { ++ *_group = NULL; ++ return ENOENT; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup group %u@%s [%d]: %s\n", ++ gid, domain->name, ret, sss_strerror(ret)); ++ return ret; ++ } ++ break; ++ case DOM_TYPE_APPLICATION: ++ ret = sysdb_getgrnam_with_views(sbus_req, domain, key, &group_res); ++ if (ret == EOK && group_res->count == 0) { ++ *_group = NULL; ++ return ENOENT; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup group %s@%s [%d]: %s\n", ++ key, domain->name, ret, sss_strerror(ret)); ++ return ret; ++ } ++ break; ++ } ++ ++ if (group_res->count > 1) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "More groups matched by the single key\n"); ++ return EIO; ++ } ++ ++ *_group = group_res->msgs[0]; ++ return EOK; ++} ++ ++static errno_t + ifp_groups_group_get(struct sbus_request *sbus_req, + void *data, +- gid_t *_gid, + struct sss_domain_info **_domain, + struct ldb_message **_group) + { + struct ifp_ctx *ctx; + struct sss_domain_info *domain; +- struct ldb_result *res; +- uid_t gid; ++ char *key; + errno_t ret; + + ctx = talloc_get_type(data, struct ifp_ctx); +@@ -430,8 +481,9 @@ ifp_groups_group_get(struct sbus_request *sbus_req, + return ERR_INTERNAL; + } + +- ret = ifp_groups_decompose_path(ctx->rctx->domains, sbus_req->path, +- &domain, &gid); ++ ret = ifp_groups_decompose_path(sbus_req, ++ ctx->rctx->domains, sbus_req->path, ++ &domain, &key); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to decompose object path" + "[%s] [%d]: %s\n", sbus_req->path, ret, sss_strerror(ret)); +@@ -439,28 +491,15 @@ ifp_groups_group_get(struct sbus_request *sbus_req, + } + + if (_group != NULL) { +- ret = sysdb_getgrgid_with_views(sbus_req, domain, gid, &res); +- if (ret == EOK && res->count == 0) { +- *_group = NULL; +- ret = ENOENT; +- } +- +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup group %u@%s [%d]: %s\n", +- gid, domain->name, ret, sss_strerror(ret)); +- } else { +- *_group = res->msgs[0]; +- } ++ ret = ifp_groups_get_from_cache(sbus_req, domain, key, _group); + } + + if (ret == EOK || ret == ENOENT) { +- if (_gid != NULL) { +- *_gid = gid; +- } +- + if (_domain != NULL) { + *_domain = domain; + } ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve group from cache\n"); + } + + return ret; +@@ -513,7 +552,7 @@ static struct tevent_req *resolv_ghosts_send(TALLOC_CTX *mem_ctx, + state->ctx = ctx; + state->data = data; + +- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group); ++ ret = ifp_groups_group_get(sbus_req, data, &domain, &group); + if (ret != EOK) { + goto immediately; + } +@@ -527,7 +566,7 @@ static struct tevent_req *resolv_ghosts_send(TALLOC_CTX *mem_ctx, + + subreq = cache_req_group_by_name_send(state, ev, ctx->rctx, + ctx->rctx->ncache, 0, +- CACHE_REQ_POSIX_DOM, ++ CACHE_REQ_ANY_DOM, + domain->name, + name); + if (subreq == NULL) { +@@ -561,7 +600,7 @@ static void resolv_ghosts_group_done(struct tevent_req *subreq) + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct resolv_ghosts_state); + +- ret = ifp_groups_group_get(state->sbus_req, state->data, NULL, ++ ret = ifp_groups_group_get(state->sbus_req, state->data, + &state->domain, &group); + if (ret != EOK) { + goto done; +@@ -608,7 +647,7 @@ errno_t resolv_ghosts_step(struct tevent_req *req) + + subreq = cache_req_user_by_name_send(state, state->ev, state->ctx->rctx, + state->ctx->rctx->ncache, 0, +- CACHE_REQ_POSIX_DOM, ++ CACHE_REQ_ANY_DOM, + state->domain->name, + state->ghosts[state->index]); + if (subreq == NULL) { +@@ -719,7 +758,7 @@ void ifp_groups_group_get_name(struct sbus_request *sbus_req, + return; + } + +- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &msg); ++ ret = ifp_groups_group_get(sbus_req, data, &domain, &msg); + if (ret != EOK) { + *_out = NULL; + return; +@@ -744,7 +783,7 @@ void ifp_groups_group_get_gid_number(struct sbus_request *sbus_req, + struct sss_domain_info *domain; + errno_t ret; + +- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &msg); ++ ret = ifp_groups_group_get(sbus_req, data, &domain, &msg); + if (ret != EOK) { + *_out = 0; + return; +@@ -763,7 +802,7 @@ void ifp_groups_group_get_unique_id(struct sbus_request *sbus_req, + struct sss_domain_info *domain; + errno_t ret; + +- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &msg); ++ ret = ifp_groups_group_get(sbus_req, data, &domain, &msg); + if (ret != EOK) { + *_out = 0; + return; +@@ -803,7 +842,7 @@ ifp_groups_group_get_members(TALLOC_CTX *mem_ctx, + return ENOMEM; + } + +- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group); ++ ret = ifp_groups_group_get(sbus_req, data, &domain, &group); + if (ret != EOK) { + goto done; + } +@@ -954,7 +993,7 @@ int ifp_cache_object_store_group(struct sbus_request *sbus_req, + struct ldb_message *group; + errno_t ret; + +- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group); ++ ret = ifp_groups_group_get(sbus_req, data, &domain, &group); + if (ret != EOK) { + error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch " + "group [%d]: %s\n", ret, sss_strerror(ret)); +@@ -973,7 +1012,7 @@ int ifp_cache_object_remove_group(struct sbus_request *sbus_req, + struct ldb_message *group; + errno_t ret; + +- ret = ifp_groups_group_get(sbus_req, data, NULL, &domain, &group); ++ ret = ifp_groups_group_get(sbus_req, data, &domain, &group); + if (ret != EOK) { + error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch " + "group [%d]: %s\n", ret, sss_strerror(ret)); +diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c +index 436bb268fa9c78d72fb744e0d338aa561a7d8764..ce9557f94351b730ee46f3cbce31613cb5901942 100644 +--- a/src/responder/ifp/ifp_users.c ++++ b/src/responder/ifp/ifp_users.c +@@ -37,25 +37,33 @@ char * ifp_users_build_path_from_msg(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + struct ldb_message *msg) + { +- const char *uid; ++ const char *key = NULL; + +- uid = ldb_msg_find_attr_as_string(msg, SYSDB_UIDNUM, NULL); ++ switch (domain->type) { ++ case DOM_TYPE_APPLICATION: ++ key = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); ++ break; ++ case DOM_TYPE_POSIX: ++ key = ldb_msg_find_attr_as_string(msg, SYSDB_UIDNUM, NULL); ++ break; ++ } + +- if (uid == NULL) { ++ ++ if (key == NULL) { + return NULL; + } + +- return sbus_opath_compose(mem_ctx, IFP_PATH_USERS, domain->name, uid); ++ return sbus_opath_compose(mem_ctx, IFP_PATH_USERS, domain->name, key); + } + +-static errno_t ifp_users_decompose_path(struct sss_domain_info *domains, ++static errno_t ifp_users_decompose_path(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domains, + const char *path, + struct sss_domain_info **_domain, +- uid_t *_uid) ++ char **_key) + { + char **parts = NULL; + struct sss_domain_info *domain; +- uid_t uid; + errno_t ret; + + ret = sbus_opath_decompose_exact(NULL, path, IFP_PATH_USERS, 2, &parts); +@@ -69,14 +77,8 @@ static errno_t ifp_users_decompose_path(struct sss_domain_info *domains, + goto done; + } + +- uid = strtouint32(parts[1], NULL, 10); +- ret = errno; +- if (ret != EOK) { +- goto done; +- } +- + *_domain = domain; +- *_uid = uid; ++ *_key = talloc_steal(mem_ctx, parts[1]); + + done: + talloc_free(parts); +@@ -100,7 +102,7 @@ int ifp_users_find_by_name(struct sbus_request *sbus_req, + + req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, + ctx->rctx->ncache, 0, +- CACHE_REQ_POSIX_DOM, ++ CACHE_REQ_ANY_DOM, + NULL, name); + if (req == NULL) { + return ENOMEM; +@@ -256,7 +258,7 @@ int ifp_users_find_by_cert(struct sbus_request *sbus_req, void *data, + + req = cache_req_user_by_cert_send(sbus_req, ctx->rctx->ev, ctx->rctx, + ctx->rctx->ncache, 0, +- CACHE_REQ_POSIX_DOM, NULL, ++ CACHE_REQ_ANY_DOM, NULL, + derb64); + if (req == NULL) { + return ENOMEM; +@@ -371,7 +373,7 @@ static int ifp_users_list_by_cert_step(struct ifp_list_ctx *list_ctx) + list_ctx->ctx->rctx, + list_ctx->ctx->rctx->ncache, + 0, +- CACHE_REQ_POSIX_DOM, ++ CACHE_REQ_ANY_DOM, + list_ctx->dom->name, + list_ctx->filter); + if (req == NULL) { +@@ -538,7 +540,7 @@ int ifp_users_find_by_name_and_cert(struct sbus_request *sbus_req, void *data, + if (name_and_cert_ctx->name != NULL) { + req = cache_req_user_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, + ctx->rctx->ncache, 0, +- CACHE_REQ_POSIX_DOM, ++ CACHE_REQ_ANY_DOM, + NULL, + name_and_cert_ctx->name); + if (req == NULL) { +@@ -621,7 +623,7 @@ static int ifp_users_find_by_name_and_cert_step( + list_ctx->ctx->rctx, + list_ctx->ctx->rctx->ncache, + 0, +- CACHE_REQ_POSIX_DOM, ++ CACHE_REQ_ANY_DOM, + list_ctx->dom->name, + list_ctx->filter); + if (req == NULL) { +@@ -782,7 +784,7 @@ static int ifp_users_list_by_name_step(struct ifp_list_ctx *list_ctx) + req = cache_req_user_by_filter_send(list_ctx, + list_ctx->ctx->rctx->ev, + list_ctx->ctx->rctx, +- CACHE_REQ_POSIX_DOM, ++ CACHE_REQ_ANY_DOM, + list_ctx->dom->name, + list_ctx->filter); + if (req == NULL) { +@@ -867,7 +869,7 @@ int ifp_users_list_by_domain_and_name(struct sbus_request *sbus_req, + } + + req = cache_req_user_by_filter_send(list_ctx, ctx->rctx->ev, ctx->rctx, +- CACHE_REQ_POSIX_DOM, ++ CACHE_REQ_ANY_DOM, + domain, filter); + if (req == NULL) { + return ENOMEM; +@@ -930,19 +932,69 @@ done: + } + + static errno_t ++ifp_users_get_from_cache(struct sbus_request *sbus_req, ++ struct sss_domain_info *domain, ++ const char *key, ++ struct ldb_message **_user) ++{ ++ struct ldb_result *user_res; ++ errno_t ret; ++ uid_t uid; ++ ++ switch (domain->type) { ++ case DOM_TYPE_POSIX: ++ uid = strtouint32(key, NULL, 10); ++ ret = errno; ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid UID value\n"); ++ return ret; ++ } ++ ++ ret = sysdb_getpwuid_with_views(sbus_req, domain, uid, &user_res); ++ if (ret == EOK && user_res->count == 0) { ++ *_user = NULL; ++ return ENOENT; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user %u@%s [%d]: %s\n", ++ uid, domain->name, ret, sss_strerror(ret)); ++ return ret; ++ } ++ break; ++ case DOM_TYPE_APPLICATION: ++ ret = sysdb_getpwnam_with_views(sbus_req, domain, key, &user_res); ++ if (ret == EOK && user_res->count == 0) { ++ *_user = NULL; ++ return ENOENT; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user %s@%s [%d]: %s\n", ++ key, domain->name, ret, sss_strerror(ret)); ++ return ret; ++ } ++ break; ++ } ++ ++ if (user_res->count > 1) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "More users matched by the single key\n"); ++ return EIO; ++ } ++ ++ *_user = user_res->msgs[0]; ++ return EOK; ++} ++ ++static errno_t + ifp_users_user_get(struct sbus_request *sbus_req, + struct ifp_ctx *ifp_ctx, +- uid_t *_uid, + struct sss_domain_info **_domain, + struct ldb_message **_user) + { + struct sss_domain_info *domain; +- struct ldb_result *res; +- uid_t uid; ++ char *key; + errno_t ret; + +- ret = ifp_users_decompose_path(ifp_ctx->rctx->domains, sbus_req->path, +- &domain, &uid); ++ ret = ifp_users_decompose_path(sbus_req, ++ ifp_ctx->rctx->domains, sbus_req->path, ++ &domain, &key); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to decompose object path" + "[%s] [%d]: %s\n", sbus_req->path, ret, sss_strerror(ret)); +@@ -950,28 +1002,15 @@ ifp_users_user_get(struct sbus_request *sbus_req, + } + + if (_user != NULL) { +- ret = sysdb_getpwuid_with_views(sbus_req, domain, uid, &res); +- if (ret == EOK && res->count == 0) { +- *_user = NULL; +- ret = ENOENT; +- } +- +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user %u@%s [%d]: %s\n", +- uid, domain->name, ret, sss_strerror(ret)); +- } else { +- *_user = res->msgs[0]; +- } ++ ret = ifp_users_get_from_cache(sbus_req, domain, key, _user); + } + + if (ret == EOK || ret == ENOENT) { +- if (_uid != NULL) { +- *_uid = uid; +- } +- + if (_domain != NULL) { + *_domain = domain; + } ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve user from cache\n"); + } + + return ret; +@@ -1000,7 +1039,7 @@ static void ifp_users_get_as_string(struct sbus_request *sbus_req, + return; + } + +- ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &msg); ++ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, &msg); + if (ret != EOK) { + return; + } +@@ -1034,7 +1073,7 @@ static void ifp_users_get_name(struct sbus_request *sbus_req, + return; + } + +- ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &msg); ++ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, &msg); + if (ret != EOK) { + return; + } +@@ -1072,7 +1111,7 @@ static void ifp_users_get_as_uint32(struct sbus_request *sbus_req, + return; + } + +- ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &msg); ++ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, &msg); + if (ret != EOK) { + return; + } +@@ -1100,7 +1139,7 @@ int ifp_users_user_update_groups_list(struct sbus_request *sbus_req, + return ERR_INTERNAL; + } + +- ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user); ++ ret = ifp_users_user_get(sbus_req, data, &domain, &user); + if (ret != EOK) { + return ret; + } +@@ -1113,7 +1152,7 @@ int ifp_users_user_update_groups_list(struct sbus_request *sbus_req, + + req = cache_req_initgr_by_name_send(sbus_req, ctx->rctx->ev, ctx->rctx, + ctx->rctx->ncache, 0, +- CACHE_REQ_POSIX_DOM, domain->name, ++ CACHE_REQ_ANY_DOM, domain->name, + username); + if (req == NULL) { + return ENOMEM; +@@ -1235,7 +1274,7 @@ void ifp_users_user_get_groups(struct sbus_request *sbus_req, + return; + } + +- ret = ifp_users_user_get(sbus_req, ifp_ctx, NULL, &domain, &user); ++ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, &user); + if (ret != EOK) { + return; + } +@@ -1268,7 +1307,7 @@ void ifp_users_user_get_groups(struct sbus_request *sbus_req, + for (i = 0; i < res->count; i++) { + gid = sss_view_ldb_msg_find_attr_as_uint64(domain, res->msgs[i], + SYSDB_GIDNUM, 0); +- if (gid == 0) { ++ if (gid == 0 && domain->type == DOM_TYPE_POSIX) { + continue; + } + +@@ -1293,11 +1332,12 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, + { + struct ifp_ctx *ifp_ctx; + struct sss_domain_info *domain; ++ struct ldb_message *base_user; ++ const char *name; + struct ldb_message **user; + struct ldb_message_element *el; + struct ldb_dn *basedn; + size_t count; +- uid_t uid; + const char *filter; + const char **extra; + hash_table_t *table; +@@ -1322,7 +1362,7 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, + return; + } + +- ret = ifp_users_user_get(sbus_req, data, &uid, &domain, NULL); ++ ret = ifp_users_user_get(sbus_req, data, &domain, &base_user); + if (ret != EOK) { + return; + } +@@ -1333,9 +1373,15 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, + return; + } + +- filter = talloc_asprintf(sbus_req, "(&(%s=%s)(%s=%u))", ++ name = ldb_msg_find_attr_as_string(base_user, SYSDB_NAME, NULL); ++ if (name == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "A user with no name\n"); ++ return; ++ } ++ ++ filter = talloc_asprintf(sbus_req, "(&(%s=%s)(%s=%s))", + SYSDB_OBJECTCLASS, SYSDB_USER_CLASS, +- SYSDB_UIDNUM, uid); ++ SYSDB_NAME, name); + if (filter == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n"); + return; +@@ -1351,7 +1397,7 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, + } + + if (count == 0) { +- DEBUG(SSSDBG_TRACE_FUNC, "User %u not found!\n", uid); ++ DEBUG(SSSDBG_TRACE_FUNC, "User %s not found!\n", name); + return; + } else if (count > 1) { + DEBUG(SSSDBG_CRIT_FAILURE, "More than one entry found!\n"); +@@ -1421,7 +1467,7 @@ int ifp_cache_object_store_user(struct sbus_request *sbus_req, + struct ldb_message *user; + errno_t ret; + +- ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user); ++ ret = ifp_users_user_get(sbus_req, data, &domain, &user); + if (ret != EOK) { + error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch " + "user [%d]: %s\n", ret, sss_strerror(ret)); +@@ -1440,7 +1486,7 @@ int ifp_cache_object_remove_user(struct sbus_request *sbus_req, + struct ldb_message *user; + errno_t ret; + +- ret = ifp_users_user_get(sbus_req, data, NULL, &domain, &user); ++ ret = ifp_users_user_get(sbus_req, data, &domain, &user); + if (ret != EOK) { + error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, "Failed to fetch " + "user [%d]: %s\n", ret, sss_strerror(ret)); +diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c +index 118b5083b14bf5692c6fdd7ba90668fe514aa89d..d10f35e41dbb1623a0b9de37a4c43363cbefc1a3 100644 +--- a/src/responder/ifp/ifpsrv_cmd.c ++++ b/src/responder/ifp/ifpsrv_cmd.c +@@ -508,8 +508,12 @@ ifp_user_get_attr_lookup(struct tevent_req *subreq) + return; + } + ++ /* IFP serves both POSIX and application domains. Requests that need ++ * to differentiate between the two must be qualified ++ */ + subreq = cache_req_send(state, state->rctx->ev, state->rctx, +- state->ncache, 0, CACHE_REQ_POSIX_DOM, ++ state->ncache, 0, ++ CACHE_REQ_ANY_DOM, + state->domname, data); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); +-- +2.9.3 + diff --git a/SOURCES/0064-LDAP-Changing-of-confusing-debug-message.patch b/SOURCES/0064-LDAP-Changing-of-confusing-debug-message.patch deleted file mode 100644 index 915b84e..0000000 --- a/SOURCES/0064-LDAP-Changing-of-confusing-debug-message.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 256f6eafd5ca3cf1ea0a573ec44b3e5e4b74919c Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Tue, 12 Jul 2016 09:32:44 +0200 -Subject: [PATCH 64/74] LDAP: Changing of confusing debug message - -This debug message used to confuse our customer. So this patch changes it. - -Resolves: -https://fedorahosted.org/sssd/ticket/3091 - -Reviewed-by: Stephen Gallagher ---- - src/providers/ldap/sdap_async.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c -index 0c67e54c8a981442b7983a3f68db1bde3a2a6280..4195ba95d911f3956f8cca665310b4b92091e6cd 100644 ---- a/src/providers/ldap/sdap_async.c -+++ b/src/providers/ldap/sdap_async.c -@@ -167,7 +167,7 @@ static void sdap_process_result(struct tevent_context *ev, void *pvt) - if (ret == 0) { - /* this almost always means we have reached the end of - * the list of received messages */ -- DEBUG(SSSDBG_TRACE_INTERNAL, "Trace: ldap_result found nothing!\n"); -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Trace: end of ldap_result list\n"); - return; - } - --- -2.4.11 - diff --git a/SOURCES/0065-IFP-ListByName-Don-t-crash-when-no-results-are-found.patch b/SOURCES/0065-IFP-ListByName-Don-t-crash-when-no-results-are-found.patch new file mode 100644 index 0000000..f062ffa --- /dev/null +++ b/SOURCES/0065-IFP-ListByName-Don-t-crash-when-no-results-are-found.patch @@ -0,0 +1,57 @@ +From c9268488cd24fe8e13580d6c4ea2fa237faededa Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 28 Mar 2017 14:07:29 +0200 +Subject: [PATCH 65/72] IFP: ListByName: Don't crash when no results are found +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If no results were found using the List command, the results variable +was undefined which resulted in a crash. + +Instead, only copy the results of the cache_req lookup returns EOK and +we can presume that the results are valid. + +Reviewed-by: Pavel Březina +Reviewed-by: Sumit Bose +--- + src/responder/ifp/ifp_users.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c +index ce9557f94351b730ee46f3cbce31613cb5901942..188194f2ab356d0e67b0f26b003f3a9ce48e6acd 100644 +--- a/src/responder/ifp/ifp_users.c ++++ b/src/responder/ifp/ifp_users.c +@@ -801,7 +801,7 @@ static void ifp_users_list_by_name_done(struct tevent_req *req) + DBusError *error; + struct ifp_list_ctx *list_ctx; + struct sbus_request *sbus_req; +- struct cache_req_result *result; ++ struct cache_req_result *result = NULL; + errno_t ret; + + list_ctx = tevent_req_callback_data(req, struct ifp_list_ctx); +@@ -816,12 +816,14 @@ static void ifp_users_list_by_name_done(struct tevent_req *req) + return; + } + +- ret = ifp_users_list_copy(list_ctx, result->ldb_result); +- if (ret != EOK) { +- error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL, +- "Failed to copy domain result"); +- sbus_request_fail_and_finish(sbus_req, error); +- return; ++ if (ret == EOK) { ++ ret = ifp_users_list_copy(list_ctx, result->ldb_result); ++ if (ret != EOK) { ++ error = sbus_error_new(sbus_req, SBUS_ERROR_INTERNAL, ++ "Failed to copy domain result"); ++ sbus_request_fail_and_finish(sbus_req, error); ++ return; ++ } + } + + list_ctx->dom = get_next_domain(list_ctx->dom, SSS_GND_DESCEND); +-- +2.9.3 + diff --git a/SOURCES/0065-LDAP-Use-FQDN-when-linking-parent-LDAP-groups.patch b/SOURCES/0065-LDAP-Use-FQDN-when-linking-parent-LDAP-groups.patch deleted file mode 100644 index d381162..0000000 --- a/SOURCES/0065-LDAP-Use-FQDN-when-linking-parent-LDAP-groups.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 8798dbf0af2850c5775e0d50165d70b17a031050 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 3 Aug 2016 13:18:51 +0200 -Subject: [PATCH 65/74] LDAP: Use FQDN when linking parent LDAP groups -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: - https://fedorahosted.org/sssd/ticket/3093 - -Because we compare the list of LDAP names with the list of sysdb names, -we need to qualify the list of LDAP names before running the diff. - -Reviewed-by: Lukáš Slebodník ---- - src/providers/ldap/sdap_async_initgroups.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c -index cc63dff781338e33a9802f97d98174fce2167b4b..82c708c226bf1a645ff5a395947dfdbad71e0f1f 100644 ---- a/src/providers/ldap/sdap_async_initgroups.c -+++ b/src/providers/ldap/sdap_async_initgroups.c -@@ -2080,7 +2080,7 @@ rfc2307bis_group_memberships_build(hash_entry_t *item, void *user_data) - } - - if (group->parents_count > 0) { -- ret = sysdb_attrs_primary_name_list(mstate->dom, tmp_ctx, -+ ret = sysdb_attrs_primary_fqdn_list(mstate->dom, tmp_ctx, - group->ldap_parents, group->parents_count, - mstate->opts->group_map[SDAP_AT_GROUP_NAME].name, - &ldap_parents_names_list); --- -2.4.11 - diff --git a/SOURCES/0066-PAM-Remove-unneeded-memory-context.patch b/SOURCES/0066-PAM-Remove-unneeded-memory-context.patch new file mode 100644 index 0000000..64ba6af --- /dev/null +++ b/SOURCES/0066-PAM-Remove-unneeded-memory-context.patch @@ -0,0 +1,58 @@ +From d11e7faa2a3464ed921ccf88a02e0a48871484b4 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 24 Mar 2017 20:36:06 +0100 +Subject: [PATCH 66/72] PAM: Remove unneeded memory context + +Since we only store data into pam_ctx in get_public_domains(), it +doesn't make sense to allow passing a separate memory context. It is +always going to be pam_ctx, otherwise the memory hierarchy will cause +issues anyway. + +Reviewed-by: Sumit Bose +--- + src/responder/pam/pamsrv.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c +index 816f2293130ff8761ca94b4a42ca93063c11ea35..ab3f4545520f3fcb2492a6089a039c46f0fb847f 100644 +--- a/src/responder/pam/pamsrv.c ++++ b/src/responder/pam/pamsrv.c +@@ -122,7 +122,7 @@ done: + return ret; + } + +-static errno_t get_public_domains(TALLOC_CTX *mem_ctx, struct pam_ctx *pctx) ++static errno_t get_public_domains(struct pam_ctx *pctx) + { + char *domains_str = NULL; + errno_t ret; +@@ -137,7 +137,7 @@ static errno_t get_public_domains(TALLOC_CTX *mem_ctx, struct pam_ctx *pctx) + + if (strcmp(domains_str, ALL_DOMAIMS_ARE_PUBLIC) == 0) { /* all */ + /* copy all domains */ +- ret = get_dom_names(mem_ctx, ++ ret = get_dom_names(pctx, + pctx->rctx->domains, + &pctx->public_domains, + &pctx->public_domains_count); +@@ -149,7 +149,7 @@ static errno_t get_public_domains(TALLOC_CTX *mem_ctx, struct pam_ctx *pctx) + pctx->public_domains = NULL; + pctx->public_domains_count = 0; + } else { +- ret = split_on_separator(mem_ctx, domains_str, ',', true, false, ++ ret = split_on_separator(pctx, domains_str, ',', true, false, + &pctx->public_domains, + &pctx->public_domains_count); + if (ret != EOK) { +@@ -212,7 +212,7 @@ static int pam_process_init(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = get_public_domains(pctx, pctx); ++ ret = get_public_domains(pctx); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "get_public_domains failed: %d:[%s].\n", + ret, sss_strerror(ret)); +-- +2.9.3 + diff --git a/SOURCES/0066-sssctl-Consistent-commands-naming.patch b/SOURCES/0066-sssctl-Consistent-commands-naming.patch deleted file mode 100644 index 35bd2e2..0000000 --- a/SOURCES/0066-sssctl-Consistent-commands-naming.patch +++ /dev/null @@ -1,330 +0,0 @@ -From 6f36e763802e35ff2c431e67be20664e221de85f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Mon, 25 Jul 2016 13:50:13 +0200 -Subject: [PATCH 66/74] sssctl: Consistent commands naming -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Use TOPIC-ACTION pattern for sssctl command -names. - -Resolves: -https://fedorahosted.org/sssd/ticket/3087 - -Reviewed-by: Pavel Březina -Reviewed-by: Lukáš Slebodník ---- - src/tools/common/sss_tools.h | 2 ++ - src/tools/sss_override.c | 26 +++++++++++------------ - src/tools/sssctl/sssctl.c | 22 ++++++++++---------- - src/tools/sssctl/sssctl.h | 43 +++++++++++++++++++-------------------- - src/tools/sssctl/sssctl_cache.c | 18 ++++++++-------- - src/tools/sssctl/sssctl_data.c | 16 +++++++-------- - src/tools/sssctl/sssctl_domains.c | 6 +++--- - src/tools/sssctl/sssctl_logs.c | 4 ++-- - 8 files changed, 69 insertions(+), 68 deletions(-) - -diff --git a/src/tools/common/sss_tools.h b/src/tools/common/sss_tools.h -index a9ebabe21df14eba52f348046c179a91a6394b97..41c8b10e8c2dd8d6a86297b42a71dd5aaf9e556a 100644 ---- a/src/tools/common/sss_tools.h -+++ b/src/tools/common/sss_tools.h -@@ -46,7 +46,9 @@ typedef errno_t - void *pvt); - - #define SSS_TOOL_COMMAND(cmd, msg, err, fn) {cmd, _(msg), err, fn} -+#define SSS_TOOL_COMMAND_NOMSG(cmd, err, fn) {cmd, NULL, err, fn} - #define SSS_TOOL_DELIMITER(message) {"", (message), 0, NULL} -+#define SSS_TOOL_LAST {NULL, NULL, 0, NULL} - - struct sss_route_cmd { - const char *command; -diff --git a/src/tools/sss_override.c b/src/tools/sss_override.c -index 45a28fd7f5366cd85e6ecd13a4846917d18e9613..d41da52e69acdb67b5a6d624254e3b89a8aa27b8 100644 ---- a/src/tools/sss_override.c -+++ b/src/tools/sss_override.c -@@ -1913,19 +1913,19 @@ static int override_group_export(struct sss_cmdline *cmdline, - int main(int argc, const char **argv) - { - struct sss_route_cmd commands[] = { -- {"user-add", NULL, 0, override_user_add}, -- {"user-del", NULL, 0, override_user_del}, -- {"user-find", NULL, 0, override_user_find}, -- {"user-show", NULL, 0, override_user_show}, -- {"user-import", NULL, 0, override_user_import}, -- {"user-export", NULL, 0, override_user_export}, -- {"group-add", NULL, 0, override_group_add}, -- {"group-del", NULL, 0, override_group_del}, -- {"group-find", NULL, 0, override_group_find}, -- {"group-show", NULL, 0, override_group_show}, -- {"group-import", NULL, 0, override_group_import}, -- {"group-export", NULL, 0, override_group_export}, -- {NULL, NULL, 0, NULL} -+ SSS_TOOL_COMMAND_NOMSG("user-add", 0, override_user_add), -+ SSS_TOOL_COMMAND_NOMSG("user-del", 0, override_user_del), -+ SSS_TOOL_COMMAND_NOMSG("user-find", 0, override_user_find), -+ SSS_TOOL_COMMAND_NOMSG("user-show", 0, override_user_show), -+ SSS_TOOL_COMMAND_NOMSG("user-import", 0, override_user_import), -+ SSS_TOOL_COMMAND_NOMSG("user-export", 0, override_user_export), -+ SSS_TOOL_COMMAND_NOMSG("group-add", 0, override_group_add), -+ SSS_TOOL_COMMAND_NOMSG("group-del", 0, override_group_del), -+ SSS_TOOL_COMMAND_NOMSG("group-find", 0, override_group_find), -+ SSS_TOOL_COMMAND_NOMSG("group-show", 0, override_group_show), -+ SSS_TOOL_COMMAND_NOMSG("group-import", 0, override_group_import), -+ SSS_TOOL_COMMAND_NOMSG("group-export", 0, override_group_export), -+ SSS_TOOL_LAST - }; - - return sss_tool_main(argc, argv, commands, NULL); -diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c -index 86656f136c00234a230b8fc779a0d245f0d125d5..20ea26f8f71c26a925f5c37327635e346f497891 100644 ---- a/src/tools/sssctl/sssctl.c -+++ b/src/tools/sssctl/sssctl.c -@@ -257,25 +257,25 @@ int main(int argc, const char **argv) - { - struct sss_route_cmd commands[] = { - SSS_TOOL_DELIMITER("SSSD Status:"), -- SSS_TOOL_COMMAND("list-domains", "List available domains", 0, sssctl_list_domains), -+ SSS_TOOL_COMMAND("domain-list", "List available domains", 0, sssctl_domain_list), - SSS_TOOL_COMMAND("domain-status", "Print information about domain", 0, sssctl_domain_status), - SSS_TOOL_DELIMITER("Information about cached content:"), -- SSS_TOOL_COMMAND("user", "Information about cached user", 0, sssctl_user), -- SSS_TOOL_COMMAND("group", "Information about cached group", 0, sssctl_group), -- SSS_TOOL_COMMAND("netgroup", "Information about cached netgroup", 0, sssctl_netgroup), -+ SSS_TOOL_COMMAND("user-show", "Information about cached user", 0, sssctl_user_show), -+ SSS_TOOL_COMMAND("group-show", "Information about cached group", 0, sssctl_group_show), -+ SSS_TOOL_COMMAND("netgroup-show", "Information about cached netgroup", 0, sssctl_netgroup_show), - SSS_TOOL_DELIMITER("Local data tools:"), -- SSS_TOOL_COMMAND("backup-local-data", "Backup local data", 0, sssctl_backup_local_data), -- SSS_TOOL_COMMAND("restore-local-data", "Restore local data from backup", 0, sssctl_restore_local_data), -- SSS_TOOL_COMMAND("remove-cache", "Backup local data and remove cached content", 0, sssctl_remove_cache), -- SSS_TOOL_COMMAND("upgrade-cache", "Perform cache upgrade", ERR_SYSDB_VERSION_TOO_OLD, sssctl_upgrade_cache), -+ SSS_TOOL_COMMAND("client-data-backup", "Backup local data", 0, sssctl_client_data_backup), -+ SSS_TOOL_COMMAND("client-data-restore", "Restore local data from backup", 0, sssctl_client_data_restore), -+ SSS_TOOL_COMMAND("cache-remove", "Backup local data and remove cached content", 0, sssctl_cache_remove), -+ SSS_TOOL_COMMAND("cache-upgrade", "Perform cache upgrade", ERR_SYSDB_VERSION_TOO_OLD, sssctl_cache_upgrade), - SSS_TOOL_DELIMITER("Log files tools:"), -- SSS_TOOL_COMMAND("remove-logs", "Remove existing SSSD log files", 0, sssctl_remove_logs), -- SSS_TOOL_COMMAND("fetch-logs", "Archive SSSD log files in tarball", 0, sssctl_fetch_logs), -+ SSS_TOOL_COMMAND("logs-remove", "Remove existing SSSD log files", 0, sssctl_logs_remove), -+ SSS_TOOL_COMMAND("logs-fetch", "Archive SSSD log files in tarball", 0, sssctl_logs_fetch), - #ifdef HAVE_LIBINI_CONFIG_V1_3 - SSS_TOOL_DELIMITER("Configuration files tools:"), - SSS_TOOL_COMMAND("config-check", "Perform static analysis of SSSD configuration", 0, sssctl_config_check), - #endif -- {NULL, NULL, 0, NULL} -+ SSS_TOOL_LAST - }; - - return sss_tool_main(argc, argv, commands, NULL); -diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h -index be624755de531df9ff5a97f5640266801695ef6e..72930ee5c3a1195e90c6e35768f715cbf6a1c4e1 100644 ---- a/src/tools/sssctl/sssctl.h -+++ b/src/tools/sssctl/sssctl.h -@@ -56,52 +56,51 @@ void _sssctl_sifp_error(sss_sifp_ctx *sifp, - #define sssctl_sifp_error(sifp, error, message) \ - _sssctl_sifp_error(sifp, error, _(message)) - --errno_t sssctl_list_domains(struct sss_cmdline *cmdline, -- struct sss_tool_ctx *tool_ctx, -- void *pvt); -+errno_t sssctl_domain_list(struct sss_cmdline *cmdline, -+ struct sss_tool_ctx *tool_ctx, -+ void *pvt); - - errno_t sssctl_domain_status(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt); - --errno_t sssctl_backup_local_data(struct sss_cmdline *cmdline, -- struct sss_tool_ctx *tool_ctx, -- void *pvt); -- --errno_t sssctl_restore_local_data(struct sss_cmdline *cmdline, -+errno_t sssctl_client_data_backup(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt); - --errno_t sssctl_remove_cache(struct sss_cmdline *cmdline, -+errno_t sssctl_client_data_restore(struct sss_cmdline *cmdline, -+ struct sss_tool_ctx *tool_ctx, -+ void *pvt); -+ -+errno_t sssctl_cache_remove(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt); - --errno_t sssctl_upgrade_cache(struct sss_cmdline *cmdline, -+errno_t sssctl_cache_upgrade(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt); - --errno_t sssctl_remove_logs(struct sss_cmdline *cmdline, -+errno_t sssctl_logs_remove(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt); - --errno_t sssctl_fetch_logs(struct sss_cmdline *cmdline, -+errno_t sssctl_logs_fetch(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt); - --errno_t sssctl_user(struct sss_cmdline *cmdline, -- struct sss_tool_ctx *tool_ctx, -- void *pvt); -+errno_t sssctl_user_show(struct sss_cmdline *cmdline, -+ struct sss_tool_ctx *tool_ctx, -+ void *pvt); - --errno_t sssctl_group(struct sss_cmdline *cmdline, -- struct sss_tool_ctx *tool_ctx, -- void *pvt); -+errno_t sssctl_group_show(struct sss_cmdline *cmdline, -+ struct sss_tool_ctx *tool_ctx, -+ void *pvt); - --errno_t sssctl_netgroup(struct sss_cmdline *cmdline, -- struct sss_tool_ctx *tool_ctx, -- void *pvt); -+errno_t sssctl_netgroup_show(struct sss_cmdline *cmdline, -+ struct sss_tool_ctx *tool_ctx, -+ void *pvt); - - errno_t sssctl_config_check(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt); -- - #endif /* _SSSCTL_H_ */ -diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c -index 4a1f3558ed7064ca40ccf9313d99fbab36e6e4c9..b1a7cc933d58d99fe34a05cb6eabe11a5270cee1 100644 ---- a/src/tools/sssctl/sssctl_cache.c -+++ b/src/tools/sssctl/sssctl_cache.c -@@ -569,9 +569,9 @@ struct sssctl_cache_opts { - int id; - }; - --errno_t sssctl_user(struct sss_cmdline *cmdline, -- struct sss_tool_ctx *tool_ctx, -- void *pvt) -+errno_t sssctl_user_show(struct sss_cmdline *cmdline, -+ struct sss_tool_ctx *tool_ctx, -+ void *pvt) - { - struct sssctl_cache_opts opts = {0}; - const char *attr; -@@ -616,9 +616,9 @@ errno_t sssctl_user(struct sss_cmdline *cmdline, - return EOK; - } - --errno_t sssctl_group(struct sss_cmdline *cmdline, -- struct sss_tool_ctx *tool_ctx, -- void *pvt) -+errno_t sssctl_group_show(struct sss_cmdline *cmdline, -+ struct sss_tool_ctx *tool_ctx, -+ void *pvt) - { - struct sssctl_cache_opts opts = {0}; - const char *attr; -@@ -662,9 +662,9 @@ errno_t sssctl_group(struct sss_cmdline *cmdline, - return EOK; - } - --errno_t sssctl_netgroup(struct sss_cmdline *cmdline, -- struct sss_tool_ctx *tool_ctx, -- void *pvt) -+errno_t sssctl_netgroup_show(struct sss_cmdline *cmdline, -+ struct sss_tool_ctx *tool_ctx, -+ void *pvt) - { - struct sssctl_cache_opts opts = {0}; - errno_t ret; -diff --git a/src/tools/sssctl/sssctl_data.c b/src/tools/sssctl/sssctl_data.c -index 3ab2ddf20006b2d5a26e2f167819677431854eb6..a26ddd8d5200319e75282b738791cf270f0d75a8 100644 ---- a/src/tools/sssctl/sssctl_data.c -+++ b/src/tools/sssctl/sssctl_data.c -@@ -124,9 +124,9 @@ static errno_t sssctl_backup(bool force) - return ret; - } - --errno_t sssctl_backup_local_data(struct sss_cmdline *cmdline, -- struct sss_tool_ctx *tool_ctx, -- void *pvt) -+errno_t sssctl_client_data_backup(struct sss_cmdline *cmdline, -+ struct sss_tool_ctx *tool_ctx, -+ void *pvt) - { - struct sssctl_data_opts opts = {0}; - errno_t ret; -@@ -184,9 +184,9 @@ static errno_t sssctl_restore(bool force_start, bool force_restart) - return ret; - } - --errno_t sssctl_restore_local_data(struct sss_cmdline *cmdline, -- struct sss_tool_ctx *tool_ctx, -- void *pvt) -+errno_t sssctl_client_data_restore(struct sss_cmdline *cmdline, -+ struct sss_tool_ctx *tool_ctx, -+ void *pvt) - { - struct sssctl_data_opts opts = {0}; - errno_t ret; -@@ -207,7 +207,7 @@ errno_t sssctl_restore_local_data(struct sss_cmdline *cmdline, - return sssctl_restore(opts.start, opts.restart); - } - --errno_t sssctl_remove_cache(struct sss_cmdline *cmdline, -+errno_t sssctl_cache_remove(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt) - { -@@ -259,7 +259,7 @@ errno_t sssctl_remove_cache(struct sss_cmdline *cmdline, - return EOK; - } - --errno_t sssctl_upgrade_cache(struct sss_cmdline *cmdline, -+errno_t sssctl_cache_upgrade(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt) - { -diff --git a/src/tools/sssctl/sssctl_domains.c b/src/tools/sssctl/sssctl_domains.c -index 5aaaf770981a92b80b9376fd244d2d97e0502dac..cfc4e56133213e27496350033d4d28c3f5b5c63d 100644 ---- a/src/tools/sssctl/sssctl_domains.c -+++ b/src/tools/sssctl/sssctl_domains.c -@@ -27,9 +27,9 @@ - #include "sbus/sssd_dbus.h" - #include "responder/ifp/ifp_iface.h" - --errno_t sssctl_list_domains(struct sss_cmdline *cmdline, -- struct sss_tool_ctx *tool_ctx, -- void *pvt) -+errno_t sssctl_domain_list(struct sss_cmdline *cmdline, -+ struct sss_tool_ctx *tool_ctx, -+ void *pvt) - { - sss_sifp_ctx *sifp; - sss_sifp_error error; -diff --git a/src/tools/sssctl/sssctl_logs.c b/src/tools/sssctl/sssctl_logs.c -index a203474648e3c1719e16146f8f7b484f9d62541c..883f2ac2fa688b672cd8f388e4c571d1a12a32af 100644 ---- a/src/tools/sssctl/sssctl_logs.c -+++ b/src/tools/sssctl/sssctl_logs.c -@@ -34,7 +34,7 @@ struct sssctl_logs_opts { - int archived; - }; - --errno_t sssctl_remove_logs(struct sss_cmdline *cmdline, -+errno_t sssctl_logs_remove(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt) - { -@@ -74,7 +74,7 @@ errno_t sssctl_remove_logs(struct sss_cmdline *cmdline, - return EOK; - } - --errno_t sssctl_fetch_logs(struct sss_cmdline *cmdline, -+errno_t sssctl_logs_fetch(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt) - { --- -2.4.11 - diff --git a/SOURCES/0067-PAM-Add-application-services.patch b/SOURCES/0067-PAM-Add-application-services.patch new file mode 100644 index 0000000..2c8fddd --- /dev/null +++ b/SOURCES/0067-PAM-Add-application-services.patch @@ -0,0 +1,452 @@ +From 855201c70f69f2b1dbcb3faef780fbdb84354f18 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Sun, 26 Mar 2017 18:28:41 +0200 +Subject: [PATCH 67/72] PAM: Add application services + +Related to: +https://pagure.io/SSSD/sssd/issue/3310 + +Adds a new PAM responder option 'pam_app_services'. This option can hold +a list of PAM services that are allowed to contact the application +non-POSIX domains. These services are NOT allowed to contact any of the +POSIX domains. + +Reviewed-by: Sumit Bose +--- + src/confdb/confdb.h | 1 + + src/config/SSSDConfig/__init__.py.in | 1 + + src/config/cfg_rules.ini | 1 + + src/config/etc/sssd.api.conf | 1 + + src/man/sssd.conf.5.xml | 12 +++ + src/responder/pam/pamsrv.c | 33 +++++++ + src/responder/pam/pamsrv.h | 5 ++ + src/responder/pam/pamsrv_cmd.c | 26 +++++- + src/tests/cmocka/test_pam_srv.c | 167 ++++++++++++++++++++++++++++++++++- + 9 files changed, 241 insertions(+), 6 deletions(-) + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 5a8d377c312f641f544b1c7cf38826192462ea3c..8719c239362b371fcdb1b78956bcddde871f141b 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -129,6 +129,7 @@ + #define CONFDB_PAM_CERT_AUTH "pam_cert_auth" + #define CONFDB_PAM_CERT_DB_PATH "pam_cert_db_path" + #define CONFDB_PAM_P11_CHILD_TIMEOUT "p11_child_timeout" ++#define CONFDB_PAM_APP_SERVICES "pam_app_services" + + /* SUDO */ + #define CONFDB_SUDO_CONF_ENTRY "config/sudo" +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index 806611b6076048c08ce08c772dbd3cea5fdd656c..211338778e81c1c60ffb3cdbc67c9619343d7798 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -102,6 +102,7 @@ option_strings = { + 'pam_cert_auth' : _('Allow certificate based/Smartcard authentication.'), + 'pam_cert_db_path' : _('Path to certificate databse with PKCS#11 modules.'), + 'p11_child_timeout' : _('How many seconds will pam_sss wait for p11_child to finish'), ++ 'pam_app_services' : _('Which PAM services are permitted to contact application domains'), + + # [sudo] + 'sudo_timed' : _('Whether to evaluate the time-based attributes in sudo rules'), +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 8fd2d2c5236246394353a88c50d1510bd6233f77..1a749db754cedd87f263f7ae596d6f8238bb4357 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -119,6 +119,7 @@ option = pam_account_locked_message + option = pam_cert_auth + option = pam_cert_db_path + option = p11_child_timeout ++option = pam_app_services + + [rule/allowed_sudo_options] + validator = ini_allowed_options +diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf +index a38b24208f89e4502e41625c540ea9958d5bbffe..a1a0c2992925a4c7df86832117eec2a0cf7894c9 100644 +--- a/src/config/etc/sssd.api.conf ++++ b/src/config/etc/sssd.api.conf +@@ -73,6 +73,7 @@ pam_account_locked_message = str, None, false + pam_cert_auth = bool, None, false + pam_cert_db_path = str, None, false + p11_child_timeout = int, None, false ++pam_app_services = str, None, false + + [sudo] + # sudo service +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 8294793c765bfa6bf481693c7d7f206950454681..c4e30396f16c40db37af2f56ac218b6e37201ef7 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -1325,6 +1325,18 @@ pam_account_locked_message = Account locked, please contact help desk. + + + ++ ++ pam_app_services (string) ++ ++ ++ Which PAM services are permitted to contact ++ domains of type application ++ ++ ++ Default: Not set ++ ++ ++ + + + +diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c +index ab3f4545520f3fcb2492a6089a039c46f0fb847f..79470823d18138da6ef9235e6336a3220ead1797 100644 +--- a/src/responder/pam/pamsrv.c ++++ b/src/responder/pam/pamsrv.c +@@ -166,6 +166,32 @@ done: + return ret; + } + ++static errno_t get_app_services(struct pam_ctx *pctx) ++{ ++ errno_t ret; ++ ++ ret = confdb_get_string_as_list(pctx->rctx->cdb, pctx, ++ CONFDB_PAM_CONF_ENTRY, ++ CONFDB_PAM_APP_SERVICES, ++ &pctx->app_services); ++ if (ret == ENOENT) { ++ pctx->app_services = talloc_zero_array(pctx, char *, 1); ++ if (pctx->app_services == NULL) { ++ return ENOMEM; ++ } ++ /* Allocating an empty array makes it easier for the consumer ++ * to iterate over it ++ */ ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot read "CONFDB_PAM_APP_SERVICES" [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ return EOK; ++} ++ + static int pam_process_init(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct confdb_ctx *cdb, +@@ -219,6 +245,13 @@ static int pam_process_init(TALLOC_CTX *mem_ctx, + goto done; + } + ++ ret = get_app_services(pctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "get_app_services failed: %d:[%s].\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ + /* Enable automatic reconnection to the Data Provider */ + + /* FIXME: "retries" is too generic, either get it from a global config +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index b3eb56441048ecdba82866a95f1d6d6d5e786c60..b569748fe2a2005cee5df34bef55e803175492a9 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -26,6 +26,7 @@ + #include "util/util.h" + #include "sbus/sssd_dbus.h" + #include "responder/common/responder.h" ++#include "responder/common/cache_req/cache_req.h" + + struct pam_auth_req; + +@@ -42,6 +43,9 @@ struct pam_ctx { + char **public_domains; + int public_domains_count; + ++ /* What services are permitted to access application domains */ ++ char **app_services; ++ + bool cert_auth; + int p11_child_debug_fd; + char *nss_db; +@@ -54,6 +58,7 @@ struct pam_auth_dp_req { + struct pam_auth_req { + struct cli_ctx *cctx; + struct sss_domain_info *domain; ++ enum cache_req_dom_type req_dom_type; + + struct pam_data *pd; + +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index fa6d2cc10fe1404196f9d9221a469d7a9a768211..f2b3c74b483e527932dda42279d14a9ac184b475 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1161,6 +1161,25 @@ static bool is_domain_public(char *name, + return false; + } + ++static enum cache_req_dom_type ++get_domain_request_type(struct pam_auth_req *preq, ++ struct pam_ctx *pctx) ++{ ++ enum cache_req_dom_type req_dom_type; ++ ++ /* By default, only POSIX domains are to be contacted */ ++ req_dom_type = CACHE_REQ_POSIX_DOM; ++ ++ for (int i = 0; pctx->app_services[i]; i++) { ++ if (strcmp(pctx->app_services[i], preq->pd->service) == 0) { ++ req_dom_type = CACHE_REQ_APPLICATION_DOM; ++ break; ++ } ++ } ++ ++ return req_dom_type; ++} ++ + static errno_t check_cert(TALLOC_CTX *mctx, + struct tevent_context *ev, + struct pam_ctx *pctx, +@@ -1257,6 +1276,9 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) + goto done; + } + ++ /* Determine what domain type to contact */ ++ preq->req_dom_type = get_domain_request_type(preq, pctx); ++ + /* try backend first for authentication before doing local Smartcard + * authentication */ + if (pd->cmd != SSS_PAM_AUTHENTICATE && may_do_cert_auth(pctx, pd)) { +@@ -1316,7 +1338,7 @@ static void pam_forwarder_cert_cb(struct tevent_req *req) + + req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx, + pctx->rctx->ncache, 0, +- CACHE_REQ_POSIX_DOM, NULL, ++ preq->req_dom_type, NULL, + cert); + if (req == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n"); +@@ -1509,7 +1531,7 @@ static int pam_check_user_search(struct pam_auth_req *preq) + preq->cctx->rctx, + preq->cctx->rctx->ncache, + 0, +- CACHE_REQ_POSIX_DOM, ++ preq->req_dom_type, + preq->pd->domain, + data); + if (!dpreq) { +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index 847419658bb983e6548722d6fa6fb22c63ee86b8..d249b8f1ea48f1c17b461c3add9e8c63774e5f88 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -186,6 +186,15 @@ struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx) + ret = sss_hash_create(pctx, 10, &pctx->id_table); + assert_int_equal(ret, EOK); + ++ /* Two NULLs so that tests can just assign a const to the first slot ++ * should they need it. The code iterates until first NULL anyway ++ */ ++ pctx->app_services = talloc_zero_array(pctx, char *, 2); ++ if (pctx->app_services == NULL) { ++ talloc_free(pctx); ++ return NULL; ++ } ++ + return pctx; + } + +@@ -495,8 +504,12 @@ int __wrap_pam_dp_send_req(struct pam_auth_req *preq, int timeout) + return EOK; + } + +-static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name, +- const char *pwd, const char *fa2) ++static void mock_input_pam_ex(TALLOC_CTX *mem_ctx, ++ const char *name, ++ const char *pwd, ++ const char *fa2, ++ const char *svc, ++ bool contact_dp) + { + size_t buf_size; + uint8_t *m_buf; +@@ -536,7 +549,10 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name, + } + } + +- pi.pam_service = "pam_test_service"; ++ if (svc == NULL) { ++ svc = "pam_test_service"; ++ } ++ pi.pam_service = svc; + pi.pam_service_size = strlen(pi.pam_service) + 1; + pi.pam_tty = "/dev/tty"; + pi.pam_tty_size = strlen(pi.pam_tty) + 1; +@@ -559,7 +575,17 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name, + will_return(__wrap_sss_packet_get_body, buf_size); + + mock_parse_inp(name, NULL, EOK); +- mock_account_recv_simple(); ++ if (contact_dp) { ++ mock_account_recv_simple(); ++ } ++} ++ ++static void mock_input_pam(TALLOC_CTX *mem_ctx, ++ const char *name, ++ const char *pwd, ++ const char *fa2) ++{ ++ return mock_input_pam_ex(mem_ctx, name, pwd, fa2, NULL, true); + } + + static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, +@@ -2097,6 +2123,127 @@ void test_filter_response(void **state) + talloc_free(pd); + } + ++static int pam_test_setup_appsvc_posix_dom(void **state) ++{ ++ int ret; ++ ++ ret = pam_test_setup(state); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ /* This config option is only read on startup, which is not executed ++ * in test, so we can't just pass in a param ++ */ ++ pam_test_ctx->pctx->app_services[0] = discard_const("app_svc"); ++ return 0; ++} ++ ++void test_appsvc_posix_dom(void **state) ++{ ++ int ret; ++ ++ /* The domain is POSIX, the request will skip over it */ ++ mock_input_pam_ex(pam_test_ctx, "pamuser", NULL, NULL, "app_svc", false); ++ pam_test_ctx->exp_pam_status = PAM_USER_UNKNOWN; ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ set_cmd_cb(test_pam_user_unknown_check); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_not_appsvc_posix_dom(void **state) ++{ ++ int ret; ++ ++ /* A different service than the app one can authenticate against a POSIX domain */ ++ mock_input_pam_ex(pam_test_ctx, "pamuser", NULL, NULL, "not_app_svc", true); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ set_cmd_cb(test_pam_simple_check); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++static int pam_test_setup_appsvc_app_dom(void **state) ++{ ++ struct sss_test_conf_param dom_params[] = { ++ { "domain_type", "application" }, ++ { NULL, NULL }, /* Sentinel */ ++ }; ++ struct sss_test_conf_param pam_params[] = { ++ { NULL, NULL }, /* Sentinel */ ++ }; ++ struct sss_test_conf_param monitor_params[] = { ++ { NULL, NULL }, /* Sentinel */ ++ }; ++ ++ ++ test_pam_setup(dom_params, pam_params, monitor_params, state); ++ pam_test_setup_common(); ++ ++ /* This config option is only read on startup, which is not executed ++ * in test, so we can't just pass in a param ++ */ ++ pam_test_ctx->pctx->app_services[0] = discard_const("app_svc"); ++ return 0; ++} ++ ++void test_appsvc_app_dom(void **state) ++{ ++ int ret; ++ ++ /* The domain is POSIX, the request will skip over it */ ++ mock_input_pam_ex(pam_test_ctx, "pamuser", NULL, NULL, "app_svc", true); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ set_cmd_cb(test_pam_simple_check); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_not_appsvc_app_dom(void **state) ++{ ++ int ret; ++ ++ /* A different service than the app one can authenticate against a POSIX domain */ ++ mock_input_pam_ex(pam_test_ctx, "pamuser", NULL, NULL, "not_app_svc", false); ++ ++ pam_test_ctx->exp_pam_status = PAM_USER_UNKNOWN; ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ set_cmd_cb(test_pam_user_unknown_check); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ + int main(int argc, const char *argv[]) + { + int rv; +@@ -2216,6 +2363,18 @@ int main(int argc, const char *argv[]) + + cmocka_unit_test_setup_teardown(test_filter_response, + pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_appsvc_posix_dom, ++ pam_test_setup_appsvc_posix_dom, ++ pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_not_appsvc_posix_dom, ++ pam_test_setup_appsvc_posix_dom, ++ pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_appsvc_app_dom, ++ pam_test_setup_appsvc_app_dom, ++ pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_not_appsvc_app_dom, ++ pam_test_setup_appsvc_posix_dom, ++ pam_test_teardown), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ +-- +2.9.3 + diff --git a/SOURCES/0067-SDAP-sanitize-member-name-before-using-in-filter.patch b/SOURCES/0067-SDAP-sanitize-member-name-before-using-in-filter.patch deleted file mode 100644 index ed5cdfa..0000000 --- a/SOURCES/0067-SDAP-sanitize-member-name-before-using-in-filter.patch +++ /dev/null @@ -1,57 +0,0 @@ -From a711326867dd901d349c648392b55b6e318196db Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Tue, 2 Aug 2016 15:20:35 +0200 -Subject: [PATCH 67/74] SDAP: sanitize member name before using in filter -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -It caused an errors. - -(Tue Aug 2 06:29:39 2016) [sssd[be[LDAP]]] [sysdb_cache_search_users] -(0x2000): Search users with filter: -(&(objectclass=user)(nameAlias=t(u)ser@ldap)) -(Tue Aug 2 06:29:39 2016) [sssd[be[LDAP]]] [sysdb_cache_search_users] -(0x0080): Error: 5 (Input/output error) - -Resolves: -https://fedorahosted.org/sssd/ticket/3121 - -Reviewed-by: Pavel Březina ---- - src/providers/ldap/sdap_async_groups.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c -index 102c1c0384be6da8732d56b7a318ded5a5132360..f19b68b8c403734f88b51a411ba0d009977d3491 100644 ---- a/src/providers/ldap/sdap_async_groups.c -+++ b/src/providers/ldap/sdap_async_groups.c -@@ -1501,6 +1501,7 @@ sdap_process_missing_member_2307(struct sdap_process_group_state *state, - const char *filter; - const char *username; - const char *user_dn; -+ char *sanitized_name; - size_t count; - struct ldb_message **msgs = NULL; - static const char *attrs[] = { SYSDB_NAME, NULL }; -@@ -1508,8 +1509,16 @@ sdap_process_missing_member_2307(struct sdap_process_group_state *state, - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) return ENOMEM; - -+ ret = sss_filter_sanitize(tmp_ctx, member_name, &sanitized_name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to sanitize the given name:'%s'.\n", member_name); -+ goto done; -+ } -+ - /* Check for the alias in the sysdb */ -- filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_NAME_ALIAS, member_name); -+ filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_NAME_ALIAS, -+ sanitized_name); - if (!filter) { - ret = ENOMEM; - goto done; --- -2.4.11 - diff --git a/SOURCES/0068-SDAP-sysdb_search_users-does-not-set-users_count-for.patch b/SOURCES/0068-SDAP-sysdb_search_users-does-not-set-users_count-for.patch deleted file mode 100644 index f82f6d8..0000000 --- a/SOURCES/0068-SDAP-sysdb_search_users-does-not-set-users_count-for.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 4e1111d869c8980f81a17b58844c48f1a342d774 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Thu, 4 Aug 2016 08:50:50 +0200 -Subject: [PATCH 68/74] SDAP: sysdb_search_users does not set users_count for - failures -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -==32577== Conditional jump or move depends on uninitialised value(s) -==32577== at 0x140DCE10: sdap_process_missing_member_2307 (sdap_async_groups.c:1556) -==32577== by 0x140DCE10: sdap_process_group_members_2307 (sdap_async_groups.c:1625) -==32577== by 0x140DCE10: sdap_process_group_send (sdap_async_groups.c:1298) -==32577== by 0x140DCE10: sdap_get_groups_process (sdap_async_groups.c:2130) -==32577== by 0x140CFDA8: generic_ext_search_handler.isra.3 (sdap_async.c:1688) -==32577== by 0x140D2416: sdap_get_generic_op_finished (sdap_async.c:1578) -==32577== by 0x140D0DFC: sdap_process_message (sdap_async.c:353) -==32577== by 0x140D0DFC: sdap_process_result (sdap_async.c:197) -==32577== by 0x8BF1B4E: tevent_common_loop_timer_delay (tevent_timed.c:341) -==32577== by 0x8BF2B59: epoll_event_loop_once (tevent_epoll.c:911) -==32577== by 0x8BF1256: std_event_loop_once (tevent_standard.c:114) -==32577== by 0x8BED40C: _tevent_loop_once (tevent.c:533) -==32577== by 0x8BED5AA: tevent_common_loop_wait (tevent.c:637) -==32577== by 0x8BF11F6: std_event_loop_wait (tevent_standard.c:140) -==32577== by 0x529DD02: server_loop (server.c:702) -==32577== by 0x110951: main (data_provider_be.c:587) - -Resolves: -https://fedorahosted.org/sssd/ticket/3121 - -Reviewed-by: Pavel Březina ---- - src/providers/ldap/sdap_async_groups.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c -index f19b68b8c403734f88b51a411ba0d009977d3491..72760b75acae4cb6ce15c72f16dae8e859d89847 100644 ---- a/src/providers/ldap/sdap_async_groups.c -+++ b/src/providers/ldap/sdap_async_groups.c -@@ -1553,7 +1553,7 @@ sdap_process_missing_member_2307(struct sdap_process_group_state *state, - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Could not add group member %s\n", username); - } -- } else if (ret == ENOENT || count == 0) { -+ } else if (ret == ENOENT) { - /* The entry really does not exist, add a ghost */ - DEBUG(SSSDBG_TRACE_FUNC, "Adding a ghost entry\n"); - ret = sdap_add_group_member_2307(state->ghost_dns, member_name); --- -2.4.11 - diff --git a/SOURCES/0068-SYSDB-Allow-storing-non-POSIX-users.patch b/SOURCES/0068-SYSDB-Allow-storing-non-POSIX-users.patch new file mode 100644 index 0000000..8ed534b --- /dev/null +++ b/SOURCES/0068-SYSDB-Allow-storing-non-POSIX-users.patch @@ -0,0 +1,152 @@ +From ea8a4436b66877bbae1a73d11917ecdb3bf72718 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 22 Mar 2017 13:00:31 +0100 +Subject: [PATCH 68/72] SYSDB: Allow storing non-POSIX users + +Related to: +https://pagure.io/SSSD/sssd/issue/3310 + +We already do the same for groups. If the user does not have UID number +set but does have the POSIX: false attribute set, then we save the user +with zero UID and the non-POSIX flag. + +Reviewed-by: Sumit Bose +--- + src/db/sysdb_ops.c | 32 ++++++++++++++++++++-------- + src/tests/sysdb-tests.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 79 insertions(+), 9 deletions(-) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 919f22370ff87eff2bf0bb569ca90f1ee699a61e..3cf9d903f25b9ccd506d7957c94040bdc7d658a3 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -1855,6 +1855,7 @@ int sysdb_add_user(struct sss_domain_info *domain, + struct sysdb_attrs *id_attrs; + uint32_t id; + int ret; ++ bool posix; + + if (domain->mpg) { + if (gid != 0) { +@@ -1926,7 +1927,28 @@ int sysdb_add_user(struct sss_domain_info *domain, + /* Not fatal */ + } + +- if (uid == 0) { ++ if (!attrs) { ++ attrs = sysdb_new_attrs(tmp_ctx); ++ if (!attrs) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ ret = sysdb_attrs_get_bool(attrs, SYSDB_POSIX, &posix); ++ if (ret == ENOENT) { ++ posix = true; ++ ret = sysdb_attrs_add_bool(attrs, SYSDB_POSIX, true); ++ if (ret) { ++ DEBUG(SSSDBG_TRACE_LIBS, "Failed to add posix attribute.\n"); ++ goto done; ++ } ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_LIBS, "Failed to get posix attribute.\n"); ++ goto done; ++ } ++ ++ if (uid == 0 && posix == true) { + ret = sysdb_get_new_id(domain, &id); + if (ret) goto done; + +@@ -1948,14 +1970,6 @@ int sysdb_add_user(struct sss_domain_info *domain, + if (ret) goto done; + } + +- if (!attrs) { +- attrs = sysdb_new_attrs(tmp_ctx); +- if (!attrs) { +- ret = ENOMEM; +- goto done; +- } +- } +- + if (!now) { + now = time(NULL); + } +diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c +index 1767dc3c734c6b2e5f74564debd603e2442f491b..6ec82ce4ca5c4f918bc9f3144c21f33b270ea47e 100644 +--- a/src/tests/sysdb-tests.c ++++ b/src/tests/sysdb-tests.c +@@ -1428,6 +1428,59 @@ START_TEST (test_sysdb_get_user_attr_subdomain) + } + END_TEST + ++START_TEST (test_sysdb_add_nonposix_user) ++{ ++ struct sysdb_test_ctx *test_ctx; ++ const char *get_attrs[] = { SYSDB_GIDNUM, ++ SYSDB_UIDNUM, ++ SYSDB_POSIX, ++ NULL }; ++ struct ldb_result *res; ++ const char *attrval; ++ const char *username = "test_sysdb_add_nonposix_user"; ++ const char *fq_name; ++ struct sysdb_attrs *user_attrs; ++ int ret; ++ uint64_t id; ++ ++ /* Setup */ ++ ret = setup_sysdb_tests(&test_ctx); ++ fail_if(ret != EOK, "Could not set up the test"); ++ ++ /* Create user */ ++ fq_name = sss_create_internal_fqname(test_ctx, username, test_ctx->domain->name); ++ fail_if(fq_name == NULL, "Failed to create fq name."); ++ ++ user_attrs = sysdb_new_attrs(test_ctx); ++ fail_if(user_attrs == NULL); ++ ++ ret = sysdb_attrs_add_bool(user_attrs, SYSDB_POSIX, false); ++ fail_if(ret != EOK, "Could not add attribute"); ++ ++ ret = sysdb_add_user(test_ctx->domain, fq_name, 0, 0, "Gecos", ++ "/home/userhome", "/bin/bash", NULL, user_attrs, 0, 0); ++ fail_if(ret != EOK, "sysdb_add_user failed."); ++ ++ /* Test */ ++ ret = sysdb_get_user_attr(test_ctx, test_ctx->domain, fq_name, ++ get_attrs, &res); ++ fail_if(ret != EOK, "Could not get user attributes."); ++ fail_if(res->count != 1, "Invalid number of entries, expected 1, got %d", ++ res->count); ++ ++ attrval = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_POSIX, NULL); ++ fail_if(strcasecmp(attrval, "false") != 0, "Got bad attribute value."); ++ ++ id = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 123); ++ fail_unless(id == 0, "Wrong UID value"); ++ ++ id = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 123); ++ fail_unless(id == 0, "Wrong GID value"); ++ ++ talloc_free(test_ctx); ++} ++END_TEST ++ + START_TEST (test_sysdb_add_group_member) + { + struct sysdb_test_ctx *test_ctx; +@@ -7044,6 +7097,9 @@ Suite *create_sysdb_suite(void) + /* Test GetUserAttr with subdomain user */ + tcase_add_test(tc_sysdb, test_sysdb_get_user_attr_subdomain); + ++ /* Test adding a non-POSIX user */ ++ tcase_add_test(tc_sysdb, test_sysdb_add_nonposix_user); ++ + /* ===== NETGROUP TESTS ===== */ + + /* Create a new netgroup */ +-- +2.9.3 + diff --git a/SOURCES/0069-SYSDB-Only-generate-new-UID-in-local-domain.patch b/SOURCES/0069-SYSDB-Only-generate-new-UID-in-local-domain.patch new file mode 100644 index 0000000..c6a76f3 --- /dev/null +++ b/SOURCES/0069-SYSDB-Only-generate-new-UID-in-local-domain.patch @@ -0,0 +1,36 @@ +From ee344275c041f68e943360c975e3356ba251cef8 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 28 Mar 2017 14:49:31 +0200 +Subject: [PATCH 69/72] SYSDB: Only generate new UID in local domain + +To avoid issues where a user with no UID but without the posix=false +flag was passed to sysdb, we only allow generating the new ID in the +local domain. This might prevent bugs where non-POSIX users would get a +UID created by sysdb which might allow accessing resources owned by that +UID. + +Reviewed-by: Sumit Bose +--- + src/db/sysdb_ops.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 3cf9d903f25b9ccd506d7957c94040bdc7d658a3..4d7b2abd8026c90aaf4e7be687102e459cf3690e 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -1422,6 +1422,12 @@ int sysdb_get_new_id(struct sss_domain_info *domain, + return ENOMEM; + } + ++ if (strcasecmp(domain->provider, "local") != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Generating new ID is only supported in the local domain!\n"); ++ return ENOTSUP; ++ } ++ + base_dn = sysdb_domain_dn(tmp_ctx, domain); + if (!base_dn) { + talloc_zfree(tmp_ctx); +-- +2.9.3 + diff --git a/SOURCES/0069-SYSDB-Sanitize-dn-in-sysdb_get_user_members_recursiv.patch b/SOURCES/0069-SYSDB-Sanitize-dn-in-sysdb_get_user_members_recursiv.patch deleted file mode 100644 index 24ea5be..0000000 --- a/SOURCES/0069-SYSDB-Sanitize-dn-in-sysdb_get_user_members_recursiv.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 0bb66d94542920870effa808861c0c20180111ba Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Tue, 2 Aug 2016 15:20:19 +0200 -Subject: [PATCH 69/74] SYSDB: Sanitize dn in - sysdb_get_user_members_recursively -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -There was a crash in nss responder when a group contained -a user with special charactes which shoudl be sanitized before -using in filter. - -==31651== Conditional jump or move depends on uninitialised value(s) -==31651== at 0x8BEA7DE: _talloc_steal_loc (talloc.c:1215) -==31651== by 0x5264889: sysdb_get_user_members_recursively (sysdb_ops.c:4759) -==31651== by 0x5278F61: sysdb_add_group_member_overrides (sysdb_views.c:1375) -==31651== by 0x526677C: sysdb_getgrnam_with_views (sysdb_search.c:799) -==31651== by 0x1172F6: nss_cmd_getgrnam_search (nsssrv_cmd.c:3168) -==31651== by 0x119C67: nss_cmd_getby_dp_callback (nsssrv_cmd.c:1382) -==31651== by 0x10FD14: nsssrv_dp_send_acct_req_done (nsssrv_cmd.c:916) -==31651== by 0x12898B: sss_dp_internal_get_done (responder_dp.c:791) -==31651== by 0x58FF861: complete_pending_call_and_unlock (dbus-connection.c:2314) -==31651== by 0x5902B50: dbus_connection_dispatch (dbus-connection.c:4580) -==31651== by 0x527F261: sbus_dispatch (sssd_dbus_connection.c:96) -==31651== by 0x89D8B4E: tevent_common_loop_timer_delay (tevent_timed.c:341) - -Resolves: -https://fedorahosted.org/sssd/ticket/3121 - -Reviewed-by: Pavel Březina ---- - src/db/sysdb_ops.c | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index ed177d1730723a61e01167a75a0baca6d81252f8..342e16fb20e2c418745b137162425509ca1fd0cb 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -4722,6 +4722,7 @@ errno_t sysdb_get_user_members_recursively(TALLOC_CTX *mem_ctx, - struct ldb_result *res; - struct ldb_dn *base_dn; - char *filter; -+ char *sanitized_name; - const char *attrs[] = SYSDB_PW_ATTRS; - struct ldb_message **msgs; - -@@ -4737,8 +4738,17 @@ errno_t sysdb_get_user_members_recursively(TALLOC_CTX *mem_ctx, - goto done; - } - -+ ret = sss_filter_sanitize(tmp_ctx, ldb_dn_get_linearized(group_dn), -+ &sanitized_name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to sanitize the given name:'%s'.\n", -+ ldb_dn_get_linearized(group_dn)); -+ goto done; -+ } -+ - filter = talloc_asprintf(tmp_ctx, "(&("SYSDB_UC")("SYSDB_MEMBEROF"=%s))", -- ldb_dn_get_linearized(group_dn)); -+ sanitized_name); - if (filter == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); - ret = ENOMEM; --- -2.4.11 - diff --git a/SOURCES/0070-LDAP-save-non-POSIX-users-in-application-domains.patch b/SOURCES/0070-LDAP-save-non-POSIX-users-in-application-domains.patch new file mode 100644 index 0000000..d70a026 --- /dev/null +++ b/SOURCES/0070-LDAP-save-non-POSIX-users-in-application-domains.patch @@ -0,0 +1,141 @@ +From 3abbd7569f96a980676e0323d95301c50acdf062 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 22 Mar 2017 13:06:08 +0100 +Subject: [PATCH 70/72] LDAP: save non-POSIX users in application domains + +Related to: +https://pagure.io/SSSD/sssd/issue/3310 + +If a user being saved by the LDAP provider does not have a UID or GID +and the domain type is application, we save the user entry as non-POSIX. + +Reviewed-by: Sumit Bose +--- + src/providers/ldap/sdap_async_users.c | 72 +++++++++++++++++++++++++++-------- + 1 file changed, 57 insertions(+), 15 deletions(-) + +diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c +index 3d957ab584865f74499bc732395388a78965fe5f..265cd7e4f7929c295d5bdcfbd781221b74601f13 100644 +--- a/src/providers/ldap/sdap_async_users.c ++++ b/src/providers/ldap/sdap_async_users.c +@@ -112,6 +112,28 @@ done: + return ret; + } + ++static errno_t sdap_set_non_posix_flag(struct sysdb_attrs *attrs, ++ const char *pkey) ++{ ++ errno_t ret; ++ ++ ret = sysdb_attrs_add_uint32(attrs, pkey, 0); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to add a zero ID to a non-posix object!\n"); ++ return ret; ++ } ++ ++ ret = sysdb_attrs_add_bool(attrs, SYSDB_POSIX, false); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Error: Failed to mark objects as non-posix!\n"); ++ return ret; ++ } ++ ++ return EOK; ++} ++ + /* FIXME: support storing additional attributes */ + int sdap_save_user(TALLOC_CTX *memctx, + struct sdap_options *opts, +@@ -130,8 +152,8 @@ int sdap_save_user(TALLOC_CTX *memctx, + const char *homedir; + const char *shell; + const char *orig_dn = NULL; +- uid_t uid; +- gid_t gid; ++ uid_t uid = 0; ++ gid_t gid = 0; + struct sysdb_attrs *user_attrs; + char *upn = NULL; + size_t i; +@@ -146,6 +168,7 @@ int sdap_save_user(TALLOC_CTX *memctx, + size_t c; + char *p1; + char *p2; ++ bool is_posix = true; + + DEBUG(SSSDBG_TRACE_FUNC, "Save user\n"); + +@@ -295,19 +318,29 @@ int sdap_save_user(TALLOC_CTX *memctx, + ret = sysdb_attrs_get_uint32_t(attrs, + opts->user_map[SDAP_AT_USER_UID].sys_name, + &uid); +- if (ret != EOK) { ++ if (ret == ENOENT && dom->type == DOM_TYPE_APPLICATION) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, ++ "Marking object as non-posix and setting ID=0!\n"); ++ ret = sdap_set_non_posix_flag(user_attrs, ++ opts->user_map[SDAP_AT_USER_UID].sys_name); ++ if (ret != EOK) { ++ goto done; ++ } ++ is_posix = false; ++ } else if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "no uid provided for [%s] in domain [%s].\n", ++ "Cannot retrieve UID for [%s] in domain [%s].\n", + user_name, dom->name); +- ret = EINVAL; ++ ret = ERR_NO_POSIX; + goto done; + } + } +- /* check that the uid is valid for this domain */ +- if (OUT_OF_ID_RANGE(uid, dom->id_min, dom->id_max)) { +- DEBUG(SSSDBG_OP_FAILURE, +- "User [%s] filtered out! (uid out of range)\n", +- user_name); ++ ++ /* check that the uid is valid for this domain if the user is a POSIX one */ ++ if (is_posix == true && OUT_OF_ID_RANGE(uid, dom->id_min, dom->id_max)) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "User [%s] filtered out! (uid out of range)\n", ++ user_name); + ret = EINVAL; + goto done; + } +@@ -349,17 +382,26 @@ int sdap_save_user(TALLOC_CTX *memctx, + ret = sysdb_attrs_get_uint32_t(attrs, + opts->user_map[SDAP_AT_USER_GID].sys_name, + &gid); +- if (ret != EOK) { ++ if (ret == ENOENT && dom->type == DOM_TYPE_APPLICATION) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, ++ "Marking object as non-posix and setting ID=0!\n"); ++ ret = sdap_set_non_posix_flag(attrs, ++ opts->user_map[SDAP_AT_USER_GID].sys_name); ++ if (ret != EOK) { ++ goto done; ++ } ++ is_posix = false; ++ } else if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "no gid provided for [%s] in domain [%s].\n", +- user_name, dom->name); +- ret = EINVAL; ++ "Cannot retrieve GID for [%s] in domain [%s].\n", ++ user_name, dom->name); ++ ret = ERR_NO_POSIX; + goto done; + } + } + + /* check that the gid is valid for this domain */ +- if (IS_SUBDOMAIN(dom) == false && ++ if (is_posix == true && IS_SUBDOMAIN(dom) == false && + OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) { + DEBUG(SSSDBG_CRIT_FAILURE, + "User [%s] filtered out! (primary gid out of range)\n", +-- +2.9.3 + diff --git a/SOURCES/0070-SYSDB-Fix-setting-dataExpireTimestamp-if-sysdb-is-su.patch b/SOURCES/0070-SYSDB-Fix-setting-dataExpireTimestamp-if-sysdb-is-su.patch deleted file mode 100644 index bed5cd3..0000000 --- a/SOURCES/0070-SYSDB-Fix-setting-dataExpireTimestamp-if-sysdb-is-su.patch +++ /dev/null @@ -1,178 +0,0 @@ -From ba87a54746b417ad32362f3c6e565c7af8d21afa Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 3 Aug 2016 14:23:39 +0200 -Subject: [PATCH 70/74] SYSDB: Fix setting dataExpireTimestamp if sysdb is - supposed to set the current time -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -sysdb is already able to retrieve the current timestamp if the caller -doesn't specify it. However, for the timestamp cache this came too late -and the timestamp cache used zero as the 'now' time. - -Resolves: -https://fedorahosted.org/sssd/ticket/3064 - -Reviewed-by: Pavel Březina ---- - src/db/sysdb_ops.c | 20 ++++---- - src/tests/cmocka/test_sysdb_ts_cache.c | 83 ++++++++++++++++++++++++++++++++++ - 2 files changed, 93 insertions(+), 10 deletions(-) - -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 342e16fb20e2c418745b137162425509ca1fd0cb..67006c155098b9fde00a01d424014852c383a325 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -2465,6 +2465,11 @@ int sysdb_store_user(struct sss_domain_info *domain, - errno_t sret = EOK; - bool in_transaction = false; - -+ /* get transaction timestamp */ -+ if (now == 0) { -+ now = time(NULL); -+ } -+ - ret = sysdb_check_and_update_ts_usr(domain, name, attrs, - cache_timeout, now); - if (ret == EOK) { -@@ -2508,11 +2513,6 @@ int sysdb_store_user(struct sss_domain_info *domain, - DEBUG(SSSDBG_TRACE_LIBS, "User %s does not exist.\n", name); - } - -- /* get transaction timestamp */ -- if (!now) { -- now = time(NULL); -- } -- - if (ret == ENOENT) { - /* the user doesn't exist, turn into adding a user */ - ret = sysdb_store_new_user(domain, name, uid, gid, gecos, homedir, -@@ -2700,6 +2700,11 @@ int sysdb_store_group(struct sss_domain_info *domain, - errno_t sret = EOK; - bool in_transaction = false; - -+ /* get transaction timestamp */ -+ if (!now) { -+ now = time(NULL); -+ } -+ - ret = sysdb_check_and_update_ts_grp(domain, name, attrs, - cache_timeout, now); - if (ret == EOK) { -@@ -2741,11 +2746,6 @@ int sysdb_store_group(struct sss_domain_info *domain, - } - } - -- /* get transaction timestamp */ -- if (!now) { -- now = time(NULL); -- } -- - if (new_group) { - ret = sysdb_store_new_group(domain, name, gid, attrs, - cache_timeout, now); -diff --git a/src/tests/cmocka/test_sysdb_ts_cache.c b/src/tests/cmocka/test_sysdb_ts_cache.c -index d5492299647f54e379ea3f305ccc1501c7f6c79f..aa857e7e4823d2d8ba1e1a794b3e2474876e9ab0 100644 ---- a/src/tests/cmocka/test_sysdb_ts_cache.c -+++ b/src/tests/cmocka/test_sysdb_ts_cache.c -@@ -1348,6 +1348,86 @@ static void test_user_byupn(void **state) - talloc_free(res); - } - -+static void test_sysdb_zero_now(void **state) -+{ -+ int ret; -+ struct sysdb_ts_test_ctx *test_ctx = talloc_get_type_abort(*state, -+ struct sysdb_ts_test_ctx); -+ struct ldb_result *res = NULL; -+ uint64_t cache_expire_sysdb; -+ uint64_t cache_expire_ts; -+ struct sysdb_attrs *attrs = NULL; -+ -+ /* Nothing must be stored in either cache at the beginning of the test */ -+ res = sysdb_getpwnam_res(test_ctx, test_ctx->tctx->dom, TEST_USER_NAME); -+ assert_int_equal(res->count, 0); -+ talloc_free(res); -+ -+ res = sysdb_getgrnam_res(test_ctx, test_ctx->tctx->dom, TEST_GROUP_NAME); -+ assert_int_equal(res->count, 0); -+ talloc_free(res); -+ -+ attrs = create_modstamp_attrs(test_ctx, TEST_MODSTAMP_1); -+ assert_non_null(attrs); -+ -+ ret = sysdb_store_user(test_ctx->tctx->dom, TEST_USER_NAME, NULL, -+ TEST_USER_UID, TEST_USER_GID, TEST_USER_NAME, -+ "/home/"TEST_USER_NAME, "/bin/bash", NULL, -+ attrs, NULL, TEST_CACHE_TIMEOUT, -+ 0); -+ talloc_zfree(attrs); -+ assert_int_equal(ret, EOK); -+ -+ attrs = create_modstamp_attrs(test_ctx, TEST_MODSTAMP_1); -+ assert_non_null(attrs); -+ -+ ret = sysdb_store_group(test_ctx->tctx->dom, -+ TEST_GROUP_NAME, -+ TEST_GROUP_GID, -+ attrs, -+ TEST_CACHE_TIMEOUT, -+ 0); -+ talloc_zfree(attrs); -+ assert_int_equal(ret, EOK); -+ talloc_zfree(attrs); -+ -+ attrs = create_modstamp_attrs(test_ctx, TEST_MODSTAMP_1); -+ assert_non_null(attrs); -+ -+ ret = sysdb_store_user(test_ctx->tctx->dom, TEST_USER_NAME, NULL, -+ TEST_USER_UID, TEST_USER_GID, TEST_USER_NAME, -+ "/home/"TEST_USER_NAME, "/bin/bash", NULL, -+ attrs, NULL, TEST_CACHE_TIMEOUT, -+ 0); -+ talloc_zfree(attrs); -+ assert_int_equal(ret, EOK); -+ -+ attrs = create_modstamp_attrs(test_ctx, TEST_MODSTAMP_1); -+ assert_non_null(attrs); -+ -+ ret = sysdb_store_group(test_ctx->tctx->dom, -+ TEST_GROUP_NAME, -+ TEST_GROUP_GID, -+ attrs, -+ TEST_CACHE_TIMEOUT, -+ 0); -+ talloc_zfree(attrs); -+ assert_int_equal(ret, EOK); -+ -+ /* Even though we passed zero as the timestamp, the timestamp cache should -+ * have used the current time instead -+ */ -+ get_pw_timestamp_attrs(test_ctx, TEST_USER_NAME, -+ &cache_expire_sysdb, &cache_expire_ts); -+ assert_true(cache_expire_sysdb > TEST_CACHE_TIMEOUT); -+ assert_true(cache_expire_ts > TEST_CACHE_TIMEOUT); -+ -+ get_gr_timestamp_attrs(test_ctx, TEST_GROUP_NAME, -+ &cache_expire_sysdb, &cache_expire_ts); -+ assert_true(cache_expire_sysdb > TEST_CACHE_TIMEOUT); -+ assert_true(cache_expire_ts > TEST_CACHE_TIMEOUT); -+} -+ - int main(int argc, const char *argv[]) - { - int rv; -@@ -1396,6 +1476,9 @@ int main(int argc, const char *argv[]) - cmocka_unit_test_setup_teardown(test_user_byupn, - test_sysdb_ts_setup, - test_sysdb_ts_teardown), -+ cmocka_unit_test_setup_teardown(test_sysdb_zero_now, -+ test_sysdb_ts_setup, -+ test_sysdb_ts_teardown), - }; - - /* Set debug level to invalid value so we can deside if -d 0 was used. */ --- -2.4.11 - diff --git a/SOURCES/0071-LDAP-Relax-search-filters-in-application-domains.patch b/SOURCES/0071-LDAP-Relax-search-filters-in-application-domains.patch new file mode 100644 index 0000000..73f2862 --- /dev/null +++ b/SOURCES/0071-LDAP-Relax-search-filters-in-application-domains.patch @@ -0,0 +1,254 @@ +From b2a823cf415a12416dca9ff019666906d61cfc2f Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 22 Mar 2017 13:06:14 +0100 +Subject: [PATCH 71/72] LDAP: Relax search filters in application domains + +Related to: +https://pagure.io/SSSD/sssd/issue/3310 + +If a request comes towards an application domain, we can drop the part +of the filter that asserts that the object has a valid UID/GID. Instead, +we just search by name. + +Reviewed-by: Sumit Bose +--- + src/providers/ldap/ldap_id.c | 35 ++++++++++++++++++++++++---- + src/providers/ldap/sdap_async_enum.c | 7 +++++- + src/providers/ldap/sdap_async_initgroups.c | 37 ++++++++++++++++++++++++------ + 3 files changed, 66 insertions(+), 13 deletions(-) + +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index 0bee0ca8d71abece6749fdb8393b9ceacb64417d..7400dc1f57e30cc6ae5f939ffa628a1e9dd47e06 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -56,6 +56,7 @@ struct users_get_state { + char *filter; + const char **attrs; + bool use_id_mapping; ++ bool non_posix; + + int dp_error; + int sdap_ret; +@@ -114,6 +115,10 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + state->filter_value = filter_value; + state->filter_type = filter_type; + ++ if (state->domain->type == DOM_TYPE_APPLICATION) { ++ state->non_posix = true; ++ } ++ + state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( + ctx->opts->idmap_ctx, + sdom->dom->name, +@@ -292,7 +297,13 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + } + } + +- if (state->use_id_mapping || filter_type == BE_FILTER_SECID) { ++ if (state->non_posix) { ++ state->filter = talloc_asprintf(state, ++ "(&%s(objectclass=%s)(%s=*))", ++ user_filter, ++ ctx->opts->user_map[SDAP_OC_USER].name, ++ ctx->opts->user_map[SDAP_AT_USER_NAME].name); ++ } else if (state->use_id_mapping || filter_type == BE_FILTER_SECID) { + /* When mapping IDs or looking for SIDs, we don't want to limit + * ourselves to users with a UID value. But there must be a SID to map + * from. +@@ -304,7 +315,8 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + ctx->opts->user_map[SDAP_AT_USER_NAME].name, + ctx->opts->user_map[SDAP_AT_USER_OBJECTSID].name); + } else { +- /* When not ID-mapping, make sure there is a non-NULL UID */ ++ /* When not ID-mapping or looking up POSIX users, ++ * make sure there is a non-NULL UID */ + state->filter = talloc_asprintf(state, + "(&%s(objectclass=%s)(%s=*)(&(%s=*)(!(%s=0))))", + user_filter, +@@ -380,6 +392,7 @@ static void users_get_connect_done(struct tevent_req *subreq) + * have no idea about POSIX attributes support, run a one-time check + */ + if (state->use_id_mapping == false && ++ state->non_posix == false && + state->ctx->opts->schema_type == SDAP_SCHEMA_AD && + state->ctx->srv_opts && + state->ctx->srv_opts->posix_checked == false) { +@@ -650,6 +663,7 @@ struct groups_get_state { + char *filter; + const char **attrs; + bool use_id_mapping; ++ bool non_posix; + + int dp_error; + int sdap_ret; +@@ -709,6 +723,10 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, + state->filter_value = filter_value; + state->filter_type = filter_type; + ++ if (state->domain->type == DOM_TYPE_APPLICATION) { ++ state->non_posix = true; ++ } ++ + state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( + ctx->opts->idmap_ctx, + sdom->dom->name, +@@ -827,9 +845,11 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, + goto done; + } + +- if (state->use_id_mapping || filter_type == BE_FILTER_SECID) { +- /* When mapping IDs or looking for SIDs, we don't want to limit +- * ourselves to groups with a GID value ++ if (state->non_posix ++ || state->use_id_mapping ++ || filter_type == BE_FILTER_SECID) { ++ /* When mapping IDs or looking for SIDs, or when in a non-POSIX domain, ++ * we don't want to limit ourselves to groups with a GID value + */ + + state->filter = talloc_asprintf(state, +@@ -1123,6 +1143,7 @@ struct groups_by_user_state { + int filter_type; + const char *extra_value; + const char **attrs; ++ bool non_posix; + + int dp_error; + int sdap_ret; +@@ -1204,6 +1225,10 @@ static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx, + state->domain = sdom->dom; + state->sysdb = sdom->dom->sysdb; + ++ if (state->domain->type == DOM_TYPE_APPLICATION) { ++ state->non_posix = true; ++ } ++ + ret = build_attrs_from_map(state, ctx->opts->group_map, SDAP_OPTS_GROUP, + NULL, &state->attrs, NULL); + if (ret != EOK) goto fail; +diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c +index 3f65059e18d5c8b548da0babec867d27c3a64198..91e481c4e694126900c729e86d187fba355de0b8 100644 +--- a/src/providers/ldap/sdap_async_enum.c ++++ b/src/providers/ldap/sdap_async_enum.c +@@ -717,6 +717,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx, + struct enum_groups_state *state; + int ret; + bool use_mapping; ++ bool non_posix = false; + char *oc_list; + + req = tevent_req_create(memctx, &state, struct enum_groups_state); +@@ -727,6 +728,10 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx, + state->ctx = ctx; + state->op = op; + ++ if (sdom->dom->type == DOM_TYPE_APPLICATION) { ++ non_posix = true; ++ } ++ + use_mapping = sdap_idmap_domain_has_algorithmic_mapping( + ctx->opts->idmap_ctx, + sdom->dom->name, +@@ -749,7 +754,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx, + goto fail; + } + +- if (use_mapping) { ++ if (!non_posix && use_mapping) { + /* If we're ID-mapping, check for the objectSID as well */ + state->filter = talloc_asprintf_append_buffer( + state->filter, "(%s=*)", +diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c +index 79af7a3eda3fe8533933535c98c2b4b4698dfda2..c926ddcbefe471daa80505e139c3f19efa33b9ba 100644 +--- a/src/providers/ldap/sdap_async_initgroups.c ++++ b/src/providers/ldap/sdap_async_initgroups.c +@@ -376,7 +376,7 @@ struct sdap_initgr_rfc2307_state { + struct sdap_handle *sh; + const char **attrs; + const char *name; +- const char *base_filter; ++ char *base_filter; + const char *orig_dn; + char *filter; + int timeout; +@@ -473,18 +473,32 @@ struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx, + } + + state->base_filter = talloc_asprintf(state, +- "(&(%s=%s)(%s)(%s=*)(&(%s=*)(!(%s=0))))", ++ "(&(%s=%s)(%s)(%s=*)", + opts->group_map[SDAP_AT_GROUP_MEMBER].name, + clean_name, oc_list, +- opts->group_map[SDAP_AT_GROUP_NAME].name, +- opts->group_map[SDAP_AT_GROUP_GID].name, +- opts->group_map[SDAP_AT_GROUP_GID].name); ++ opts->group_map[SDAP_AT_GROUP_NAME].name); + if (!state->base_filter) { + talloc_zfree(req); + return NULL; + } + talloc_zfree(clean_name); + ++ switch (domain->type) { ++ case DOM_TYPE_APPLICATION: ++ state->base_filter = talloc_asprintf_append(state->base_filter, ")"); ++ break; ++ case DOM_TYPE_POSIX: ++ state->base_filter = talloc_asprintf_append(state->base_filter, ++ "(&(%s=*)(!(%s=0))))", ++ opts->group_map[SDAP_AT_GROUP_GID].name, ++ opts->group_map[SDAP_AT_GROUP_GID].name); ++ break; ++ } ++ if (!state->base_filter) { ++ ret = ENOMEM; ++ goto done; ++ } ++ + ret = sdap_initgr_rfc2307_next_base(req); + + done: +@@ -2666,6 +2680,7 @@ struct sdap_get_initgr_state { + char *shortname; + char *filter; + int timeout; ++ bool non_posix; + + struct sysdb_attrs *orig_user; + +@@ -2724,6 +2739,10 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, + goto done; + } + ++ if (state->dom->type == DOM_TYPE_APPLICATION) { ++ state->non_posix = true; ++ } ++ + use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( + id_ctx->opts->idmap_ctx, + sdom->dom->name, +@@ -2813,7 +2832,10 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, + } + } + +- if (use_id_mapping) { ++ if (state->non_posix) { ++ state->user_base_filter = talloc_asprintf_append(state->user_base_filter, ++ ")"); ++ } else if (use_id_mapping) { + /* When mapping IDs or looking for SIDs, we don't want to limit + * ourselves to users with a UID value. But there must be a SID to map + * from. +@@ -2822,7 +2844,8 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, + "(%s=*))", + id_ctx->opts->user_map[SDAP_AT_USER_OBJECTSID].name); + } else { +- /* When not ID-mapping, make sure there is a non-NULL UID */ ++ /* When not ID-mapping or looking up app users, make sure there ++ * is a non-NULL UID */ + state->user_base_filter = talloc_asprintf_append(state->user_base_filter, + "(&(%s=*)(!(%s=0))))", + id_ctx->opts->user_map[SDAP_AT_USER_UID].name, +-- +2.9.3 + diff --git a/SOURCES/0071-Revert-LDAP-Lookup-services-by-all-protocols-unless-.patch b/SOURCES/0071-Revert-LDAP-Lookup-services-by-all-protocols-unless-.patch deleted file mode 100644 index 0caae35..0000000 --- a/SOURCES/0071-Revert-LDAP-Lookup-services-by-all-protocols-unless-.patch +++ /dev/null @@ -1,44 +0,0 @@ -From e4fd5c67a8f63062b17e615ce746a19994ee310c Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Wed, 27 Jul 2016 11:13:04 +0200 -Subject: [PATCH 71/74] Revert "LDAP: Lookup services by all protocols unless a - protocol is specified" -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This reverts commit aa58e216c1f794bd335151f19e79adbb3ddf4c73. - -Reviewed-by: Pavel Březina ---- - src/providers/ldap/ldap_id_services.c | 7 ++----- - 1 file changed, 2 insertions(+), 5 deletions(-) - -diff --git a/src/providers/ldap/ldap_id_services.c b/src/providers/ldap/ldap_id_services.c -index 401228c20af31ae2df9bb3d35ed25fb6f06b1839..77215127b53297d840eaa4d2f35a75eedb085e43 100644 ---- a/src/providers/ldap/ldap_id_services.c -+++ b/src/providers/ldap/ldap_id_services.c -@@ -89,9 +89,6 @@ services_get_send(TALLOC_CTX *mem_ctx, - state->sysdb = sdom->dom->sysdb; - state->name = name; - state->protocol = protocol; -- if (state->protocol != NULL && state->protocol[0] == '\0') { -- state->protocol = NULL; -- } - state->filter_type = filter_type; - state->noexist_delete = noexist_delete; - -@@ -117,8 +114,8 @@ services_get_send(TALLOC_CTX *mem_ctx, - ret = sss_filter_sanitize(state, name, &clean_name); - if (ret != EOK) goto error; - -- if (state->protocol != NULL) { -- ret = sss_filter_sanitize(state, state->protocol, &clean_protocol); -+ if (protocol) { -+ ret = sss_filter_sanitize(state, protocol, &clean_protocol); - if (ret != EOK) goto error; - } - --- -2.4.11 - diff --git a/SOURCES/0072-KRB5-Authenticate-users-in-a-non-POSIX-domain-using-.patch b/SOURCES/0072-KRB5-Authenticate-users-in-a-non-POSIX-domain-using-.patch new file mode 100644 index 0000000..05693f1 --- /dev/null +++ b/SOURCES/0072-KRB5-Authenticate-users-in-a-non-POSIX-domain-using-.patch @@ -0,0 +1,353 @@ +From 3f32e79858f268ce6501de44e5158e8c12f688dd Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 22 Mar 2017 13:01:18 +0100 +Subject: [PATCH 72/72] KRB5: Authenticate users in a non-POSIX domain using a + MEMORY ccache + +Related to: +https://pagure.io/SSSD/sssd/issue/3310 + +The following changes were done to the Kerberos authentication code +in order to support authentication in a non-POSIX environment: + - delayed authentication is disabled in non-POSIX domains + - when a user logs in in a non-POSIX domain, SSSD uses a + MEMORY:$username ccache and destroys is then krb5_child finishes + so that just the numeric result is used + - krb5_child doesn't drop privileges in this configuration because + there is nothing to drop privileges to + +Reviewed-by: Sumit Bose +--- + src/providers/krb5/krb5_auth.c | 62 ++++++++++++++++------ + src/providers/krb5/krb5_auth.h | 2 + + src/providers/krb5/krb5_child.c | 32 +++++++++-- + src/providers/krb5/krb5_child_handler.c | 15 +++++- + .../krb5/krb5_delayed_online_authentication.c | 7 +++ + src/providers/krb5/krb5_init.c | 3 ++ + 6 files changed, 99 insertions(+), 22 deletions(-) + +diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c +index c2d6d7eeacc1f766024c4d629f25fd0f0be24e5e..2faf18d17a735476c20f9cc27b15be4a39cadc5c 100644 +--- a/src/providers/krb5/krb5_auth.c ++++ b/src/providers/krb5/krb5_auth.c +@@ -42,6 +42,8 @@ + #include "providers/krb5/krb5_utils.h" + #include "providers/krb5/krb5_ccache.h" + ++#define NON_POSIX_CCNAME_FMT "MEMORY:sssd_nonposix_dummy_%u" ++ + static int krb5_mod_ccname(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, +@@ -200,6 +202,7 @@ errno_t krb5_setup(TALLOC_CTX *mem_ctx, + talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup); + + kr->pd = pd; ++ kr->dom = dom; + kr->krb5_ctx = krb5_ctx; + + ret = get_krb_primary(krb5_ctx->name_to_primary, +@@ -275,8 +278,11 @@ static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx, + return; + } + +- ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid); +- if (ret != EOK) { ++ ret = add_user_to_delayed_online_authentication(krb5_ctx, domain, pd, uid); ++ if (ret == ENOTSUP) { ++ /* This error is not fatal */ ++ DEBUG(SSSDBG_MINOR_FAILURE, "Delayed authentication not supported\n"); ++ } else if (ret != EOK) { + /* This error is not fatal */ + DEBUG(SSSDBG_CRIT_FAILURE, + "add_user_to_delayed_online_authentication failed.\n"); +@@ -291,21 +297,43 @@ static errno_t krb5_auth_prepare_ccache_name(struct krb5child_req *kr, + { + const char *ccname_template; + +- ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL); ++ switch (kr->dom->type) { ++ case DOM_TYPE_POSIX: ++ ccname_template = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_CCNAME_TMPL); + +- kr->ccname = expand_ccname_template(kr, kr, ccname_template, +- kr->krb5_ctx->illegal_path_re, true, +- be_ctx->domain->case_sensitive); +- if (kr->ccname == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n"); +- return ENOMEM; +- } ++ kr->ccname = expand_ccname_template(kr, kr, ccname_template, ++ kr->krb5_ctx->illegal_path_re, true, ++ be_ctx->domain->case_sensitive); ++ if (kr->ccname == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "expand_ccname_template failed.\n"); ++ return ENOMEM; ++ } + +- kr->old_ccname = ldb_msg_find_attr_as_string(user_msg, +- SYSDB_CCACHE_FILE, NULL); +- if (kr->old_ccname == NULL) { +- DEBUG(SSSDBG_TRACE_LIBS, +- "No ccache file for user [%s] found.\n", kr->pd->user); ++ kr->old_ccname = ldb_msg_find_attr_as_string(user_msg, ++ SYSDB_CCACHE_FILE, NULL); ++ if (kr->old_ccname == NULL) { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "No ccache file for user [%s] found.\n", kr->pd->user); ++ } ++ break; ++ case DOM_TYPE_APPLICATION: ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Domain type application, will use in-memory ccache\n"); ++ /* We don't care about using cryptographic randomness, just ++ * a non-predictable ccname, so using rand() here is fine ++ */ ++ kr->ccname = talloc_asprintf(kr, ++ NON_POSIX_CCNAME_FMT, ++ rand() % UINT_MAX); ++ if (kr->ccname == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n"); ++ return ENOMEM; ++ } ++ ++ break; ++ default: ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unsupported domain type\n"); ++ return EINVAL; + } + + return EOK; +@@ -617,7 +645,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, + kr->uid = sss_view_ldb_msg_find_attr_as_uint64(state->domain, + res->msgs[0], + SYSDB_UIDNUM, 0); +- if (kr->uid == 0) { ++ if (kr->uid == 0 && state->domain->type == DOM_TYPE_POSIX) { + DEBUG(SSSDBG_CONF_SETTINGS, + "UID for user [%s] not known.\n", pd->user); + ret = ENOENT; +@@ -627,7 +655,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, + kr->gid = sss_view_ldb_msg_find_attr_as_uint64(state->domain, + res->msgs[0], + SYSDB_GIDNUM, 0); +- if (kr->gid == 0) { ++ if (kr->gid == 0 && state->domain->type == DOM_TYPE_POSIX) { + DEBUG(SSSDBG_CONF_SETTINGS, + "GID for user [%s] not known.\n", pd->user); + ret = ENOENT; +diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h +index 75ad916e79b29043120543ab3c4c1bd27e09d913..8ad3aeff21e58f9055ae144eaa450992c6391ba6 100644 +--- a/src/providers/krb5/krb5_auth.h ++++ b/src/providers/krb5/krb5_auth.h +@@ -50,6 +50,7 @@ + struct krb5child_req { + struct pam_data *pd; + struct krb5_ctx *krb5_ctx; ++ struct sss_domain_info *dom; + + const char *ccname; + const char *old_ccname; +@@ -118,6 +119,7 @@ parse_krb5_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t len, + struct krb5_child_response **_res); + + errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, ++ struct sss_domain_info *domain, + struct pam_data *pd, + uid_t uid); + errno_t init_delayed_online_authentication(struct krb5_ctx *krb5_ctx, +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index a4128dda6b0861a95dba223047d66c4158b1afb6..cbbc892bee0365892ac66d3654c974d325166b60 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -80,6 +80,7 @@ struct krb5_req { + char *ccname; + char *keytab; + bool validate; ++ bool posix_domain; + bool send_pac; + bool use_enterprise_princ; + char *fast_ccname; +@@ -102,6 +103,16 @@ struct krb5_req { + static krb5_context krb5_error_ctx; + #define KRB5_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error) + ++static errno_t k5c_become_user(uid_t uid, gid_t gid, bool is_posix) ++{ ++ if (is_posix == false) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Will not drop privileges for a non-POSIX user\n"); ++ return EOK; ++ } ++ return become_user(uid, gid); ++} ++ + static krb5_error_code set_lifetime_options(struct cli_opts *cli_opts, + krb5_get_init_creds_opt *options) + { +@@ -1561,6 +1572,15 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, + DEBUG(SSSDBG_CONF_SETTINGS, "TGT validation is disabled.\n"); + } + ++ /* In a non-POSIX environment, we only care about the return code from ++ * krb5_child, so let's not even attempt to create the ccache ++ */ ++ if (kr->posix_domain == false) { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "Finished authentication in a non-POSIX domain\n"); ++ goto done; ++ } ++ + /* If kr->ccname is cache collection (DIR:/...), we want to work + * directly with file ccache (DIR::/...), but cache collection + * should be returned back to back end. +@@ -2146,6 +2166,7 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, + size_t p = 0; + uint32_t len; + uint32_t validate; ++ uint32_t posix_domain; + uint32_t send_pac; + uint32_t use_enterprise_princ; + struct pam_data *pd; +@@ -2167,6 +2188,8 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, + SAFEALIGN_COPY_UINT32_CHECK(&kr->gid, buf + p, size, &p); + SAFEALIGN_COPY_UINT32_CHECK(&validate, buf + p, size, &p); + kr->validate = (validate == 0) ? false : true; ++ SAFEALIGN_COPY_UINT32_CHECK(&posix_domain, buf + p, size, &p); ++ kr->posix_domain = (posix_domain == 0) ? false : true; + SAFEALIGN_COPY_UINT32_CHECK(offline, buf + p, size, &p); + SAFEALIGN_COPY_UINT32_CHECK(&send_pac, buf + p, size, &p); + kr->send_pac = (send_pac == 0) ? false : true; +@@ -2331,6 +2354,7 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx, + krb5_context ctx, + uid_t fast_uid, + gid_t fast_gid, ++ bool posix_domain, + struct cli_opts *cli_opts, + const char *primary, + const char *realm, +@@ -2420,7 +2444,7 @@ static krb5_error_code check_fast_ccache(TALLOC_CTX *mem_ctx, + /* Try to carry on */ + } + +- kerr = become_user(fast_uid, fast_gid); ++ kerr = k5c_become_user(fast_uid, fast_gid, posix_domain); + if (kerr != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed: %d\n", kerr); + exit(1); +@@ -2572,7 +2596,7 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand) + } + + kerr = check_fast_ccache(kr, kr->ctx, kr->fast_uid, kr->fast_gid, +- kr->cli_opts, ++ kr->posix_domain, kr->cli_opts, + fast_principal, fast_principal_realm, + kr->keytab, &kr->fast_ccname); + if (kerr != 0) { +@@ -2773,7 +2797,7 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline) + * the user who is logging in. The same applies to the offline case + * the user who is logging in. The same applies to the offline case. + */ +- kerr = become_user(kr->uid, kr->gid); ++ kerr = k5c_become_user(kr->uid, kr->gid, kr->posix_domain); + if (kerr != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n"); + return kerr; +@@ -3075,7 +3099,7 @@ int main(int argc, const char *argv[]) + if ((sss_authtok_get_type(kr->pd->authtok) != SSS_AUTHTOK_TYPE_SC_PIN + && sss_authtok_get_type(kr->pd->authtok) + != SSS_AUTHTOK_TYPE_SC_KEYPAD)) { +- kerr = become_user(kr->uid, kr->gid); ++ kerr = k5c_become_user(kr->uid, kr->gid, kr->posix_domain); + if (kerr != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n"); + ret = EFAULT; +diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c +index 680e67b089fcb32280352af24aae35af133a52f3..87e79a06e917aadb622455bccfc2e9c6769f70c2 100644 +--- a/src/providers/krb5/krb5_child_handler.c ++++ b/src/providers/krb5/krb5_child_handler.c +@@ -107,6 +107,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, + uint32_t validate; + uint32_t send_pac; + uint32_t use_enterprise_principal; ++ uint32_t posix_domain; + size_t username_len = 0; + errno_t ret; + +@@ -131,6 +132,17 @@ static errno_t create_send_buffer(struct krb5child_req *kr, + break; + } + ++ switch (kr->dom->type) { ++ case DOM_TYPE_POSIX: ++ posix_domain = 1; ++ break; ++ case DOM_TYPE_APPLICATION: ++ posix_domain = 0; ++ break; ++ default: ++ return EINVAL; ++ } ++ + if (kr->pd->cmd == SSS_CMD_RENEW || kr->is_offline) { + use_enterprise_principal = false; + } else { +@@ -151,7 +163,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, + kr->pd->cmd == SSS_CMD_RENEW || + kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM || + kr->pd->cmd == SSS_PAM_CHAUTHTOK) { +- buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + ++ buf->size += 5*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + + sss_authtok_get_size(kr->pd->authtok); + + buf->size += sizeof(uint32_t); +@@ -182,6 +194,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, + SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->uid, &rp); + SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->gid, &rp); + SAFEALIGN_COPY_UINT32(&buf->data[rp], &validate, &rp); ++ SAFEALIGN_COPY_UINT32(&buf->data[rp], &posix_domain, &rp); + SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->is_offline, &rp); + SAFEALIGN_COPY_UINT32(&buf->data[rp], &send_pac, &rp); + SAFEALIGN_COPY_UINT32(&buf->data[rp], &use_enterprise_principal, &rp); +diff --git a/src/providers/krb5/krb5_delayed_online_authentication.c b/src/providers/krb5/krb5_delayed_online_authentication.c +index bf2ef775573ba6bad79a99ad43b5d9748516e794..1cb7eade0e4cb9afbc4d031a07b3519ba08456d6 100644 +--- a/src/providers/krb5/krb5_delayed_online_authentication.c ++++ b/src/providers/krb5/krb5_delayed_online_authentication.c +@@ -234,6 +234,7 @@ static void delayed_online_authentication_callback(void *private_data) + } + + errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, ++ struct sss_domain_info *domain, + struct pam_data *pd, + uid_t uid) + { +@@ -242,6 +243,12 @@ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx, + hash_value_t value; + struct pam_data *new_pd; + ++ if (domain->type != DOM_TYPE_POSIX) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Domain type does not support delayed authentication\n"); ++ return ENOTSUP; ++ } ++ + if (krb5_ctx->deferred_auth_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Missing context for delayed online authentication.\n"); +diff --git a/src/providers/krb5/krb5_init.c b/src/providers/krb5/krb5_init.c +index 12c8dfcc49af75de619ec0858aaff81504698273..66ae68fb4773af3987f2062246bc6493107c74d5 100644 +--- a/src/providers/krb5/krb5_init.c ++++ b/src/providers/krb5/krb5_init.c +@@ -136,6 +136,9 @@ errno_t sssm_krb5_init(TALLOC_CTX *mem_ctx, + return ENOMEM; + } + ++ /* Only needed to generate random ccache names for non-POSIX domains */ ++ srand(time(NULL) * getpid()); ++ + ret = sss_krb5_get_options(ctx, be_ctx->cdb, be_ctx->conf_path, &ctx->opts); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get krb5 options [%d]: %s\n", +-- +2.9.3 + diff --git a/SOURCES/0072-PROVIDER-Conversion-empty-string-from-D-Bus-to-NULL.patch b/SOURCES/0072-PROVIDER-Conversion-empty-string-from-D-Bus-to-NULL.patch deleted file mode 100644 index 1e57a7b..0000000 --- a/SOURCES/0072-PROVIDER-Conversion-empty-string-from-D-Bus-to-NULL.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 0edb93b54bf79df41aa34a77e9a173cf8529559a Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Wed, 27 Jul 2016 11:13:32 +0200 -Subject: [PATCH 72/74] PROVIDER: Conversion empty string from D-Bus to NULL -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This patch fixes the issue with empty string recieving from D-Bus. -Data providers obtains NULL. So this is simple conversin. - -Resolves: -https://fedorahosted.org/sssd/ticket/3084 - -Reviewed-by: Pavel Březina ---- - src/providers/data_provider/dp_target_id.c | 6 +++--- - src/providers/ldap/ldap_id_services.c | 2 +- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c -index 7c882be2c17650d818cb3907197e381a8f635a77..1b06cbe5b96f56c33dd048cf6211b7c97819db8c 100644 ---- a/src/providers/data_provider/dp_target_id.c -+++ b/src/providers/data_provider/dp_target_id.c -@@ -62,15 +62,15 @@ static bool check_and_parse_filter(struct be_acct_req *data, - {0, 0, 0}}; - int i; - -- if (filter == NULL) { -+ if (SBUS_IS_STRING_EMPTY(filter)) { - return false; - } - - for (i = 0; types[i].name != NULL; i++) { - if (strncmp(filter, types[i].name, types[i].lenght) == 0) { - data->filter_type = types[i].type; -- data->filter_value = &filter[types[i].lenght]; -- data->extra_value = extra; -+ data->filter_value = SBUS_SET_STRING(&filter[types[i].lenght]); -+ data->extra_value = SBUS_SET_STRING(extra); - return true; - } - } -diff --git a/src/providers/ldap/ldap_id_services.c b/src/providers/ldap/ldap_id_services.c -index 77215127b53297d840eaa4d2f35a75eedb085e43..e91fc52d731eaa22be7e98365fc75e7057cb8f1f 100644 ---- a/src/providers/ldap/ldap_id_services.c -+++ b/src/providers/ldap/ldap_id_services.c -@@ -114,7 +114,7 @@ services_get_send(TALLOC_CTX *mem_ctx, - ret = sss_filter_sanitize(state, name, &clean_name); - if (ret != EOK) goto error; - -- if (protocol) { -+ if (protocol == NULL) { - ret = sss_filter_sanitize(state, protocol, &clean_protocol); - if (ret != EOK) goto error; - } --- -2.4.11 - diff --git a/SOURCES/0073-KCM-Fix-off-by-one-error-in-secrets-key-parsing.patch b/SOURCES/0073-KCM-Fix-off-by-one-error-in-secrets-key-parsing.patch new file mode 100644 index 0000000..0530278 --- /dev/null +++ b/SOURCES/0073-KCM-Fix-off-by-one-error-in-secrets-key-parsing.patch @@ -0,0 +1,211 @@ +From 088be07a9e5aae54379a7f98e9e4615cd4451501 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 29 Mar 2017 22:49:09 +0200 +Subject: [PATCH 73/90] KCM: Fix off-by-one error in secrets key parsing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When parsing the secrets key, the code tried to protect against malformed keys +or keys that are too short, but it did an error - the UUID stringified +form is 36 bytes long, so the UUID_STR_SIZE is 37 because UUID_STR_SIZE +accounts for the null terminator. + +But the code, that was trying to assert that there are two characters after +the UUID string (separator and at least a single character for the name) +didn't take the NULL terminator (which strlen() doesn't return) into +account and ended up rejecting all ccaches whose name is only a single +character. + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 7d73049884e3a96ca3b00b5bd4104f4edd6287ab) +--- + src/responder/kcm/kcmsrv_ccache_json.c | 43 +++++++++------- + src/tests/cmocka/test_kcm_json_marshalling.c | 75 ++++++++++++++++++++++++++++ + 2 files changed, 101 insertions(+), 17 deletions(-) + +diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c +index 40b64861c209206d6f60ccd0843857edee24a844..8199bc613e4204859438e1cd820f3f4b2123dd7e 100644 +--- a/src/responder/kcm/kcmsrv_ccache_json.c ++++ b/src/responder/kcm/kcmsrv_ccache_json.c +@@ -109,6 +109,28 @@ static const char *sec_key_create(TALLOC_CTX *mem_ctx, + "%s%c%s", uuid_str, SEC_KEY_SEPARATOR, name); + } + ++static bool sec_key_valid(const char *sec_key) ++{ ++ if (sec_key == NULL) { ++ return false; ++ } ++ ++ if (strlen(sec_key) < UUID_STR_SIZE + 1) { ++ /* One char for separator (at UUID_STR_SIZE, because strlen doesn't ++ * include the '\0', but UUID_STR_SIZE does) and at least one for ++ * the name */ ++ DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); ++ return false; ++ } ++ ++ if (sec_key[UUID_STR_SIZE - 1] != SEC_KEY_SEPARATOR) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n"); ++ return false; ++ } ++ ++ return true; ++} ++ + static errno_t sec_key_parse(TALLOC_CTX *mem_ctx, + const char *sec_key, + const char **_name, +@@ -116,9 +138,7 @@ static errno_t sec_key_parse(TALLOC_CTX *mem_ctx, + { + char uuid_str[UUID_STR_SIZE]; + +- if (strlen(sec_key) < UUID_STR_SIZE + 2) { +- /* One char for separator and at least one for the name */ +- DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); ++ if (!sec_key_valid(sec_key)) { + return EINVAL; + } + +@@ -143,14 +163,7 @@ errno_t sec_key_get_uuid(const char *sec_key, + { + char uuid_str[UUID_STR_SIZE]; + +- if (strlen(sec_key) < UUID_STR_SIZE + 2) { +- /* One char for separator and at least one for the name */ +- DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); +- return EINVAL; +- } +- +- if (sec_key[UUID_STR_SIZE-1] != SEC_KEY_SEPARATOR) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n"); ++ if (!sec_key_valid(sec_key)) { + return EINVAL; + } + +@@ -162,9 +175,7 @@ errno_t sec_key_get_uuid(const char *sec_key, + + const char *sec_key_get_name(const char *sec_key) + { +- if (strlen(sec_key) < UUID_STR_SIZE + 2) { +- /* One char for separator and at least one for the name */ +- DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key); ++ if (!sec_key_valid(sec_key)) { + return NULL; + } + +@@ -174,9 +185,7 @@ const char *sec_key_get_name(const char *sec_key) + bool sec_key_match_name(const char *sec_key, + const char *name) + { +- if (strlen(sec_key) < UUID_STR_SIZE + 2) { +- /* One char for separator and at least one for the name */ +- DEBUG(SSSDBG_MINOR_FAILURE, "Key %s is too short\n", sec_key); ++ if (!sec_key_valid(sec_key) || name == NULL) { + return false; + } + +diff --git a/src/tests/cmocka/test_kcm_json_marshalling.c b/src/tests/cmocka/test_kcm_json_marshalling.c +index 8eff2f501066c70a8730cd3d4dc41b92d7a03e4c..108eaf55628029a6de8c23cd6486bdccc42c0364 100644 +--- a/src/tests/cmocka/test_kcm_json_marshalling.c ++++ b/src/tests/cmocka/test_kcm_json_marshalling.c +@@ -32,6 +32,12 @@ + + #define TEST_CREDS "TESTCREDS" + ++#define TEST_UUID_STR "5f8f296b-02be-4e86-9235-500e82354186" ++#define TEST_SEC_KEY_ONEDIGIT TEST_UUID_STR"-0" ++#define TEST_SEC_KEY_MULTIDIGITS TEST_UUID_STR"-123456" ++ ++#define TEST_SEC_KEY_NOSEP TEST_UUID_STR"+0" ++ + const struct kcm_ccdb_ops ccdb_mem_ops; + const struct kcm_ccdb_ops ccdb_sec_ops; + +@@ -188,6 +194,72 @@ static void test_kcm_ccache_marshall_unmarshall(void **state) + assert_int_equal(ret, EOK); + + assert_cc_equal(cc, cc2); ++ ++ /* This key is exactly one byte shorter than it should be */ ++ ret = sec_kv_to_ccache(test_ctx, ++ TEST_UUID_STR"-", ++ (const char *) data, ++ &owner, ++ &cc2); ++ assert_int_equal(ret, EINVAL); ++} ++ ++void test_sec_key_get_uuid(void **state) ++{ ++ errno_t ret; ++ uuid_t uuid; ++ char str_uuid[UUID_STR_SIZE]; ++ ++ uuid_clear(uuid); ++ ret = sec_key_get_uuid(TEST_SEC_KEY_ONEDIGIT, uuid); ++ assert_int_equal(ret, EOK); ++ uuid_unparse(uuid, str_uuid); ++ assert_string_equal(TEST_UUID_STR, str_uuid); ++ ++ ret = sec_key_get_uuid(TEST_SEC_KEY_NOSEP, uuid); ++ assert_int_equal(ret, EINVAL); ++ ++ ret = sec_key_get_uuid(TEST_UUID_STR, uuid); ++ assert_int_equal(ret, EINVAL); ++ ++ ret = sec_key_get_uuid(NULL, uuid); ++ assert_int_equal(ret, EINVAL); ++} ++ ++void test_sec_key_get_name(void **state) ++{ ++ const char *name; ++ ++ name = sec_key_get_name(TEST_SEC_KEY_ONEDIGIT); ++ assert_non_null(name); ++ assert_string_equal(name, "0"); ++ ++ name = sec_key_get_name(TEST_SEC_KEY_MULTIDIGITS); ++ assert_non_null(name); ++ assert_string_equal(name, "123456"); ++ ++ name = sec_key_get_name(TEST_UUID_STR); ++ assert_null(name); ++ ++ name = sec_key_get_name(TEST_SEC_KEY_NOSEP); ++ assert_null(name); ++ ++ name = sec_key_get_name(NULL); ++ assert_null(name); ++} ++ ++void test_sec_key_match_name(void **state) ++{ ++ assert_true(sec_key_match_name(TEST_SEC_KEY_ONEDIGIT, "0")); ++ assert_true(sec_key_match_name(TEST_SEC_KEY_MULTIDIGITS, "123456")); ++ ++ assert_false(sec_key_match_name(TEST_SEC_KEY_MULTIDIGITS, "0")); ++ assert_false(sec_key_match_name(TEST_SEC_KEY_ONEDIGIT, "123456")); ++ ++ assert_false(sec_key_match_name(TEST_UUID_STR, "0")); ++ assert_false(sec_key_match_name(TEST_SEC_KEY_NOSEP, "0")); ++ assert_false(sec_key_match_name(TEST_SEC_KEY_ONEDIGIT, NULL)); ++ assert_false(sec_key_match_name(NULL, "0")); + } + + int main(int argc, const char *argv[]) +@@ -205,6 +277,9 @@ int main(int argc, const char *argv[]) + cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall, + setup_kcm_marshalling, + teardown_kcm_marshalling), ++ cmocka_unit_test(test_sec_key_get_uuid), ++ cmocka_unit_test(test_sec_key_get_name), ++ cmocka_unit_test(test_sec_key_match_name), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ +-- +2.9.3 + diff --git a/SOURCES/0073-LDAP-Fix-Dereference-after-NULL-check.patch b/SOURCES/0073-LDAP-Fix-Dereference-after-NULL-check.patch deleted file mode 100644 index 3d467ba..0000000 --- a/SOURCES/0073-LDAP-Fix-Dereference-after-NULL-check.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 33649cb41206f568e2bef582e13edbc721184a29 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Mon, 8 Aug 2016 09:03:47 +0200 -Subject: [PATCH 73/74] LDAP: Fix Dereference after NULL check -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The commit dc30c60f166ad9adc63a47a1013508a71624ac87 -changed the logic in NULL check - - if (protocol) { - + if (protocol == NULL) { - -Found by Coverity: - -Reviewed-by: Petr Čech ---- - src/providers/ldap/ldap_id_services.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/providers/ldap/ldap_id_services.c b/src/providers/ldap/ldap_id_services.c -index e91fc52d731eaa22be7e98365fc75e7057cb8f1f..638cb619b39f135307090dcf0f2c6ab2cc4119d0 100644 ---- a/src/providers/ldap/ldap_id_services.c -+++ b/src/providers/ldap/ldap_id_services.c -@@ -114,7 +114,7 @@ services_get_send(TALLOC_CTX *mem_ctx, - ret = sss_filter_sanitize(state, name, &clean_name); - if (ret != EOK) goto error; - -- if (protocol == NULL) { -+ if (protocol != NULL) { - ret = sss_filter_sanitize(state, protocol, &clean_protocol); - if (ret != EOK) goto error; - } --- -2.4.11 - diff --git a/SOURCES/0074-LDAP-Fixing-wrong-pam-error-code-for-passwd.patch b/SOURCES/0074-LDAP-Fixing-wrong-pam-error-code-for-passwd.patch deleted file mode 100644 index 913b219..0000000 --- a/SOURCES/0074-LDAP-Fixing-wrong-pam-error-code-for-passwd.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 89f9598e19000fed30c1069eec01b094eeae0377 Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Tue, 2 Aug 2016 10:11:14 +0200 -Subject: [PATCH 74/74] LDAP: Fixing wrong pam error code for passwd - -This patch adds right pam error code for sssd offline state. - -Resolves: -https://fedorahosted.org/sssd/ticket/3109 ---- - src/providers/ldap/ldap_auth.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c -index 107f6ded1a903904e088f0b6b0320fe82a52af52..35f16b0d4a6f8e566b0cf63b65ba46f31e7c1bcd 100644 ---- a/src/providers/ldap/ldap_auth.c -+++ b/src/providers/ldap/ldap_auth.c -@@ -1101,6 +1101,11 @@ sdap_pam_chpass_handler_send(TALLOC_CTX *mem_ctx, - state->auth_ctx = auth_ctx; - state->ev = params->ev; - -+ if (be_is_offline(state->be_ctx)) { -+ pd->pam_status = PAM_AUTHINFO_UNAVAIL; -+ goto immediately; -+ } -+ - if ((pd->priv == 1) && (pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) && - (sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD)) { - DEBUG(SSSDBG_CONF_SETTINGS, --- -2.4.11 - diff --git a/SOURCES/0074-tcurl-add-support-for-ssl-and-raw-output.patch b/SOURCES/0074-tcurl-add-support-for-ssl-and-raw-output.patch new file mode 100644 index 0000000..6351c10 --- /dev/null +++ b/SOURCES/0074-tcurl-add-support-for-ssl-and-raw-output.patch @@ -0,0 +1,1478 @@ +From 2ca9a394063baac075e05b14fcc6c027027ab8f9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 24 Feb 2017 10:40:43 +0100 +Subject: [PATCH 74/90] tcurl: add support for ssl and raw output + +At first, this patch separates curl_easy handle from the multi-handle +processing and makes it encapsulated in custom tcurl_request structure. +This allows us to separate protocol initialization from its asynchonous +logic which gives us the ability to set different options for each +request without over-extending the parameter list. + +In this patch we implement options for peer verification for TLS-enabled +protocols and to return response with body and headers together. + +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit 300b9e9217ee1ed8d845ed2370c5ccf5c87afb36) +--- + src/tests/tcurl_test_tool.c | 41 +- + src/util/tev_curl.c | 992 +++++++++++++++++++++++++------------------- + src/util/tev_curl.h | 172 +++++++- + src/util/util_errors.c | 4 + + src/util/util_errors.h | 4 + + 5 files changed, 755 insertions(+), 458 deletions(-) + +diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c +index 2af950ebb76a22bdf4a6dfd58442b10486e64293..9a6266f89131ffd3a561e857af85df9854c44949 100644 +--- a/src/tests/tcurl_test_tool.c ++++ b/src/tests/tcurl_test_tool.c +@@ -42,9 +42,7 @@ static void request_done(struct tevent_req *req) + struct tool_ctx *tool_ctx = tevent_req_callback_data(req, + struct tool_ctx); + +- tool_ctx->error = tcurl_http_recv(tool_ctx, req, +- &http_code, +- &outbuf); ++ tool_ctx->error = tcurl_request_recv(tool_ctx, req, &outbuf, &http_code); + talloc_zfree(req); + + if (tool_ctx->error != EOK) { +@@ -87,16 +85,17 @@ int main(int argc, const char *argv[]) + "The path to the HTTP server socket", NULL }, + { "get", 'g', POPT_ARG_NONE, NULL, 'g', "Perform a HTTP GET (default)", NULL }, + { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL }, +- { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, + { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL }, ++ { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, + { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "Print response code and body", NULL }, + POPT_TABLEEND + }; + + struct tevent_req *req; + struct tevent_context *ev; +- enum tcurl_http_request req_type = TCURL_HTTP_GET; ++ enum tcurl_http_method method = TCURL_HTTP_GET; + struct tcurl_ctx *ctx; ++ struct tcurl_request *tcurl_req; + struct tool_ctx *tool_ctx; + + const char *urls[MAXREQ] = { 0 }; +@@ -111,16 +110,16 @@ int main(int argc, const char *argv[]) + while ((opt = poptGetNextOpt(pc)) > 0) { + switch (opt) { + case 'g': +- req_type = TCURL_HTTP_GET; ++ method = TCURL_HTTP_GET; + break; + case 'p': +- req_type = TCURL_HTTP_PUT; +- break; +- case 'd': +- req_type = TCURL_HTTP_DELETE; ++ method = TCURL_HTTP_PUT; + break; + case 'o': +- req_type = TCURL_HTTP_POST; ++ method = TCURL_HTTP_POST; ++ break; ++ case 'd': ++ method = TCURL_HTTP_DELETE; + break; + case 'v': + pc_verbose = 1; +@@ -146,7 +145,7 @@ int main(int argc, const char *argv[]) + } + + while ((extra_arg_ptr = poptGetArg(pc)) != NULL) { +- switch (req_type) { ++ switch(method) { + case TCURL_HTTP_GET: + case TCURL_HTTP_DELETE: + case TCURL_HTTP_POST: +@@ -203,14 +202,16 @@ int main(int argc, const char *argv[]) + } + + for (size_t i = 0; i < n_reqs; i++) { +- req = tcurl_http_send(tool_ctx, ev, ctx, +- req_type, +- socket_path, +- urls[i], +- headers, +- inbufs[i], +- 5); +- if (req == NULL) { ++ tcurl_req = tcurl_http(tool_ctx, method, socket_path, ++ urls[i], headers, inbufs[i]); ++ if (tcurl_req == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to create TCURL request\n"); ++ talloc_zfree(tool_ctx); ++ return 1; ++ } ++ ++ req = tcurl_request_send(tool_ctx, ev, ctx, tcurl_req, 10); ++ if (ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Could not create request\n"); + talloc_zfree(tool_ctx); + return 1; +diff --git a/src/util/tev_curl.c b/src/util/tev_curl.c +index 645d1182d10f825f209f48e0ba7e6804dde1971c..c155f4c038d4215933ee30d41c694ad4a14ae132 100644 +--- a/src/util/tev_curl.c ++++ b/src/util/tev_curl.c +@@ -34,8 +34,8 @@ + #include "util/util.h" + #include "util/tev_curl.h" + +-#define IOBUF_CHUNK 1024 +-#define IOBUF_MAX 4096 ++#define TCURL_IOBUF_CHUNK 1024 ++#define TCURL_IOBUF_MAX 4096 + + static bool global_is_curl_initialized; + +@@ -71,39 +71,12 @@ struct tcurl_sock { + struct tevent_fd *fde; /* tevent tracker of the fd events */ + }; + +-/** +- * @brief A state of one curl transfer +- * +- * Intentionally breaking the tevent coding style here and making the struct available +- * in the whole module so that the structure is available to curl callbacks that +- * need to access the state of the transfer. +- * +- * @see handle_curlmsg_done() +- */ +-struct tcurl_http_state { +- /* Input parameters */ +- struct tcurl_ctx *tctx; +- const char *socket_path; +- const char *url; +- int timeout; +- struct sss_iobuf *inbuf; +- +- /* Internal state */ +- CURL *http_handle; +- struct curl_slist *curl_headers; +- +- /* Output data */ +- struct sss_iobuf *outbuf; +- long http_code; +-}; ++static void tcurl_request_done(struct tevent_req *req, ++ errno_t process_error, ++ int response_code); + + static errno_t curl_code2errno(CURLcode crv) + { +- if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "curl error %d: %s\n", crv, curl_easy_strerror(crv)); +- } +- + switch (crv) { + /* HTTP error does not fail the whole request, just returns the error + * separately +@@ -121,6 +94,47 @@ static errno_t curl_code2errno(CURLcode crv) + return ENOMEM; + case CURLE_OPERATION_TIMEDOUT: + return ETIMEDOUT; ++ case CURLE_SSL_ISSUER_ERROR: ++ case CURLE_SSL_CACERT_BADFILE: ++ case CURLE_SSL_CACERT: ++ case CURLE_SSL_CERTPROBLEM: ++ return ERR_INVALID_CERT; ++ ++ case CURLE_SSL_CRL_BADFILE: ++ case CURLE_SSL_SHUTDOWN_FAILED: ++ case CURLE_SSL_ENGINE_INITFAILED: ++ case CURLE_USE_SSL_FAILED: ++ case CURLE_SSL_CIPHER: ++ case CURLE_SSL_ENGINE_SETFAILED: ++ case CURLE_SSL_ENGINE_NOTFOUND: ++ case CURLE_SSL_CONNECT_ERROR: ++ return ERR_SSL_FAILURE; ++ case CURLE_PEER_FAILED_VERIFICATION: ++ return ERR_UNABLE_TO_VERIFY_PEER; ++ case CURLE_COULDNT_RESOLVE_HOST: ++ return ERR_UNABLE_TO_RESOLVE_HOST; ++ default: ++ break; ++ } ++ ++ return EIO; ++} ++ ++static errno_t curlm_code2errno(CURLcode crv) ++{ ++ switch (crv) { ++ case CURLM_OK: ++ return EOK; ++ case CURLM_BAD_SOCKET: ++ return EPIPE; ++ case CURLM_OUT_OF_MEMORY: ++ return ENOMEM; ++ case CURLM_BAD_HANDLE: ++ case CURLM_BAD_EASY_HANDLE: ++ case CURLM_UNKNOWN_OPTION: ++ return EINVAL; ++ case CURLM_INTERNAL_ERROR: ++ return ERR_INTERNAL; + default: + break; + } +@@ -145,22 +159,6 @@ static errno_t tcurl_global_init(void) + return EOK; + } + +-static const char *http_req2str(enum tcurl_http_request req) +-{ +- switch (req) { +- case TCURL_HTTP_GET: +- return "GET"; +- case TCURL_HTTP_PUT: +- return "PUT"; +- case TCURL_HTTP_DELETE: +- return "DELETE"; +- case TCURL_HTTP_POST: +- return "POST"; +- } +- +- return "Uknown request type"; +-} +- + static int curl2tev_flags(int curlflags) + { + int flags = 0; +@@ -185,9 +183,9 @@ static void handle_curlmsg_done(CURLMsg *message) + CURL *easy_handle; + CURLcode crv; + struct tevent_req *req; ++ long response_code = 0; + char *done_url; + errno_t ret; +- struct tcurl_http_state *state; + + easy_handle = message->easy_handle; + if (easy_handle == NULL) { +@@ -198,9 +196,8 @@ static void handle_curlmsg_done(CURLMsg *message) + if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) { + crv = curl_easy_getinfo(easy_handle, CURLINFO_EFFECTIVE_URL, &done_url); + if (crv != CURLE_OK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- "Cannot get CURLINFO_EFFECTIVE_URL [%d]: %s\n", +- crv, curl_easy_strerror(crv)); ++ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot get CURLINFO_EFFECTIVE_URL " ++ "[%d]: %s\n", crv, curl_easy_strerror(crv)); + /* not fatal since we need this only for debugging */ + } else { + DEBUG(SSSDBG_TRACE_FUNC, "Handled %s\n", done_url); +@@ -209,38 +206,32 @@ static void handle_curlmsg_done(CURLMsg *message) + + crv = curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, (void *) &req); + if (crv != CURLE_OK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Cannot get CURLINFO_PRIVATE [%d]: %s\n", ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get CURLINFO_PRIVATE [%d]: %s\n", + crv, curl_easy_strerror(crv)); +- return; +- } +- +- state = tevent_req_data(req, struct tcurl_http_state); +- if (state == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "BUG: request has no state\n"); +- tevent_req_error(req, EFAULT); +- return; ++ ret = curl_code2errno(crv); ++ goto done; + } + + ret = curl_code2errno(message->data.result); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "curl operation failed [%d]: %s\n", ret, sss_strerror(ret)); +- tevent_req_error(req, ret); +- return; ++ DEBUG(SSSDBG_OP_FAILURE, "CURL operation failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; + } + +- /* If there was no fatal error, let's read the HTTP error code and mark +- * the request as done +- */ +- crv = curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE, &state->http_code); ++ /* If there was no fatal error, let's read the response code ++ * and mark the request as done */ ++ crv = curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE, &response_code); + if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, "Cannot get HTTP status code\n"); +- tevent_req_error(req, EFAULT); +- return; ++ DEBUG(SSSDBG_OP_FAILURE, "Cannot get response code\n"); ++ ret = curl_code2errno(crv); ++ goto done; + } + +- tevent_req_done(req); ++ ret = EOK; ++ ++done: ++ tcurl_request_done(req, ret, response_code); + } + + static void process_curl_activity(struct tcurl_ctx *tctx) +@@ -551,346 +542,42 @@ fail: + return NULL; + } + +-static errno_t tcurl_add_headers(struct tcurl_http_state *state, +- const char *headers[]); +- +-static errno_t tcurl_set_options(struct tcurl_http_state *state, +- struct tevent_req *req, +- enum tcurl_http_request req_type); +- +-static int tcurl_http_cleanup_handle(TALLOC_CTX *ptr); +- +-static size_t tcurl_http_write_data(char *ptr, +- size_t size, +- size_t nmemb, +- void *userdata); +- +-static size_t tcurl_http_read_data(void *ptr, +- size_t size, +- size_t nmemb, +- void *userdata); +- +-struct tevent_req *tcurl_http_send(TALLOC_CTX *mem_ctx, +- struct tevent_context *ev, +- struct tcurl_ctx *tctx, +- enum tcurl_http_request req_type, +- const char *socket_path, +- const char *url, +- const char *headers[], +- struct sss_iobuf *req_data, +- int timeout) +-{ +- errno_t ret; +- struct tevent_req *req; +- struct tcurl_http_state *state; +- +- req = tevent_req_create(mem_ctx, &state, struct tcurl_http_state); +- if (req == NULL) { +- return NULL; +- } +- +- state->tctx = tctx; +- state->socket_path = socket_path; +- state->url = url; +- state->inbuf = req_data; +- state->timeout = timeout; +- +- state->outbuf = sss_iobuf_init_empty(state, IOBUF_CHUNK, IOBUF_MAX); +- if (state->outbuf == NULL) { +- ret = ENOMEM; +- goto fail; +- } +- +- DEBUG(SSSDBG_TRACE_FUNC, +- "HTTP request %s for URL %s\n", http_req2str(req_type), url); +- talloc_set_destructor((TALLOC_CTX *) state, tcurl_http_cleanup_handle); +- +- /* All transfer share the same multi handle, but each trasfer has its own +- * easy handle we can use to set per-transfer options +- */ +- state->http_handle = curl_easy_init(); +- if (state->http_handle == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "curl_easy_init failed\n"); +- ret = EIO; +- goto fail; +- } +- +- ret = tcurl_add_headers(state, headers); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to set CURL headers [%d]: %s\n", ret, sss_strerror(ret)); +- goto fail; +- } +- +- ret = tcurl_set_options(state, req, req_type); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to set CURL options [%d]: %s\n", ret, sss_strerror(ret)); +- goto fail; +- } +- +- /* Pass control to the curl handling which will mark the request as +- * done +- */ +- curl_multi_add_handle(tctx->multi_handle, state->http_handle); +- +- return req; +- +-fail: +- tevent_req_error(req, ret); +- tevent_req_post(req, ev); +- return req; +-} +- +-static int tcurl_http_cleanup_handle(TALLOC_CTX *ptr) +-{ +- struct tcurl_http_state *state = talloc_get_type(ptr, struct tcurl_http_state); +- +- if (state == NULL) { +- return 0; +- } +- +- /* it is safe to pass NULL here */ +- curl_multi_remove_handle(state->tctx->multi_handle, state->http_handle); +- curl_slist_free_all(state->curl_headers); +- curl_easy_cleanup(state->http_handle); +- return 0; +-} +- +-static errno_t tcurl_add_headers(struct tcurl_http_state *state, +- const char *headers[]) +-{ +- if (headers == NULL) { +- return EOK; +- } +- +- /* The headers will be freed later in tcurl_http_cleanup_handle */ +- for (int i = 0; headers[i] != NULL; i++) { +- state->curl_headers = curl_slist_append(state->curl_headers, headers[i]); +- if (state->curl_headers == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot add header %s\n", headers[i]); +- return ENOMEM; +- } +- } +- +- /* Add a dummy header to suppress libcurl adding Expect 100-continue which +- * was causing libcurl to always wait for the internal timeout when sending +- * a PUT/PATCH request +- */ +- state->curl_headers = curl_slist_append(state->curl_headers, "Expect:"); +- if (state->curl_headers == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot add the dummy expect header\n"); +- return ENOMEM; +- } +- +- return EOK; +-} +- +-static errno_t tcurl_set_common_options(struct tcurl_http_state *state, +- struct tevent_req *req) +-{ +- CURLcode crv; +- +- crv = curl_easy_setopt(state->http_handle, +- CURLOPT_HTTPHEADER, +- state->curl_headers); +- if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to set HTTP headers [%d]: %s\n", +- crv, curl_easy_strerror(crv)); +- return EIO; +- } +- +- crv = curl_easy_setopt(state->http_handle, +- CURLOPT_UNIX_SOCKET_PATH, +- state->socket_path); +- if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to set UNIX socket path %s [%d]: %s\n", +- state->socket_path, crv, curl_easy_strerror(crv)); +- return EIO; +- } +- +- crv = curl_easy_setopt(state->http_handle, CURLOPT_URL, state->url); +- if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to set URL %s [%d]: %s\n", +- state->url, crv, curl_easy_strerror(crv)); +- return EIO; +- } +- +- crv = curl_easy_setopt(state->http_handle, CURLOPT_PRIVATE, req); +- if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to set private data [%d]: %s\n", +- crv, curl_easy_strerror(crv)); +- return EIO; +- } +- +- if (state->timeout > 0) { +- crv = curl_easy_setopt(state->http_handle, +- CURLOPT_TIMEOUT, +- state->timeout); +- if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to set timeout [%d]: %s\n", +- crv, curl_easy_strerror(crv)); +- return EIO; +- } +- } +- +- return EOK; +-} +- +-static errno_t tcurl_set_write_options(struct tcurl_http_state *state) +-{ +- CURLcode crv; +- +- crv = curl_easy_setopt(state->http_handle, +- CURLOPT_WRITEFUNCTION, +- tcurl_http_write_data); +- if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to set write function [%d]: %s\n", +- crv, curl_easy_strerror(crv)); +- return EIO; +- } +- +- crv = curl_easy_setopt(state->http_handle, +- CURLOPT_WRITEDATA, +- state->outbuf); +- if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to set write data [%d]: %s\n", +- crv, curl_easy_strerror(crv)); +- return EIO; +- } +- +- return EOK; +-} +- +-static errno_t tcurl_set_read_options(struct tcurl_http_state *state) +-{ +- CURLcode crv; +- +- crv = curl_easy_setopt(state->http_handle, +- CURLOPT_READFUNCTION, +- tcurl_http_read_data); +- if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to set read function [%d]: %s\n", +- crv, curl_easy_strerror(crv)); +- return EIO; +- } +- +- crv = curl_easy_setopt(state->http_handle, +- CURLOPT_READDATA, +- state->inbuf); +- if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to set read data [%d]: %s\n", +- crv, curl_easy_strerror(crv)); +- return EIO; +- } +- +- return EOK; +-} +- +-static errno_t tcurl_set_options(struct tcurl_http_state *state, +- struct tevent_req *req, +- enum tcurl_http_request req_type) +-{ +- CURLcode crv; +- errno_t ret; +- +- ret = tcurl_set_common_options(state, req); +- if (ret != EOK) { +- return ret; +- } +- +- ret = tcurl_set_write_options(state); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to set write callbacks [%d]: %s\n", +- ret, sss_strerror(ret)); +- return ret; +- } +- +- switch (req_type) { +- case TCURL_HTTP_POST: +- crv = curl_easy_setopt(state->http_handle, +- CURLOPT_CUSTOMREQUEST, +- "POST"); +- break; +- case TCURL_HTTP_PUT: +- /* CURLOPT_UPLOAD enables HTTP_PUT */ +- crv = curl_easy_setopt(state->http_handle, +- CURLOPT_UPLOAD, +- 1L); +- if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to set the uplodad option [%d]: %s\n", +- crv, curl_easy_strerror(crv)); +- return EIO; +- } +- +- /* Causes libcurl to add a sane Content-Length header */ +- crv = curl_easy_setopt(state->http_handle, +- CURLOPT_INFILESIZE_LARGE, +- (curl_off_t) sss_iobuf_get_size(state->inbuf)); +- if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to set CURLOPT_INFILESIZE_LARGE [%d]: %s\n", +- crv, curl_easy_strerror(crv)); +- return EIO; +- } +- +- ret = tcurl_set_read_options(state); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to set write callbacks [%d]: %s\n", +- ret, sss_strerror(ret)); +- return ret; +- } +- break; +- case TCURL_HTTP_GET: +- /* GET just needs the write callbacks, nothing to do here.. */ +- break; +- case TCURL_HTTP_DELETE: +- crv = curl_easy_setopt(state->http_handle, +- CURLOPT_CUSTOMREQUEST, +- "DELETE"); +- if (crv != CURLE_OK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to set the uplodad option [%d]: %s\n", +- crv, curl_easy_strerror(crv)); +- return EIO; +- } +- break; +- default: +- return EFAULT; +- } +- +- return EOK; +-} +- +-static size_t tcurl_http_write_data(char *ptr, +- size_t size, +- size_t nmemb, +- void *userdata) ++#define tcurl_set_option(tcurl_req, option, value) \ ++({ \ ++ CURLcode __curl_code; \ ++ errno_t __ret; \ ++ \ ++ __curl_code = curl_easy_setopt((tcurl_req)->curl_easy_handle, \ ++ (option), (value)); \ ++ if (__curl_code == CURLE_OK) { \ ++ __ret = EOK; \ ++ } else { \ ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to set CURL option %s [%d]: %s\n", \ ++ #option, __curl_code, curl_easy_strerror(__curl_code)); \ ++ __ret = curl_code2errno(__curl_code); \ ++ } \ ++ __ret; \ ++}) ++ ++static size_t tcurl_write_data(char *ptr, ++ size_t size, ++ size_t nmemb, ++ void *userdata) + { + errno_t ret; + size_t realsize = size * nmemb; +- struct sss_iobuf *outbuf = talloc_get_type(userdata, struct sss_iobuf); ++ struct sss_iobuf *outbuf; ++ ++ outbuf = talloc_get_type(userdata, struct sss_iobuf); + + DEBUG(SSSDBG_TRACE_INTERNAL, "---> begin libcurl data\n"); + DEBUG(SSSDBG_TRACE_INTERNAL, "%s\n", ptr); + DEBUG(SSSDBG_TRACE_INTERNAL, "<--- end libcurl data\n"); + +- ret = sss_iobuf_write_len(outbuf, (uint8_t *) ptr, realsize); ++ ret = sss_iobuf_write_len(outbuf, (uint8_t *)ptr, realsize); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to write data to buffer [%d]: %s\n", ret, sss_strerror(ret)); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to write data to buffer [%d]: %s\n", ++ ret, sss_strerror(ret)); + /* zero signifies an EOF */ + return 0; + } +@@ -898,14 +585,16 @@ static size_t tcurl_http_write_data(char *ptr, + return realsize; + } + +-static size_t tcurl_http_read_data(void *ptr, +- size_t size, +- size_t nmemb, +- void *userdata) ++static size_t tcurl_read_data(void *ptr, ++ size_t size, ++ size_t nmemb, ++ void *userdata) + { + errno_t ret; + size_t readbytes; +- struct sss_iobuf *inbuf = (struct sss_iobuf *) userdata; ++ struct sss_iobuf *inbuf; ++ ++ inbuf = talloc_get_type(userdata, struct sss_iobuf); + + if (inbuf == NULL) { + return CURL_READFUNC_ABORT; +@@ -919,22 +608,487 @@ static size_t tcurl_http_read_data(void *ptr, + return readbytes; + } + +-int tcurl_http_recv(TALLOC_CTX *mem_ctx, +- struct tevent_req *req, +- int *_http_code, +- struct sss_iobuf **_outbuf) ++ ++struct tcurl_request { ++ CURL *curl_easy_handle; ++ ++ struct sss_iobuf *body; ++ struct curl_slist *headers; ++ ++ const char *url; ++ const char *socket; ++ ++ /* Associated tcurl context if this request is in progress. */ ++ struct tcurl_ctx *tcurl_ctx; ++}; ++ ++struct tcurl_request_state { ++ struct tcurl_request *tcurl_req; ++ struct sss_iobuf *response; ++ int response_code; ++}; ++ ++struct tevent_req * ++tcurl_request_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct tcurl_ctx *tcurl_ctx, ++ struct tcurl_request *tcurl_req, ++ long int timeout) + { +- struct tcurl_http_state *state = tevent_req_data(req, struct tcurl_http_state); ++ struct tcurl_request_state *state; ++ struct tevent_req *req; ++ CURLMcode curl_code; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct tcurl_request_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ return NULL; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Sending TCURL request for %s, at socket %s\n", ++ tcurl_req->url == NULL ? "" : tcurl_req->url, ++ tcurl_req->socket == NULL ? "" : tcurl_req->socket); ++ ++ state->tcurl_req = talloc_steal(state, tcurl_req); ++ ++ state->response = sss_iobuf_init_empty(state, TCURL_IOBUF_CHUNK, TCURL_IOBUF_MAX); ++ if (state->response == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_PRIVATE, req); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_TIMEOUT, timeout); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_WRITEFUNCTION, tcurl_write_data); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_WRITEDATA, state->response); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ if (tcurl_req->body != NULL) { ++ ret = tcurl_set_option(tcurl_req, CURLOPT_READFUNCTION, tcurl_read_data); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_READDATA, tcurl_req->body); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ ++ curl_code = curl_multi_add_handle(tcurl_ctx->multi_handle, ++ tcurl_req->curl_easy_handle); ++ if (curl_code != CURLM_OK) { ++ ret = curlm_code2errno(curl_code); ++ goto done; ++ } ++ ++ tcurl_req->tcurl_ctx = tcurl_ctx; ++ ++ ret = EAGAIN; ++ ++done: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ tevent_req_post(req, ev); ++ } else if (ret != EAGAIN) { ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ } ++ ++ return req; ++} ++ ++static void tcurl_request_done(struct tevent_req *req, ++ errno_t process_error, ++ int response_code) ++{ ++ struct tcurl_request_state *state; ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "TCURL request finished [%d]: %s\n", ++ process_error, sss_strerror(process_error)); ++ ++ if (req == NULL) { ++ /* To handle case where we fail to obtain request from private data. */ ++ DEBUG(SSSDBG_MINOR_FAILURE, "No tevent request provided!\n"); ++ return; ++ } ++ ++ state = tevent_req_data(req, struct tcurl_request_state); ++ ++ curl_multi_remove_handle(state->tcurl_req->tcurl_ctx->multi_handle, ++ state->tcurl_req->curl_easy_handle); ++ ++ /* This request is no longer associated with tcurl context. */ ++ state->tcurl_req->tcurl_ctx = NULL; ++ ++ if (process_error != EOK) { ++ tevent_req_error(req, process_error); ++ return; ++ } ++ ++ state->response_code = response_code; ++ ++ tevent_req_done(req); ++ return; ++} ++ ++errno_t tcurl_request_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct sss_iobuf **_response, ++ int *_response_code) ++{ ++ struct tcurl_request_state *state; ++ state = tevent_req_data(req, struct tcurl_request_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + +- if (_http_code != NULL) { +- *_http_code = state->http_code; ++ if (_response != NULL) { ++ *_response = talloc_steal(mem_ctx, state->response); + } + +- if (_outbuf != NULL) { +- *_outbuf = talloc_steal(mem_ctx, state->outbuf); ++ if (_response_code != NULL) { ++ *_response_code = state->response_code; ++ } ++ ++ return EOK; ++} ++ ++static struct curl_slist * ++tcurl_add_header(struct curl_slist *slist, const char *header) ++{ ++ struct curl_slist *new; ++ ++ new = curl_slist_append(slist, header); ++ if (new == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot add header %s\n", header); ++ if (slist != NULL) { ++ curl_slist_free_all(slist); ++ } ++ ++ return NULL; ++ } ++ ++ return new; ++} ++ ++static errno_t ++tcurl_construct_headers(const char **headers, ++ struct curl_slist **_slist) ++{ ++ struct curl_slist *slist = NULL; ++ int i; ++ ++ if (headers == NULL || headers[0] == NULL) { ++ *_slist = NULL; ++ return EOK; ++ } ++ ++ for (i = 0; headers[i] != NULL; i++) { ++ slist = tcurl_add_header(slist, headers[i]); ++ if (slist == NULL) { ++ return ENOMEM; ++ } ++ } ++ ++ /* Add a dummy header to suppress libcurl adding Expect 100-continue which ++ * was causing libcurl to always wait for the internal timeout when sending ++ * a PUT/POST request because secrets responder does not implement this. ++ */ ++ slist = tcurl_add_header(slist, "Expect: "); ++ if (slist == NULL) { ++ return ENOMEM; ++ } ++ ++ *_slist = slist; ++ ++ return EOK; ++} ++ ++static int ++tcurl_request_destructor(struct tcurl_request *tcurl_req) ++{ ++ if (tcurl_req->tcurl_ctx != NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Terminating TCURL request...\n"); ++ curl_multi_remove_handle(tcurl_req->tcurl_ctx->multi_handle, ++ tcurl_req->curl_easy_handle); ++ } ++ ++ if (tcurl_req->headers != NULL) { ++ curl_slist_free_all(tcurl_req->headers); ++ } ++ ++ if (tcurl_req->curl_easy_handle != NULL) { ++ curl_easy_cleanup(tcurl_req->curl_easy_handle); + } + + return 0; + } ++ ++static struct tcurl_request * ++tcurl_request_create(TALLOC_CTX *mem_ctx, ++ const char *socket_path, ++ const char *url, ++ const char **headers, ++ struct sss_iobuf *body) ++{ ++ struct tcurl_request *tcurl_req; ++ errno_t ret; ++ ++ tcurl_req = talloc_zero(mem_ctx, struct tcurl_request); ++ if (tcurl_req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); ++ return NULL; ++ } ++ ++ if (url == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "URL cannot be NULL!\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ /* Setup a curl easy handle. This handle contains state for the request ++ * and is later associated with curl multi handle which performs ++ * asynchronous processing. */ ++ tcurl_req->curl_easy_handle = curl_easy_init(); ++ if (tcurl_req->curl_easy_handle == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize curl easy handle!\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tcurl_req->url = talloc_strdup(tcurl_req, url); ++ if (tcurl_req->url == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ if (socket_path != NULL) { ++ tcurl_req->socket = talloc_strdup(tcurl_req, socket_path); ++ if (tcurl_req->socket == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ ret = tcurl_construct_headers(headers, &tcurl_req->headers); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to construct headers [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tcurl_req->body = body; ++ ++ talloc_set_destructor(tcurl_req, tcurl_request_destructor); ++ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_URL, url); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ if (socket_path != NULL) { ++ ret = tcurl_set_option(tcurl_req, CURLOPT_UNIX_SOCKET_PATH, socket_path); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ ++ if (body != NULL) { ++ /* Curl will tell the underlying protocol about incoming data length. ++ * In case of HTTP it will add a sane Content-Length header. */ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_INFILESIZE_LARGE, ++ (curl_off_t)sss_iobuf_get_size(body)); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(tcurl_req); ++ return NULL; ++ } ++ ++ return tcurl_req; ++} ++ ++struct tcurl_request *tcurl_http(TALLOC_CTX *mem_ctx, ++ enum tcurl_http_method method, ++ const char *socket_path, ++ const char *url, ++ const char **headers, ++ struct sss_iobuf *body) ++{ ++ struct tcurl_request *tcurl_req; ++ errno_t ret; ++ ++ tcurl_req = tcurl_request_create(mem_ctx, socket_path, url, headers, body); ++ if (tcurl_req == NULL) { ++ return NULL; ++ } ++ ++ /* Set HTTP specific options. */ ++ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_HTTPHEADER, tcurl_req->headers); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ switch (method) { ++ case TCURL_HTTP_GET: ++ /* Nothing to do here. GET is default. */ ++ break; ++ case TCURL_HTTP_PUT: ++ ret = tcurl_set_option(tcurl_req, CURLOPT_UPLOAD, 1L); ++ if (ret != EOK) { ++ goto done; ++ } ++ break; ++ case TCURL_HTTP_POST: ++ ret = tcurl_set_option(tcurl_req, CURLOPT_CUSTOMREQUEST, "POST"); ++ if (ret != EOK) { ++ goto done; ++ } ++ break; ++ case TCURL_HTTP_DELETE: ++ ret = tcurl_set_option(tcurl_req, CURLOPT_CUSTOMREQUEST, "DELETE"); ++ if (ret != EOK) { ++ goto done; ++ } ++ break; ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(tcurl_req); ++ return NULL; ++ } ++ ++ return tcurl_req; ++} ++ ++struct tevent_req *tcurl_http_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct tcurl_ctx *tcurl_ctx, ++ enum tcurl_http_method method, ++ const char *socket_path, ++ const char *url, ++ const char **headers, ++ struct sss_iobuf *body, ++ int timeout) ++{ ++ struct tcurl_request *tcurl_req; ++ struct tevent_req *req; ++ ++ tcurl_req = tcurl_http(mem_ctx, method, socket_path, url, headers, body); ++ if (tcurl_req == NULL) { ++ return NULL; ++ } ++ ++ req = tcurl_request_send(mem_ctx, ev, tcurl_ctx, tcurl_req, timeout); ++ if (req == NULL) { ++ talloc_free(tcurl_req); ++ } ++ ++ return req; ++} ++ ++errno_t tcurl_http_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ int *_http_code, ++ struct sss_iobuf **_response) ++{ ++ return tcurl_request_recv(mem_ctx, req, _response, _http_code); ++} ++ ++errno_t tcurl_req_enable_rawoutput(struct tcurl_request *tcurl_req) ++{ ++ return tcurl_set_option(tcurl_req, CURLOPT_HEADER, 1L); ++} ++ ++errno_t tcurl_req_verify_peer(struct tcurl_request *tcurl_req, ++ const char *capath, ++ const char *cacert, ++ bool verify_peer, ++ bool verify_host) ++{ ++ errno_t ret; ++ ++ long peer = verify_peer ? 1L : 0L; ++ long host = verify_host ? 2L : 0L; ++ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_SSL_VERIFYPEER, peer); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_SSL_VERIFYHOST, host); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ if (capath != NULL) { ++ ret = tcurl_set_option(tcurl_req, CURLOPT_CAPATH, capath); ++ if (ret != EOK) { ++ return ret; ++ } ++ } ++ ++ if (cacert != NULL) { ++ ret = tcurl_set_option(tcurl_req, CURLOPT_CAINFO, cacert); ++ if (ret != EOK) { ++ return ret; ++ } ++ } ++ ++ return EOK; ++} ++ ++errno_t tcurl_req_set_client_cert(struct tcurl_request *tcurl_req, ++ const char *cert, ++ const char *key) ++{ ++ errno_t ret; ++ ++ if (cert == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "You must specify client certificate!\n"); ++ return EINVAL; ++ } ++ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_SSLCERT, cert); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ if (key != NULL) { ++ /* If client's private key is in separate file. */ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_SSLKEY, key); ++ if (ret != EOK) { ++ return ret; ++ } ++ } ++ ++ return EOK; ++} +diff --git a/src/util/tev_curl.h b/src/util/tev_curl.h +index 444eb286e09d189b4588e2b2152b5202df3914d8..933abcb9b531412737e8fcf391644d828b125cf8 100644 +--- a/src/util/tev_curl.h ++++ b/src/util/tev_curl.h +@@ -27,14 +27,16 @@ + + #include "util/sss_iobuf.h" + ++struct tcurl_request; ++ + /** +- * @brief Supported HTTP requests ++ * @brief Supported HTTP methods + */ +-enum tcurl_http_request { ++enum tcurl_http_method { + TCURL_HTTP_GET, + TCURL_HTTP_PUT, +- TCURL_HTTP_DELETE, + TCURL_HTTP_POST, ++ TCURL_HTTP_DELETE, + }; + + /** +@@ -46,16 +48,95 @@ struct tcurl_ctx *tcurl_init(TALLOC_CTX *mem_ctx, + struct tevent_context *ev); + + /** ++ * @brief Run a single asynchronous TCURL request. ++ * ++ * If the libcurl processing succeeds but we obtain a protocol error we still ++ * mark the tevent request as successful. The protocol error is return from ++ * @tcurl_request_recv as an output parameter. ++ * ++ * @param[in] mem_ctx The talloc context that owns the request ++ * @param[in] ev Event loop context ++ * @param[in] tctx Use tcurl_init to get this context ++ * @param[in] tcurl_req TCURL request ++ * @param[in] timeout The request timeout in seconds. Use 0 if you want ++ * to use the default libcurl timeout. ++ * ++ * @returns A tevent request or NULL on allocation error. On other errors, we ++ * try to set the errno as event error code and run it to completion so that ++ * the programmer can use tcurl_request_recv to read the error code. ++ * ++ * @see tcurl_init ++ * @see tcurl_http ++ * @see tcurl_request_recv ++ */ ++struct tevent_req * ++tcurl_request_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct tcurl_ctx *tcurl_ctx, ++ struct tcurl_request *tcurl_req, ++ long int timeout); ++ ++/** ++ * @brief Receive a result of a single asynchronous TCURL request. ++ * ++ * @param[in] mem_ctx The talloc context that owns the response ++ * @param[in] req The request previously obtained with tcurl_request_send ++ * @param[out] _response Response to the request ++ * @param[out] _response_code Protocol response code (may indicate a protocl error) ++ * ++ * @returns The error code of the curl request (not the HTTP code!) ++ */ ++errno_t tcurl_request_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct sss_iobuf **_response, ++ int *_response_code); ++ ++/** ++ * @brief Create a HTTP request. ++ * ++ * Use this if you need better control over the request options. ++ * ++ * Headers are a NULL-terminated array of strings such as: ++ * static const char *headers[] = { ++ * "Content-type: application/octet-stream", ++ * NULL, ++ * }; ++ * ++ * @param[in] mem_ctx The talloc context that owns the tcurl_request ++ * @param[in] method TCURL HTTP method ++ * @param[in] socket_path The path to the UNIX socket to forward the ++ * request to, may be NULL. ++ * @param[in] url The request URL, cannot be NULL. ++ * @param[in] headers A NULL-terminated array of strings to use ++ * as additional HTTP headers. Pass NULL if you ++ * don't need any additional headers. ++ * @param[in] body The HTTP request input data. For some request ++ * types like DELETE, this is OK to leave as NULL. ++ * ++ * @returns A tcurl_request that can be later started with tcurl_request_send ++ * or NULL on error. ++ * ++ * @see tcurl_init ++ * @see tcurl_request_send ++ * @see tcurl_request_recv ++ */ ++struct tcurl_request *tcurl_http(TALLOC_CTX *mem_ctx, ++ enum tcurl_http_method method, ++ const char *socket_path, ++ const char *url, ++ const char **headers, ++ struct sss_iobuf *body); ++ ++/** + * @brief Run a single asynchronous HTTP request. + * +- * Currently only UNIX sockets at socket_path are supported. ++ * Use this if you do not need control over additional request options. + * + * If the request runs into completion, but reports a failure with HTTP return + * code, the request will be marked as done. Only if the request cannot run at + * all (if e.g. the socket is unreachable), the request will fail completely. + * +- * Headers are a NULL-terminated +- * array of strings such as: ++ * Headers are a NULL-terminated array of strings such as: + * static const char *headers[] = { + * "Content-type: application/octet-stream", + * NULL, +@@ -63,15 +144,15 @@ struct tcurl_ctx *tcurl_init(TALLOC_CTX *mem_ctx, + * + * @param[in] mem_ctx The talloc context that owns the iobuf + * @param[in] ev Event loop context +- * @param[in] tctx Use tcurl_init to get this context +- * @param[in] req_type The request type ++ * @param[in] tcurl_ctx Use tcurl_init to get this context ++ * @param[in] method HTTP method + * @param[in] socket_path The path to the UNIX socket to forward the +- * request to +- * @param[in] url The request URL ++ * request to, may be NULL. ++ * @param[in] url The request URL, cannot be NULL. + * @param[in] headers A NULL-terminated array of strings to use + * as additional HTTP headers. Pass NULL if you + * don't need any additional headers. +- * @param[in] req_data The HTTP request input data. For some request ++ * @param[in] body The HTTP request input data. For some request + * types like DELETE, this is OK to leave as NULL. + * @param[in] timeout The request timeout in seconds. Use 0 if you want + * to use the default libcurl timeout. +@@ -85,12 +166,12 @@ struct tcurl_ctx *tcurl_init(TALLOC_CTX *mem_ctx, + */ + struct tevent_req *tcurl_http_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +- struct tcurl_ctx *tctx, +- enum tcurl_http_request req_type, ++ struct tcurl_ctx *tcurl_ctx, ++ enum tcurl_http_method method, + const char *socket_path, + const char *url, +- const char *headers[], +- struct sss_iobuf *req_data, ++ const char **headers, ++ struct sss_iobuf *body, + int timeout); + + /** +@@ -104,9 +185,62 @@ struct tevent_req *tcurl_http_send(TALLOC_CTX *mem_ctx, + * + * @returns The error code of the curl request (not the HTTP code!) + */ +-int tcurl_http_recv(TALLOC_CTX *mem_ctx, +- struct tevent_req *req, +- int *_http_code, +- struct sss_iobuf **_outbuf); ++errno_t tcurl_http_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ int *_http_code, ++ struct sss_iobuf **_response); ++ ++/** ++ * @brief We are usually interested only in the reply body without protocol ++ * headers. Call this function on tcurl_request, if you want to include ++ * complete protocol response in the output buffer. ++ * ++ * @param[in] tcurl_request ++ * ++ * @returns errno code ++ * ++ * @see tcurl_http ++ */ ++errno_t tcurl_req_enable_rawoutput(struct tcurl_request *tcurl_req); ++ ++/** ++ * @brief TLS is enabled automatically by providing an URL that points to ++ * TLS-enabled protocol such as https. If you want to provide different ++ * path to CA directory or disable peer/hostname check explicitly, use ++ * this function on tcurl_request. ++ * ++ * @param[in] tcurl_request ++ * @param[in] capath Path to directory containing installed CA certificates. ++ * If not set, libcurl default is used. ++ * @param[ing cacert CA certificate. If NULL it is found in @capath. ++ * @param[in] verify_peer If false, the peer certificate is not verified. ++ * @param[in] verify_host If false, the host name provided in remote ++ * certificate may differ from the actual host name. ++ * ++ * @returns errno code ++ * ++ * @see tcurl_http ++ */ ++errno_t tcurl_req_verify_peer(struct tcurl_request *tcurl_req, ++ const char *capath, ++ const char *cacert, ++ bool verify_peer, ++ bool verify_host); ++/** ++ * @brief Some server require client verification during TLS setup. You can ++ * provide path to client's certificate file. If this file does not contain ++ * private key, you can specify a different file the holds the private key. ++ * ++ * @param[in] tcurl_request ++ * @param[in] cert Path to client's certificate. ++ * @param[in] key Path to client's private key. ++ * ++ * @returns errno code ++ * ++ * @see tcurl_http ++ */ ++errno_t tcurl_req_set_client_cert(struct tcurl_request *tcurl_req, ++ const char *cert, ++ const char *key); + + #endif /* __TEV_CURL_H */ +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index 60c2f439b3e39b1dbff353e429114cb5a3070052..466a3b4062f39b29d831a5d8a62dc8d576eb2e97 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -111,6 +111,10 @@ struct err_string error_to_str[] = { + { "Credential cache name not allowed" }, /* ERR_KCM_WRONG_CCNAME_FORMAT */ + { "Cannot encode a JSON object to string" }, /* ERR_JSON_ENCODING */ + { "Cannot decode a JSON object from string" }, /* ERR_JSON_DECODING */ ++ { "Invalid certificate provided" }, /* ERR_INVALID_CERT */ ++ { "Unable to initialize SSL" }, /* ERR_SSL_FAILURE */ ++ { "Unable to verify peer" }, /* ERR_UNABLE_TO_VERIFY_PEER */ ++ { "Unable to resolve host" }, /* ERR_UNABLE_TO_RESOLVE_HOST */ + { "ERR_LAST" } /* ERR_LAST */ + }; + +diff --git a/src/util/util_errors.h b/src/util/util_errors.h +index 4e9da814702e2cd46edc52fd5c2ae5f640602609..2f90c0a5d65325a431a8e4d9a480170808c9198e 100644 +--- a/src/util/util_errors.h ++++ b/src/util/util_errors.h +@@ -133,6 +133,10 @@ enum sssd_errors { + ERR_KCM_WRONG_CCNAME_FORMAT, + ERR_JSON_ENCODING, + ERR_JSON_DECODING, ++ ERR_INVALID_CERT, ++ ERR_SSL_FAILURE, ++ ERR_UNABLE_TO_VERIFY_PEER, ++ ERR_UNABLE_TO_RESOLVE_HOST, + ERR_LAST /* ALWAYS LAST */ + }; + +-- +2.9.3 + diff --git a/SOURCES/0075-PAM-Do-not-act-on-ldb_message-in-case-of-a-failure.patch b/SOURCES/0075-PAM-Do-not-act-on-ldb_message-in-case-of-a-failure.patch deleted file mode 100644 index 8adb0ca..0000000 --- a/SOURCES/0075-PAM-Do-not-act-on-ldb_message-in-case-of-a-failure.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 86f099e6ca0e09dd5fe44816238a4323c63f9ee7 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 3 Aug 2016 17:43:14 +0200 -Subject: [PATCH 75/82] PAM: Do not act on ldb_message in case of a failure -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Lukáš Slebodník ---- - src/responder/pam/pamsrv_cmd.c | 33 ++++++++++++++++++--------------- - 1 file changed, 18 insertions(+), 15 deletions(-) - -diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c -index 66564f5d301a53dcdb5967f43ef4afdb897e9974..be54fbf9b627d0ec1c3b0416401885245794cf9f 100644 ---- a/src/responder/pam/pamsrv_cmd.c -+++ b/src/responder/pam/pamsrv_cmd.c -@@ -1534,21 +1534,24 @@ static int pam_check_user_search(struct pam_auth_req *preq) - - if (preq->pd->name_is_upn) { - ret = sysdb_search_user_by_upn(preq, dom, name, user_attrs, &msg); -- -- /* Since sysdb_search_user_by_upn() searches the whole cache we -- * have to set the domain so that it matches the result. */ -- sysdb_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); -- if (sysdb_name == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Cached entry has no name.\n"); -- return EINVAL; -- } -- preq->domain = find_domain_by_object_name(get_domains_head(dom), -- sysdb_name); -- if (preq->domain == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Cannot find matching domain for [%s].\n", -- sysdb_name); -- return EINVAL; -+ if (ret == EOK) { -+ /* Since sysdb_search_user_by_upn() searches the whole cache we -+ * have to set the domain so that it matches the result. */ -+ sysdb_name = ldb_msg_find_attr_as_string(msg, -+ SYSDB_NAME, NULL); -+ if (sysdb_name == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Cached entry has no name.\n"); -+ return EINVAL; -+ } -+ preq->domain = find_domain_by_object_name( -+ get_domains_head(dom), -+ sysdb_name); -+ if (preq->domain == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot find matching domain for [%s].\n", -+ sysdb_name); -+ return EINVAL; -+ } - } - } else { - ret = sysdb_getpwnam_with_views(preq, dom, name, &res); --- -2.4.11 - diff --git a/SOURCES/0075-tcurl-test-refactor-so-new-options-can-be-added-more.patch b/SOURCES/0075-tcurl-test-refactor-so-new-options-can-be-added-more.patch new file mode 100644 index 0000000..bcea2c6 --- /dev/null +++ b/SOURCES/0075-tcurl-test-refactor-so-new-options-can-be-added-more.patch @@ -0,0 +1,438 @@ +From a886247bcdb1c551486c34a8d4eccd046a11382f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 24 Feb 2017 12:23:01 +0100 +Subject: [PATCH 75/90] tcurl test: refactor so new options can be added more + easily + +Just to make the tool a little bit nicer and more flexible. + +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit b800a6d09244359959404aca81c6796a58cafbcb) +--- + src/tests/tcurl_test_tool.c | 334 +++++++++++++++++++++++++++----------------- + 1 file changed, 209 insertions(+), 125 deletions(-) + +diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c +index 9a6266f89131ffd3a561e857af85df9854c44949..e5fc9705db415650d849b89c3d18e41574b7e28b 100644 +--- a/src/tests/tcurl_test_tool.c ++++ b/src/tests/tcurl_test_tool.c +@@ -28,26 +28,39 @@ + + struct tool_ctx { + bool verbose; +- +- errno_t error; + bool done; + + size_t nreqs; + }; + ++struct tool_options { ++ int debug; ++ int verbose; ++ ++ enum tcurl_http_method method; ++ const char *socket_path; ++}; ++ + static void request_done(struct tevent_req *req) + { +- int http_code; ++ struct tool_ctx *tool_ctx; + struct sss_iobuf *outbuf; +- struct tool_ctx *tool_ctx = tevent_req_callback_data(req, +- struct tool_ctx); ++ int http_code; ++ errno_t ret; + +- tool_ctx->error = tcurl_request_recv(tool_ctx, req, &outbuf, &http_code); ++ tool_ctx = tevent_req_callback_data(req, struct tool_ctx); ++ ++ ret = tcurl_request_recv(tool_ctx, req, &outbuf, &http_code); + talloc_zfree(req); + +- if (tool_ctx->error != EOK) { +- DEBUG(SSSDBG_FATAL_FAILURE, "HTTP request failed: %d\n", tool_ctx->error); ++ tool_ctx->nreqs--; ++ if (tool_ctx->nreqs == 0) { + tool_ctx->done = true; ++ } ++ ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "HTTP request failed [%d]: %s\n", ++ ret, sss_strerror(ret)); + return; + } else if (tool_ctx->verbose) { + printf("Request HTTP code: %d\n", http_code); +@@ -55,167 +68,171 @@ static void request_done(struct tevent_req *req) + (const char *) sss_iobuf_get_data(outbuf)); + talloc_zfree(outbuf); + } +- +- tool_ctx->nreqs--; +- if (tool_ctx->nreqs == 0) { +- tool_ctx->done = true; +- } + } + +-int main(int argc, const char *argv[]) ++static errno_t ++parse_options(poptContext pc, struct tool_options *opts) + { + int opt; +- poptContext pc; +- +- int pc_debug = 0; +- int pc_verbose = 0; +- const char *socket_path = NULL; +- const char *extra_arg_ptr; +- +- static const char *headers[] = { +- "Content-type: application/octet-stream", +- NULL, +- }; +- +- struct poptOption long_options[] = { +- POPT_AUTOHELP +- { "debug", '\0', POPT_ARG_INT, &pc_debug, 0, +- "The debug level to run with", NULL }, +- { "socket-path", 's', POPT_ARG_STRING, &socket_path, 0, +- "The path to the HTTP server socket", NULL }, +- { "get", 'g', POPT_ARG_NONE, NULL, 'g', "Perform a HTTP GET (default)", NULL }, +- { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL }, +- { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL }, +- { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, +- { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "Print response code and body", NULL }, +- POPT_TABLEEND +- }; +- +- struct tevent_req *req; +- struct tevent_context *ev; +- enum tcurl_http_method method = TCURL_HTTP_GET; +- struct tcurl_ctx *ctx; +- struct tcurl_request *tcurl_req; +- struct tool_ctx *tool_ctx; +- +- const char *urls[MAXREQ] = { 0 }; +- struct sss_iobuf **inbufs; +- +- size_t n_reqs = 0; +- +- debug_prg_name = argv[0]; +- pc = poptGetContext(NULL, argc, argv, long_options, 0); +- poptSetOtherOptionHelp(pc, "HTTPDATA"); + + while ((opt = poptGetNextOpt(pc)) > 0) { + switch (opt) { + case 'g': +- method = TCURL_HTTP_GET; ++ opts->method = TCURL_HTTP_GET; + break; + case 'p': +- method = TCURL_HTTP_PUT; ++ opts->method = TCURL_HTTP_PUT; + break; + case 'o': +- method = TCURL_HTTP_POST; ++ opts->method = TCURL_HTTP_POST; + break; + case 'd': +- method = TCURL_HTTP_DELETE; +- break; +- case 'v': +- pc_verbose = 1; ++ opts->method = TCURL_HTTP_DELETE; + break; + default: + DEBUG(SSSDBG_FATAL_FAILURE, "Unexpected option\n"); +- return 1; ++ return EINVAL; + } + } + +- DEBUG_CLI_INIT(pc_debug); +- +- tool_ctx = talloc_zero(NULL, struct tool_ctx); +- if (tool_ctx == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not init tool context\n"); +- return 1; ++ if (opt != -1) { ++ poptPrintUsage(pc, stderr, 0); ++ fprintf(stderr, "%s", poptStrerror(opt)); ++ return EINVAL; + } + +- inbufs = talloc_zero_array(tool_ctx, struct sss_iobuf *, MAXREQ); +- if (inbufs == NULL) { +- talloc_zfree(tool_ctx); +- return 1; ++ return EOK; ++} ++ ++static errno_t ++prepare_requests(TALLOC_CTX *mem_ctx, ++ poptContext pc, ++ struct tool_options *opts, ++ struct tcurl_request ***_requests, ++ size_t *_num_requests) ++{ ++ struct tcurl_request **requests; ++ const char *arg; ++ const char *url; ++ struct sss_iobuf *body; ++ errno_t ret; ++ size_t i; ++ ++ static const char *headers[] = { ++ "Content-type: application/octet-stream", ++ NULL, ++ }; ++ ++ requests = talloc_zero_array(mem_ctx, struct tcurl_request *, MAXREQ + 1); ++ if (requests == NULL) { ++ return ENOMEM; + } + +- while ((extra_arg_ptr = poptGetArg(pc)) != NULL) { +- switch(method) { ++ i = 0; ++ while ((arg = poptGetArg(pc)) != NULL) { ++ if (i >= MAXREQ) { ++ fprintf(stderr, _("Too many requests!\n")); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ switch (opts->method) { + case TCURL_HTTP_GET: + case TCURL_HTTP_DELETE: +- case TCURL_HTTP_POST: +- urls[n_reqs++] = extra_arg_ptr; ++ url = arg; ++ body = NULL; + break; + case TCURL_HTTP_PUT: +- if (urls[n_reqs] == NULL) { +- urls[n_reqs] = extra_arg_ptr; +- } else { +- inbufs[n_reqs] = sss_iobuf_init_readonly( +- inbufs, +- (uint8_t *) discard_const(extra_arg_ptr), +- strlen(extra_arg_ptr)); +- if (inbufs[n_reqs] == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not init input buffer\n"); +- talloc_zfree(tool_ctx); +- return 1; +- } +- n_reqs++; ++ case TCURL_HTTP_POST: ++ url = arg; ++ ++ arg = poptGetArg(pc); ++ if (arg == NULL) { ++ body = NULL; ++ break; ++ } ++ ++ body = sss_iobuf_init_readonly(requests, ++ discard_const_p(uint8_t, arg), ++ strlen(arg)); ++ if (body == NULL) { ++ ret = ENOMEM; ++ goto done; + } + break; ++ default: ++ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid method!\n"); ++ ret = EINVAL; ++ goto done; + } ++ ++ requests[i] = tcurl_http(requests, opts->method, opts->socket_path, ++ url, headers, body); ++ if (requests[i] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ i++; + } + +- if (opt != -1) { +- poptPrintUsage(pc, stderr, 0); +- fprintf(stderr, "%s", poptStrerror(opt)); +- talloc_zfree(tool_ctx); +- return 1; ++ *_requests = requests; ++ *_num_requests = i; ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(requests); + } + +- if (!socket_path) { +- DEBUG(SSSDBG_FATAL_FAILURE, "Please specify the socket path\n"); +- poptPrintUsage(pc, stderr, 0); +- talloc_zfree(tool_ctx); +- return 1; ++ return ret; ++} ++ ++static errno_t ++run_requests(struct tool_ctx *tool_ctx, ++ struct tcurl_request **requests) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct tcurl_ctx *tcurl_ctx; ++ struct tevent_context *ev; ++ struct tevent_req *req; ++ errno_t ret; ++ int i; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n"); ++ return ENOMEM; + } + +- tool_ctx->nreqs = n_reqs; +- tool_ctx->verbose = !!pc_verbose; ++ if (requests == NULL || requests[0] == NULL) { ++ ret = EOK; ++ goto done; ++ } + +- ev = tevent_context_init(tool_ctx); ++ ev = tevent_context_init(tmp_ctx); + if (ev == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not init tevent context\n"); +- talloc_zfree(tool_ctx); +- return 1; ++ ret = ENOMEM; ++ goto done; + } + +- ctx = tcurl_init(tool_ctx, ev); +- if (ctx == NULL) { ++ tcurl_ctx = tcurl_init(tmp_ctx, ev); ++ if (tcurl_ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Could not init tcurl context\n"); +- talloc_zfree(tool_ctx); +- return 1; ++ ret = ENOMEM; ++ goto done; + } + +- for (size_t i = 0; i < n_reqs; i++) { +- tcurl_req = tcurl_http(tool_ctx, method, socket_path, +- urls[i], headers, inbufs[i]); +- if (tcurl_req == NULL) { +- DEBUG(SSSDBG_FATAL_FAILURE, "Unable to create TCURL request\n"); +- talloc_zfree(tool_ctx); +- return 1; ++ for (i = 0; requests[i] != NULL; i++) { ++ req = tcurl_request_send(tmp_ctx, ev, tcurl_ctx, requests[i], 5); ++ if (req == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Could not create tevent request\n"); ++ ret = ENOMEM; ++ goto done; + } + +- req = tcurl_request_send(tool_ctx, ev, ctx, tcurl_req, 10); +- if (ctx == NULL) { +- DEBUG(SSSDBG_FATAL_FAILURE, "Could not create request\n"); +- talloc_zfree(tool_ctx); +- return 1; +- } + tevent_req_set_callback(req, request_done, tool_ctx); + } + +@@ -226,11 +243,78 @@ int main(int argc, const char *argv[]) + if (tool_ctx->nreqs > 0) { + DEBUG(SSSDBG_FATAL_FAILURE, + "The tool finished with some pending requests, fail!\n"); +- talloc_zfree(tool_ctx); +- return 1; ++ ret = EEXIST; ++ goto done; + } + ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ struct tool_options opts = { 0 }; ++ struct tool_ctx *tool_ctx; ++ struct tcurl_request **requests; ++ poptContext pc; ++ errno_t ret; ++ ++ struct poptOption long_options[] = { ++ POPT_AUTOHELP ++ { "debug", '\0', POPT_ARG_INT, &opts.debug, 0, "The debug level to run with", NULL }, ++ { "socket-path", 's', POPT_ARG_STRING, &opts.socket_path, 0, "The path to the HTTP server socket", NULL }, ++ { "get", 'g', POPT_ARG_NONE, NULL, 'g', "Perform a HTTP GET (default)", NULL }, ++ { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL }, ++ { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL }, ++ { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, ++ { "verbose", 'v', POPT_ARG_NONE, &opts.verbose, '\0', "Print response code and body", NULL }, ++ POPT_TABLEEND ++ }; ++ ++ pc = poptGetContext(NULL, argc, argv, long_options, 0); ++ poptSetOtherOptionHelp(pc, "[URL HTTPDATA]*"); ++ ++ tool_ctx = talloc_zero(NULL, struct tool_ctx); ++ if (tool_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not init tool context\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = parse_options(pc, &opts); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to parse options [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ DEBUG_CLI_INIT(opts.debug); ++ tool_ctx->verbose = opts.verbose; ++ ++ ret = prepare_requests(tool_ctx, pc, &opts, &requests, &tool_ctx->nreqs); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to prepare requests [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = run_requests(tool_ctx, requests); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to issue requests [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++done: + talloc_free(tool_ctx); + poptFreeContext(pc); +- return 0; ++ ++ if (ret != EOK) { ++ return EXIT_FAILURE; ++ } ++ ++ return EXIT_SUCCESS; + } +-- +2.9.3 + diff --git a/SOURCES/0076-IPA-Check-the-return-value-of-sss_parse_internal_fqn.patch b/SOURCES/0076-IPA-Check-the-return-value-of-sss_parse_internal_fqn.patch deleted file mode 100644 index 1dfbf21..0000000 --- a/SOURCES/0076-IPA-Check-the-return-value-of-sss_parse_internal_fqn.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 2e027e43f0adb1b7c80e51d5613fca5a497ca331 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 3 Aug 2016 18:03:59 +0200 -Subject: [PATCH 76/82] IPA: Check the return value of - sss_parse_internal_fqname -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We should fail the request if sss_parse_internal_fqname() fails. - -Reviewed-by: Lukáš Slebodník ---- - src/providers/ipa/ipa_subdomains_id.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c -index 002857699b65c86a6ed0c912a2a7ae06a8f9e507..2299523d0c52e3277db6d1061c79b320e78c8f72 100644 ---- a/src/providers/ipa/ipa_subdomains_id.c -+++ b/src/providers/ipa/ipa_subdomains_id.c -@@ -509,6 +509,14 @@ static void ipa_get_subdom_acct_connected(struct tevent_req *subreq) - } else { - ret = sss_parse_internal_fqname(req_input, state->filter, - &shortname, NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot parse internal name [%s]: %d\n", -+ state->filter, ret); -+ tevent_req_error(req, ret); -+ return; -+ } -+ - req_input->inp.name = talloc_steal(req_input, shortname); - } - if (req_input->inp.name == NULL) { --- -2.4.11 - diff --git a/SOURCES/0076-tcurl-test-add-support-for-raw-output.patch b/SOURCES/0076-tcurl-test-add-support-for-raw-output.patch new file mode 100644 index 0000000..3004adc --- /dev/null +++ b/SOURCES/0076-tcurl-test-add-support-for-raw-output.patch @@ -0,0 +1,49 @@ +From 961abf2d35e296fe2b12b2b48c5d3fc67c0bc779 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 24 Feb 2017 12:23:22 +0100 +Subject: [PATCH 76/90] tcurl test: add support for raw output + +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit 36e49a842e257ac9bde71728ee3bef4299b6e6e2) +--- + src/tests/tcurl_test_tool.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c +index e5fc9705db415650d849b89c3d18e41574b7e28b..7d3bc19f0ec7e118e251247536d25c58fe009f54 100644 +--- a/src/tests/tcurl_test_tool.c ++++ b/src/tests/tcurl_test_tool.c +@@ -36,6 +36,7 @@ struct tool_ctx { + struct tool_options { + int debug; + int verbose; ++ int raw; + + enum tcurl_http_method method; + const char *socket_path; +@@ -173,6 +174,13 @@ prepare_requests(TALLOC_CTX *mem_ctx, + goto done; + } + ++ if (opts->raw) { ++ ret = tcurl_req_enable_rawoutput(requests[i]); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ + i++; + } + +@@ -270,6 +278,7 @@ int main(int argc, const char *argv[]) + { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL }, + { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL }, + { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, ++ { "raw", 'r', POPT_ARG_NONE, &opts.raw, '\0', "Print raw protocol output", NULL }, + { "verbose", 'v', POPT_ARG_NONE, &opts.verbose, '\0', "Print response code and body", NULL }, + POPT_TABLEEND + }; +-- +2.9.3 + diff --git a/SOURCES/0077-DP-Initialize-D-Bus-as-soon-as-possible.patch b/SOURCES/0077-DP-Initialize-D-Bus-as-soon-as-possible.patch deleted file mode 100644 index 9641722..0000000 --- a/SOURCES/0077-DP-Initialize-D-Bus-as-soon-as-possible.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 178e61b6dc5b547bd77998f586f118bfa9b06d30 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Fri, 5 Aug 2016 11:32:43 +0200 -Subject: [PATCH 77/82] DP: Initialize D-Bus as soon as possible - -Resolves: -https://fedorahosted.org/sssd/ticket/3111 - -Reviewed-by: Petr Cech ---- - src/providers/data_provider/dp.c | 34 +++++++++++++++++++------------- - src/providers/data_provider/dp_methods.c | 6 ++++++ - 2 files changed, 26 insertions(+), 14 deletions(-) - -diff --git a/src/providers/data_provider/dp.c b/src/providers/data_provider/dp.c -index c4590e3152126fe166d0bc9e3be2a14978f90168..b672370aa153c9cd2031399a8d61c95fb16cd641 100644 ---- a/src/providers/data_provider/dp.c -+++ b/src/providers/data_provider/dp.c -@@ -86,6 +86,7 @@ errno_t dp_init(struct tevent_context *ev, - provider->gid = gid; - provider->be_ctx = be_ctx; - -+ /* Initialize request table. */ - ret = dp_req_table_init(provider, &provider->requests.reply_table); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize request table " -@@ -93,20 +94,11 @@ errno_t dp_init(struct tevent_context *ev, - goto done; - } - -- ret = dp_init_modules(provider, &provider->modules); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize DP modules " -- "[%d]: %s\n", ret, sss_strerror(ret)); -- goto done; -- } -- -- ret = dp_init_targets(provider, be_ctx, provider, provider->modules); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize DP targets " -- "[%d]: %s\n", ret, sss_strerror(ret)); -- goto done; -- } -- -+ /* Initialize data provider bus. Data provider can receive client -+ * registration and other D-Bus methods. However no data provider -+ * request will be executed as long as the modules and targets -+ * are not initialized. -+ */ - talloc_set_destructor(provider, dp_destructor); - - ret = dp_init_dbus_server(provider); -@@ -118,6 +110,20 @@ errno_t dp_init(struct tevent_context *ev, - - be_ctx->provider = provider; - -+ ret = dp_init_modules(provider, &provider->modules); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize DP modules " -+ "[%d]: %s\n", ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ ret = dp_init_targets(provider, be_ctx, provider, provider->modules); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize DP targets " -+ "[%d]: %s\n", ret, sss_strerror(ret)); -+ goto done; -+ } -+ - ret = EOK; - - done: -diff --git a/src/providers/data_provider/dp_methods.c b/src/providers/data_provider/dp_methods.c -index e4290beeeef3c0c4d156271ad88f891d3245af08..498676d1bec2da300ca4b33f7110debcbf0aac00 100644 ---- a/src/providers/data_provider/dp_methods.c -+++ b/src/providers/data_provider/dp_methods.c -@@ -76,6 +76,12 @@ bool dp_method_enabled(struct data_provider *provider, - return false; - } - -+ if (provider == NULL || provider->targets == NULL) { -+ DEBUG(SSSDBG_TRACE_FUNC, "Target %s is not yet initialized\n", -+ dp_target_to_string(target)); -+ return false; -+ } -+ - dp_target = provider->targets[target]; - if (dp_target == NULL || dp_target->initialized == false) { - DEBUG(SSSDBG_TRACE_FUNC, "Target %s is not configured\n", --- -2.4.11 - diff --git a/SOURCES/0077-tcurl-test-add-support-for-tls-settings.patch b/SOURCES/0077-tcurl-test-add-support-for-tls-settings.patch new file mode 100644 index 0000000..d1e5926 --- /dev/null +++ b/SOURCES/0077-tcurl-test-add-support-for-tls-settings.patch @@ -0,0 +1,62 @@ +From 4a0d05defd8da2fb7e618e485909b9807b83acbf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Mon, 27 Feb 2017 12:58:06 +0100 +Subject: [PATCH 77/90] tcurl test: add support for tls settings + +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit 886e0f75e6f4c7877a23a3625f8a20c09109b09d) +--- + src/tests/tcurl_test_tool.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c +index 7d3bc19f0ec7e118e251247536d25c58fe009f54..9cec000fbf2e4eca2fdc5213c8b3b4cb10f1df1b 100644 +--- a/src/tests/tcurl_test_tool.c ++++ b/src/tests/tcurl_test_tool.c +@@ -37,9 +37,14 @@ struct tool_options { + int debug; + int verbose; + int raw; ++ int tls; ++ int verify_peer; ++ int verify_host; + + enum tcurl_http_method method; + const char *socket_path; ++ const char *capath; ++ const char *cacert; + }; + + static void request_done(struct tevent_req *req) +@@ -181,6 +186,14 @@ prepare_requests(TALLOC_CTX *mem_ctx, + } + } + ++ if (opts->tls) { ++ ret = tcurl_req_verify_peer(requests[i], opts->capath, opts->cacert, ++ opts->verify_peer, opts->verify_host); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ + i++; + } + +@@ -280,6 +293,12 @@ int main(int argc, const char *argv[]) + { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, + { "raw", 'r', POPT_ARG_NONE, &opts.raw, '\0', "Print raw protocol output", NULL }, + { "verbose", 'v', POPT_ARG_NONE, &opts.verbose, '\0', "Print response code and body", NULL }, ++ /* TLS */ ++ { "tls", '\0', POPT_ARG_NONE, &opts.tls, '\0', "Enable TLS", NULL }, ++ { "verify-peer", '\0', POPT_ARG_NONE, &opts.verify_peer, '\0', "Verify peer when TLS is enabled", NULL }, ++ { "verify-host", '\0', POPT_ARG_NONE, &opts.verify_host, '\0', "Verify host when TLS is enabled", NULL }, ++ { "capath", '\0', POPT_ARG_STRING, &opts.capath, '\0', "Path to CA directory where peer certificate is stored", NULL }, ++ { "cacert", '\0', POPT_ARG_STRING, &opts.cacert, '\0', "Path to CA certificate", NULL }, + POPT_TABLEEND + }; + +-- +2.9.3 + diff --git a/SOURCES/0078-sssctl-Generic-help-for-cache-upgrade-and-config-che.patch b/SOURCES/0078-sssctl-Generic-help-for-cache-upgrade-and-config-che.patch deleted file mode 100644 index bff746f..0000000 --- a/SOURCES/0078-sssctl-Generic-help-for-cache-upgrade-and-config-che.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 44b93ae9e80652661da7c1f35aa5aec532e6f04d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 26 Jul 2016 16:35:55 +0200 -Subject: [PATCH 78/82] sssctl: Generic help for cache-upgrade and config-check -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -sssctl COMMAND --help should print at least -generic help, even if the command does not -accept any command specific options. - -Resolves: -https://fedorahosted.org/sssd/ticket/3086 - -Reviewed-by: Pavel Březina ---- - src/tools/sssctl/sssctl_config.c | 6 ++++++ - src/tools/sssctl/sssctl_data.c | 6 ++++++ - 2 files changed, 12 insertions(+) - -diff --git a/src/tools/sssctl/sssctl_config.c b/src/tools/sssctl/sssctl_config.c -index a66d7749c4aee9bd00c0ad2d296292658ffdb9b2..630df3c8ff5368ef253bb9753380e94c8c0a307d 100644 ---- a/src/tools/sssctl/sssctl_config.c -+++ b/src/tools/sssctl/sssctl_config.c -@@ -47,6 +47,12 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline, - char **strs = NULL; - TALLOC_CTX *tmp_ctx = NULL; - -+ ret = sss_tool_popt(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL, NULL, NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); -+ return ret; -+ } -+ - tmp_ctx = talloc_new(NULL); - init_data = sss_ini_initdata_init(tmp_ctx); - if (!init_data) { -diff --git a/src/tools/sssctl/sssctl_data.c b/src/tools/sssctl/sssctl_data.c -index a26ddd8d5200319e75282b738791cf270f0d75a8..72823ab254344bba6f7679882a733b6ef2250525 100644 ---- a/src/tools/sssctl/sssctl_data.c -+++ b/src/tools/sssctl/sssctl_data.c -@@ -266,6 +266,12 @@ errno_t sssctl_cache_upgrade(struct sss_cmdline *cmdline, - struct sysdb_upgrade_ctx db_up_ctx; - errno_t ret; - -+ ret = sss_tool_popt(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL, NULL, NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); -+ return ret; -+ } -+ - if (sss_deamon_running()) { - return ERR_SSSD_RUNNING; - } --- -2.4.11 - diff --git a/SOURCES/0078-tcurl-add-support-for-http-basic-auth.patch b/SOURCES/0078-tcurl-add-support-for-http-basic-auth.patch new file mode 100644 index 0000000..fd6ce23 --- /dev/null +++ b/SOURCES/0078-tcurl-add-support-for-http-basic-auth.patch @@ -0,0 +1,112 @@ +From 1c543722b2b1c55b06c3cc02ace987fc68bc26d7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 28 Feb 2017 13:32:31 +0100 +Subject: [PATCH 78/90] tcurl: add support for http basic auth + +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit c2ea75da72b426d98ba489039e220d417bfb4c2a) +--- + src/tests/tcurl_test_tool.c | 14 ++++++++++++++ + src/util/tev_curl.c | 24 ++++++++++++++++++++++++ + src/util/tev_curl.h | 15 +++++++++++++++ + 3 files changed, 53 insertions(+) + +diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c +index 9cec000fbf2e4eca2fdc5213c8b3b4cb10f1df1b..4ceef8e06040ea0abd4d112a5b7845f436c69488 100644 +--- a/src/tests/tcurl_test_tool.c ++++ b/src/tests/tcurl_test_tool.c +@@ -45,6 +45,9 @@ struct tool_options { + const char *socket_path; + const char *capath; + const char *cacert; ++ ++ const char *username; ++ const char *password; + }; + + static void request_done(struct tevent_req *req) +@@ -194,6 +197,14 @@ prepare_requests(TALLOC_CTX *mem_ctx, + } + } + ++ if (opts->username != NULL && opts->password != NULL) { ++ ret = tcurl_req_http_basic_auth(requests[i], opts->username, ++ opts->password); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ + i++; + } + +@@ -299,6 +310,9 @@ int main(int argc, const char *argv[]) + { "verify-host", '\0', POPT_ARG_NONE, &opts.verify_host, '\0', "Verify host when TLS is enabled", NULL }, + { "capath", '\0', POPT_ARG_STRING, &opts.capath, '\0', "Path to CA directory where peer certificate is stored", NULL }, + { "cacert", '\0', POPT_ARG_STRING, &opts.cacert, '\0', "Path to CA certificate", NULL }, ++ /* BASIC AUTH */ ++ { "username", '\0', POPT_ARG_STRING, &opts.username, '\0', "Username for basic authentication", NULL }, ++ { "password", '\0', POPT_ARG_STRING, &opts.password, '\0', "Password for basic authentication", NULL }, + POPT_TABLEEND + }; + +diff --git a/src/util/tev_curl.c b/src/util/tev_curl.c +index c155f4c038d4215933ee30d41c694ad4a14ae132..8faf07c714b636a0351be365597de68d2f68a1be 100644 +--- a/src/util/tev_curl.c ++++ b/src/util/tev_curl.c +@@ -1092,3 +1092,27 @@ errno_t tcurl_req_set_client_cert(struct tcurl_request *tcurl_req, + + return EOK; + } ++ ++errno_t tcurl_req_http_basic_auth(struct tcurl_request *tcurl_req, ++ const char *username, ++ const char *password) ++{ ++ errno_t ret; ++ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_USERNAME, username); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = tcurl_set_option(tcurl_req, CURLOPT_PASSWORD, password); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ return EOK; ++} +diff --git a/src/util/tev_curl.h b/src/util/tev_curl.h +index 933abcb9b531412737e8fcf391644d828b125cf8..c733127b3686b5665f53cf53ea72674e0d7af64e 100644 +--- a/src/util/tev_curl.h ++++ b/src/util/tev_curl.h +@@ -243,4 +243,19 @@ errno_t tcurl_req_set_client_cert(struct tcurl_request *tcurl_req, + const char *cert, + const char *key); + ++/** ++ * @brief Force HTTP basic authentication with @username and @password. ++ * ++ * @param[in] tcurl_request ++ * @param[in] username ++ * @param[in] password ++ * ++ * @returns errno code ++ * ++ * @see tcurl_http ++ */ ++errno_t tcurl_req_http_basic_auth(struct tcurl_request *tcurl_req, ++ const char *username, ++ const char *password); ++ + #endif /* __TEV_CURL_H */ +-- +2.9.3 + diff --git a/SOURCES/0079-NSS-Do-not-check-local-users-with-disabled-local_neg.patch b/SOURCES/0079-NSS-Do-not-check-local-users-with-disabled-local_neg.patch deleted file mode 100644 index b4c2e9e..0000000 --- a/SOURCES/0079-NSS-Do-not-check-local-users-with-disabled-local_neg.patch +++ /dev/null @@ -1,166 +0,0 @@ -From acb2de04987b163d602aa02155b34c50bce93584 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Mon, 8 Aug 2016 13:55:52 +0200 -Subject: [PATCH 79/82] NSS: Do not check local users with disabled - local_negative_timeout - -sssd_nss can set different negative timeout for local users -and groups. However, checking whether user/group is local -is quite expensive operation. We can avoid such operations -if local_negative_timeout is not set. - -This fix improve performance(40%) of lookup non-existing -entries in offline mode and with disabled local_negative_timeout. - - sh$ cat pok.sh - for i in {1..10000}; do - getent passwd -s sss temp$i - getent group -s sss temp$i - done - - #without patch - sh $time /bin/bash pok.sh - real 0m41.534s - user 0m3.580s - sys 0m14.202s - - #with patch - sh $time /bin/bash pok.sh - real 0m26.686s - user 0m3.292s - sys 0m13.165s - -Resolves: -https://fedorahosted.org/sssd/ticket/3122 - -Reviewed-by: Petr Cech ---- - src/responder/common/negcache.c | 45 ++++++++++++++++++++++++----------------- - 1 file changed, 27 insertions(+), 18 deletions(-) - -diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c -index dfeb0d483e4db34cb2f25e1f82884611a707aabe..5b7ad69f432518be94b88e92e24265add722c852 100644 ---- a/src/responder/common/negcache.c -+++ b/src/responder/common/negcache.c -@@ -143,7 +143,7 @@ done: - } - - static int sss_ncache_set_str(struct sss_nc_ctx *ctx, char *str, -- bool permanent, bool is_local) -+ bool permanent, bool use_local_negative) - { - TDB_DATA key; - TDB_DATA data; -@@ -157,15 +157,16 @@ static int sss_ncache_set_str(struct sss_nc_ctx *ctx, char *str, - if (permanent) { - timest = talloc_strdup(ctx, "0"); - } else { -- if (is_local == true && ctx->local_timeout > 0) { -- timell = (unsigned long long int)time(NULL) + ctx->local_timeout; -+ if (use_local_negative == true && ctx->local_timeout > ctx->timeout) { -+ timell = ctx->local_timeout; - } else { -- if (ctx->timeout > 0) { -- timell = (unsigned long long int)time(NULL) + ctx->timeout; -- } else { -+ /* EOK is tested in cwrap based unit test */ -+ if (ctx->timeout == 0) { - return EOK; - } -+ timell = ctx->timeout; - } -+ timell += (unsigned long long int)time(NULL); - timest = talloc_asprintf(ctx, "%llu", timell); - } - if (!timest) return ENOMEM; -@@ -457,7 +458,7 @@ int sss_ncache_check_cert(struct sss_nc_ctx *ctx, const char *cert) - static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent, - const char *domain, const char *name) - { -- bool is_local; -+ bool use_local_negative = false; - char *str; - int ret; - -@@ -466,8 +467,10 @@ static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent, - str = talloc_asprintf(ctx, "%s/%s/%s", NC_USER_PREFIX, domain, name); - if (!str) return ENOMEM; - -- is_local = is_user_local_by_name(name); -- ret = sss_ncache_set_str(ctx, str, permanent, is_local); -+ if (ctx->local_timeout > 0) { -+ use_local_negative = is_user_local_by_name(name); -+ } -+ ret = sss_ncache_set_str(ctx, str, permanent, use_local_negative); - - talloc_free(str); - return ret; -@@ -476,7 +479,7 @@ static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent, - static int sss_ncache_set_group_int(struct sss_nc_ctx *ctx, bool permanent, - const char *domain, const char *name) - { -- bool is_local; -+ bool use_local_negative = false; - char *str; - int ret; - -@@ -485,8 +488,10 @@ static int sss_ncache_set_group_int(struct sss_nc_ctx *ctx, bool permanent, - str = talloc_asprintf(ctx, "%s/%s/%s", NC_GROUP_PREFIX, domain, name); - if (!str) return ENOMEM; - -- is_local = is_group_local_by_name(name); -- ret = sss_ncache_set_str(ctx, str, permanent, is_local); -+ if (ctx->local_timeout > 0) { -+ use_local_negative = is_group_local_by_name(name); -+ } -+ ret = sss_ncache_set_str(ctx, str, permanent, use_local_negative); - - talloc_free(str); - return ret; -@@ -550,7 +555,7 @@ int sss_ncache_set_netgr(struct sss_nc_ctx *ctx, bool permanent, - int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent, - struct sss_domain_info *dom, uid_t uid) - { -- bool is_local; -+ bool use_local_negative = false; - char *str; - int ret; - -@@ -562,8 +567,10 @@ int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent, - } - if (!str) return ENOMEM; - -- is_local = is_user_local_by_uid(uid); -- ret = sss_ncache_set_str(ctx, str, permanent, is_local); -+ if (ctx->local_timeout > 0) { -+ use_local_negative = is_user_local_by_uid(uid); -+ } -+ ret = sss_ncache_set_str(ctx, str, permanent, use_local_negative); - - talloc_free(str); - return ret; -@@ -572,7 +579,7 @@ int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent, - int sss_ncache_set_gid(struct sss_nc_ctx *ctx, bool permanent, - struct sss_domain_info *dom, gid_t gid) - { -- bool is_local; -+ bool use_local_negative = false; - char *str; - int ret; - -@@ -584,8 +591,10 @@ int sss_ncache_set_gid(struct sss_nc_ctx *ctx, bool permanent, - } - if (!str) return ENOMEM; - -- is_local = is_group_local_by_gid(gid); -- ret = sss_ncache_set_str(ctx, str, permanent, is_local); -+ if (ctx->local_timeout > 0) { -+ use_local_negative = is_group_local_by_gid(gid); -+ } -+ ret = sss_ncache_set_str(ctx, str, permanent, use_local_negative); - - talloc_free(str); - return ret; --- -2.4.11 - diff --git a/SOURCES/0079-tcurl-test-allow-to-set-custom-headers.patch b/SOURCES/0079-tcurl-test-allow-to-set-custom-headers.patch new file mode 100644 index 0000000..ac764da --- /dev/null +++ b/SOURCES/0079-tcurl-test-allow-to-set-custom-headers.patch @@ -0,0 +1,63 @@ +From 8047207b470ea417b11919e84931a751485d2326 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 10 Mar 2017 12:11:12 +0100 +Subject: [PATCH 79/90] tcurl test: allow to set custom headers + +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit d1ed11fc50922aab2332758a9300f3fbf814f112) +--- + src/tests/tcurl_test_tool.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c +index 4ceef8e06040ea0abd4d112a5b7845f436c69488..63a3e26b561781795873c2a4d72ac071a4da9939 100644 +--- a/src/tests/tcurl_test_tool.c ++++ b/src/tests/tcurl_test_tool.c +@@ -40,6 +40,7 @@ struct tool_options { + int tls; + int verify_peer; + int verify_host; ++ const char **headers; + + enum tcurl_http_method method; + const char *socket_path; +@@ -121,13 +122,14 @@ prepare_requests(TALLOC_CTX *mem_ctx, + size_t *_num_requests) + { + struct tcurl_request **requests; ++ struct sss_iobuf *body; ++ const char **headers; + const char *arg; + const char *url; +- struct sss_iobuf *body; + errno_t ret; + size_t i; + +- static const char *headers[] = { ++ static const char *default_headers[] = { + "Content-type: application/octet-stream", + NULL, + }; +@@ -137,6 +139,8 @@ prepare_requests(TALLOC_CTX *mem_ctx, + return ENOMEM; + } + ++ headers = opts->headers == NULL ? default_headers : opts->headers; ++ + i = 0; + while ((arg = poptGetArg(pc)) != NULL) { + if (i >= MAXREQ) { +@@ -302,6 +306,9 @@ int main(int argc, const char *argv[]) + { "put", 'p', POPT_ARG_NONE, NULL, 'p', "Perform a HTTP PUT", NULL }, + { "post", 'o', POPT_ARG_NONE, NULL, 'o', "Perform a HTTP POST", NULL }, + { "del", 'd', POPT_ARG_NONE, NULL, 'd', "Perform a HTTP DELETE", NULL }, ++#ifdef POPT_ARG_ARGV ++ { "header", 'h', POPT_ARG_ARGV, &opts.headers, '\0', "Add HTTP header", NULL }, ++#endif + { "raw", 'r', POPT_ARG_NONE, &opts.raw, '\0', "Print raw protocol output", NULL }, + { "verbose", 'v', POPT_ARG_NONE, &opts.verbose, '\0', "Print response code and body", NULL }, + /* TLS */ +-- +2.9.3 + diff --git a/SOURCES/0080-config_schema-Add-ldap_user_email-to-schema.patch b/SOURCES/0080-config_schema-Add-ldap_user_email-to-schema.patch deleted file mode 100644 index 416c768..0000000 --- a/SOURCES/0080-config_schema-Add-ldap_user_email-to-schema.patch +++ /dev/null @@ -1,31 +0,0 @@ -From fad4c17acbc0170110a98806886e0eeec793c0c6 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Wed, 10 Aug 2016 08:17:02 +0200 -Subject: [PATCH 80/82] config_schema: Add ldap_user_email to schema -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: -https://fedorahosted.org/sssd/ticket/3068 - -Reviewed-by: Fabiano Fidêncio ---- - src/config/cfg_rules.ini | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 635c078436e8ca47f60e8d82341cb131469fe4c9..09f53fa41eb2904f11a78af333b6d79619d2759c 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -588,6 +588,7 @@ option = ldap_user_authorized_host - option = ldap_user_authorized_service - option = ldap_user_auth_type - option = ldap_user_certificate -+option = ldap_user_email - option = ldap_user_entry_usn - option = ldap_user_extra_attrs - option = ldap_user_fullname --- -2.4.11 - diff --git a/SOURCES/0080-tcurl-test-add-support-for-client-certificate.patch b/SOURCES/0080-tcurl-test-add-support-for-client-certificate.patch new file mode 100644 index 0000000..8635100 --- /dev/null +++ b/SOURCES/0080-tcurl-test-add-support-for-client-certificate.patch @@ -0,0 +1,53 @@ +From f63d4b3749fd76796a26f1c1f07bdddcb681a768 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Mon, 13 Mar 2017 13:30:48 +0100 +Subject: [PATCH 80/90] tcurl test: add support for client certificate + +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit ae6b11229d9961e26922918183c7c1de7780b8d6) +--- + src/tests/tcurl_test_tool.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/src/tests/tcurl_test_tool.c b/src/tests/tcurl_test_tool.c +index 63a3e26b561781795873c2a4d72ac071a4da9939..fbc2790357b131ebb21b4be041688e5f699d73e7 100644 +--- a/src/tests/tcurl_test_tool.c ++++ b/src/tests/tcurl_test_tool.c +@@ -47,6 +47,9 @@ struct tool_options { + const char *capath; + const char *cacert; + ++ const char *clientcert; ++ const char *clientkey; ++ + const char *username; + const char *password; + }; +@@ -201,6 +204,14 @@ prepare_requests(TALLOC_CTX *mem_ctx, + } + } + ++ if (opts->clientcert != NULL) { ++ ret = tcurl_req_set_client_cert(requests[i], opts->clientcert, ++ opts->clientkey); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ + if (opts->username != NULL && opts->password != NULL) { + ret = tcurl_req_http_basic_auth(requests[i], opts->username, + opts->password); +@@ -317,6 +328,8 @@ int main(int argc, const char *argv[]) + { "verify-host", '\0', POPT_ARG_NONE, &opts.verify_host, '\0', "Verify host when TLS is enabled", NULL }, + { "capath", '\0', POPT_ARG_STRING, &opts.capath, '\0', "Path to CA directory where peer certificate is stored", NULL }, + { "cacert", '\0', POPT_ARG_STRING, &opts.cacert, '\0', "Path to CA certificate", NULL }, ++ { "clientcert", '\0', POPT_ARG_STRING, &opts.clientcert, '\0', "Path to client's certificate", NULL }, ++ { "clientkey", '\0', POPT_ARG_STRING, &opts.clientkey, '\0', "Path to client's private key", NULL }, + /* BASIC AUTH */ + { "username", '\0', POPT_ARG_STRING, &opts.username, '\0', "Username for basic authentication", NULL }, + { "password", '\0', POPT_ARG_STRING, &opts.password, '\0', "Password for basic authentication", NULL }, +-- +2.9.3 + diff --git a/SOURCES/0081-NSS-Use-correct-name-for-invalidating-memory-cache.patch b/SOURCES/0081-NSS-Use-correct-name-for-invalidating-memory-cache.patch deleted file mode 100644 index 3cc0985..0000000 --- a/SOURCES/0081-NSS-Use-correct-name-for-invalidating-memory-cache.patch +++ /dev/null @@ -1,113 +0,0 @@ -From 1d0a914578ce72bad86cbe9e0beeda0c3b2d1dee Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Mon, 8 Aug 2016 17:30:29 +0200 -Subject: [PATCH 81/82] NSS: Use correct name for invalidating memory cache - -After refactoring of sysdb, we get and internal fully qualified -name from backend in org.freedesktop.sssd.dataprovider_rev.initgrCheck -Previously we got short name and we created fq name in -nss_update_initgr_memcache. Memory cache still need to use short names -if it was specified. - -This patch uses right name in different places. - -Reviewed-by: Petr Cech -Reviewed-by: Jakub Hrozek ---- - src/responder/nss/nsssrv_cmd.c | 31 +++++++++++++++++-------------- - src/responder/nss/nsssrv_private.h | 2 +- - 2 files changed, 18 insertions(+), 15 deletions(-) - -diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c -index f3b6ac4afb5d1571f283933b48e0256b91c56391..573959ea76fc1277fe84f40b88dcd34093da468d 100644 ---- a/src/responder/nss/nsssrv_cmd.c -+++ b/src/responder/nss/nsssrv_cmd.c -@@ -3961,13 +3961,13 @@ done: - } - - void nss_update_initgr_memcache(struct nss_ctx *nctx, -- const char *name, const char *domain, -+ const char *fq_name, const char *domain, - int gnum, uint32_t *groups) - { - TALLOC_CTX *tmp_ctx = NULL; - struct sss_domain_info *dom; - struct ldb_result *res; -- struct sized_string delete_name; -+ struct sized_string *delete_name; - bool changed = false; - uint32_t id; - uint32_t gids[gnum]; -@@ -3987,8 +3987,19 @@ void nss_update_initgr_memcache(struct nss_ctx *nctx, - } - - tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return; -+ } - -- ret = sysdb_initgroups(tmp_ctx, dom, name, &res); -+ ret = sized_output_name(tmp_ctx, nctx->rctx, fq_name, dom, &delete_name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sized_output_name failed for '%s': %d [%s]\n", -+ fq_name, ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ ret = sysdb_initgroups(tmp_ctx, dom, fq_name, &res); - if (ret != EOK && ret != ENOENT) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Failed to make request to our cache! [%d][%s]\n", -@@ -4002,8 +4013,7 @@ void nss_update_initgr_memcache(struct nss_ctx *nctx, - - if (ret == ENOENT || res->count == 0) { - /* The user is gone. Invalidate the mc record */ -- to_sized_string(&delete_name, name); -- ret = sss_mmap_cache_pw_invalidate(nctx->pwd_mc_ctx, &delete_name); -+ ret = sss_mmap_cache_pw_invalidate(nctx->pwd_mc_ctx, delete_name); - if (ret != EOK && ret != ENOENT) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Internal failure in memory cache code: %d [%s]\n", -@@ -4047,13 +4057,6 @@ void nss_update_initgr_memcache(struct nss_ctx *nctx, - } - - if (changed) { -- char *fq_name = sss_tc_fqname(tmp_ctx, dom->names, dom, name); -- if (!fq_name) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Could not create fq name\n"); -- goto done; -- } -- - for (i = 0; i < gnum; i++) { - id = groups[i]; - -@@ -4065,9 +4068,9 @@ void nss_update_initgr_memcache(struct nss_ctx *nctx, - } - } - -- to_sized_string(&delete_name, fq_name); -+ to_sized_string(delete_name, fq_name); - ret = sss_mmap_cache_initgr_invalidate(nctx->initgr_mc_ctx, -- &delete_name); -+ delete_name); - if (ret != EOK && ret != ENOENT) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Internal failure in memory cache code: %d [%s]\n", -diff --git a/src/responder/nss/nsssrv_private.h b/src/responder/nss/nsssrv_private.h -index 79c7b7265f66f57e0ea89fe192a1da4f8992f1a3..391eaaf40f84a7436bee63fd699241e4957fdbeb 100644 ---- a/src/responder/nss/nsssrv_private.h -+++ b/src/responder/nss/nsssrv_private.h -@@ -146,7 +146,7 @@ errno_t check_cache(struct nss_dom_ctx *dctx, - void nss_update_pw_memcache(struct nss_ctx *nctx); - void nss_update_gr_memcache(struct nss_ctx *nctx); - void nss_update_initgr_memcache(struct nss_ctx *nctx, -- const char *name, const char *domain, -+ const char *fq_name, const char *domain, - int gnum, uint32_t *groups); - - int nss_connection_setup(struct cli_ctx *cctx); --- -2.4.11 - diff --git a/SOURCES/0081-ci-do-not-build-secrets-on-rhel6.patch b/SOURCES/0081-ci-do-not-build-secrets-on-rhel6.patch new file mode 100644 index 0000000..f804036 --- /dev/null +++ b/SOURCES/0081-ci-do-not-build-secrets-on-rhel6.patch @@ -0,0 +1,115 @@ +From c9358747b25b257d82b050967812e54860fe7685 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 28 Mar 2017 15:24:01 +0200 +Subject: [PATCH 81/90] ci: do not build secrets on rhel6 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We require newer libcurl version than is available on rhel6. We don't +ship secrets responder in rhel6 so we just disable its build. + +Reviewed-by: Lukáš Slebodník +(cherry picked from commit 6698d40512e55e7c2d03e14c227c51b1edc77ffa) +--- + contrib/ci/configure.sh | 1 + + contrib/sssd.spec.in | 15 +++++++++++++++ + src/tests/intg/test_secrets.py | 4 ++++ + 3 files changed, 20 insertions(+) + +diff --git a/contrib/ci/configure.sh b/contrib/ci/configure.sh +index 7590743c2aa5fe31bcdf1a3e92a3f482dbec699b..9d18d0c187561a2dc3bc47d3e8913626e7ff3046 100644 +--- a/contrib/ci/configure.sh ++++ b/contrib/ci/configure.sh +@@ -38,6 +38,7 @@ if [[ "$DISTRO_BRANCH" == -redhat-redhatenterprise*-6.*- || + "--disable-cifs-idmap-plugin" + "--with-syslog=syslog" + "--without-python3-bindings" ++ "--without-secrets" + "--without-kcm" + ) + fi +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index af14d4e3d6b9ffeb4696f1517113b8daa575cb99..39a974edebba3dbcd7625d1729b4a7330eaa8a27 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -112,6 +112,12 @@ + %global enable_systemtap_opt --enable-systemtap + %endif + ++%if (0%{?fedora} || 0%{?epel} >= 7) ++ %global with_secrets 1 ++%else ++ %global with_secret_responder --without-secrets ++%endif ++ + %if (0%{?fedora} >= 23 || 0%{?rhel} >= 7) + %global with_kcm 1 + %global with_kcm_option --with-kcm +@@ -220,8 +226,10 @@ BuildRequires: libsmbclient-devel + %if (0%{?enable_systemtap} == 1) + BuildRequires: systemtap-sdt-devel + %endif ++%if (0%{?with_secrets} == 1) + BuildRequires: http-parser-devel + BuildRequires: jansson-devel ++%endif + BuildRequires: libuuid-devel + BuildRequires: libcurl-devel + +@@ -727,6 +735,7 @@ autoreconf -ivf + %{?with_python3_option} \ + %{?enable_polkit_rules_option} \ + %{?enable_systemtap_opt} \ ++ %{?with_secret_responder} \ + %{?with_kcm_option} \ + %{?experimental} + +@@ -865,7 +874,9 @@ done + %{_libexecdir}/%{servicename}/sssd_nss + %{_libexecdir}/%{servicename}/sssd_pam + %{_libexecdir}/%{servicename}/sssd_autofs ++%if (0%{?with_secrets} == 1) + %{_libexecdir}/%{servicename}/sssd_secrets ++%endif + %{_libexecdir}/%{servicename}/sssd_ssh + %{_libexecdir}/%{servicename}/sssd_sudo + %{_libexecdir}/%{servicename}/p11_child +@@ -900,7 +911,9 @@ done + %dir %{_localstatedir}/cache/krb5rcache + %attr(700,sssd,sssd) %dir %{dbpath} + %attr(755,sssd,sssd) %dir %{mcpath} ++%if (0%{?with_secrets} == 1) + %attr(700,root,root) %dir %{secdbpath} ++%endif + %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/passwd + %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/group + %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/initgroups +@@ -933,7 +946,9 @@ done + %{_mandir}/man5/sssd.conf.5* + %{_mandir}/man5/sssd-simple.5* + %{_mandir}/man5/sssd-sudo.5* ++%if (0%{?with_secrets} == 1) + %{_mandir}/man5/sssd-secrets.5* ++%endif + %{_mandir}/man5/sss_rpcidmapd.5* + %{_mandir}/man8/sssd.8* + %{_mandir}/man8/sss_cache.8* +diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py +index d71c1904558cc6f8a6eee36c4049582705bc30ac..202f43e61cb0e4986394ad2b32da5abdcb0be3e9 100644 +--- a/src/tests/intg/test_secrets.py ++++ b/src/tests/intg/test_secrets.py +@@ -46,6 +46,10 @@ def create_sssd_secrets_fixture(request): + raise Exception("failed to regenerate confdb") + + resp_path = os.path.join(config.LIBEXEC_PATH, "sssd", "sssd_secrets") ++ if not os.access(resp_path, os.X_OK): ++ # It would be cleaner to use pytest.mark.skipif on the package level ++ # but upstream insists on supporting RHEL-6. ++ pytest.skip("No Secrets responder, skipping") + + secpid = os.fork() + assert secpid >= 0 +-- +2.9.3 + diff --git a/SOURCES/0082-SYSDB-Avoid-optimisation-with-modifyTimestamp-for-us.patch b/SOURCES/0082-SYSDB-Avoid-optimisation-with-modifyTimestamp-for-us.patch deleted file mode 100644 index 9e36f14..0000000 --- a/SOURCES/0082-SYSDB-Avoid-optimisation-with-modifyTimestamp-for-us.patch +++ /dev/null @@ -1,89 +0,0 @@ -From d3925525068798e92cee1da95dbee0f838b2f36f Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Wed, 3 Aug 2016 18:48:04 +0200 -Subject: [PATCH 82/82] SYSDB: Avoid optimisation with modifyTimestamp for - users - -The usage of modifyTimestamp needn't be a reliable way -for detecting of changes in user entry in LDAP. -The authorisation need to rely current data from LDAP -and therefore we will temporary disable optimisation with -modifyTimestamp and we will rather rely on deep comparison -of attributes. In he future, it might be changed and -responders might control the optimization level. - -Resolves: -https://fedorahosted.org/sssd/ticket/3110 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 00f3c5cd03625357e226552084e499965512bf53) ---- - src/db/sysdb_ops.c | 19 ------------------- - src/tests/cmocka/test_sysdb_ts_cache.c | 14 -------------- - 2 files changed, 33 deletions(-) - -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 67006c155098b9fde00a01d424014852c383a325..44fb5b70e6d33fffbca5824f831a3229254ecb57 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -1101,16 +1101,6 @@ done: - return ret; - } - --static errno_t sysdb_check_and_update_ts_usr(struct sss_domain_info *domain, -- const char *grp_name, -- struct sysdb_attrs *attrs, -- uint64_t cache_timeout, -- time_t now) --{ -- return sysdb_check_and_update_ts_obj(domain, SYSDB_USER, grp_name, -- attrs, cache_timeout, now); --} -- - static errno_t sysdb_check_and_update_ts_grp(struct sss_domain_info *domain, - const char *grp_name, - struct sysdb_attrs *attrs, -@@ -2470,15 +2460,6 @@ int sysdb_store_user(struct sss_domain_info *domain, - now = time(NULL); - } - -- ret = sysdb_check_and_update_ts_usr(domain, name, attrs, -- cache_timeout, now); -- if (ret == EOK) { -- DEBUG(SSSDBG_TRACE_LIBS, -- "The user record of %s did not change, only updated " -- "the timestamp cache\n", name); -- return EOK; -- } -- - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - return ENOMEM; -diff --git a/src/tests/cmocka/test_sysdb_ts_cache.c b/src/tests/cmocka/test_sysdb_ts_cache.c -index aa857e7e4823d2d8ba1e1a794b3e2474876e9ab0..e950f88631e4c78573bbb7290edfe94b5ced57cd 100644 ---- a/src/tests/cmocka/test_sysdb_ts_cache.c -+++ b/src/tests/cmocka/test_sysdb_ts_cache.c -@@ -980,20 +980,6 @@ static void test_sysdb_user_update(void **state) - assert_int_equal(cache_expire_sysdb, TEST_CACHE_TIMEOUT + TEST_NOW_2); - assert_int_equal(cache_expire_ts, TEST_CACHE_TIMEOUT + TEST_NOW_2); - -- /* Update the same attrs and the same modifyTimestamp. -- * Only the timestamp cache must be bumped */ -- ret = sysdb_store_user(test_ctx->tctx->dom, TEST_USER_NAME, NULL, -- TEST_USER_UID, TEST_USER_GID, TEST_USER_NAME, -- "/home/"TEST_USER_NAME, "/bin/bash", NULL, -- user_attrs, NULL, TEST_CACHE_TIMEOUT, -- TEST_NOW_3); -- assert_int_equal(ret, EOK); -- -- get_pw_timestamp_attrs(test_ctx, TEST_USER_NAME, -- &cache_expire_sysdb, &cache_expire_ts); -- assert_int_equal(cache_expire_sysdb, TEST_CACHE_TIMEOUT + TEST_NOW_2); -- assert_int_equal(cache_expire_ts, TEST_CACHE_TIMEOUT + TEST_NOW_3); -- - /* Update with different modifyTimestamp but same attrs as previously - * saved to the timestamp cache. We should detect the 'real' attributes - * are the same and only bump the timestamp cache --- -2.4.11 - diff --git a/SOURCES/0082-build-make-curl-required-by-secrets.patch b/SOURCES/0082-build-make-curl-required-by-secrets.patch new file mode 100644 index 0000000..0880b3c --- /dev/null +++ b/SOURCES/0082-build-make-curl-required-by-secrets.patch @@ -0,0 +1,65 @@ +From 1ea81a335baa08746df7daf2707c070271990937 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 22 Mar 2017 12:32:31 +0100 +Subject: [PATCH 82/90] build: make curl required by secrets +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Also remove --disable-libcurl since it doesn't make sense. + +Reviewed-by: Lukáš Slebodník +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit 793f2573b2beaf8b48eab850429482acf68ec2b1) +--- + configure.ac | 6 +++++- + src/external/libcurl.m4 | 16 ++-------------- + 2 files changed, 7 insertions(+), 15 deletions(-) + +diff --git a/configure.ac b/configure.ac +index cf5e2557ef0a1bd6374200aa33abea6c509d03aa..80d8ea9ff5785b0d76edbb04f454d0dd8c8a1e6d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -201,9 +201,13 @@ if test x$with_secrets = xyes; then + fi + + if test x$with_kcm = xyes; then +- m4_include([src/external/libcurl.m4]) + m4_include([src/external/libuuid.m4]) + fi ++ ++if test x$with_kcm = xyes -o x$with_secrets = xyes; then ++ m4_include([src/external/libcurl.m4]) ++fi ++ + # This variable is defined by external/libcurl.m4, but conditionals + # must be always evaluated + AM_CONDITIONAL([BUILD_WITH_LIBCURL], +diff --git a/src/external/libcurl.m4 b/src/external/libcurl.m4 +index b420b04ad806bd1251f086b773ffe480d39f8bd3..42be308cd1e4b04e736daf887be9b75ea92db80e 100644 +--- a/src/external/libcurl.m4 ++++ b/src/external/libcurl.m4 +@@ -1,17 +1,5 @@ +-AC_ARG_ENABLE([curl], +- [AS_HELP_STRING([--disable-curl-support], +- [do not build with libcurl support])], +- [enable_libcurl=$enableval], +- [enable_libcurl=yes]) +- +-found_libcurl="no" +-AS_IF([test x$enable_libcurl = xyes], +- [PKG_CHECK_MODULES([CURL], +- [libcurl], +- [found_libcurl=yes], +- [AC_MSG_ERROR([ +-The libcurl development library was not found.]) +- ])]) ++PKG_CHECK_MODULES([CURL], [libcurl], [found_libcurl=yes], ++ [AC_MSG_ERROR([The libcurl development library was not found.])]) + + AS_IF([test x"$found_libcurl" = xyes], + CFLAGS="$CFLAGS $CURL_CFLAGS" +-- +2.9.3 + diff --git a/SOURCES/0083-SIMPLE-Do-not-parse-names-on-startup.patch b/SOURCES/0083-SIMPLE-Do-not-parse-names-on-startup.patch deleted file mode 100644 index 8185485..0000000 --- a/SOURCES/0083-SIMPLE-Do-not-parse-names-on-startup.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 701cabea51526c3bd40607761dc02069c9c2e499 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Thu, 21 Jul 2016 12:18:01 +0200 -Subject: [PATCH 83/86] SIMPLE: Do not parse names on startup -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -It's not required to parse names on SSSD startup in the simple access -provider. We can instead just parse the name when the access request is -processed. - -Resolves: -https://fedorahosted.org/sssd/ticket/3101 - -Reviewed-by: Lukáš Slebodník ---- - src/providers/simple/simple_access.c | 7 ------- - 1 file changed, 7 deletions(-) - -diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c -index cb72ada20727c63452936647876ef297106e17b0..ae90215351fe7db834898067d3b4bad71015ec5f 100644 ---- a/src/providers/simple/simple_access.c -+++ b/src/providers/simple/simple_access.c -@@ -284,7 +284,6 @@ errno_t sssm_simple_access_init(TALLOC_CTX *mem_ctx, - struct dp_method *dp_methods) - { - struct simple_ctx *ctx; -- errno_t ret; - - ctx = talloc_zero(mem_ctx, struct simple_ctx); - if (ctx == NULL) { -@@ -296,12 +295,6 @@ errno_t sssm_simple_access_init(TALLOC_CTX *mem_ctx, - ctx->be_ctx = be_ctx; - ctx->last_refresh_of_filter_lists = 0; - -- ret = simple_access_obtain_filter_lists(ctx); -- if (ret != EOK) { -- talloc_free(ctx); -- return ret; -- } -- - dp_set_method(dp_methods, DPM_ACCESS_HANDLER, - simple_access_handler_send, simple_access_handler_recv, ctx, - struct simple_ctx, struct pam_data, struct pam_data *); --- -2.4.11 - diff --git a/SOURCES/0083-secrets-use-tcurl-in-proxy-provider.patch b/SOURCES/0083-secrets-use-tcurl-in-proxy-provider.patch new file mode 100644 index 0000000..7292536 --- /dev/null +++ b/SOURCES/0083-secrets-use-tcurl-in-proxy-provider.patch @@ -0,0 +1,459 @@ +From a53c4afd13d92572b8c0ebb93d0dbe3f7c7bc680 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 22 Feb 2017 10:38:56 +0100 +Subject: [PATCH 83/90] secrets: use tcurl in proxy provider + +We switch from http-parser to libcurl for an http client. This gaves us many +features for free such as tls and http basic authentication support instead +of implementing it on our own. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3192 + +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit df99d709c8cbef3c378c111944d83b7345e4c1ea) +--- + Makefile.am | 3 + + src/responder/secrets/providers.c | 20 +++ + src/responder/secrets/proxy.c | 246 ++++++++++++++++++++++----------- + src/responder/secrets/secsrv_private.h | 5 + + 4 files changed, 191 insertions(+), 83 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 573b37c52fdeab1add4ea057e1e1844ea4d348a5..4a414f77df999b8b1d81f663fcc18dbd2d6d2dc4 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1486,6 +1486,8 @@ sssd_secrets_SOURCES = \ + src/responder/secrets/local.c \ + src/responder/secrets/proxy.c \ + src/util/sss_sockets.c \ ++ src/util/sss_iobuf.c \ ++ src/util/tev_curl.c \ + $(SSSD_RESPONDER_OBJ) \ + $(SSSD_RESOLV_OBJ) \ + $(NULL) +@@ -1497,6 +1499,7 @@ sssd_secrets_LDADD = \ + $(SYSTEMD_DAEMON_LIBS) \ + $(CARES_LIBS) \ + $(SSSD_INTERNAL_LTLIBS) \ ++ $(CURL_LIBS) \ + $(NULL) + endif + +diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c +index 94831c73036d269addca45c0117811a2c68873fd..80a443d91135447ec8ce8d424b692a6d7e26a907 100644 +--- a/src/responder/secrets/providers.c ++++ b/src/responder/secrets/providers.c +@@ -22,6 +22,7 @@ + #include "responder/secrets/secsrv_private.h" + #include "responder/secrets/secsrv_local.h" + #include "responder/secrets/secsrv_proxy.h" ++#include "util/sss_iobuf.h" + #include + + typedef int (*url_mapper_fn)(struct sec_req_ctx *secreq, +@@ -387,6 +388,25 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply, + return EOK; + } + ++errno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx, ++ struct sec_data *reply, ++ int response_code, ++ struct sss_iobuf *response) ++{ ++ DEBUG(SSSDBG_TRACE_LIBS, "HTTP reply %d\n", response_code); ++ ++ reply->data = (char *)sss_iobuf_get_data(response); ++ reply->length = sss_iobuf_get_len(response); ++ ++ talloc_steal(mem_ctx, reply->data); ++ ++ if (reply->data == NULL) { ++ return EINVAL; ++ } ++ ++ return EOK; ++} ++ + enum sec_http_status_codes sec_errno_to_http_status(errno_t err) + { + DEBUG(SSSDBG_TRACE_LIBS, "Request errno: %d\n", err); +diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c +index 3ed03e6086d0de0f6f80de227ffc65ef4067db4f..fe2f0134e233d9a98f499fe563abe0af69762514 100644 +--- a/src/responder/secrets/proxy.c ++++ b/src/responder/secrets/proxy.c +@@ -23,10 +23,15 @@ + #include "util/crypto/sss_crypto.h" + #include "resolv/async_resolv.h" + #include "util/sss_sockets.h" ++#include "util/sss_iobuf.h" ++#include "util/tev_curl.h" ++ ++#define SEC_PROXY_TIMEOUT 5 + + struct proxy_context { + struct resolv_ctx *resctx; + struct confdb_ctx *cdb; ++ struct tcurl_ctx *tcurl; + }; + + enum proxy_auth_type { +@@ -216,103 +221,177 @@ int proxy_sec_map_url(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq, + return EOK; + } + +-int proxy_sec_map_headers(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq, +- struct proxy_cfg *pcfg, char **req_headers) ++static errno_t proxy_http_append_header(TALLOC_CTX *mem_ctx, ++ const char *name, ++ const char *value, ++ const char ***_headers, ++ size_t *_num_headers) + { +- int ret; +- +- for (int i = 0; i < secreq->num_headers; i++) { +- bool forward = false; +- for (int j = 0; pcfg->fwd_headers[j]; j++) { +- if (strcasecmp(secreq->headers[i].name, +- pcfg->fwd_headers[j]) == 0) { +- forward = true; ++ const char **headers = *_headers; ++ size_t num_headers = *_num_headers; ++ ++ num_headers++; ++ headers = talloc_realloc(mem_ctx, headers, const char *, ++ num_headers + 1); ++ if (headers == NULL) { ++ return ENOMEM; ++ } ++ ++ headers[num_headers - 1] = talloc_asprintf(headers, "%s: %s", name, value); ++ if (headers[num_headers - 1] == NULL) { ++ return ENOMEM; ++ } ++ ++ headers[num_headers] = NULL; ++ ++ *_headers = headers; ++ *_num_headers = num_headers; ++ ++ return EOK; ++} ++ ++static const char ** ++proxy_http_create_headers(TALLOC_CTX *mem_ctx, ++ struct sec_req_ctx *secreq, ++ struct proxy_cfg *pcfg) ++{ ++ TALLOC_CTX *tmp_ctx; ++ const char **headers; ++ size_t num_headers; ++ errno_t ret; ++ int i, j; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n"); ++ return NULL; ++ } ++ ++ headers = talloc_zero_array(tmp_ctx, const char *, 1); ++ if (headers == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ num_headers = 0; ++ for (i = 0; i < secreq->num_headers; i++) { ++ for (j = 0; pcfg->fwd_headers[j]; j++) { ++ if (strcasecmp(secreq->headers[i].name, pcfg->fwd_headers[j]) == 0) { ++ DEBUG(SSSDBG_TRACE_LIBS, "Forwarding header %s: %s\n", ++ secreq->headers[i].name, secreq->headers[i].value); ++ ++ ret = proxy_http_append_header(tmp_ctx, secreq->headers[i].name, ++ secreq->headers[i].value, ++ &headers, &num_headers); ++ if (ret != EOK) { ++ goto done; ++ } ++ + break; + } + } +- if (forward) { +- DEBUG(SSSDBG_TRACE_LIBS, "Forwarding header %s:%s\n", +- secreq->headers[i].name, secreq->headers[i].value); +- +- ret = sec_http_append_header(mem_ctx, req_headers, +- secreq->headers[i].name, +- secreq->headers[i].value); +- if (ret) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Couldn't append header %s\n", secreq->headers[i].name); +- return ret; +- } +- } + } + + if (pcfg->auth_type == PAT_HEADER) { +- DEBUG(SSSDBG_TRACE_LIBS, +- "Forwarding header %s\n", pcfg->auth.header.name); ++ DEBUG(SSSDBG_TRACE_LIBS, "Forwarding header %s\n", ++ pcfg->auth.header.name); + +- ret = sec_http_append_header(mem_ctx, req_headers, +- pcfg->auth.header.name, +- pcfg->auth.header.value); +- if (ret) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Couldn't append header %s\n", pcfg->auth.header.name); +- return ret; ++ ret = proxy_http_append_header(tmp_ctx, pcfg->auth.header.name, ++ pcfg->auth.header.value, ++ &headers, &num_headers); ++ if (ret != EOK) { ++ goto done; + } + } + +- return EOK; ++ talloc_steal(mem_ctx, headers); ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ ++ if (ret != EOK) { ++ return NULL; ++ } ++ ++ return headers; + } + +-static int proxy_http_create_request(TALLOC_CTX *mem_ctx, +- struct sec_req_ctx *secreq, +- struct proxy_cfg *pcfg, +- const char *http_uri, +- struct sec_data **http_req) ++static errno_t proxy_http_create_request(TALLOC_CTX *mem_ctx, ++ struct sec_req_ctx *secreq, ++ struct proxy_cfg *pcfg, ++ const char *url, ++ struct tcurl_request **_tcurl_req) + { +- struct sec_data *req; +- int ret; ++ TALLOC_CTX *tmp_ctx; ++ struct tcurl_request *tcurl_req; ++ enum tcurl_http_method method; ++ struct sss_iobuf *body; ++ const char **headers; ++ errno_t ret; + +- req = talloc_zero(mem_ctx, struct sec_data); +- if (!req) return ENOMEM; ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n"); ++ return ENOMEM; ++ } + +- /* Request-Line */ +- req->data = talloc_asprintf(req, "%s %s HTTP/1.1\r\n", +- http_method_str(secreq->method), http_uri); +- if (!req->data) { ++ headers = proxy_http_create_headers(tmp_ctx, secreq, pcfg); ++ if (headers == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to construct HTTP headers!\n"); + ret = ENOMEM; + goto done; + } + +- /* Headers */ +- ret = proxy_sec_map_headers(req, secreq, pcfg, &req->data); +- if (ret) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't map headers\n"); ++ body = sss_iobuf_init_readonly(tmp_ctx, (uint8_t *)secreq->body.data, ++ secreq->body.length); ++ if (body == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create HTTP body!\n"); ++ ret = ENOMEM; + goto done; + } + +- /* CRLF separator before body */ +- req->data = talloc_strdup_append_buffer(req->data, "\r\n"); +- +- req->length = strlen(req->data); ++ switch (secreq->method) { ++ case HTTP_GET: ++ method = TCURL_HTTP_GET; ++ break; ++ case HTTP_PUT: ++ method = TCURL_HTTP_PUT; ++ break; ++ case HTTP_POST: ++ method = TCURL_HTTP_POST; ++ break; ++ case HTTP_DELETE: ++ method = TCURL_HTTP_DELETE; ++ break; ++ default: ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected HTTP method: %d\n", ++ secreq->method); ++ ret = EINVAL; ++ goto done; ++ } + +- /* Message-Body */ +- if (secreq->body.length > 0) { +- req->data = talloc_realloc_size(req, req->data, +- req->length + secreq->body.length); +- if (!req->data) { +- ret = ENOMEM; +- goto done; +- } ++ tcurl_req = tcurl_http(tmp_ctx, method, NULL, url, headers, body); ++ if (tcurl_req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create TCURL request!\n"); ++ ret = ENOMEM; ++ goto done; ++ } + +- memcpy(&req->data[req->length], +- secreq->body.data, secreq->body.length); +- req->length += secreq->body.length; ++ /* TCURL will return response buffer also with headers. */ ++ ret = tcurl_req_enable_rawoutput(tcurl_req); ++ if (ret != EOK) { ++ goto done; + } + +- *http_req = req; ++ talloc_steal(tcurl_req, body); ++ *_tcurl_req = talloc_steal(mem_ctx, tcurl_req); ++ + ret = EOK; + + done: +- if (ret) talloc_free(req); ++ talloc_free(tmp_ctx); + return ret; + } + +@@ -911,8 +990,8 @@ struct tevent_req *proxy_secret_req(TALLOC_CTX *mem_ctx, + { + struct tevent_req *req, *subreq; + struct proxy_secret_state *state; ++ struct tcurl_request *tcurl_req; + struct proxy_context *pctx; +- struct sec_data *http_req; + char *http_uri; + int ret; + +@@ -942,9 +1021,8 @@ struct tevent_req *proxy_secret_req(TALLOC_CTX *mem_ctx, + goto done; + } + +- + ret = proxy_http_create_request(state, state->secreq, state->pcfg, +- http_uri, &http_req); ++ http_uri, &tcurl_req); + if (ret) { + DEBUG(SSSDBG_CRIT_FAILURE, + "proxy_http_create_request failed [%d]: %s\n", +@@ -952,10 +1030,9 @@ struct tevent_req *proxy_secret_req(TALLOC_CTX *mem_ctx, + goto done; + } + +- +- subreq = proxy_http_req_send(pctx, state, ev, state->secreq, +- http_uri, http_req); +- if (!subreq) { ++ subreq = tcurl_request_send(mem_ctx, ev, pctx->tcurl, tcurl_req, ++ SEC_PROXY_TIMEOUT); ++ if (subreq == NULL) { + ret = ENOMEM; + goto done; + } +@@ -981,32 +1058,30 @@ static void proxy_secret_req_done(struct tevent_req *subreq) + { + struct tevent_req *req; + struct proxy_secret_state *state; +- struct proxy_http_reply *reply = NULL; ++ struct sss_iobuf *response; ++ int http_code; + int ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct proxy_secret_state); + +- ret = proxy_http_req_recv(subreq, state, &reply); ++ ret = tcurl_request_recv(state, subreq, &response, &http_code); + talloc_zfree(subreq); + + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "proxy_http request failed [%d]: %s\n", ++ DEBUG(SSSDBG_OP_FAILURE, "proxy_http request failed [%d]: %s\n", + ret, sss_strerror(ret)); + tevent_req_error(req, ret); + return; + } + +- ret = sec_http_reply_with_headers(state->secreq, &state->secreq->reply, +- reply->status_code, reply->reason_phrase, +- reply->headers, reply->num_headers, +- &reply->body); ++ ret = sec_http_reply_iobuf(state->secreq, &state->secreq->reply, ++ http_code, response); + if (ret == EOK) { + tevent_req_done(req); + } else { + DEBUG(SSSDBG_OP_FAILURE, +- "sec_http_reply_with_headers request failed [%d]: %s\n", ++ "sec_http_reply_iobuf request failed [%d]: %s\n", + ret, sss_strerror(ret)); + tevent_req_error(req, ret); + } +@@ -1034,6 +1109,11 @@ int proxy_secrets_provider_handle(struct sec_ctx *sctx, + + pctx->resctx = sctx->resctx; + pctx->cdb = sctx->rctx->cdb; ++ pctx->tcurl = tcurl_init(pctx, sctx->rctx->ev); ++ if (pctx->tcurl == NULL) { ++ talloc_free(pctx); ++ return ENOMEM; ++ } + + handle->context = pctx; + +diff --git a/src/responder/secrets/secsrv_private.h b/src/responder/secrets/secsrv_private.h +index a8544f656517a17fe4576247779bff4850beaf97..2e68628f61a0a8e79cd48fb5a510221e6fc36c70 100644 +--- a/src/responder/secrets/secsrv_private.h ++++ b/src/responder/secrets/secsrv_private.h +@@ -25,6 +25,7 @@ + #include "config.h" + #include "responder/common/responder.h" + #include "responder/secrets/secsrv.h" ++#include "util/sss_iobuf.h" + #include + + struct sec_kvp { +@@ -129,6 +130,10 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply, + int status_code, const char *reason, + struct sec_kvp *headers, int num_headers, + struct sec_data *body); ++errno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx, ++ struct sec_data *reply, ++ int response_code, ++ struct sss_iobuf *response); + enum sec_http_status_codes sec_errno_to_http_status(errno_t err); + + int sec_json_to_simple_secret(TALLOC_CTX *mem_ctx, +-- +2.9.3 + diff --git a/SOURCES/0084-SIMPLE-Fail-on-any-error-parsing-the-access-control-.patch b/SOURCES/0084-SIMPLE-Fail-on-any-error-parsing-the-access-control-.patch deleted file mode 100644 index 375b95e..0000000 --- a/SOURCES/0084-SIMPLE-Fail-on-any-error-parsing-the-access-control-.patch +++ /dev/null @@ -1,40 +0,0 @@ -From b40c53b524816f9308c90d79662f887e6a2ac1eb Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Thu, 21 Jul 2016 13:33:18 +0200 -Subject: [PATCH 84/86] SIMPLE: Fail on any error parsing the access control - list -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Luckily this error was hidden by the fact that SSSD didn't start at all -when an unparseable name was encountered after startup. Otherwise, this -would have been a security issue. - -Nonetheless, we should just fail and deny access if we can't parse a -name in a simple access list. - -Reviewed-by: Lukáš Slebodník ---- - src/providers/simple/simple_access.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c -index ae90215351fe7db834898067d3b4bad71015ec5f..577e8354e9b574764734248b2bde4ef06c6fb4fc 100644 ---- a/src/providers/simple/simple_access.c -+++ b/src/providers/simple/simple_access.c -@@ -211,7 +211,10 @@ simple_access_handler_send(TALLOC_CTX *mem_ctx, - - ret = simple_access_obtain_filter_lists(simple_ctx); - if (ret != EOK) { -- DEBUG(SSSDBG_MINOR_FAILURE, "Failed to refresh filter lists\n"); -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Failed to refresh filter lists, denying all access\n"); -+ pd->pam_status = PAM_PERM_DENIED; -+ goto immediately; - } - simple_ctx->last_refresh_of_filter_lists = now; - } --- -2.4.11 - diff --git a/SOURCES/0084-secrets-remove-http-parser-code-in-proxy-provider.patch b/SOURCES/0084-secrets-remove-http-parser-code-in-proxy-provider.patch new file mode 100644 index 0000000..7245f94 --- /dev/null +++ b/SOURCES/0084-secrets-remove-http-parser-code-in-proxy-provider.patch @@ -0,0 +1,612 @@ +From cfb82199afe237b4e892aaf2816db63279d7cb21 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 28 Feb 2017 14:14:40 +0100 +Subject: [PATCH 84/90] secrets: remove http-parser code in proxy provider + +We switche to libcurl in previous patch. This just removes the unused code. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3192 + +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit 06744bf5a47d5971a338281c8243b11cf72dac90) +--- + src/responder/secrets/proxy.c | 581 ------------------------------------------ + 1 file changed, 581 deletions(-) + +diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c +index fe2f0134e233d9a98f499fe563abe0af69762514..3c495716010ac468c9e2f1fb6356529a8dbdc614 100644 +--- a/src/responder/secrets/proxy.c ++++ b/src/responder/secrets/proxy.c +@@ -395,587 +395,6 @@ done: + return ret; + } + +-struct proxy_http_request { +- struct sec_data *data; +- size_t written; +-}; +- +-struct proxy_http_reply { +- http_parser parser; +- bool complete; +- +- int status_code; +- char *reason_phrase; +- struct sec_kvp *headers; +- int num_headers; +- struct sec_data body; +- +- size_t received; +-}; +- +-struct proxy_http_req_state { +- struct tevent_context *ev; +- +- char *proxyname; +- int port; +- +- struct resolv_hostent *hostent; +- int hostidx; +- +- int sd; +- struct tevent_fd *fde; +- +- struct proxy_http_request request; +- struct proxy_http_reply *reply; +-}; +- +-static int proxy_http_req_state_destroy(void *data); +-static void proxy_http_req_gethostname_done(struct tevent_req *subreq); +-static void proxy_http_req_connect_step(struct tevent_req *req); +-static void proxy_http_req_connect_done(struct tevent_req *subreq); +-static void proxy_fd_handler(struct tevent_context *ev, struct tevent_fd *fde, +- uint16_t flags, void *ptr); +- +-struct tevent_req *proxy_http_req_send(struct proxy_context *pctx, +- TALLOC_CTX *mem_ctx, +- struct tevent_context *ev, +- struct sec_req_ctx *secreq, +- const char *http_uri, +- struct sec_data *http_req) +-{ +- struct proxy_http_req_state *state; +- struct http_parser_url parsed; +- struct tevent_req *req, *subreq; +- int ret; +- +- req = tevent_req_create(mem_ctx, &state, struct proxy_http_req_state); +- if (!req) return NULL; +- +- state->ev = ev; +- state->request.data = http_req; +- state->sd = -1; +- talloc_set_destructor((TALLOC_CTX *)state, +- proxy_http_req_state_destroy); +- +- /* STEP1: reparse URL to get hostname and port */ +- ret = http_parser_parse_url(http_uri, strlen(http_uri), 0, &parsed); +- if (ret) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse URL [%s]: %d: %s\n", +- http_uri, ret, sss_strerror(ret)); +- goto done; +- } +- +- if (!(parsed.field_set & (1 << UF_HOST))) { +- DEBUG(SSSDBG_CRIT_FAILURE, "No UF_HOST flag found\n"); +- ret = EINVAL; +- goto done; +- } +- state->proxyname = +- talloc_strndup(state, +- &http_uri[parsed.field_data[UF_HOST].off], +- parsed.field_data[UF_HOST].len); +- if (!state->proxyname) { +- ret = ENOMEM; +- goto done; +- } +- DEBUG(SSSDBG_TRACE_LIBS, "proxy name: %s\n", state->proxyname); +- +- if (parsed.field_set & (1 << UF_PORT)) { +- state->port = parsed.port; +- } else if (parsed.field_set & (1 << UF_SCHEMA)) { +- uint16_t off = parsed.field_data[UF_SCHEMA].off; +- uint16_t len = parsed.field_data[UF_SCHEMA].len; +- +- if ((len == 5) && +- (strncmp("https", &http_uri[off], len) == 0)) { +- state->port = 443; +- } else if ((len == 4) && +- (strncmp("http", &http_uri[off], len) == 0)) { +- state->port = 80; +- } +- } +- DEBUG(SSSDBG_TRACE_LIBS, "proxy port: %d\n", state->port); +- +- /* STEP2: resolve hostname first */ +- subreq = resolv_gethostbyname_send(state, ev, pctx->resctx, +- state->proxyname, IPV4_FIRST, +- default_host_dbs); +- if (subreq == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- tevent_req_set_callback(subreq, proxy_http_req_gethostname_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 void proxy_http_req_gethostname_done(struct tevent_req *subreq) +-{ +- struct tevent_req *req; +- struct proxy_http_req_state *state; +- int resolv_status; +- int ret; +- +- req = tevent_req_callback_data(subreq, struct tevent_req); +- state = tevent_req_data(req, struct proxy_http_req_state); +- +- ret = resolv_gethostbyname_recv(subreq, state, &resolv_status, NULL, +- &state->hostent); +- talloc_zfree(subreq); +- if (ret != EOK) { +- if (ret == ENOENT) { +- /* Empty result, just quit */ +- DEBUG(SSSDBG_TRACE_INTERNAL, "No hostent found\n"); +- } else { +- DEBUG(SSSDBG_OP_FAILURE, +- "Could not resolve fqdn for this machine, error [%d]: %s, " +- "resolver returned: [%d]: %s\n", ret, strerror(ret), +- resolv_status, resolv_strerror(resolv_status)); +- } +- goto done; +- } +- +- /* EOK */ +- DEBUG(SSSDBG_TRACE_INTERNAL, "Found fqdn: %s\n", state->hostent->name); +- +- /* STEP3: connect to one of the servers */ +- proxy_http_req_connect_step(req); +- return; +- +-done: +- if (ret == EOK) { +- tevent_req_done(req); +- } else { +- tevent_req_error(req, ret); +- } +-} +- +-static void proxy_http_req_connect_step(struct tevent_req *req) +-{ +- struct proxy_http_req_state *state; +- struct sockaddr_storage *sockaddr; +- char *ipaddr; +- struct tevent_req *subreq; +- int ret; +- +- state = tevent_req_data(req, struct proxy_http_req_state); +- +- if (!state->hostent->addr_list[state->hostidx]) { +- DEBUG(SSSDBG_CRIT_FAILURE, "No more addresses to try.\n"); +- ret = ERR_SEC_NO_PROXY; +- goto done; +- } +- +- sockaddr = resolv_get_sockaddr_address_index(state, state->hostent, +- state->port, state->hostidx); +- if (sockaddr == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "resolv_get_sockaddr_address() failed\n"); +- ret = EIO; +- goto done; +- } +- +- if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) { +- ipaddr = resolv_get_string_address_index(state, state->hostent, +- state->hostidx); +- if (!ipaddr) { +- ret = EFAULT; +- goto done; +- } +- DEBUG(SSSDBG_TRACE_FUNC, "Connecting to %s:%d\n", +- ipaddr, state->port); +- } +- +- /* increase idx for next attempt */ +- state->hostidx++; +- +- subreq = sssd_async_socket_init_send(state, state->ev, sockaddr, +- sizeof(struct sockaddr_storage), +- SEC_NET_TIMEOUT); +- if (!subreq) { +- ret = EIO; +- goto done; +- } +- tevent_req_set_callback(subreq, proxy_http_req_connect_done, req); +- return; +- +-done: +- if (ret == EOK) { +- tevent_req_done(req); +- } else { +- tevent_req_error(req, ret); +- } +-} +- +-static void proxy_http_req_connect_done(struct tevent_req *subreq) +-{ +- struct tevent_req *req; +- struct proxy_http_req_state *state; +- int ret; +- +- req = tevent_req_callback_data(subreq, struct tevent_req); +- state = tevent_req_data(req, struct proxy_http_req_state); +- +- ret = sssd_async_socket_init_recv(subreq, &state->sd); +- talloc_zfree(subreq); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "sssd_async_socket_init request failed: [%d]: %s.\n", +- ret, sss_strerror(ret)); +- +- /* try next server if any */ +- proxy_http_req_connect_step(req); +- return; +- } +- +- /* EOK */ +- DEBUG(SSSDBG_TRACE_FUNC, "Connected to %s\n", state->hostent->name); +- +- state->fde = tevent_add_fd(state->ev, state, state->sd, +- TEVENT_FD_WRITE, proxy_fd_handler, +- req); +- if (!state->fde) { +- ret = EIO; +- goto done; +- } +- +- return; +- +-done: +- if (ret == EOK) { +- tevent_req_done(req); +- } else { +- tevent_req_error(req, ret); +- } +-} +- +- +-int proxy_http_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, +- struct proxy_http_reply **reply) +-{ +- struct proxy_http_req_state *state = +- tevent_req_data(req, struct proxy_http_req_state); +- +- TEVENT_REQ_RETURN_ON_ERROR(req); +- +- *reply = talloc_move(mem_ctx, &state->reply); +- +- return EOK; +-} +- +-static int proxy_http_req_state_destroy(void *data) +-{ +- struct proxy_http_req_state *state = +- talloc_get_type(data, struct proxy_http_req_state); +- +- if (!state) return 0; +- +- if (state->sd != -1) { +- DEBUG(SSSDBG_TRACE_FUNC, "closing socket [%d]\n", state->sd); +- close(state->sd); +- state->sd = -1; +- } +- +- return 0; +-} +- +-static int proxy_wire_send(int fd, struct proxy_http_request *req) +-{ +- struct sec_data data; +- int ret; +- +- data.data = req->data->data + req->written; +- data.length = req->data->length - req->written; +- +- ret = sec_send_data(fd, &data); +- if (ret != EOK && ret != EAGAIN) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "sec_send_data failed [%d]: %s\n", ret, sss_strerror(ret)); +- return ret; +- } +- +- req->written = req->data->length - data.length; +- return ret; +-} +- +-static void proxy_fd_send(void *data) +-{ +- struct proxy_http_req_state *state; +- struct tevent_req * req; +- int ret; +- +- req = talloc_get_type(data, struct tevent_req); +- state = tevent_req_data(req, struct proxy_http_req_state); +- +- ret = proxy_wire_send(state->sd, &state->request); +- if (ret == EAGAIN) { +- /* not all data was sent, loop again */ +- return; +- } +- if (ret != EOK) { +- DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting!\n"); +- tevent_req_error(req, ret); +- return; +- } +- +- /* ok all sent, wait for reply now */ +- TEVENT_FD_NOT_WRITEABLE(state->fde); +- TEVENT_FD_READABLE(state->fde); +- return; +-} +- +-static bool ph_received_data(struct proxy_http_reply *reply, size_t length) +-{ +- reply->received += length; +- if (reply->received > SEC_REQUEST_MAX_SIZE) { +- DEBUG(SSSDBG_FATAL_FAILURE, "Request too big, aborting!\n"); +- return true; +- } +- return false; +-} +- +-static void ph_append_string(TALLOC_CTX *memctx, char **dest, +- const char *src, size_t len) +-{ +- if (*dest) { +- *dest = talloc_strndup_append_buffer(*dest, src, len); +- } else { +- *dest = talloc_strndup(memctx, src, len); +- } +-} +- +-static int ph_on_message_begin(http_parser *parser) +-{ +- DEBUG(SSSDBG_TRACE_INTERNAL, "HTTP Message parsing begins\n"); +- return 0; +-} +- +-#if ((HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2)) +-static int ph_on_status(http_parser *parser, const char *at, size_t length) +-{ +- struct proxy_http_reply *reply = +- talloc_get_type(parser->data, struct proxy_http_reply); +- +- if (ph_received_data(reply, length)) return -1; +- +- ph_append_string(reply, &reply->reason_phrase, at, length); +- if (!reply->reason_phrase) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Failed to store reason phrase, aborting client!\n"); +- return -1; +- } +- +- return 0; +-} +-#endif +- +-static int ph_on_header_field(http_parser *parser, +- const char *at, size_t length) +-{ +- struct proxy_http_reply *reply = +- talloc_get_type(parser->data, struct proxy_http_reply); +- int n = reply->num_headers; +- +- if (ph_received_data(reply, length)) return -1; +- +- if (!reply->headers) { +- reply->headers = talloc_zero_array(reply, struct sec_kvp, 10); +- } else if ((n % 10 == 0) && +- (reply->headers[n - 1].value)) { +- reply->headers = talloc_realloc(reply, reply->headers, +- struct sec_kvp, n + 10); +- if (reply->headers) { +- memset(&reply->headers[n], 0, sizeof(struct sec_kvp) * 10); +- } +- } +- if (!reply->headers) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Failed to store headers, aborting client!\n"); +- return -1; +- } +- +- if (!n || reply->headers[n - 1].value) { +- /* new field */ +- n++; +- } +- ph_append_string(reply->headers, &reply->headers[n - 1].name, at, length); +- if (!reply->headers[n - 1].name) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Failed to store header name, aborting client!\n"); +- return -1; +- } +- +- return 0; +-} +- +-static int ph_on_header_value(http_parser *parser, +- const char *at, size_t length) +-{ +- struct proxy_http_reply *reply = +- talloc_get_type(parser->data, struct proxy_http_reply); +- int n = reply->num_headers; +- +- if (ph_received_data(reply, length)) return -1; +- +- if (!reply->headers) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Invalid headers pointer, aborting client!\n"); +- return -1; +- } +- +- if (reply->headers[n].name && !reply->headers[n].value) { +- /* we increment on new value */ +- n = ++reply->num_headers; +- } +- +- ph_append_string(reply->headers, &reply->headers[n - 1].value, at, length); +- if (!reply->headers[n - 1].value) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Failed to store header value, aborting client!\n"); +- return -1; +- } +- +- return 0; +-} +- +-static int ph_on_headers_complete(http_parser *parser) +-{ +- /* TODO: if message has no body we should return 1 */ +- return 0; +-} +- +-static int ph_on_body(http_parser *parser, const char *at, size_t length) +-{ +- struct proxy_http_reply *reply = +- talloc_get_type(parser->data, struct proxy_http_reply); +- +- if (ph_received_data(reply, length)) return -1; +- +- /* FIXME: body may be binary */ +- ph_append_string(reply, &reply->body.data, at, length); +- if (!reply->body.data) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Failed to store body, aborting!\n"); +- return -1; +- } +- reply->body.length += length; +- +- return 0; +-} +- +-static int ph_on_message_complete(http_parser *parser) +-{ +- struct proxy_http_reply *reply = +- talloc_get_type(parser->data, struct proxy_http_reply); +- +- reply->status_code = parser->status_code; +- reply->complete = true; +- +- return 0; +-} +- +-static http_parser_settings ph_callbacks = { +- .on_message_begin = ph_on_message_begin, +-#if ((HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2)) +- .on_status = ph_on_status, +-#endif +- .on_header_field = ph_on_header_field, +- .on_header_value = ph_on_header_value, +- .on_headers_complete = ph_on_headers_complete, +- .on_body = ph_on_body, +- .on_message_complete = ph_on_message_complete +-}; +- +-static void proxy_fd_recv(void *data) +-{ +- char buffer[SEC_PACKET_MAX_RECV_SIZE]; +- struct sec_data packet = { buffer, +- SEC_PACKET_MAX_RECV_SIZE }; +- struct proxy_http_req_state *state; +- struct tevent_req *req; +- bool must_complete = false; +- int ret; +- +- req = talloc_get_type(data, struct tevent_req); +- state = tevent_req_data(req, struct proxy_http_req_state); +- +- if (!state->reply) { +- /* A new reply */ +- state->reply = talloc_zero(state, struct proxy_http_reply); +- if (!state->reply) { +- DEBUG(SSSDBG_FATAL_FAILURE, "Failed to allocate reply, aborting!\n"); +- tevent_req_error(req, ENOMEM); +- return; +- } +- http_parser_init(&state->reply->parser, HTTP_RESPONSE); +- state->reply->parser.data = state->reply; +- } +- +- ret = sec_recv_data(state->sd, &packet); +- switch (ret) { +- case ENODATA: +- DEBUG(SSSDBG_TRACE_ALL, "Server closed connection.\n"); +- /* if we got no content length and the request is not complete, +- * then 0 length will indicate EOF to the parser, otherwise we +- * have an error */ +- must_complete = true; +- break; +- case EAGAIN: +- DEBUG(SSSDBG_TRACE_ALL, +- "Interrupted before any data could be read, retry later\n"); +- return; +- case EOK: +- /* all fine */ +- break; +- default: +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Failed to receive data (%d, %s), aborting\n", +- ret, sss_strerror(ret)); +- tevent_req_error(req, EIO); +- return; +- } +- +- ret = http_parser_execute(&state->reply->parser, &ph_callbacks, +- packet.data, packet.length); +- if (ret != packet.length) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Failed to parse request, aborting!\n"); +- tevent_req_error(req, EIO); +- return; +- } +- +- if (!state->reply->complete) { +- if (must_complete) { +- tevent_req_error(req, EIO); +- } +- return; +- } +- +- /* do not read anymore, server is done sending */ +- TEVENT_FD_NOT_READABLE(state->fde); +- tevent_req_done(req); +-} +- +-static void proxy_fd_handler(struct tevent_context *ev, struct tevent_fd *fde, +- uint16_t flags, void *data) +-{ +- if (flags & TEVENT_FD_READ) { +- proxy_fd_recv(data); +- } else if (flags & TEVENT_FD_WRITE) { +- proxy_fd_send(data); +- } +-} +- + struct proxy_secret_state { + struct tevent_context *ev; + struct sec_req_ctx *secreq; +-- +2.9.3 + diff --git a/SOURCES/0085-SIMPLE-Make-the-DP-handlers-testable.patch b/SOURCES/0085-SIMPLE-Make-the-DP-handlers-testable.patch deleted file mode 100644 index 62c43fa..0000000 --- a/SOURCES/0085-SIMPLE-Make-the-DP-handlers-testable.patch +++ /dev/null @@ -1,113 +0,0 @@ -From ab6ee9104826e286e0c67c9176c08b9a239e0622 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 26 Jul 2016 12:13:43 +0200 -Subject: [PATCH 85/86] SIMPLE: Make the DP handlers testable -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -To make it possible to call the whole DP handler in the unit test, not -just the evaluator part. - -Reviewed-by: Lukáš Slebodník ---- - Makefile.am | 1 + - src/providers/simple/simple_access.c | 5 ++-- - src/providers/simple/simple_access_pvt.h | 43 ++++++++++++++++++++++++++++++++ - 3 files changed, 47 insertions(+), 2 deletions(-) - create mode 100644 src/providers/simple/simple_access_pvt.h - -diff --git a/Makefile.am b/Makefile.am -index cefd9a43442fc19933f1e373d4f2ed4bb3ba3201..ee9b48c666a44781b582ba5d83102b705e898f29 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -665,6 +665,7 @@ dist_noinst_HEADERS = \ - src/providers/fail_over_srv.h \ - src/util/child_common.h \ - src/providers/simple/simple_access.h \ -+ src/providers/simple/simple_access_pvt.h \ - src/providers/krb5/krb5_auth.h \ - src/providers/krb5/krb5_common.h \ - src/providers/krb5/krb5_utils.h \ -diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c -index 577e8354e9b574764734248b2bde4ef06c6fb4fc..521beee84833b47b547bd1045c24e3384aa4d9a5 100644 ---- a/src/providers/simple/simple_access.c -+++ b/src/providers/simple/simple_access.c -@@ -22,6 +22,7 @@ - #include - - #include "providers/simple/simple_access.h" -+#include "providers/simple/simple_access_pvt.h" - #include "util/sss_utf8.h" - #include "providers/backend.h" - #include "db/sysdb.h" -@@ -176,7 +177,7 @@ struct simple_access_handler_state { - - static void simple_access_handler_done(struct tevent_req *subreq); - --static struct tevent_req * -+struct tevent_req * - simple_access_handler_send(TALLOC_CTX *mem_ctx, - struct simple_ctx *simple_ctx, - struct pam_data *pd, -@@ -265,7 +266,7 @@ done: - tevent_req_done(req); - } - --static errno_t -+errno_t - simple_access_handler_recv(TALLOC_CTX *mem_ctx, - struct tevent_req *req, - struct pam_data **_data) -diff --git a/src/providers/simple/simple_access_pvt.h b/src/providers/simple/simple_access_pvt.h -new file mode 100644 -index 0000000000000000000000000000000000000000..c133e1c5531be35861178e0b23aa7a09db9f7703 ---- /dev/null -+++ b/src/providers/simple/simple_access_pvt.h -@@ -0,0 +1,43 @@ -+/* -+ SSSD -+ -+ Simple access control -+ -+ Copyright (C) Sumit Bose 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 . -+*/ -+ -+#ifndef __SIMPLE_ACCESS_PVT_H__ -+#define __SIMPLE_ACCESS_PVT_H__ -+ -+#include "providers/data_provider/dp.h" -+ -+/* We only 'export' the functions in a private header file to be able to call -+ * them from unit tests -+ */ -+struct tevent_req * -+simple_access_handler_send(TALLOC_CTX *mem_ctx, -+ struct simple_ctx *simple_ctx, -+ struct pam_data *pd, -+ struct dp_req_params *params); -+ -+errno_t -+simple_access_handler_recv(TALLOC_CTX *mem_ctx, -+ struct tevent_req *req, -+ struct pam_data **_data); -+ -+int simple_access_obtain_filter_lists(struct simple_ctx *ctx); -+ -+#endif /* __SIMPLE_ACCESS_PVT_H__ */ --- -2.4.11 - diff --git a/SOURCES/0085-secrets-allow-to-configure-certificate-check.patch b/SOURCES/0085-secrets-allow-to-configure-certificate-check.patch new file mode 100644 index 0000000..dd9bea7 --- /dev/null +++ b/SOURCES/0085-secrets-allow-to-configure-certificate-check.patch @@ -0,0 +1,254 @@ +From d35f47a4e50feeb2b54c1621d0c2f5b15cd275eb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 28 Feb 2017 11:47:32 +0100 +Subject: [PATCH 85/90] secrets: allow to configure certificate check + +Some users may want to use TLS with unverified peer (for example if +they use self-signed certificate) or if unverified hostname (if +certificate hostname does not match with the real hostname). On the +other side it may be useful to point to a directory containing custom +certificate authorities. + +This patch add three new options to secrets responder: +verify_peer => peer's certificate must be valid +verify_host => hostnames must match +capath => path to directory containing CA certs +cacert => ca certificate +cert => client certificate +key => client private key + +Resolves: +https://pagure.io/SSSD/sssd/issue/3192 + +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit 720e1a5b95a953a0f1c8315bbb7c9c1edf9fb417) +--- + src/config/SSSDConfig/__init__.py.in | 6 +++ + src/config/cfg_rules.ini | 6 +++ + src/config/etc/sssd.api.conf | 6 +++ + src/man/sssd-secrets.5.xml | 76 ++++++++++++++++++++++++++++++++++++ + src/responder/secrets/proxy.c | 55 ++++++++++++++++++++++++++ + 5 files changed, 149 insertions(+) + +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index 211338778e81c1c60ffb3cdbc67c9619343d7798..75515ab5c68822538728900482296b9159e1547e 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -137,6 +137,12 @@ option_strings = { + 'forward_headers': _('The list of the headers to forward to the Custodia server together with the request'), + 'username': _('The username to use when authenticating to a Custodia server using basic_auth'), + 'password': _('The password to use when authenticating to a Custodia server using basic_auth'), ++ 'verify_peer': _('If true peer\'s certificate is verified if proxy_url uses https protocol'), ++ 'verify_host': _('If false peer\'s certificate may contain different hostname then proxy_url when https protocol is used'), ++ 'capath': _('Path to directory where certificate authority certificates are stored'), ++ 'cacert': _('Path to file containing server\'s CA certificate'), ++ 'cert': _('Path to file containing client\'s certificate'), ++ 'key': _('Path to file containing client\'s private key'), + + # [provider] + 'id_provider' : _('Identity provider'), +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 1a749db754cedd87f263f7ae596d6f8238bb4357..e47ff33242d6a9e5979fe0eb8eea14c2af28685a 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -265,6 +265,12 @@ option = auth_header_value + option = forward_headers + option = username + option = password ++option = verify_peer ++option = verify_host ++option = capath ++option = cacert ++option = cert ++option = key + + # KCM responder + [rule/allowed_kcm_options] +diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf +index a1a0c2992925a4c7df86832117eec2a0cf7894c9..f86589ecefa0b9e046aba781ded107f8e94395d6 100644 +--- a/src/config/etc/sssd.api.conf ++++ b/src/config/etc/sssd.api.conf +@@ -114,6 +114,12 @@ auth_header_value = str, None, false + forward_headers = list, None, false + username = str, None, false + password = str, None, false ++verify_peer = bool, None, false ++verify_host = bool, None, false ++capath = str, None, false ++cacert = str, None, false ++cert = str, None, false ++key = str, None, false + + [provider] + #Available provider types +diff --git a/src/man/sssd-secrets.5.xml b/src/man/sssd-secrets.5.xml +index 80e9c405921e1fb46a3d172d9873deebfa5ed2ce..44a86c3fb56a8bdebebd01e9f49ad171986282a4 100644 +--- a/src/man/sssd-secrets.5.xml ++++ b/src/man/sssd-secrets.5.xml +@@ -273,6 +273,82 @@ systemctl enable sssd-secrets.service + + + ++ ++ verify_peer (boolean) ++ ++ ++ Whether peer's certificate should be verified and valid ++ if HTTPS protocol is used with the proxy provider. ++ ++ ++ Default: true ++ ++ ++ ++ ++ verify_host (boolean) ++ ++ ++ Whether peer's hostname must match with hostname in ++ its certificate if HTTPS protocol is used with the ++ proxy provider. ++ ++ ++ Default: true ++ ++ ++ ++ ++ capath (string) ++ ++ ++ Path to directory containing stored certificate authority ++ certificates. System default path is used if this option is ++ not set. ++ ++ ++ Default: not set ++ ++ ++ ++ ++ cacert (string) ++ ++ ++ Path to file containing server's certificate authority ++ certificate. If this option is not set then the CA's ++ certificate is looked up in capath. ++ ++ ++ Default: not set ++ ++ ++ ++ ++ cert (string) ++ ++ ++ Path to file containing client's certificate if required ++ by the server. This file may also contain private key or ++ the private key may be in separate file set with ++ key. ++ ++ ++ Default: not set ++ ++ ++ ++ ++ key (string) ++ ++ ++ Path to file containing client's private key. ++ ++ ++ Default: not set ++ ++ ++ + + + +diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c +index 3c495716010ac468c9e2f1fb6356529a8dbdc614..240a1de1e431d511a1eca24d8b463c37ba893e7b 100644 +--- a/src/responder/secrets/proxy.c ++++ b/src/responder/secrets/proxy.c +@@ -59,6 +59,13 @@ struct proxy_cfg { + struct pat_basic_auth basic; + struct pat_header header; + } auth; ++ ++ char *key; ++ char *cert; ++ char *cacert; ++ char *capath; ++ bool verify_peer; ++ bool verify_host; + }; + + static int proxy_get_config_string(struct proxy_context *pctx, +@@ -129,6 +136,38 @@ static int proxy_sec_get_cfg(struct proxy_context *pctx, + } + } + ++ ret = confdb_get_bool(pctx->cdb, secreq->cfg_section, "verify_peer", ++ true, &cfg->verify_peer); ++ if (ret) goto done; ++ DEBUG(SSSDBG_CONF_SETTINGS, "verify_peer: %s\n", ++ (&cfg->verify_peer ? "true" : "false")); ++ ++ ret = confdb_get_bool(pctx->cdb, secreq->cfg_section, "verify_host", ++ true, &cfg->verify_host); ++ if (ret) goto done; ++ DEBUG(SSSDBG_CONF_SETTINGS, "verify_host: %s\n", ++ (&cfg->verify_host ? "true" : "false")); ++ ++ ret = proxy_get_config_string(pctx, cfg, false, secreq, ++ "capath", &cfg->capath); ++ if (ret) goto done; ++ DEBUG(SSSDBG_CONF_SETTINGS, "capath: %s\n", cfg->capath); ++ ++ ret = proxy_get_config_string(pctx, cfg, false, secreq, ++ "cacert", &cfg->cacert); ++ if (ret) goto done; ++ DEBUG(SSSDBG_CONF_SETTINGS, "cacert: %s\n", cfg->cacert); ++ ++ ret = proxy_get_config_string(pctx, cfg, false, secreq, ++ "cert", &cfg->cert); ++ if (ret) goto done; ++ DEBUG(SSSDBG_CONF_SETTINGS, "cert: %s\n", cfg->cert); ++ ++ ret = proxy_get_config_string(pctx, cfg, false, secreq, ++ "key", &cfg->key); ++ if (ret) goto done; ++ DEBUG(SSSDBG_CONF_SETTINGS, "key: %s\n", cfg->key); ++ + ret = confdb_get_string_as_list(pctx->cdb, cfg, secreq->cfg_section, + "forward_headers", &cfg->fwd_headers); + if ((ret != 0) && (ret != ENOENT)) goto done; +@@ -385,6 +424,22 @@ static errno_t proxy_http_create_request(TALLOC_CTX *mem_ctx, + goto done; + } + ++ /* Set TLS settings to verify peer. ++ * This has no effect for HTTP protocol so we can set it anyway. */ ++ ret = tcurl_req_verify_peer(tcurl_req, pcfg->capath, pcfg->cacert, ++ pcfg->verify_peer, pcfg->verify_host); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ /* Set client's certificate if required. */ ++ if (pcfg->cert != NULL) { ++ ret = tcurl_req_set_client_cert(tcurl_req, pcfg->cert, pcfg->key); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ + talloc_steal(tcurl_req, body); + *_tcurl_req = talloc_steal(mem_ctx, tcurl_req); + +-- +2.9.3 + diff --git a/SOURCES/0086-TESTS-Use-the-DP-handlers-in-simple-provider-tests-a.patch b/SOURCES/0086-TESTS-Use-the-DP-handlers-in-simple-provider-tests-a.patch deleted file mode 100644 index 4eed171..0000000 --- a/SOURCES/0086-TESTS-Use-the-DP-handlers-in-simple-provider-tests-a.patch +++ /dev/null @@ -1,308 +0,0 @@ -From 157781d8a05975c034858a38d2c00cdd94d374b0 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 26 Jul 2016 12:14:47 +0200 -Subject: [PATCH 86/86] TESTS: Use the DP handlers in simple provider tests, - add more tests -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Use the full simple access control handlers, just like SSSD does in the -tests. - -Reviewed-by: Lukáš Slebodník ---- - src/tests/cmocka/test_simple_access.c | 186 ++++++++++++++++++++++++++++++---- - 1 file changed, 165 insertions(+), 21 deletions(-) - -diff --git a/src/tests/cmocka/test_simple_access.c b/src/tests/cmocka/test_simple_access.c -index 1f093cf7fee4d046dcc727aa8815fb9aafb68c52..d41bb295e24ef2104cf17636f37d487fd14d0b93 100644 ---- a/src/tests/cmocka/test_simple_access.c -+++ b/src/tests/cmocka/test_simple_access.c -@@ -21,12 +21,14 @@ - #include - #include - #include -+#include - - #include "tests/cmocka/common_mock.h" - #include "tests/cmocka/common_mock_be.h" - #include "tests/cmocka/common_mock_resp.h" - #include "db/sysdb_private.h" /* new_subdomain() */ - #include "providers/simple/simple_access.h" -+#include "providers/simple/simple_access_pvt.h" - - #define TESTS_PATH "tp_" BASE_FILE_STEM - #define TEST_CONF_DB "test_simple_conf.ldb" -@@ -34,8 +36,6 @@ - #define TEST_SUBDOM_NAME "test.subdomain" - #define TEST_ID_PROVIDER "ldap" - --int simple_access_obtain_filter_lists(struct simple_ctx *ctx); -- - struct simple_test_ctx { - struct sss_test_ctx *tctx; - struct be_ctx *be_ctx; -@@ -43,6 +43,8 @@ struct simple_test_ctx { - - bool access_granted; - struct simple_ctx *ctx; -+ struct pam_data *pd; -+ struct dp_req_params *params; - }; - - static int test_simple_setup(struct sss_test_conf_param params[], void **state) -@@ -75,6 +77,19 @@ static int test_simple_setup(struct sss_test_conf_param params[], void **state) - return ENOMEM; - } - -+ simple_test_ctx->pd = talloc_zero(simple_test_ctx, struct pam_data); -+ if (simple_test_ctx->pd == NULL) { -+ return ENOMEM; -+ } -+ simple_test_ctx->pd->cmd = SSS_PAM_ACCT_MGMT; -+ -+ simple_test_ctx->params = talloc_zero(simple_test_ctx, -+ struct dp_req_params); -+ if (simple_test_ctx->params == NULL) { -+ return ENOMEM; -+ } -+ simple_test_ctx->params->ev = simple_test_ctx->tctx->ev; -+ - *state = simple_test_ctx; - return 0; - } -@@ -122,7 +137,7 @@ static int setup_with_params(struct simple_test_ctx *test_ctx, - return ret; - } - -- test_ctx->ctx = talloc(test_ctx, struct simple_ctx); -+ test_ctx->ctx = talloc_zero(test_ctx, struct simple_ctx); - if (test_ctx->ctx == NULL) { - return ENOMEM; - } -@@ -130,11 +145,6 @@ static int setup_with_params(struct simple_test_ctx *test_ctx, - test_ctx->ctx->be_ctx = test_ctx->be_ctx; - test_ctx->ctx->domain = test_ctx->tctx->dom; - -- ret = simple_access_obtain_filter_lists(test_ctx->ctx); -- if (ret != EOK) { -- return ret; -- } -- - return EOK; - } - -@@ -155,13 +165,14 @@ static int simple_test_teardown(void **state) - return 0; - } - --static void simple_access_check_done(struct tevent_req *req) -+static void simple_access_handler_done(struct tevent_req *req) - { - struct simple_test_ctx *simple_test_ctx = - tevent_req_callback_data(req, struct simple_test_ctx); - -- simple_test_ctx->tctx->error = simple_access_check_recv(req, -- &simple_test_ctx->access_granted); -+ simple_test_ctx->tctx->error = simple_access_handler_recv(simple_test_ctx, -+ req, &simple_test_ctx->pd); -+ simple_test_ctx->access_granted = (simple_test_ctx->pd->pam_status == PAM_SUCCESS); - talloc_free(req); - simple_test_ctx->tctx->done = true; - } -@@ -175,10 +186,13 @@ static void run_simple_access_check(struct simple_test_ctx *simple_test_ctx, - struct tevent_req *req; - - simple_test_ctx->tctx->done = false; -- req = simple_access_check_send(simple_test_ctx, simple_test_ctx->tctx->ev, -- simple_test_ctx->ctx, username); -+ simple_test_ctx->pd->user = discard_const(username); -+ req = simple_access_handler_send(simple_test_ctx, -+ simple_test_ctx->ctx, -+ simple_test_ctx->pd, -+ simple_test_ctx->params); - assert_non_null(req); -- tevent_req_set_callback(req, simple_access_check_done, simple_test_ctx); -+ tevent_req_set_callback(req, simple_access_handler_done, simple_test_ctx); - - ret = test_ev_loop(simple_test_ctx->tctx); - assert_int_equal(ret, expected_rv); -@@ -487,23 +501,29 @@ static void test_group_allow_empty(void **state) - { NULL, NULL }, - }; - -- ret = setup_with_params(simple_test_ctx, simple_test_ctx->tctx->dom, params); -+ ret = setup_with_params(simple_test_ctx, -+ simple_test_ctx->tctx->dom, -+ params); - assert_int_equal(ret, EOK); - -- req = simple_access_check_send(simple_test_ctx, simple_test_ctx->tctx->ev, -- simple_test_ctx->ctx, "u1@simple_test"); -+ simple_test_ctx->pd->user = discard_const("u1@simple_test"); -+ req = simple_access_handler_send(simple_test_ctx, simple_test_ctx->ctx, -+ simple_test_ctx->pd, -+ simple_test_ctx->params); - assert_non_null(req); -- tevent_req_set_callback(req, simple_access_check_done, simple_test_ctx); -+ tevent_req_set_callback(req, simple_access_handler_done, simple_test_ctx); - - ret = test_ev_loop(simple_test_ctx->tctx); - assert_int_equal(ret, EOK); - assert_false(simple_test_ctx->access_granted); - - simple_test_ctx->tctx->done = false; -- req = simple_access_check_send(simple_test_ctx, simple_test_ctx->tctx->ev, -- simple_test_ctx->ctx, "u3@simple_test"); -+ simple_test_ctx->pd->user = discard_const("u3@simple_test"); -+ req = simple_access_handler_send(simple_test_ctx, simple_test_ctx->ctx, -+ simple_test_ctx->pd, -+ simple_test_ctx->params); - assert_non_null(req); -- tevent_req_set_callback(req, simple_access_check_done, simple_test_ctx); -+ tevent_req_set_callback(req, simple_access_handler_done, simple_test_ctx); - - ret = test_ev_loop(simple_test_ctx->tctx); - assert_int_equal(ret, EOK); -@@ -584,6 +604,118 @@ static void test_group_allow_case_insensitive(void **state) - run_simple_access_check(simple_test_ctx, "u1@simple_test", EOK, true); - } - -+static void test_unparseable_allow_user(void **state) -+{ -+ errno_t ret; -+ struct simple_test_ctx *simple_test_ctx = \ -+ talloc_get_type(*state, struct simple_test_ctx); -+ struct sss_test_conf_param params[] = { -+ { "simple_allow_users", "u1, user@no.such.domain" }, -+ { NULL, NULL }, -+ }; -+ -+ ret = setup_with_params(simple_test_ctx, -+ simple_test_ctx->tctx->dom, -+ params); -+ assert_int_equal(ret, EOK); -+ -+ /* Case-sensitive domain, wrong case */ -+ simple_test_ctx->tctx->done = false; -+ simple_test_ctx->tctx->dom->case_sensitive = false; -+ /* A user that would normally be denied access will be denied because -+ * the access list can't be parsed -+ */ -+ run_simple_access_check(simple_test_ctx, "u2@simple_test", EOK, false); -+ /* A user that would normally be allowed access will be denied because -+ * the access list can't be parsed -+ */ -+ run_simple_access_check(simple_test_ctx, "u1@simple_test", EOK, false); -+} -+ -+static void test_unparseable_deny_user(void **state) -+{ -+ errno_t ret; -+ struct simple_test_ctx *simple_test_ctx = \ -+ talloc_get_type(*state, struct simple_test_ctx); -+ struct sss_test_conf_param params[] = { -+ { "simple_deny_users", "u2, user@no.such.domain" }, -+ { NULL, NULL }, -+ }; -+ -+ ret = setup_with_params(simple_test_ctx, -+ simple_test_ctx->tctx->dom, -+ params); -+ assert_int_equal(ret, EOK); -+ -+ /* Case-sensitive domain, wrong case */ -+ simple_test_ctx->tctx->done = false; -+ simple_test_ctx->tctx->dom->case_sensitive = false; -+ /* A user that would normally be denied access will be denied because -+ * the access list can't be parsed -+ */ -+ run_simple_access_check(simple_test_ctx, "u2@simple_test", EOK, false); -+ /* A user that would normally be allowed access will be denied because -+ * the access list can't be parsed -+ */ -+ run_simple_access_check(simple_test_ctx, "u1@simple_test", EOK, false); -+} -+ -+static void test_unparseable_allow_group(void **state) -+{ -+ errno_t ret; -+ struct simple_test_ctx *simple_test_ctx = \ -+ talloc_get_type(*state, struct simple_test_ctx); -+ struct sss_test_conf_param params[] = { -+ { "simple_allow_groups", "g1, group@no.such.domain" }, -+ { NULL, NULL }, -+ }; -+ -+ ret = setup_with_params(simple_test_ctx, -+ simple_test_ctx->tctx->dom, -+ params); -+ assert_int_equal(ret, EOK); -+ -+ /* Case-sensitive domain, wrong case */ -+ simple_test_ctx->tctx->done = false; -+ simple_test_ctx->tctx->dom->case_sensitive = false; -+ /* A group that would normally be denied access will be denied because -+ * the access list can't be parsed -+ */ -+ run_simple_access_check(simple_test_ctx, "u2@simple_test", EOK, false); -+ /* A group that would normally be allowed access will be denied because -+ * the access list can't be parsed -+ */ -+ run_simple_access_check(simple_test_ctx, "u1@simple_test", EOK, false); -+} -+ -+static void test_unparseable_deny_group(void **state) -+{ -+ errno_t ret; -+ struct simple_test_ctx *simple_test_ctx = \ -+ talloc_get_type(*state, struct simple_test_ctx); -+ struct sss_test_conf_param params[] = { -+ { "simple_deny_groups", "g2, group@no.such.domain" }, -+ { NULL, NULL }, -+ }; -+ -+ ret = setup_with_params(simple_test_ctx, -+ simple_test_ctx->tctx->dom, -+ params); -+ assert_int_equal(ret, EOK); -+ -+ /* Case-sensitive domain, wrong case */ -+ simple_test_ctx->tctx->done = false; -+ simple_test_ctx->tctx->dom->case_sensitive = false; -+ /* A group that would normally be denied access will be denied because -+ * the access list can't be parsed -+ */ -+ run_simple_access_check(simple_test_ctx, "u2@simple_test", EOK, false); -+ /* A group that would normally be allowed access will be denied because -+ * the access list can't be parsed -+ */ -+ run_simple_access_check(simple_test_ctx, "u1@simple_test", EOK, false); -+} -+ - static void test_group_space(void **state) - { - errno_t ret; -@@ -659,6 +791,18 @@ int main(int argc, const char *argv[]) - cmocka_unit_test_setup_teardown(test_group_space, - simple_group_test_setup, - simple_group_test_teardown), -+ cmocka_unit_test_setup_teardown(test_unparseable_allow_user, -+ simple_test_setup, -+ simple_test_teardown), -+ cmocka_unit_test_setup_teardown(test_unparseable_deny_user, -+ simple_test_setup, -+ simple_test_teardown), -+ cmocka_unit_test_setup_teardown(test_unparseable_allow_group, -+ simple_test_setup, -+ simple_test_teardown), -+ cmocka_unit_test_setup_teardown(test_unparseable_deny_group, -+ simple_test_setup, -+ simple_test_teardown), - }; - - /* Set debug level to invalid value so we can decide if -d 0 was used. */ --- -2.4.11 - diff --git a/SOURCES/0086-secrets-support-HTTP-basic-authentication-with-proxy.patch b/SOURCES/0086-secrets-support-HTTP-basic-authentication-with-proxy.patch new file mode 100644 index 0000000..f048f94 --- /dev/null +++ b/SOURCES/0086-secrets-support-HTTP-basic-authentication-with-proxy.patch @@ -0,0 +1,39 @@ +From 28d590900ab20dec3dc447562aefaa5e2771c48e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 28 Feb 2017 13:58:20 +0100 +Subject: [PATCH 86/90] secrets: support HTTP basic authentication with proxy + provider + +Even though configuration options auth_type = basic, username and password +are read they were not used anywhere prior this patch. + +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit af026ea6a6e812b7d6c5c889dda64ba7b7c433ee) +--- + src/responder/secrets/proxy.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c +index 240a1de1e431d511a1eca24d8b463c37ba893e7b..fd96e985c897e2cb470a9b5d6eecbd34350fb7d2 100644 +--- a/src/responder/secrets/proxy.c ++++ b/src/responder/secrets/proxy.c +@@ -440,6 +440,15 @@ static errno_t proxy_http_create_request(TALLOC_CTX *mem_ctx, + } + } + ++ /* Set basic authentication if required. */ ++ if (pcfg->auth_type == PAT_BASIC_AUTH) { ++ ret = tcurl_req_http_basic_auth(tcurl_req, pcfg->auth.basic.username, ++ pcfg->auth.basic.password); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ + talloc_steal(tcurl_req, body); + *_tcurl_req = talloc_steal(mem_ctx, tcurl_req); + +-- +2.9.3 + diff --git a/SOURCES/0087-gpo-gPCMachineExtensionNames-with-just-whitespaces.patch b/SOURCES/0087-gpo-gPCMachineExtensionNames-with-just-whitespaces.patch deleted file mode 100644 index d36a75a..0000000 --- a/SOURCES/0087-gpo-gPCMachineExtensionNames-with-just-whitespaces.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 662af3eaefdb11aff02947c0d34d31ba37c7b09c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Fri, 29 Jul 2016 16:09:16 +0200 -Subject: [PATCH 87/87] gpo: gPCMachineExtensionNames with just whitespaces - -Resolves: -https://fedorahosted.org/sssd/ticket/3114 - -We failed GPO procesing if the gPCMachineExtensionNames -attribute contained just whitespaces. This coused -failures in some server settings. - -Comment from Alexander Bokovoy quoting: - -You should use MS-GPOL spec. 2.2.4 'GPO Search' section says that when -processing gPCMachineExtensionNames, "Group Policy processing terminates -at the first out of sequence." -Since ' ' (space only) does not fall into defined syntax for -gPCMachineExtensionNames, this Group Policy processing is stopped and -its CSE GUIDs are set to 'empty list'. - -Because of the 3.2.5.1.10 'Extension Protocol Sequences' language ------------------------------------------------------------------------- -The Group Policy client MUST evaluate the subset of the abstract element -Filtered GPO list separately for each Group Policy extension by -including in the subset only those GPOs whose gPCUserExtensionNames (for -user policy mode) or gPCMachineExtensionNames (for computer policy mode) -attributes contain CSE GUID that correspond to the Group Policy -extension. If the CSE GUID corresponding to the Group Policy extension -is present in Extension List, it is invoked using the -Implementation Identifier field. Applicability is determined as -specified in section 3.2.1.5. The Group Policy Registry Extension MUST -always execute first. All other applicable Group Policy extensions in -the Extension List MUST be loaded and executed in Extension List order. -A failure in any Group Policy extension sequence MUST NOT affect the -execution of other Group Policy extensions. -------------------------------------------------------------------------- - -I think we can practically treat wrong content of -gPCMachineExtensionNames (and gPCUserExtensionNames) as inability of the -GPO to pass through the Filtered GPO list. Thus, the GPO would be -ignored. - -Reviewed-by: Alexander Bokovoy -Reviewed-by: Jakub Hrozek ---- - src/providers/ad/ad_gpo.c | 21 ++++++++++++++++++++- - 1 file changed, 20 insertions(+), 1 deletion(-) - -diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c -index f609d28136918adfe6a8d5e95319b27ffcab79c0..63c68ce35922ca0407ae6ea32c0a78100e14504b 100644 ---- a/src/providers/ad/ad_gpo.c -+++ b/src/providers/ad/ad_gpo.c -@@ -3765,6 +3765,24 @@ done: - } - } - -+static bool machine_ext_names_is_blank(char *attr_value) -+{ -+ char *ptr; -+ -+ if (attr_value == NULL) { -+ return true; -+ } -+ -+ ptr = attr_value; -+ for (; *ptr != '\0'; ptr++) { -+ if (!isspace(*ptr)) { -+ return false; -+ } -+ } -+ -+ return true; -+} -+ - static errno_t - ad_gpo_sd_process_attrs(struct tevent_req *req, - char *smb_host, -@@ -3880,7 +3898,8 @@ ad_gpo_sd_process_attrs(struct tevent_req *req, - goto done; - } - -- if ((ret == ENOENT) || (el->num_values == 0)) { -+ if ((ret == ENOENT) || (el->num_values == 0) -+ || machine_ext_names_is_blank((char *) el[0].values[0].data)) { - /* - * if gpo has no machine_ext_names (which is perfectly valid: it could - * have only user_ext_names, for example), we continue to next gpo --- -2.4.11 - diff --git a/SOURCES/0087-secrets-fix-debug-message.patch b/SOURCES/0087-secrets-fix-debug-message.patch new file mode 100644 index 0000000..19e563b --- /dev/null +++ b/SOURCES/0087-secrets-fix-debug-message.patch @@ -0,0 +1,29 @@ +From 265c8ea3b9564a53e38df08b89e0fbfb4e7dbfb9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 15 Mar 2017 13:27:59 +0100 +Subject: [PATCH 87/90] secrets: fix debug message + +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit db826f57b4c2ee814823057cc536386889f7aa1d) +--- + src/responder/secrets/secsrv_cmd.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/responder/secrets/secsrv_cmd.c b/src/responder/secrets/secsrv_cmd.c +index 70679ec0398fca25cfb0525772f539526a0eb3ff..b88680c3d7c3105d160de5c78e6d981b852318b9 100644 +--- a/src/responder/secrets/secsrv_cmd.c ++++ b/src/responder/secrets/secsrv_cmd.c +@@ -451,7 +451,8 @@ int sec_send_data(int fd, struct sec_data *data) + + data->length -= len; + data->data += len; +- DEBUG(SSSDBG_TRACE_INTERNAL, "sent %zu bytes\n", data->length); ++ DEBUG(SSSDBG_TRACE_INTERNAL, "sent %zu bytes, %zu bytes remaining\n", ++ len, data->length); + return EOK; + } + +-- +2.9.3 + diff --git a/SOURCES/0088-secrets-always-add-Content-Length-header.patch b/SOURCES/0088-secrets-always-add-Content-Length-header.patch new file mode 100644 index 0000000..d941ad3 --- /dev/null +++ b/SOURCES/0088-secrets-always-add-Content-Length-header.patch @@ -0,0 +1,112 @@ +From 07271dbd7c8f28a6aace48787040580973eb5a4e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 15 Mar 2017 15:15:08 +0100 +Subject: [PATCH 88/90] secrets: always add Content-Length header + +If custodia server does not reply with Content-Length header, curl may +wait for non-existing body of http reply if such body does not exist +(for example during POST operation when creating a container). + +Reviewed-by: Simo Sorce +Reviewed-by: Jakub Hrozek +(cherry picked from commit 13d720de13e490850c1139eea865bcd5195a2630) +--- + src/responder/secrets/providers.c | 72 ++++++++++++++++++++++++++++++++++++--- + 1 file changed, 68 insertions(+), 4 deletions(-) + +diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c +index 80a443d91135447ec8ce8d424b692a6d7e26a907..a27fb720b394e7c76d1b65f656146bcd00755449 100644 +--- a/src/responder/secrets/providers.c ++++ b/src/responder/secrets/providers.c +@@ -388,20 +388,84 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply, + return EOK; + } + ++static errno_t ++sec_http_iobuf_split(struct sss_iobuf *response, ++ const char **headers, ++ const char **body) ++{ ++ const char *data = (const char *)sss_iobuf_get_data(response); ++ char *delim; ++ ++ /* The last header ends with \r\n and then comes \r\n again as a separator ++ * of body from headers. We can use this to find this point. */ ++ delim = strstr(data, "\r\n\r\n"); ++ if (delim == NULL) { ++ return EINVAL; ++ } ++ ++ /* Skip to the body delimiter. */ ++ delim = delim + sizeof("\r\n") - 1; ++ ++ /* Replace \r\n with zeros turning data into: ++ * from HEADER\r\nBODY into HEADER\0\0BODY format. */ ++ delim[0] = '\0'; ++ delim[1] = '\0'; ++ ++ /* Split the buffer. */ ++ *headers = data; ++ *body = delim + 2; ++ ++ return 0; ++} ++ ++static const char * ++sec_http_iobuf_add_content_length(TALLOC_CTX *mem_ctx, ++ const char *headers, ++ size_t body_len) ++{ ++ /* If Content-Length is already present we do nothing. */ ++ if (strstr(headers, "Content-Length:") != NULL) { ++ return headers; ++ } ++ ++ return talloc_asprintf(mem_ctx, "%sContent-Length: %zu\r\n", ++ headers, body_len); ++} ++ + errno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx, + struct sec_data *reply, + int response_code, + struct sss_iobuf *response) + { ++ const char *headers; ++ const char *body; ++ size_t body_len; ++ errno_t ret; ++ + DEBUG(SSSDBG_TRACE_LIBS, "HTTP reply %d\n", response_code); + +- reply->data = (char *)sss_iobuf_get_data(response); +- reply->length = sss_iobuf_get_len(response); ++ ret = sec_http_iobuf_split(response, &headers, &body); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Unexpected HTTP reply, returning what we got from server\n"); ++ reply->data = (char *)sss_iobuf_get_data(response); ++ reply->length = sss_iobuf_get_len(response); + +- talloc_steal(mem_ctx, reply->data); ++ return EOK; ++ } + ++ /* Add Content-Length header if not present so client does not await ++ * not-existing incoming data. */ ++ body_len = strlen(body); ++ headers = sec_http_iobuf_add_content_length(mem_ctx, headers, body_len); ++ if (headers == NULL) { ++ return ENOMEM; ++ } ++ ++ reply->length = strlen(headers) + sizeof("\r\n") - 1 + body_len; ++ reply->data = talloc_asprintf(mem_ctx, "%s\r\n%s", headers, body); + if (reply->data == NULL) { +- return EINVAL; ++ return ENOMEM; + } + + return EOK; +-- +2.9.3 + diff --git a/SOURCES/0088-sss_ini-Change-debug-level-of-config-error-msgs.patch b/SOURCES/0088-sss_ini-Change-debug-level-of-config-error-msgs.patch deleted file mode 100644 index 1ed8612..0000000 --- a/SOURCES/0088-sss_ini-Change-debug-level-of-config-error-msgs.patch +++ /dev/null @@ -1,44 +0,0 @@ -From d049533953665fa3494a4932aeae7705ff84e107 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Wed, 27 Jul 2016 14:14:33 +0200 -Subject: [PATCH 088/102] sss_ini: Change debug level of config error msgs -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Syntax errors in configuration files -prevent SSSD or sssctl to start completely. -It would be good to display these errors -by default with the highest level. - -Reviewed-by: Petr Čech -(cherry picked from commit 9dc081500979616f9af623ebe2d52837c211759f) ---- - src/util/sss_ini.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/util/sss_ini.c b/src/util/sss_ini.c -index d9bc46ad71fa820fd5f462cf71036213171fa92a..e56006c05555d6e0c5e726e83771abce5a72b139 100644 ---- a/src/util/sss_ini.c -+++ b/src/util/sss_ini.c -@@ -182,7 +182,7 @@ int sss_ini_get_mtime(struct sss_ini_initdata *init_data, - - /* Print ini_config errors */ - --void sss_ini_config_print_errors(char **error_list) -+static void sss_ini_config_print_errors(char **error_list) - { - #ifdef HAVE_LIBINI_CONFIG_V1 - unsigned count = 0; -@@ -192,7 +192,7 @@ void sss_ini_config_print_errors(char **error_list) - } - - while (error_list[count]) { -- DEBUG(SSSDBG_CRIT_FAILURE, "%s\n", error_list[count]); -+ DEBUG(SSSDBG_FATAL_FAILURE, "%s\n", error_list[count]); - count++; - } - #endif --- -2.4.11 - diff --git a/SOURCES/0089-CONFIG-full_name_format-is-an-allowed-option-for-all.patch b/SOURCES/0089-CONFIG-full_name_format-is-an-allowed-option-for-all.patch deleted file mode 100644 index 6c52b00..0000000 --- a/SOURCES/0089-CONFIG-full_name_format-is-an-allowed-option-for-all.patch +++ /dev/null @@ -1,77 +0,0 @@ -From c54b38573a93d1176a44935ba310e590904edb92 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Fri, 12 Aug 2016 13:23:16 +0200 -Subject: [PATCH 089/102] CONFIG: full_name_format is an allowed option for all - domains -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit cc4d1af16820b15595b60c3df15220fb852eb897) ---- - src/config/SSSDConfig/__init__.py.in | 1 + - src/config/SSSDConfigTest.py | 2 ++ - src/config/cfg_rules.ini | 1 + - src/config/etc/sssd.api.conf | 1 + - 4 files changed, 5 insertions(+) - -diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in -index 7856c4c6b2d675b7f7f0f5f2048086044e8fb5ea..3114d1da9fe8e833ae4050ac343ba2763dc56e68 100644 ---- a/src/config/SSSDConfig/__init__.py.in -+++ b/src/config/SSSDConfig/__init__.py.in -@@ -163,6 +163,7 @@ option_strings = { - 'subdomain_refresh_interval' : _('How often should subdomains list be refreshed'), - 'subdomain_inherit' : _('List of options that should be inherited into a subdomain'), - 'cached_auth_timeout' : _('How long can cached credentials be used for cached authentication'), -+ 'full_name_format' : _('Printf-compatible format for displaying fully-qualified names'), - - # [provider/ipa] - 'ipa_domain' : _('IPA domain'), -diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py -index 332d8702d983b6ec8bf12ec781a1bbf296b552e0..bfb247ac45f752397000d43c54a20e57c6fbd9a5 100755 ---- a/src/config/SSSDConfigTest.py -+++ b/src/config/SSSDConfigTest.py -@@ -560,6 +560,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): - 'realmd_tags', - 'subdomain_refresh_interval', - 'subdomain_inherit', -+ 'full_name_format', - 'cached_auth_timeout'] - - self.assertTrue(type(options) == dict, -@@ -927,6 +928,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): - 'realmd_tags', - 'subdomain_refresh_interval', - 'subdomain_inherit', -+ 'full_name_format', - 'cached_auth_timeout'] - - self.assertTrue(type(options) == dict, -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index 09f53fa41eb2904f11a78af333b6d79619d2759c..febe4289832f3778b7e974ef4e8b3f6d9d8bffd8 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -287,6 +287,7 @@ option = subdomain_refresh_interval - option = subdomain_inherit - option = cached_auth_timeout - option = wildcard_limit -+option = full_name_format - - #Entry cache timeouts - option = entry_cache_user_timeout -diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf -index 737f0e149d56bd07b078cb83acbc43ea2ed3a057..2a43b8b68051c5133abc65a78f0d4a5561e760bd 100644 ---- a/src/config/etc/sssd.api.conf -+++ b/src/config/etc/sssd.api.conf -@@ -147,6 +147,7 @@ realmd_tags = str, None, false - subdomain_refresh_interval = int, None, false - subdomain_inherit = str, None, false - cached_auth_timeout = int, None, false -+full_name_format = str, None, false - - #Entry cache timeouts - entry_cache_user_timeout = int, None, false --- -2.4.11 - diff --git a/SOURCES/0089-sss_iobuf-fix-read-shadows-a-global-declaration.patch b/SOURCES/0089-sss_iobuf-fix-read-shadows-a-global-declaration.patch new file mode 100644 index 0000000..2524495 --- /dev/null +++ b/SOURCES/0089-sss_iobuf-fix-read-shadows-a-global-declaration.patch @@ -0,0 +1,40 @@ +From ce191dc1922d894573eee828c88c325f64515d3e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 28 Mar 2017 15:26:52 +0200 +Subject: [PATCH 89/90] sss_iobuf: fix 'read' shadows a global declaration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Lukáš Slebodník +(cherry picked from commit 18e4fe9d836e8f7bee52724374ffc0011172329f) +--- + src/util/sss_iobuf.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/util/sss_iobuf.c b/src/util/sss_iobuf.c +index fc288d2df2bfaaba393dd490d4da8976de804cb5..518713e4cc3dd99627a3a4450f235cbbc69ed3a2 100644 +--- a/src/util/sss_iobuf.c ++++ b/src/util/sss_iobuf.c +@@ -188,15 +188,15 @@ errno_t sss_iobuf_read_len(struct sss_iobuf *iobuf, + size_t len, + uint8_t *_buf) + { +- size_t read; ++ size_t read_bytes; + errno_t ret; + +- ret = sss_iobuf_read(iobuf, len, _buf, &read); ++ ret = sss_iobuf_read(iobuf, len, _buf, &read_bytes); + if (ret != EOK) { + return ret; + } + +- if (read != len) { ++ if (read_bytes != len) { + return ENOBUFS; + } + +-- +2.9.3 + diff --git a/SOURCES/0090-CONFIG-re_expression-is-an-allowed-option-for-all-do.patch b/SOURCES/0090-CONFIG-re_expression-is-an-allowed-option-for-all-do.patch deleted file mode 100644 index 61b409a..0000000 --- a/SOURCES/0090-CONFIG-re_expression-is-an-allowed-option-for-all-do.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 92302f81c25bc2b5ce9dbc2236c671d591fe69e0 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Fri, 12 Aug 2016 16:41:21 +0200 -Subject: [PATCH 090/102] CONFIG: re_expression is an allowed option for all - domains -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 6d19051c50c10fc4de056ebb385c63ec0ed221cb) ---- - src/config/SSSDConfig/__init__.py.in | 1 + - src/config/SSSDConfigTest.py | 2 ++ - src/config/cfg_rules.ini | 1 + - src/config/etc/sssd.api.conf | 1 + - 4 files changed, 5 insertions(+) - -diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in -index 3114d1da9fe8e833ae4050ac343ba2763dc56e68..ac538788b9878dc2613cb48b7483d392cca41d47 100644 ---- a/src/config/SSSDConfig/__init__.py.in -+++ b/src/config/SSSDConfig/__init__.py.in -@@ -164,6 +164,7 @@ option_strings = { - 'subdomain_inherit' : _('List of options that should be inherited into a subdomain'), - 'cached_auth_timeout' : _('How long can cached credentials be used for cached authentication'), - 'full_name_format' : _('Printf-compatible format for displaying fully-qualified names'), -+ 're_expression' : _('Regex to parse username and domain'), - - # [provider/ipa] - 'ipa_domain' : _('IPA domain'), -diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py -index bfb247ac45f752397000d43c54a20e57c6fbd9a5..00c688f1e57c5f481d3adba2fe0374145216bc33 100755 ---- a/src/config/SSSDConfigTest.py -+++ b/src/config/SSSDConfigTest.py -@@ -561,6 +561,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): - 'subdomain_refresh_interval', - 'subdomain_inherit', - 'full_name_format', -+ 're_expression', - 'cached_auth_timeout'] - - self.assertTrue(type(options) == dict, -@@ -929,6 +930,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): - 'subdomain_refresh_interval', - 'subdomain_inherit', - 'full_name_format', -+ 're_expression', - 'cached_auth_timeout'] - - self.assertTrue(type(options) == dict, -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index febe4289832f3778b7e974ef4e8b3f6d9d8bffd8..bd0116f334e2605e7671a208225761421511a75a 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -288,6 +288,7 @@ option = subdomain_inherit - option = cached_auth_timeout - option = wildcard_limit - option = full_name_format -+option = re_expression - - #Entry cache timeouts - option = entry_cache_user_timeout -diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf -index 2a43b8b68051c5133abc65a78f0d4a5561e760bd..5ac6f79521f5f776fc17319c3afb87d44961afca 100644 ---- a/src/config/etc/sssd.api.conf -+++ b/src/config/etc/sssd.api.conf -@@ -148,6 +148,7 @@ subdomain_refresh_interval = int, None, false - subdomain_inherit = str, None, false - cached_auth_timeout = int, None, false - full_name_format = str, None, false -+re_expression = str, None, false - - #Entry cache timeouts - entry_cache_user_timeout = int, None, false --- -2.4.11 - diff --git a/SOURCES/0090-configure-fix-typo.patch b/SOURCES/0090-configure-fix-typo.patch new file mode 100644 index 0000000..f7a0f28 --- /dev/null +++ b/SOURCES/0090-configure-fix-typo.patch @@ -0,0 +1,29 @@ +From a87cb169e5700bf9a3e74d4a1980e8e5c8e24692 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 29 Mar 2017 13:28:49 +0200 +Subject: [PATCH 90/90] configure: fix typo +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Lukáš Slebodník +(cherry picked from commit dc186bfe90665c13d589b3b4efd9009293e62c46) +--- + src/external/libhttp_parser.m4 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/external/libhttp_parser.m4 b/src/external/libhttp_parser.m4 +index 504bdf0f66c95b3d224c677a205a46e6f8b44726..3a5ef0dbbc63423ad8e960d72e97ec4fb4481dd1 100644 +--- a/src/external/libhttp_parser.m4 ++++ b/src/external/libhttp_parser.m4 +@@ -17,6 +17,6 @@ AS_IF([test x"$found_http_parser" != xyes], + ], + [-L$sss_extra_libdir -lhttp_parser_strict])], + [AC_MSG_ERROR([ +-You must have the header file http_parse.h installed to build sssd ++You must have the header file http_parser.h installed to build sssd + with secrets responder. If you want to build sssd without secret responder + then specify --without-secrets when running configure.])])]) +-- +2.9.3 + diff --git a/SOURCES/0091-pam_test_client-add-service-and-environment-to-PAM-t.patch b/SOURCES/0091-pam_test_client-add-service-and-environment-to-PAM-t.patch new file mode 100644 index 0000000..e511e0d --- /dev/null +++ b/SOURCES/0091-pam_test_client-add-service-and-environment-to-PAM-t.patch @@ -0,0 +1,105 @@ +From a5a6f0ab816be0dfd24b97a59c161adbe15ef406 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 24 Jan 2017 14:50:20 +0100 +Subject: [PATCH 91/96] pam_test_client: add service and environment to PAM + test client +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related to https://pagure.io/SSSD/sssd/issue/3292 + +Reviewed-by: Pavel Březina +(cherry picked from commit 7be6624d9eda369e9a4d70c8ee4939b3622229b3) +--- + src/sss_client/pam_test_client.c | 50 ++++++++++++++++++++++++++++++---------- + 1 file changed, 38 insertions(+), 12 deletions(-) + +diff --git a/src/sss_client/pam_test_client.c b/src/sss_client/pam_test_client.c +index 29d1fcbf01682668d51bf154736aec673bd46501..ea032a75b195a9bf8078ed7d248da154ab0c8430 100644 +--- a/src/sss_client/pam_test_client.c ++++ b/src/sss_client/pam_test_client.c +@@ -48,34 +48,44 @@ static struct pam_conv conv = { + # error "Missing text based pam conversation function" + #endif + ++#define DEFAULT_ACTION "acct" ++#define DEFAULT_SERVICE "system-auth" ++ + int main(int argc, char *argv[]) { + + pam_handle_t *pamh; + char *user; + char *action; ++ char *service; + int ret; ++ size_t c; ++ char **pam_env; + + if (argc == 1) { +- fprintf(stderr, "missing action and user name, using default\n"); +- action = strdup("auth"); +- user = strdup("dummy"); ++ fprintf(stderr, "Usage: pam_test_client USERNAME " ++ "[auth|acct|setc|chau|open|clos] [pam_service]\n"); ++ return 0; + } else if (argc == 2) { +- fprintf(stdout, "using first argument as action and default user name\n"); +- action = strdup(argv[1]); +- user = strdup("dummy"); +- } else { +- action = strdup(argv[1]); +- user = strdup(argv[2]); ++ fprintf(stderr, "using first argument as user name and default action " ++ "and service\n"); ++ } else if (argc == 3) { ++ fprintf(stderr, "using first argument as user name, second as action " ++ "and default service\n"); + } + +- if (action == NULL || user == NULL) { ++ user = strdup(argv[1]); ++ action = argc > 2 ? strdup(argv[2]) : strdup(DEFAULT_ACTION); ++ service = argc > 3 ? strdup(argv[3]) : strdup(DEFAULT_SERVICE); ++ ++ if (action == NULL || user == NULL || service == NULL) { + fprintf(stderr, "Out of memory!\n"); + return 1; + } + +- fprintf(stdout, "action: %s\nuser: %s\n", action,user); ++ fprintf(stdout, "user: %s\naction: %s\nservice: %s\n", ++ user, action, service); + +- ret = pam_start("sss_test", user, &conv, &pamh); ++ ret = pam_start(service, user, &conv, &pamh); + if (ret != PAM_SUCCESS) { + fprintf(stderr, "pam_start failed: %s\n", pam_strerror(pamh, ret)); + return 1; +@@ -109,7 +119,23 @@ int main(int argc, char *argv[]) { + fprintf(stderr, "unknown action\n"); + } + ++ fprintf(stderr, "PAM Environment:\n"); ++ pam_env = pam_getenvlist(pamh); ++ if (pam_env != NULL && pam_env[0] != NULL) { ++ for (c = 0; pam_env[c] != NULL; c++) { ++ fprintf(stderr, " - %s\n", pam_env[c]); ++ free(pam_env[c]); ++ } ++ } else { ++ fprintf(stderr, " - no env -\n"); ++ } ++ free(pam_env); ++ + pam_end(pamh, ret); + ++ free(user); ++ free(action); ++ free(service); ++ + return 0; + } +-- +2.9.3 + diff --git a/SOURCES/0091-rdp-add-ability-to-forward-reply-to-the-client-reque.patch b/SOURCES/0091-rdp-add-ability-to-forward-reply-to-the-client-reque.patch deleted file mode 100644 index 1719c18..0000000 --- a/SOURCES/0091-rdp-add-ability-to-forward-reply-to-the-client-reque.patch +++ /dev/null @@ -1,518 +0,0 @@ -From dc115d8a6aa1a656522c4f11c89e11d61360fd05 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Tue, 28 Jun 2016 11:40:16 +0200 -Subject: [PATCH 091/102] rdp: add ability to forward reply to the client - request -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -In cases where the InfoPipe servers just as a middle-man between -the DataProvider and a client we can simply forward the reply -reducing amount of coded needed in the InfoPipe. - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Jakub Hrozek -(cherry picked from commit a40d9cc11d17d9c3c22a0462cd8c419d1e79ffb8) ---- - src/responder/common/data_provider/rdp.h | 20 ++ - src/responder/common/data_provider/rdp_message.c | 260 +++++++++++++++++------ - src/responder/ifp/ifp_domains.c | 78 +------ - 3 files changed, 220 insertions(+), 138 deletions(-) - -diff --git a/src/responder/common/data_provider/rdp.h b/src/responder/common/data_provider/rdp.h -index 8a3ec803d8ea7914e2a54661e31dec084586582a..f0aed179a3d33de0462591e6c0bcd3c518105707 100644 ---- a/src/responder/common/data_provider/rdp.h -+++ b/src/responder/common/data_provider/rdp.h -@@ -54,6 +54,26 @@ errno_t _rdp_message_recv(struct tevent_req *req, - #define rdp_message_recv(req, ...) \ - _rdp_message_recv(req, ##__VA_ARGS__, DBUS_TYPE_INVALID) - -+/** -+ * Send D-Bus message to Data Provider but instead of returning the reply -+ * to the caller it forwards the reply to the client request. No further -+ * processing is required by the caller. In case of a failure the client -+ * request is freed since there is nothing we can do. -+ */ -+void _rdp_message_send_and_reply(struct sbus_request *sbus_req, -+ struct resp_ctx *rctx, -+ struct sss_domain_info *domain, -+ const char *path, -+ const char *iface, -+ const char *method, -+ int first_arg_type, -+ ...); -+ -+#define rdp_message_send_and_reply(sbus_req, rctx, domain, path, iface, \ -+ method, ...) \ -+ _rdp_message_send_and_reply(sbus_req, rctx, domain, path, iface, method, \ -+ ##__VA_ARGS__, DBUS_TYPE_INVALID) -+ - errno_t rdp_register_client(struct be_conn *be_conn, - const char *client_name); - -diff --git a/src/responder/common/data_provider/rdp_message.c b/src/responder/common/data_provider/rdp_message.c -index 78af6f8967b378536b6456274fbcac4b609d1033..e226401567e4a1b2b9784a9aba21540ff5f0bc8d 100644 ---- a/src/responder/common/data_provider/rdp_message.c -+++ b/src/responder/common/data_provider/rdp_message.c -@@ -53,104 +53,72 @@ static errno_t rdp_error_to_errno(DBusError *error) - return EIO; - } - --struct rdp_message_state { -- struct DBusMessage *reply; --}; -- --static int rdp_message_state_destructor(struct rdp_message_state *state) -+static errno_t -+rdp_message_send_internal(struct resp_ctx *rctx, -+ struct sss_domain_info *domain, -+ DBusPendingCallNotifyFunction notify_fn, -+ void *notify_fn_data, -+ const char *path, -+ const char *iface, -+ const char *method, -+ int first_arg_type, -+ va_list va) - { -- if (state->reply != NULL) { -- dbus_message_unref(state->reply); -- } -- -- return 0; --} -- --static void rdp_message_done(DBusPendingCall *pending, void *ptr); -- --struct tevent_req *_rdp_message_send(TALLOC_CTX *mem_ctx, -- struct resp_ctx *rctx, -- struct sss_domain_info *domain, -- const char *path, -- const char *iface, -- const char *method, -- int first_arg_type, -- ...) --{ -- struct rdp_message_state *state; - struct be_conn *be_conn; -- struct tevent_req *req; -- DBusMessage *msg; -+ DBusMessage *msg = NULL; - dbus_bool_t bret; - errno_t ret; -- va_list va; -- -- req = tevent_req_create(mem_ctx, &state, struct rdp_message_state); -- if (req == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); -- return NULL; -- } -- -- talloc_set_destructor(state, rdp_message_state_destructor); - - ret = sss_dp_get_domain_conn(rctx, domain->conn_name, &be_conn); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "BUG: The Data Provider connection for " - "%s is not available!\n", domain->name); -- ret = ERR_INTERNAL; -- goto immediately; -+ goto done; - } - - msg = dbus_message_new_method_call(NULL, path, iface, method); - if (msg == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create message\n"); - ret = ENOMEM; -- goto immediately; -+ goto done; - } - -- va_start(va, first_arg_type); - bret = dbus_message_append_args_valist(msg, first_arg_type, va); -- va_end(va); - if (!bret) { - DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n"); - ret = EIO; -- goto immediately; -+ goto done; - } - - DEBUG(SSSDBG_TRACE_FUNC, "DP Request: %s %s.%s\n", path, iface, method); - -- ret = sbus_conn_send(be_conn->conn, msg, 30000, -- rdp_message_done, req, NULL); -+ ret = sbus_conn_send(be_conn->conn, msg, 3000, -+ notify_fn, notify_fn_data, NULL); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to contact Data Provider " - "[%d]: %s\n", ret, sss_strerror(ret)); -- goto immediately; -+ goto done; - } - -- return req; -+ ret = EOK; - --immediately: -- if (ret == EOK) { -- tevent_req_done(req); -- } else { -- tevent_req_error(req, ret); -+done: -+ if (msg != NULL) { -+ dbus_message_unref(msg); - } -- tevent_req_post(req, rctx->ev); - -- return req; -+ return ret; - } - --static void rdp_message_done(DBusPendingCall *pending, void *ptr) -+static errno_t rdp_process_pending_call(DBusPendingCall *pending, -+ DBusMessage **_reply) - { -- struct rdp_message_state *state; -- DBusMessage *reply = NULL; -- struct tevent_req *req; -- DBusError error; -+ DBusMessage *reply; - dbus_bool_t bret; -+ DBusError error; - errno_t ret; - -- req = talloc_get_type(ptr, struct tevent_req); -- state = tevent_req_data(req, struct rdp_message_state); -+ *_reply = NULL; - - dbus_error_init(&error); - -@@ -165,9 +133,8 @@ static void rdp_message_done(DBusPendingCall *pending, void *ptr) - switch (dbus_message_get_type(reply)) { - case DBUS_MESSAGE_TYPE_METHOD_RETURN: - DEBUG(SSSDBG_TRACE_FUNC, "DP Success\n"); -- state->reply = reply; - ret = EOK; -- goto done; -+ break; - - case DBUS_MESSAGE_TYPE_ERROR: - bret = dbus_set_error_from_message(&error, reply); -@@ -180,28 +147,105 @@ static void rdp_message_done(DBusPendingCall *pending, void *ptr) - DEBUG(SSSDBG_CRIT_FAILURE, "DP Error [%s]: %s\n", - error.name, (error.message == NULL ? "(null)" : error.message)); - ret = rdp_error_to_errno(&error); -- goto done; -+ break; - default: -+ dbus_message_unref(reply); - DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected type?\n"); - ret = ERR_INTERNAL; - goto done; - } - -- ret = ERR_INTERNAL; -+ *_reply = reply; - - done: - dbus_pending_call_unref(pending); - dbus_error_free(&error); - -+ return ret; -+} -+ -+struct rdp_message_state { -+ struct DBusMessage *reply; -+}; -+ -+static int rdp_message_state_destructor(struct rdp_message_state *state) -+{ -+ if (state->reply != NULL) { -+ dbus_message_unref(state->reply); -+ } -+ -+ return 0; -+} -+ -+static void rdp_message_done(DBusPendingCall *pending, void *ptr); -+ -+struct tevent_req *_rdp_message_send(TALLOC_CTX *mem_ctx, -+ struct resp_ctx *rctx, -+ struct sss_domain_info *domain, -+ const char *path, -+ const char *iface, -+ const char *method, -+ int first_arg_type, -+ ...) -+{ -+ struct rdp_message_state *state; -+ struct tevent_req *req; -+ errno_t ret; -+ va_list va; -+ -+ req = tevent_req_create(mem_ctx, &state, struct rdp_message_state); -+ if (req == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); -+ return NULL; -+ } -+ -+ talloc_set_destructor(state, rdp_message_state_destructor); -+ -+ va_start(va, first_arg_type); -+ ret = rdp_message_send_internal(rctx, domain, rdp_message_done, req, -+ path, iface, method, first_arg_type, va); -+ va_end(va); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to contact Data Provider " -+ "[%d]: %s\n", ret, sss_strerror(ret)); -+ goto immediately; -+ } -+ -+ return req; -+ -+immediately: - if (ret == EOK) { - tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ tevent_req_post(req, rctx->ev); -+ -+ return req; -+} -+ -+static void rdp_message_done(DBusPendingCall *pending, void *ptr) -+{ -+ struct rdp_message_state *state; -+ struct tevent_req *req; -+ errno_t ret; -+ -+ req = talloc_get_type(ptr, struct tevent_req); -+ state = tevent_req_data(req, struct rdp_message_state); -+ -+ ret = rdp_process_pending_call(pending, &state->reply); -+ if (ret != EOK) { -+ if (state->reply != NULL) { -+ dbus_message_unref(state->reply); -+ } -+ -+ state->reply = NULL; -+ -+ tevent_req_error(req, ret); - return; - } - -- if (reply != NULL) { -- dbus_message_unref(reply); -- } -- tevent_req_error(req, ret); -+ tevent_req_done(req); - } - - errno_t _rdp_message_recv(struct tevent_req *req, -@@ -241,3 +285,85 @@ done: - return ret; - } - -+static void rdp_message_send_and_reply_done(DBusPendingCall *pending, -+ void *ptr); -+ -+void _rdp_message_send_and_reply(struct sbus_request *sbus_req, -+ struct resp_ctx *rctx, -+ struct sss_domain_info *domain, -+ const char *path, -+ const char *iface, -+ const char *method, -+ int first_arg_type, -+ ...) -+{ -+ errno_t ret; -+ va_list va; -+ -+ va_start(va, first_arg_type); -+ ret = rdp_message_send_internal(rctx, domain, -+ rdp_message_send_and_reply_done, sbus_req, -+ path, iface, method, first_arg_type, va); -+ va_end(va); -+ -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to contact Data Provider " -+ "[%d]: %s\n", ret, sss_strerror(ret)); -+ talloc_free(sbus_req); -+ } -+} -+ -+static void rdp_message_send_and_reply_done(DBusPendingCall *pending, -+ void *ptr) -+{ -+ struct sbus_request *sbus_req; -+ DBusMessage *reply = NULL; -+ dbus_uint32_t serial; -+ const char *sender; -+ dbus_bool_t dbret; -+ errno_t ret; -+ -+ sbus_req = talloc_get_type(ptr, struct sbus_request); -+ -+ ret = rdp_process_pending_call(pending, &reply); -+ if (reply == NULL) { -+ /* Something bad happened. Just kill the request. */ -+ ret = EIO; -+ goto done; -+ } -+ -+ /* Otherwise we have a valid reply and we do not care about returned -+ * value. We set destination and serial in reply to point to the original -+ * client request. */ -+ -+ sender = dbus_message_get_sender(sbus_req->message); -+ serial = dbus_message_get_serial(sbus_req->message); -+ -+ dbret = dbus_message_set_destination(reply, sender); -+ if (dbret == false) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set reply sender!\n"); -+ ret = EIO; -+ goto done; -+ } -+ -+ dbret = dbus_message_set_reply_serial(reply, serial); -+ if (dbret == false) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set reply serial!\n"); -+ ret = EIO; -+ goto done; -+ } -+ -+ sbus_request_finish(sbus_req, reply); -+ -+ ret = EOK; -+ -+done: -+ if (reply != NULL) { -+ dbus_message_unref(reply); -+ } -+ -+ if (ret != EOK) { -+ /* Something bad happend, just kill the request. */ -+ talloc_free(sbus_req); -+ } -+} -diff --git a/src/responder/ifp/ifp_domains.c b/src/responder/ifp/ifp_domains.c -index 5333b25275e0847015f9cdd294eab5dbdda32f6c..8bfd39feb39822921ea703d8a89ac372e0ad5410 100644 ---- a/src/responder/ifp/ifp_domains.c -+++ b/src/responder/ifp/ifp_domains.c -@@ -538,14 +538,11 @@ void ifp_dom_get_parent_domain(struct sbus_request *dbus_req, - dom->parent->name); - } - --static void ifp_domains_domain_is_online_done(struct tevent_req *req); -- - int ifp_domains_domain_is_online(struct sbus_request *sbus_req, - void *data) - { - struct ifp_ctx *ifp_ctx; - struct sss_domain_info *dom; -- struct tevent_req *req; - DBusError *error; - - ifp_ctx = talloc_get_type(data, struct ifp_ctx); -@@ -558,49 +555,18 @@ int ifp_domains_domain_is_online(struct sbus_request *sbus_req, - return EOK; - } - -- req = rdp_message_send(sbus_req, ifp_ctx->rctx, dom, DP_PATH, -- IFACE_DP_BACKEND, IFACE_DP_BACKEND_ISONLINE, -- DBUS_TYPE_STRING, &dom->name); -- if (req == NULL) { -- return ENOMEM; -- } -- -- tevent_req_set_callback(req, ifp_domains_domain_is_online_done, sbus_req); -+ rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH, -+ IFACE_DP_BACKEND, IFACE_DP_BACKEND_ISONLINE, -+ DBUS_TYPE_STRING, &dom->name); - - return EOK; - } - --static void ifp_domains_domain_is_online_done(struct tevent_req *req) --{ -- struct sbus_request *sbus_req; -- DBusError *error; -- bool is_online; -- errno_t ret; -- -- sbus_req = tevent_req_callback_data(req, struct sbus_request); -- -- ret = rdp_message_recv(req, DBUS_TYPE_BOOLEAN, &is_online); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, "Unable to get online status [%d]: %s\n", -- ret, sss_strerror(ret)); -- error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, -- "Unable to get online status [%d]: %s", -- ret, sss_strerror(ret)); -- sbus_request_fail_and_finish(sbus_req, error); -- return; -- } -- -- iface_ifp_domains_domain_IsOnline_finish(sbus_req, is_online); --} -- --static void ifp_domains_domain_list_services_done(struct tevent_req *req); -- - int ifp_domains_domain_list_services(struct sbus_request *sbus_req, - void *data) - { - struct ifp_ctx *ifp_ctx; - struct sss_domain_info *dom; -- struct tevent_req *req; - DBusError *error; - - ifp_ctx = talloc_get_type(data, struct ifp_ctx); -@@ -613,40 +579,10 @@ int ifp_domains_domain_list_services(struct sbus_request *sbus_req, - return EOK; - } - -- req = rdp_message_send(sbus_req, ifp_ctx->rctx, dom, DP_PATH, -- IFACE_DP_FAILOVER, IFACE_DP_FAILOVER_LISTSERVICES, -- DBUS_TYPE_STRING, &dom->name); -- if (req == NULL) { -- return ENOMEM; -- } -- -- tevent_req_set_callback(req, ifp_domains_domain_list_services_done, sbus_req); -+ rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH, -+ IFACE_DP_FAILOVER, -+ IFACE_DP_FAILOVER_LISTSERVICES, -+ DBUS_TYPE_STRING, &dom->name); - - return EOK; - } -- --static void ifp_domains_domain_list_services_done(struct tevent_req *req) --{ -- struct sbus_request *sbus_req; -- DBusError *error; -- int num_services; -- const char **services; -- errno_t ret; -- -- sbus_req = tevent_req_callback_data(req, struct sbus_request); -- -- ret = rdp_message_recv(req, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, -- &services, &num_services); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, "Unable to get failover services [%d]: %s\n", -- ret, sss_strerror(ret)); -- error = sbus_error_new(sbus_req, DBUS_ERROR_FAILED, -- "Unable to get failover services [%d]: %s", -- ret, sss_strerror(ret)); -- sbus_request_fail_and_finish(sbus_req, error); -- return; -- } -- -- iface_ifp_domains_domain_ListServices_finish(sbus_req, services, -- num_services); --} --- -2.4.11 - diff --git a/SOURCES/0092-pam_test_client-add-SSSD-getpwnam-lookup.patch b/SOURCES/0092-pam_test_client-add-SSSD-getpwnam-lookup.patch new file mode 100644 index 0000000..fc139dc --- /dev/null +++ b/SOURCES/0092-pam_test_client-add-SSSD-getpwnam-lookup.patch @@ -0,0 +1,142 @@ +From 109c99463219be59fbf168a4075a74585193aef9 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 25 Jan 2017 16:50:00 +0100 +Subject: [PATCH 92/96] pam_test_client: add SSSD getpwnam lookup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related to https://pagure.io/SSSD/sssd/issue/3292 + +Reviewed-by: Pavel Březina +(cherry picked from commit 435b3678de25d22eb8a6e892109d26c32f0760a4) +--- + Makefile.am | 10 ++++-- + src/sss_client/pam_test_client.c | 76 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 84 insertions(+), 2 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 4a414f77df999b8b1d81f663fcc18dbd2d6d2dc4..368ebe54b8617cb5bafb079322582d5346b6c4df 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3460,8 +3460,14 @@ if BUILD_WITH_LIBCURL + noinst_PROGRAMS += tcurl-test-tool + endif + +-pam_test_client_SOURCES = src/sss_client/pam_test_client.c +-pam_test_client_LDADD = $(PAM_LIBS) $(PAM_MISC_LIBS) ++pam_test_client_SOURCES = \ ++ src/sss_client/pam_test_client.c \ ++ $(NULL) ++pam_test_client_LDADD = \ ++ $(PAM_LIBS) \ ++ $(PAM_MISC_LIBS) \ ++ $(LIBADD_DL) \ ++ $(NULL) + + if BUILD_AUTOFS + autofs_test_client_SOURCES = \ +diff --git a/src/sss_client/pam_test_client.c b/src/sss_client/pam_test_client.c +index ea032a75b195a9bf8078ed7d248da154ab0c8430..69af612270492968b56d1c11de2bf56ebf57471f 100644 +--- a/src/sss_client/pam_test_client.c ++++ b/src/sss_client/pam_test_client.c +@@ -25,6 +25,11 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include + + #include + +@@ -51,6 +56,70 @@ static struct pam_conv conv = { + #define DEFAULT_ACTION "acct" + #define DEFAULT_SERVICE "system-auth" + ++#define DEFAULT_BUFSIZE 4096 ++ ++static int sss_getpwnam_check(const char *user) ++{ ++ void *dl_handle = NULL; ++ enum nss_status (*sss_getpwnam_r)(const char *name, struct passwd *result, ++ char *buffer, size_t buflen, ++ int *errnop); ++ struct passwd pwd = { 0 }; ++ enum nss_status status; ++ char *buffer = NULL; ++ size_t buflen; ++ int nss_errno; ++ int ret; ++ ++ dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW); ++ if (dl_handle == NULL) { ++ fprintf(stderr, "dlopen failed with [%s].\n", dlerror()); ++ ret = EIO; ++ goto done; ++ } ++ ++ sss_getpwnam_r = dlsym(dl_handle, "_nss_sss_getpwnam_r"); ++ if (sss_getpwnam_r == NULL) { ++ fprintf(stderr, "dlsym failed with [%s].\n", dlerror()); ++ ret = EIO; ++ goto done; ++ } ++ ++ buflen = DEFAULT_BUFSIZE; ++ buffer = malloc(buflen); ++ if (buffer == NULL) { ++ fprintf(stderr, "malloc failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ status = sss_getpwnam_r(user, &pwd, buffer, buflen, &nss_errno); ++ if (status != NSS_STATUS_SUCCESS) { ++ fprintf(stderr, "sss_getpwnam_r failed with [%d].\n", status); ++ ret = EIO; ++ goto done; ++ } ++ ++ fprintf(stdout, "SSSD nss user lookup result:\n"); ++ fprintf(stdout, " - user name: %s\n", pwd.pw_name); ++ fprintf(stdout, " - user id: %d\n", pwd.pw_uid); ++ fprintf(stdout, " - group id: %d\n", pwd.pw_gid); ++ fprintf(stdout, " - gecos: %s\n", pwd.pw_gecos); ++ fprintf(stdout, " - home directory: %s\n", pwd.pw_dir); ++ fprintf(stdout, " - shell: %s\n", pwd.pw_shell); ++ ++ ret = 0; ++ ++done: ++ if (dl_handle != NULL) { ++ dlclose(dl_handle); ++ } ++ ++ free(buffer); ++ ++ return ret; ++} ++ + int main(int argc, char *argv[]) { + + pam_handle_t *pamh; +@@ -85,6 +154,13 @@ int main(int argc, char *argv[]) { + fprintf(stdout, "user: %s\naction: %s\nservice: %s\n", + user, action, service); + ++ if (*user != '\0') { ++ ret = sss_getpwnam_check(user); ++ if (ret != 0) { ++ fprintf(stderr, "User name lookup with [%s] failed.\n", user); ++ } ++ } ++ + ret = pam_start(service, user, &conv, &pamh); + if (ret != PAM_SUCCESS) { + fprintf(stderr, "pam_start failed: %s\n", pam_strerror(pamh, ret)); +-- +2.9.3 + diff --git a/SOURCES/0092-sbus-add-sbus_request_reply_error.patch b/SOURCES/0092-sbus-add-sbus_request_reply_error.patch deleted file mode 100644 index 623cc9c..0000000 --- a/SOURCES/0092-sbus-add-sbus_request_reply_error.patch +++ /dev/null @@ -1,218 +0,0 @@ -From 9b0cda6876a5407b152bdeb51bb312aa52916172 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Tue, 28 Jun 2016 15:29:39 +0200 -Subject: [PATCH 092/102] sbus: add sbus_request_reply_error() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This simplifies error handling in sbus requests since we avoid -creating DBusError and checking for NULL manually. It removes -few lines of code. - -This patch does not replace all calls to sbus_request_fail_and_finish -since sometimes it is desirable to create the error manualy. But -it replaces it in most recent places. - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Jakub Hrozek -(cherry picked from commit a06e23c0bcf0c8669a29b801876aca8aac422931) ---- - src/providers/data_provider/dp_iface_backend.c | 11 ++-- - src/responder/ifp/ifp_domains.c | 12 ++--- - src/sbus/sssd_dbus.h | 9 +++- - src/sbus/sssd_dbus_request.c | 73 ++++++++++++++++++++------ - 4 files changed, 70 insertions(+), 35 deletions(-) - -diff --git a/src/providers/data_provider/dp_iface_backend.c b/src/providers/data_provider/dp_iface_backend.c -index f4af35ed6ec3858b7fff80cf2933926a653ba6f5..d9a84bfee4c5c11e46e0e8f7021f829825ad95c1 100644 ---- a/src/providers/data_provider/dp_iface_backend.c -+++ b/src/providers/data_provider/dp_iface_backend.c -@@ -34,7 +34,6 @@ errno_t dp_backend_is_online(struct sbus_request *sbus_req, - { - struct be_ctx *be_ctx; - struct sss_domain_info *domain; -- DBusError *error; - bool online; - - be_ctx = dp_client_be(dp_cli); -@@ -44,13 +43,9 @@ errno_t dp_backend_is_online(struct sbus_request *sbus_req, - } else { - domain = find_domain_by_name(be_ctx->domain, domname, false); - if (domain == NULL) { -- error = sbus_error_new(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN, -- "Unknown domain %s", domname); -- if (error == NULL) { -- return ENOMEM; -- } -- -- return sbus_request_fail_and_finish(sbus_req, error); -+ sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN, -+ "Unknown domain %s", domname); -+ return EOK; - } - } - -diff --git a/src/responder/ifp/ifp_domains.c b/src/responder/ifp/ifp_domains.c -index 8bfd39feb39822921ea703d8a89ac372e0ad5410..ff690ed6a7d5519979d242a4d5dadd08aff50347 100644 ---- a/src/responder/ifp/ifp_domains.c -+++ b/src/responder/ifp/ifp_domains.c -@@ -543,15 +543,13 @@ int ifp_domains_domain_is_online(struct sbus_request *sbus_req, - { - struct ifp_ctx *ifp_ctx; - struct sss_domain_info *dom; -- DBusError *error; - - ifp_ctx = talloc_get_type(data, struct ifp_ctx); - - dom = get_domain_info_from_req(sbus_req, data); - if (dom == NULL) { -- error = sbus_error_new(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN, -- "Unknown domain"); -- sbus_request_fail_and_finish(sbus_req, error); -+ sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN, -+ "Unknown domain"); - return EOK; - } - -@@ -567,15 +565,13 @@ int ifp_domains_domain_list_services(struct sbus_request *sbus_req, - { - struct ifp_ctx *ifp_ctx; - struct sss_domain_info *dom; -- DBusError *error; - - ifp_ctx = talloc_get_type(data, struct ifp_ctx); - - dom = get_domain_info_from_req(sbus_req, data); - if (dom == NULL) { -- error = sbus_error_new(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN, -- "Unknown domain"); -- sbus_request_fail_and_finish(sbus_req, error); -+ sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN, -+ "Unknown domain"); - return EOK; - } - -diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h -index fe1c4a7e1730e088647744d9b49a68c3c71db57f..c0aedf36b496bfda05dcde921ea7060efb4cc91f 100644 ---- a/src/sbus/sssd_dbus.h -+++ b/src/sbus/sssd_dbus.h -@@ -357,6 +357,11 @@ int sbus_request_return_and_finish(struct sbus_request *dbus_req, - int sbus_request_fail_and_finish(struct sbus_request *dbus_req, - const DBusError *error); - -+void sbus_request_reply_error(struct sbus_request *sbus_req, -+ const char *error_name, -+ const char *fmt, -+ ...) SSS_ATTRIBUTE_PRINTF(3, 4); -+ - /* - * Construct a new DBusError instance which can be consumed by functions such - * as @sbus_request_fail_and_finish(). -@@ -368,9 +373,9 @@ int sbus_request_fail_and_finish(struct sbus_request *dbus_req, - * is duplicated using the returned DBusError instance as a talloc parent. - */ - DBusError *sbus_error_new(TALLOC_CTX *mem_ctx, -- const char *dbus_err_name, -+ const char *dbus_error_name, - const char *fmt, -- ...) SSS_ATTRIBUTE_PRINTF(3,4); -+ ...) SSS_ATTRIBUTE_PRINTF(3, 4); - - /* - * Parse a DBus method call request. -diff --git a/src/sbus/sssd_dbus_request.c b/src/sbus/sssd_dbus_request.c -index f8647b5ecfb4a49d45a15733b22c6014f4bd084c..c5b08539ff85b5427e41f6e03991b40a0a43a7e3 100644 ---- a/src/sbus/sssd_dbus_request.c -+++ b/src/sbus/sssd_dbus_request.c -@@ -199,31 +199,70 @@ int sbus_request_fail_and_finish(struct sbus_request *dbus_req, - return ret; - } - -+static DBusError *sbus_error_new_va(TALLOC_CTX *mem_ctx, -+ const char *error_name, -+ const char *fmt, -+ va_list ap) -+{ -+ DBusError *error; -+ const char *error_msg; -+ -+ error = talloc_zero(mem_ctx, DBusError); -+ if (error == NULL) { -+ return NULL; -+ } -+ -+ if (fmt != NULL) { -+ error_msg = talloc_vasprintf(error, fmt, ap); -+ if (error_msg == NULL) { -+ talloc_free(error); -+ return NULL; -+ } -+ } else { -+ error_msg = NULL; -+ } -+ -+ dbus_error_init(error); -+ dbus_set_error_const(error, error_name, error_msg); -+ -+ return error; -+} -+ - DBusError *sbus_error_new(TALLOC_CTX *mem_ctx, -- const char *dbus_err_name, -+ const char *dbus_error_name, - const char *fmt, - ...) - { -- DBusError *dberr; -- const char *err_msg_dup = NULL; -+ DBusError *error; - va_list ap; - -- dberr = talloc(mem_ctx, DBusError); -- if (dberr == NULL) return NULL; -- -- if (fmt) { -- va_start(ap, fmt); -- err_msg_dup = talloc_vasprintf(dberr, fmt, ap); -- va_end(ap); -- if (err_msg_dup == NULL) { -- talloc_free(dberr); -- return NULL; -- } -+ va_start(ap, fmt); -+ error = sbus_error_new_va(mem_ctx, dbus_error_name, fmt, ap); -+ va_end(ap); -+ -+ return error; -+} -+ -+void sbus_request_reply_error(struct sbus_request *sbus_req, -+ const char *error_name, -+ const char *fmt, -+ ...) -+{ -+ DBusError *error; -+ va_list ap; -+ -+ va_start(ap, fmt); -+ error = sbus_error_new_va(sbus_req, error_name, fmt, ap); -+ va_end(ap); -+ -+ if (error == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Unable to create D-Bus error, killing request!\n"); -+ talloc_free(sbus_req); -+ return; - } - -- dbus_error_init(dberr); -- dbus_set_error_const(dberr, dbus_err_name, err_msg_dup); -- return dberr; -+ sbus_request_fail_and_finish(sbus_req, error); - } - - struct array_arg { --- -2.4.11 - diff --git a/SOURCES/0093-sbus-add-utility-function-to-simplify-message-and-re.patch b/SOURCES/0093-sbus-add-utility-function-to-simplify-message-and-re.patch deleted file mode 100644 index 561fd47..0000000 --- a/SOURCES/0093-sbus-add-utility-function-to-simplify-message-and-re.patch +++ /dev/null @@ -1,624 +0,0 @@ -From 420e47f6a0e173e774faa426d172c6e2160b8302 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Wed, 29 Jun 2016 12:35:59 +0200 -Subject: [PATCH 093/102] sbus: add utility function to simplify message and - reply handling -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This patch adds the ability to hook DBusMessage to a talloc context -to remove the need of calling dbus_message_unref(). It also provides -an automatical way to detect error in a reply so the caller does -not need to parse it manually and the whole code around DBusError -can be avoided. - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Jakub Hrozek -(cherry picked from commit 439e08cdc5c83b3e5835cb0435983f1da2ffbaf1) ---- - Makefile.am | 2 + - src/responder/common/data_provider/rdp_message.c | 85 ++------- - src/sbus/sssd_dbus.h | 2 + - src/sbus/sssd_dbus_utils.c | 226 +++++++++++++++++++++++ - src/sbus/sssd_dbus_utils.h | 64 +++++++ - src/tools/sssctl/sssctl_domains.c | 32 +--- - 6 files changed, 313 insertions(+), 98 deletions(-) - create mode 100644 src/sbus/sssd_dbus_utils.c - create mode 100644 src/sbus/sssd_dbus_utils.h - -diff --git a/Makefile.am b/Makefile.am -index ee9b48c666a44781b582ba5d83102b705e898f29..1837e36da7302cb51c0b90e51b762ce0a87cd65f 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -634,6 +634,7 @@ dist_noinst_HEADERS = \ - src/sbus/sssd_dbus_private.h \ - src/sbus/sssd_dbus_invokers.h \ - src/sbus/sssd_dbus_errors.h \ -+ src/sbus/sssd_dbus_utils.h \ - src/db/sysdb.h \ - src/db/sysdb_sudo.h \ - src/db/sysdb_autofs.h \ -@@ -915,6 +916,7 @@ libsss_util_la_SOURCES = \ - src/sbus/sssd_dbus_server.c \ - src/sbus/sssd_dbus_signals.c \ - src/sbus/sssd_dbus_common_signals.c \ -+ src/sbus/sssd_dbus_utils.c \ - src/util/util.c \ - src/util/memory.c \ - src/util/safe-format-string.c \ -diff --git a/src/responder/common/data_provider/rdp_message.c b/src/responder/common/data_provider/rdp_message.c -index e226401567e4a1b2b9784a9aba21540ff5f0bc8d..6ad2ba056e992cd89b87b478d422d1a4259a12d9 100644 ---- a/src/responder/common/data_provider/rdp_message.c -+++ b/src/responder/common/data_provider/rdp_message.c -@@ -26,33 +26,6 @@ - #include "sbus/sssd_dbus_errors.h" - #include "util/util.h" - --static errno_t rdp_error_to_errno(DBusError *error) --{ -- static struct { -- const char *name; -- errno_t ret; -- } list[] = {{SBUS_ERROR_INTERNAL, ERR_INTERNAL}, -- {SBUS_ERROR_NOT_FOUND, ENOENT}, -- {SBUS_ERROR_DP_FATAL, ERR_TERMINATED}, -- {SBUS_ERROR_DP_OFFLINE, ERR_OFFLINE}, -- {SBUS_ERROR_DP_NOTSUP, ENOTSUP}, -- {NULL, ERR_INTERNAL} -- }; -- int i; -- -- if (!dbus_error_is_set(error)) { -- return EOK; -- } -- -- for (i = 0; list[i].name != NULL; i ++) { -- if (dbus_error_has_name(error, list[i].name)) { -- return list[i].ret; -- } -- } -- -- return EIO; --} -- - static errno_t - rdp_message_send_internal(struct resp_ctx *rctx, - struct sss_domain_info *domain, -@@ -110,7 +83,8 @@ done: - return ret; - } - --static errno_t rdp_process_pending_call(DBusPendingCall *pending, -+static errno_t rdp_process_pending_call(TALLOC_CTX *mem_ctx, -+ DBusPendingCall *pending, - DBusMessage **_reply) - { - DBusMessage *reply; -@@ -130,6 +104,11 @@ static errno_t rdp_process_pending_call(DBusPendingCall *pending, - goto done; - } - -+ ret = sbus_talloc_bound_message(mem_ctx, reply); -+ if (ret != EOK) { -+ return ret; -+ } -+ - switch (dbus_message_get_type(reply)) { - case DBUS_MESSAGE_TYPE_METHOD_RETURN: - DEBUG(SSSDBG_TRACE_FUNC, "DP Success\n"); -@@ -146,10 +125,9 @@ static errno_t rdp_process_pending_call(DBusPendingCall *pending, - - DEBUG(SSSDBG_CRIT_FAILURE, "DP Error [%s]: %s\n", - error.name, (error.message == NULL ? "(null)" : error.message)); -- ret = rdp_error_to_errno(&error); -+ ret = sbus_error_to_errno(&error); - break; - default: -- dbus_message_unref(reply); - DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected type?\n"); - ret = ERR_INTERNAL; - goto done; -@@ -168,15 +146,6 @@ struct rdp_message_state { - struct DBusMessage *reply; - }; - --static int rdp_message_state_destructor(struct rdp_message_state *state) --{ -- if (state->reply != NULL) { -- dbus_message_unref(state->reply); -- } -- -- return 0; --} -- - static void rdp_message_done(DBusPendingCall *pending, void *ptr); - - struct tevent_req *_rdp_message_send(TALLOC_CTX *mem_ctx, -@@ -199,8 +168,6 @@ struct tevent_req *_rdp_message_send(TALLOC_CTX *mem_ctx, - return NULL; - } - -- talloc_set_destructor(state, rdp_message_state_destructor); -- - va_start(va, first_arg_type); - ret = rdp_message_send_internal(rctx, domain, rdp_message_done, req, - path, iface, method, first_arg_type, va); -@@ -233,14 +200,8 @@ static void rdp_message_done(DBusPendingCall *pending, void *ptr) - req = talloc_get_type(ptr, struct tevent_req); - state = tevent_req_data(req, struct rdp_message_state); - -- ret = rdp_process_pending_call(pending, &state->reply); -+ ret = rdp_process_pending_call(state, pending, &state->reply); - if (ret != EOK) { -- if (state->reply != NULL) { -- dbus_message_unref(state->reply); -- } -- -- state->reply = NULL; -- - tevent_req_error(req, ret); - return; - } -@@ -253,35 +214,17 @@ errno_t _rdp_message_recv(struct tevent_req *req, - ...) - { - struct rdp_message_state *state; -- DBusError error; -- dbus_bool_t bret; - errno_t ret; - va_list va; - - TEVENT_REQ_RETURN_ON_ERROR(req); - - state = tevent_req_data(req, struct rdp_message_state); -- dbus_error_init(&error); - - va_start(va, first_arg_type); -- bret = dbus_message_get_args_valist(state->reply, &error, first_arg_type, va); -+ ret = sbus_parse_message_valist(state->reply, false, first_arg_type, va); - va_end(va); - -- if (bret == false) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse reply\n"); -- ret = EIO; -- goto done; -- } -- -- ret = rdp_error_to_errno(&error); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse message [%s]: %s\n", -- error.name, error.message); -- goto done; -- } -- --done: -- dbus_error_free(&error); - return ret; - } - -@@ -317,7 +260,7 @@ static void rdp_message_send_and_reply_done(DBusPendingCall *pending, - void *ptr) - { - struct sbus_request *sbus_req; -- DBusMessage *reply = NULL; -+ DBusMessage *reply; - dbus_uint32_t serial; - const char *sender; - dbus_bool_t dbret; -@@ -325,7 +268,7 @@ static void rdp_message_send_and_reply_done(DBusPendingCall *pending, - - sbus_req = talloc_get_type(ptr, struct sbus_request); - -- ret = rdp_process_pending_call(pending, &reply); -+ ret = rdp_process_pending_call(sbus_req, pending, &reply); - if (reply == NULL) { - /* Something bad happened. Just kill the request. */ - ret = EIO; -@@ -358,10 +301,6 @@ static void rdp_message_send_and_reply_done(DBusPendingCall *pending, - ret = EOK; - - done: -- if (reply != NULL) { -- dbus_message_unref(reply); -- } -- - if (ret != EOK) { - /* Something bad happend, just kill the request. */ - talloc_free(sbus_req); -diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h -index c0aedf36b496bfda05dcde921ea7060efb4cc91f..15e3b117e1a467f4e250cdf4ba8fd0326e4d380e 100644 ---- a/src/sbus/sssd_dbus.h -+++ b/src/sbus/sssd_dbus.h -@@ -29,6 +29,8 @@ struct sbus_request; - #include - #include - #include "util/util.h" -+#include "sbus/sssd_dbus_errors.h" -+#include "sbus/sssd_dbus_utils.h" - - /* Older platforms (such as RHEL-6) might not have these error constants - * defined */ -diff --git a/src/sbus/sssd_dbus_utils.c b/src/sbus/sssd_dbus_utils.c -new file mode 100644 -index 0000000000000000000000000000000000000000..4c33f9fd75cac2d4a56a5638982f8ecb73da8e2e ---- /dev/null -+++ b/src/sbus/sssd_dbus_utils.c -@@ -0,0 +1,226 @@ -+/* -+ Authors: -+ Pavel Březina -+ -+ Copyright (C) 2016 Red Hat -+ -+ 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 . -+*/ -+ -+#include -+ -+#include "sbus/sssd_dbus.h" -+#include "util/util.h" -+ -+struct sbus_talloc_msg { -+ DBusMessage *msg; -+}; -+ -+static int sbus_talloc_msg_destructor(struct sbus_talloc_msg *talloc_msg) -+{ -+ if (talloc_msg->msg == NULL) { -+ return 0; -+ } -+ -+ dbus_message_unref(talloc_msg->msg); -+ return 0; -+} -+ -+errno_t sbus_talloc_bound_message(TALLOC_CTX *mem_ctx, DBusMessage *msg) -+{ -+ struct sbus_talloc_msg *talloc_msg; -+ -+ talloc_msg = talloc(mem_ctx, struct sbus_talloc_msg); -+ if (talloc_msg == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Unable to bound D-Bus message with talloc context!\n"); -+ return ENOMEM; -+ } -+ -+ talloc_msg->msg = msg; -+ -+ talloc_set_destructor(talloc_msg, sbus_talloc_msg_destructor); -+ -+ return EOK; -+} -+ -+errno_t sbus_error_to_errno(DBusError *error) -+{ -+ static struct { -+ const char *name; -+ errno_t ret; -+ } list[] = { { SBUS_ERROR_INTERNAL, ERR_INTERNAL }, -+ { SBUS_ERROR_NOT_FOUND, ENOENT }, -+ { SBUS_ERROR_UNKNOWN_DOMAIN, ERR_DOMAIN_NOT_FOUND }, -+ { SBUS_ERROR_DP_FATAL, ERR_TERMINATED }, -+ { SBUS_ERROR_DP_OFFLINE, ERR_OFFLINE }, -+ { SBUS_ERROR_DP_NOTSUP, ENOTSUP }, -+ { NULL, ERR_INTERNAL } }; -+ int i; -+ -+ if (!dbus_error_is_set(error)) { -+ return EOK; -+ } -+ -+ for (i = 0; list[i].name != NULL; i++) { -+ if (dbus_error_has_name(error, list[i].name)) { -+ return list[i].ret; -+ } -+ } -+ -+ return EIO; -+} -+ -+errno_t sbus_check_reply(DBusMessage *reply) -+{ -+ dbus_bool_t bret; -+ DBusError error; -+ errno_t ret; -+ -+ dbus_error_init(&error); -+ -+ switch (dbus_message_get_type(reply)) { -+ case DBUS_MESSAGE_TYPE_METHOD_RETURN: -+ ret = EOK; -+ goto done; -+ -+ case DBUS_MESSAGE_TYPE_ERROR: -+ bret = dbus_set_error_from_message(&error, reply); -+ if (bret == false) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read error from message\n"); -+ ret = EIO; -+ goto done; -+ } -+ -+ DEBUG(SSSDBG_CRIT_FAILURE, "D-Bus error [%s]: %s\n", -+ error.name, (error.message == NULL ? "(null)" : error.message)); -+ ret = sbus_error_to_errno(&error); -+ goto done; -+ default: -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected D-Bus message type?\n"); -+ ret = ERR_INTERNAL; -+ goto done; -+ } -+ -+done: -+ dbus_error_free(&error); -+ -+ return ret; -+} -+ -+DBusMessage *sbus_create_message_valist(TALLOC_CTX *mem_ctx, -+ const char *bus, -+ const char *path, -+ const char *iface, -+ const char *method, -+ int first_arg_type, -+ va_list va) -+{ -+ DBusMessage *msg; -+ dbus_bool_t bret; -+ errno_t ret; -+ -+ msg = dbus_message_new_method_call(bus, path, iface, method); -+ if (msg == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create message\n"); -+ return NULL; -+ } -+ -+ bret = dbus_message_append_args_valist(msg, first_arg_type, va); -+ if (!bret) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n"); -+ ret = EIO; -+ goto done; -+ } -+ -+ ret = sbus_talloc_bound_message(mem_ctx, msg); -+ -+done: -+ if (ret != EOK) { -+ dbus_message_unref(msg); -+ } -+ -+ return msg; -+} -+ -+DBusMessage *_sbus_create_message(TALLOC_CTX *mem_ctx, -+ const char *bus, -+ const char *path, -+ const char *iface, -+ const char *method, -+ int first_arg_type, -+ ...) -+{ -+ DBusMessage *msg; -+ va_list va; -+ -+ va_start(va, first_arg_type); -+ msg = sbus_create_message_valist(mem_ctx, bus, path, iface, method, -+ first_arg_type, va); -+ va_end(va); -+ -+ return msg; -+} -+ -+errno_t sbus_parse_message_valist(DBusMessage *msg, -+ bool check_reply, -+ int first_arg_type, -+ va_list va) -+{ -+ DBusError error; -+ dbus_bool_t bret; -+ errno_t ret; -+ -+ if (check_reply) { -+ ret = sbus_check_reply(msg); -+ if (ret != EOK) { -+ return ret; -+ } -+ } -+ -+ dbus_error_init(&error); -+ -+ bret = dbus_message_get_args_valist(msg, &error, first_arg_type, va); -+ if (bret == false) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse D-Bus message\n"); -+ ret = EIO; -+ goto done; -+ } -+ -+ ret = sbus_error_to_errno(&error); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse D-Bus message [%s]: %s\n", -+ error.name, error.message); -+ goto done; -+ } -+ -+done: -+ dbus_error_free(&error); -+ return ret; -+} -+ -+errno_t _sbus_parse_message(DBusMessage *msg, -+ bool check_reply, -+ int first_arg_type, -+ ...) -+{ -+ errno_t ret; -+ va_list va; -+ -+ va_start(va, first_arg_type); -+ ret = sbus_parse_message_valist(msg, check_reply, first_arg_type, va); -+ va_end(va); -+ -+ return ret; -+} -diff --git a/src/sbus/sssd_dbus_utils.h b/src/sbus/sssd_dbus_utils.h -new file mode 100644 -index 0000000000000000000000000000000000000000..74c21fb7930c7f5f5417b6a2587cf691b1bc0b19 ---- /dev/null -+++ b/src/sbus/sssd_dbus_utils.h -@@ -0,0 +1,64 @@ -+/* -+ Authors: -+ Pavel Březina -+ -+ Copyright (C) 2016 Red Hat -+ -+ 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 . -+*/ -+ -+#ifndef SSSD_DBUS_UTILS_H_ -+#define SSSD_DBUS_UTILS_H_ -+ -+errno_t sbus_talloc_bound_message(TALLOC_CTX *mem_ctx, DBusMessage *msg); -+errno_t sbus_error_to_errno(DBusError *error); -+errno_t sbus_check_reply(DBusMessage *reply); -+ -+DBusMessage *sbus_create_message_valist(TALLOC_CTX *mem_ctx, -+ const char *bus, -+ const char *path, -+ const char *iface, -+ const char *method, -+ int first_arg_type, -+ va_list va); -+ -+DBusMessage *_sbus_create_message(TALLOC_CTX *mem_ctx, -+ const char *bus, -+ const char *path, -+ const char *iface, -+ const char *method, -+ int first_arg_type, -+ ...); -+ -+#define sbus_create_message(mem_ctx, bus, path, iface, method, ...) \ -+ _sbus_create_message(mem_ctx, bus, path, iface, method, \ -+ ##__VA_ARGS__, DBUS_TYPE_INVALID) -+ -+errno_t sbus_parse_message_valist(DBusMessage *msg, -+ bool check_reply, -+ int first_arg_type, -+ va_list va); -+ -+errno_t _sbus_parse_message(DBusMessage *msg, -+ bool check_reply, -+ int first_arg_type, -+ ...); -+ -+#define sbus_parse_message(msg, ...) \ -+ _sbus_parse_message(msg, false, ##__VA_ARGS__, DBUS_TYPE_INVALID) -+ -+#define sbus_parse_reply(msg, ...) \ -+ _sbus_parse_message(msg, true, ##__VA_ARGS__, DBUS_TYPE_INVALID) -+ -+#endif /* SSSD_DBUS_UTILS_H_ */ -diff --git a/src/tools/sssctl/sssctl_domains.c b/src/tools/sssctl/sssctl_domains.c -index cfc4e56133213e27496350033d4d28c3f5b5c63d..17ad670f39dfc045ba090210ffcfa77df713c306 100644 ---- a/src/tools/sssctl/sssctl_domains.c -+++ b/src/tools/sssctl/sssctl_domains.c -@@ -79,15 +79,11 @@ static errno_t sssctl_domain_status_online(struct sss_tool_ctx *tool_ctx, - { - sss_sifp_ctx *sifp; - sss_sifp_error sifp_error; -- DBusError dbus_error; - DBusMessage *reply = NULL; -- DBusMessage *msg = NULL; -+ DBusMessage *msg; - bool is_online; -- dbus_bool_t dbret; - errno_t ret; - -- dbus_error_init(&dbus_error); -- - if (!sssctl_start_sssd(force_start)) { - ret = ERR_SSSD_NOT_RUNNING; - goto done; -@@ -100,16 +96,15 @@ static errno_t sssctl_domain_status_online(struct sss_tool_ctx *tool_ctx, - goto done; - } - -- -- msg = sss_sifp_create_message(domain_path, IFACE_IFP_DOMAINS_DOMAIN, -- IFACE_IFP_DOMAINS_DOMAIN_ISONLINE); -+ msg = sbus_create_message(tool_ctx, SSS_SIFP_ADDRESS, domain_path, -+ IFACE_IFP_DOMAINS_DOMAIN, -+ IFACE_IFP_DOMAINS_DOMAIN_ISONLINE); - if (msg == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create D-Bus message\n"); - ret = ENOMEM; - goto done; - } - -- - sifp_error = sss_sifp_send_message(sifp, msg, &reply); - if (sifp_error != SSS_SIFP_OK) { - sssctl_sifp_error(sifp, sifp_error, "Unable to get online status"); -@@ -117,16 +112,9 @@ static errno_t sssctl_domain_status_online(struct sss_tool_ctx *tool_ctx, - goto done; - } - -- dbret = dbus_message_get_args(reply, &dbus_error, -- DBUS_TYPE_BOOLEAN, &is_online, -- DBUS_TYPE_INVALID); -- if (!dbret) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse D-Bus reply\n"); -- if (dbus_error_is_set(&dbus_error)) { -- DEBUG(SSSDBG_CRIT_FAILURE, "%s: %s\n", -- dbus_error.name, dbus_error.message); -- } -- ret = EIO; -+ ret = sbus_parse_reply(reply, DBUS_TYPE_BOOLEAN, &is_online); -+ if (ret != EOK) { -+ fprintf(stderr, _("Unable to get information from SSSD\n")); - goto done; - } - -@@ -135,16 +123,10 @@ static errno_t sssctl_domain_status_online(struct sss_tool_ctx *tool_ctx, - ret = EOK; - - done: -- if (msg != NULL) { -- dbus_message_unref(msg); -- } -- - if (reply != NULL) { - dbus_message_unref(reply); - } - -- dbus_error_free(&dbus_error); -- - return ret; - } - --- -2.4.11 - diff --git a/SOURCES/0093-sss_sifp-update-method-names.patch b/SOURCES/0093-sss_sifp-update-method-names.patch new file mode 100644 index 0000000..0dac7de --- /dev/null +++ b/SOURCES/0093-sss_sifp-update-method-names.patch @@ -0,0 +1,54 @@ +From 52622fbb51d972ba1f02ff0c7dff2e9fa7adf96c Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 16 Mar 2017 11:37:41 +0100 +Subject: [PATCH 93/96] sss_sifp: update method names +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related to https://pagure.io/SSSD/sssd/issue/3292 + +Reviewed-by: Pavel Březina +(cherry picked from commit 40ff10d73063949ca699670ca212e96b809d5fcd) +--- + Makefile.am | 2 +- + src/lib/sifp/sss_sifp_common.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 368ebe54b8617cb5bafb079322582d5346b6c4df..b16a71cc9e07f21d02b4ceb3f41a8e9de0591ec9 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1221,7 +1221,7 @@ libsss_simpleifp_la_LIBADD = \ + $(DHASH_LIBS) + libsss_simpleifp_la_LDFLAGS = \ + -Wl,--version-script,$(srcdir)/src/lib/sifp/sss_simpleifp.exports \ +- -version-info 1:0:1 ++ -version-info 1:1:1 + + dist_noinst_DATA += src/lib/sifp/sss_simpleifp.exports + +diff --git a/src/lib/sifp/sss_sifp_common.c b/src/lib/sifp/sss_sifp_common.c +index bd1dc6a3108329d2c795dc0a259637e71964be9f..8913d0be3d43bd8707829001a5b476d9ab864fd8 100644 +--- a/src/lib/sifp/sss_sifp_common.c ++++ b/src/lib/sifp/sss_sifp_common.c +@@ -168,7 +168,7 @@ sss_sifp_fetch_user_by_uid(sss_sifp_ctx *ctx, + uint64_t _uid = uid; + + return sss_sifp_fetch_object_by_attr(ctx, IFP_PATH_USERS, IFACE_IFP_USERS, +- IFACE_IFP_USERS_USER, "UserByID", ++ IFACE_IFP_USERS_USER, "ByID", + DBUS_TYPE_UINT64, &_uid, _user); + } + +@@ -178,6 +178,6 @@ sss_sifp_fetch_user_by_name(sss_sifp_ctx *ctx, + sss_sifp_object **_user) + { + return sss_sifp_fetch_object_by_name(ctx, IFP_PATH_USERS, IFACE_IFP_USERS, +- IFACE_IFP_USERS_USER, "UserByName", ++ IFACE_IFP_USERS_USER, "ByName", + name, _user); + } +-- +2.9.3 + diff --git a/SOURCES/0094-pam_test_client-add-InfoPipe-user-lookup.patch b/SOURCES/0094-pam_test_client-add-InfoPipe-user-lookup.patch new file mode 100644 index 0000000..6d20370 --- /dev/null +++ b/SOURCES/0094-pam_test_client-add-InfoPipe-user-lookup.patch @@ -0,0 +1,131 @@ +From acefbdd65a083b5d9577d9f683ac64e358c2f9c0 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 16 Mar 2017 11:38:20 +0100 +Subject: [PATCH 94/96] pam_test_client: add InfoPipe user lookup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related to https://pagure.io/SSSD/sssd/issue/3292 + +Reviewed-by: Pavel Březina +(cherry picked from commit 9be97c9cc69e5e6e568d7e21f61a46c3ae2dc387) +--- + Makefile.am | 1 + + src/sss_client/pam_test_client.c | 71 ++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 72 insertions(+) + +diff --git a/Makefile.am b/Makefile.am +index b16a71cc9e07f21d02b4ceb3f41a8e9de0591ec9..c4d252357356c2d5452a414fd360fc5370b2c775 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3467,6 +3467,7 @@ pam_test_client_LDADD = \ + $(PAM_LIBS) \ + $(PAM_MISC_LIBS) \ + $(LIBADD_DL) \ ++ libsss_simpleifp.la \ + $(NULL) + + if BUILD_AUTOFS +diff --git a/src/sss_client/pam_test_client.c b/src/sss_client/pam_test_client.c +index 69af612270492968b56d1c11de2bf56ebf57471f..40ef3f6d480c0108c985fce7e34e983d145f237e 100644 +--- a/src/sss_client/pam_test_client.c ++++ b/src/sss_client/pam_test_client.c +@@ -30,9 +30,12 @@ + #include + #include + #include ++#include + + #include + ++#include "lib/sifp/sss_sifp.h" ++ + #ifdef HAVE_SECURITY_PAM_MISC_H + # include + #elif defined(HAVE_SECURITY_OPENPAM_H) +@@ -58,6 +61,69 @@ static struct pam_conv conv = { + + #define DEFAULT_BUFSIZE 4096 + ++static int get_ifp_user(const char *user) ++{ ++ sss_sifp_ctx *sifp; ++ sss_sifp_error error; ++ sss_sifp_object *user_obj; ++ const char *tmp_str; ++ uint32_t tmp_uint32; ++ size_t c; ++ ++ struct ifp_user_attr { ++ const char *name; ++ bool is_string; ++ } ifp_user_attr[] = { ++ { "name", true }, ++ { "uidNumber", false }, ++ { "gidNumber", false }, ++ { "gecos", true }, ++ { "homeDirectory", true }, ++ { "loginShell", true }, ++ { NULL, false } ++ }; ++ ++ error = sss_sifp_init(&sifp); ++ if (error != SSS_SIFP_OK) { ++ fprintf(stderr, "Unable to connect to the InfoPipe"); ++ return EFAULT; ++ } ++ ++ error = sss_sifp_fetch_user_by_name(sifp, user, &user_obj); ++ if (error != SSS_SIFP_OK) { ++ fprintf(stderr, "Unable to get user object"); ++ return EIO; ++ } ++ ++ fprintf(stdout, "SSSD InfoPipe user lookup result:\n"); ++ for (c = 0; ifp_user_attr[c].name != NULL; c++) { ++ if (ifp_user_attr[c].is_string) { ++ error = sss_sifp_find_attr_as_string(user_obj->attrs, ++ ifp_user_attr[c].name, ++ &tmp_str); ++ } else { ++ error = sss_sifp_find_attr_as_uint32(user_obj->attrs, ++ ifp_user_attr[c].name, ++ &tmp_uint32); ++ } ++ if (error != SSS_SIFP_OK) { ++ fprintf(stderr, "Unable to get user name attr"); ++ return EIO; ++ } ++ ++ if (ifp_user_attr[c].is_string) { ++ fprintf(stdout, " - %s: %s\n", ifp_user_attr[c].name, tmp_str); ++ } else { ++ fprintf(stdout, " - %s: %"PRIu32"\n", ifp_user_attr[c].name, ++ tmp_uint32); ++ } ++ } ++ ++ sss_sifp_free_object(sifp, &user_obj); ++ sss_sifp_free(&sifp); ++ return 0; ++} ++ + static int sss_getpwnam_check(const char *user) + { + void *dl_handle = NULL; +@@ -159,6 +225,11 @@ int main(int argc, char *argv[]) { + if (ret != 0) { + fprintf(stderr, "User name lookup with [%s] failed.\n", user); + } ++ ++ ret = get_ifp_user(user); ++ if (ret != 0) { ++ fprintf(stderr, "InforPipe User lookup with [%s] failed.\n", user); ++ } + } + + ret = pam_start(service, user, &conv, &pamh); +-- +2.9.3 + diff --git a/SOURCES/0094-sssctl-use-talloc-with-sifp.patch b/SOURCES/0094-sssctl-use-talloc-with-sifp.patch deleted file mode 100644 index 4417086..0000000 --- a/SOURCES/0094-sssctl-use-talloc-with-sifp.patch +++ /dev/null @@ -1,215 +0,0 @@ -From bb8653ba6ba4eddb7faeddd9ceb3349107f77fd9 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Wed, 29 Jun 2016 14:03:38 +0200 -Subject: [PATCH 094/102] sssctl: use talloc with sifp -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This way we completely move D-Bus memory management to talloc and -we reduce number of code lines needed to send and receive reply. - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Jakub Hrozek -(cherry picked from commit 9b74009c1260e6f3b1031a6ae110bf1d957cba81) ---- - src/tools/sssctl/sssctl.h | 14 +++++++++ - src/tools/sssctl/sssctl_domains.c | 62 ++++++++++++++++++--------------------- - src/tools/sssctl/sssctl_sifp.c | 46 +++++++++++++++++++++++++++++ - 3 files changed, 88 insertions(+), 34 deletions(-) - -diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h -index 72930ee5c3a1195e90c6e35768f715cbf6a1c4e1..d4e3359b0b160d12a0c2699f754989a24b2b336a 100644 ---- a/src/tools/sssctl/sssctl.h -+++ b/src/tools/sssctl/sssctl.h -@@ -24,6 +24,7 @@ - #include "lib/sifp/sss_sifp.h" - #include "lib/sifp/sss_sifp_dbus.h" - #include "tools/common/sss_tools.h" -+#include "sbus/sssd_dbus.h" - - enum sssctl_prompt_result { - SSSCTL_PROMPT_YES, -@@ -56,6 +57,19 @@ void _sssctl_sifp_error(sss_sifp_ctx *sifp, - #define sssctl_sifp_error(sifp, error, message) \ - _sssctl_sifp_error(sifp, error, _(message)) - -+sss_sifp_error _sssctl_sifp_send(TALLOC_CTX *mem_ctx, -+ sss_sifp_ctx *sifp, -+ DBusMessage **_reply, -+ const char *path, -+ const char *iface, -+ const char *method, -+ int first_arg_type, -+ ...); -+ -+#define sssctl_sifp_send(mem_ctx, sifp, reply, path, iface, method, ...) \ -+ _sssctl_sifp_send(mem_ctx, sifp, reply, path, iface, method, \ -+ ##__VA_ARGS__, DBUS_TYPE_INVALID); -+ - errno_t sssctl_domain_list(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt); -diff --git a/src/tools/sssctl/sssctl_domains.c b/src/tools/sssctl/sssctl_domains.c -index 17ad670f39dfc045ba090210ffcfa77df713c306..40962792b84eabeb2c142f158184b17180a01669 100644 ---- a/src/tools/sssctl/sssctl_domains.c -+++ b/src/tools/sssctl/sssctl_domains.c -@@ -74,47 +74,32 @@ errno_t sssctl_domain_list(struct sss_cmdline *cmdline, - } - - static errno_t sssctl_domain_status_online(struct sss_tool_ctx *tool_ctx, -- const char *domain_path, -- bool force_start) -+ sss_sifp_ctx *sifp, -+ const char *domain_path) - { -- sss_sifp_ctx *sifp; -- sss_sifp_error sifp_error; -- DBusMessage *reply = NULL; -- DBusMessage *msg; -+ TALLOC_CTX *tmp_ctx; -+ sss_sifp_error error; -+ DBusMessage *reply; - bool is_online; - errno_t ret; - -- if (!sssctl_start_sssd(force_start)) { -- ret = ERR_SSSD_NOT_RUNNING; -- goto done; -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); -+ return ENOMEM; - } - -- sifp_error = sssctl_sifp_init(tool_ctx, &sifp); -- if (sifp_error != SSS_SIFP_OK) { -- sssctl_sifp_error(sifp, sifp_error, "Unable to connect to the InfoPipe"); -- ret = EFAULT; -- goto done; -- } -- -- msg = sbus_create_message(tool_ctx, SSS_SIFP_ADDRESS, domain_path, -- IFACE_IFP_DOMAINS_DOMAIN, -- IFACE_IFP_DOMAINS_DOMAIN_ISONLINE); -- if (msg == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create D-Bus message\n"); -- ret = ENOMEM; -- goto done; -- } -- -- sifp_error = sss_sifp_send_message(sifp, msg, &reply); -- if (sifp_error != SSS_SIFP_OK) { -- sssctl_sifp_error(sifp, sifp_error, "Unable to get online status"); -+ error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path, -+ IFACE_IFP_DOMAINS_DOMAIN, -+ IFACE_IFP_DOMAINS_DOMAIN_ISONLINE); -+ if (error != SSS_SIFP_OK) { -+ sssctl_sifp_error(sifp, error, "Unable to get online status"); - ret = EIO; - goto done; - } - - ret = sbus_parse_reply(reply, DBUS_TYPE_BOOLEAN, &is_online); - if (ret != EOK) { -- fprintf(stderr, _("Unable to get information from SSSD\n")); - goto done; - } - -@@ -123,10 +108,7 @@ static errno_t sssctl_domain_status_online(struct sss_tool_ctx *tool_ctx, - ret = EOK; - - done: -- if (reply != NULL) { -- dbus_message_unref(reply); -- } -- -+ talloc_free(tmp_ctx); - return ret; - } - -@@ -144,6 +126,8 @@ errno_t sssctl_domain_status(struct sss_cmdline *cmdline, - void *pvt) - { - struct sssctl_domain_status_opts opts = {0}; -+ sss_sifp_ctx *sifp; -+ sss_sifp_error error; - const char *path; - bool opt_set; - errno_t ret; -@@ -181,7 +165,17 @@ errno_t sssctl_domain_status(struct sss_cmdline *cmdline, - return ENOMEM; - } - -- ret = sssctl_domain_status_online(tool_ctx, path, opts.force_start); -+ if (!sssctl_start_sssd(opts.force_start)) { -+ return ERR_SSSD_NOT_RUNNING; -+ } -+ -+ error = sssctl_sifp_init(tool_ctx, &sifp); -+ if (error != SSS_SIFP_OK) { -+ sssctl_sifp_error(sifp, error, "Unable to connect to the InfoPipe"); -+ return EFAULT; -+ } -+ -+ ret = sssctl_domain_status_online(tool_ctx, sifp, path); - if (ret != EOK) { - fprintf(stderr, _("Unable to get online status\n")); - return ret; -diff --git a/src/tools/sssctl/sssctl_sifp.c b/src/tools/sssctl/sssctl_sifp.c -index e541c4b27ba38e50b209b0957c8b38f03afc891a..782a72d7ce8bbf1080c6d6ac988ffac2f432955f 100644 ---- a/src/tools/sssctl/sssctl_sifp.c -+++ b/src/tools/sssctl/sssctl_sifp.c -@@ -116,3 +116,49 @@ void _sssctl_sifp_error(sss_sifp_ctx *sifp, - break; - } - } -+ -+sss_sifp_error _sssctl_sifp_send(TALLOC_CTX *mem_ctx, -+ sss_sifp_ctx *sifp, -+ DBusMessage **_reply, -+ const char *path, -+ const char *iface, -+ const char *method, -+ int first_arg_type, -+ ...) -+{ -+ sss_sifp_error error; -+ DBusMessage *msg; -+ dbus_bool_t bret; -+ errno_t ret; -+ va_list va; -+ -+ msg = sss_sifp_create_message(path, iface, method); -+ if (msg == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create D-Bus message\n"); -+ return SSS_SIFP_OUT_OF_MEMORY; -+ } -+ -+ va_start(va, first_arg_type); -+ bret = dbus_message_append_args_valist(msg, first_arg_type, va); -+ va_end(va); -+ if (!bret) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n"); -+ error = SSS_SIFP_OUT_OF_MEMORY; -+ goto done; -+ } -+ -+ error = sss_sifp_send_message(sifp, msg, _reply); -+ if (error != SSS_SIFP_OK) { -+ goto done; -+ } -+ -+ ret = sbus_talloc_bound_message(mem_ctx, *_reply); -+ if (ret != EOK) { -+ error = SSS_SIFP_OUT_OF_MEMORY; -+ goto done; -+ } -+ -+done: -+ dbus_message_unref(msg); -+ return error; -+} --- -2.4.11 - diff --git a/SOURCES/0095-failover-mark-subdomain-service-with-sd_-prefix.patch b/SOURCES/0095-failover-mark-subdomain-service-with-sd_-prefix.patch deleted file mode 100644 index 4d9a1bf..0000000 --- a/SOURCES/0095-failover-mark-subdomain-service-with-sd_-prefix.patch +++ /dev/null @@ -1,92 +0,0 @@ -From a3b502fa85d493795c963e4298aeec3dc5806fcf Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Wed, 29 Jun 2016 14:58:37 +0200 -Subject: [PATCH 095/102] failover: mark subdomain service with sd_ prefix -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Jakub Hrozek -(cherry picked from commit 778f241e78241b0d6b8734148175f8dee804f494) ---- - src/providers/ad/ad_subdomains.c | 11 +++++++++-- - src/providers/ipa/ipa_subdomains_server.c | 11 +++++++++-- - 2 files changed, 18 insertions(+), 4 deletions(-) - -diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c -index e9da04e384e598927f9c8c203a751bcccd29e895..a0d5c2e544fc62fda64771dce59b3b7ab8ecd8b6 100644 ---- a/src/providers/ad/ad_subdomains.c -+++ b/src/providers/ad/ad_subdomains.c -@@ -66,6 +66,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, - struct ad_options *ad_options; - struct ad_id_ctx *ad_id_ctx; - const char *gc_service_name; -+ const char *service_name; - struct ad_srv_plugin_ctx *srv_ctx; - char *ad_domain; - char *ad_site_override; -@@ -94,14 +95,20 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, - - ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE); - -- gc_service_name = talloc_asprintf(ad_options, "%s%s", "gc_", subdom->name); -+ gc_service_name = talloc_asprintf(ad_options, "sd_gc_%s", subdom->name); - if (gc_service_name == NULL) { - talloc_free(ad_options); - return ENOMEM; - } - -+ service_name = talloc_asprintf(ad_options, "sd_%s", subdom->name); -+ if (service_name == NULL) { -+ talloc_free(ad_options); -+ return ENOMEM; -+ } -+ - ret = ad_failover_init(ad_options, be_ctx, NULL, NULL, realm, -- subdom->name, gc_service_name, -+ service_name, gc_service_name, - subdom->name, &ad_options->service); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD failover\n"); -diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c -index 43636098f6928006db0e0a9c05f2e39f8427d705..13640b04d66a1cdbbf0c8eab7648f7ebe921884b 100644 ---- a/src/providers/ipa/ipa_subdomains_server.c -+++ b/src/providers/ipa/ipa_subdomains_server.c -@@ -203,6 +203,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx, - struct ad_options *ad_options; - struct ad_id_ctx *ad_id_ctx; - const char *gc_service_name; -+ const char *service_name; - struct ad_srv_plugin_ctx *srv_ctx; - const char *ad_domain; - const char *ad_site_override; -@@ -250,17 +251,23 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx, - DEBUG(SSSDBG_TRACE_ALL, "No extra attrs set.\n"); - } - -- gc_service_name = talloc_asprintf(ad_options, "%s%s", "gc_", subdom->forest); -+ gc_service_name = talloc_asprintf(ad_options, "sd_gc_%s", subdom->forest); - if (gc_service_name == NULL) { - talloc_free(ad_options); - return ENOMEM; - } - -+ service_name = talloc_asprintf(ad_options, "sd_%s", subdom->name); -+ if (service_name == NULL) { -+ talloc_free(ad_options); -+ return ENOMEM; -+ } -+ - /* Set KRB5 realm to same as the one of IPA when IPA - * is able to attach PAC. For testing, use hardcoded. */ - ret = ad_failover_init(ad_options, be_ctx, NULL, NULL, - id_ctx->server_mode->realm, -- subdom->name, gc_service_name, -+ service_name, gc_service_name, - subdom->name, &ad_options->service); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD failover\n"); --- -2.4.11 - diff --git a/SOURCES/0095-sssctl-integrate-pam_test_client-into-sssctl.patch b/SOURCES/0095-sssctl-integrate-pam_test_client-into-sssctl.patch new file mode 100644 index 0000000..d942a65 --- /dev/null +++ b/SOURCES/0095-sssctl-integrate-pam_test_client-into-sssctl.patch @@ -0,0 +1,359 @@ +From 1bc25dba8f4725ef34e394d8e8eee42dbdaed924 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 30 Mar 2017 16:21:15 +0200 +Subject: [PATCH 95/96] sssctl: integrate pam_test_client into sssctl +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +(cherry picked from commit 4a9160e2b3b9c531e2b4a7884f49bfbb4a07a992) +--- + Makefile.am | 16 +-- + po/POTFILES.in | 1 - + src/tools/sssctl/sssctl.c | 1 + + src/tools/sssctl/sssctl.h | 4 + + .../sssctl/sssctl_user_checks.c} | 122 +++++++++++---------- + 5 files changed, 72 insertions(+), 72 deletions(-) + rename src/{sss_client/pam_test_client.c => tools/sssctl/sssctl_user_checks.c} (62%) + +diff --git a/Makefile.am b/Makefile.am +index c4d252357356c2d5452a414fd360fc5370b2c775..f5ac363a35e4aae51e8b70bad27c7fc824be10f2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1724,11 +1724,15 @@ sssctl_SOURCES = \ + src/tools/sssctl/sssctl_domains.c \ + src/tools/sssctl/sssctl_sifp.c \ + src/tools/sssctl/sssctl_config.c \ ++ src/tools/sssctl/sssctl_user_checks.c \ + $(SSSD_TOOLS_OBJ) \ + $(NULL) + sssctl_LDADD = \ + $(TOOLS_LIBS) \ + $(SSSD_INTERNAL_LTLIBS) \ ++ $(PAM_LIBS) \ ++ $(PAM_MISC_LIBS) \ ++ $(LIBADD_DL) \ + libsss_simpleifp.la \ + $(NULL) + sssctl_CFLAGS = \ +@@ -3449,7 +3453,7 @@ endif # BUILD_KCM + + endif # HAVE_CMOCKA + +-noinst_PROGRAMS = pam_test_client ++noinst_PROGRAMS = + if BUILD_SUDO + noinst_PROGRAMS += sss_sudo_cli + endif +@@ -3460,16 +3464,6 @@ if BUILD_WITH_LIBCURL + noinst_PROGRAMS += tcurl-test-tool + endif + +-pam_test_client_SOURCES = \ +- src/sss_client/pam_test_client.c \ +- $(NULL) +-pam_test_client_LDADD = \ +- $(PAM_LIBS) \ +- $(PAM_MISC_LIBS) \ +- $(LIBADD_DL) \ +- libsss_simpleifp.la \ +- $(NULL) +- + if BUILD_AUTOFS + autofs_test_client_SOURCES = \ + src/sss_client/autofs/autofs_test_client.c \ +diff --git a/po/POTFILES.in b/po/POTFILES.in +index ee532def223fdd5db632ad98fd11a57e38d0e125..f4e4e095f9e4025d129b6b13422bdd0bc07c8e1a 100644 +--- a/po/POTFILES.in ++++ b/po/POTFILES.in +@@ -9,7 +9,6 @@ src/sss_client/common.c + src/sss_client/nss_group.c + src/sss_client/nss_passwd.c + src/sss_client/pam_sss.c +-src/sss_client/pam_test_client.c + src/sss_client/ssh/sss_ssh_authorizedkeys.c + src/sss_client/ssh/sss_ssh_knownhostsproxy.c + src/tools/sss_useradd.c +diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c +index e1cf46382cd1dee54cd372ca500368f149411b78..509d2e1a00d3b57b541590ce7db5f94d2ff43add 100644 +--- a/src/tools/sssctl/sssctl.c ++++ b/src/tools/sssctl/sssctl.c +@@ -263,6 +263,7 @@ int main(int argc, const char **argv) + SSS_TOOL_DELIMITER("SSSD Status:"), + SSS_TOOL_COMMAND("domain-list", "List available domains", 0, sssctl_domain_list), + SSS_TOOL_COMMAND("domain-status", "Print information about domain", 0, sssctl_domain_status), ++ SSS_TOOL_COMMAND("user-checks", "Print information about a user and check authentication", 0, sssctl_user_checks), + SSS_TOOL_DELIMITER("Information about cached content:"), + SSS_TOOL_COMMAND("user-show", "Information about cached user", 0, sssctl_user_show), + SSS_TOOL_COMMAND("group-show", "Information about cached group", 0, sssctl_group_show), +diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h +index 5270a9ec62dfb288511af179a99e9a542ea26ec4..22626e2210252e5e3fadeb6c5d01d4620cd60e5b 100644 +--- a/src/tools/sssctl/sssctl.h ++++ b/src/tools/sssctl/sssctl.h +@@ -121,4 +121,8 @@ errno_t sssctl_netgroup_show(struct sss_cmdline *cmdline, + errno_t sssctl_config_check(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); ++ ++errno_t sssctl_user_checks(struct sss_cmdline *cmdline, ++ struct sss_tool_ctx *tool_ctx, ++ void *pvt); + #endif /* _SSSCTL_H_ */ +diff --git a/src/sss_client/pam_test_client.c b/src/tools/sssctl/sssctl_user_checks.c +similarity index 62% +rename from src/sss_client/pam_test_client.c +rename to src/tools/sssctl/sssctl_user_checks.c +index 40ef3f6d480c0108c985fce7e34e983d145f237e..7c7b564bd29100382c9bbef7a3131c379e9aa97e 100644 +--- a/src/sss_client/pam_test_client.c ++++ b/src/tools/sssctl/sssctl_user_checks.c +@@ -35,6 +35,9 @@ + #include + + #include "lib/sifp/sss_sifp.h" ++#include "util/util.h" ++#include "tools/common/sss_tools.h" ++#include "tools/sssctl/sssctl.h" + + #ifdef HAVE_SECURITY_PAM_MISC_H + # include +@@ -85,17 +88,17 @@ static int get_ifp_user(const char *user) + + error = sss_sifp_init(&sifp); + if (error != SSS_SIFP_OK) { +- fprintf(stderr, "Unable to connect to the InfoPipe"); ++ fprintf(stderr, _("Unable to connect to the InfoPipe")); + return EFAULT; + } + + error = sss_sifp_fetch_user_by_name(sifp, user, &user_obj); + if (error != SSS_SIFP_OK) { +- fprintf(stderr, "Unable to get user object"); ++ fprintf(stderr, _("Unable to get user object")); + return EIO; + } + +- fprintf(stdout, "SSSD InfoPipe user lookup result:\n"); ++ fprintf(stdout, _("SSSD InfoPipe user lookup result:\n")); + for (c = 0; ifp_user_attr[c].name != NULL; c++) { + if (ifp_user_attr[c].is_string) { + error = sss_sifp_find_attr_as_string(user_obj->attrs, +@@ -107,7 +110,7 @@ static int get_ifp_user(const char *user) + &tmp_uint32); + } + if (error != SSS_SIFP_OK) { +- fprintf(stderr, "Unable to get user name attr"); ++ fprintf(stderr, _("Unable to get user name attr")); + return EIO; + } + +@@ -118,6 +121,7 @@ static int get_ifp_user(const char *user) + tmp_uint32); + } + } ++ fprintf(stdout, "\n"); + + sss_sifp_free_object(sifp, &user_obj); + sss_sifp_free(&sifp); +@@ -139,14 +143,14 @@ static int sss_getpwnam_check(const char *user) + + dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW); + if (dl_handle == NULL) { +- fprintf(stderr, "dlopen failed with [%s].\n", dlerror()); ++ fprintf(stderr, _("dlopen failed with [%s].\n"), dlerror()); + ret = EIO; + goto done; + } + + sss_getpwnam_r = dlsym(dl_handle, "_nss_sss_getpwnam_r"); + if (sss_getpwnam_r == NULL) { +- fprintf(stderr, "dlsym failed with [%s].\n", dlerror()); ++ fprintf(stderr, _("dlsym failed with [%s].\n"), dlerror()); + ret = EIO; + goto done; + } +@@ -154,25 +158,25 @@ static int sss_getpwnam_check(const char *user) + buflen = DEFAULT_BUFSIZE; + buffer = malloc(buflen); + if (buffer == NULL) { +- fprintf(stderr, "malloc failed.\n"); ++ fprintf(stderr, _("malloc failed.\n")); + ret = ENOMEM; + goto done; + } + + status = sss_getpwnam_r(user, &pwd, buffer, buflen, &nss_errno); + if (status != NSS_STATUS_SUCCESS) { +- fprintf(stderr, "sss_getpwnam_r failed with [%d].\n", status); ++ fprintf(stderr, _("sss_getpwnam_r failed with [%d].\n"), status); + ret = EIO; + goto done; + } + +- fprintf(stdout, "SSSD nss user lookup result:\n"); +- fprintf(stdout, " - user name: %s\n", pwd.pw_name); +- fprintf(stdout, " - user id: %d\n", pwd.pw_uid); +- fprintf(stdout, " - group id: %d\n", pwd.pw_gid); +- fprintf(stdout, " - gecos: %s\n", pwd.pw_gecos); +- fprintf(stdout, " - home directory: %s\n", pwd.pw_dir); +- fprintf(stdout, " - shell: %s\n", pwd.pw_shell); ++ fprintf(stdout, _("SSSD nss user lookup result:\n")); ++ fprintf(stdout, _(" - user name: %s\n"), pwd.pw_name); ++ fprintf(stdout, _(" - user id: %d\n"), pwd.pw_uid); ++ fprintf(stdout, _(" - group id: %d\n"), pwd.pw_gid); ++ fprintf(stdout, _(" - gecos: %s\n"), pwd.pw_gecos); ++ fprintf(stdout, _(" - home directory: %s\n"), pwd.pw_dir); ++ fprintf(stdout, _(" - shell: %s\n\n"), pwd.pw_shell); + + ret = 0; + +@@ -186,87 +190,89 @@ done: + return ret; + } + +-int main(int argc, char *argv[]) { ++errno_t sssctl_user_checks(struct sss_cmdline *cmdline, ++ struct sss_tool_ctx *tool_ctx, ++ void *pvt) ++{ + + pam_handle_t *pamh; +- char *user; +- char *action; +- char *service; ++ const char *user = NULL; ++ const char *action = DEFAULT_ACTION; ++ const char *service = DEFAULT_SERVICE; + int ret; + size_t c; + char **pam_env; + +- if (argc == 1) { +- fprintf(stderr, "Usage: pam_test_client USERNAME " +- "[auth|acct|setc|chau|open|clos] [pam_service]\n"); +- return 0; +- } else if (argc == 2) { +- fprintf(stderr, "using first argument as user name and default action " +- "and service\n"); +- } else if (argc == 3) { +- fprintf(stderr, "using first argument as user name, second as action " +- "and default service\n"); +- } +- +- user = strdup(argv[1]); +- action = argc > 2 ? strdup(argv[2]) : strdup(DEFAULT_ACTION); +- service = argc > 3 ? strdup(argv[3]) : strdup(DEFAULT_SERVICE); ++ /* Parse command line. */ ++ struct poptOption options[] = { ++ { "action", 'a', POPT_ARG_STRING, &action, 0, ++ _("PAM action [auth|acct|setc|chau|open|clos], default: " ++ DEFAULT_ACTION), NULL }, ++ { "service", 's', POPT_ARG_STRING, &service, 0, ++ _("PAM service, default: " DEFAULT_SERVICE), NULL }, ++ POPT_TABLEEND ++ }; + +- if (action == NULL || user == NULL || service == NULL) { +- fprintf(stderr, "Out of memory!\n"); +- return 1; ++ ret = sss_tool_popt_ex(cmdline, options, SSS_TOOL_OPT_OPTIONAL, ++ NULL, NULL, "USERNAME", _("Specify user name."), ++ &user, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); ++ return ret; + } + +- fprintf(stdout, "user: %s\naction: %s\nservice: %s\n", ++ fprintf(stdout, _("user: %s\naction: %s\nservice: %s\n\n"), + user, action, service); + + if (*user != '\0') { + ret = sss_getpwnam_check(user); + if (ret != 0) { +- fprintf(stderr, "User name lookup with [%s] failed.\n", user); ++ fprintf(stderr, _("User name lookup with [%s] failed.\n"), user); + } + + ret = get_ifp_user(user); + if (ret != 0) { +- fprintf(stderr, "InforPipe User lookup with [%s] failed.\n", user); ++ fprintf(stderr, _("InforPipe User lookup with [%s] failed.\n"), ++ user); + } + } + + ret = pam_start(service, user, &conv, &pamh); + if (ret != PAM_SUCCESS) { +- fprintf(stderr, "pam_start failed: %s\n", pam_strerror(pamh, ret)); ++ fprintf(stderr, _("pam_start failed: %s\n"), pam_strerror(pamh, ret)); + return 1; + } + + if ( strncmp(action, "auth", 4)== 0 ) { +- fprintf(stdout, "testing pam_authenticate\n"); ++ fprintf(stdout, _("testing pam_authenticate\n\n")); + ret = pam_authenticate(pamh, 0); +- fprintf(stderr, "pam_authenticate: %s\n", pam_strerror(pamh, ret)); ++ fprintf(stderr, _("pam_authenticate: %s\n\n"), pam_strerror(pamh, ret)); + } else if ( strncmp(action, "chau", 4)== 0 ) { +- fprintf(stdout, "testing pam_chauthtok\n"); ++ fprintf(stdout, _("testing pam_chauthtok\n\n")); + ret = pam_chauthtok(pamh, 0); +- fprintf(stderr, "pam_chauthtok: %s\n", pam_strerror(pamh, ret)); ++ fprintf(stderr, _("pam_chauthtok: %s\n\n"), pam_strerror(pamh, ret)); + } else if ( strncmp(action, "acct", 4)== 0 ) { +- fprintf(stdout, "testing pam_acct_mgmt\n"); ++ fprintf(stdout, _("testing pam_acct_mgmt\n\n")); + ret = pam_acct_mgmt(pamh, 0); +- fprintf(stderr, "pam_acct_mgmt: %s\n", pam_strerror(pamh, ret)); ++ fprintf(stderr, _("pam_acct_mgmt: %s\n\n"), pam_strerror(pamh, ret)); + } else if ( strncmp(action, "setc", 4)== 0 ) { +- fprintf(stdout, "testing pam_setcred\n"); ++ fprintf(stdout, _("testing pam_setcred\n\n")); + ret = pam_setcred(pamh, 0); +- fprintf(stderr, "pam_setcred: %d[%s]\n", ret, pam_strerror(pamh, ret)); ++ fprintf(stderr, _("pam_setcred: [%s]\n\n"), pam_strerror(pamh, ret)); + } else if ( strncmp(action, "open", 4)== 0 ) { +- fprintf(stdout, "testing pam_open_session\n"); ++ fprintf(stdout, _("testing pam_open_session\n\n")); + ret = pam_open_session(pamh, 0); +- fprintf(stderr, "pam_open_session: %s\n", pam_strerror(pamh, ret)); ++ fprintf(stderr, _("pam_open_session: %s\n\n"), pam_strerror(pamh, ret)); + } else if ( strncmp(action, "clos", 4)== 0 ) { +- fprintf(stdout, "testing pam_close_session\n"); ++ fprintf(stdout, _("testing pam_close_session\n\n")); + ret = pam_close_session(pamh, 0); +- fprintf(stderr, "pam_close_session: %s\n", pam_strerror(pamh, ret)); ++ fprintf(stderr, _("pam_close_session: %s\n\n"), ++ pam_strerror(pamh, ret)); + } else { +- fprintf(stderr, "unknown action\n"); ++ fprintf(stderr, _("unknown action\n")); + } + +- fprintf(stderr, "PAM Environment:\n"); ++ fprintf(stderr, _("PAM Environment:\n")); + pam_env = pam_getenvlist(pamh); + if (pam_env != NULL && pam_env[0] != NULL) { + for (c = 0; pam_env[c] != NULL; c++) { +@@ -274,15 +280,11 @@ int main(int argc, char *argv[]) { + free(pam_env[c]); + } + } else { +- fprintf(stderr, " - no env -\n"); ++ fprintf(stderr, _(" - no env -\n")); + } + free(pam_env); + + pam_end(pamh, ret); + +- free(user); +- free(action); +- free(service); +- + return 0; + } +-- +2.9.3 + diff --git a/SOURCES/0096-i18n-adding-sssctl-files.patch b/SOURCES/0096-i18n-adding-sssctl-files.patch new file mode 100644 index 0000000..84984cf --- /dev/null +++ b/SOURCES/0096-i18n-adding-sssctl-files.patch @@ -0,0 +1,34 @@ +From e66f1df979b47519f9f51b6064154dae7ba5b396 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 7 Apr 2017 14:24:10 +0200 +Subject: [PATCH 96/96] i18n: adding sssctl files +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +(cherry picked from commit dbeae483464e42238a84c6a5b8c3c4f5312ae643) +--- + po/POTFILES.in | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/po/POTFILES.in b/po/POTFILES.in +index f4e4e095f9e4025d129b6b13422bdd0bc07c8e1a..33e7ed7f9e9bc19f33fca8a1f2649b69b79a882f 100644 +--- a/po/POTFILES.in ++++ b/po/POTFILES.in +@@ -23,4 +23,12 @@ src/tools/sss_cache.c + src/tools/sss_debuglevel.c + src/tools/tools_util.c + src/tools/tools_util.h ++src/tools/sssctl/sssctl.c ++src/tools/sssctl/sssctl_cache.c ++src/tools/sssctl/sssctl_config.c ++src/tools/sssctl/sssctl_data.c ++src/tools/sssctl/sssctl_domains.c ++src/tools/sssctl/sssctl_logs.c ++src/tools/sssctl/sssctl_sifp.c ++src/tools/sssctl/sssctl_user_checks.c + src/util/util.h +-- +2.9.3 + diff --git a/SOURCES/0096-sssctl-print-active-server-and-server-list.patch b/SOURCES/0096-sssctl-print-active-server-and-server-list.patch deleted file mode 100644 index 8bb1918..0000000 --- a/SOURCES/0096-sssctl-print-active-server-and-server-list.patch +++ /dev/null @@ -1,1013 +0,0 @@ -From 7f4199c2d4dc9147be436005d75e03fc468f5349 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Mon, 27 Jun 2016 13:56:13 +0200 -Subject: [PATCH 096/102] sssctl: print active server and server list -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: -https://fedorahosted.org/sssd/ticket/3069 - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Jakub Hrozek -(cherry picked from commit bd4c2ed5aec7f57ea04500f0e43f151eedfdde45) ---- - src/providers/data_provider/dp_iface.c | 6 +- - src/providers/data_provider/dp_iface.h | 8 + - src/providers/data_provider/dp_iface.xml | 8 + - src/providers/data_provider/dp_iface_failover.c | 297 ++++++++++++++++++++++- - src/providers/data_provider/dp_iface_generated.c | 52 ++++ - src/providers/data_provider/dp_iface_generated.h | 10 + - src/providers/fail_over.c | 42 ++++ - src/providers/fail_over.h | 4 + - src/responder/ifp/ifp_domains.c | 48 ++++ - src/responder/ifp/ifp_domains.h | 8 + - src/responder/ifp/ifp_iface.c | 4 +- - src/responder/ifp/ifp_iface.xml | 10 + - src/responder/ifp/ifp_iface_generated.c | 52 ++++ - src/responder/ifp/ifp_iface_generated.h | 10 + - src/tools/sssctl/sssctl_domains.c | 182 +++++++++++++- - 15 files changed, 722 insertions(+), 19 deletions(-) - -diff --git a/src/providers/data_provider/dp_iface.c b/src/providers/data_provider/dp_iface.c -index 8ed7274f0dd7b59598e2cf21e0dd59d16666df0b..4b2b0ddca68be8899f7285b4d881a91444b99362 100644 ---- a/src/providers/data_provider/dp_iface.c -+++ b/src/providers/data_provider/dp_iface.c -@@ -42,8 +42,10 @@ struct iface_dp_backend iface_dp_backend = { - }; - - struct iface_dp_failover iface_dp_failover = { -- {&iface_dp_failover_meta, 0}, -- .ListServices = dp_failover_list_services -+ { &iface_dp_failover_meta, 0 }, -+ .ListServices = dp_failover_list_services, -+ .ActiveServer = dp_failover_active_server, -+ .ListServers = dp_failover_list_servers - }; - - static struct sbus_iface_map dp_map[] = { -diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h -index 76e623d21c413fd68f8f3c9a91ea32fd707dc54d..5c6f0eb2f5dd68b63bda389e6fdd2446ca9efb21 100644 ---- a/src/providers/data_provider/dp_iface.h -+++ b/src/providers/data_provider/dp_iface.h -@@ -69,4 +69,12 @@ errno_t dp_failover_list_services(struct sbus_request *sbus_req, - void *dp_cli, - const char *domname); - -+errno_t dp_failover_active_server(struct sbus_request *sbus_req, -+ void *dp_cli, -+ const char *service_name); -+ -+errno_t dp_failover_list_servers(struct sbus_request *sbus_req, -+ void *dp_cli, -+ const char *service_name); -+ - #endif /* DP_IFACE_H_ */ -diff --git a/src/providers/data_provider/dp_iface.xml b/src/providers/data_provider/dp_iface.xml -index eab7fc0f1500bf8890030352421da62c134115b9..992848a048ef9fe813d6ae05bbcabd0913ecb277 100644 ---- a/src/providers/data_provider/dp_iface.xml -+++ b/src/providers/data_provider/dp_iface.xml -@@ -22,6 +22,14 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ - - - -diff --git a/src/providers/data_provider/dp_iface_failover.c b/src/providers/data_provider/dp_iface_failover.c -index 038791088eeab7e9c5923996db77d2a107ff067d..7d95ffdd627604eb8c7e1b2882bf1665f792b660 100644 ---- a/src/providers/data_provider/dp_iface_failover.c -+++ b/src/providers/data_provider/dp_iface_failover.c -@@ -28,20 +28,208 @@ - #include "providers/backend.h" - #include "util/util.h" - -+static errno_t -+dp_failover_list_services_ldap(struct be_ctx *be_ctx, -+ const char **services, -+ int *_count) -+{ -+ struct be_svc_data *svc; -+ int count; -+ -+ count = 0; -+ DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) { -+ services[count] = talloc_strdup(services, svc->name); -+ if (services[count] == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); -+ return ENOMEM; -+ } -+ count++; -+ } -+ -+ *_count = count; -+ -+ return EOK; -+} -+ -+static errno_t -+dp_failover_list_services_ad(struct be_ctx *be_ctx, -+ struct sss_domain_info *domain, -+ const char **services, -+ int *_count) -+{ -+ char *fo_svc_name = NULL; -+ struct be_svc_data *svc; -+ errno_t ret; -+ int count; -+ -+ fo_svc_name = talloc_asprintf(services, "sd_%s", domain->name); -+ if (fo_svc_name == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ count = 0; -+ DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) { -+ /* Drop each sd_gc_* since this service is not used with AD at all, -+ * we only connect to AD_GC for global catalog. */ -+ if (strncasecmp(svc->name, "sd_gc_", strlen("sd_gc_")) == 0) { -+ continue; -+ } -+ -+ /* Drop all subdomain services for different domain. */ -+ if (strncasecmp(svc->name, "sd_", strlen("sd_")) == 0) { -+ if (!IS_SUBDOMAIN(domain)) { -+ continue; -+ } -+ -+ if (strcasecmp(svc->name, fo_svc_name) != 0) { -+ continue; -+ } -+ } -+ -+ if (IS_SUBDOMAIN(domain)) { -+ /* Drop AD since we connect to subdomain.com for LDAP. */ -+ if (strcasecmp(svc->name, "AD") == 0) { -+ continue; -+ } -+ } -+ -+ services[count] = talloc_strdup(services, svc->name); -+ if (services[count] == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ count++; -+ } -+ -+ *_count = count; -+ -+ ret = EOK; -+ -+done: -+ talloc_free(fo_svc_name); -+ return ret; -+} -+ -+static errno_t -+dp_failover_list_services_ipa(struct be_ctx *be_ctx, -+ struct sss_domain_info *domain, -+ const char **services, -+ int *_count) -+{ -+ struct be_svc_data *svc; -+ char *fo_svc_name = NULL; -+ char *fo_gc_name = NULL; -+ errno_t ret; -+ int count; -+ -+ fo_svc_name = talloc_asprintf(services, "sd_%s", domain->name); -+ if (fo_svc_name == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ fo_gc_name = talloc_asprintf(services, "sd_gc_%s", domain->name); -+ if (fo_gc_name == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ count = 0; -+ DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) { -+ /* Drop all subdomain services for different domain. */ -+ if (strncasecmp(svc->name, "sd_", strlen("sd_")) == 0) { -+ if (!IS_SUBDOMAIN(domain)) { -+ continue; -+ } -+ -+ if (strcasecmp(svc->name, fo_svc_name) != 0 -+ && strcasecmp(svc->name, fo_gc_name) != 0) { -+ continue; -+ } -+ } -+ -+ services[count] = talloc_strdup(services, svc->name); -+ if (services[count] == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); -+ return ENOMEM; -+ } -+ count++; -+ } -+ -+ *_count = count; -+ -+ ret = EOK; -+ -+done: -+ talloc_free(fo_svc_name); -+ talloc_free(fo_gc_name); -+ -+ return ret; -+} -+ -+enum dp_fo_svc_type { -+ DP_FO_SVC_LDAP = 0, -+ DP_FO_SVC_AD = 1, -+ DP_FO_SVC_IPA = 1 << 1, -+ DP_FO_SVC_MIXED = DP_FO_SVC_AD | DP_FO_SVC_IPA -+}; -+ - errno_t dp_failover_list_services(struct sbus_request *sbus_req, - void *dp_cli, - const char *domname) - { -+ enum dp_fo_svc_type svc_type = DP_FO_SVC_LDAP; -+ struct sss_domain_info *domain; - struct be_ctx *be_ctx; - struct be_svc_data *svc; - const char **services; - int num_services; -+ errno_t ret; - - be_ctx = dp_client_be(dp_cli); - -+ if (SBUS_IS_STRING_EMPTY(domname)) { -+ domain = be_ctx->domain; -+ } else { -+ domain = find_domain_by_name(be_ctx->domain, domname, false); -+ if (domain == NULL) { -+ sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN, -+ "Unknown domain %s", domname); -+ return EOK; -+ } -+ } -+ -+ /** -+ * Returning list of failover services is currently rather difficult -+ * since there is only one failover context for the whole backend. -+ * -+ * The list of services for the given domain depends on whether it is -+ * a master domain or a subdomain and whether we are using IPA, AD or -+ * LDAP backend. -+ * -+ * For LDAP we just return everything we have. -+ * For AD master domain we return AD, AD_GC. -+ * For AD subdomain we return subdomain.com, AD_GC. -+ * For IPA in client mode we return IPA. -+ * For IPA in server mode we return IPA for master domain and -+ * subdomain.com, gc_subdomain.com for subdomain. -+ * -+ * We also return everything else for all cases if any other service -+ * such as kerberos is configured separately. -+ */ -+ -+ /* Allocate enough space. */ - num_services = 0; - DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) { - num_services++; -+ -+ if (strcasecmp(svc->name, "AD") == 0) { -+ svc_type |= DP_FO_SVC_AD; -+ } else if (strcasecmp(svc->name, "IPA") == 0) { -+ svc_type |= DP_FO_SVC_IPA; -+ } - } - - services = talloc_zero_array(sbus_req, const char *, num_services); -@@ -50,17 +238,108 @@ errno_t dp_failover_list_services(struct sbus_request *sbus_req, - return ENOMEM; - } - -- num_services = 0; -- DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) { -- services[num_services] = talloc_strdup(services, svc->name); -- if (services[num_services] == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); -- talloc_free(services); -- return ENOMEM; -- } -- num_services++; -+ /* Fill the list. */ -+ switch (svc_type) { -+ case DP_FO_SVC_LDAP: -+ case DP_FO_SVC_MIXED: -+ ret = dp_failover_list_services_ldap(be_ctx, services, &num_services); -+ break; -+ case DP_FO_SVC_AD: -+ ret = dp_failover_list_services_ad(be_ctx, domain, -+ services, &num_services); -+ break; -+ case DP_FO_SVC_IPA: -+ ret = dp_failover_list_services_ipa(be_ctx, domain, -+ services, &num_services); -+ break; -+ default: -+ ret = ERR_INTERNAL; -+ break; -+ } -+ -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create service list [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ talloc_free(services); -+ return ret; - } - - iface_dp_failover_ListServices_finish(sbus_req, services, num_services); - return EOK; - } -+ -+errno_t dp_failover_active_server(struct sbus_request *sbus_req, -+ void *dp_cli, -+ const char *service_name) -+{ -+ struct be_ctx *be_ctx; -+ struct be_svc_data *svc; -+ const char *server; -+ bool found = false; -+ -+ be_ctx = dp_client_be(dp_cli); -+ -+ DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) { -+ if (strcmp(svc->name, service_name) == 0) { -+ found = true; -+ break; -+ } -+ } -+ -+ if (!found) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get server name\n"); -+ sbus_request_reply_error(sbus_req, SBUS_ERROR_NOT_FOUND, -+ "Unknown service name"); -+ return EOK; -+ } -+ -+ if (svc->last_good_srv == NULL) { -+ server = ""; -+ } else { -+ server = fo_get_server_name(svc->last_good_srv); -+ if (server == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get server name\n"); -+ sbus_request_reply_error(sbus_req, SBUS_ERROR_INTERNAL, -+ "Unable to get server name"); -+ return EOK; -+ } -+ } -+ -+ iface_dp_failover_ActiveServer_finish(sbus_req, server); -+ return EOK; -+} -+ -+errno_t dp_failover_list_servers(struct sbus_request *sbus_req, -+ void *dp_cli, -+ const char *service_name) -+{ -+ struct be_ctx *be_ctx; -+ struct be_svc_data *svc; -+ const char **servers; -+ bool found = false; -+ size_t count; -+ -+ be_ctx = dp_client_be(dp_cli); -+ -+ DLIST_FOR_EACH(svc, be_ctx->be_fo->svcs) { -+ if (strcmp(svc->name, service_name) == 0) { -+ found = true; -+ break; -+ } -+ } -+ -+ if (!found) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get server list\n"); -+ sbus_request_reply_error(sbus_req, SBUS_ERROR_NOT_FOUND, -+ "Unknown service name"); -+ return EOK; -+ } -+ -+ servers = fo_svc_server_list(sbus_req, svc->fo_service, &count); -+ if (servers == NULL) { -+ return ENOMEM; -+ } -+ -+ iface_dp_failover_ListServers_finish(sbus_req, servers, (int)count); -+ return EOK; -+} -diff --git a/src/providers/data_provider/dp_iface_generated.c b/src/providers/data_provider/dp_iface_generated.c -index 7b36fd8aaeebb976a511c5592b1dd0ae28e9bb8a..fd2acb4f4bd8cf1dcbe8842cccc6dc2077fc83a2 100644 ---- a/src/providers/data_provider/dp_iface_generated.c -+++ b/src/providers/data_provider/dp_iface_generated.c -@@ -111,6 +111,44 @@ int iface_dp_failover_ListServices_finish(struct sbus_request *req, const char * - DBUS_TYPE_INVALID); - } - -+/* arguments for org.freedesktop.sssd.DataProvider.Failover.ActiveServer */ -+const struct sbus_arg_meta iface_dp_failover_ActiveServer__in[] = { -+ { "service_name", "s" }, -+ { NULL, } -+}; -+ -+/* arguments for org.freedesktop.sssd.DataProvider.Failover.ActiveServer */ -+const struct sbus_arg_meta iface_dp_failover_ActiveServer__out[] = { -+ { "server", "s" }, -+ { NULL, } -+}; -+ -+int iface_dp_failover_ActiveServer_finish(struct sbus_request *req, const char *arg_server) -+{ -+ return sbus_request_return_and_finish(req, -+ DBUS_TYPE_STRING, &arg_server, -+ DBUS_TYPE_INVALID); -+} -+ -+/* arguments for org.freedesktop.sssd.DataProvider.Failover.ListServers */ -+const struct sbus_arg_meta iface_dp_failover_ListServers__in[] = { -+ { "service_name", "s" }, -+ { NULL, } -+}; -+ -+/* arguments for org.freedesktop.sssd.DataProvider.Failover.ListServers */ -+const struct sbus_arg_meta iface_dp_failover_ListServers__out[] = { -+ { "servers", "as" }, -+ { NULL, } -+}; -+ -+int iface_dp_failover_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers) -+{ -+ return sbus_request_return_and_finish(req, -+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &arg_servers, len_servers, -+ DBUS_TYPE_INVALID); -+} -+ - /* methods for org.freedesktop.sssd.DataProvider.Failover */ - const struct sbus_method_meta iface_dp_failover__methods[] = { - { -@@ -120,6 +158,20 @@ const struct sbus_method_meta iface_dp_failover__methods[] = { - offsetof(struct iface_dp_failover, ListServices), - invoke_s_method, - }, -+ { -+ "ActiveServer", /* name */ -+ iface_dp_failover_ActiveServer__in, -+ iface_dp_failover_ActiveServer__out, -+ offsetof(struct iface_dp_failover, ActiveServer), -+ invoke_s_method, -+ }, -+ { -+ "ListServers", /* name */ -+ iface_dp_failover_ListServers__in, -+ iface_dp_failover_ListServers__out, -+ offsetof(struct iface_dp_failover, ListServers), -+ invoke_s_method, -+ }, - { NULL, } - }; - -diff --git a/src/providers/data_provider/dp_iface_generated.h b/src/providers/data_provider/dp_iface_generated.h -index 977ab3bae803ca002162b02d0c3d9677779983f4..7c2216aa27022769c707d80b59e9b436e72d1739 100644 ---- a/src/providers/data_provider/dp_iface_generated.h -+++ b/src/providers/data_provider/dp_iface_generated.h -@@ -22,6 +22,8 @@ - /* constants for org.freedesktop.sssd.DataProvider.Failover */ - #define IFACE_DP_FAILOVER "org.freedesktop.sssd.DataProvider.Failover" - #define IFACE_DP_FAILOVER_LISTSERVICES "ListServices" -+#define IFACE_DP_FAILOVER_ACTIVESERVER "ActiveServer" -+#define IFACE_DP_FAILOVER_LISTSERVERS "ListServers" - - /* constants for org.freedesktop.sssd.dataprovider */ - #define IFACE_DP "org.freedesktop.sssd.dataprovider" -@@ -72,11 +74,19 @@ int iface_dp_backend_IsOnline_finish(struct sbus_request *req, bool arg_status); - struct iface_dp_failover { - struct sbus_vtable vtable; /* derive from sbus_vtable */ - int (*ListServices)(struct sbus_request *req, void *data, const char *arg_domain_name); -+ int (*ActiveServer)(struct sbus_request *req, void *data, const char *arg_service_name); -+ int (*ListServers)(struct sbus_request *req, void *data, const char *arg_service_name); - }; - - /* finish function for ListServices */ - int iface_dp_failover_ListServices_finish(struct sbus_request *req, const char *arg_services[], int len_services); - -+/* finish function for ActiveServer */ -+int iface_dp_failover_ActiveServer_finish(struct sbus_request *req, const char *arg_server); -+ -+/* finish function for ListServers */ -+int iface_dp_failover_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers); -+ - /* vtable for org.freedesktop.sssd.dataprovider */ - struct iface_dp { - struct sbus_vtable vtable; /* derive from sbus_vtable */ -diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c -index 1d88d2aa54bfdebd4b648e2b13fa8d03e2be3973..8ab39f27f77e19e601855632196006a8dbbdf136 100644 ---- a/src/providers/fail_over.c -+++ b/src/providers/fail_over.c -@@ -1660,6 +1660,48 @@ bool fo_svc_has_server(struct fo_service *service, struct fo_server *server) - return false; - } - -+const char **fo_svc_server_list(TALLOC_CTX *mem_ctx, -+ struct fo_service *service, -+ size_t *_count) -+{ -+ const char **list; -+ const char *server; -+ struct fo_server *srv; -+ size_t count; -+ -+ count = 0; -+ DLIST_FOR_EACH(srv, service->server_list) { -+ count++; -+ } -+ -+ list = talloc_zero_array(mem_ctx, const char *, count + 1); -+ if (list == NULL) { -+ return NULL; -+ } -+ -+ count = 0; -+ DLIST_FOR_EACH(srv, service->server_list) { -+ server = fo_get_server_name(srv); -+ if (server == NULL) { -+ /* _srv_ */ -+ continue; -+ } -+ -+ list[count] = talloc_strdup(list, server); -+ if (list[count] == NULL) { -+ talloc_free(list); -+ return NULL; -+ } -+ count++; -+ } -+ -+ if (_count != NULL) { -+ *_count = count; -+ } -+ -+ return list; -+} -+ - bool fo_set_srv_lookup_plugin(struct fo_ctx *ctx, - fo_srv_lookup_plugin_send_t send_fn, - fo_srv_lookup_plugin_recv_t recv_fn, -diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h -index f24b5715f13931965400c20562a1578aaf756908..d70212fb7ea569b9c47bba36704aa8ae18754cbb 100644 ---- a/src/providers/fail_over.h -+++ b/src/providers/fail_over.h -@@ -212,6 +212,10 @@ struct fo_server *fo_get_active_server(struct fo_service *service); - - bool fo_svc_has_server(struct fo_service *service, struct fo_server *server); - -+const char **fo_svc_server_list(TALLOC_CTX *mem_ctx, -+ struct fo_service *service, -+ size_t *_count); -+ - /* - * pvt will be talloc_stealed to ctx - */ -diff --git a/src/responder/ifp/ifp_domains.c b/src/responder/ifp/ifp_domains.c -index ff690ed6a7d5519979d242a4d5dadd08aff50347..977bbfcbe818f08873ce072d34fdcf900cabf52f 100644 ---- a/src/responder/ifp/ifp_domains.c -+++ b/src/responder/ifp/ifp_domains.c -@@ -582,3 +582,51 @@ int ifp_domains_domain_list_services(struct sbus_request *sbus_req, - - return EOK; - } -+ -+int ifp_domains_domain_active_server(struct sbus_request *sbus_req, -+ void *data, -+ const char *service) -+{ -+ struct ifp_ctx *ifp_ctx; -+ struct sss_domain_info *dom; -+ -+ ifp_ctx = talloc_get_type(data, struct ifp_ctx); -+ -+ dom = get_domain_info_from_req(sbus_req, data); -+ if (dom == NULL) { -+ sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN, -+ "Unknown domain"); -+ return EOK; -+ } -+ -+ rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH, -+ IFACE_DP_FAILOVER, -+ IFACE_DP_FAILOVER_ACTIVESERVER, -+ DBUS_TYPE_STRING, &service); -+ -+ return EOK; -+} -+ -+int ifp_domains_domain_list_servers(struct sbus_request *sbus_req, -+ void *data, -+ const char *service) -+{ -+ struct ifp_ctx *ifp_ctx; -+ struct sss_domain_info *dom; -+ -+ ifp_ctx = talloc_get_type(data, struct ifp_ctx); -+ -+ dom = get_domain_info_from_req(sbus_req, data); -+ if (dom == NULL) { -+ sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN, -+ "Unknown domain"); -+ return EOK; -+ } -+ -+ rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH, -+ IFACE_DP_FAILOVER, -+ IFACE_DP_FAILOVER_LISTSERVERS, -+ DBUS_TYPE_STRING, &service); -+ -+ return EOK; -+} -diff --git a/src/responder/ifp/ifp_domains.h b/src/responder/ifp/ifp_domains.h -index 91645e60701f8f75e89a42e93e2c066def67b018..621ba6158e285911cb8298cef212219dfd3afec8 100644 ---- a/src/responder/ifp/ifp_domains.h -+++ b/src/responder/ifp/ifp_domains.h -@@ -100,4 +100,12 @@ int ifp_domains_domain_is_online(struct sbus_request *sbus_req, - int ifp_domains_domain_list_services(struct sbus_request *sbus_req, - void *data); - -+int ifp_domains_domain_active_server(struct sbus_request *sbus_req, -+ void *data, -+ const char *service); -+ -+int ifp_domains_domain_list_servers(struct sbus_request *sbus_req, -+ void *data, -+ const char *service); -+ - #endif /* IFP_DOMAINS_H_ */ -diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c -index 90bb52b2ccf5207034abbe12bddbfa1eeaf875f7..e6ddc687ba9db878ee39fee5868d1f924d58482d 100644 ---- a/src/responder/ifp/ifp_iface.c -+++ b/src/responder/ifp/ifp_iface.c -@@ -81,7 +81,9 @@ struct iface_ifp_domains iface_ifp_domains = { - struct iface_ifp_domains_domain iface_ifp_domains_domain = { - { &iface_ifp_domains_domain_meta, 0 }, - .IsOnline = ifp_domains_domain_is_online, -- .ListServices = ifp_domains_domain_list_services -+ .ListServices = ifp_domains_domain_list_services, -+ .ActiveServer = ifp_domains_domain_active_server, -+ .ListServers = ifp_domains_domain_list_servers - }; - - struct iface_ifp_users iface_ifp_users = { -diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml -index 7f6f47299deeba4b1baa23d1e63ee7bb17304a59..25b104ad70c0fd84b6c0fe9dbb0dc6e6439c1376 100644 ---- a/src/responder/ifp/ifp_iface.xml -+++ b/src/responder/ifp/ifp_iface.xml -@@ -112,6 +112,16 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - - - -diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c -index 4d3bb5727b03ae64adad14fcdbb3eb5366edb406..6156ca2947434f301d206232f83cfc0647007707 100644 ---- a/src/responder/ifp/ifp_iface_generated.c -+++ b/src/responder/ifp/ifp_iface_generated.c -@@ -558,6 +558,44 @@ int iface_ifp_domains_domain_ListServices_finish(struct sbus_request *req, const - DBUS_TYPE_INVALID); - } - -+/* arguments for org.freedesktop.sssd.infopipe.Domains.Domain.ActiveServer */ -+const struct sbus_arg_meta iface_ifp_domains_domain_ActiveServer__in[] = { -+ { "service", "s" }, -+ { NULL, } -+}; -+ -+/* arguments for org.freedesktop.sssd.infopipe.Domains.Domain.ActiveServer */ -+const struct sbus_arg_meta iface_ifp_domains_domain_ActiveServer__out[] = { -+ { "server", "s" }, -+ { NULL, } -+}; -+ -+int iface_ifp_domains_domain_ActiveServer_finish(struct sbus_request *req, const char *arg_server) -+{ -+ return sbus_request_return_and_finish(req, -+ DBUS_TYPE_STRING, &arg_server, -+ DBUS_TYPE_INVALID); -+} -+ -+/* arguments for org.freedesktop.sssd.infopipe.Domains.Domain.ListServers */ -+const struct sbus_arg_meta iface_ifp_domains_domain_ListServers__in[] = { -+ { "service_name", "s" }, -+ { NULL, } -+}; -+ -+/* arguments for org.freedesktop.sssd.infopipe.Domains.Domain.ListServers */ -+const struct sbus_arg_meta iface_ifp_domains_domain_ListServers__out[] = { -+ { "servers", "as" }, -+ { NULL, } -+}; -+ -+int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers) -+{ -+ return sbus_request_return_and_finish(req, -+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &arg_servers, len_servers, -+ DBUS_TYPE_INVALID); -+} -+ - /* methods for org.freedesktop.sssd.infopipe.Domains.Domain */ - const struct sbus_method_meta iface_ifp_domains_domain__methods[] = { - { -@@ -574,6 +612,20 @@ const struct sbus_method_meta iface_ifp_domains_domain__methods[] = { - offsetof(struct iface_ifp_domains_domain, ListServices), - NULL, /* no invoker */ - }, -+ { -+ "ActiveServer", /* name */ -+ iface_ifp_domains_domain_ActiveServer__in, -+ iface_ifp_domains_domain_ActiveServer__out, -+ offsetof(struct iface_ifp_domains_domain, ActiveServer), -+ invoke_s_method, -+ }, -+ { -+ "ListServers", /* name */ -+ iface_ifp_domains_domain_ListServers__in, -+ iface_ifp_domains_domain_ListServers__out, -+ offsetof(struct iface_ifp_domains_domain, ListServers), -+ invoke_s_method, -+ }, - { NULL, } - }; - -diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h -index 2eff57410e5292a05818050b96eb85aa3a4f2e16..141348249d2da5447fa04495564a8c6a55d67a1b 100644 ---- a/src/responder/ifp/ifp_iface_generated.h -+++ b/src/responder/ifp/ifp_iface_generated.h -@@ -58,6 +58,8 @@ - #define IFACE_IFP_DOMAINS_DOMAIN "org.freedesktop.sssd.infopipe.Domains.Domain" - #define IFACE_IFP_DOMAINS_DOMAIN_ISONLINE "IsOnline" - #define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVICES "ListServices" -+#define IFACE_IFP_DOMAINS_DOMAIN_ACTIVESERVER "ActiveServer" -+#define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVERS "ListServers" - - /* constants for org.freedesktop.sssd.infopipe.Cache */ - #define IFACE_IFP_CACHE "org.freedesktop.sssd.infopipe.Cache" -@@ -215,6 +217,8 @@ struct iface_ifp_domains_domain { - struct sbus_vtable vtable; /* derive from sbus_vtable */ - int (*IsOnline)(struct sbus_request *req, void *data); - int (*ListServices)(struct sbus_request *req, void *data); -+ int (*ActiveServer)(struct sbus_request *req, void *data, const char *arg_service); -+ int (*ListServers)(struct sbus_request *req, void *data, const char *arg_service_name); - }; - - /* finish function for IsOnline */ -@@ -223,6 +227,12 @@ int iface_ifp_domains_domain_IsOnline_finish(struct sbus_request *req, bool arg_ - /* finish function for ListServices */ - int iface_ifp_domains_domain_ListServices_finish(struct sbus_request *req, const char *arg_services[], int len_services); - -+/* finish function for ActiveServer */ -+int iface_ifp_domains_domain_ActiveServer_finish(struct sbus_request *req, const char *arg_server); -+ -+/* finish function for ListServers */ -+int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers); -+ - /* vtable for org.freedesktop.sssd.infopipe.Cache */ - struct iface_ifp_cache { - struct sbus_vtable vtable; /* derive from sbus_vtable */ -diff --git a/src/tools/sssctl/sssctl_domains.c b/src/tools/sssctl/sssctl_domains.c -index 40962792b84eabeb2c142f158184b17180a01669..545ed95f4415da597b191146409ea6ba028f36f8 100644 ---- a/src/tools/sssctl/sssctl_domains.c -+++ b/src/tools/sssctl/sssctl_domains.c -@@ -112,6 +112,155 @@ done: - return ret; - } - -+static const char *proper_service_name(const char *service) -+{ -+ if (strcasecmp(service, "AD_GC") == 0) { -+ return "AD Global Catalog"; -+ } else if (strcasecmp(service, "AD") == 0) { -+ return "AD Domain Controller"; -+ } else if (strncasecmp(service, "sd_gc_", strlen("sd_gc_")) == 0) { -+ return "AD Global Catalog"; -+ } else if (strncasecmp(service, "sd_", strlen("sd_")) == 0) { -+ return "AD Domain Controller"; -+ } -+ -+ return service; -+} -+ -+static errno_t sssctl_domain_status_active_server(struct sss_tool_ctx *tool_ctx, -+ sss_sifp_ctx *sifp, -+ const char *domain_path) -+{ -+ TALLOC_CTX *tmp_ctx; -+ sss_sifp_error error; -+ DBusMessage *reply; -+ const char *server; -+ const char **services; -+ int num_services; -+ errno_t ret; -+ int i; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); -+ return ENOMEM; -+ } -+ -+ error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path, -+ IFACE_IFP_DOMAINS_DOMAIN, -+ IFACE_IFP_DOMAINS_DOMAIN_LISTSERVICES); -+ if (error != SSS_SIFP_OK) { -+ sssctl_sifp_error(sifp, error, "Unable to list services"); -+ ret = EIO; -+ goto done; -+ } -+ -+ ret = sbus_parse_reply(reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, -+ &services, &num_services); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ printf(_("Active servers:\n")); -+ for (i = 0; i < num_services; i++) { -+ error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path, -+ IFACE_IFP_DOMAINS_DOMAIN, -+ IFACE_IFP_DOMAINS_DOMAIN_ACTIVESERVER, -+ DBUS_TYPE_STRING, &services[i]); -+ if (error != SSS_SIFP_OK) { -+ sssctl_sifp_error(sifp, error, "Unable to get active server"); -+ ret = EIO; -+ goto done; -+ } -+ -+ ret = sbus_parse_reply(reply, DBUS_TYPE_STRING, &server); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ server = SBUS_IS_STRING_EMPTY(server) ? _("not connected") : server; -+ printf("%s: %s\n", proper_service_name(services[i]), server); -+ } -+ -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ -+static errno_t sssctl_domain_status_server_list(struct sss_tool_ctx *tool_ctx, -+ sss_sifp_ctx *sifp, -+ const char *domain_path) -+{ -+ TALLOC_CTX *tmp_ctx; -+ sss_sifp_error error; -+ DBusMessage *reply; -+ const char **servers; -+ int num_servers; -+ const char **services; -+ int num_services; -+ errno_t ret; -+ int i, j; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); -+ return ENOMEM; -+ } -+ -+ error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path, -+ IFACE_IFP_DOMAINS_DOMAIN, -+ IFACE_IFP_DOMAINS_DOMAIN_LISTSERVICES); -+ if (error != SSS_SIFP_OK) { -+ sssctl_sifp_error(sifp, error, "Unable to list services"); -+ ret = EIO; -+ goto done; -+ } -+ -+ ret = sbus_parse_reply(reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, -+ &services, &num_services); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ for (i = 0; i < num_services; i++) { -+ printf(_("Discovered %s servers:\n"), proper_service_name(services[i])); -+ error = sssctl_sifp_send(tmp_ctx, sifp, &reply, domain_path, -+ IFACE_IFP_DOMAINS_DOMAIN, -+ IFACE_IFP_DOMAINS_DOMAIN_LISTSERVERS, -+ DBUS_TYPE_STRING, &services[i]); -+ if (error != SSS_SIFP_OK) { -+ sssctl_sifp_error(sifp, error, "Unable to get active server"); -+ ret = EIO; -+ goto done; -+ } -+ -+ ret = sbus_parse_reply(reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, -+ &servers, &num_servers); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ if (num_servers == 0) { -+ puts(_("None so far.\n")); -+ continue; -+ } -+ -+ for (j = 0; j < num_servers; j++) { -+ printf("- %s\n", servers[j]); -+ } -+ -+ printf("\n"); -+ } -+ -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ - struct sssctl_domain_status_opts { - const char *domain; - int online; -@@ -135,11 +284,8 @@ errno_t sssctl_domain_status(struct sss_cmdline *cmdline, - /* Parse command line. */ - struct poptOption options[] = { - {"online", 'o', POPT_ARG_NONE , &opts.online, 0, _("Show online status"), NULL }, -- /* -- {"last-requests", 'l', POPT_ARG_NONE, &opts.last, 0, _("Show last requests that went to data provider"), NULL }, - {"active-server", 'a', POPT_ARG_NONE, &opts.active, 0, _("Show information about active server"), NULL }, - {"servers", 'r', POPT_ARG_NONE, &opts.servers, 0, _("Show list of discovered servers"), NULL }, -- */ - {"start", 's', POPT_ARG_NONE, &opts.force_start, 0, _("Start SSSD if it is not running"), NULL }, - POPT_TABLEEND - }; -@@ -175,10 +321,32 @@ errno_t sssctl_domain_status(struct sss_cmdline *cmdline, - return EFAULT; - } - -- ret = sssctl_domain_status_online(tool_ctx, sifp, path); -- if (ret != EOK) { -- fprintf(stderr, _("Unable to get online status\n")); -- return ret; -+ if (opts.online) { -+ ret = sssctl_domain_status_online(tool_ctx, sifp, path); -+ if (ret != EOK) { -+ fprintf(stderr, _("Unable to get online status\n")); -+ return ret; -+ } -+ -+ printf("\n"); -+ } -+ -+ if (opts.active) { -+ ret = sssctl_domain_status_active_server(tool_ctx, sifp, path); -+ if (ret != EOK) { -+ fprintf(stderr, _("Unable to get online status\n")); -+ return ret; -+ } -+ -+ printf("\n"); -+ } -+ -+ if (opts.servers) { -+ ret = sssctl_domain_status_server_list(tool_ctx, sifp, path); -+ if (ret != EOK) { -+ fprintf(stderr, _("Unable to get server list\n")); -+ return ret; -+ } - } - - return EOK; --- -2.4.11 - diff --git a/SOURCES/0097-responders-do-not-leak-selinux-context-on-clients-de.patch b/SOURCES/0097-responders-do-not-leak-selinux-context-on-clients-de.patch new file mode 100644 index 0000000..a38530b --- /dev/null +++ b/SOURCES/0097-responders-do-not-leak-selinux-context-on-clients-de.patch @@ -0,0 +1,69 @@ +From 3a07827a3722fd2166b94af1f5790273fbac01eb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Mon, 3 Apr 2017 12:56:01 +0200 +Subject: [PATCH 97/99] responders: do not leak selinux context on clients + destruction +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The SELinux context created in get_client_cred is not talloc bound and +we were leaking it if available with each client's destruction. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3360 + +Reviewed-by: Lukáš Slebodník +(cherry picked from commit 05c2c3047912fca1c1a35ab1c8d3157b05383495) +--- + src/responder/common/responder_common.c | 20 +++++++++++++++++++- + 1 file changed, 19 insertions(+), 1 deletion(-) + +diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c +index 154d7dc7718c437d10e152fcba98161e2034fb14..67e1deefdfde19c95a68029b11099579d851513f 100644 +--- a/src/responder/common/responder_common.c ++++ b/src/responder/common/responder_common.c +@@ -97,7 +97,7 @@ static errno_t get_client_cred(struct cli_ctx *cctx) + SEC_CTX secctx; + int ret; + +- cctx->creds = talloc(cctx, struct cli_creds); ++ cctx->creds = talloc_zero(cctx, struct cli_creds); + if (!cctx->creds) return ENOMEM; + + #ifdef HAVE_UCRED +@@ -464,6 +464,22 @@ static void client_fd_handler(struct tevent_context *ev, + + static errno_t setup_client_idle_timer(struct cli_ctx *cctx); + ++static int cli_ctx_destructor(struct cli_ctx *cctx) ++{ ++ if (cctx->creds == NULL) { ++ return 0; ++ } ++ ++ if (cctx->creds->selinux_ctx == NULL) { ++ return 0; ++ } ++ ++ SELINUX_context_free(cctx->creds->selinux_ctx); ++ cctx->creds->selinux_ctx = NULL; ++ ++ return 0; ++} ++ + struct accept_fd_ctx { + struct resp_ctx *rctx; + bool is_private; +@@ -520,6 +536,8 @@ static void accept_fd_handler(struct tevent_context *ev, + return; + } + ++ talloc_set_destructor(cctx, cli_ctx_destructor); ++ + len = sizeof(cctx->addr); + cctx->cfd = accept(fd, (struct sockaddr *)&cctx->addr, &len); + if (cctx->cfd == -1) { +-- +2.9.3 + diff --git a/SOURCES/0097-sifp-fix-coverity-warning.patch b/SOURCES/0097-sifp-fix-coverity-warning.patch deleted file mode 100644 index 6a761a7..0000000 --- a/SOURCES/0097-sifp-fix-coverity-warning.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 87f7c2f1f44085963b41eb78e337840ddbc7be76 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Thu, 14 Jul 2016 10:49:37 +0200 -Subject: [PATCH 097/102] sifp: fix coverity warning -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -sssd-1.14.1/src/lib/sifp/sss_sifp_dbus.c:51: check_return: - Calling "dbus_message_append_args_valist" without checking return value - (as is done elsewhere 4 out of 5 times). - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Jakub Hrozek -(cherry picked from commit de5160e354c02020f0593c7cabdb811107d5d8e2) ---- - src/lib/sifp/sss_sifp_dbus.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/src/lib/sifp/sss_sifp_dbus.c b/src/lib/sifp/sss_sifp_dbus.c -index 7c72c52f0d226ccdfaf7b8ffaed7776647a7771c..2906c5ac383c412231127f6ffa8081d47eb2bced 100644 ---- a/src/lib/sifp/sss_sifp_dbus.c -+++ b/src/lib/sifp/sss_sifp_dbus.c -@@ -36,6 +36,7 @@ static sss_sifp_error sss_sifp_ifp_call(sss_sifp_ctx *ctx, - { - DBusMessage *msg = NULL; - sss_sifp_error ret; -+ dbus_bool_t bret; - - if (object_path == NULL || interface == NULL || method == NULL) { - return SSS_SIFP_INVALID_ARGUMENT; -@@ -48,7 +49,11 @@ static sss_sifp_error sss_sifp_ifp_call(sss_sifp_ctx *ctx, - } - - if (first_arg_type != DBUS_TYPE_INVALID) { -- dbus_message_append_args_valist(msg, first_arg_type, ap); -+ bret = dbus_message_append_args_valist(msg, first_arg_type, ap); -+ if (!bret) { -+ ret = SSS_SIFP_IO_ERROR; -+ goto done; -+ } - } - - ret = sss_sifp_send_message(ctx, msg, _reply); --- -2.4.11 - diff --git a/SOURCES/0098-ipa_s2n_get_acct_info_send-provide-correct-req_input.patch b/SOURCES/0098-ipa_s2n_get_acct_info_send-provide-correct-req_input.patch new file mode 100644 index 0000000..5a49b15 --- /dev/null +++ b/SOURCES/0098-ipa_s2n_get_acct_info_send-provide-correct-req_input.patch @@ -0,0 +1,89 @@ +From 250777f65dc23917c436d3ecf0fe21abc65db65e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Mon, 3 Apr 2017 12:09:44 +0200 +Subject: [PATCH 98/99] ipa_s2n_get_acct_info_send: provide correct req_input + name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To avoid crash. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3358 + +Reviewed-by: Sumit Bose +Reviewed-by: Lukáš Slebodník +(cherry picked from commit b07bcd8b99590bd404733fa7ff1add37c55126bc) +--- + src/providers/ipa/ipa_s2n_exop.c | 40 ++++++++++++++++++++++++++++++++++++---- + 1 file changed, 36 insertions(+), 4 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index 8a3391b4093f1547d84fe44a0f24b1d063d1e28c..2173db357700499a6140aa61841e443139981483 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -1054,6 +1054,33 @@ static const char *ipa_s2n_reqtype2str(enum request_types request_type) + return "Unknown request type"; + } + ++static const char *ipa_s2n_reqinp2str(TALLOC_CTX *mem_ctx, ++ struct req_input *req_input) ++{ ++ const char *str = NULL; ++ ++ switch (req_input->type) { ++ case REQ_INP_NAME: ++ str = talloc_strdup(mem_ctx, req_input->inp.name); ++ break; ++ case REQ_INP_SECID: ++ str = talloc_strdup(mem_ctx, req_input->inp.secid); ++ break; ++ case REQ_INP_CERT: ++ str = talloc_strdup(mem_ctx, req_input->inp.cert); ++ break; ++ case REQ_INP_ID: ++ str = talloc_asprintf(mem_ctx, "%u", req_input->inp.id); ++ break; ++ } ++ ++ if (str == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); ++ } ++ ++ return str; ++} ++ + struct ipa_s2n_get_list_state { + struct tevent_context *ev; + struct ipa_id_ctx *ipa_ctx; +@@ -1410,6 +1437,7 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx, + struct tevent_req *req; + struct tevent_req *subreq; + struct berval *bv_req = NULL; ++ const char *input; + int ret = EFAULT; + bool is_v1 = false; + +@@ -1454,10 +1482,14 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx, + goto fail; + } + +- DEBUG(SSSDBG_TRACE_FUNC, "Sending request_type: [%s] for trust user [%s] " +- "to IPA server\n", +- ipa_s2n_reqtype2str(state->request_type), +- req_input->inp.name); ++ if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) { ++ input = ipa_s2n_reqinp2str(state, req_input); ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Sending request_type: [%s] for trust user [%s] to IPA server\n", ++ ipa_s2n_reqtype2str(state->request_type), ++ input); ++ talloc_zfree(input); ++ } + + subreq = ipa_s2n_exop_send(state, state->ev, state->sh, is_v1, + state->exop_timeout, bv_req); +-- +2.9.3 + diff --git a/SOURCES/0098-sbus-allow-freeing-msg-through-dbus-api-when-using-t.patch b/SOURCES/0098-sbus-allow-freeing-msg-through-dbus-api-when-using-t.patch deleted file mode 100644 index 37be3b9..0000000 --- a/SOURCES/0098-sbus-allow-freeing-msg-through-dbus-api-when-using-t.patch +++ /dev/null @@ -1,112 +0,0 @@ -From efb18a2688546db9c6fe7ba75b595a2fc54dff41 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Fri, 15 Jul 2016 14:50:41 +0200 -Subject: [PATCH 098/102] sbus: allow freeing msg through dbus api when using - talloc -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When a talloc-bound message was freed by removing all references -to it with dbus_message_unref we failed to free the talloc context -and thus leaking memory or unreferencing invalid message when -the parent context is freed. - -This patch allows to bound dbus message to talloc in the way that -allows us to free the message by both talloc and dbus api. - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 5d556f70f00c43864d8495d7caacfadf962799df) ---- - src/sbus/sssd_dbus_utils.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 51 insertions(+) - -diff --git a/src/sbus/sssd_dbus_utils.c b/src/sbus/sssd_dbus_utils.c -index 4c33f9fd75cac2d4a56a5638982f8ecb73da8e2e..b0150e2fe7f829013677e0a4a894d1468e5b9128 100644 ---- a/src/sbus/sssd_dbus_utils.c -+++ b/src/sbus/sssd_dbus_utils.c -@@ -25,22 +25,52 @@ - - struct sbus_talloc_msg { - DBusMessage *msg; -+ dbus_int32_t data_slot; -+ bool in_talloc_destructor; - }; - - static int sbus_talloc_msg_destructor(struct sbus_talloc_msg *talloc_msg) - { -+ talloc_msg->in_talloc_destructor = true; -+ - if (talloc_msg->msg == NULL) { - return 0; - } - -+ /* There may exist more references to this message but this talloc -+ * context is no longer valid. We remove dbus message data to invoke -+ * dbus destructor now. */ -+ dbus_message_set_data(talloc_msg->msg, talloc_msg->data_slot, NULL, NULL); - dbus_message_unref(talloc_msg->msg); - return 0; - } - -+static void sbus_msg_data_destructor(void *ctx) -+{ -+ struct sbus_talloc_msg *talloc_msg; -+ -+ talloc_msg = talloc_get_type(ctx, struct sbus_talloc_msg); -+ -+ dbus_message_free_data_slot(&talloc_msg->data_slot); -+ -+ if (!talloc_msg->in_talloc_destructor) { -+ /* References to this message dropped to zero but through -+ * dbus_message_unref(), not by calling talloc_free(). We need to free -+ * the talloc context and avoid running talloc desctuctor. */ -+ talloc_set_destructor(talloc_msg, NULL); -+ talloc_free(talloc_msg); -+ } -+} -+ - errno_t sbus_talloc_bound_message(TALLOC_CTX *mem_ctx, DBusMessage *msg) - { - struct sbus_talloc_msg *talloc_msg; -+ dbus_int32_t data_slot = -1; -+ DBusFreeFunction free_fn; -+ dbus_bool_t bret; - -+ /* Create a talloc context that will unreference this message when -+ * the parent context is freed. */ - talloc_msg = talloc(mem_ctx, struct sbus_talloc_msg); - if (talloc_msg == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, -@@ -48,7 +78,28 @@ errno_t sbus_talloc_bound_message(TALLOC_CTX *mem_ctx, DBusMessage *msg) - return ENOMEM; - } - -+ /* Allocate a dbus message data slot that will contain point to the -+ * talloc context so we can pick up cases when the dbus message is -+ * freed through dbus api. */ -+ bret = dbus_message_allocate_data_slot(&data_slot); -+ if (!bret) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to allocate data slot!\n"); -+ talloc_free(talloc_msg); -+ return ENOMEM; -+ } -+ -+ free_fn = sbus_msg_data_destructor; -+ bret = dbus_message_set_data(msg, data_slot, talloc_msg, free_fn); -+ if (!bret) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set message data!\n"); -+ talloc_free(talloc_msg); -+ dbus_message_free_data_slot(&data_slot); -+ return ENOMEM; -+ } -+ - talloc_msg->msg = msg; -+ talloc_msg->data_slot = data_slot; -+ talloc_msg->in_talloc_destructor = false; - - talloc_set_destructor(talloc_msg, sbus_talloc_msg_destructor); - --- -2.4.11 - diff --git a/SOURCES/0099-PROXY-Do-not-abuse-data-provider-interface.patch b/SOURCES/0099-PROXY-Do-not-abuse-data-provider-interface.patch deleted file mode 100644 index df4370b..0000000 --- a/SOURCES/0099-PROXY-Do-not-abuse-data-provider-interface.patch +++ /dev/null @@ -1,730 +0,0 @@ -From 4b23c3128726fe59e02d28352e37bb0ff7f97640 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Fri, 15 Jul 2016 14:20:32 +0200 -Subject: [PATCH 099/102] PROXY: Do not abuse data provider interface -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We want to use custom interface for proxy provider so we do not -abuse the data provider one. This way we gain more control over -it and we can remove the old interface entirely. - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit e07d700ed9daf0cf96607fa2d72978cb2431b794) ---- - Makefile.am | 6 +- - src/providers/dp_auth_util.c | 64 --------------- - src/providers/proxy/proxy.h | 2 + - src/providers/proxy/proxy_auth.c | 8 +- - src/providers/proxy/proxy_child.c | 119 +++++++++++++++------------- - src/providers/proxy/proxy_client.c | 108 +++++++++++-------------- - src/providers/proxy/proxy_iface.xml | 17 ++++ - src/providers/proxy/proxy_iface_generated.c | 80 +++++++++++++++++++ - src/providers/proxy/proxy_iface_generated.h | 71 +++++++++++++++++ - 9 files changed, 288 insertions(+), 187 deletions(-) - create mode 100644 src/providers/proxy/proxy_iface.xml - create mode 100644 src/providers/proxy/proxy_iface_generated.c - create mode 100644 src/providers/proxy/proxy_iface_generated.h - -diff --git a/Makefile.am b/Makefile.am -index 1837e36da7302cb51c0b90e51b762ce0a87cd65f..5d54838659e44fa446fc921d014e48ac91469b25 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -715,6 +715,7 @@ dist_noinst_HEADERS = \ - src/providers/ad/ad_domain_info.h \ - src/providers/ad/ad_subdomains.h \ - src/providers/proxy/proxy.h \ -+ src/providers/proxy/proxy_iface_generated.h \ - src/tools/tools_util.h \ - src/tools/sss_sync_ops.h \ - src/resolv/async_resolv.h \ -@@ -1197,6 +1198,7 @@ CODEGEN_XML = \ - $(srcdir)/src/monitor/monitor_iface.xml \ - $(srcdir)/src/providers/data_provider_iface.xml \ - $(srcdir)/src/providers/data_provider/dp_iface.xml \ -+ $(srcdir)/src/providers/proxy/proxy_iface.xml \ - $(srcdir)/src/responder/ifp/ifp_iface.xml - - SBUS_CODEGEN = src/sbus/sbus_codegen -@@ -3337,7 +3339,7 @@ libsss_proxy_la_SOURCES = \ - src/providers/proxy/proxy_netgroup.c \ - src/providers/proxy/proxy_services.c \ - src/providers/proxy/proxy_auth.c \ -- src/providers/data_provider_iface_generated.c \ -+ src/providers/proxy/proxy_iface_generated.c \ - $(NULL) - libsss_proxy_la_CFLAGS = \ - $(AM_CFLAGS) -@@ -3606,7 +3608,7 @@ gpo_child_LDADD = \ - - proxy_child_SOURCES = \ - src/providers/proxy/proxy_child.c \ -- src/providers/data_provider_iface_generated.c \ -+ src/providers/proxy/proxy_iface_generated.c \ - $(NULL) - proxy_child_CFLAGS = \ - $(AM_CFLAGS) \ -diff --git a/src/providers/dp_auth_util.c b/src/providers/dp_auth_util.c -index 8c09299b12c703ed703a025d1e8cfe5df2088eb2..35d22ab5f24ba2300889256f477a9ed856b69cb9 100644 ---- a/src/providers/dp_auth_util.c -+++ b/src/providers/dp_auth_util.c -@@ -321,67 +321,3 @@ bool dp_unpack_pam_response(DBusMessage *msg, struct pam_data *pd, DBusError *db - - return true; - } -- --void dp_id_callback(DBusPendingCall *pending, void *ptr) --{ -- DBusMessage *reply; -- DBusError dbus_error; -- dbus_bool_t ret; -- dbus_uint16_t dp_ver; -- int type; -- -- dbus_error_init(&dbus_error); -- -- reply = dbus_pending_call_steal_reply(pending); -- if (!reply) { -- /* reply should never be null. This function shouldn't be called -- * until reply is valid or timeout has occurred. If reply is NULL -- * here, something is seriously wrong and we should bail out. -- */ -- DEBUG(SSSDBG_FATAL_FAILURE, -- "Severe error. A reply callback was called but no" -- " reply was received and no timeout occurred\n"); -- -- /* FIXME: Destroy this connection ? */ -- goto done; -- } -- -- type = dbus_message_get_type(reply); -- switch (type) { -- case DBUS_MESSAGE_TYPE_METHOD_RETURN: -- ret = dbus_message_get_args(reply, &dbus_error, -- DBUS_TYPE_UINT16, &dp_ver, -- DBUS_TYPE_INVALID); -- if (!ret) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse message\n"); -- if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error); -- /* FIXME: Destroy this connection ? */ -- goto done; -- } -- -- DEBUG(SSSDBG_CONF_SETTINGS, -- "Got id ack and version (%d) from DP\n", dp_ver); -- -- break; -- -- case DBUS_MESSAGE_TYPE_ERROR: -- DEBUG(SSSDBG_FATAL_FAILURE,"The Monitor returned an error [%s]\n", -- dbus_message_get_error_name(reply)); -- /* Falling through to default intentionally*/ -- default: -- /* -- * Timeout or other error occurred or something -- * unexpected happened. -- * It doesn't matter which, because either way we -- * know that this connection isn't trustworthy. -- * We'll destroy it now. -- */ -- -- /* FIXME: Destroy this connection ? */ -- break; -- } -- --done: -- dbus_pending_call_unref(pending); -- dbus_message_unref(reply); --} -diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h -index 11c85c54ea64db7ad9feb163bd5a86f65ac0ea90..6f91782bb06ea8bbf3ac35052b840dd21300b96e 100644 ---- a/src/providers/proxy/proxy.h -+++ b/src/providers/proxy/proxy.h -@@ -42,6 +42,8 @@ - #include "sss_client/nss_compat.h" - #include - -+#define PROXY_CHILD_PATH "/org/freedesktop/sssd/proxychild" -+ - struct proxy_nss_ops { - enum nss_status (*getpwnam_r)(const char *name, struct passwd *result, - char *buffer, size_t buflen, int *errnop); -diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c -index 6e7139aaa5d45631fa08f265c54b66ab97555a64..2b3510c38b1cb265e3042425c373f39e524a71eb 100644 ---- a/src/providers/proxy/proxy_auth.c -+++ b/src/providers/proxy/proxy_auth.c -@@ -23,6 +23,7 @@ - */ - - #include "providers/proxy/proxy.h" -+#include "providers/proxy/proxy_iface_generated.h" - - struct pc_init_ctx; - -@@ -531,9 +532,9 @@ static struct tevent_req *proxy_pam_conv_send(TALLOC_CTX *mem_ctx, - state->pid = pid; - - msg = dbus_message_new_method_call(NULL, -- DP_PATH, -- DATA_PROVIDER_IFACE, -- DATA_PROVIDER_IFACE_PAMHANDLER); -+ PROXY_CHILD_PATH, -+ IFACE_PROXY_AUTH, -+ IFACE_PROXY_AUTH_PAM); - if (msg == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "dbus_message_new_method_call failed.\n"); - talloc_zfree(req); -@@ -847,4 +848,3 @@ proxy_pam_handler_recv(TALLOC_CTX *mem_ctx, - - return EOK; - } -- -diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c -index efd304d5aafd5e53792ef96b75d8aa0c908bbe13..b492adcb3b5efefc08e6eb9e069035aeff8d34df 100644 ---- a/src/providers/proxy/proxy_child.c -+++ b/src/providers/proxy/proxy_child.c -@@ -44,22 +44,10 @@ - #include "confdb/confdb.h" - #include "sbus/sssd_dbus.h" - #include "providers/proxy/proxy.h" -+#include "providers/proxy/proxy_iface_generated.h" - - #include "providers/backend.h" - --static int pc_pam_handler(struct sbus_request *dbus_req, void *user_data); -- --struct data_provider_iface pc_methods = { -- { &data_provider_iface_meta, 0 }, -- .RegisterService = NULL, -- .pamHandler = pc_pam_handler, -- .sudoHandler = NULL, -- .autofsHandler = NULL, -- .hostHandler = NULL, -- .getDomains = NULL, -- .getAccountInfo = NULL, --}; -- - struct pc_ctx { - struct tevent_context *ev; - struct confdb_ctx *cdb; -@@ -382,17 +370,71 @@ done: - exit(ret); - } - --int proxy_child_send_id(struct sbus_connection *conn, -- uint16_t version, -- uint32_t id); -+static void proxy_child_id_callback(DBusPendingCall *pending, void *ptr) -+{ -+ DBusMessage *reply; -+ errno_t ret; -+ -+ reply = dbus_pending_call_steal_reply(pending); -+ if (reply == NULL) { -+ /* reply should never be null. This function shouldn't be called -+ * until reply is valid or timeout has occurred. If reply is NULL -+ * here, something is seriously wrong and we should bail out. -+ */ -+ DEBUG(SSSDBG_FATAL_FAILURE, "Severe error. A reply callback was " -+ "called but no reply was received and no timeout occurred\n"); -+ goto done; -+ } -+ -+ ret = sbus_parse_reply(reply); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get ID ack [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ } -+ -+ DEBUG(SSSDBG_TRACE_FUNC, "Got id ack from proxy child\n"); -+ -+done: -+ dbus_pending_call_unref(pending); -+ dbus_message_unref(reply); -+} -+ -+static errno_t proxy_child_send_id(struct sbus_connection *conn, uint32_t id) -+{ -+ DBusMessage *msg; -+ errno_t ret; -+ -+ msg = sbus_create_message(NULL, NULL, PROXY_CHILD_PATH, IFACE_PROXY_CLIENT, -+ IFACE_PROXY_CLIENT_REGISTER, -+ DBUS_TYPE_UINT32, &id); -+ if (msg == NULL) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?!\n"); -+ return ENOMEM; -+ } -+ -+ DEBUG(SSSDBG_TRACE_FUNC, "Sending ID to Proxy Backend: (%"PRIu32")\n", id); -+ -+ ret = sbus_conn_send(conn, msg, 30000, proxy_child_id_callback, NULL, NULL); -+ -+ dbus_message_unref(msg); -+ -+ return ret; -+} -+ - static int proxy_cli_init(struct pc_ctx *ctx) - { - char *sbus_address; - int ret; - -+ static struct iface_proxy_auth iface_proxy_auth = { -+ { &iface_proxy_auth_meta, 0 }, -+ -+ .PAM = pc_pam_handler, -+ }; -+ - sbus_address = talloc_asprintf(ctx, "unix:path=%s/%s_%s", -- PIPE_PATH, PROXY_CHILD_PIPE, -- ctx->domain->name); -+ PIPE_PATH, PROXY_CHILD_PIPE, -+ ctx->domain->name); - if (sbus_address == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n"); - return ENOMEM; -@@ -404,13 +446,14 @@ static int proxy_cli_init(struct pc_ctx *ctx) - return ret; - } - -- ret = sbus_conn_register_iface(ctx->conn, &pc_methods.vtable, DP_PATH, ctx); -+ ret = sbus_conn_register_iface(ctx->conn, &iface_proxy_auth.vtable, -+ PROXY_CHILD_PATH, ctx); - if (ret != EOK) { - DEBUG(SSSDBG_FATAL_FAILURE, "Failed to export proxy.\n"); - return ret; - } - -- ret = proxy_child_send_id(ctx->conn, DATA_PROVIDER_VERSION, ctx->id); -+ ret = proxy_child_send_id(ctx->conn, ctx->id); - if (ret != EOK) { - DEBUG(SSSDBG_FATAL_FAILURE, "dp_common_send_id failed.\n"); - return ret; -@@ -419,42 +462,6 @@ static int proxy_cli_init(struct pc_ctx *ctx) - return EOK; - } - --int proxy_child_send_id(struct sbus_connection *conn, -- uint16_t version, -- uint32_t id) --{ -- DBusMessage *msg; -- dbus_bool_t ret; -- int retval; -- -- /* create the message */ -- msg = dbus_message_new_method_call(NULL, -- DP_PATH, -- DATA_PROVIDER_IFACE, -- DATA_PROVIDER_IFACE_REGISTERSERVICE); -- if (msg == NULL) { -- DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?!\n"); -- return ENOMEM; -- } -- -- DEBUG(SSSDBG_FUNC_DATA, "Sending ID to Proxy Backend: (%d,%"PRIu32")\n", -- version, id); -- -- ret = dbus_message_append_args(msg, -- DBUS_TYPE_UINT16, &version, -- DBUS_TYPE_UINT32, &id, -- DBUS_TYPE_INVALID); -- if (!ret) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n"); -- return EIO; -- } -- -- retval = sbus_conn_send(conn, msg, 30000, dp_id_callback, NULL, NULL); -- -- dbus_message_unref(msg); -- return retval; --} -- - int proxy_child_process_init(TALLOC_CTX *mem_ctx, const char *domain, - struct tevent_context *ev, struct confdb_ctx *cdb, - const char *pam_target, uint32_t id) -diff --git a/src/providers/proxy/proxy_client.c b/src/providers/proxy/proxy_client.c -index fc1735f2a101528a1edeaf3cf9c1118e4a21e937..74957caeec5bf50b5cb959d6f5b8ec1ca9ecba37 100644 ---- a/src/providers/proxy/proxy_client.c -+++ b/src/providers/proxy/proxy_client.c -@@ -22,24 +22,10 @@ - along with this program. If not, see . - */ - --#include "config.h" -- --#include "util/sss_format.h" -+#include "util/util.h" -+#include "providers/proxy/proxy_iface_generated.h" - #include "providers/proxy/proxy.h" - --static int client_registration(struct sbus_request *dbus_req, void *data); -- --static struct data_provider_iface proxy_methods = { -- { &data_provider_iface_meta, 0 }, -- .RegisterService = client_registration, -- .pamHandler = NULL, -- .sudoHandler = NULL, -- .autofsHandler = NULL, -- .hostHandler = NULL, -- .getDomains = NULL, -- .getAccountInfo = NULL, --}; -- - struct proxy_client { - struct proxy_auth_ctx *proxy_auth_ctx; - struct sbus_connection *conn; -@@ -47,24 +33,22 @@ struct proxy_client { - bool initialized; - }; - --static int client_registration(struct sbus_request *dbus_req, void *data) -+static int proxy_client_register(struct sbus_request *sbus_req, -+ void *data, -+ uint32_t cli_id) - { -- dbus_uint16_t version = DATA_PROVIDER_VERSION; - struct sbus_connection *conn; - struct proxy_client *proxy_cli; -- dbus_uint16_t cli_ver; -- uint32_t cli_id; - int hret; - hash_key_t key; - hash_value_t value; - struct tevent_req *req; - struct proxy_child_ctx *child_ctx; - struct pc_init_ctx *init_ctx; -- int ret; - -- conn = dbus_req->conn; -+ conn = sbus_req->conn; - proxy_cli = talloc_get_type(data, struct proxy_client); -- if (!proxy_cli) { -+ if (proxy_cli == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE, "Connection holds no valid init data\n"); - return EINVAL; - } -@@ -74,14 +58,6 @@ static int client_registration(struct sbus_request *dbus_req, void *data) - "Cancel proxy client ID timeout [%p]\n", proxy_cli->timeout); - talloc_zfree(proxy_cli->timeout); - -- if (!sbus_request_parse_or_finish(dbus_req, -- DBUS_TYPE_UINT16, &cli_ver, -- DBUS_TYPE_UINT32, &cli_id, -- DBUS_TYPE_INVALID)) { -- sbus_disconnect(conn); -- return EOK; /* handled */ -- } -- - DEBUG(SSSDBG_FUNC_DATA, "Proxy client [%"PRIu32"] connected\n", cli_id); - - /* Check the hash table */ -@@ -94,20 +70,14 @@ static int client_registration(struct sbus_request *dbus_req, void *data) - return EIO; - } - -- /* reply that all is ok */ -- ret = sbus_request_return_and_finish(dbus_req, -- DBUS_TYPE_UINT16, &version, -- DBUS_TYPE_INVALID); -- if (ret != EOK) { -- sbus_disconnect(conn); -- return ret; -- } -+ iface_proxy_client_Register_finish(sbus_req); - - hret = hash_lookup(proxy_cli->proxy_auth_ctx->request_table, &key, &value); - if (hret != HASH_SUCCESS) { - DEBUG(SSSDBG_CRIT_FAILURE, -- "Hash error [%d][%s]\n", hret, hash_error_string(hret)); -+ "Hash error [%d]: %s\n", hret, hash_error_string(hret)); - sbus_disconnect(conn); -+ return EIO; - } - - /* Signal that the child is up and ready to receive the request */ -@@ -121,7 +91,7 @@ static int client_registration(struct sbus_request *dbus_req, void *data) - * break. - */ - DEBUG(SSSDBG_CRIT_FAILURE, "Client connection from a request " -- "that's not marked as running\n"); -+ "that's not marked as running\n"); - return EIO; - } - -@@ -133,9 +103,10 @@ static int client_registration(struct sbus_request *dbus_req, void *data) - return EOK; - } - --static void init_timeout(struct tevent_context *ev, -- struct tevent_timer *te, -- struct timeval t, void *ptr) -+static void proxy_client_timeout(struct tevent_context *ev, -+ struct tevent_timer *te, -+ struct timeval t, -+ void *ptr) - { - struct proxy_client *proxy_cli; - -@@ -155,38 +126,53 @@ static void init_timeout(struct tevent_context *ev, - - int proxy_client_init(struct sbus_connection *conn, void *data) - { -- struct proxy_auth_ctx *proxy_auth_ctx; -+ struct proxy_auth_ctx *auth_ctx; - struct proxy_client *proxy_cli; - struct timeval tv; -+ errno_t ret; - -- proxy_auth_ctx = talloc_get_type(data, struct proxy_auth_ctx); -+ static struct iface_proxy_client iface_proxy_client = { -+ { &iface_proxy_client_meta, 0 }, - -- /* hang off this memory to the connection so that when the connection -- * is freed we can potentially call a destructor */ -+ .Register = proxy_client_register, -+ }; - -+ auth_ctx = talloc_get_type(data, struct proxy_auth_ctx); -+ -+ /* When connection is lost we also free the client. */ - proxy_cli = talloc_zero(conn, struct proxy_client); -- if (!proxy_cli) { -- DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n"); -- talloc_zfree(conn); -+ if (proxy_cli == NULL) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory, killing connection.\n"); -+ talloc_free(conn); - return ENOMEM; - } -- proxy_cli->proxy_auth_ctx = proxy_auth_ctx; -+ -+ proxy_cli->proxy_auth_ctx = auth_ctx; - proxy_cli->conn = conn; - proxy_cli->initialized = false; - -- /* 5 seconds should be plenty */ -+ /* Setup timeout in case client fails to register himself in time. */ - tv = tevent_timeval_current_ofs(5, 0); -- -- proxy_cli->timeout = tevent_add_timer(proxy_auth_ctx->be->ev, proxy_cli, -- tv, init_timeout, proxy_cli); -- if (!proxy_cli->timeout) { -- DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n"); -- talloc_zfree(conn); -+ proxy_cli->timeout = tevent_add_timer(auth_ctx->be->ev, proxy_cli, tv, -+ proxy_client_timeout, proxy_cli); -+ if (proxy_cli->timeout == NULL) { -+ /* Connection is closed in the caller. */ -+ DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory, killing connection\n"); - return ENOMEM; - } -+ - DEBUG(SSSDBG_CONF_SETTINGS, - "Set-up proxy client ID timeout [%p]\n", proxy_cli->timeout); - -- return sbus_conn_register_iface(conn, &proxy_methods.vtable, -- DP_PATH, proxy_cli); -+ /* Setup D-Bus interfaces and methods. */ -+ ret = sbus_conn_register_iface(conn, &iface_proxy_client.vtable, -+ PROXY_CHILD_PATH, proxy_cli); -+ if (ret != EOK) { -+ /* Connection is closed in the caller. */ -+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to register D-Bus interface, " -+ "killing connection [%d]: %s\n", ret, sss_strerror(ret)); -+ return ret; -+ } -+ -+ return ret; - } -diff --git a/src/providers/proxy/proxy_iface.xml b/src/providers/proxy/proxy_iface.xml -new file mode 100644 -index 0000000000000000000000000000000000000000..39b0b03928661a1851fd739598b0194547441c2c ---- /dev/null -+++ b/src/providers/proxy/proxy_iface.xml -@@ -0,0 +1,17 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/src/providers/proxy/proxy_iface_generated.c b/src/providers/proxy/proxy_iface_generated.c -new file mode 100644 -index 0000000000000000000000000000000000000000..425727d1496b537eb25b002815d14e1f57b8f00d ---- /dev/null -+++ b/src/providers/proxy/proxy_iface_generated.c -@@ -0,0 +1,80 @@ -+/* The following definitions are auto-generated from proxy_iface.xml */ -+ -+#include "util/util.h" -+#include "sbus/sssd_dbus.h" -+#include "sbus/sssd_dbus_meta.h" -+#include "sbus/sssd_dbus_invokers.h" -+#include "proxy_iface_generated.h" -+ -+/* invokes a handler with a 'u' DBus signature */ -+static int invoke_u_method(struct sbus_request *dbus_req, void *function_ptr); -+ -+/* arguments for org.freedesktop.sssd.ProxyChild.Client.Register */ -+const struct sbus_arg_meta iface_proxy_client_Register__in[] = { -+ { "ID", "u" }, -+ { NULL, } -+}; -+ -+int iface_proxy_client_Register_finish(struct sbus_request *req) -+{ -+ return sbus_request_return_and_finish(req, -+ DBUS_TYPE_INVALID); -+} -+ -+/* methods for org.freedesktop.sssd.ProxyChild.Client */ -+const struct sbus_method_meta iface_proxy_client__methods[] = { -+ { -+ "Register", /* name */ -+ iface_proxy_client_Register__in, -+ NULL, /* no out_args */ -+ offsetof(struct iface_proxy_client, Register), -+ invoke_u_method, -+ }, -+ { NULL, } -+}; -+ -+/* interface info for org.freedesktop.sssd.ProxyChild.Client */ -+const struct sbus_interface_meta iface_proxy_client_meta = { -+ "org.freedesktop.sssd.ProxyChild.Client", /* name */ -+ iface_proxy_client__methods, -+ NULL, /* no signals */ -+ NULL, /* no properties */ -+ sbus_invoke_get_all, /* GetAll invoker */ -+}; -+ -+/* methods for org.freedesktop.sssd.ProxyChild.Auth */ -+const struct sbus_method_meta iface_proxy_auth__methods[] = { -+ { -+ "PAM", /* name */ -+ NULL, /* no in_args */ -+ NULL, /* no out_args */ -+ offsetof(struct iface_proxy_auth, PAM), -+ NULL, /* no invoker */ -+ }, -+ { NULL, } -+}; -+ -+/* interface info for org.freedesktop.sssd.ProxyChild.Auth */ -+const struct sbus_interface_meta iface_proxy_auth_meta = { -+ "org.freedesktop.sssd.ProxyChild.Auth", /* name */ -+ iface_proxy_auth__methods, -+ NULL, /* no signals */ -+ NULL, /* no properties */ -+ sbus_invoke_get_all, /* GetAll invoker */ -+}; -+ -+/* invokes a handler with a 'u' DBus signature */ -+static int invoke_u_method(struct sbus_request *dbus_req, void *function_ptr) -+{ -+ uint32_t arg_0; -+ int (*handler)(struct sbus_request *, void *, uint32_t) = function_ptr; -+ -+ if (!sbus_request_parse_or_finish(dbus_req, -+ DBUS_TYPE_UINT32, &arg_0, -+ DBUS_TYPE_INVALID)) { -+ return EOK; /* request handled */ -+ } -+ -+ return (handler)(dbus_req, dbus_req->intf->handler_data, -+ arg_0); -+} -diff --git a/src/providers/proxy/proxy_iface_generated.h b/src/providers/proxy/proxy_iface_generated.h -new file mode 100644 -index 0000000000000000000000000000000000000000..7af074fa3d839263318ceac7ea34f62dcde64563 ---- /dev/null -+++ b/src/providers/proxy/proxy_iface_generated.h -@@ -0,0 +1,71 @@ -+/* The following declarations are auto-generated from proxy_iface.xml */ -+ -+#ifndef __PROXY_IFACE_XML__ -+#define __PROXY_IFACE_XML__ -+ -+#include "sbus/sssd_dbus.h" -+ -+/* ------------------------------------------------------------------------ -+ * DBus Constants -+ * -+ * Various constants of interface and method names mostly for use by clients -+ */ -+ -+/* constants for org.freedesktop.sssd.ProxyChild.Client */ -+#define IFACE_PROXY_CLIENT "org.freedesktop.sssd.ProxyChild.Client" -+#define IFACE_PROXY_CLIENT_REGISTER "Register" -+ -+/* constants for org.freedesktop.sssd.ProxyChild.Auth */ -+#define IFACE_PROXY_AUTH "org.freedesktop.sssd.ProxyChild.Auth" -+#define IFACE_PROXY_AUTH_PAM "PAM" -+ -+/* ------------------------------------------------------------------------ -+ * DBus handlers -+ * -+ * These structures are filled in by implementors of the different -+ * dbus interfaces to handle method calls. -+ * -+ * Handler functions of type sbus_msg_handler_fn accept raw messages, -+ * other handlers are typed appropriately. If a handler that is -+ * set to NULL is invoked it will result in a -+ * org.freedesktop.DBus.Error.NotSupported error for the caller. -+ * -+ * Handlers have a matching xxx_finish() function (unless the method has -+ * accepts raw messages). These finish functions the -+ * sbus_request_return_and_finish() with the appropriate arguments to -+ * construct a valid reply. Once a finish function has been called, the -+ * @dbus_req it was called with is freed and no longer valid. -+ */ -+ -+/* vtable for org.freedesktop.sssd.ProxyChild.Client */ -+struct iface_proxy_client { -+ struct sbus_vtable vtable; /* derive from sbus_vtable */ -+ int (*Register)(struct sbus_request *req, void *data, uint32_t arg_ID); -+}; -+ -+/* finish function for Register */ -+int iface_proxy_client_Register_finish(struct sbus_request *req); -+ -+/* vtable for org.freedesktop.sssd.ProxyChild.Auth */ -+struct iface_proxy_auth { -+ struct sbus_vtable vtable; /* derive from sbus_vtable */ -+ sbus_msg_handler_fn PAM; -+}; -+ -+/* ------------------------------------------------------------------------ -+ * DBus Interface Metadata -+ * -+ * These structure definitions are filled in with the information about -+ * the interfaces, methods, properties and so on. -+ * -+ * The actual definitions are found in the accompanying C file next -+ * to this header. -+ */ -+ -+/* interface info for org.freedesktop.sssd.ProxyChild.Client */ -+extern const struct sbus_interface_meta iface_proxy_client_meta; -+ -+/* interface info for org.freedesktop.sssd.ProxyChild.Auth */ -+extern const struct sbus_interface_meta iface_proxy_auth_meta; -+ -+#endif /* __PROXY_IFACE_XML__ */ --- -2.4.11 - diff --git a/SOURCES/0099-config-check-Message-when-sssd.conf-is-missing.patch b/SOURCES/0099-config-check-Message-when-sssd.conf-is-missing.patch new file mode 100644 index 0000000..2862d4d --- /dev/null +++ b/SOURCES/0099-config-check-Message-when-sssd.conf-is-missing.patch @@ -0,0 +1,39 @@ +From be05d577626835e3c72d71fc60e6abfa564c7cbe Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Tue, 14 Mar 2017 15:43:41 +0100 +Subject: [PATCH 99/99] config-check: Message when sssd.conf is missing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +sssctl config-check should print a message for user +if no sssd.conf was found. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3330 + +Reviewed-by: Lukáš Slebodník +(cherry picked from commit 955574eeb3a3b937abc3df150e9bbbb79b75c889) +--- + src/tools/sssctl/sssctl_config.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/tools/sssctl/sssctl_config.c b/src/tools/sssctl/sssctl_config.c +index 630df3c8ff5368ef253bb9753380e94c8c0a307d..7e3ebf5428ce3fef232eee7334c7fd90e904b2d3 100644 +--- a/src/tools/sssctl/sssctl_config.c ++++ b/src/tools/sssctl/sssctl_config.c +@@ -63,7 +63,10 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline, + + /* Open config file */ + ret = sss_ini_config_file_open(init_data, SSSD_CONFIG_FILE); +- if (ret != EOK) { ++ if (ret == ENOENT) { ++ ERROR("File %1$s does not exist.\n", SSSD_CONFIG_FILE); ++ goto done; ++ } else if (ret != EOK) { + DEBUG(SSSDBG_TRACE_FUNC, + "sss_ini_config_file_open failed: %s [%d]\n", + sss_strerror(ret), +-- +2.9.3 + diff --git a/SOURCES/0100-DP-Remove-old-data-provider-interface.patch b/SOURCES/0100-DP-Remove-old-data-provider-interface.patch deleted file mode 100644 index db73927..0000000 --- a/SOURCES/0100-DP-Remove-old-data-provider-interface.patch +++ /dev/null @@ -1,1034 +0,0 @@ -From c2fe5c54faa92c670161d65fe5a1ff62acd4ac91 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Tue, 19 Jul 2016 14:24:16 +0200 -Subject: [PATCH 100/102] DP: Remove old data provider interface -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reverse data provider interface is moved to a better location in -NSS responder. All responders now can have an sbus interface -defined per data provider connection. The unused old data provider -interface is removed. - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 04e870d99e72aa3160bdb6ab05d986fb4005c3ed) ---- - Makefile.am | 11 +-- - src/providers/data_provider.h | 1 - - src/providers/data_provider/dp_target_id.c | 7 +- - src/providers/data_provider_iface.xml | 53 --------------- - src/providers/data_provider_iface_generated.c | 98 --------------------------- - src/providers/data_provider_iface_generated.h | 82 ---------------------- - src/responder/autofs/autofssrv.c | 13 +--- - src/responder/common/responder.h | 8 +-- - src/responder/common/responder_common.c | 16 +++-- - src/responder/common/responder_get_domains.c | 4 +- - src/responder/ifp/ifpsrv.c | 13 +--- - src/responder/nss/nss_iface.c | 38 +++++++++++ - src/responder/nss/nss_iface.h | 30 ++++++++ - src/responder/nss/nss_iface.xml | 12 ++++ - src/responder/nss/nss_iface_generated.c | 69 +++++++++++++++++++ - src/responder/nss/nss_iface_generated.h | 58 ++++++++++++++++ - src/responder/nss/nsssrv.c | 39 ++++------- - src/responder/nss/nsssrv.h | 7 ++ - src/responder/pac/pacsrv.c | 13 +--- - src/responder/pam/pamsrv.c | 13 +--- - src/responder/pam/pamsrv_dp.c | 4 +- - src/responder/ssh/sshsrv.c | 13 +--- - src/responder/sudo/sudosrv.c | 13 +--- - src/tests/cwrap/Makefile.am | 1 - - 24 files changed, 259 insertions(+), 357 deletions(-) - delete mode 100644 src/providers/data_provider_iface.xml - delete mode 100644 src/providers/data_provider_iface_generated.c - delete mode 100644 src/providers/data_provider_iface_generated.h - create mode 100644 src/responder/nss/nss_iface.c - create mode 100644 src/responder/nss/nss_iface.h - create mode 100644 src/responder/nss/nss_iface.xml - create mode 100644 src/responder/nss/nss_iface_generated.c - create mode 100644 src/responder/nss/nss_iface_generated.h - -diff --git a/Makefile.am b/Makefile.am -index 5d54838659e44fa446fc921d014e48ac91469b25..e2e4c4c08f66ef15684e1b3b1fe17bfae4e4131b 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -492,7 +492,6 @@ SSSD_RESPONDER_OBJ = \ - src/responder/common/data_provider/rdp_message.c \ - src/responder/common/data_provider/rdp_client.c \ - src/monitor/monitor_iface_generated.c \ -- src/providers/data_provider_iface_generated.c \ - src/providers/data_provider_req.c - - SSSD_TOOLS_OBJ = \ -@@ -610,6 +609,8 @@ dist_noinst_HEADERS = \ - src/responder/nss/nsssrv_netgroup.h \ - src/responder/nss/nsssrv_services.h \ - src/responder/nss/nsssrv_mmap_cache.h \ -+ src/responder/nss/nss_iface_generated.h \ -+ src/responder/nss/nss_iface.h \ - src/responder/pac/pacsrv.h \ - src/responder/common/negcache_files.h \ - src/responder/common/negcache.h \ -@@ -647,7 +648,6 @@ dist_noinst_HEADERS = \ - src/confdb/confdb_setup.h \ - src/providers/data_provider.h \ - src/providers/data_provider_req.h \ -- src/providers/data_provider_iface_generated.h \ - src/providers/data_provider/dp.h \ - src/providers/data_provider/dp_flags.h \ - src/providers/data_provider/dp_responder_iface.h \ -@@ -1196,10 +1196,10 @@ endif - CODEGEN_XML = \ - $(srcdir)/src/tests/sbus_codegen_tests.xml \ - $(srcdir)/src/monitor/monitor_iface.xml \ -- $(srcdir)/src/providers/data_provider_iface.xml \ - $(srcdir)/src/providers/data_provider/dp_iface.xml \ - $(srcdir)/src/providers/proxy/proxy_iface.xml \ -- $(srcdir)/src/responder/ifp/ifp_iface.xml -+ $(srcdir)/src/responder/ifp/ifp_iface.xml \ -+ $(srcdir)/src/responder/nss/nss_iface.xml - - SBUS_CODEGEN = src/sbus/sbus_codegen - -@@ -1248,6 +1248,8 @@ sssd_nss_SOURCES = \ - src/responder/nss/nsssrv_netgroup.c \ - src/responder/nss/nsssrv_services.c \ - src/responder/nss/nsssrv_mmap_cache.c \ -+ src/responder/nss/nss_iface_generated.c \ -+ src/responder/nss/nss_iface.c \ - $(SSSD_RESPONDER_OBJ) - sssd_nss_LDADD = \ - $(TDB_LIBS) \ -@@ -1411,7 +1413,6 @@ sssd_be_SOURCES = \ - src/providers/be_ptask.c \ - src/providers/be_refresh.c \ - src/monitor/monitor_iface_generated.c \ -- src/providers/data_provider_iface_generated.c \ - src/providers/data_provider/dp.c \ - src/providers/data_provider/dp_modules.c \ - src/providers/data_provider/dp_targets.c \ -diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h -index b0b6876d984d7c6574baaa8d130e374ba2e6f0c4..14a0902c265850d91fa7d29cc2708e70b060ec18 100644 ---- a/src/providers/data_provider.h -+++ b/src/providers/data_provider.h -@@ -44,7 +44,6 @@ - #include "sss_client/sss_cli.h" - #include "util/authtok.h" - #include "providers/data_provider_req.h" --#include "providers/data_provider_iface_generated.h" - - #define DATA_PROVIDER_VERSION 0x0001 - #define DATA_PROVIDER_PIPE "private/sbus-dp" -diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c -index 1b06cbe5b96f56c33dd048cf6211b7c97819db8c..938651545ea995091d0aaf29da12bbb8110c9add 100644 ---- a/src/providers/data_provider/dp_target_id.c -+++ b/src/providers/data_provider/dp_target_id.c -@@ -25,6 +25,7 @@ - #include "providers/data_provider/dp_private.h" - #include "providers/data_provider/dp_iface.h" - #include "providers/backend.h" -+#include "responder/nss/nss_iface.h" - #include "util/util.h" - - #define FILTER_TYPE(str, type) {str "=", sizeof(str "=") - 1, type} -@@ -168,9 +169,9 @@ static void dp_req_initgr_pp(const char *req_name, - } - - msg = dbus_message_new_method_call(NULL, -- DP_PATH, -- DATA_PROVIDER_REV_IFACE, -- DATA_PROVIDER_REV_IFACE_INITGRCHECK); -+ NSS_MEMORYCACHE_PATH, -+ IFACE_NSS_MEMORYCACHE, -+ IFACE_NSS_MEMORYCACHE_UPDATEINITGROUPS); - if (msg == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n"); - return; -diff --git a/src/providers/data_provider_iface.xml b/src/providers/data_provider_iface.xml -deleted file mode 100644 -index 143975633081ce2ae5690c4036e7169e41d776fc..0000000000000000000000000000000000000000 ---- a/src/providers/data_provider_iface.xml -+++ /dev/null -@@ -1,53 +0,0 @@ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -diff --git a/src/providers/data_provider_iface_generated.c b/src/providers/data_provider_iface_generated.c -deleted file mode 100644 -index bdd6a4d76d18bbb44530d816fce14009736b6f6d..0000000000000000000000000000000000000000 ---- a/src/providers/data_provider_iface_generated.c -+++ /dev/null -@@ -1,98 +0,0 @@ --/* The following definitions are auto-generated from data_provider_iface.xml */ -- --#include "util/util.h" --#include "sbus/sssd_dbus.h" --#include "sbus/sssd_dbus_meta.h" --#include "sbus/sssd_dbus_invokers.h" --#include "data_provider_iface_generated.h" -- --/* methods for org.freedesktop.sssd.dataprovider */ --const struct sbus_method_meta data_provider_iface__methods[] = { -- { -- "RegisterService", /* name */ -- NULL, /* no in_args */ -- NULL, /* no out_args */ -- offsetof(struct data_provider_iface, RegisterService), -- NULL, /* no invoker */ -- }, -- { -- "pamHandler", /* name */ -- NULL, /* no in_args */ -- NULL, /* no out_args */ -- offsetof(struct data_provider_iface, pamHandler), -- NULL, /* no invoker */ -- }, -- { -- "sudoHandler", /* name */ -- NULL, /* no in_args */ -- NULL, /* no out_args */ -- offsetof(struct data_provider_iface, sudoHandler), -- NULL, /* no invoker */ -- }, -- { -- "autofsHandler", /* name */ -- NULL, /* no in_args */ -- NULL, /* no out_args */ -- offsetof(struct data_provider_iface, autofsHandler), -- NULL, /* no invoker */ -- }, -- { -- "hostHandler", /* name */ -- NULL, /* no in_args */ -- NULL, /* no out_args */ -- offsetof(struct data_provider_iface, hostHandler), -- NULL, /* no invoker */ -- }, -- { -- "getDomains", /* name */ -- NULL, /* no in_args */ -- NULL, /* no out_args */ -- offsetof(struct data_provider_iface, getDomains), -- NULL, /* no invoker */ -- }, -- { -- "getAccountInfo", /* name */ -- NULL, /* no in_args */ -- NULL, /* no out_args */ -- offsetof(struct data_provider_iface, getAccountInfo), -- NULL, /* no invoker */ -- }, -- { NULL, } --}; -- --/* interface info for org.freedesktop.sssd.dataprovider */ --const struct sbus_interface_meta data_provider_iface_meta = { -- "org.freedesktop.sssd.dataprovider", /* name */ -- data_provider_iface__methods, -- NULL, /* no signals */ -- NULL, /* no properties */ -- sbus_invoke_get_all, /* GetAll invoker */ --}; -- --/* methods for org.freedesktop.sssd.dataprovider_rev */ --const struct sbus_method_meta data_provider_rev_iface__methods[] = { -- { -- "updateCache", /* name */ -- NULL, /* no in_args */ -- NULL, /* no out_args */ -- offsetof(struct data_provider_rev_iface, updateCache), -- NULL, /* no invoker */ -- }, -- { -- "initgrCheck", /* name */ -- NULL, /* no in_args */ -- NULL, /* no out_args */ -- offsetof(struct data_provider_rev_iface, initgrCheck), -- NULL, /* no invoker */ -- }, -- { NULL, } --}; -- --/* interface info for org.freedesktop.sssd.dataprovider_rev */ --const struct sbus_interface_meta data_provider_rev_iface_meta = { -- "org.freedesktop.sssd.dataprovider_rev", /* name */ -- data_provider_rev_iface__methods, -- NULL, /* no signals */ -- NULL, /* no properties */ -- sbus_invoke_get_all, /* GetAll invoker */ --}; -diff --git a/src/providers/data_provider_iface_generated.h b/src/providers/data_provider_iface_generated.h -deleted file mode 100644 -index 976e42b89c6aaf9523b16999b8f5103a1e6f8e66..0000000000000000000000000000000000000000 ---- a/src/providers/data_provider_iface_generated.h -+++ /dev/null -@@ -1,82 +0,0 @@ --/* The following declarations are auto-generated from data_provider_iface.xml */ -- --#ifndef __DATA_PROVIDER_IFACE_XML__ --#define __DATA_PROVIDER_IFACE_XML__ -- --#include "sbus/sssd_dbus.h" -- --/* ------------------------------------------------------------------------ -- * DBus Constants -- * -- * Various constants of interface and method names mostly for use by clients -- */ -- --/* constants for org.freedesktop.sssd.dataprovider */ --#define DATA_PROVIDER_IFACE "org.freedesktop.sssd.dataprovider" --#define DATA_PROVIDER_IFACE_REGISTERSERVICE "RegisterService" --#define DATA_PROVIDER_IFACE_PAMHANDLER "pamHandler" --#define DATA_PROVIDER_IFACE_SUDOHANDLER "sudoHandler" --#define DATA_PROVIDER_IFACE_AUTOFSHANDLER "autofsHandler" --#define DATA_PROVIDER_IFACE_HOSTHANDLER "hostHandler" --#define DATA_PROVIDER_IFACE_GETDOMAINS "getDomains" --#define DATA_PROVIDER_IFACE_GETACCOUNTINFO "getAccountInfo" -- --/* constants for org.freedesktop.sssd.dataprovider_rev */ --#define DATA_PROVIDER_REV_IFACE "org.freedesktop.sssd.dataprovider_rev" --#define DATA_PROVIDER_REV_IFACE_UPDATECACHE "updateCache" --#define DATA_PROVIDER_REV_IFACE_INITGRCHECK "initgrCheck" -- --/* ------------------------------------------------------------------------ -- * DBus handlers -- * -- * These structures are filled in by implementors of the different -- * dbus interfaces to handle method calls. -- * -- * Handler functions of type sbus_msg_handler_fn accept raw messages, -- * other handlers are typed appropriately. If a handler that is -- * set to NULL is invoked it will result in a -- * org.freedesktop.DBus.Error.NotSupported error for the caller. -- * -- * Handlers have a matching xxx_finish() function (unless the method has -- * accepts raw messages). These finish functions the -- * sbus_request_return_and_finish() with the appropriate arguments to -- * construct a valid reply. Once a finish function has been called, the -- * @dbus_req it was called with is freed and no longer valid. -- */ -- --/* vtable for org.freedesktop.sssd.dataprovider */ --struct data_provider_iface { -- struct sbus_vtable vtable; /* derive from sbus_vtable */ -- sbus_msg_handler_fn RegisterService; -- sbus_msg_handler_fn pamHandler; -- sbus_msg_handler_fn sudoHandler; -- sbus_msg_handler_fn autofsHandler; -- sbus_msg_handler_fn hostHandler; -- sbus_msg_handler_fn getDomains; -- sbus_msg_handler_fn getAccountInfo; --}; -- --/* vtable for org.freedesktop.sssd.dataprovider_rev */ --struct data_provider_rev_iface { -- struct sbus_vtable vtable; /* derive from sbus_vtable */ -- sbus_msg_handler_fn updateCache; -- sbus_msg_handler_fn initgrCheck; --}; -- --/* ------------------------------------------------------------------------ -- * DBus Interface Metadata -- * -- * These structure definitions are filled in with the information about -- * the interfaces, methods, properties and so on. -- * -- * The actual definitions are found in the accompanying C file next -- * to this header. -- */ -- --/* interface info for org.freedesktop.sssd.dataprovider */ --extern const struct sbus_interface_meta data_provider_iface_meta; -- --/* interface info for org.freedesktop.sssd.dataprovider_rev */ --extern const struct sbus_interface_meta data_provider_rev_iface_meta; -- --#endif /* __DATA_PROVIDER_IFACE_XML__ */ -diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c -index c72f3c1f7aee81a9986076975086cdd88e968edb..826a36e9bc0e2afedfda17104d15b86c5fc1b7e1 100644 ---- a/src/responder/autofs/autofssrv.c -+++ b/src/responder/autofs/autofssrv.c -@@ -44,17 +44,6 @@ struct mon_cli_iface monitor_autofs_methods = { - .sysbusReconnect = NULL, - }; - --static struct data_provider_iface autofs_dp_methods = { -- { &data_provider_iface_meta, 0 }, -- .RegisterService = NULL, -- .pamHandler = NULL, -- .sudoHandler = NULL, -- .autofsHandler = NULL, -- .hostHandler = NULL, -- .getDomains = NULL, -- .getAccountInfo = NULL, --}; -- - static errno_t - autofs_get_config(struct autofs_ctx *actx, - struct confdb_ctx *cdb) -@@ -130,7 +119,7 @@ autofs_process_init(TALLOC_CTX *mem_ctx, - SSS_AUTOFS_SBUS_SERVICE_VERSION, - &monitor_autofs_methods, - "autofs", -- &autofs_dp_methods.vtable, -+ NULL, - autofs_connection_setup, - &rctx); - if (ret != EOK) { -diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h -index 335b313ce1a6bc7c0e0ba332786e2e9f39a04ff1..9e3b2fdbda4e30b859df597374fc7d490b1720e5 100644 ---- a/src/responder/common/responder.h -+++ b/src/responder/common/responder.h -@@ -163,11 +163,7 @@ struct mon_cli_iface; - typedef int (*connection_setup_t)(struct cli_ctx *cctx); - - int sss_connection_setup(struct cli_ctx *cctx); --/* -- * NOTE: We would like to use more strong typing for the @dp_vtable argument -- * but can't since it accepts either a struct data_provider_iface -- * or struct data_provider_rev_iface. So pass the base struct: sbus_vtable -- */ -+ - int sss_process_init(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct confdb_ctx *cdb, -@@ -181,7 +177,7 @@ int sss_process_init(TALLOC_CTX *mem_ctx, - uint16_t svc_version, - struct mon_cli_iface *monitor_intf, - const char *cli_name, -- struct sbus_vtable *dp_intf, -+ struct sbus_iface_map *sbus_iface, - connection_setup_t conn_setup, - struct resp_ctx **responder_ctx); - -diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c -index 7f6264ae70e5073063b5cfcd73098eefad2ce653..c604c64a652221521ec7114b8588186f087eb11a 100644 ---- a/src/responder/common/responder_common.c -+++ b/src/responder/common/responder_common.c -@@ -549,7 +549,7 @@ void idle_handler(struct tevent_context *ev, - } - - static int sss_dp_init(struct resp_ctx *rctx, -- struct sbus_vtable *dp_intf, -+ struct sbus_iface_map *sbus_iface, - const char *cli_name, - struct sss_domain_info *domain) - { -@@ -577,10 +577,12 @@ static int sss_dp_init(struct resp_ctx *rctx, - return ret; - } - -- ret = sbus_conn_register_iface(be_conn->conn, dp_intf, DP_PATH, rctx); -- if (ret != EOK) { -- DEBUG(SSSDBG_FATAL_FAILURE, "Failed to export data provider.\n"); -- return ret; -+ if (sbus_iface != NULL) { -+ ret = sbus_conn_register_iface_map(be_conn->conn, sbus_iface, rctx); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to register D-Bus interface.\n"); -+ return ret; -+ } - } - - DLIST_ADD_END(rctx->be_conns, be_conn, struct be_conn *); -@@ -925,7 +927,7 @@ int sss_process_init(TALLOC_CTX *mem_ctx, - uint16_t svc_version, - struct mon_cli_iface *monitor_intf, - const char *cli_name, -- struct sbus_vtable *dp_intf, -+ struct sbus_iface_map *sbus_iface, - connection_setup_t conn_setup, - struct resp_ctx **responder_ctx) - { -@@ -1040,7 +1042,7 @@ int sss_process_init(TALLOC_CTX *mem_ctx, - continue; - } - -- ret = sss_dp_init(rctx, dp_intf, cli_name, dom); -+ ret = sss_dp_init(rctx, sbus_iface, cli_name, dom); - if (ret != EOK) { - DEBUG(SSSDBG_FATAL_FAILURE, - "fatal error setting up backend connector\n"); -diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c -index 6b354d8b2251f3a5cf576a58ae191fd99f307dd7..cc7b99f30046569547a08f83e46cbbe9d6c19897 100644 ---- a/src/responder/common/responder_get_domains.c -+++ b/src/responder/common/responder_get_domains.c -@@ -88,8 +88,8 @@ sss_dp_get_domains_msg(void *pvt) - - msg = dbus_message_new_method_call(NULL, - DP_PATH, -- DATA_PROVIDER_IFACE, -- DATA_PROVIDER_IFACE_GETDOMAINS); -+ IFACE_DP, -+ IFACE_DP_GETDOMAINS); - if (msg == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n"); - return NULL; -diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c -index a2137ecb218824909325df6c7052dbbbcb144679..0555c00167045707b7d455d28df368749b9b84f6 100644 ---- a/src/responder/ifp/ifpsrv.c -+++ b/src/responder/ifp/ifpsrv.c -@@ -58,17 +58,6 @@ struct mon_cli_iface monitor_ifp_methods = { - .sysbusReconnect = ifp_sysbus_reconnect, - }; - --static struct data_provider_iface ifp_dp_methods = { -- { &data_provider_iface_meta, 0 }, -- .RegisterService = NULL, -- .pamHandler = NULL, -- .sudoHandler = NULL, -- .autofsHandler = NULL, -- .hostHandler = NULL, -- .getDomains = NULL, -- .getAccountInfo = NULL, --}; -- - struct sss_cmd_table *get_ifp_cmds(void) - { - static struct sss_cmd_table ifp_cmds[] = { -@@ -238,7 +227,7 @@ int ifp_process_init(TALLOC_CTX *mem_ctx, - SSS_IFP_SBUS_SERVICE_VERSION, - &monitor_ifp_methods, - "InfoPipe", -- &ifp_dp_methods.vtable, -+ NULL, - sss_connection_setup, - &rctx); - if (ret != EOK) { -diff --git a/src/responder/nss/nss_iface.c b/src/responder/nss/nss_iface.c -new file mode 100644 -index 0000000000000000000000000000000000000000..b01732e086c5fc5c7018ec84c3438e19ed812fef ---- /dev/null -+++ b/src/responder/nss/nss_iface.c -@@ -0,0 +1,38 @@ -+/* -+ Authors: -+ Pavel Březina -+ -+ Copyright (C) 2016 Red Hat -+ -+ 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 . -+*/ -+ -+#include "sbus/sssd_dbus.h" -+#include "responder/nss/nss_iface.h" -+#include "responder/nss/nsssrv.h" -+ -+struct iface_nss_memorycache iface_nss_memorycache = { -+ { &iface_nss_memorycache_meta, 0 }, -+ .UpdateInitgroups = nss_memorycache_update_initgroups -+}; -+ -+static struct sbus_iface_map iface_map[] = { -+ { NSS_MEMORYCACHE_PATH, &iface_nss_memorycache.vtable }, -+ { NULL, NULL } -+}; -+ -+struct sbus_iface_map *nss_get_sbus_interface() -+{ -+ return iface_map; -+} -diff --git a/src/responder/nss/nss_iface.h b/src/responder/nss/nss_iface.h -new file mode 100644 -index 0000000000000000000000000000000000000000..ab59928c3e2dac62cea6f793ff774d9e0f8da6db ---- /dev/null -+++ b/src/responder/nss/nss_iface.h -@@ -0,0 +1,30 @@ -+/* -+ Authors: -+ Pavel Březina -+ -+ Copyright (C) 2016 Red Hat -+ -+ 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 . -+*/ -+ -+#ifndef _NSS_IFACE_H_ -+#define _NSS_IFACE_H_ -+ -+#include "responder/nss/nss_iface_generated.h" -+ -+#define NSS_MEMORYCACHE_PATH "/org/freedesktop/sssd/nss/memcache" -+ -+struct sbus_iface_map *nss_get_sbus_interface(void); -+ -+#endif /* _NSS_IFACE_H_ */ -diff --git a/src/responder/nss/nss_iface.xml b/src/responder/nss/nss_iface.xml -new file mode 100644 -index 0000000000000000000000000000000000000000..b7cc4deb77135a592bad2ca62570f206231129b7 ---- /dev/null -+++ b/src/responder/nss/nss_iface.xml -@@ -0,0 +1,12 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/src/responder/nss/nss_iface_generated.c b/src/responder/nss/nss_iface_generated.c -new file mode 100644 -index 0000000000000000000000000000000000000000..2d0031090e33df9c9e9d9fbf1a18825026509803 ---- /dev/null -+++ b/src/responder/nss/nss_iface_generated.c -@@ -0,0 +1,69 @@ -+/* The following definitions are auto-generated from nss_iface.xml */ -+ -+#include "util/util.h" -+#include "sbus/sssd_dbus.h" -+#include "sbus/sssd_dbus_meta.h" -+#include "sbus/sssd_dbus_invokers.h" -+#include "nss_iface_generated.h" -+ -+/* invokes a handler with a 'ssau' DBus signature */ -+static int invoke_ssau_method(struct sbus_request *dbus_req, void *function_ptr); -+ -+/* arguments for org.freedesktop.sssd.nss.MemoryCache.UpdateInitgroups */ -+const struct sbus_arg_meta iface_nss_memorycache_UpdateInitgroups__in[] = { -+ { "user", "s" }, -+ { "domain", "s" }, -+ { "groups", "au" }, -+ { NULL, } -+}; -+ -+int iface_nss_memorycache_UpdateInitgroups_finish(struct sbus_request *req) -+{ -+ return sbus_request_return_and_finish(req, -+ DBUS_TYPE_INVALID); -+} -+ -+/* methods for org.freedesktop.sssd.nss.MemoryCache */ -+const struct sbus_method_meta iface_nss_memorycache__methods[] = { -+ { -+ "UpdateInitgroups", /* name */ -+ iface_nss_memorycache_UpdateInitgroups__in, -+ NULL, /* no out_args */ -+ offsetof(struct iface_nss_memorycache, UpdateInitgroups), -+ invoke_ssau_method, -+ }, -+ { NULL, } -+}; -+ -+/* interface info for org.freedesktop.sssd.nss.MemoryCache */ -+const struct sbus_interface_meta iface_nss_memorycache_meta = { -+ "org.freedesktop.sssd.nss.MemoryCache", /* name */ -+ iface_nss_memorycache__methods, -+ NULL, /* no signals */ -+ NULL, /* no properties */ -+ sbus_invoke_get_all, /* GetAll invoker */ -+}; -+ -+/* invokes a handler with a 'ssau' DBus signature */ -+static int invoke_ssau_method(struct sbus_request *dbus_req, void *function_ptr) -+{ -+ const char * arg_0; -+ const char * arg_1; -+ uint32_t *arg_2; -+ int len_2; -+ int (*handler)(struct sbus_request *, void *, const char *, const char *, uint32_t[], int) = function_ptr; -+ -+ if (!sbus_request_parse_or_finish(dbus_req, -+ DBUS_TYPE_STRING, &arg_0, -+ DBUS_TYPE_STRING, &arg_1, -+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &arg_2, &len_2, -+ DBUS_TYPE_INVALID)) { -+ return EOK; /* request handled */ -+ } -+ -+ return (handler)(dbus_req, dbus_req->intf->handler_data, -+ arg_0, -+ arg_1, -+ arg_2, -+ len_2); -+} -diff --git a/src/responder/nss/nss_iface_generated.h b/src/responder/nss/nss_iface_generated.h -new file mode 100644 -index 0000000000000000000000000000000000000000..ad902482a9be03a60cbf3663b6f771d0a2020b88 ---- /dev/null -+++ b/src/responder/nss/nss_iface_generated.h -@@ -0,0 +1,58 @@ -+/* The following declarations are auto-generated from nss_iface.xml */ -+ -+#ifndef __NSS_IFACE_XML__ -+#define __NSS_IFACE_XML__ -+ -+#include "sbus/sssd_dbus.h" -+ -+/* ------------------------------------------------------------------------ -+ * DBus Constants -+ * -+ * Various constants of interface and method names mostly for use by clients -+ */ -+ -+/* constants for org.freedesktop.sssd.nss.MemoryCache */ -+#define IFACE_NSS_MEMORYCACHE "org.freedesktop.sssd.nss.MemoryCache" -+#define IFACE_NSS_MEMORYCACHE_UPDATEINITGROUPS "UpdateInitgroups" -+ -+/* ------------------------------------------------------------------------ -+ * DBus handlers -+ * -+ * These structures are filled in by implementors of the different -+ * dbus interfaces to handle method calls. -+ * -+ * Handler functions of type sbus_msg_handler_fn accept raw messages, -+ * other handlers are typed appropriately. If a handler that is -+ * set to NULL is invoked it will result in a -+ * org.freedesktop.DBus.Error.NotSupported error for the caller. -+ * -+ * Handlers have a matching xxx_finish() function (unless the method has -+ * accepts raw messages). These finish functions the -+ * sbus_request_return_and_finish() with the appropriate arguments to -+ * construct a valid reply. Once a finish function has been called, the -+ * @dbus_req it was called with is freed and no longer valid. -+ */ -+ -+/* vtable for org.freedesktop.sssd.nss.MemoryCache */ -+struct iface_nss_memorycache { -+ struct sbus_vtable vtable; /* derive from sbus_vtable */ -+ int (*UpdateInitgroups)(struct sbus_request *req, void *data, const char *arg_user, const char *arg_domain, uint32_t arg_groups[], int len_groups); -+}; -+ -+/* finish function for UpdateInitgroups */ -+int iface_nss_memorycache_UpdateInitgroups_finish(struct sbus_request *req); -+ -+/* ------------------------------------------------------------------------ -+ * DBus Interface Metadata -+ * -+ * These structure definitions are filled in with the information about -+ * the interfaces, methods, properties and so on. -+ * -+ * The actual definitions are found in the accompanying C file next -+ * to this header. -+ */ -+ -+/* interface info for org.freedesktop.sssd.nss.MemoryCache */ -+extern const struct sbus_interface_meta iface_nss_memorycache_meta; -+ -+#endif /* __NSS_IFACE_XML__ */ -diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c -index 8be3455e57e07481e7cf7d4d0f525dad5b8601fc..05b51ecdf2e17e20af2ee3ee48377cbe1bf19a24 100644 ---- a/src/responder/nss/nsssrv.c -+++ b/src/responder/nss/nsssrv.c -@@ -37,6 +37,7 @@ - #include "responder/nss/nsssrv_private.h" - #include "responder/nss/nsssrv_mmap_cache.h" - #include "responder/nss/nsssrv_netgroup.h" -+#include "responder/nss/nss_iface.h" - #include "responder/common/negcache.h" - #include "db/sysdb.h" - #include "confdb/confdb.h" -@@ -327,7 +328,7 @@ done: - return ret; - } - --static int nss_update_memcache(struct sbus_request *dbus_req, void *data) -+int nss_update_memcache(struct sbus_request *dbus_req, void *data) - { - struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx); - struct nss_ctx *nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx); -@@ -338,37 +339,24 @@ static int nss_update_memcache(struct sbus_request *dbus_req, void *data) - return EOK; - } - --static int nss_memcache_initgr_check(struct sbus_request *dbus_req, void *data) -+int nss_memorycache_update_initgroups(struct sbus_request *sbus_req, -+ void *data, -+ const char *user, -+ const char *domain, -+ uint32_t *groups, -+ int num_groups) - { - struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx); - struct nss_ctx *nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx); -- char *user; -- char *domain; -- uint32_t *groups; -- int gnum; - -- if (!sbus_request_parse_or_finish(dbus_req, -- DBUS_TYPE_STRING, &user, -- DBUS_TYPE_STRING, &domain, -- DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &groups, &gnum, -- DBUS_TYPE_INVALID)) { -- return EOK; /* handled */ -- } -+ DEBUG(SSSDBG_TRACE_LIBS, "Updating inigroups memory cache of [%s@%s]\n", -+ user, domain); - -- DEBUG(SSSDBG_TRACE_LIBS, -- "Got request for [%s@%s]\n", user, domain); -+ nss_update_initgr_memcache(nctx, user, domain, num_groups, groups); - -- nss_update_initgr_memcache(nctx, user, domain, gnum, groups); -- -- return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID); -+ return iface_nss_memorycache_UpdateInitgroups_finish(sbus_req); - } - --static struct data_provider_rev_iface nss_dp_methods = { -- { &data_provider_rev_iface_meta, 0 }, -- .updateCache = nss_update_memcache, -- .initgrCheck = nss_memcache_initgr_check --}; -- - static void nss_dp_reconnect_init(struct sbus_connection *conn, - int status, void *pvt) - { -@@ -419,7 +407,8 @@ int nss_process_init(TALLOC_CTX *mem_ctx, - NSS_SBUS_SERVICE_NAME, - NSS_SBUS_SERVICE_VERSION, - &monitor_nss_methods, -- "NSS", &nss_dp_methods.vtable, -+ "NSS", -+ nss_get_sbus_interface(), - nss_connection_setup, - &rctx); - if (ret != EOK) { -diff --git a/src/responder/nss/nsssrv.h b/src/responder/nss/nsssrv.h -index 2977479aa52082480f92eab94f7833e2e696a9ac..d4a80f76df236f40d872c701687bf453255d9890 100644 ---- a/src/responder/nss/nsssrv.h -+++ b/src/responder/nss/nsssrv.h -@@ -81,4 +81,11 @@ struct nss_packet; - - struct sss_cmd_table *get_nss_cmds(void); - -+int nss_memorycache_update_initgroups(struct sbus_request *sbus_req, -+ void *data, -+ const char *user, -+ const char *domain, -+ uint32_t *groups, -+ int num_groups); -+ - #endif /* __NSSSRV_H__ */ -diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c -index 15d1986f842ac8397cf509ca8ef44728d6ddc5f1..852deb10eff014189d35a2769d895a901d8296e1 100644 ---- a/src/responder/pac/pacsrv.c -+++ b/src/responder/pac/pacsrv.c -@@ -61,17 +61,6 @@ struct mon_cli_iface monitor_pac_methods = { - .sysbusReconnect = NULL, - }; - --static struct data_provider_iface pac_dp_methods = { -- { &data_provider_iface_meta, 0 }, -- .RegisterService = NULL, -- .pamHandler = NULL, -- .sudoHandler = NULL, -- .autofsHandler = NULL, -- .hostHandler = NULL, -- .getDomains = NULL, -- .getAccountInfo = NULL, --}; -- - /* TODO: check if this can be made generic for all responders */ - static void pac_dp_reconnect_init(struct sbus_connection *conn, - int status, void *pvt) -@@ -122,7 +111,7 @@ int pac_process_init(TALLOC_CTX *mem_ctx, - PAC_SBUS_SERVICE_NAME, - PAC_SBUS_SERVICE_VERSION, - &monitor_pac_methods, -- "PAC", &pac_dp_methods.vtable, -+ "PAC", NULL, - sss_connection_setup, - &rctx); - if (ret != EOK) { -diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c -index efd1e5c7527decda5de7304b54919846fa2ee0db..9374de4d63b2886262ca1541daff581603d7c838 100644 ---- a/src/responder/pam/pamsrv.c -+++ b/src/responder/pam/pamsrv.c -@@ -66,17 +66,6 @@ struct mon_cli_iface monitor_pam_methods = { - .sysbusReconnect = NULL, - }; - --static struct data_provider_iface pam_dp_methods = { -- { &data_provider_iface_meta, 0 }, -- .RegisterService = NULL, -- .pamHandler = NULL, -- .sudoHandler = NULL, -- .autofsHandler = NULL, -- .hostHandler = NULL, -- .getDomains = NULL, -- .getAccountInfo = NULL, --}; -- - static void pam_dp_reconnect_init(struct sbus_connection *conn, int status, void *pvt) - { - struct be_conn *be_conn = talloc_get_type(pvt, struct be_conn); -@@ -201,7 +190,7 @@ static int pam_process_init(TALLOC_CTX *mem_ctx, - SSS_PAM_SBUS_SERVICE_NAME, - SSS_PAM_SBUS_SERVICE_VERSION, - &monitor_pam_methods, -- "PAM", &pam_dp_methods.vtable, -+ "PAM", NULL, - sss_connection_setup, - &rctx); - if (ret != EOK) { -diff --git a/src/responder/pam/pamsrv_dp.c b/src/responder/pam/pamsrv_dp.c -index 826146350670d67f897ee7eec2cf6ca607b96435..aa3fdc3c32d234ed54a9f5202886157601ee3846 100644 ---- a/src/responder/pam/pamsrv_dp.c -+++ b/src/responder/pam/pamsrv_dp.c -@@ -130,8 +130,8 @@ int pam_dp_send_req(struct pam_auth_req *preq, int timeout) - - msg = dbus_message_new_method_call(NULL, - DP_PATH, -- DATA_PROVIDER_IFACE, -- DATA_PROVIDER_IFACE_PAMHANDLER); -+ IFACE_DP, -+ IFACE_DP_PAMHANDLER); - if (msg == NULL) { - DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n"); - return ENOMEM; -diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c -index f763e3b00d20527225046a85609e7ff56861f682..88938215b542b5748721cfecc59ca4141010fb88 100644 ---- a/src/responder/ssh/sshsrv.c -+++ b/src/responder/ssh/sshsrv.c -@@ -41,17 +41,6 @@ struct mon_cli_iface monitor_ssh_methods = { - .sysbusReconnect = NULL, - }; - --static struct data_provider_iface ssh_dp_methods = { -- { &data_provider_iface_meta, 0 }, -- .RegisterService = NULL, -- .pamHandler = NULL, -- .sudoHandler = NULL, -- .autofsHandler = NULL, -- .hostHandler = NULL, -- .getDomains = NULL, -- .getAccountInfo = NULL, --}; -- - static void ssh_dp_reconnect_init(struct sbus_connection *conn, - int status, void *pvt) - { -@@ -96,7 +85,7 @@ int ssh_process_init(TALLOC_CTX *mem_ctx, - SSS_SSH_SBUS_SERVICE_VERSION, - &monitor_ssh_methods, - "SSH", -- &ssh_dp_methods.vtable, -+ NULL, - sss_connection_setup, - &rctx); - if (ret != EOK) { -diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c -index e0346033e38f1e39e621e131c3265a583b91a5c3..d832686a8572f3729a0477cdca2f77ebcb19fbc0 100644 ---- a/src/responder/sudo/sudosrv.c -+++ b/src/responder/sudo/sudosrv.c -@@ -42,17 +42,6 @@ struct mon_cli_iface monitor_sudo_methods = { - .sysbusReconnect = NULL, - }; - --static struct data_provider_iface sudo_dp_methods = { -- { &data_provider_iface_meta, 0 }, -- .RegisterService = NULL, -- .pamHandler = NULL, -- .sudoHandler = NULL, -- .autofsHandler = NULL, -- .hostHandler = NULL, -- .getDomains = NULL, -- .getAccountInfo = NULL, --}; -- - static void sudo_dp_reconnect_init(struct sbus_connection *conn, - int status, - void *pvt) -@@ -98,7 +87,7 @@ int sudo_process_init(TALLOC_CTX *mem_ctx, - SSS_SUDO_SBUS_SERVICE_VERSION, - &monitor_sudo_methods, - "SUDO", -- &sudo_dp_methods.vtable, -+ NULL, - sss_connection_setup, - &rctx); - if (ret != EOK) { -diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am -index d8a49f1434cefc02bc7fce505d1b4e07fc74ec5f..3e40cba52e927730483b14cc7e56687b250de646 100644 ---- a/src/tests/cwrap/Makefile.am -+++ b/src/tests/cwrap/Makefile.am -@@ -49,7 +49,6 @@ SSSD_RESPONDER_OBJ = \ - ../../../src/responder/common/data_provider/rdp_message.c \ - ../../../src/responder/common/data_provider/rdp_client.c \ - ../../../src/monitor/monitor_iface_generated.c \ -- ../../../src/providers/data_provider_iface_generated.c \ - ../../../src/providers/data_provider_req.c - - dist_noinst_DATA = \ --- -2.4.11 - diff --git a/SOURCES/0100-sbus-check-connection-for-NULL-before-unregister-it.patch b/SOURCES/0100-sbus-check-connection-for-NULL-before-unregister-it.patch new file mode 100644 index 0000000..66fee16 --- /dev/null +++ b/SOURCES/0100-sbus-check-connection-for-NULL-before-unregister-it.patch @@ -0,0 +1,44 @@ +From 556eb1200a3754935f573ccffee87554bf9e9296 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 10 Apr 2017 13:45:27 +0200 +Subject: [PATCH 100/101] sbus: check connection for NULL before unregister it +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There seem to be code paths where the data is a added to the hash before +the connection is properly initialized, to avoid core dump during shut +down we only call dbus_conection_unregister_object_path() if there is a +connection. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3367 + +Reviewed-by: Pavel Březina +(cherry picked from commit 35186217d44d0138a1aedf7a4db72249b2c40e66) +--- + src/sbus/sssd_dbus_interface.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/sbus/sssd_dbus_interface.c b/src/sbus/sssd_dbus_interface.c +index 1a11c6abcf23053e3b8c77f4d469d7c202a88eb8..c9007a4814e09e26fedaf605ca7313234d5ebf2c 100644 +--- a/src/sbus/sssd_dbus_interface.c ++++ b/src/sbus/sssd_dbus_interface.c +@@ -490,7 +490,13 @@ sbus_opath_hash_delete_cb(hash_entry_t *item, + conn = talloc_get_type(pvt, struct sbus_connection); + path = sbus_opath_get_base_path(NULL, item->key.str); + +- dbus_connection_unregister_object_path(conn->dbus.conn, path); ++ /* There seem to be code paths where the data is added to the hash ++ * before the connection is properly initialized, to avoid core dump ++ * during shut down we only call dbus_connection_unregister_object_path() ++ * if there is a connection. */ ++ if (conn->dbus.conn != NULL) { ++ dbus_connection_unregister_object_path(conn->dbus.conn, path); ++ } + } + + hash_table_t * +-- +2.9.3 + diff --git a/SOURCES/0101-NSS-Remove-unused-functions.patch b/SOURCES/0101-NSS-Remove-unused-functions.patch deleted file mode 100644 index f7b683f..0000000 --- a/SOURCES/0101-NSS-Remove-unused-functions.patch +++ /dev/null @@ -1,187 +0,0 @@ -From 684ab7416ea1311a98516faddcc975a9731b2a0f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Tue, 19 Jul 2016 14:42:26 +0200 -Subject: [PATCH 101/102] NSS: Remove unused functions -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When removing the old data provider I noticed that those functions -are not used at all. - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit f31610a9ba26b46de9eeab2b0719ff6ad8961104) ---- - src/responder/nss/nsssrv.c | 11 ---- - src/responder/nss/nsssrv_cmd.c | 112 ------------------------------------- - src/responder/nss/nsssrv_private.h | 2 - - 3 files changed, 125 deletions(-) - -diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c -index 05b51ecdf2e17e20af2ee3ee48377cbe1bf19a24..06d58f21b00b73c6c7a4b7583e10b4b61a627d75 100644 ---- a/src/responder/nss/nsssrv.c -+++ b/src/responder/nss/nsssrv.c -@@ -328,17 +328,6 @@ done: - return ret; - } - --int nss_update_memcache(struct sbus_request *dbus_req, void *data) --{ -- struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx); -- struct nss_ctx *nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx); -- -- nss_update_pw_memcache(nctx); -- nss_update_gr_memcache(nctx); -- -- return EOK; --} -- - int nss_memorycache_update_initgroups(struct sbus_request *sbus_req, - void *data, - const char *user, -diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c -index 573959ea76fc1277fe84f40b88dcd34093da468d..b64cea2a53ec6032904237b0afc1377022c2c804 100644 ---- a/src/responder/nss/nsssrv_cmd.c -+++ b/src/responder/nss/nsssrv_cmd.c -@@ -118,66 +118,6 @@ static int nss_reset_negcache(struct resp_ctx *rctx) - * PASSWD db related functions - ***************************************************************************/ - --void nss_update_pw_memcache(struct nss_ctx *nctx) --{ -- struct sss_domain_info *dom; -- struct ldb_result *res; -- uint64_t exp; -- struct sized_string key; -- const char *id; -- time_t now; -- int ret; -- int i; -- -- now = time(NULL); -- -- for (dom = nctx->rctx->domains; dom; dom = get_next_domain(dom, 0)) { -- ret = sysdb_enumpwent_with_views(nctx, dom, &res); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Failed to enumerate users for domain [%s]\n", dom->name); -- continue; -- } -- -- for (i = 0; i < res->count; i++) { -- exp = ldb_msg_find_attr_as_uint64(res->msgs[i], -- SYSDB_CACHE_EXPIRE, 0); -- if (exp >= now) { -- continue; -- } -- -- /* names require more manipulation (build up fqname conditionally), -- * but uidNumber is unique and always resolvable too, so we use -- * that to update the cache, as it points to the same entry */ -- id = sss_view_ldb_msg_find_attr_as_string(dom, res->msgs[i], -- SYSDB_UIDNUM, NULL); -- if (!id) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Failed to find uidNumber in %s.\n", -- ldb_dn_get_linearized(res->msgs[i]->dn)); -- continue; -- } -- to_sized_string(&key, id); -- -- ret = sss_mmap_cache_pw_invalidate(nctx->pwd_mc_ctx, &key); -- if (ret != EOK && ret != ENOENT) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Internal failure in memory cache code: %d [%s]\n", -- ret, strerror(ret)); -- } -- -- ret = sss_mmap_cache_pw_invalidate(nctx->initgr_mc_ctx, &key); -- if (ret != EOK && ret != ENOENT) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Internal failure in memory cache code: %d [%s]\n", -- ret, strerror(ret)); -- } -- } -- -- talloc_zfree(res); -- } --} -- - static gid_t get_gid_override(struct ldb_message *msg, - struct sss_domain_info *dom) - { -@@ -2743,58 +2683,6 @@ done: - * GROUP db related functions - ***************************************************************************/ - --void nss_update_gr_memcache(struct nss_ctx *nctx) --{ -- struct sss_domain_info *dom; -- struct ldb_result *res; -- uint64_t exp; -- struct sized_string key; -- const char *id; -- time_t now; -- int ret; -- int i; -- -- now = time(NULL); -- -- for (dom = nctx->rctx->domains; dom; dom = get_next_domain(dom, 0)) { -- ret = sysdb_enumgrent_with_views(nctx, dom, &res); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Failed to enumerate users for domain [%s]\n", dom->name); -- continue; -- } -- -- for (i = 0; i < res->count; i++) { -- exp = ldb_msg_find_attr_as_uint64(res->msgs[i], -- SYSDB_CACHE_EXPIRE, 0); -- if (exp >= now) { -- continue; -- } -- -- /* names require more manipulation (build up fqname conditionally), -- * but uidNumber is unique and always resolvable too, so we use -- * that to update the cache, as it points to the same entry */ -- id = sss_view_ldb_msg_find_attr_as_string(dom, res->msgs[i], -- SYSDB_GIDNUM, NULL); -- if (!id) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Failed to find gidNumber in %s.\n", -- ldb_dn_get_linearized(res->msgs[i]->dn)); -- continue; -- } -- to_sized_string(&key, id); -- -- ret = sss_mmap_cache_gr_invalidate(nctx->grp_mc_ctx, &key); -- if (ret != EOK && ret != ENOENT) { -- DEBUG(SSSDBG_CRIT_FAILURE, -- "Internal failure in memory cache code: %d [%s]\n", -- ret, strerror(ret)); -- } -- } -- talloc_zfree(res); -- } --} -- - #define GID_ROFFSET 0 - #define MNUM_ROFFSET sizeof(uint32_t) - #define STRS_ROFFSET 2*sizeof(uint32_t) -diff --git a/src/responder/nss/nsssrv_private.h b/src/responder/nss/nsssrv_private.h -index 391eaaf40f84a7436bee63fd699241e4957fdbeb..472022235adab2c2d2547ee2706ef23fa91b1f8d 100644 ---- a/src/responder/nss/nsssrv_private.h -+++ b/src/responder/nss/nsssrv_private.h -@@ -143,8 +143,6 @@ errno_t check_cache(struct nss_dom_ctx *dctx, - sss_dp_callback_t callback, - void *pvt); - --void nss_update_pw_memcache(struct nss_ctx *nctx); --void nss_update_gr_memcache(struct nss_ctx *nctx); - void nss_update_initgr_memcache(struct nss_ctx *nctx, - const char *fq_name, const char *domain, - int gnum, uint32_t *groups); --- -2.4.11 - diff --git a/SOURCES/0101-selinux-Do-not-fail-if-SELinux-is-not-managed.patch b/SOURCES/0101-selinux-Do-not-fail-if-SELinux-is-not-managed.patch new file mode 100644 index 0000000..1ae6353 --- /dev/null +++ b/SOURCES/0101-selinux-Do-not-fail-if-SELinux-is-not-managed.patch @@ -0,0 +1,211 @@ +From 9b7c29b67ec845b2004d6bcac2bcceabfd855f1e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Wed, 8 Feb 2017 12:01:37 +0100 +Subject: [PATCH 101/101] selinux: Do not fail if SELinux is not managed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Previously we failed if semanage_is_managed returned 0 or -1 (not +managed or error). With this patch we only fail in case of error and +continue normally if selinux is not managed by libsemanage at all. + +Resolves: +https://fedorahosted.org/sssd/ticket/3297 + +Reviewed-by: Lukáš Slebodník +(cherry picked from commit 78a08d30b5fbf6e1e3b589e0cf67022e0c1faa33) +--- + Makefile.am | 1 + + src/providers/ipa/selinux_child.c | 9 ++++-- + src/util/sss_semanage.c | 61 +++++++++++++++++++++++++-------------- + src/util/util_errors.c | 1 + + src/util/util_errors.h | 1 + + 5 files changed, 49 insertions(+), 24 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index f5ac363a35e4aae51e8b70bad27c7fc824be10f2..370d6442ec58a14946ad288a23c696f25ca98f47 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -4040,6 +4040,7 @@ selinux_child_SOURCES = \ + src/util/atomic_io.c \ + src/util/util.c \ + src/util/util_ext.c \ ++ src/util/util_errors.c + $(NULL) + selinux_child_CFLAGS = \ + $(AM_CFLAGS) \ +diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c +index 380005c7ad3269fc8113c62ceef30b076455b5dd..f8dd3954a7244df2dcbb910aabf8888f41306c09 100644 +--- a/src/providers/ipa/selinux_child.c ++++ b/src/providers/ipa/selinux_child.c +@@ -174,14 +174,19 @@ static bool seuser_needs_update(struct input_buffer *ibuf) + + ret = get_seuser(ibuf, ibuf->username, &db_seuser, &db_mls_range); + DEBUG(SSSDBG_TRACE_INTERNAL, +- "get_seuser: ret: %d seuser: %s mls: %s\n", +- ret, db_seuser ? db_seuser : "unknown", ++ "get_seuser: ret: %d msg: [%s] seuser: %s mls: %s\n", ++ ret, sss_strerror(ret), ++ db_seuser ? db_seuser : "unknown", + db_mls_range ? db_mls_range : "unknown"); + if (ret == EOK && db_seuser && db_mls_range && + strcmp(db_seuser, ibuf->seuser) == 0 && + strcmp(db_mls_range, ibuf->mls_range) == 0) { + needs_update = false; + } ++ /* OR */ ++ if (ret == ERR_SELINUX_NOT_MANAGED) { ++ needs_update = false; ++ } + + talloc_free(db_seuser); + talloc_free(db_mls_range); +diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c +index fe06bee1dfec3abca3aa3cd5e85e55386ac11343..0da97aad4d8eba733b131c2749932e03ca4242c4 100644 +--- a/src/util/sss_semanage.c ++++ b/src/util/sss_semanage.c +@@ -73,7 +73,7 @@ static void sss_semanage_close(semanage_handle_t *handle) + semanage_handle_destroy(handle); + } + +-static semanage_handle_t *sss_semanage_init(void) ++static int sss_semanage_init(semanage_handle_t **_handle) + { + int ret; + semanage_handle_t *handle = NULL; +@@ -81,7 +81,8 @@ static semanage_handle_t *sss_semanage_init(void) + handle = semanage_handle_create(); + if (!handle) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n"); +- return NULL; ++ ret = EIO; ++ goto done; + } + + semanage_msg_set_callback(handle, +@@ -89,28 +90,41 @@ static semanage_handle_t *sss_semanage_init(void) + NULL); + + ret = semanage_is_managed(handle); +- if (ret != 1) { +- DEBUG(SSSDBG_CRIT_FAILURE, "SELinux policy not managed\n"); +- goto fail; ++ if (ret == 0) { ++ DEBUG(SSSDBG_TRACE_FUNC, "SELinux policy not managed via libsemanage\n"); ++ ret = ERR_SELINUX_NOT_MANAGED; ++ goto done; ++ } else if (ret == -1) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Call to semanage_is_managed failed\n"); ++ ret = EIO; ++ goto done; + } + + ret = semanage_access_check(handle); + if (ret < SEMANAGE_CAN_READ) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot read SELinux policy store\n"); +- goto fail; ++ ret = EACCES; ++ goto done; + } + + ret = semanage_connect(handle); + if (ret != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot estabilish SELinux management connection\n"); +- goto fail; ++ ret = EIO; ++ goto done; + } + +- return handle; +-fail: +- sss_semanage_close(handle); +- return NULL; ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ sss_semanage_close(handle); ++ } else { ++ *_handle = handle; ++ } ++ ++ return ret; + } + + static int sss_semanage_user_add(semanage_handle_t *handle, +@@ -228,10 +242,11 @@ int set_seuser(const char *login_name, const char *seuser_name, + return EOK; + } + +- handle = sss_semanage_init(); +- if (!handle) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init SELinux management\n"); +- ret = EIO; ++ ret = sss_semanage_init(&handle); ++ if (ret == ERR_SELINUX_NOT_MANAGED) { ++ goto done; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux handle\n"); + goto done; + } + +@@ -295,10 +310,11 @@ int del_seuser(const char *login_name) + int ret; + int exists = 0; + +- handle = sss_semanage_init(); +- if (!handle) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init SELinux management\n"); +- ret = EIO; ++ ret = sss_semanage_init(&handle); ++ if (ret == ERR_SELINUX_NOT_MANAGED) { ++ goto done; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux handle\n"); + goto done; + } + +@@ -377,10 +393,11 @@ int get_seuser(TALLOC_CTX *mem_ctx, const char *login_name, + semanage_seuser_t *sm_user = NULL; + semanage_seuser_key_t *sm_key = NULL; + +- sm_handle = sss_semanage_init(); +- if (sm_handle == NULL) { ++ ret = sss_semanage_init(&sm_handle); ++ if (ret == ERR_SELINUX_NOT_MANAGED) { ++ goto done; ++ } else if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux handle\n"); +- ret = EIO; + goto done; + } + +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index 466a3b4062f39b29d831a5d8a62dc8d576eb2e97..97eaf160f20bcc8cfe52254070a2d182e19addd4 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -75,6 +75,7 @@ struct err_string error_to_str[] = { + { "Cannot connect to system bus" }, /* ERR_NO_SYSBUS */ + { "LDAP search returned a referral" }, /* ERR_REFERRAL */ + { "Error setting SELinux user context" }, /* ERR_SELINUX_CONTEXT */ ++ { "SELinux is not managed by libsemanage" }, /* ERR_SELINUX_NOT_MANAGED */ + { "Username format not allowed by re_expression" }, /* ERR_REGEX_NOMATCH */ + { "Time specification not supported" }, /* ERR_TIMESPEC_NOT_SUPPORTED */ + { "Invalid SSSD configuration detected" }, /* ERR_INVALID_CONFIG */ +diff --git a/src/util/util_errors.h b/src/util/util_errors.h +index 2f90c0a5d65325a431a8e4d9a480170808c9198e..4a250bf0339ba689680c155fa8e6d43f42c2467e 100644 +--- a/src/util/util_errors.h ++++ b/src/util/util_errors.h +@@ -97,6 +97,7 @@ enum sssd_errors { + ERR_NO_SYSBUS, + ERR_REFERRAL, + ERR_SELINUX_CONTEXT, ++ ERR_SELINUX_NOT_MANAGED, + ERR_REGEX_NOMATCH, + ERR_TIMESPEC_NOT_SUPPORTED, + ERR_INVALID_CONFIG, +-- +2.9.3 + diff --git a/SOURCES/0102-LDAP-Fixing-of-removing-netgroup-from-cache.patch b/SOURCES/0102-LDAP-Fixing-of-removing-netgroup-from-cache.patch deleted file mode 100644 index 2932c7e..0000000 --- a/SOURCES/0102-LDAP-Fixing-of-removing-netgroup-from-cache.patch +++ /dev/null @@ -1,75 +0,0 @@ -From c0dedeccc42fa7cc14e207182d54595926dfd700 Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Fri, 22 Jul 2016 14:28:54 +0200 -Subject: [PATCH 102/102] LDAP: Fixing of removing netgroup from cache - -There were problem with local key which wasn't properly removed. -This patch fixes it. - -Resolves: -https://fedorahosted.org/sssd/ticket/2841 ---- - src/providers/ldap/sdap_async_netgroups.c | 40 +++++++++++++++++++++++++++++++ - 1 file changed, 40 insertions(+) - -diff --git a/src/providers/ldap/sdap_async_netgroups.c b/src/providers/ldap/sdap_async_netgroups.c -index df233d956df70cfcb5f68bd2afc9e2a23c50c3bb..cf7d7b12361f8cc578b891961c0c5566442f1b4e 100644 ---- a/src/providers/ldap/sdap_async_netgroups.c -+++ b/src/providers/ldap/sdap_async_netgroups.c -@@ -38,6 +38,35 @@ bool is_dn(const char *str) - return (ret == LDAP_SUCCESS ? true : false); - } - -+static errno_t add_to_missing_attrs(TALLOC_CTX * mem_ctx, -+ struct sysdb_attrs *attrs, -+ const char *ext_key, -+ char ***_missing) -+{ -+ bool is_present = false; -+ size_t size = 0; -+ size_t ret; -+ -+ for (int i = 0; i < attrs->num; i++) { -+ if (strcmp(ext_key, attrs->a[i].name) == 0) { -+ is_present = true; -+ } -+ size++; -+ } -+ -+ if (is_present == false) { -+ ret = add_string_to_list(attrs, ext_key, _missing); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ -+ ret = EOK; -+ -+done: -+ return ret; -+} -+ - static errno_t sdap_save_netgroup(TALLOC_CTX *memctx, - struct sss_domain_info *dom, - struct sdap_options *opts, -@@ -138,6 +167,17 @@ static errno_t sdap_save_netgroup(TALLOC_CTX *memctx, - goto fail; - } - -+ /* Prepare SYSDB_NETGROUP_MEMBER removing -+ * if not present in netgroup_attrs -+ */ -+ ret = add_to_missing_attrs(attrs, netgroup_attrs, SYSDB_NETGROUP_MEMBER, -+ &missing); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to add [%s] to missing attributes\n", -+ SYSDB_NETGROUP_MEMBER); -+ goto fail; -+ } -+ - ret = sysdb_add_netgroup(dom, name, NULL, netgroup_attrs, missing, - dom->netgroup_timeout, now); - if (ret) goto fail; --- -2.4.11 - diff --git a/SOURCES/0102-UTIL-Use-max-15-characters-for-AD-host-UPN.patch b/SOURCES/0102-UTIL-Use-max-15-characters-for-AD-host-UPN.patch new file mode 100644 index 0000000..c91d390 --- /dev/null +++ b/SOURCES/0102-UTIL-Use-max-15-characters-for-AD-host-UPN.patch @@ -0,0 +1,49 @@ +From b2dcfa00dcb7b315a739d35ff6722a25b0ab5556 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 14 Mar 2017 10:34:00 +0100 +Subject: [PATCH 102/102] UTIL: Use max 15 characters for AD host UPN +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We do not want to use host principal with AD +"host/name.domain.tld@DOMAIN.TLD" because it does not work. +We need to use correct user principal for AD hosts. And we cannot +rely all fallback "*$" because of other principals in keytab. + +The NetBIOS naming convention allows for 16 characters in a NetBIOS +name. Microsoft, however, limits NetBIOS names to 15 characters and +uses the 16th character as a NetBIOS suffix. +https://support.microsoft.com/en-us/help/163409/netbios-suffixes-16th-character-of-the-netbios-name + +Resolves: +https://pagure.io/SSSD/sssd/issue/3329 + +Reviewed-by: Michal Židek +(cherry picked from commit c6f1bc32774a7cf2f8678499dfbced420be3a3a1) +--- + src/util/sss_krb5.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c +index d461cf881566af37f31524c16f6a5f1511a5dc89..a3f066e8add5b7d7575c1e0f537c5729e4a0dad0 100644 +--- a/src/util/sss_krb5.c ++++ b/src/util/sss_krb5.c +@@ -51,7 +51,13 @@ sss_krb5_get_primary(TALLOC_CTX *mem_ctx, + *c = toupper(*c); + } + +- primary = talloc_asprintf(mem_ctx, "%s$", shortname); ++ /* The samAccountName is recommended to be less than 20 characters. ++ * This is only for users and groups. For machine accounts, ++ * the real limit is caused by NetBIOS protocol. ++ * NetBIOS names are limited to 16 (15 + $) ++ * https://support.microsoft.com/en-us/help/163409/netbios-suffixes-16th-character-of-the-netbios-name ++ */ ++ primary = talloc_asprintf(mem_ctx, "%.15s$", shortname); + talloc_free(shortname); + return primary; + } +-- +2.9.3 + diff --git a/SOURCES/0103-AD_PROVIDER-Add-ad_enabled_domains-option.patch b/SOURCES/0103-AD_PROVIDER-Add-ad_enabled_domains-option.patch deleted file mode 100644 index d31b96f..0000000 --- a/SOURCES/0103-AD_PROVIDER-Add-ad_enabled_domains-option.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 5377817417b800335c5ae21f7e6b301ddbcbe1d1 Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Fri, 13 May 2016 05:21:07 -0400 -Subject: [PATCH 103/108] AD_PROVIDER: Add ad_enabled_domains option -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: -https://fedorahosted.org/sssd/ticket/2828 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - src/config/SSSDConfig/__init__.py.in | 1 + - src/config/cfg_rules.ini | 1 + - src/config/etc/sssd.api.d/sssd-ad.conf | 1 + - src/man/sssd-ad.5.xml | 27 +++++++++++++++++++++++++++ - src/providers/ad/ad_common.h | 1 + - src/providers/ad/ad_opts.c | 1 + - 6 files changed, 32 insertions(+) - -diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in -index ac538788b9878dc2613cb48b7483d392cca41d47..1718a9babf390b95710ec356f25f09ea679bdd73 100644 ---- a/src/config/SSSDConfig/__init__.py.in -+++ b/src/config/SSSDConfig/__init__.py.in -@@ -192,6 +192,7 @@ option_strings = { - - # [provider/ad] - 'ad_domain' : _('Active Directory domain'), -+ 'ad_enabled_domains' : _('Enabled Active Directory domains'), - 'ad_server' : _('Active Directory server address'), - 'ad_backup_server' : _('Active Directory backup server address'), - 'ad_hostname' : _('Active Directory client hostname'), -diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini -index bd0116f334e2605e7671a208225761421511a75a..ef6435b08aee416e377fe854e6768f3fa4fd9650 100644 ---- a/src/config/cfg_rules.ini -+++ b/src/config/cfg_rules.ini -@@ -335,6 +335,7 @@ option = ad_access_filter - option = ad_backup_server - option = ad_domain - option = ad_enable_dns_sites -+option = ad_enabled_domains - option = ad_enable_gc - option = ad_gpo_access_control - option = ad_gpo_cache_timeout -diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf -index 87a74f4af0770874c71baaea02d2313721db78bf..8d97a416c8c97bff096042b0b70a3b2c18183710 100644 ---- a/src/config/etc/sssd.api.d/sssd-ad.conf -+++ b/src/config/etc/sssd.api.d/sssd-ad.conf -@@ -1,5 +1,6 @@ - [provider/ad] - ad_domain = str, None, false -+ad_enabled_domains = str, None, false - ad_server = str, None, false - ad_backup_server = str, None, false - ad_hostname = str, None, false -diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml -index ef27976dd62e164cfb91359efc69bd54e1aa9711..8a2f4ade9387f0d5723b7056bdce9e83363cf035 100644 ---- a/src/man/sssd-ad.5.xml -+++ b/src/man/sssd-ad.5.xml -@@ -114,6 +114,33 @@ ldap_id_mapping = False - - - -+ ad_enabled_domains (string) -+ -+ -+ A comma-separated list of enabled Active Directory domains. -+ If provided, SSSD will ignore any domains not listed in this -+ option. If left unset, all domains from the AD forest will -+ be available. -+ -+ -+ For proper operation, this option must be specified in all -+ lower-case and as the fully qualified domain name of the -+ Active Directory domain. For example: -+ -+ad_enabled_domains = sales.example.com, eng.example.com -+ -+ -+ -+ The short domain name (also known as the NetBIOS or the flat -+ name) will be autodetected by SSSD. -+ -+ -+ Default: Not set -+ -+ -+ -+ -+ - ad_server, ad_backup_server (string) - - -diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h -index 7e86faf1142d7be49eef01e1ddd7bfafea2fcedc..23351e328968918aa9ca9009c052e670a7d55258 100644 ---- a/src/providers/ad/ad_common.h -+++ b/src/providers/ad/ad_common.h -@@ -42,6 +42,7 @@ struct ad_options; - - enum ad_basic_opt { - AD_DOMAIN = 0, -+ AD_ENABLED_DOMAINS, - AD_SERVER, - AD_BACKUP_SERVER, - AD_HOSTNAME, -diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c -index 829f9d9556bc3fa74a95eb76db0e31b19befe8fe..fc1dc67337845754eba8c879c78e08c1777a4abc 100644 ---- a/src/providers/ad/ad_opts.c -+++ b/src/providers/ad/ad_opts.c -@@ -28,6 +28,7 @@ - - struct dp_option ad_basic_opts[] = { - { "ad_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING }, -+ { "ad_enabled_domains", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ad_server", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ad_backup_server", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ad_hostname", DP_OPT_STRING, NULL_STRING, NULL_STRING }, --- -2.4.11 - diff --git a/SOURCES/0103-Move-sized_output_name-and-sized_domain_name-into-re.patch b/SOURCES/0103-Move-sized_output_name-and-sized_domain_name-into-re.patch new file mode 100644 index 0000000..89b507c --- /dev/null +++ b/SOURCES/0103-Move-sized_output_name-and-sized_domain_name-into-re.patch @@ -0,0 +1,300 @@ +From 84be2901aeb36ac60760cc11c424b717df360e87 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 19 Apr 2017 17:44:40 +0200 +Subject: [PATCH 103/104] Move sized_output_name() and sized_domain_name() into + responder common code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +These functions are used to format a name into a format that the user +configured for output, including case sensitiveness, replacing +whitespace and qualified format. They were used only in the NSS +responder, which typically returns strings to the NSS client library and +then the user. + +But it makes sense to just reuse the same code in the IFP responder as +well, since it does essentially the same job. + +The patch also renames sized_member_name to sized_domain_name. +Previously, the function was only used to format a group member, the IFP +responder would use the same function to format a group the user is a +member of. + +Related to: + https://pagure.io/SSSD/sssd/issue/3268 + +Reviewed-by: Pavel Březina +(cherry picked from commit 7c074ba2f923985ab0d4f9d6a5e01ff3f2f0a7a8) +--- + src/responder/common/responder.h | 21 ++++++++ + src/responder/common/responder_common.c | 90 +++++++++++++++++++++++++++++++++ + src/responder/nss/nss_private.h | 11 ---- + src/responder/nss/nss_protocol_grent.c | 2 +- + src/responder/nss/nss_utils.c | 87 ------------------------------- + 5 files changed, 112 insertions(+), 99 deletions(-) + +diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h +index 4210307489fe25829a1674f254ecc7d185029698..dfe1ec455e355de263c3550306e53fea3ada85df 100644 +--- a/src/responder/common/responder.h ++++ b/src/responder/common/responder.h +@@ -393,4 +393,25 @@ char *sss_resp_create_fqname(TALLOC_CTX *mem_ctx, + + errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx); + ++/** ++ * Helper functions to format output names ++ */ ++ ++/* Format orig_name into a sized_string in output format as prescribed ++ * by the name_dom domain ++ */ ++int sized_output_name(TALLOC_CTX *mem_ctx, ++ struct resp_ctx *rctx, ++ const char *orig_name, ++ struct sss_domain_info *name_dom, ++ struct sized_string **_name); ++ ++/* Format orig_name into a sized_string in output format as prescribed ++ * by the domain read from the fully qualified name. ++ */ ++int sized_domain_name(TALLOC_CTX *mem_ctx, ++ struct resp_ctx *rctx, ++ const char *member_name, ++ struct sized_string **_name); ++ + #endif /* __SSS_RESPONDER_H__ */ +diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c +index 67e1deefdfde19c95a68029b11099579d851513f..ac6320b08de09bc6c7e8dd1af72e0a493a449f7a 100644 +--- a/src/responder/common/responder_common.c ++++ b/src/responder/common/responder_common.c +@@ -1651,3 +1651,93 @@ done: + + return ret; + } ++ ++/** ++ * Helper functions to format output names ++ */ ++int sized_output_name(TALLOC_CTX *mem_ctx, ++ struct resp_ctx *rctx, ++ const char *orig_name, ++ struct sss_domain_info *name_dom, ++ struct sized_string **_name) ++{ ++ TALLOC_CTX *tmp_ctx = NULL; ++ errno_t ret; ++ char *username; ++ struct sized_string *name; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ username = sss_output_name(tmp_ctx, orig_name, name_dom->case_preserve, ++ rctx->override_space); ++ if (username == NULL) { ++ ret = EIO; ++ goto done; ++ } ++ ++ if (name_dom->fqnames) { ++ username = sss_tc_fqname(tmp_ctx, name_dom->names, name_dom, username); ++ if (username == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "sss_replace_space failed\n"); ++ ret = EIO; ++ goto done; ++ } ++ } ++ ++ name = talloc_zero(tmp_ctx, struct sized_string); ++ if (name == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ to_sized_string(name, username); ++ name->str = talloc_steal(name, username); ++ *_name = talloc_steal(mem_ctx, name); ++ ret = EOK; ++done: ++ talloc_zfree(tmp_ctx); ++ return ret; ++} ++ ++int sized_domain_name(TALLOC_CTX *mem_ctx, ++ struct resp_ctx *rctx, ++ const char *member_name, ++ struct sized_string **_name) ++{ ++ TALLOC_CTX *tmp_ctx = NULL; ++ errno_t ret; ++ char *domname; ++ struct sss_domain_info *member_dom; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sss_parse_internal_fqname(tmp_ctx, member_name, NULL, &domname); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "sss_parse_internal_fqname failed\n"); ++ goto done; ++ } ++ ++ if (domname == NULL) { ++ ret = ERR_WRONG_NAME_FORMAT; ++ goto done; ++ } ++ ++ member_dom = find_domain_by_name(get_domains_head(rctx->domains), ++ domname, true); ++ if (member_dom == NULL) { ++ ret = ERR_DOMAIN_NOT_FOUND; ++ goto done; ++ } ++ ++ ret = sized_output_name(mem_ctx, rctx, member_name, ++ member_dom, _name); ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} +diff --git a/src/responder/nss/nss_private.h b/src/responder/nss/nss_private.h +index acb3c4aa504e538ca56dca8d43ee04b0f60954a9..13de83226177bbaa8b8237e3e27b7e72da369194 100644 +--- a/src/responder/nss/nss_private.h ++++ b/src/responder/nss/nss_private.h +@@ -140,17 +140,6 @@ const char * + nss_get_name_from_msg(struct sss_domain_info *domain, + struct ldb_message *msg); + +-int sized_output_name(TALLOC_CTX *mem_ctx, +- struct resp_ctx *rctx, +- const char *orig_name, +- struct sss_domain_info *name_dom, +- struct sized_string **_name); +- +-int sized_member_name(TALLOC_CTX *mem_ctx, +- struct resp_ctx *rctx, +- const char *member_name, +- struct sized_string **_name); +- + const char * + nss_get_pwfield(struct nss_ctx *nctx, + struct sss_domain_info *dom); +diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c +index 283ab9f6731bc4c8261ca79075ab030005bf70db..fae1d47d7b217beafba75740e2e6d9cb8cdbc1d0 100644 +--- a/src/responder/nss/nss_protocol_grent.c ++++ b/src/responder/nss/nss_protocol_grent.c +@@ -163,7 +163,7 @@ nss_protocol_fill_members(struct sss_packet *packet, + } + } + +- ret = sized_member_name(tmp_ctx, rctx, member_name, &name); ++ ret = sized_domain_name(tmp_ctx, rctx, member_name, &name); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Unable to get sized name [%d]: %s\n", + ret, sss_strerror(ret)); +diff --git a/src/responder/nss/nss_utils.c b/src/responder/nss/nss_utils.c +index f839930a275db56e8d729888af870562d7b6f260..2cd9c33b42f7e018ea89d2df206637f35646489e 100644 +--- a/src/responder/nss/nss_utils.c ++++ b/src/responder/nss/nss_utils.c +@@ -53,93 +53,6 @@ nss_get_name_from_msg(struct sss_domain_info *domain, + return ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); + } + +-int sized_output_name(TALLOC_CTX *mem_ctx, +- struct resp_ctx *rctx, +- const char *orig_name, +- struct sss_domain_info *name_dom, +- struct sized_string **_name) +-{ +- TALLOC_CTX *tmp_ctx = NULL; +- errno_t ret; +- char *username; +- struct sized_string *name; +- +- tmp_ctx = talloc_new(NULL); +- if (tmp_ctx == NULL) { +- return ENOMEM; +- } +- +- username = sss_output_name(tmp_ctx, orig_name, name_dom->case_preserve, +- rctx->override_space); +- if (username == NULL) { +- ret = EIO; +- goto done; +- } +- +- if (name_dom->fqnames) { +- username = sss_tc_fqname(tmp_ctx, name_dom->names, name_dom, username); +- if (username == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "sss_replace_space failed\n"); +- ret = EIO; +- goto done; +- } +- } +- +- name = talloc_zero(tmp_ctx, struct sized_string); +- if (name == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- to_sized_string(name, username); +- name->str = talloc_steal(name, username); +- *_name = talloc_steal(mem_ctx, name); +- ret = EOK; +-done: +- talloc_zfree(tmp_ctx); +- return ret; +-} +- +-int sized_member_name(TALLOC_CTX *mem_ctx, +- struct resp_ctx *rctx, +- const char *member_name, +- struct sized_string **_name) +-{ +- TALLOC_CTX *tmp_ctx = NULL; +- errno_t ret; +- char *domname; +- struct sss_domain_info *member_dom; +- +- tmp_ctx = talloc_new(NULL); +- if (tmp_ctx == NULL) { +- return ENOMEM; +- } +- +- ret = sss_parse_internal_fqname(tmp_ctx, member_name, NULL, &domname); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "sss_parse_internal_fqname failed\n"); +- goto done; +- } +- +- if (domname == NULL) { +- ret = ERR_WRONG_NAME_FORMAT; +- goto done; +- } +- +- member_dom = find_domain_by_name(get_domains_head(rctx->domains), +- domname, true); +- if (member_dom == NULL) { +- ret = ERR_DOMAIN_NOT_FOUND; +- goto done; +- } +- +- ret = sized_output_name(mem_ctx, rctx, member_name, +- member_dom, _name); +-done: +- talloc_free(tmp_ctx); +- return ret; +-} +- + const char * + nss_get_pwfield(struct nss_ctx *nctx, + struct sss_domain_info *dom) +-- +2.9.3 + diff --git a/SOURCES/0104-AD_PROVIDER-Initializing-of-ad_enabled_domains.patch b/SOURCES/0104-AD_PROVIDER-Initializing-of-ad_enabled_domains.patch deleted file mode 100644 index 9fa1c6c..0000000 --- a/SOURCES/0104-AD_PROVIDER-Initializing-of-ad_enabled_domains.patch +++ /dev/null @@ -1,143 +0,0 @@ -From 7e8b6166086cf04c5b1290c3dffd268438ef9c2c Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Tue, 21 Jun 2016 08:34:15 +0200 -Subject: [PATCH 104/108] AD_PROVIDER: Initializing of ad_enabled_domains -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We add ad_enabled_domains into ad_subdomains_ctx. - -Resolves: -https://fedorahosted.org/sssd/ticket/2828 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - src/providers/ad/ad_subdomains.c | 82 ++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 82 insertions(+) - -diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c -index a0d5c2e544fc62fda64771dce59b3b7ab8ecd8b6..6e44760330275f7e4262e6863f180747f659edb5 100644 ---- a/src/providers/ad/ad_subdomains.c -+++ b/src/providers/ad/ad_subdomains.c -@@ -57,6 +57,79 @@ - /* do not refresh more often than every 5 seconds for now */ - #define AD_SUBDOMAIN_REFRESH_LIMIT 5 - -+static errno_t ad_get_enabled_domains(TALLOC_CTX *mem_ctx, -+ struct ad_id_ctx *ad_id_ctx, -+ const char *ad_domain, -+ const char ***_ad_enabled_domains) -+{ -+ int ret; -+ const char *str; -+ const char *option_name; -+ const char **domains = NULL; -+ int count; -+ bool is_ad_in_domains; -+ TALLOC_CTX *tmp_ctx = NULL; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ str = dp_opt_get_cstring(ad_id_ctx->ad_options->basic, AD_ENABLED_DOMAINS); -+ if (str == NULL) { -+ *_ad_enabled_domains = NULL; -+ ret = EOK; -+ goto done; -+ } -+ -+ count = 0; -+ ret = split_on_separator(tmp_ctx, str, ',', true, true, -+ discard_const_p(char **, &domains), &count); -+ if (ret != EOK) { -+ option_name = ad_id_ctx->ad_options->basic[AD_ENABLED_DOMAINS].opt_name; -+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse option [%s], [%i] [%s]!\n", -+ option_name, ret, sss_strerror(ret)); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ is_ad_in_domains = false; -+ for (int i = 0; i < count; i++) { -+ is_ad_in_domains += strcmp(ad_domain, domains[i]) == 0 ? true : false; -+ } -+ -+ if (is_ad_in_domains == false) { -+ domains = talloc_realloc(tmp_ctx, domains, const char*, count + 2); -+ if (domains == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ domains[count] = talloc_strdup(domains, ad_domain); -+ if (domains[count] == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ domains[count + 1] = NULL; -+ } else { -+ domains = talloc_realloc(tmp_ctx, domains, const char*, count + 1); -+ if (domains == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ domains[count] = NULL; -+ } -+ -+ *_ad_enabled_domains = talloc_steal(mem_ctx, domains); -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -+ - static errno_t - ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, - struct ad_id_ctx *id_ctx, -@@ -171,6 +244,7 @@ struct ad_subdomains_ctx { - - struct sdap_domain *sdom; - char *domain_name; -+ const char **ad_enabled_domains; - - time_t last_refreshed; - }; -@@ -1357,6 +1431,7 @@ errno_t ad_subdomains_init(TALLOC_CTX *mem_ctx, - { - struct ad_subdomains_ctx *sd_ctx; - const char *ad_domain; -+ const char **ad_enabled_domains = NULL; - time_t period; - errno_t ret; - -@@ -1368,6 +1443,12 @@ errno_t ad_subdomains_init(TALLOC_CTX *mem_ctx, - return ENOMEM; - } - -+ ret = ad_get_enabled_domains(sd_ctx, ad_id_ctx, ad_domain, -+ &ad_enabled_domains); -+ if (ret != EOK) { -+ return EINVAL; -+ } -+ - sd_ctx->be_ctx = be_ctx; - sd_ctx->sdom = ad_id_ctx->sdap_id_ctx->opts->sdom; - sd_ctx->sdap_id_ctx = ad_id_ctx->sdap_id_ctx; -@@ -1376,6 +1457,7 @@ errno_t ad_subdomains_init(TALLOC_CTX *mem_ctx, - DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); - return ENOMEM; - } -+ sd_ctx->ad_enabled_domains = ad_enabled_domains; - sd_ctx->ad_id_ctx = ad_id_ctx; - - dp_set_method(dp_methods, DPM_DOMAINS_HANDLER, --- -2.4.11 - diff --git a/SOURCES/0104-IFP-Use-sized_domain_name-to-format-the-groups-the-u.patch b/SOURCES/0104-IFP-Use-sized_domain_name-to-format-the-groups-the-u.patch new file mode 100644 index 0000000..8d252f9 --- /dev/null +++ b/SOURCES/0104-IFP-Use-sized_domain_name-to-format-the-groups-the-u.patch @@ -0,0 +1,95 @@ +From 956d7e794d6c07eec3c0009253c8a86320c3e741 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 19 Apr 2017 17:46:03 +0200 +Subject: [PATCH 104/104] IFP: Use sized_domain_name to format the groups the + user is a member of +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves: + https://pagure.io/SSSD/sssd/issue/3268 + +Uses the common function sized_domain_name() to format a group the user +is a member of to the appropriate format. + +To see the code is working correctly, run: + dbus-send --system --print-reply --dest=org.freedesktop.sssd.infopipe + /org/freedesktop/sssd/infopipe + org.freedesktop.sssd.infopipe.GetUserGroups + string:trusted_user + +Where trusted_user is a user from a trusted domain that is a member of groups +from the joined domain and a trusted domain as well. The groups from the +joined domain should not be qualified, the groups from the trusted +domain should be qualified. + +Reviewed-by: Pavel Březina +(cherry picked from commit c9a73bb6ffa010ef206896a0d1c2801bc056fa45) +--- + src/responder/ifp/ifpsrv_cmd.c | 29 +++++++++++++++-------------- + 1 file changed, 15 insertions(+), 14 deletions(-) + +diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c +index d10f35e41dbb1623a0b9de37a4c43363cbefc1a3..e4d6c42ef35ef372472803d3d26b17d4181021a8 100644 +--- a/src/responder/ifp/ifpsrv_cmd.c ++++ b/src/responder/ifp/ifpsrv_cmd.c +@@ -369,10 +369,11 @@ ifp_user_get_groups_reply(struct sss_domain_info *domain, + struct ifp_req *ireq, + struct ldb_result *res) + { +- int i, num; ++ int i, gri, num; + const char *name; + const char **groupnames; +- char *out_name; ++ struct sized_string *group_name; ++ errno_t ret; + + /* one less, the first one is the user entry */ + num = res->count - 1; +@@ -381,6 +382,7 @@ ifp_user_get_groups_reply(struct sss_domain_info *domain, + return sbus_request_finish(ireq->dbus_req, NULL); + } + ++ gri = 0; + for (i = 0; i < num; i++) { + name = sss_view_ldb_msg_find_attr_as_string(domain, + res->msgs[i + 1], +@@ -390,22 +392,21 @@ ifp_user_get_groups_reply(struct sss_domain_info *domain, + continue; + } + +- out_name = sss_output_name(ireq, name, domain->case_preserve, +- ireq->ifp_ctx->rctx->override_space); +- if (out_name == NULL) { ++ ret = sized_domain_name(ireq, ireq->ifp_ctx->rctx, name, &group_name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Unable to get sized name for %s [%d]: %s\n", ++ name, ret, sss_strerror(ret)); + continue; + } + +- if (domain->fqnames) { +- groupnames[i] = sss_tc_fqname(groupnames, domain->names, +- domain, out_name); +- if (out_name == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "sss_tc_fqname failed\n"); +- continue; +- } +- } else { +- groupnames[i] = talloc_steal(groupnames, out_name); ++ groupnames[gri] = talloc_strndup(groupnames, ++ group_name->str, group_name->len); ++ if (groupnames[gri] == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "talloc_strndup failed\n"); ++ continue; + } ++ gri++; + + DEBUG(SSSDBG_TRACE_FUNC, "Adding group %s\n", groupnames[i]); + } +-- +2.9.3 + diff --git a/SOURCES/0105-AD_PROVIDER-ad_enabled_domains-only-master.patch b/SOURCES/0105-AD_PROVIDER-ad_enabled_domains-only-master.patch deleted file mode 100644 index 81520da..0000000 --- a/SOURCES/0105-AD_PROVIDER-ad_enabled_domains-only-master.patch +++ /dev/null @@ -1,57 +0,0 @@ -From a0009ecf7cfaaa14eb5b041b9e1d8247d18c61cb Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Tue, 21 Jun 2016 09:48:52 +0200 -Subject: [PATCH 105/108] AD_PROVIDER: ad_enabled_domains - only master -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We can skip looking up other domains if option ad_enabled_domains -contains only master domain. - -Resolves: -https://fedorahosted.org/sssd/ticket/2828 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - src/providers/ad/ad_subdomains.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c -index 6e44760330275f7e4262e6863f180747f659edb5..5fdfc63886457db02ea4edc430341b31c3e545ce 100644 ---- a/src/providers/ad/ad_subdomains.c -+++ b/src/providers/ad/ad_subdomains.c -@@ -1170,6 +1170,7 @@ static void ad_subdomains_refresh_connect_done(struct tevent_req *subreq) - return; - } - -+ /* connect to the DC we are a member of */ - subreq = ad_master_domain_send(state, state->ev, state->id_ctx->conn, - state->sdap_op, state->sd_ctx->domain_name); - if (subreq == NULL) { -@@ -1218,6 +1219,21 @@ static void ad_subdomains_refresh_master_done(struct tevent_req *subreq) - goto done; - } - -+ /* -+ * If ad_enabled_domains contains only master domain -+ * we shouldn't lookup other domains. -+ */ -+ if (state->sd_ctx->ad_enabled_domains != NULL) { -+ if (talloc_array_length(state->sd_ctx->ad_enabled_domains) == 2) { -+ if (strcasecmp(state->sd_ctx->ad_enabled_domains[0], -+ state->be_ctx->domain->name) == 0) { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "No other enabled domain than master.\n"); -+ goto done; -+ } -+ } -+ } -+ - subreq = ad_get_root_domain_send(state, state->ev, forest, - sdap_id_op_handle(state->sdap_op), - state->sd_ctx); --- -2.4.11 - diff --git a/SOURCES/0105-RESPONDER-Fallback-to-global-domain-resolution-order.patch b/SOURCES/0105-RESPONDER-Fallback-to-global-domain-resolution-order.patch new file mode 100644 index 0000000..e0094c0 --- /dev/null +++ b/SOURCES/0105-RESPONDER-Fallback-to-global-domain-resolution-order.patch @@ -0,0 +1,313 @@ +From b7d2310e9ddd79bfdea2bc334bd11d4df9be37a2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 12 Apr 2017 10:43:25 +0200 +Subject: [PATCH 105/110] RESPONDER: Fallback to global domain resolution order + in case the view doesn't have this option set +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The current code has been ignoring the domain resolution order set +globally on IPA in case there's a view but this doesn't have any domain +resolution order set. + +It happens because we haven't been checking whether the view attribute +didn't exist and then we ended up populating the list cache_req domains' +list assuming that no order has been set instead of falling back to the +next preferred method. + +Related: +https://pagure.io/SSSD/sssd/issue/3001 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +(cherry picked from commit a3faad0e4dc1ca4473746c3822ecfc5aed876e6d) +--- + src/responder/common/cache_req/cache_req_domain.c | 14 ++- + src/responder/common/cache_req/cache_req_domain.h | 5 +- + src/responder/common/responder_common.c | 108 +++++++++++++--------- + 3 files changed, 74 insertions(+), 53 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c +index bbabd695f1c6b6c29b7e61f571382ab9adfb0ea2..86a88efd54ca0f4a0748b44ece1b8515438d4628 100644 +--- a/src/responder/common/cache_req/cache_req_domain.c ++++ b/src/responder/common/cache_req/cache_req_domain.c +@@ -120,20 +120,21 @@ done: + return cr_domains; + } + +-struct cache_req_domain * ++errno_t + cache_req_domain_new_list_from_domain_resolution_order( + TALLOC_CTX *mem_ctx, + struct sss_domain_info *domains, +- const char *domain_resolution_order) ++ const char *domain_resolution_order, ++ struct cache_req_domain **_cr_domains) + { + TALLOC_CTX *tmp_ctx; +- struct cache_req_domain *cr_domains = NULL; ++ struct cache_req_domain *cr_domains; + char **list = NULL; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { +- return NULL; ++ return ENOMEM; + } + + if (domain_resolution_order != NULL) { +@@ -160,7 +161,10 @@ cache_req_domain_new_list_from_domain_resolution_order( + goto done; + } + ++ *_cr_domains = cr_domains; ++ ret = EOK; ++ + done: + talloc_free(tmp_ctx); +- return cr_domains; ++ return ret; + } +diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h +index 41c50e8c293d7b032cb2f05482c40e93e4f723dc..000087e5ca2074f22169a4af627810f4f287e430 100644 +--- a/src/responder/common/cache_req/cache_req_domain.h ++++ b/src/responder/common/cache_req/cache_req_domain.h +@@ -34,11 +34,12 @@ struct cache_req_domain * + cache_req_domain_get_domain_by_name(struct cache_req_domain *domains, + const char *name); + +-struct cache_req_domain * ++errno_t + cache_req_domain_new_list_from_domain_resolution_order( + TALLOC_CTX *mem_ctx, + struct sss_domain_info *domains, +- const char *domain_resolution_order); ++ const char *domain_resolution_order, ++ struct cache_req_domain **_cr_domains); + + void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains); + +diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c +index ac6320b08de09bc6c7e8dd1af72e0a493a449f7a..62b71b5104fdbb585d086d44d2ca2ab9717dd788 100644 +--- a/src/responder/common/responder_common.c ++++ b/src/responder/common/responder_common.c +@@ -1486,10 +1486,11 @@ fail: + } + + /* ====== Helper functions for the domain resolution order ======= */ +-static struct cache_req_domain * ++static errno_t + sss_resp_new_cr_domains_from_ipa_id_view(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domains, +- struct sysdb_ctx *sysdb) ++ struct sysdb_ctx *sysdb, ++ struct cache_req_domain **_cr_domains) + { + TALLOC_CTX *tmp_ctx; + struct cache_req_domain *cr_domains = NULL; +@@ -1498,7 +1499,7 @@ sss_resp_new_cr_domains_from_ipa_id_view(TALLOC_CTX *mem_ctx, + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { +- return NULL; ++ return ENOMEM; + } + + ret = sysdb_get_view_domain_resolution_order(tmp_ctx, sysdb, +@@ -1510,12 +1511,13 @@ sss_resp_new_cr_domains_from_ipa_id_view(TALLOC_CTX *mem_ctx, + goto done; + } + +- /* Using mem_ctx (which is rctx) directly here to avoid copying +- * this memory around. */ +- cr_domains = cache_req_domain_new_list_from_domain_resolution_order( +- mem_ctx, domains, domain_resolution_order); +- if (cr_domains == NULL) { +- ret = ENOMEM; ++ if (ret == ENOENT) { ++ goto done; ++ } ++ ++ ret = cache_req_domain_new_list_from_domain_resolution_order( ++ mem_ctx, domains, domain_resolution_order, &cr_domains); ++ if (ret != EOK) { + DEBUG(SSSDBG_DEFAULT, + "cache_req_domain_new_list_from_domain_resolution_order() " + "failed [%d]: [%s].\n", +@@ -1523,25 +1525,31 @@ sss_resp_new_cr_domains_from_ipa_id_view(TALLOC_CTX *mem_ctx, + goto done; + } + ++ *_cr_domains = cr_domains; ++ ++ ret = EOK; ++ + done: + talloc_free(tmp_ctx); +- return cr_domains; ++ return ret; + } + +-static struct cache_req_domain * ++static errno_t + sss_resp_new_cr_domains_from_ipa_config(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domains, + struct sysdb_ctx *sysdb, +- const char *domain) ++ const char *domain, ++ struct cache_req_domain **_cr_domains) + { + TALLOC_CTX *tmp_ctx; +- struct cache_req_domain *cr_domains = NULL; + const char *domain_resolution_order = NULL; + errno_t ret; + ++ *_cr_domains = NULL; ++ + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { +- return NULL; ++ return ENOMEM; + } + + ret = sysdb_domain_get_domain_resolution_order(tmp_ctx, sysdb, domain, +@@ -1554,11 +1562,13 @@ sss_resp_new_cr_domains_from_ipa_config(TALLOC_CTX *mem_ctx, + goto done; + } + +- /* Using mem_ctx (which is rctx) directly here to avoid copying +- * this memory around. */ +- cr_domains = cache_req_domain_new_list_from_domain_resolution_order( +- mem_ctx, domains, domain_resolution_order); +- if (cr_domains == NULL) { ++ if (ret == ENOENT) { ++ goto done; ++ } ++ ++ ret = cache_req_domain_new_list_from_domain_resolution_order( ++ mem_ctx, domains, domain_resolution_order, _cr_domains); ++ if (ret != EOK) { + DEBUG(SSSDBG_DEFAULT, + "cache_req_domain_new_list_from_domain_resolution_order() " + "failed [%d]: [%s].\n", +@@ -1566,9 +1576,11 @@ sss_resp_new_cr_domains_from_ipa_config(TALLOC_CTX *mem_ctx, + goto done; + } + ++ ret = EOK; ++ + done: + talloc_free(tmp_ctx); +- return cr_domains; ++ return ret; + } + + errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) +@@ -1578,16 +1590,16 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) + errno_t ret; + + if (rctx->domain_resolution_order != NULL) { +- cr_domains = cache_req_domain_new_list_from_domain_resolution_order( +- rctx, rctx->domains, rctx->domain_resolution_order); +- +- if (cr_domains == NULL) { ++ ret = cache_req_domain_new_list_from_domain_resolution_order( ++ rctx, rctx->domains, ++ rctx->domain_resolution_order, &cr_domains); ++ if (ret == EOK) { ++ goto done; ++ } else { + DEBUG(SSSDBG_MINOR_FAILURE, + "Failed to use domain_resolution_order set in the config file.\n" + "Trying to fallback to use ipaDomainOrderResolution setup by " + "IPA.\n"); +- } else { +- goto done; + } + } + +@@ -1598,9 +1610,9 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) + } + + if (dom == NULL) { +- cr_domains = cache_req_domain_new_list_from_domain_resolution_order( +- rctx, rctx->domains, NULL); +- if (cr_domains == NULL) { ++ ret = cache_req_domain_new_list_from_domain_resolution_order( ++ rctx, rctx->domains, NULL, &cr_domains); ++ if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to flatten the list of domains.\n"); + } +@@ -1608,44 +1620,48 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) + } + + if (dom->has_views) { +- cr_domains = sss_resp_new_cr_domains_from_ipa_id_view(rctx, +- rctx->domains, +- dom->sysdb); +- if (cr_domains == NULL) { ++ ret = sss_resp_new_cr_domains_from_ipa_id_view(rctx, rctx->domains, ++ dom->sysdb, ++ &cr_domains); ++ if (ret == EOK) { ++ goto done; ++ } ++ ++ if (ret != ENOENT) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Failed to use ipaDomainResolutionOrder set for the " + "view \"%s\".\n" + "Trying to fallback to use ipaDomainOrderResolution " + "set in ipaConfig for the domain: %s.\n", + dom->view_name, dom->name); +- } else { +- goto done; + } + } + +- cr_domains = sss_resp_new_cr_domains_from_ipa_config(rctx, rctx->domains, +- dom->sysdb, +- dom->name); +- if (cr_domains == NULL) { ++ ret = sss_resp_new_cr_domains_from_ipa_config(rctx, rctx->domains, ++ dom->sysdb, dom->name, ++ &cr_domains); ++ if (ret == EOK) { ++ goto done; ++ } ++ ++ if (ret != ENOENT) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Failed to use ipaDomainResolutionOrder set in ipaConfig " + "for the domain: \"%s\".\n" + "No ipaDomainResolutionOrder will be followed.\n", + dom->name); +- } else { +- goto done; + } + +- cr_domains = cache_req_domain_new_list_from_domain_resolution_order( +- rctx, rctx->domains, NULL); +- if (cr_domains == NULL) { ++ ret = cache_req_domain_new_list_from_domain_resolution_order( ++ rctx, rctx->domains, NULL, &cr_domains); ++ if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to flatten the list of domains.\n"); + goto done; + } + +-done: +- ret = cr_domains != NULL ? EOK : ENOMEM; ++ ret = EOK; + ++done: + cache_req_domain_list_zfree(&rctx->cr_domains); + rctx->cr_domains = cr_domains; + +-- +2.9.3 + diff --git a/SOURCES/0106-AD_PROVIDER-ad_enabled_domains-other-then-master.patch b/SOURCES/0106-AD_PROVIDER-ad_enabled_domains-other-then-master.patch deleted file mode 100644 index 6946373..0000000 --- a/SOURCES/0106-AD_PROVIDER-ad_enabled_domains-other-then-master.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 9438cd7b8c8cca1e919afec6c5aa3a3233a31f8c Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Mon, 27 Jun 2016 11:51:30 +0200 -Subject: [PATCH 106/108] AD_PROVIDER: ad_enabled_domains - other then master -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We can skip looking up other domains if -option ad_enabled_domains doesn't contain them. - -Resolves: -https://fedorahosted.org/sssd/ticket/2828 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - src/providers/ad/ad_subdomains.c | 40 +++++++++++++++++++++++++++++++++++++--- - 1 file changed, 37 insertions(+), 3 deletions(-) - -diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c -index 5fdfc63886457db02ea4edc430341b31c3e545ce..52bf5361fa8de02c7165cbc3513a923ec018fc15 100644 ---- a/src/providers/ad/ad_subdomains.c -+++ b/src/providers/ad/ad_subdomains.c -@@ -130,6 +130,16 @@ done: - return ret; - } - -+static bool is_domain_enabled(const char *domain, -+ const char **enabled_doms) -+{ -+ if (enabled_doms == NULL) { -+ return true; -+ } -+ -+ return string_in_list(domain, discard_const_p(char *, enabled_doms), false); -+} -+ - static errno_t - ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, - struct ad_id_ctx *id_ctx, -@@ -492,6 +502,7 @@ done: - - static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, -+ const char **enabled_domains_list, - size_t nsd, struct sysdb_attrs **sd, - struct sysdb_attrs *root, - size_t *_nsd_out, -@@ -500,9 +511,10 @@ static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx, - size_t i, sdi; - struct sysdb_attrs **sd_out; - const char *sd_name; -+ const char *root_name; - errno_t ret; - -- if (root == NULL) { -+ if (root == NULL && enabled_domains_list == NULL) { - /* We are connected directly to the root domain. The 'sd' - * list is complete and we can just use it - */ -@@ -529,6 +541,13 @@ static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx, - goto fail; - } - -+ if (is_domain_enabled(sd_name, enabled_domains_list) == false) { -+ DEBUG(SSSDBG_TRACE_FUNC, "Disabling subdomain %s\n", sd_name); -+ continue; -+ } else { -+ DEBUG(SSSDBG_TRACE_FUNC, "Enabling subdomain %s\n", sd_name); -+ } -+ - if (strcasecmp(sd_name, domain->name) == 0) { - DEBUG(SSSDBG_TRACE_INTERNAL, - "Not including primary domain %s in the subdomain list\n", -@@ -541,9 +560,23 @@ static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx, - } - - /* Now include the root */ -- sd_out[sdi] = talloc_steal(sd_out, root); -+ if (root != NULL) { -+ ret = sysdb_attrs_get_string(root, AD_AT_TRUST_PARTNER, &root_name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); -+ goto fail; -+ } - -- *_nsd_out = sdi+1; -+ if (is_domain_enabled(root_name, enabled_domains_list) == true) { -+ sd_out[sdi] = talloc_steal(sd_out, root); -+ sdi++; -+ } else { -+ DEBUG(SSSDBG_TRACE_FUNC, "Disabling forest root domain %s\n", -+ root_name); -+ } -+ } -+ -+ *_nsd_out = sdi; - *_sd_out = sd_out; - return EOK; - -@@ -789,6 +822,7 @@ static void ad_get_slave_domain_done(struct tevent_req *subreq) - * subdomains. - */ - ret = ad_subdomains_process(state, state->be_ctx->domain, -+ state->sd_ctx->ad_enabled_domains, - reply_count, reply, state->root_attrs, - &nsubdoms, &subdoms); - if (ret != EOK) { --- -2.4.11 - diff --git a/SOURCES/0106-NSS-TESTS-Improve-non-fqnames-tests.patch b/SOURCES/0106-NSS-TESTS-Improve-non-fqnames-tests.patch new file mode 100644 index 0000000..fce885a --- /dev/null +++ b/SOURCES/0106-NSS-TESTS-Improve-non-fqnames-tests.patch @@ -0,0 +1,164 @@ +From b4b409f2c5bd0f0b26015b0562ae0ee0e831da82 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 17 Apr 2017 09:32:39 +0200 +Subject: [PATCH 106/110] NSS/TESTS: Improve non-fqnames tests +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With the changes that are about to happen we have to have the subdomain's +fqnames flag set by the time we populate the cr_domains list (as it +actually occurs with the real code), as this list may set its own fqnames +flag based on the subdomain's fqnames flag. + +Currently the flag is set to false only when running the tests itself so +the cr_domains list doesn't get populate properly (although it still +works with the current code). + +For the changes that are comming, let's introduce a new setup function +that ensures that the subdomain's fqnames flag is set up in the right +time. + +Related: +https://pagure.io/SSSD/sssd/issue/3001 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +(cherry picked from commit ed518f61f1a5d4cf5d87eec492c158725a73d6a1) +--- + src/tests/cmocka/test_nss_srv.c | 45 +++++++++++++++++++++++++++-------------- + 1 file changed, 30 insertions(+), 15 deletions(-) + +diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c +index 2f526660cbbbf2443dbae4e213c1336feb6c661e..8c72f44f1869558893627e1f2f91b5f3b96c6317 100644 +--- a/src/tests/cmocka/test_nss_srv.c ++++ b/src/tests/cmocka/test_nss_srv.c +@@ -1709,8 +1709,6 @@ 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); +@@ -1802,8 +1800,6 @@ 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, +@@ -1917,6 +1913,7 @@ 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; +@@ -1929,10 +1926,6 @@ void test_nss_getgrnam_mix_dom_fqdn_nonfqnames(void **state) + 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); +@@ -2044,8 +2037,6 @@ 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, +@@ -3417,9 +3408,11 @@ static int nss_test_setup_extra_attr(void **state) + return 0; + } + +-static int nss_subdom_test_setup(void **state) ++static int nss_subdom_test_setup_common(void **state, bool nonfqnames) + { + const char *const testdom[4] = { TEST_SUBDOM_NAME, "TEST.SUB", "test", "S-3" }; ++ struct sss_domain_info *dom; ++ + struct sss_domain_info *subdomain; + errno_t ret; + +@@ -3440,6 +3433,17 @@ static int nss_subdom_test_setup(void **state) + nss_test_ctx->tctx->confdb); + assert_int_equal(ret, EOK); + ++ if (nonfqnames) { ++ for (dom = nss_test_ctx->rctx->domains; ++ dom != NULL; ++ dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) { ++ if (strcmp(dom->name, subdomain->name) == 0) { ++ dom->fqnames = false; ++ break; ++ } ++ } ++ } ++ + ret = sss_resp_populate_cr_domains(nss_test_ctx->rctx); + assert_int_equal(ret, EOK); + assert_non_null(nss_test_ctx->rctx->cr_domains); +@@ -3475,6 +3479,17 @@ static int nss_subdom_test_setup(void **state) + assert_int_equal(ret, EOK); + + return 0; ++ ++} ++ ++static int nss_subdom_test_setup(void **state) ++{ ++ return nss_subdom_test_setup_common(state, false); ++} ++ ++static int nss_subdom_test_setup_nonfqnames(void **state) ++{ ++ return nss_subdom_test_setup_common(state, true); + } + + static int nss_fqdn_fancy_test_setup(void **state) +@@ -4192,25 +4207,25 @@ int main(int argc, const char *argv[]) + 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_setup_nonfqnames, + 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_setup_nonfqnames, + 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_setup_nonfqnames, + 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_setup_nonfqnames, + nss_subdom_test_teardown), + cmocka_unit_test_setup_teardown(test_nss_getgrnam_space, + nss_test_setup, nss_test_teardown), +-- +2.9.3 + diff --git a/SOURCES/0107-CACHE_REQ-Allow-configurationless-shortname-lookups.patch b/SOURCES/0107-CACHE_REQ-Allow-configurationless-shortname-lookups.patch new file mode 100644 index 0000000..352e52d --- /dev/null +++ b/SOURCES/0107-CACHE_REQ-Allow-configurationless-shortname-lookups.patch @@ -0,0 +1,139 @@ +From 7c6fd66fa9ca942bc240b49f903d9d3d85340c4c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 11 Apr 2017 17:19:29 +0200 +Subject: [PATCH 107/110] CACHE_REQ: Allow configurationless shortname lookups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Configurationless shortnames lookups must be allowed when a domains' +resolution order is present and the (head) domain is not enforcing the +usage of fully-qualified-names. + +With this patch SSSD does not require any kind of changes from client +side for taking advantage of shortname lookups. + +Related: +https://pagure.io/SSSD/sssd/issue/3001 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +(cherry picked from commit dae798231fc2c575f213785768bc24ed765ba243) +--- + src/responder/common/cache_req/cache_req.c | 2 +- + src/responder/common/cache_req/cache_req_domain.c | 48 +++++++++++++++++++++++ + src/responder/common/cache_req/cache_req_domain.h | 1 + + 3 files changed, 50 insertions(+), 1 deletion(-) + +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index 3a5fecf34427437bbf95317e05c5bd8b07b4537d..797325a30e6c1ed5f1d4b4c147c65391d5204b52 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -480,7 +480,7 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req) + * qualified names on domain less search. We do not descend into + * subdomains here since those are implicitly qualified. + */ +- if (state->check_next && !allow_no_fqn && domain->fqnames) { ++ if (state->check_next && !allow_no_fqn && state->cr_domain->fqnames) { + state->cr_domain = state->cr_domain->next; + continue; + } +diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c +index 86a88efd54ca0f4a0748b44ece1b8515438d4628..bfdd2b7f640178f6d0a0d92f2fed329c856b478c 100644 +--- a/src/responder/common/cache_req/cache_req_domain.c ++++ b/src/responder/common/cache_req/cache_req_domain.c +@@ -60,6 +60,48 @@ void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains) + *cr_domains = NULL; + } + ++static bool ++cache_req_domain_use_fqnames(struct sss_domain_info *domain, ++ bool enforce_non_fqnames) ++{ ++ struct sss_domain_info *head; ++ ++ head = get_domains_head(domain); ++ ++ /* ++ * In order to decide whether fully_qualified_names must be used on the ++ * lookups we have to take into consideration: ++ * - use_fully_qualified_name value of the head of the domains; ++ * (head->fqnames) ++ * - the presence of a domains' resolution order list; ++ * (non_fqnames_enforced) ++ * ++ * The relationship between those two can be described by: ++ * - head->fqnames: ++ * - true: in this case doesn't matter whether it's enforced or not, ++ * fully-qualified-names will _always_ be used ++ * - false: in this case (which is also the default case), the usage ++ * depends on it being enforced; ++ * ++ * - enforce_non_fqnames: ++ * - true: in this case, the usage of fully-qualified-names is not ++ * needed; ++ * - false: in this case, the usage of fully-qualified-names will be ++ * done accordingly to what's set for the domain itself. ++ */ ++ switch (head->fqnames) { ++ case true: ++ return true; ++ case false: ++ switch (enforce_non_fqnames) { ++ case true: ++ return false; ++ case false: ++ return domain->fqnames; ++ } ++ } ++} ++ + static struct cache_req_domain * + cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domains, +@@ -71,9 +113,11 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, + char *name; + int flag = SSS_GND_ALL_DOMAINS; + int i; ++ bool enforce_non_fqnames = false; + errno_t ret; + + if (resolution_order != NULL) { ++ enforce_non_fqnames = true; + for (i = 0; resolution_order[i] != NULL; i++) { + name = resolution_order[i]; + for (dom = domains; dom; dom = get_next_domain(dom, flag)) { +@@ -87,6 +131,8 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, + goto done; + } + cr_domain->domain = dom; ++ cr_domain->fqnames = ++ cache_req_domain_use_fqnames(dom, enforce_non_fqnames); + + DLIST_ADD_END(cr_domains, cr_domain, + struct cache_req_domain *); +@@ -106,6 +152,8 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, + goto done; + } + cr_domain->domain = dom; ++ cr_domain->fqnames = ++ cache_req_domain_use_fqnames(dom, enforce_non_fqnames); + + DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *); + } +diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h +index 000087e5ca2074f22169a4af627810f4f287e430..5bcbb9b493caf05bf71aac5cf7633ded91f22e73 100644 +--- a/src/responder/common/cache_req/cache_req_domain.h ++++ b/src/responder/common/cache_req/cache_req_domain.h +@@ -25,6 +25,7 @@ + + struct cache_req_domain { + struct sss_domain_info *domain; ++ bool fqnames; + + struct cache_req_domain *prev; + struct cache_req_domain *next; +-- +2.9.3 + diff --git a/SOURCES/0107-TESTS-Adding-tests-for-ad_enabled_domains-option.patch b/SOURCES/0107-TESTS-Adding-tests-for-ad_enabled_domains-option.patch deleted file mode 100644 index 96cddc6..0000000 --- a/SOURCES/0107-TESTS-Adding-tests-for-ad_enabled_domains-option.patch +++ /dev/null @@ -1,398 +0,0 @@ -From 70c1809c7ad309d87fba7570cff5c5e9f10d17f1 Mon Sep 17 00:00:00 2001 -From: Petr Cech -Date: Mon, 27 Jun 2016 11:53:19 +0200 -Subject: [PATCH 107/108] TESTS: Adding tests for ad_enabled_domains option -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -There is special logic around ad_enabled_domains option: - * option is disabled by default - * master domain is always added to enabled domains - -Resolves: -https://fedorahosted.org/sssd/ticket/2828 - -Reviewed-by: Jakub Hrozek -Reviewed-by: Lukáš Slebodník ---- - Makefile.am | 20 +++ - src/tests/cmocka/test_ad_subdomains.c | 328 ++++++++++++++++++++++++++++++++++ - 2 files changed, 348 insertions(+) - create mode 100644 src/tests/cmocka/test_ad_subdomains.c - -diff --git a/Makefile.am b/Makefile.am -index e2e4c4c08f66ef15684e1b3b1fe17bfae4e4131b..4d90c7a46e2ee0fe652aa392cf647d056e06c7fc 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -257,6 +257,7 @@ if HAVE_CMOCKA - test_sbus_opath \ - test_fo_srv \ - pam-srv-tests \ -+ test_ad_subdom \ - test_ipa_subdom_util \ - test_tools_colondb \ - test_krb5_wait_queue \ -@@ -2817,6 +2818,25 @@ test_fo_srv_LDADD = \ - libsss_test_common.la \ - $(NULL) - -+test_ad_subdom_SOURCES = \ -+ src/tests/cmocka/test_ad_subdomains.c \ -+ $(NULL) -+test_ad_subdom_CFLAGS = \ -+ $(AM_CFLAGS) \ -+ $(NDR_NBT_CFLAGS) \ -+ $(NULL) -+test_ad_subdom_LDADD = \ -+ $(CMOCKA_LIBS) \ -+ $(POPT_LIBS) \ -+ $(TALLOC_LIBS) \ -+ $(SSSD_INTERNAL_LTLIBS) \ -+ libsss_ldap_common.la \ -+ libsss_ad_tests.la \ -+ libsss_idmap.la \ -+ libsss_test_common.la \ -+ libdlopen_test_providers.la \ -+ $(NULL) -+ - test_ipa_subdom_util_SOURCES = \ - src/tests/cmocka/test_ipa_subdomains_utils.c \ - src/providers/ipa/ipa_subdomains_utils.c \ -diff --git a/src/tests/cmocka/test_ad_subdomains.c b/src/tests/cmocka/test_ad_subdomains.c -new file mode 100644 -index 0000000000000000000000000000000000000000..99908b5f8f0b89c2cc391b5496e24a247bfd7448 ---- /dev/null -+++ b/src/tests/cmocka/test_ad_subdomains.c -@@ -0,0 +1,328 @@ -+/* -+ Authors: -+ Petr Čech -+ -+ Copyright (C) 2016 Red Hat -+ -+ SSSD tests: AD subdomain tests -+ -+ 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 . -+*/ -+ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests/cmocka/common_mock.h" -+#include "tests/cmocka/common_mock_resp.h" -+#include "providers/ad/ad_common.h" -+ -+#include "providers/ad/ad_subdomains.c" -+#include "providers/ad/ad_opts.c" -+ -+#define AD_DOMAIN "ad_domain.domain.test" -+#define DOMAIN_1 "one.domain.test" -+#define DOMAIN_2 "two.domain.test" -+ -+struct test_ad_subdom_ctx { -+ struct ad_id_ctx *ad_id_ctx; -+}; -+ -+static struct ad_id_ctx * -+test_ad_subdom_init_ad_id_ctx(TALLOC_CTX *mem_ctx) -+{ -+ struct ad_id_ctx *ad_id_ctx; -+ struct ad_options *ad_options; -+ errno_t ret; -+ -+ ad_id_ctx = talloc_zero(mem_ctx, struct ad_id_ctx); -+ assert_non_null(ad_id_ctx); -+ -+ ad_options = talloc_zero(ad_id_ctx, struct ad_options); -+ assert_non_null(ad_options); -+ -+ ret = dp_copy_defaults(ad_options, -+ ad_basic_opts, -+ AD_OPTS_BASIC, -+ &ad_options->basic); -+ assert_int_equal(ret, EOK); -+ -+ ad_id_ctx->ad_options = ad_options; -+ -+ return ad_id_ctx; -+} -+ -+static int test_ad_subdom_setup(void **state) -+{ -+ struct test_ad_subdom_ctx *test_ctx; -+ -+ assert_true(leak_check_setup()); -+ -+ test_ctx = talloc_zero(global_talloc_context, struct test_ad_subdom_ctx); -+ assert_non_null(test_ctx); -+ -+ test_ctx->ad_id_ctx = NULL; -+ -+ check_leaks_push(test_ctx); -+ *state = test_ctx; -+ return 0; -+} -+ -+static int test_ad_subdom_teardown(void **state) -+{ -+ struct test_ad_subdom_ctx *test_ctx; -+ -+ test_ctx = talloc_get_type(*state, struct test_ad_subdom_ctx); -+ assert_non_null(test_ctx); -+ -+ assert_true(check_leaks_pop(test_ctx) == true); -+ talloc_free(test_ctx); -+ assert_true(leak_check_teardown()); -+ return 0; -+} -+ -+static void test_ad_subdom_default(void **state) -+{ -+ struct test_ad_subdom_ctx *test_ctx; -+ const char **ad_enabled_domains = NULL; -+ errno_t ret; -+ -+ test_ctx = talloc_get_type(*state, struct test_ad_subdom_ctx); -+ test_ctx->ad_id_ctx = test_ad_subdom_init_ad_id_ctx(test_ctx); -+ assert_non_null(test_ctx->ad_id_ctx); -+ -+ ret = ad_get_enabled_domains(test_ctx, test_ctx->ad_id_ctx, -+ AD_DOMAIN, -+ &ad_enabled_domains); -+ assert_int_equal(ret, EOK); -+ assert_null(ad_enabled_domains); -+ -+ talloc_zfree(test_ctx->ad_id_ctx); -+} -+ -+static void test_ad_subdom_add_one(void **state) -+{ -+ struct test_ad_subdom_ctx *test_ctx; -+ const char **ad_enabled_domains = NULL; -+ int enabled_domains_count; -+ int domain_count = 2; -+ const char *domains[domain_count]; -+ errno_t ret; -+ -+ test_ctx = talloc_get_type(*state, struct test_ad_subdom_ctx); -+ test_ctx->ad_id_ctx = test_ad_subdom_init_ad_id_ctx(test_ctx); -+ assert_non_null(test_ctx->ad_id_ctx); -+ -+ ret = dp_opt_set_string(test_ctx->ad_id_ctx->ad_options->basic, -+ AD_ENABLED_DOMAINS, DOMAIN_1); -+ assert_int_equal(ret, EOK); -+ -+ ret = ad_get_enabled_domains(test_ctx, test_ctx->ad_id_ctx, -+ AD_DOMAIN, -+ &ad_enabled_domains); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ad_enabled_domains); -+ -+ for (enabled_domains_count = 0; -+ ad_enabled_domains[enabled_domains_count] != NULL; -+ enabled_domains_count++) { -+ } -+ assert_int_equal(domain_count, enabled_domains_count); -+ -+ domains[0] = AD_DOMAIN; -+ domains[1] = DOMAIN_1; -+ assert_true(are_values_in_array(domains, domain_count, -+ ad_enabled_domains, enabled_domains_count)); -+ -+ talloc_zfree(test_ctx->ad_id_ctx); -+ talloc_zfree(ad_enabled_domains); -+} -+ -+static void test_ad_subdom_add_two(void **state) -+{ -+ struct test_ad_subdom_ctx *test_ctx; -+ const char **ad_enabled_domains = NULL; -+ int enabled_domains_count; -+ int domain_count = 3; -+ const char *domains[domain_count]; -+ errno_t ret; -+ -+ test_ctx = talloc_get_type(*state, struct test_ad_subdom_ctx); -+ test_ctx->ad_id_ctx = test_ad_subdom_init_ad_id_ctx(test_ctx); -+ assert_non_null(test_ctx->ad_id_ctx); -+ -+ ret = dp_opt_set_string(test_ctx->ad_id_ctx->ad_options->basic, -+ AD_ENABLED_DOMAINS, DOMAIN_1","DOMAIN_2); -+ assert_int_equal(ret, EOK); -+ -+ ret = ad_get_enabled_domains(test_ctx, test_ctx->ad_id_ctx, -+ AD_DOMAIN, -+ &ad_enabled_domains); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ad_enabled_domains); -+ -+ for (enabled_domains_count = 0; -+ ad_enabled_domains[enabled_domains_count] != NULL; -+ enabled_domains_count++) { -+ } -+ assert_int_equal(domain_count, enabled_domains_count); -+ -+ domains[0] = AD_DOMAIN; -+ domains[1] = DOMAIN_1; -+ domains[2] = DOMAIN_2; -+ assert_true(are_values_in_array(domains, domain_count, -+ ad_enabled_domains, enabled_domains_count)); -+ -+ talloc_zfree(test_ctx->ad_id_ctx); -+ talloc_zfree(ad_enabled_domains); -+} -+ -+static void test_ad_subdom_add_master(void **state) -+{ -+ struct test_ad_subdom_ctx *test_ctx; -+ const char **ad_enabled_domains = NULL; -+ int enabled_domains_count; -+ int domain_count = 1; -+ const char *domains[domain_count]; -+ errno_t ret; -+ -+ test_ctx = talloc_get_type(*state, struct test_ad_subdom_ctx); -+ test_ctx->ad_id_ctx = test_ad_subdom_init_ad_id_ctx(test_ctx); -+ assert_non_null(test_ctx->ad_id_ctx); -+ -+ ret = dp_opt_set_string(test_ctx->ad_id_ctx->ad_options->basic, -+ AD_ENABLED_DOMAINS, AD_DOMAIN); -+ assert_int_equal(ret, EOK); -+ -+ ret = ad_get_enabled_domains(test_ctx, test_ctx->ad_id_ctx, -+ AD_DOMAIN, -+ &ad_enabled_domains); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ad_enabled_domains); -+ -+ for (enabled_domains_count = 0; -+ ad_enabled_domains[enabled_domains_count] != NULL; -+ enabled_domains_count++) { -+ } -+ assert_int_equal(domain_count, enabled_domains_count); -+ -+ domains[0] = AD_DOMAIN; -+ assert_true(are_values_in_array(domains, domain_count, -+ ad_enabled_domains, enabled_domains_count)); -+ -+ talloc_zfree(test_ctx->ad_id_ctx); -+ talloc_zfree(ad_enabled_domains); -+} -+ -+static void test_ad_subdom_add_two_with_master(void **state) -+{ -+ struct test_ad_subdom_ctx *test_ctx; -+ const char **ad_enabled_domains = NULL; -+ int enabled_domains_count; -+ int domain_count = 3; -+ const char *domains[domain_count]; -+ errno_t ret; -+ -+ test_ctx = talloc_get_type(*state, struct test_ad_subdom_ctx); -+ test_ctx->ad_id_ctx = test_ad_subdom_init_ad_id_ctx(test_ctx); -+ assert_non_null(test_ctx->ad_id_ctx); -+ -+ ret = dp_opt_set_string(test_ctx->ad_id_ctx->ad_options->basic, -+ AD_ENABLED_DOMAINS, -+ DOMAIN_1","AD_DOMAIN","DOMAIN_2); -+ assert_int_equal(ret, EOK); -+ -+ ret = ad_get_enabled_domains(test_ctx, test_ctx->ad_id_ctx, -+ AD_DOMAIN, -+ &ad_enabled_domains); -+ assert_int_equal(ret, EOK); -+ assert_non_null(ad_enabled_domains); -+ -+ for (enabled_domains_count = 0; -+ ad_enabled_domains[enabled_domains_count] != NULL; -+ enabled_domains_count++) { -+ } -+ assert_int_equal(domain_count, enabled_domains_count); -+ -+ domains[0] = AD_DOMAIN; -+ domains[1] = DOMAIN_1; -+ domains[2] = DOMAIN_2; -+ assert_true(are_values_in_array(domains, domain_count, -+ ad_enabled_domains, enabled_domains_count)); -+ -+ talloc_zfree(test_ctx->ad_id_ctx); -+ talloc_zfree(ad_enabled_domains); -+} -+ -+int main(int argc, const char *argv[]) -+{ -+ int rv; -+ poptContext pc; -+ int opt; -+ struct poptOption long_options[] = { -+ POPT_AUTOHELP -+ SSSD_DEBUG_OPTS -+ POPT_TABLEEND -+ }; -+ -+ const struct CMUnitTest tests[] = { -+ cmocka_unit_test_setup_teardown(test_ad_subdom_default, -+ test_ad_subdom_setup, -+ test_ad_subdom_teardown), -+ cmocka_unit_test_setup_teardown(test_ad_subdom_add_one, -+ test_ad_subdom_setup, -+ test_ad_subdom_teardown), -+ cmocka_unit_test_setup_teardown(test_ad_subdom_add_two, -+ test_ad_subdom_setup, -+ test_ad_subdom_teardown), -+ cmocka_unit_test_setup_teardown(test_ad_subdom_add_master, -+ test_ad_subdom_setup, -+ test_ad_subdom_teardown), -+ cmocka_unit_test_setup_teardown(test_ad_subdom_add_two_with_master, -+ test_ad_subdom_setup, -+ test_ad_subdom_teardown), -+ }; -+ -+ /* Set debug level to invalid value so we can deside if -d 0 was used. */ -+ debug_level = SSSDBG_INVALID; -+ -+ pc = poptGetContext(argv[0], argc, argv, long_options, 0); -+ while((opt = poptGetNextOpt(pc)) != -1) { -+ switch(opt) { -+ default: -+ fprintf(stderr, "\nInvalid option %s: %s\n\n", -+ poptBadOption(pc, 0), poptStrerror(opt)); -+ poptPrintUsage(pc, stderr, 0); -+ return 1; -+ } -+ } -+ poptFreeContext(pc); -+ -+ DEBUG_CLI_INIT(debug_level); -+ -+ /* Even though normally the tests should clean up after themselves -+ * they might not after a failed run. Remove the old db to be sure */ -+ tests_set_cwd(); -+ -+ rv = cmocka_run_group_tests(tests, NULL, NULL); -+ return rv; -+} --- -2.4.11 - diff --git a/SOURCES/0108-CACHE_REQ_DOMAIN-Add-some-comments-to-cache_req_doma.patch b/SOURCES/0108-CACHE_REQ_DOMAIN-Add-some-comments-to-cache_req_doma.patch new file mode 100644 index 0000000..86ba24f --- /dev/null +++ b/SOURCES/0108-CACHE_REQ_DOMAIN-Add-some-comments-to-cache_req_doma.patch @@ -0,0 +1,42 @@ +From 3d55506f2e6584d412ca07f2d0d77375aae48ba9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 24 Apr 2017 21:04:58 +0200 +Subject: [PATCH 108/110] CACHE_REQ_DOMAIN: Add some comments to + cache_req_domain_new_list_from_string_list() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +(cherry picked from commit f9bac02756aa05cc9c6ac07ae581dba67240c1a4) +--- + src/responder/common/cache_req/cache_req_domain.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c +index bfdd2b7f640178f6d0a0d92f2fed329c856b478c..6d37db0f109d5343eb6d7f4272bea522d4c34cf7 100644 +--- a/src/responder/common/cache_req/cache_req_domain.c ++++ b/src/responder/common/cache_req/cache_req_domain.c +@@ -116,6 +116,8 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, + bool enforce_non_fqnames = false; + errno_t ret; + ++ /* Firstly, in case a domains' resolution order is passed ... iterate over ++ * the list adding its domains to the flatten cache req domains' list */ + if (resolution_order != NULL) { + enforce_non_fqnames = true; + for (i = 0; resolution_order[i] != NULL; i++) { +@@ -141,6 +143,8 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, + } + } + ++ /* Then iterate through all the other domains (and subdomains) and add them ++ * to the flatten cache req domains' list */ + for (dom = domains; dom; dom = get_next_domain(dom, flag)) { + if (string_in_list(dom->name, resolution_order, false)) { + continue; +-- +2.9.3 + diff --git a/SOURCES/0109-RESPONDER_COMMON-Improve-domaiN_resolution_order-deb.patch b/SOURCES/0109-RESPONDER_COMMON-Improve-domaiN_resolution_order-deb.patch new file mode 100644 index 0000000..a1abb10 --- /dev/null +++ b/SOURCES/0109-RESPONDER_COMMON-Improve-domaiN_resolution_order-deb.patch @@ -0,0 +1,54 @@ +From 326442dc734de72b950a47c5fe2b3ac6a1dfc35e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 24 Apr 2017 21:09:02 +0200 +Subject: [PATCH 109/110] RESPONDER_COMMON: Improve domaiN_resolution_order + debug messages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Indicate whether a domain_resolution_order has been used and where +it came from. + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +(cherry picked from commit 213048fd9a5e800deb74cb5b7f0eaf465945c640) +--- + src/responder/common/responder_common.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c +index 62b71b5104fdbb585d086d44d2ca2ab9717dd788..7496d293fddb3e947d59a4f2aaeb2c83234dfcc7 100644 +--- a/src/responder/common/responder_common.c ++++ b/src/responder/common/responder_common.c +@@ -1594,6 +1594,8 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) + rctx, rctx->domains, + rctx->domain_resolution_order, &cr_domains); + if (ret == EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Using domain_resolution_order from sssd.conf\n"); + goto done; + } else { + DEBUG(SSSDBG_MINOR_FAILURE, +@@ -1624,6 +1626,8 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) + dom->sysdb, + &cr_domains); + if (ret == EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Using domain_resolution_order from IPA ID View\n"); + goto done; + } + +@@ -1641,6 +1645,8 @@ errno_t sss_resp_populate_cr_domains(struct resp_ctx *rctx) + dom->sysdb, dom->name, + &cr_domains); + if (ret == EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Using domain_resolution_order from IPA Config\n"); + goto done; + } + +-- +2.9.3 + diff --git a/SOURCES/0109-UTIL-Use-sss_atomic_read_s-in-generate_csprng_buffer.patch b/SOURCES/0109-UTIL-Use-sss_atomic_read_s-in-generate_csprng_buffer.patch deleted file mode 100644 index 0734ff1..0000000 --- a/SOURCES/0109-UTIL-Use-sss_atomic_read_s-in-generate_csprng_buffer.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 60596973b503637c742b597aeb862eecae9f9c91 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Mon, 8 Aug 2016 14:07:04 +0200 -Subject: [PATCH 109/111] UTIL: Use sss_atomic_read_s in generate_csprng_buffer -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -There was a bug in generate_csprng_buffer() where if we read the exact -amount of bytes from /dev/urandom, we would always return EIO. Instead, -let's reuse the existing code from sss_atomic_read_s() which fixes this -bug and reduces code duplication. - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Fabiano Fidêncio ---- - Makefile.am | 2 ++ - src/util/crypto/sss_crypto.c | 29 +++++------------------------ - 2 files changed, 7 insertions(+), 24 deletions(-) - -diff --git a/Makefile.am b/Makefile.am -index 4d90c7a46e2ee0fe652aa392cf647d056e06c7fc..a32a1e37c85e2370fa006ee73b730145f03c3fc1 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -815,6 +815,7 @@ if HAVE_NSS - src/util/crypto/nss/nss_nite.c \ - src/util/crypto/nss/nss_util.c \ - src/util/crypto/sss_crypto.c \ -+ src/util/atomic_io.c \ - $(NULL) - SSS_CRYPT_CFLAGS = $(NSS_CFLAGS) - SSS_CRYPT_LIBS = $(NSS_LIBS) -@@ -836,6 +837,7 @@ else - src/util/crypto/libcrypto/crypto_obfuscate.c \ - src/util/crypto/libcrypto/crypto_nite.c \ - src/util/crypto/sss_crypto.c \ -+ src/util/atomic_io.c \ - $(NULL) - SSS_CRYPT_CFLAGS = $(CRYPTO_CFLAGS) - SSS_CRYPT_LIBS = $(CRYPTO_LIBS) -diff --git a/src/util/crypto/sss_crypto.c b/src/util/crypto/sss_crypto.c -index 4c775f3d926ae32f3cb72b1329c0a025a0550ed5..ac90bac07c7006a2950331b86bcc412207a3e401 100644 ---- a/src/util/crypto/sss_crypto.c -+++ b/src/util/crypto/sss_crypto.c -@@ -25,41 +25,22 @@ - int generate_csprng_buffer(uint8_t *buf, size_t size) - { - ssize_t rsize; -- ssize_t pos; - int ret; - int fd; - - fd = open("/dev/urandom", O_RDONLY); - if (fd == -1) return errno; - -- rsize = 0; -- pos = 0; -- while (rsize < size) { -- rsize = read(fd, buf + pos, size - pos); -- switch (rsize) { -- case -1: -- if (errno == EINTR) continue; -- ret = EIO; -- goto done; -- case 0: -- ret = EIO; -- goto done; -- default: -- if (rsize + pos < size - pos) { -- pos += rsize; -- continue; -- } -- ret = EIO; -- goto done; -- } -- } -- if (rsize != size) { -+ rsize = sss_atomic_read_s(fd, buf, size); -+ if (rsize == -1) { -+ ret = errno; -+ goto done; -+ } else if (rsize != size) { - ret = EFAULT; - goto done; - } - - ret = EOK; -- - done: - close(fd); - return ret; --- -2.4.11 - diff --git a/SOURCES/0110-CACHE_REQ_DOMAIN-debug-the-set-domain-resolution-ord.patch b/SOURCES/0110-CACHE_REQ_DOMAIN-debug-the-set-domain-resolution-ord.patch new file mode 100644 index 0000000..8507ad0 --- /dev/null +++ b/SOURCES/0110-CACHE_REQ_DOMAIN-debug-the-set-domain-resolution-ord.patch @@ -0,0 +1,50 @@ +From 3671f188ff9e379022d62eaf7171f397f04ac153 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 25 Apr 2017 14:25:12 +0200 +Subject: [PATCH 110/110] CACHE_REQ_DOMAIN: debug the set domain resolution + order +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +(cherry picked from commit b78febe4c579f86f8007a27599605d1eb9f97a62) +--- + src/responder/common/cache_req/cache_req_domain.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c +index 6d37db0f109d5343eb6d7f4272bea522d4c34cf7..2c238c9966d322bb542fa2047313ee9e5144edee 100644 +--- a/src/responder/common/cache_req/cache_req_domain.c ++++ b/src/responder/common/cache_req/cache_req_domain.c +@@ -191,6 +191,10 @@ cache_req_domain_new_list_from_domain_resolution_order( + + if (domain_resolution_order != NULL) { + if (strcmp(domain_resolution_order, ":") != 0) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Domain resolution order list (split by ':'): \"%s\"\n", ++ domain_resolution_order); ++ + ret = split_on_separator(tmp_ctx, domain_resolution_order, ':', + true, true, &list, NULL); + if (ret != EOK) { +@@ -199,7 +203,14 @@ cache_req_domain_new_list_from_domain_resolution_order( + ret, sss_strerror(ret)); + goto done; + } ++ } else { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Domain resolution order list: ':' " ++ "(do not use any specific order)\n"); + } ++ } else { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Domain resolution order list: not set\n"); + } + + cr_domains = cache_req_domain_new_list_from_string_list(mem_ctx, domains, +-- +2.9.3 + diff --git a/SOURCES/0110-SECRETS-Use-sss_atomic_read-write-for-better-readabi.patch b/SOURCES/0110-SECRETS-Use-sss_atomic_read-write-for-better-readabi.patch deleted file mode 100644 index 1c66e09..0000000 --- a/SOURCES/0110-SECRETS-Use-sss_atomic_read-write-for-better-readabi.patch +++ /dev/null @@ -1,46 +0,0 @@ -From eb6a90621a53424e4d0a5534eca303b432509433 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Mon, 8 Aug 2016 13:50:54 +0200 -Subject: [PATCH 110/111] SECRETS: Use sss_atomic_read/write for better - readability -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -sss_atomic_read_s and sss_atomic_write_s are macro-wrappers around -sss_atomic_io_s but it's easier to follow the code with the read/write -vairants used directly. - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Fabiano Fidêncio ---- - src/responder/secrets/local.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c -index 470aec0e195a54dd2af2b929ff1b7a304331a214..17469249b357cbdc5e50ddff6b563fdf2f377577 100644 ---- a/src/responder/secrets/local.c -+++ b/src/responder/secrets/local.c -@@ -621,7 +621,7 @@ int generate_master_key(const char *filename, size_t size) - fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, 0600); - if (fd == -1) return errno; - -- rsize = sss_atomic_io_s(fd, buf, size, false); -+ rsize = sss_atomic_write_s(fd, buf, size); - close(fd); - if (rsize != size) { - ret = unlink(filename); -@@ -681,8 +681,8 @@ int local_secrets_provider_handle(struct sec_ctx *sctx, - } - if (ret) return EFAULT; - -- size = sss_atomic_io_s(mfd, lctx->master_key.data, -- lctx->master_key.length, true); -+ size = sss_atomic_read_s(mfd, lctx->master_key.data, -+ lctx->master_key.length); - close(mfd); - if (size < 0 || size != lctx->master_key.length) return EIO; - --- -2.4.11 - diff --git a/SOURCES/0111-BUILD-Ship-systemd-service-file-for-sssd-secrets.patch b/SOURCES/0111-BUILD-Ship-systemd-service-file-for-sssd-secrets.patch deleted file mode 100644 index 3b6ae74..0000000 --- a/SOURCES/0111-BUILD-Ship-systemd-service-file-for-sssd-secrets.patch +++ /dev/null @@ -1,154 +0,0 @@ -From d0b2cd8d161e7fc6e6c96f51342c88e6572eb1da Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Mon, 15 Aug 2016 14:10:23 +0200 -Subject: [PATCH 111/111] BUILD: Ship systemd service file for sssd-secrets -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Adds two new files: sssd-secrets.socket and sssd-secrets.service. These -can be used to socket-acticate the secrets responder even without -explicitly starting it in the sssd config file. - -The specfile activates the socket after installation which means that -the admin would just be able to use the secrets socket and the -sssd_secrets responder would be started automatically by systemd. - -The sssd-secrets responder is started as root, mostly because I didn't -think of an easy way to pass the uid/gid to the responders without -asking about the sssd user identity in the first place. But nonetheless, -the sssd-secrets responder wasn't tested as non-root and at least the -initialization should be performed as root for the time being. - -Reviewed-by: Fabiano Fidêncio -Reviewed-by: Lukáš Slebodník ---- - Makefile.am | 21 +++++++++++++++++++-- - contrib/sssd.spec.in | 6 ++++++ - src/sysv/systemd/sssd-secrets.service.in | 8 ++++++++ - src/sysv/systemd/sssd-secrets.socket.in | 8 ++++++++ - 4 files changed, 41 insertions(+), 2 deletions(-) - create mode 100644 src/sysv/systemd/sssd-secrets.service.in - create mode 100644 src/sysv/systemd/sssd-secrets.socket.in - -diff --git a/Makefile.am b/Makefile.am -index a32a1e37c85e2370fa006ee73b730145f03c3fc1..6ab4399d5b68644668198bc9b0e3056562a4e51a 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -3888,7 +3888,10 @@ systemdunit_DATA = - systemdconf_DATA = - if HAVE_SYSTEMD_UNIT - systemdunit_DATA += \ -- src/sysv/systemd/sssd.service -+ src/sysv/systemd/sssd.service \ -+ src/sysv/systemd/sssd-secrets.socket \ -+ src/sysv/systemd/sssd-secrets.service \ -+ $(NULL) - if WITH_JOURNALD - systemdconf_DATA += \ - src/sysv/systemd/journal.conf -@@ -3926,6 +3929,7 @@ edit_cmd = $(SED) \ - -e 's|@sbindir[@]|$(sbindir)|g' \ - -e 's|@environment_file[@]|$(environment_file)|g' \ - -e 's|@localstatedir[@]|$(localstatedir)|g' \ -+ -e 's|@libexecdir[@]|$(libexecdir)|g' \ - -e 's|@prefix[@]|$(prefix)|g' - - replace_script = \ -@@ -3937,7 +3941,10 @@ replace_script = \ - - EXTRA_DIST += \ - src/sysv/systemd/sssd.service.in \ -- src/sysv/systemd/journal.conf.in -+ src/sysv/systemd/journal.conf.in \ -+ src/sysv/systemd/sssd-secrets.socket.in \ -+ src/sysv/systemd/sssd-secrets.service.in \ -+ $(NULL) - - src/sysv/systemd/sssd.service: src/sysv/systemd/sssd.service.in Makefile - @$(MKDIR_P) src/sysv/systemd/ -@@ -3947,6 +3954,14 @@ src/sysv/systemd/journal.conf: src/sysv/systemd/journal.conf.in Makefile - @$(MKDIR_P) src/sysv/systemd/ - $(replace_script) - -+src/sysv/systemd/sssd-secrets.socket: src/sysv/systemd/sssd-secrets.socket.in Makefile -+ @$(MKDIR_P) src/sysv/systemd/ -+ $(replace_script) -+ -+src/sysv/systemd/sssd-secrets.service: src/sysv/systemd/sssd-secrets.service.in Makefile -+ @$(MKDIR_P) src/sysv/systemd/ -+ $(replace_script) -+ - SSSD_USER_DIRS = \ - $(DESTDIR)$(dbpath) \ - $(DESTDIR)$(keytabdir) \ -@@ -4162,6 +4177,8 @@ endif - done; - rm -Rf ldb_mod_test_dir - rm -f $(builddir)/src/sysv/systemd/sssd.service -+ rm -f $(builddir)/src/sysv/systemd/sssd-secrets.socket -+ rm -f $(builddir)/src/sysv/systemd/sssd-secrets.service - rm -f $(builddir)/src/sysv/systemd/journal.conf - - CLEANFILES += *.X */*.X */*/*.X -diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in -index 14f0cb27ac8f1acc3aa0786da576be33b727e024..f1ff16176cb8ca974b98948958cfa1e9290b0bca 100644 ---- a/contrib/sssd.spec.in -+++ b/contrib/sssd.spec.in -@@ -737,6 +737,8 @@ done - %{_sbindir}/sssd - %if (0%{?use_systemd} == 1) - %{_unitdir}/sssd.service -+%{_unitdir}/sssd-secrets.socket -+%{_unitdir}/sssd-secrets.service - %else - %{_initrddir}/%{name} - %endif -@@ -1069,12 +1071,16 @@ getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "Us - # systemd - %post common - %systemd_post sssd.service -+%systemd_post sssd-secrets.socket - - %preun common - %systemd_preun sssd.service -+%systemd_preun sssd-secrets.socket - - %postun common - %systemd_postun_with_restart sssd.service -+%systemd_postun_with_restart sssd-secrets.socket -+%systemd_postun_with_restart sssd-secrets.service - - %else - # sysv -diff --git a/src/sysv/systemd/sssd-secrets.service.in b/src/sysv/systemd/sssd-secrets.service.in -new file mode 100644 -index 0000000000000000000000000000000000000000..119c9bb4b37b672159db707aa11a6d11215f29bf ---- /dev/null -+++ b/src/sysv/systemd/sssd-secrets.service.in -@@ -0,0 +1,8 @@ -+[Unit] -+Description=SSSD Secrets Service responder -+ -+[Install] -+Also=sssd-secrets.socket -+ -+[Service] -+ExecStart=@libexecdir@/sssd/sssd_secrets --uid 0 --gid 0 --debug-to-files -diff --git a/src/sysv/systemd/sssd-secrets.socket.in b/src/sysv/systemd/sssd-secrets.socket.in -new file mode 100644 -index 0000000000000000000000000000000000000000..682e8f6e0fa58092a90259523f9f2f59e0131435 ---- /dev/null -+++ b/src/sysv/systemd/sssd-secrets.socket.in -@@ -0,0 +1,8 @@ -+[Unit] -+Description=SSSD Secrets Service responder socket -+ -+[Socket] -+ListenStream=@localstatedir@/run/secrets.socket -+ -+[Install] -+WantedBy=sockets.target --- -2.4.11 - diff --git a/SOURCES/0111-SECRETS-remove-unused-variable.patch b/SOURCES/0111-SECRETS-remove-unused-variable.patch new file mode 100644 index 0000000..1e1d87c --- /dev/null +++ b/SOURCES/0111-SECRETS-remove-unused-variable.patch @@ -0,0 +1,33 @@ +From 429c282e54feb0e1c9ac27d23be6a8c1d4119976 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 19 Apr 2017 17:56:20 +0200 +Subject: [PATCH 111/118] SECRETS: remove unused variable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +(cherry picked from commit 0e8f0c06cad5805b1a1161f60e3f2cdb7a5a2921) +--- + src/responder/secrets/proxy.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c +index fd96e985c897e2cb470a9b5d6eecbd34350fb7d2..9c2aa425d414728d10aa830f640632e98def3c1c 100644 +--- a/src/responder/secrets/proxy.c ++++ b/src/responder/secrets/proxy.c +@@ -570,11 +570,6 @@ static void proxy_secret_req_done(struct tevent_req *subreq) + } + } + +-struct provider_handle proxy_secrets_handle = { +- .fn = proxy_secret_req, +- .context = NULL, +-}; +- + int proxy_secrets_provider_handle(struct sec_ctx *sctx, + struct provider_handle **out_handle) + { +-- +2.9.3 + diff --git a/SOURCES/0112-DP-Add-log-message-for-get-account-info.patch b/SOURCES/0112-DP-Add-log-message-for-get-account-info.patch deleted file mode 100644 index a2fa19c..0000000 --- a/SOURCES/0112-DP-Add-log-message-for-get-account-info.patch +++ /dev/null @@ -1,33 +0,0 @@ -From b05afb6811e42d3297e884b0664884aa47af923f Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Tue, 16 Aug 2016 08:49:57 +0200 -Subject: [PATCH 112/115] DP: Add log message for get account info -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reviewed-by: Petr Čech -(cherry picked from commit 806f65f3c90dc0f7921932494228ad93f3ed3027) ---- - src/providers/data_provider/dp_target_id.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c -index 938651545ea995091d0aaf29da12bbb8110c9add..8b126d70e59cb33b6de8b678f5b4c1a15b391329 100644 ---- a/src/providers/data_provider/dp_target_id.c -+++ b/src/providers/data_provider/dp_target_id.c -@@ -281,6 +281,11 @@ errno_t dp_get_account_info_handler(struct sbus_request *sbus_req, - goto done; - } - -+ DEBUG(SSSDBG_FUNC_DATA, -+ "Got request for [%#"PRIx32"][%s][%"PRId32"][%s]\n", -+ data->entry_type, be_req2str(data->entry_type), -+ attr_type, filter); -+ - key = talloc_asprintf(data, "%u:%u:%s:%s:%s", data->entry_type, - data->attr_type, extra, domain, filter); - if (key == NULL) { --- -2.4.11 - diff --git a/SOURCES/0112-IPA-Improve-DEBUG-message-if-a-group-has-no-ipaNTSec.patch b/SOURCES/0112-IPA-Improve-DEBUG-message-if-a-group-has-no-ipaNTSec.patch new file mode 100644 index 0000000..77c2a5b --- /dev/null +++ b/SOURCES/0112-IPA-Improve-DEBUG-message-if-a-group-has-no-ipaNTSec.patch @@ -0,0 +1,42 @@ +From 396849b6160594dbb6dedec5d1bd7fbc3af12cdd Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 21 Apr 2017 12:39:44 +0200 +Subject: [PATCH 112/118] IPA: Improve DEBUG message if a group has no + ipaNTSecurityIdentifier +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There was an issue in a production deployment where the admin selected a +GID outside the IDM range for a group that contained a user from the +trusted domain. This resulted in not adding a SID for the IPA group, +which in turn meant the group couldn't be resolved on the client. + +This patch just improves the DEBUG message so that it's clearer for the +admins where the issue is. + +Reviewed-by: Lukáš Slebodník +(cherry picked from commit ef019268d2d112ebff3577e551cd19478d73d93b) +--- + src/providers/ipa/ipa_s2n_exop.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index 2173db357700499a6140aa61841e443139981483..55ec904ca3188c7cf10ac41972e9ecf94ebf44bb 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -1308,7 +1308,10 @@ static void ipa_s2n_get_list_next(struct tevent_req *subreq) + ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR, + &sid_str); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Object [%s] has no SID, please check the " ++ "ipaNTSecurityIdentifier attribute on the server-side", ++ state->attrs->a.name); + goto fail; + } + +-- +2.9.3 + diff --git a/SOURCES/0113-IPA-Improve-s2n-debug-message-for-missing-ipaNTSecur.patch b/SOURCES/0113-IPA-Improve-s2n-debug-message-for-missing-ipaNTSecur.patch new file mode 100644 index 0000000..a2ccf0b --- /dev/null +++ b/SOURCES/0113-IPA-Improve-s2n-debug-message-for-missing-ipaNTSecur.patch @@ -0,0 +1,45 @@ +From 522dffca552146c0af74325b6ceab0ca950bbc1a Mon Sep 17 00:00:00 2001 +From: Justin Stephenson +Date: Tue, 25 Apr 2017 13:02:10 -0400 +Subject: [PATCH 113/118] IPA: Improve s2n debug message for missing + ipaNTSecurityIdentifier +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch improves the log message to be more information for +the SSSD user troubleshooting issues. + +If the IDM POSIX group used for AD trust HBAC/SUDO operation is missing +the ipaNTSecurityIdentifier it can cause client s2n operations failures +resolving the group which resulted in the inability to login for the AD +user. + +Reviewed-by: Pavel Březina +(cherry picked from commit 0c5f463e9629ac08d647c70cffb30bccdd57ae96) +--- + src/providers/ipa/ipa_s2n_exop.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index 55ec904ca3188c7cf10ac41972e9ecf94ebf44bb..f5f4401f86615dc7f81f844e1096ad43e965c384 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -2580,7 +2580,13 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + ret = sysdb_attrs_get_string(attrs->sysdb_attrs, SYSDB_SID_STR, &sid_str); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "Cannot find SID of object with override.\n"); ++ "Cannot find SID of object.\n"); ++ if (name != NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Object [%s] has no SID, please check the " ++ "ipaNTSecurityIdentifier attribute on the server-side.\n", ++ name); ++ } + goto done; + } + +-- +2.9.3 + diff --git a/SOURCES/0113-LDAP-Log-autofs-rfc2307-config-changes-only-with-ena.patch b/SOURCES/0113-LDAP-Log-autofs-rfc2307-config-changes-only-with-ena.patch deleted file mode 100644 index 678ec4e..0000000 --- a/SOURCES/0113-LDAP-Log-autofs-rfc2307-config-changes-only-with-ena.patch +++ /dev/null @@ -1,65 +0,0 @@ -From b415b9d2b6d016928a2bbcaa710cdc876e4ecc9c Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Tue, 16 Aug 2016 13:32:06 +0200 -Subject: [PATCH 113/115] LDAP: Log autofs rfc2307 config changes only with - enabled responder -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -grep -nE "0x0040" /var/log/sssd/sssd_example.com.log -361:(Tue Aug 16 13:04:04 2016) [sssd[be[example.com]]] - [ldap_get_autofs_options] (0x0040): Your configuration uses the autofs - provider with schema set to rfc2307 and default attribute mappings. - The default map has changed in this release, please make sure - the configuration matches the server attributes. - -Reviewed-by: Petr Čech ---- - src/providers/ldap/ldap_options.c | 23 ++++++++++++++++++++++- - 1 file changed, 22 insertions(+), 1 deletion(-) - -diff --git a/src/providers/ldap/ldap_options.c b/src/providers/ldap/ldap_options.c -index 018f6c31fb6360952308e44979581790b8477dc3..15a2609f07506b6dd442b180651a7e25461976c0 100644 ---- a/src/providers/ldap/ldap_options.c -+++ b/src/providers/ldap/ldap_options.c -@@ -444,6 +444,10 @@ static bool has_defaults(struct confdb_ctx *cdb, - static bool ldap_rfc2307_autofs_defaults(struct confdb_ctx *cdb, - const char *conf_path) - { -+ char **services = NULL; -+ errno_t ret; -+ bool has_autofs_defaults = false; -+ - const char *attrs[] = { - rfc2307_autofs_entry_map[SDAP_OC_AUTOFS_ENTRY].opt_name, - /* SDAP_AT_AUTOFS_ENTRY_KEY missing on purpose, its value was -@@ -455,7 +459,24 @@ static bool ldap_rfc2307_autofs_defaults(struct confdb_ctx *cdb, - NULL, - }; - -- return has_defaults(cdb, conf_path, attrs); -+ ret = confdb_get_string_as_list(cdb, cdb, -+ CONFDB_MONITOR_CONF_ENTRY, -+ CONFDB_MONITOR_ACTIVE_SERVICES, &services); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to read from confdb [%d]: %s\n", -+ ret, sss_strerror(ret)); -+ goto done; -+ } -+ -+ if (string_in_list("autofs", services, true) == false) { -+ goto done; -+ } -+ -+ has_autofs_defaults = has_defaults(cdb, conf_path, attrs); -+done: -+ talloc_free(services); -+ -+ return has_autofs_defaults; - } - - int ldap_get_autofs_options(TALLOC_CTX *memctx, --- -2.4.11 - diff --git a/SOURCES/0114-CONFDB-Fix-standalone-application-domains.patch b/SOURCES/0114-CONFDB-Fix-standalone-application-domains.patch new file mode 100644 index 0000000..9d2968e --- /dev/null +++ b/SOURCES/0114-CONFDB-Fix-standalone-application-domains.patch @@ -0,0 +1,128 @@ +From 8441030009c22daa835f89dbc36365415524b320 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 31 Mar 2017 17:12:56 +0200 +Subject: [PATCH 114/118] CONFDB: Fix standalone application domains +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When a standalone application domain was configured, for example: + +------------------------------------------------- +[sssd] +domains = appdomain + +[application/appdomain] +id_provider=ldap +ldap_uri = ldap://dc.ipa.test +ldap_search_base = cn=accounts,dc=ipa,dc=test +ldap_schema = rfc2307bis +sudo_provider = none + +ldap_sasl_mech = gssapi +krb5_realm = IPA.TEST +krb5_server = dc.ipa.test + +ldap_user_uid_number = telephonenumber +ldap_user_gid_number = mobile +ldap_user_extra_attrs = location:l +------------------------------------------------- + +We would, when unrolling the application section into a domain section, +first add a domain stub, equivalent to: +----------------------------- +[domain/appdomain] +domain_type = application +----------------------------- + +Which in config.ldb also contains cn. Then, whem we would add the parameters +from the [application] section, but try to add the cn again. + +This didn't happen when inheriting from a POSIX domain, because there we +would set LDB_FLAG_REPLACE for any attributes that exist in the inherited +domain. + +This patch skips the cn attribute both when replacing an inherited +domain's attributes and when writing a standalone application domain. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3355 + +Reviewed-by: Pavel Březina +(cherry picked from commit 734e73257fff1c1884b72b8cf988f6d75c3a7567) +--- + src/confdb/confdb.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index 88e114457deac3ca50c291a131122624fb6f6fe4..5bb593de03cc2fb26218b883fd1d753e31bedc2d 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -1909,7 +1909,7 @@ static int confdb_add_app_domain(TALLOC_CTX *mem_ctx, + + cdb_path = talloc_asprintf(mem_ctx, CONFDB_DOMAIN_PATH_TMPL, name); + if (cdb_path == NULL) { +- return ENOMEM; ++ return ENOMEM; + } + + val[0] = CONFDB_DOMAIN_TYPE_APP; +@@ -1933,6 +1933,7 @@ static int confdb_merge_parent_domain(const char *name, + struct ldb_message *replace_msg = NULL; + struct ldb_message *app_msg = NULL; + struct ldb_dn *domain_dn; ++ struct ldb_message_element *el = NULL; + TALLOC_CTX *tmp_ctx = NULL; + + tmp_ctx = talloc_new(NULL); +@@ -1974,6 +1975,12 @@ static int confdb_merge_parent_domain(const char *name, + replace_msg->elements[i].flags = LDB_FLAG_MOD_ADD; + } + ++ el = ldb_msg_find_element(replace_msg, "cn"); ++ if (el != NULL) { ++ /* Don't add second cn */ ++ ldb_msg_remove_element(replace_msg, el); ++ } ++ + ret = ldb_modify(cdb->ldb, replace_msg); + if (ret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(ret); +@@ -1993,7 +2000,14 @@ static int confdb_merge_parent_domain(const char *name, + app_msg->dn = domain_dn; + + for (unsigned i = 0; i < app_section->msgs[0]->num_elements; i++) { +- struct ldb_message_element *el = NULL; ++ struct ldb_message_element *app_el = &app_section->msgs[0]->elements[i]; ++ ++ /* These elements will be skipped when replacing attributes in ++ * a domain to avoid EEXIST errors ++ */ ++ if (strcasecmp(app_el->name, "cn") == 0) { ++ continue; ++ } + + if (replace_msg != NULL) { + el = ldb_msg_find_element(replace_msg, +@@ -2013,12 +2027,16 @@ static int confdb_merge_parent_domain(const char *name, + ret = ldb_msg_add(app_msg, + &app_section->msgs[0]->elements[i], + ldb_flag); +- if (ret != EOK) { ++ if (ret != LDB_SUCCESS) { + continue; + } + } + +- ret = ldb_modify(cdb->ldb, app_msg); ++ /* We use permissive modification here because adding cn or ++ * distinguishedName from the app_section to the application ++ * message would throw EEXIST ++ */ ++ ret = sss_ldb_modify_permissive(cdb->ldb, app_msg); + if (ret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(ret); + DEBUG(SSSDBG_OP_FAILURE, +-- +2.9.3 + diff --git a/SOURCES/0114-SSSCTL-More-helpful-error-message-when-InfoPipe-is-d.patch b/SOURCES/0114-SSSCTL-More-helpful-error-message-when-InfoPipe-is-d.patch deleted file mode 100644 index f59feff..0000000 --- a/SOURCES/0114-SSSCTL-More-helpful-error-message-when-InfoPipe-is-d.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 2b8b5e03319ab72d2c74d61ec24038c5ca412661 Mon Sep 17 00:00:00 2001 -From: Justin Stephenson -Date: Fri, 12 Aug 2016 12:12:57 -0400 -Subject: [PATCH 114/115] SSSCTL: More helpful error message when InfoPipe is - disabled -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: -https://fedorahosted.org/sssd/ticket/3130 - -Reviewed-by: Petr Čech -Reviewed-by: Pavel Březina ---- - src/tools/sssctl/sssctl_sifp.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/tools/sssctl/sssctl_sifp.c b/src/tools/sssctl/sssctl_sifp.c -index 782a72d7ce8bbf1080c6d6ac988ffac2f432955f..c53119b4e199852d1d233c79a0ad3c0bc4de7470 100644 ---- a/src/tools/sssctl/sssctl_sifp.c -+++ b/src/tools/sssctl/sssctl_sifp.c -@@ -26,7 +26,9 @@ - #include "tools/sssctl/sssctl.h" - - #define ERR_SSSD _("Check that SSSD is running and " \ -- "the InfoPipe responder is enabled.\n") -+ "the InfoPipe responder is enabled. " \ -+ "Make sure 'ifp' is listed in the " \ -+ "'services' option in sssd.conf.\n") - - struct sssctl_sifp_data { - sss_sifp_ctx *sifp; --- -2.4.11 - diff --git a/SOURCES/0115-sdap-Skip-exact-duplicates-when-extending-maps.patch b/SOURCES/0115-sdap-Skip-exact-duplicates-when-extending-maps.patch deleted file mode 100644 index cfd3300..0000000 --- a/SOURCES/0115-sdap-Skip-exact-duplicates-when-extending-maps.patch +++ /dev/null @@ -1,111 +0,0 @@ -From c4379aa97754b4c4cfc02663315b7c6319e3fa61 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Wed, 10 Aug 2016 15:41:34 +0200 -Subject: [PATCH 115/115] sdap: Skip exact duplicates when extending maps -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When extending map with entry that already -exists in the map in the exacty same form, -then there is no need to fail. - -We should only fail if we try to -change purpose of already used sysdb -attribute. - -Resolves: -https://fedorahosted.org/sssd/ticket/3120 - -Signed-off-by: Lukas Slebodnik - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Jakub Hrozek ---- - src/providers/ldap/sdap.c | 42 ++++++++++++++++++++++++++++++++---------- - 1 file changed, 32 insertions(+), 10 deletions(-) - -diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c -index 97b8f126d4ed6bc59c510d5763789a458bd4863a..dc7d5e0caf223c3ee3c43054aa44e796f1b37766 100644 ---- a/src/providers/ldap/sdap.c -+++ b/src/providers/ldap/sdap.c -@@ -122,19 +122,30 @@ static errno_t split_extra_attr(TALLOC_CTX *mem_ctx, - return EOK; - } - --static bool is_sysdb_duplicate(struct sdap_attr_map *map, -- int num_entries, -- const char *sysdb_attr) -+enum duplicate_t { -+ NOT_FOUND = 0, -+ ALREADY_IN_MAP, /* nothing to add */ -+ CONFLICT_WITH_MAP /* attempt to redefine attribute */ -+}; -+ -+static enum duplicate_t check_duplicate(struct sdap_attr_map *map, -+ int num_entries, -+ const char *sysdb_attr, -+ const char *ldap_attr) - { - int i; - - for (i = 0; i < num_entries; i++) { - if (strcmp(map[i].sys_name, sysdb_attr) == 0) { -- return true; -+ if (strcmp(map[i].name, ldap_attr) == 0) { -+ return ALREADY_IN_MAP; -+ } else { -+ return CONFLICT_WITH_MAP; -+ } - } - } - -- return false; -+ return NOT_FOUND; - } - - int sdap_extend_map(TALLOC_CTX *memctx, -@@ -167,14 +178,20 @@ int sdap_extend_map(TALLOC_CTX *memctx, - return ENOMEM; - } - -- for (i = 0; extra_attrs[i]; i++) { -- ret = split_extra_attr(map, extra_attrs[i], &sysdb_attr, &ldap_attr); -+ for (i = 0; *extra_attrs != NULL; extra_attrs++) { -+ ret = split_extra_attr(map, *extra_attrs, &sysdb_attr, &ldap_attr); - if (ret != EOK) { -- DEBUG(SSSDBG_MINOR_FAILURE, "Cannot split %s\n", extra_attrs[i]); -+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot split %s\n", *extra_attrs); - continue; - } - -- if (is_sysdb_duplicate(map, num_entries, sysdb_attr)) { -+ ret = check_duplicate(map, num_entries, sysdb_attr, ldap_attr); -+ if (ret == ALREADY_IN_MAP) { -+ DEBUG(SSSDBG_TRACE_FUNC, -+ "Attribute %s (%s in LDAP) is already in map.\n", -+ sysdb_attr, ldap_attr); -+ continue; -+ } else if (ret == CONFLICT_WITH_MAP) { - DEBUG(SSSDBG_FATAL_FAILURE, - "Attribute %s (%s in LDAP) is already used by SSSD, please " - "choose a different cache name\n", sysdb_attr, ldap_attr); -@@ -193,9 +210,14 @@ int sdap_extend_map(TALLOC_CTX *memctx, - map[num_entries+i].def_name == NULL) { - return ENOMEM; - } -- DEBUG(SSSDBG_TRACE_FUNC, "Extending map with %s\n", extra_attrs[i]); -+ DEBUG(SSSDBG_TRACE_FUNC, "Extending map with %s\n", *extra_attrs); -+ -+ /* index must be incremented only for appended entry. */ -+ i++; - } - -+ nextra = i; -+ - /* Sentinel */ - memset(&map[num_entries+nextra], 0, sizeof(struct sdap_attr_map)); - --- -2.4.11 - diff --git a/SOURCES/0115-utils-add-sss_domain_is_forest_root.patch b/SOURCES/0115-utils-add-sss_domain_is_forest_root.patch new file mode 100644 index 0000000..f46b9e2 --- /dev/null +++ b/SOURCES/0115-utils-add-sss_domain_is_forest_root.patch @@ -0,0 +1,48 @@ +From dc8a5bc411403b3d216947e317dfce9dbc5f79d3 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 4 Apr 2017 14:35:47 +0200 +Subject: [PATCH 115/118] utils: add sss_domain_is_forest_root() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related to https://pagure.io/SSSD/sssd/issue/3361 + +Reviewed-by: Pavel Březina +(cherry picked from commit 712e5b2e4465812c00a8667c75813322373bc657) +--- + src/util/domain_info_utils.c | 5 +++++ + src/util/util.h | 1 + + 2 files changed, 6 insertions(+) + +diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c +index 2af7852f03f89b61f5b9fd8a244e98fb27b7e6a2..541058a16d585155b3b51511740f7db45281e2fd 100644 +--- a/src/util/domain_info_utils.c ++++ b/src/util/domain_info_utils.c +@@ -844,6 +844,11 @@ void sss_domain_set_state(struct sss_domain_info *dom, + "Domain %s is %s\n", dom->name, domain_state_str(dom)); + } + ++bool sss_domain_is_forest_root(struct sss_domain_info *dom) ++{ ++ return (dom->forest_root == dom); ++} ++ + bool is_email_from_domain(const char *email, struct sss_domain_info *dom) + { + const char *p; +diff --git a/src/util/util.h b/src/util/util.h +index 436550f5078cc173b8ed8cb58836d366f813146b..4ef13ced48addc19403402d7d880176da24ceec6 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -539,6 +539,7 @@ enum sss_domain_state sss_domain_get_state(struct sss_domain_info *dom); + void sss_domain_set_state(struct sss_domain_info *dom, + enum sss_domain_state state); + bool is_email_from_domain(const char *email, struct sss_domain_info *dom); ++bool sss_domain_is_forest_root(struct sss_domain_info *dom); + const char *sss_domain_type_str(struct sss_domain_info *dom); + + struct sss_domain_info* +-- +2.9.3 + diff --git a/SOURCES/0116-ad-handle-forest-root-not-listed-in-ad_enabled_domai.patch b/SOURCES/0116-ad-handle-forest-root-not-listed-in-ad_enabled_domai.patch new file mode 100644 index 0000000..28f65d5 --- /dev/null +++ b/SOURCES/0116-ad-handle-forest-root-not-listed-in-ad_enabled_domai.patch @@ -0,0 +1,104 @@ +From 5ca331e80520035d7de2680cd2803fa508d15287 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 3 Apr 2017 21:27:32 +0200 +Subject: [PATCH 116/118] ad: handle forest root not listed in + ad_enabled_domains +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Although users and groups from the forest root should be ignored SSSD +will still try to get information about the forest topology from a DC +from the forest root. So even if the forest root domain is disabled we +should makes sure it is usable for those searches. + +Resolves https://pagure.io/SSSD/sssd/issue/3361 + +Reviewed-by: Pavel Březina +(cherry picked from commit feeabf273aa7af580552366ce58655e6a482a0cd) +--- + src/providers/ad/ad_subdomains.c | 39 ++++++++++++++++++++++++++++++++++++--- + 1 file changed, 36 insertions(+), 3 deletions(-) + +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index bc659b2cb0a02723437d24d0021ec3592381e84c..ef166446e837c3f7cd824c1abf4b5cc587aec9da 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -433,6 +433,14 @@ static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx, + if (c >= num_subdomains) { + /* ok this subdomain does not exist anymore, let's clean up */ + sss_domain_set_state(dom, DOM_DISABLED); ++ ++ /* Just disable the forest root but do not remove sdap data */ ++ if (sss_domain_is_forest_root(dom)) { ++ DEBUG(SSSDBG_TRACE_ALL, ++ "Skipping removal of forest root sdap data.\n"); ++ continue; ++ } ++ + ret = sysdb_subdomain_delete(dom->sysdb, dom->name); + if (ret != EOK) { + goto done; +@@ -633,6 +641,7 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *subdoms_ctx) + const char *path; + errno_t ret; + bool canonicalize = false; ++ struct sss_domain_info *dom; + + path = dp_opt_get_string(subdoms_ctx->ad_id_ctx->ad_options->basic, + AD_KRB5_CONFD_PATH); +@@ -675,6 +684,17 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *subdoms_ctx) + return ret; + } + ++ /* Make sure disabled domains are not re-enabled accidentially */ ++ if (subdoms_ctx->ad_enabled_domains != NULL) { ++ for (dom = subdoms_ctx->be_ctx->domain->subdomains; dom; ++ dom = get_next_domain(dom, false)) { ++ if (!is_domain_enabled(dom->name, ++ subdoms_ctx->ad_enabled_domains)) { ++ sss_domain_set_state(dom, DOM_DISABLED); ++ } ++ } ++ } ++ + return EOK; + } + +@@ -898,7 +918,7 @@ static errno_t ad_get_slave_domain_recv(struct tevent_req *req) + static struct sss_domain_info * + ads_get_root_domain(struct be_ctx *be_ctx, struct sysdb_attrs *attrs) + { +- struct sss_domain_info *root; ++ struct sss_domain_info *dom; + const char *name; + errno_t ret; + +@@ -909,9 +929,22 @@ ads_get_root_domain(struct be_ctx *be_ctx, struct sysdb_attrs *attrs) + } + + /* With a subsequent run, the root should already be known */ +- root = find_domain_by_name(be_ctx->domain, name, false); ++ for (dom = be_ctx->domain; dom != NULL; ++ dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) { + +- return root; ++ if (strcasecmp(dom->name, name) == 0) { ++ /* The forest root is special, although it might be disabled for ++ * general lookups we still want to try to get the domains in the ++ * forest from a DC of the forest root */ ++ if (sss_domain_get_state(dom) == DOM_DISABLED ++ && !sss_domain_is_forest_root(dom)) { ++ return NULL; ++ } ++ return dom; ++ } ++ } ++ ++ return NULL; + } + + static struct ad_id_ctx * +-- +2.9.3 + diff --git a/SOURCES/0116-watchdog-cope-with-time-shift.patch b/SOURCES/0116-watchdog-cope-with-time-shift.patch deleted file mode 100644 index dbea5c2..0000000 --- a/SOURCES/0116-watchdog-cope-with-time-shift.patch +++ /dev/null @@ -1,96 +0,0 @@ -From c99c5bb88c8b02f24a2b0b15ea8bc9fe2a8dc6c4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Mon, 22 Aug 2016 13:15:04 +0200 -Subject: [PATCH 116/117] watchdog: cope with time shift -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When a time is changed into the past during sssd runtime -(e.g. on boot during time correction), it is possible that -we never hit watchdog tevent timer since it is based on -system time. - -This patch adds a past-time shift detection mechanism. If a time -shift is detected we restart watchdog. - -Resolves: -https://fedorahosted.org/sssd/ticket/3154 - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Fabiano Fidêncio ---- - src/util/util_watchdog.c | 41 +++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 41 insertions(+) - -diff --git a/src/util/util_watchdog.c b/src/util/util_watchdog.c -index 5032fddba1b94b3fc7e560162c392dfa57d699cf..1c27d73f13b3042ecb549a2184e1368e8339d199 100644 ---- a/src/util/util_watchdog.c -+++ b/src/util/util_watchdog.c -@@ -29,8 +29,39 @@ struct watchdog_ctx { - struct timeval interval; - struct tevent_timer *te; - volatile int ticks; -+ -+ /* To detect time shift. */ -+ struct tevent_context *ev; -+ int input_interval; -+ time_t timestamp; - } watchdog_ctx; - -+static bool watchdog_detect_timeshift(void) -+{ -+ time_t prev_time; -+ time_t cur_time; -+ errno_t ret; -+ -+ prev_time = watchdog_ctx.timestamp; -+ cur_time = watchdog_ctx.timestamp = time(NULL); -+ if (cur_time < prev_time) { -+ /* Time shift detected. We need to restart watchdog. */ -+ DEBUG(SSSDBG_IMPORTANT_INFO, "Time shift detected, " -+ "restarting watchdog!\n"); -+ teardown_watchdog(); -+ ret = setup_watchdog(watchdog_ctx.ev, watchdog_ctx.input_interval); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to restart watchdog " -+ "[%d]: %s\n", ret, sss_strerror(ret)); -+ orderly_shutdown(1); -+ } -+ -+ return true; -+ } -+ -+ return false; -+} -+ - /* the watchdog is purposefully *not* handled by the tevent - * signal handler as it is meant to check if the daemon is - * still processing the event queue itself. A stuck process -@@ -38,6 +69,12 @@ struct watchdog_ctx { - * signals either */ - static void watchdog_handler(int sig) - { -+ /* Do not count ticks if time shift was detected -+ * since watchdog was restarted. */ -+ if (watchdog_detect_timeshift()) { -+ return; -+ } -+ - /* if 3 ticks passed by kills itself */ - - if (__sync_add_and_fetch(&watchdog_ctx.ticks, 1) > 3) { -@@ -101,6 +138,10 @@ int setup_watchdog(struct tevent_context *ev, int interval) - watchdog_ctx.interval.tv_sec = interval; - watchdog_ctx.interval.tv_usec = 0; - -+ watchdog_ctx.ev = ev; -+ watchdog_ctx.input_interval = interval; -+ watchdog_ctx.timestamp = time(NULL); -+ - /* Start the timer */ - /* we give 1 second head start to the watchdog event */ - its.it_value.tv_sec = interval + 1; --- -2.4.11 - diff --git a/SOURCES/0117-PROXY-Use-the-fqname-when-converting-to-lowercase.patch b/SOURCES/0117-PROXY-Use-the-fqname-when-converting-to-lowercase.patch deleted file mode 100644 index a41eedb..0000000 --- a/SOURCES/0117-PROXY-Use-the-fqname-when-converting-to-lowercase.patch +++ /dev/null @@ -1,39 +0,0 @@ -From fe4117b3203c0464b1366066bf09d83978c632d8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Tue, 23 Aug 2016 23:46:59 +0200 -Subject: [PATCH 117/117] PROXY: Use the fqname when converting to lowercase -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When saving the user there is a comparison between the "cased alias" -and the "lowercase password name". However, the first doesn't use fully -qualified name while the second does, resulting in a not expected -override of the "nameAlias" attribute of a stored user when trying to -authenticate more than once using an alias. - -Resolves: -https://fedorahosted.org/sssd/ticket/3134 - -Signed-off-by: Fabiano Fidêncio -Reviewed-by: Lukáš Slebodník ---- - src/providers/proxy/proxy_id.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c -index f633a5e1c71dfc7f8d124e62169cfda48773bbb1..df8a329d4a5a4bd7ed7723d0219089e7b4ef639d 100644 ---- a/src/providers/proxy/proxy_id.c -+++ b/src/providers/proxy/proxy_id.c -@@ -256,7 +256,7 @@ static int save_user(struct sss_domain_info *domain, - } - - if (lowercase) { -- lc_pw_name = sss_tc_utf8_str_tolower(attrs, pwd->pw_name); -+ lc_pw_name = sss_tc_utf8_str_tolower(attrs, real_name); - if (lc_pw_name == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n"); - ret = ENOMEM; --- -2.4.11 - diff --git a/SOURCES/0117-SDAP-Fix-handling-of-search-bases.patch b/SOURCES/0117-SDAP-Fix-handling-of-search-bases.patch new file mode 100644 index 0000000..52c114d --- /dev/null +++ b/SOURCES/0117-SDAP-Fix-handling-of-search-bases.patch @@ -0,0 +1,168 @@ +From ef6d1aaaa416bca3318e2961269620db7720a55b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Tue, 11 Apr 2017 19:56:37 +0200 +Subject: [PATCH 117/118] SDAP: Fix handling of search bases + +We were rewriting the sdap_domain's search bases for only the first +sdap_domain in the list, which does not work for subdomains. + +Also when search bases were already initialized in sdap_domain_subdom_add, +we should only rewrite them when they were explicitly set in sssd.conf. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3351 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 4c49edbd8df651b1737c59459637962c117212c6) +--- + src/providers/ad/ad_common.c | 39 +++++++++++++++++++++---------- + src/providers/ad/ad_common.h | 3 ++- + src/providers/ipa/ipa_subdomains_server.c | 2 +- + src/providers/ldap/ldap_options.c | 2 -- + 4 files changed, 30 insertions(+), 16 deletions(-) + +diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c +index f893b748a2ddcff1eab6e8d919d2aa950b825446..1a9d8dc0bfdf18e76e3c97a7ac7e297c4d24fd44 100644 +--- a/src/providers/ad/ad_common.c ++++ b/src/providers/ad/ad_common.c +@@ -29,7 +29,8 @@ struct ad_server_data { + bool gc; + }; + +-errno_t ad_set_search_bases(struct sdap_options *id_opts); ++errno_t ad_set_search_bases(struct sdap_options *id_opts, ++ struct sdap_domain *sdap); + static errno_t ad_set_sdap_options(struct ad_options *ad_opts, + struct sdap_options *id_opts); + +@@ -1074,7 +1075,7 @@ ad_get_id_options(struct ad_options *ad_opts, + } + + /* Set up search bases if they were assigned explicitly */ +- ret = ad_set_search_bases(id_opts); ++ ret = ad_set_search_bases(id_opts, NULL); + if (ret != EOK) { + talloc_free(id_opts); + return ret; +@@ -1116,11 +1117,14 @@ ad_get_autofs_options(struct ad_options *ad_opts, + } + + errno_t +-ad_set_search_bases(struct sdap_options *id_opts) ++ad_set_search_bases(struct sdap_options *id_opts, ++ struct sdap_domain *sdom) + { + errno_t ret; +- char *default_search_base; ++ char *default_search_base = NULL; + size_t o; ++ struct sdap_domain *sdap_dom; ++ bool has_default; + const int search_base_options[] = { SDAP_USER_SEARCH_BASE, + SDAP_GROUP_SEARCH_BASE, + SDAP_NETGROUP_SEARCH_BASE, +@@ -1132,10 +1136,21 @@ ad_set_search_bases(struct sdap_options *id_opts) + * been specifically overridden. + */ + +- default_search_base = +- dp_opt_get_string(id_opts->basic, SDAP_SEARCH_BASE); ++ if (sdom != NULL) { ++ sdap_dom = sdom; ++ } else { ++ /* If no specific sdom was given, use the first in the list. */ ++ sdap_dom = id_opts->sdom; ++ } + +- if (default_search_base) { ++ has_default = sdap_dom->search_bases != NULL; ++ ++ if (has_default == false) { ++ default_search_base = ++ dp_opt_get_string(id_opts->basic, SDAP_SEARCH_BASE); ++ } ++ ++ if (default_search_base && has_default == false) { + /* set search bases if they are not */ + for (o = 0; search_base_options[o] != -1; o++) { + if (NULL == dp_opt_get_string(id_opts->basic, +@@ -1162,31 +1177,31 @@ ad_set_search_bases(struct sdap_options *id_opts) + /* Default search */ + ret = sdap_parse_search_base(id_opts, id_opts->basic, + SDAP_SEARCH_BASE, +- &id_opts->sdom->search_bases); ++ &sdap_dom->search_bases); + if (ret != EOK && ret != ENOENT) goto done; + + /* User search */ + ret = sdap_parse_search_base(id_opts, id_opts->basic, + SDAP_USER_SEARCH_BASE, +- &id_opts->sdom->user_search_bases); ++ &sdap_dom->user_search_bases); + if (ret != EOK && ret != ENOENT) goto done; + + /* Group search base */ + ret = sdap_parse_search_base(id_opts, id_opts->basic, + SDAP_GROUP_SEARCH_BASE, +- &id_opts->sdom->group_search_bases); ++ &sdap_dom->group_search_bases); + if (ret != EOK && ret != ENOENT) goto done; + + /* Netgroup search */ + ret = sdap_parse_search_base(id_opts, id_opts->basic, + SDAP_NETGROUP_SEARCH_BASE, +- &id_opts->sdom->netgroup_search_bases); ++ &sdap_dom->netgroup_search_bases); + if (ret != EOK && ret != ENOENT) goto done; + + /* Service search */ + ret = sdap_parse_search_base(id_opts, id_opts->basic, + SDAP_SERVICE_SEARCH_BASE, +- &id_opts->sdom->service_search_bases); ++ &sdap_dom->service_search_bases); + if (ret != EOK && ret != ENOENT) goto done; + + ret = EOK; +diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h +index 2981550f6c390929501ec8942e861b16ea0a5cb0..ce33b37c75f45ae72adb268858cce34759b8b02f 100644 +--- a/src/providers/ad/ad_common.h ++++ b/src/providers/ad/ad_common.h +@@ -130,7 +130,8 @@ struct ad_options *ad_create_1way_trust_options(TALLOC_CTX *mem_ctx, + const char *keytab, + const char *sasl_authid); + +-errno_t ad_set_search_bases(struct sdap_options *id_opts); ++errno_t ad_set_search_bases(struct sdap_options *id_opts, ++ struct sdap_domain *sdap); + + errno_t + ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *ctx, +diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c +index e8ee30392d84f84e30bcdaa3d2110ba130b1ad73..b02ea67af964a03e5466067cdb2b3ba4498120eb 100644 +--- a/src/providers/ipa/ipa_subdomains_server.c ++++ b/src/providers/ipa/ipa_subdomains_server.c +@@ -332,7 +332,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx, + return EFAULT; + } + +- ret = ad_set_search_bases(ad_options->id); ++ ret = ad_set_search_bases(ad_options->id, sdom); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD search bases\n"); + talloc_free(ad_options); +diff --git a/src/providers/ldap/ldap_options.c b/src/providers/ldap/ldap_options.c +index 15a2609f07506b6dd442b180651a7e25461976c0..eb4e177b456253ebdfa06ee52886a5dffe0d3351 100644 +--- a/src/providers/ldap/ldap_options.c ++++ b/src/providers/ldap/ldap_options.c +@@ -581,8 +581,6 @@ errno_t sdap_parse_search_base(TALLOC_CTX *mem_ctx, + char *unparsed_base; + const char *old_filter = NULL; + +- *_search_bases = NULL; +- + switch (class) { + case SDAP_SEARCH_BASE: + class_name = "DEFAULT"; +-- +2.9.3 + diff --git a/SOURCES/0118-BUILD-Allow-to-read-private-pipes-for-root.patch b/SOURCES/0118-BUILD-Allow-to-read-private-pipes-for-root.patch deleted file mode 100644 index 8d87aad..0000000 --- a/SOURCES/0118-BUILD-Allow-to-read-private-pipes-for-root.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 711a29023252013a8451ee1b90f045782fee1a38 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Fri, 19 Aug 2016 10:46:12 +0200 -Subject: [PATCH 118/121] BUILD: Allow to read private pipes for root - -Root can read anything from any directory even with permissions 000. - -However SELinux checks discretionary access control (DAC) -and deny access if access is not allowed for root by DAC. -The pam_sss use different unix socket /var/lib/sss/pipes/private/pam -for user with uid 0. Therefore root need to be able read content -of directory with private pipes. - -type=AVC msg=audit(08/19/2016 10:58:34.081:3369) : avc: denied - { dac_read_search } for pid=20257 comm=vsftpd capability=dac_read_search - scontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023 - tcontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023 tclass=capability - -type=AVC msg=audit(08/19/2016 10:58:34.081:3369) : avc: denied - { dac_override } for pid=20257 comm=vsftpd capability=dac_override - scontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023 - tcontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023 tclass=capability - -Resolves: -https://fedorahosted.org/sssd/ticket/3143 - -Reviewed-by: Jakub Hrozek ---- - Makefile.am | 8 ++++---- - contrib/sssd.spec.in | 2 +- - 2 files changed, 5 insertions(+), 5 deletions(-) - -diff --git a/Makefile.am b/Makefile.am -index 6ab4399d5b68644668198bc9b0e3056562a4e51a..b8cd8b64ca8a130a5dd3107e1fb1445310192059 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -3967,7 +3967,6 @@ SSSD_USER_DIRS = \ - $(DESTDIR)$(keytabdir) \ - $(DESTDIR)$(mcpath) \ - $(DESTDIR)$(pipepath) \ -- $(DESTDIR)$(pipepath)/private \ - $(DESTDIR)$(pubconfpath) \ - $(DESTDIR)$(pubconfpath)/krb5.include.d \ - $(DESTDIR)$(gpocachepath) \ -@@ -3994,16 +3993,17 @@ installsssddirs:: - $(DESTDIR)$(sssddatadir) \ - $(DESTDIR)$(sudolibdir) \ - $(DESTDIR)$(autofslibdir) \ -+ $(DESTDIR)$(pipepath)/private \ - $(SSSD_USER_DIRS) \ - $(NULL); - if SSSD_USER -- -chown $(SSSD_USER):$(SSSD_USER) \ -- $(SSSD_USER_DIRS) -+ -chown $(SSSD_USER):$(SSSD_USER) $(SSSD_USER_DIRS) -+ -chown $(SSSD_USER) $(DESTDIR)$(pipepath)/private - endif - $(INSTALL) -d -m 0700 $(DESTDIR)$(dbpath) $(DESTDIR)$(logpath) \ -- $(DESTDIR)$(pipepath)/private \ - $(DESTDIR)$(keytabdir) \ - $(NULL) -+ $(INSTALL) -d -m 0750 $(DESTDIR)$(pipepath)/private - $(INSTALL) -d -m 0755 $(DESTDIR)$(mcpath) $(DESTDIR)$(pipepath) \ - $(DESTDIR)$(pubconfpath) \ - $(DESTDIR)$(pubconfpath)/krb5.include.d $(DESTDIR)$(gpocachepath) -diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in -index f1ff16176cb8ca974b98948958cfa1e9290b0bca..cb68a73e85122b016de7df37bcf4fc232a10a2ac 100644 ---- a/contrib/sssd.spec.in -+++ b/contrib/sssd.spec.in -@@ -784,7 +784,7 @@ done - %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/group - %ghost %attr(0644,sssd,sssd) %verify(not md5 size mtime) %{mcpath}/initgroups - %attr(755,sssd,sssd) %dir %{pipepath} --%attr(700,sssd,sssd) %dir %{pipepath}/private -+%attr(750,sssd,root) %dir %{pipepath}/private - %attr(755,sssd,sssd) %dir %{pubconfpath} - %attr(755,sssd,sssd) %dir %{gpocachepath} - %attr(750,sssd,sssd) %dir %{_var}/log/%{name} --- -2.4.11 - diff --git a/SOURCES/0118-overrides-add-certificates-to-mapped-attribute.patch b/SOURCES/0118-overrides-add-certificates-to-mapped-attribute.patch new file mode 100644 index 0000000..2bfa2c1 --- /dev/null +++ b/SOURCES/0118-overrides-add-certificates-to-mapped-attribute.patch @@ -0,0 +1,102 @@ +From 4a3f3c675e360c888da7d23ab6ec4cca10876b08 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 27 Apr 2017 09:28:55 +0200 +Subject: [PATCH 118/118] overrides: add certificates to mapped attribute +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Certificates in overrides are explicitly used to map users to +certificates, so we add them to SYSDB_USER_MAPPED_CERT as well. + +Resolves https://pagure.io/SSSD/sssd/issue/3373 + +Reviewed-by: Pavel Březina +(cherry picked from commit 2e5fc89ef25434fab7febe2c52e97ef989b50d5b) +--- + src/db/sysdb_views.c | 41 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 41 insertions(+) + +diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c +index 20db9b06183d68b33bb19f498513d7f5cf84b1cf..3773dda77e16b35fa217be0aa7974da7e34c09f4 100644 +--- a/src/db/sysdb_views.c ++++ b/src/db/sysdb_views.c +@@ -777,6 +777,7 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain, + int ret; + TALLOC_CTX *tmp_ctx; + struct sysdb_attrs *attrs; ++ struct sysdb_attrs *mapped_attrs = NULL; + size_t c; + size_t d; + size_t num_values; +@@ -791,6 +792,7 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain, + SYSDB_USER_CERT, + NULL }; + bool override_attrs_found = false; ++ bool is_cert = false; + + if (override_attrs == NULL) { + /* nothing to do */ +@@ -846,6 +848,24 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain, + num_values = 1; + } + ++ is_cert = false; ++ if (strcmp(allowed_attrs[c], SYSDB_USER_CERT) == 0) { ++ /* Certificates in overrides are explicitly used to map ++ * users to certificates, so we add them to ++ * SYSDB_USER_MAPPED_CERT as well. */ ++ is_cert = true; ++ ++ if (mapped_attrs == NULL) { ++ mapped_attrs = sysdb_new_attrs(tmp_ctx); ++ if (mapped_attrs == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_new_attrs failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ } ++ + for (d = 0; d < num_values; d++) { + ret = sysdb_attrs_add_val(attrs, allowed_attrs[c], + &el->values[d]); +@@ -854,6 +874,18 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain, + "sysdb_attrs_add_val failed.\n"); + goto done; + } ++ ++ if (is_cert) { ++ ret = sysdb_attrs_add_val(mapped_attrs, ++ SYSDB_USER_MAPPED_CERT, ++ &el->values[d]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_attrs_add_val failed.\n"); ++ goto done; ++ } ++ } ++ + DEBUG(SSSDBG_TRACE_ALL, + "Override [%s] with [%.*s] for [%s].\n", + allowed_attrs[c], (int) el->values[d].length, +@@ -878,6 +910,15 @@ errno_t sysdb_apply_default_override(struct sss_domain_info *domain, + DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_entry_attr failed.\n"); + goto done; + } ++ ++ if (mapped_attrs != NULL) { ++ ret = sysdb_set_entry_attr(domain->sysdb, obj_dn, mapped_attrs, ++ SYSDB_MOD_ADD); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_set_entry_attr failed, ignored.\n"); ++ } ++ } + } + + ret = EOK; +-- +2.9.3 + diff --git a/SOURCES/0119-AD-Make-ad_account_can_shortcut-reusable-by-SSSD-on-.patch b/SOURCES/0119-AD-Make-ad_account_can_shortcut-reusable-by-SSSD-on-.patch new file mode 100644 index 0000000..c9874b9 --- /dev/null +++ b/SOURCES/0119-AD-Make-ad_account_can_shortcut-reusable-by-SSSD-on-.patch @@ -0,0 +1,243 @@ +From 54790675d0fd0627f7db8449ef97d59c0632006e Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 24 Apr 2017 10:13:44 +0200 +Subject: [PATCH 119/119] AD: Make ad_account_can_shortcut() reusable by SSSD + on an IPA server +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves: + https://pagure.io/SSSD/sssd/issue/3318 + +The ad_account_can_shortcut() function is helpful to avoid unnecessary +searches when SSSD is configured with an Active Directory domain that +uses ID-mapping in the sense that if we find that an ID is outside our +range, we can just abort the search in this domain and carry on. + +This function was only used in the AD provider functions which are used +when SSSD is enrolled direcly with an AD server. This patch moves the +function to a codepath that is shared between directly enrolled SSSD and +SSSD running on an IPA server. + +Apart from moving the code, there are some minor changes to the function +signature, namely the domain is passed as as struct (previously the +domain name from the DP input was passed). + +Reviewed-by: Michal Židek +(cherry picked from commit dfe05f505dcfea16e7d66ca1a44206aa2570e861) +--- + src/providers/ad/ad_id.c | 162 ++++++++++++++++++++++++----------------------- + 1 file changed, 84 insertions(+), 78 deletions(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index 8f26cb8744d2372c6180342c0d1bca025b16f52c..d1f6c444f5ddbcbbac6ff7f41fb6c8bf9ca976cb 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -50,6 +50,77 @@ disable_gc(struct ad_options *ad_options) + } + } + ++static bool ad_account_can_shortcut(struct sdap_idmap_ctx *idmap_ctx, ++ struct sss_domain_info *domain, ++ int filter_type, ++ const char *filter_value) ++{ ++ struct sss_domain_info *dom_head = NULL; ++ struct sss_domain_info *sid_dom = NULL; ++ enum idmap_error_code err; ++ char *sid = NULL; ++ const char *csid = NULL; ++ uint32_t id; ++ bool shortcut = false; ++ errno_t ret; ++ ++ if (!sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, domain->name, ++ domain->domain_id)) { ++ goto done; ++ } ++ ++ switch (filter_type) { ++ case BE_FILTER_IDNUM: ++ /* convert value to ID */ ++ errno = 0; ++ id = strtouint32(filter_value, NULL, 10); ++ if (errno != 0) { ++ ret = errno; ++ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to convert filter value to " ++ "number [%d]: %s\n", ret, strerror(ret)); ++ goto done; ++ } ++ ++ /* convert the ID to its SID equivalent */ ++ err = sss_idmap_unix_to_sid(idmap_ctx->map, id, &sid); ++ if (err != IDMAP_SUCCESS) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Mapping ID [%s] to SID failed: " ++ "[%s]\n", filter_value, idmap_error_string(err)); ++ goto done; ++ } ++ /* fall through */ ++ SSS_ATTRIBUTE_FALLTHROUGH; ++ case BE_FILTER_SECID: ++ csid = sid == NULL ? filter_value : sid; ++ ++ dom_head = get_domains_head(domain); ++ if (dom_head == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find domain head\n"); ++ goto done; ++ } ++ ++ sid_dom = find_domain_by_sid(dom_head, csid); ++ if (sid_dom == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "Invalid domain for SID:%s\n", csid); ++ goto done; ++ } ++ ++ if (strcasecmp(sid_dom->name, domain->name) != 0) { ++ shortcut = true; ++ } ++ break; ++ default: ++ break; ++ } ++ ++done: ++ if (sid != NULL) { ++ sss_idmap_free_sid(idmap_ctx->map, sid); ++ } ++ ++ return shortcut; ++} ++ + struct ad_handle_acct_info_state { + struct dp_id_data *ar; + struct sdap_id_ctx *ctx; +@@ -78,6 +149,7 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx, + struct ad_handle_acct_info_state *state; + struct be_ctx *be_ctx = ctx->be; + errno_t ret; ++ bool shortcut; + + req = tevent_req_create(mem_ctx, &state, struct ad_handle_acct_info_state); + if (req == NULL) { +@@ -90,6 +162,18 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx, + state->ad_options = ad_options; + state->cindex = 0; + ++ /* Try to shortcut if this is ID or SID search and it belongs to ++ * other domain range than is in ar->domain. */ ++ shortcut = ad_account_can_shortcut(ctx->opts->idmap_ctx, ++ sdom->dom, ++ ar->filter_type, ++ ar->filter_value); ++ if (shortcut) { ++ DEBUG(SSSDBG_TRACE_FUNC, "This ID is from different domain\n"); ++ ret = EOK; ++ goto immediate; ++ } ++ + if (sss_domain_get_state(sdom->dom) == DOM_INACTIVE) { + ret = ERR_SUBDOM_INACTIVE; + goto immediate; +@@ -297,72 +381,6 @@ get_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx, + return clist; + } + +-static bool ad_account_can_shortcut(struct be_ctx *be_ctx, +- struct sdap_idmap_ctx *idmap_ctx, +- int filter_type, +- const char *filter_value, +- const char *filter_domain) +-{ +- struct sss_domain_info *domain = be_ctx->domain; +- struct sss_domain_info *req_dom = NULL; +- enum idmap_error_code err; +- char *sid = NULL; +- const char *csid = NULL; +- uint32_t id; +- bool shortcut = false; +- errno_t ret; +- +- if (!sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, domain->name, +- domain->domain_id)) { +- goto done; +- } +- +- switch (filter_type) { +- case BE_FILTER_IDNUM: +- /* convert value to ID */ +- errno = 0; +- id = strtouint32(filter_value, NULL, 10); +- if (errno != 0) { +- ret = errno; +- DEBUG(SSSDBG_MINOR_FAILURE, "Unable to convert filter value to " +- "number [%d]: %s\n", ret, strerror(ret)); +- goto done; +- } +- +- /* convert the ID to its SID equivalent */ +- err = sss_idmap_unix_to_sid(idmap_ctx->map, id, &sid); +- if (err != IDMAP_SUCCESS) { +- DEBUG(SSSDBG_MINOR_FAILURE, "Mapping ID [%s] to SID failed: " +- "[%s]\n", filter_value, idmap_error_string(err)); +- goto done; +- } +- /* fall through */ +- SSS_ATTRIBUTE_FALLTHROUGH; +- case BE_FILTER_SECID: +- csid = sid == NULL ? filter_value : sid; +- +- req_dom = find_domain_by_sid(domain, csid); +- if (req_dom == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "Invalid domain for SID:%s\n", csid); +- goto done; +- } +- +- if (strcasecmp(req_dom->name, filter_domain) != 0) { +- shortcut = true; +- } +- break; +- default: +- break; +- } +- +-done: +- if (sid != NULL) { +- sss_idmap_free_sid(idmap_ctx->map, sid); +- } +- +- return shortcut; +-} +- + struct ad_account_info_handler_state { + struct sss_domain_info *domain; + struct dp_reply_std reply; +@@ -384,7 +402,6 @@ ad_account_info_handler_send(TALLOC_CTX *mem_ctx, + struct tevent_req *subreq; + struct tevent_req *req; + struct be_ctx *be_ctx; +- bool shortcut; + errno_t ret; + + sdap_id_ctx = id_ctx->sdap_id_ctx; +@@ -403,17 +420,6 @@ ad_account_info_handler_send(TALLOC_CTX *mem_ctx, + goto immediately; + } + +- /* Try to shortcut if this is ID or SID search and it belongs to +- * other domain range than is in ar->domain. */ +- shortcut = ad_account_can_shortcut(be_ctx, sdap_id_ctx->opts->idmap_ctx, +- data->filter_type, data->filter_value, +- data->domain); +- if (shortcut) { +- DEBUG(SSSDBG_TRACE_FUNC, "This ID is from different domain\n"); +- ret = EOK; +- goto immediately; +- } +- + domain = be_ctx->domain; + if (strcasecmp(data->domain, be_ctx->domain->name) != 0) { + /* Subdomain request, verify subdomain. */ +-- +2.9.3 + diff --git a/SOURCES/0119-SYSDB-Rework-sysdb_cache_connect.patch b/SOURCES/0119-SYSDB-Rework-sysdb_cache_connect.patch deleted file mode 100644 index bc2bacb..0000000 --- a/SOURCES/0119-SYSDB-Rework-sysdb_cache_connect.patch +++ /dev/null @@ -1,123 +0,0 @@ -From 960eca66245f23cf8ae0f32c3e44581a0e1117f9 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Tue, 16 Aug 2016 11:20:49 +0200 -Subject: [PATCH 119/121] SYSDB: Rework sysdb_cache_connect() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -As sysdb_cache_connect() has two very specific use cases (connect to the -cache and connect to the timestamp cache) and each of those calls have a -predetermined/fixed sets of values for a few parameters, let's try to -make the code a bit simpler to follow by having explicit functions for -connecting to the cache and connecting to the timestamp cache. - -Macros could be used as well, but I have a slightly preference for -having two new functions instead of macros accessing internal parameters -of the macro's parameter. - -Related: -https://fedorahosted.org/sssd/ticket/3128 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Jakub Hrozek ---- - src/db/sysdb_init.c | 53 ++++++++++++++++++++++++++++++++++------------------- - 1 file changed, 34 insertions(+), 19 deletions(-) - -diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c -index 9e3646bfeb9a494ebff2d348ab1c53336f8a5c03..59934701c4d2b9d770385a202af058404a6d3eb9 100644 ---- a/src/db/sysdb_init.c -+++ b/src/db/sysdb_init.c -@@ -511,14 +511,14 @@ done: - return ret; - } - --static errno_t sysdb_cache_connect(TALLOC_CTX *mem_ctx, -- struct sss_domain_info *domain, -- const char *ldb_file, -- int flags, -- const char *exp_version, -- const char *base_ldif, -- struct ldb_context **_ldb, -- const char **_version) -+static errno_t sysdb_cache_connect_helper(TALLOC_CTX *mem_ctx, -+ struct sss_domain_info *domain, -+ const char *ldb_file, -+ int flags, -+ const char *exp_version, -+ const char *base_ldif, -+ struct ldb_context **_ldb, -+ const char **_version) - { - TALLOC_CTX *tmp_ctx = NULL; - struct ldb_message_element *el; -@@ -619,6 +619,29 @@ done: - return ret; - } - -+static errno_t sysdb_cache_connect(TALLOC_CTX *mem_ctx, -+ struct sysdb_ctx *sysdb, -+ struct sss_domain_info *domain, -+ struct ldb_context **ldb, -+ const char **version) -+{ -+ return sysdb_cache_connect_helper(mem_ctx, domain, sysdb->ldb_file, -+ 0, SYSDB_VERSION, SYSDB_BASE_LDIF, -+ ldb, version); -+} -+ -+static errno_t sysdb_ts_cache_connect(TALLOC_CTX *mem_ctx, -+ struct sysdb_ctx *sysdb, -+ struct sss_domain_info *domain, -+ struct ldb_context **ldb, -+ const char **version) -+{ -+ return sysdb_cache_connect_helper(mem_ctx, domain, sysdb->ldb_ts_file, -+ LDB_FLG_NOSYNC, SYSDB_TS_VERSION, -+ SYSDB_TS_BASE_LDIF, -+ ldb, version); -+} -+ - static errno_t remove_ts_cache(struct sysdb_ctx *sysdb) - { - errno_t ret; -@@ -649,9 +672,7 @@ static int sysdb_domain_cache_connect(struct sysdb_ctx *sysdb, - return ENOMEM; - } - -- ret = sysdb_cache_connect(tmp_ctx, domain, sysdb->ldb_file, 0, -- SYSDB_VERSION, SYSDB_BASE_LDIF, -- &ldb, &version); -+ ret = sysdb_cache_connect(tmp_ctx, sysdb, domain, &ldb, &version); - switch (ret) { - case ERR_SYSDB_VERSION_TOO_OLD: - if (upgrade_ctx == NULL) { -@@ -731,10 +752,7 @@ static int sysdb_timestamp_cache_connect(struct sysdb_ctx *sysdb, - return ENOMEM; - } - -- ret = sysdb_cache_connect(tmp_ctx, domain, -- sysdb->ldb_ts_file, LDB_FLG_NOSYNC, -- SYSDB_TS_VERSION, SYSDB_TS_BASE_LDIF, -- &ldb, &version); -+ ret = sysdb_ts_cache_connect(tmp_ctx, sysdb, domain, &ldb, &version); - switch (ret) { - case ERR_SYSDB_VERSION_TOO_OLD: - if (upgrade_ctx == NULL) { -@@ -801,10 +819,7 @@ static int sysdb_timestamp_cache_connect(struct sysdb_ctx *sysdb, - /* Now the connect must succeed because the previous cache doesn't - * exist anymore. - */ -- ret = sysdb_cache_connect(tmp_ctx, domain, -- sysdb->ldb_ts_file, LDB_FLG_NOSYNC, -- SYSDB_TS_VERSION, SYSDB_TS_BASE_LDIF, -- &ldb, &version); -+ ret = sysdb_ts_cache_connect(tmp_ctx, sysdb, domain, &ldb, &version); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, - "Could not delete the timestamp ldb file (%d) (%s)\n", --- -2.4.11 - diff --git a/SOURCES/0120-LDAP-AD-Do-not-fail-in-case-rfc2307bis_nested_groups.patch b/SOURCES/0120-LDAP-AD-Do-not-fail-in-case-rfc2307bis_nested_groups.patch new file mode 100644 index 0000000..abe44ec --- /dev/null +++ b/SOURCES/0120-LDAP-AD-Do-not-fail-in-case-rfc2307bis_nested_groups.patch @@ -0,0 +1,47 @@ +From 428909abd59f1eb8bb02b6627f37f61af3de2691 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 1 May 2017 14:49:50 +0200 +Subject: [PATCH 120/120] LDAP/AD: Do not fail in case + rfc2307bis_nested_groups_recv() returns ENOENT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 25699846 introduced a regression seen when an initgroup lookup is +done and there's no nested groups involved. + +In this scenario the whole lookup fails due to an ENOENT returned by +rfc2307bis_nested_groups_recv(), which leads to the user removal from +sysdb causing some authentication issues. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3331 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Sumit Bose +--- + src/providers/ldap/sdap_async_initgroups_ad.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c +index f75b9211e2a06616dbf9b948e60b023a818c7e19..2831be9776293260aeec0e2ff85160f1938bdb32 100644 +--- a/src/providers/ldap/sdap_async_initgroups_ad.c ++++ b/src/providers/ldap/sdap_async_initgroups_ad.c +@@ -1746,7 +1746,13 @@ static void sdap_ad_get_domain_local_groups_done(struct tevent_req *subreq) + + ret = rfc2307bis_nested_groups_recv(subreq); + talloc_zfree(subreq); +- if (ret != EOK) { ++ if (ret == ENOENT) { ++ /* In case of ENOENT we can just proceed without making ++ * sdap_get_initgr_user() fail because there's no nested ++ * groups for this user/group. */ ++ ret = EOK; ++ goto done; ++ } else if (ret != EOK) { + tevent_req_error(req, ret); + return; + } +-- +2.9.3 + diff --git a/SOURCES/0120-SYSDB-Remove-the-timestamp-cache-for-a-newly-created.patch b/SOURCES/0120-SYSDB-Remove-the-timestamp-cache-for-a-newly-created.patch deleted file mode 100644 index 9145773..0000000 --- a/SOURCES/0120-SYSDB-Remove-the-timestamp-cache-for-a-newly-created.patch +++ /dev/null @@ -1,151 +0,0 @@ -From 9e5fc47e6636f6a149dba9a0a708892be85a6f22 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Tue, 16 Aug 2016 11:46:41 +0200 -Subject: [PATCH 120/121] SYSDB: Remove the timestamp cache for a newly created - cache -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -As many users are used to remove the persistent cache without removing -the timestamp cache, let's throw away the timestamp cache in this case. - -Resolves: -https://fedorahosted.org/sssd/ticket/3128 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Jakub Hrozek ---- - src/db/sysdb_init.c | 69 ++++++++++++++++++++++++++++++++++++----------------- - 1 file changed, 47 insertions(+), 22 deletions(-) - -diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c -index 59934701c4d2b9d770385a202af058404a6d3eb9..c387c1b12c116f38d5a13f1adeac5ef64d593af8 100644 ---- a/src/db/sysdb_init.c -+++ b/src/db/sysdb_init.c -@@ -511,12 +511,30 @@ done: - return ret; - } - -+static errno_t remove_ts_cache(struct sysdb_ctx *sysdb) -+{ -+ errno_t ret; -+ -+ if (sysdb->ldb_ts_file == NULL) { -+ return EOK; -+ } -+ -+ ret = unlink(sysdb->ldb_ts_file); -+ if (ret != EOK && errno != ENOENT) { -+ return errno; -+ } -+ -+ return EOK; -+} -+ - static errno_t sysdb_cache_connect_helper(TALLOC_CTX *mem_ctx, -+ struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - const char *ldb_file, - int flags, - const char *exp_version, - const char *base_ldif, -+ bool *_newly_created, - struct ldb_context **_ldb, - const char **_version) - { -@@ -527,6 +545,7 @@ static errno_t sysdb_cache_connect_helper(TALLOC_CTX *mem_ctx, - const char *version = NULL; - int ret; - struct ldb_context *ldb; -+ bool newly_created; - - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { -@@ -592,8 +611,9 @@ static errno_t sysdb_cache_connect_helper(TALLOC_CTX *mem_ctx, - goto done; - } - -- /* The cache has been newly created. -- * We need to reopen the LDB to ensure that -+ newly_created = true; -+ -+ /* We need to reopen the LDB to ensure that - * all of the special values take effect - * (such as enabling the memberOf plugin and - * the various indexes). -@@ -613,6 +633,9 @@ static errno_t sysdb_cache_connect_helper(TALLOC_CTX *mem_ctx, - } - done: - if (ret == EOK) { -+ if (_newly_created != NULL) { -+ *_newly_created = newly_created; -+ } - *_ldb = talloc_steal(mem_ctx, ldb); - } - talloc_free(tmp_ctx); -@@ -625,9 +648,27 @@ static errno_t sysdb_cache_connect(TALLOC_CTX *mem_ctx, - struct ldb_context **ldb, - const char **version) - { -- return sysdb_cache_connect_helper(mem_ctx, domain, sysdb->ldb_file, -+ bool newly_created; -+ bool ldb_file_exists; -+ errno_t ret; -+ -+ ldb_file_exists = !(access(sysdb->ldb_file, F_OK) == -1 && errno == ENOENT); -+ -+ ret = sysdb_cache_connect_helper(mem_ctx, sysdb, domain, sysdb->ldb_file, - 0, SYSDB_VERSION, SYSDB_BASE_LDIF, -- ldb, version); -+ &newly_created, ldb, version); -+ -+ /* The cache has been newly created. */ -+ if (ret == EOK && newly_created && !ldb_file_exists) { -+ ret = remove_ts_cache(sysdb); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Could not delete the timestamp ldb file (%d) (%s)\n", -+ ret, sss_strerror(ret)); -+ } -+ } -+ -+ return ret; - } - - static errno_t sysdb_ts_cache_connect(TALLOC_CTX *mem_ctx, -@@ -636,28 +677,12 @@ static errno_t sysdb_ts_cache_connect(TALLOC_CTX *mem_ctx, - struct ldb_context **ldb, - const char **version) - { -- return sysdb_cache_connect_helper(mem_ctx, domain, sysdb->ldb_ts_file, -+ return sysdb_cache_connect_helper(mem_ctx, sysdb, domain, sysdb->ldb_ts_file, - LDB_FLG_NOSYNC, SYSDB_TS_VERSION, -- SYSDB_TS_BASE_LDIF, -+ SYSDB_TS_BASE_LDIF, NULL, - ldb, version); - } - --static errno_t remove_ts_cache(struct sysdb_ctx *sysdb) --{ -- errno_t ret; -- -- if (sysdb->ldb_ts_file == NULL) { -- return EOK; -- } -- -- ret = unlink(sysdb->ldb_ts_file); -- if (ret != EOK && errno != ENOENT) { -- return errno; -- } -- -- return EOK; --} -- - static int sysdb_domain_cache_connect(struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - struct sysdb_dom_upgrade_ctx *upgrade_ctx) --- -2.4.11 - diff --git a/SOURCES/0121-PAM-check-matching-certificates-from-all-domains.patch b/SOURCES/0121-PAM-check-matching-certificates-from-all-domains.patch new file mode 100644 index 0000000..55c7c61 --- /dev/null +++ b/SOURCES/0121-PAM-check-matching-certificates-from-all-domains.patch @@ -0,0 +1,116 @@ +From 52514960f5b0609cd9f31f3c4455b61fbe4c04c5 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 26 Apr 2017 17:16:19 +0200 +Subject: [PATCH 121/121] PAM: check matching certificates from all domains + +Although the cache_req lookup found matching in multiple domains only +the results from the first domain were used. With this patch the results +from all domains are checked. + +Resolves https://pagure.io/SSSD/sssd/issue/3385 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 92d8b072f8c521e1b4effe109b5caedabd36ed6f) +--- + src/responder/pam/pamsrv_cmd.c | 69 ++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 63 insertions(+), 6 deletions(-) + +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index f2b3c74b483e527932dda42279d14a9ac184b475..10a178f839ec011c09a6da4575efbb026f3f7700 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1352,15 +1352,71 @@ done: + pam_check_user_done(preq, ret); + } + ++static errno_t get_results_from_all_domains(TALLOC_CTX *mem_ctx, ++ struct cache_req_result **results, ++ struct ldb_result **ldb_results) ++{ ++ int ret; ++ size_t count = 0; ++ size_t c; ++ size_t d; ++ size_t r = 0; ++ struct ldb_result *res; ++ ++ for (d = 0; results != NULL && results[d] != NULL; d++) { ++ count += results[d]->count; ++ } ++ ++ res = talloc_zero(mem_ctx, struct ldb_result); ++ if (res == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); ++ return ENOMEM; ++ } ++ ++ if (count == 0) { ++ *ldb_results = res; ++ return EOK; ++ } ++ ++ res->msgs = talloc_zero_array(res, struct ldb_message *, count); ++ if (res->msgs == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_array failed.\n"); ++ return ENOMEM; ++ } ++ res->count = count; ++ ++ for (d = 0; results != NULL && results[d] != NULL; d++) { ++ for (c = 0; c < results[d]->count; c++) { ++ if (r >= count) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "More results found then counted before.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ res->msgs[r++] = talloc_steal(res->msgs, results[d]->msgs[c]); ++ } ++ } ++ ++ *ldb_results = res; ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(res); ++ } ++ ++ return ret; ++} ++ + static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + { + int ret; +- struct cache_req_result *result; ++ struct cache_req_result **results; + struct pam_auth_req *preq = tevent_req_callback_data(req, + struct pam_auth_req); + const char *cert_user; + +- ret = cache_req_user_by_cert_recv(preq, req, &result); ++ ret = cache_req_recv(preq, req, &results); + talloc_zfree(req); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert request failed.\n"); +@@ -1368,12 +1424,13 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + } + + if (ret == EOK) { +- if (preq->domain == NULL) { +- preq->domain = result->domain; ++ ret = get_results_from_all_domains(preq, results, ++ &preq->cert_user_objs); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "get_results_from_all_domains failed.\n"); ++ goto done; + } + +- preq->cert_user_objs = talloc_steal(preq, result->ldb_result); +- + if (preq->pd->logon_name == NULL) { + if (preq->pd->cmd != SSS_PAM_PREAUTH) { + DEBUG(SSSDBG_CRIT_FAILURE, +-- +2.9.3 + diff --git a/SOURCES/0121-SECRETS-Return-ENOENT-when_deleting-a-non-existent-s.patch b/SOURCES/0121-SECRETS-Return-ENOENT-when_deleting-a-non-existent-s.patch deleted file mode 100644 index 80ff5bb..0000000 --- a/SOURCES/0121-SECRETS-Return-ENOENT-when_deleting-a-non-existent-s.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0f3b872aa881d5480fc98b0cfc7421ffc7f802a3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Wed, 17 Aug 2016 13:12:21 +0200 -Subject: [PATCH 121/121] SECRETS: Return ENOENT when_deleting a non-existent - secret -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -For this, just make use of the sysdb_error_to_errno() function. - -Resolves: -https://fedorahosted.org/sssd/ticket/3125 - -Signed-off-by: Fabiano Fidêncio - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Jakub Hrozek ---- - src/responder/secrets/local.c | 9 ++------- - 1 file changed, 2 insertions(+), 7 deletions(-) - -diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c -index 17469249b357cbdc5e50ddff6b563fdf2f377577..ac3049b62fa77f69d44ec5792139fe3378afb3f4 100644 ---- a/src/responder/secrets/local.c -+++ b/src/responder/secrets/local.c -@@ -375,15 +375,10 @@ int local_db_delete(TALLOC_CTX *mem_ctx, - int ret; - - ret = local_db_dn(mem_ctx, lctx->ldb, req_path, &dn); -- if (ret != EOK) goto done; -+ if (ret != EOK) return ret; - - ret = ldb_delete(lctx->ldb, dn); -- if (ret != EOK) { -- ret = EIO; -- } -- --done: -- return ret; -+ return sysdb_error_to_errno(ret); - } - - int local_db_create(TALLOC_CTX *mem_ctx, --- -2.4.11 - diff --git a/SOURCES/0122-DP-Reduce-Data-Provider-log-level-noise.patch b/SOURCES/0122-DP-Reduce-Data-Provider-log-level-noise.patch new file mode 100644 index 0000000..b7dfbd3 --- /dev/null +++ b/SOURCES/0122-DP-Reduce-Data-Provider-log-level-noise.patch @@ -0,0 +1,80 @@ +From b818bb3f27ce672df0a6cadf2fd90716d2a576dc Mon Sep 17 00:00:00 2001 +From: Justin Stephenson +Date: Wed, 26 Apr 2017 15:45:33 -0400 +Subject: [PATCH 122/127] DP: Reduce Data Provider log level noise +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Certain operations are not supported with certain providers +causing informational Data Provider log messages to be logged as +errors or failures. This patch lowers the log level to reduce overall +log noise and ensure only critical log messages are logged when +a low debug_level value is used. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3287 +https://pagure.io/SSSD/sssd/issue/3278 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Pavel Březina +(cherry picked from commit e98d085b529e0ae5e07a717ce3b30f3943be0ee0) +--- + src/providers/data_provider/dp_methods.c | 2 +- + src/providers/data_provider/dp_targets.c | 2 +- + src/responder/common/responder_dp.c | 13 +++++++++++-- + 3 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/src/providers/data_provider/dp_methods.c b/src/providers/data_provider/dp_methods.c +index 498676d1bec2da300ca4b33f7110debcbf0aac00..9e49c5f5d65b869b3699fdc682a535e0111b6fd4 100644 +--- a/src/providers/data_provider/dp_methods.c ++++ b/src/providers/data_provider/dp_methods.c +@@ -109,7 +109,7 @@ errno_t dp_find_method(struct data_provider *provider, + } + + if (!dp_target_initialized(provider->targets, target)) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Target [%s] is not initialized\n", ++ DEBUG(SSSDBG_CONF_SETTINGS, "Target [%s] is not initialized\n", + dp_target_to_string(target)); + return ERR_MISSING_DP_TARGET; + } +diff --git a/src/providers/data_provider/dp_targets.c b/src/providers/data_provider/dp_targets.c +index 26d20a8ef79b80d56df76d7a73ec8e63d001ecbc..e2a45bbac969ca7b9b13729f26b8cded8ab7eebc 100644 +--- a/src/providers/data_provider/dp_targets.c ++++ b/src/providers/data_provider/dp_targets.c +@@ -284,7 +284,7 @@ static errno_t dp_target_init(struct be_ctx *be_ctx, + if (!target->explicitly_configured && (ret == ELIBBAD || ret == ENOTSUP)) { + /* Target not found but it wasn't explicitly + * configured so we shall just continue. */ +- DEBUG(SSSDBG_CRIT_FAILURE, "Target [%s] is not supported by " ++ DEBUG(SSSDBG_CONF_SETTINGS, "Target [%s] is not supported by " + "module [%s].\n", target->name, target->module_name); + ret = EOK; + goto done; +diff --git a/src/responder/common/responder_dp.c b/src/responder/common/responder_dp.c +index 080f70fd5945ffd234e0ef226d8139df071c4752..a75a611960801f5f5bdc95f00aea9ab921e8e293 100644 +--- a/src/responder/common/responder_dp.c ++++ b/src/responder/common/responder_dp.c +@@ -218,8 +218,17 @@ static int sss_dp_get_reply(DBusPendingCall *pending, + err = ETIME; + goto done; + } +- DEBUG(SSSDBG_FATAL_FAILURE,"The Data Provider returned an error [%s]\n", +- dbus_message_get_error_name(reply)); ++ ++ if (strcmp(dbus_message_get_error_name(reply), ++ SBUS_ERROR_DP_NOTSUP) == 0) { ++ DEBUG(SSSDBG_CONF_SETTINGS, ++ "Data Provider does not support this operation.\n"); ++ } else { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "The Data Provider returned an error [%s]\n", ++ dbus_message_get_error_name(reply)); ++ } ++ + /* Falling through to default intentionally*/ + SSS_ATTRIBUTE_FALLTHROUGH; + default: +-- +2.9.3 + diff --git a/SOURCES/0122-IPA-Parse-qualified-names-when-guessing-AD-user-prin.patch b/SOURCES/0122-IPA-Parse-qualified-names-when-guessing-AD-user-prin.patch deleted file mode 100644 index 8bc504d..0000000 --- a/SOURCES/0122-IPA-Parse-qualified-names-when-guessing-AD-user-prin.patch +++ /dev/null @@ -1,61 +0,0 @@ -From b93f618189d9906802c79d3090fcc477f762e6e6 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 9 Aug 2016 22:08:27 +0200 -Subject: [PATCH 122/126] IPA: Parse qualified names when guessing AD user - principal - -Most AD users store their UPN in an attribute. If they don't, or the sssd -was configured (typically in earlier versions to work around a bug) to not -look at the principal attribute, then sssd is supposed to guess -the attribute. - -That currently doesn't work in 1.14, because the username is already -qualified and then we also append the realm name to it. We need to parse -the simple username from the qualified name first. - -The issue can be reproduced simply by authenticating as the Administrator -account in IPA-AD trust setups. - -Resolves: -https://fedorahosted.org/sssd/ticket/3127 - -Reviewed-by: Sumit Bose ---- - src/providers/ipa/ipa_s2n_exop.c | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) - -diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c -index 255dad45037a6cb8f399bf2df500215f6fb25b59..bfa6757046282d656627aa57cb9054b09facd2b8 100644 ---- a/src/providers/ipa/ipa_s2n_exop.c -+++ b/src/providers/ipa/ipa_s2n_exop.c -@@ -1941,6 +1941,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, - struct sss_nss_homedir_ctx homedir_ctx; - char *name = NULL; - char *realm; -+ char *short_name = NULL; - char *upn = NULL; - gid_t gid; - gid_t orig_gid = 0; -@@ -2092,8 +2093,17 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, - ret = ENOMEM; - goto done; - } -- upn = talloc_asprintf(tmp_ctx, "%s@%s", -- attrs->a.user.pw_name, realm); -+ -+ ret = sss_parse_internal_fqname(tmp_ctx, attrs->a.user.pw_name, -+ &short_name, NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "Cannot parse internal name %s\n", -+ attrs->a.user.pw_name); -+ goto done; -+ } -+ -+ upn = talloc_asprintf(tmp_ctx, "%s@%s", short_name, realm); - if (!upn) { - DEBUG(SSSDBG_OP_FAILURE, "failed to format UPN.\n"); - ret = ENOMEM; --- -2.4.11 - diff --git a/SOURCES/0123-NSS-Move-output-name-formatting-to-utils.patch b/SOURCES/0123-NSS-Move-output-name-formatting-to-utils.patch new file mode 100644 index 0000000..abc8b99 --- /dev/null +++ b/SOURCES/0123-NSS-Move-output-name-formatting-to-utils.patch @@ -0,0 +1,249 @@ +From 43b07b3fe8794a6e19db5cd2e9036e3d4d6c43ad Mon Sep 17 00:00:00 2001 +From: Nikolai Kondrashov +Date: Wed, 22 Mar 2017 14:32:35 +0200 +Subject: [PATCH 123/127] NSS: Move output name formatting to utils +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Move NSS nss_get_name_from_msg and the core of sized_output_name to the +utils to make them available to provider and other responders. + +Reviewed-by: Pavel Březina +(cherry picked from commit a012a71f21bf1a4687e58085f19c18cc5b2bbadd) +--- + src/responder/common/responder_common.c | 27 ++++--------- + src/responder/nss/nss_protocol_grent.c | 2 +- + src/responder/nss/nss_protocol_pwent.c | 2 +- + src/responder/nss/nss_protocol_sid.c | 2 +- + src/responder/nss/nss_utils.c | 27 ------------- + src/util/usertools.c | 67 +++++++++++++++++++++++++++++++++ + src/util/util.h | 9 +++++ + 7 files changed, 87 insertions(+), 49 deletions(-) + +diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c +index 7496d293fddb3e947d59a4f2aaeb2c83234dfcc7..9d4889be652c6d6fb974b59001a9ac77b496e9ab 100644 +--- a/src/responder/common/responder_common.c ++++ b/src/responder/common/responder_common.c +@@ -1685,7 +1685,7 @@ int sized_output_name(TALLOC_CTX *mem_ctx, + { + TALLOC_CTX *tmp_ctx = NULL; + errno_t ret; +- char *username; ++ char *name_str; + struct sized_string *name; + + tmp_ctx = talloc_new(NULL); +@@ -1693,30 +1693,19 @@ int sized_output_name(TALLOC_CTX *mem_ctx, + return ENOMEM; + } + +- username = sss_output_name(tmp_ctx, orig_name, name_dom->case_preserve, +- rctx->override_space); +- if (username == NULL) { +- ret = EIO; +- goto done; +- } +- +- if (name_dom->fqnames) { +- username = sss_tc_fqname(tmp_ctx, name_dom->names, name_dom, username); +- if (username == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "sss_replace_space failed\n"); +- ret = EIO; +- goto done; +- } +- } +- + name = talloc_zero(tmp_ctx, struct sized_string); + if (name == NULL) { + ret = ENOMEM; + goto done; + } + +- to_sized_string(name, username); +- name->str = talloc_steal(name, username); ++ ret = sss_output_fqname(mem_ctx, name_dom, orig_name, ++ rctx->override_space, &name_str); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ to_sized_string(name, name_str); + *_name = talloc_steal(mem_ctx, name); + ret = EOK; + done: +diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c +index fae1d47d7b217beafba75740e2e6d9cb8cdbc1d0..947463df93e188729959737efa4ac4f44a8459c4 100644 +--- a/src/responder/nss/nss_protocol_grent.c ++++ b/src/responder/nss/nss_protocol_grent.c +@@ -41,7 +41,7 @@ nss_get_grent(TALLOC_CTX *mem_ctx, + } + + /* Get fields. */ +- name = nss_get_name_from_msg(domain, msg); ++ name = sss_get_name_from_msg(domain, msg); + gid = sss_view_ldb_msg_find_attr_as_uint64(domain, msg, SYSDB_GIDNUM, 0); + + if (name == NULL || gid == 0) { +diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c +index edda9d3c87389898435a34fe7927868bc1cd9ac5..cb643f29e2d5f0a0c55c51afd9def73813061aa7 100644 +--- a/src/responder/nss/nss_protocol_pwent.c ++++ b/src/responder/nss/nss_protocol_pwent.c +@@ -225,7 +225,7 @@ nss_get_pwent(TALLOC_CTX *mem_ctx, + + /* Get fields. */ + upn = ldb_msg_find_attr_as_string(msg, SYSDB_UPN, NULL); +- name = nss_get_name_from_msg(domain, msg); ++ name = sss_get_name_from_msg(domain, msg); + gid = nss_get_gid(domain, msg); + uid = sss_view_ldb_msg_find_attr_as_uint64(domain, msg, SYSDB_UIDNUM, 0); + +diff --git a/src/responder/nss/nss_protocol_sid.c b/src/responder/nss/nss_protocol_sid.c +index a6a4e27d039c67ef98f6d5900d5e3fcadb3ee717..d4b7ee22d7c68a9e6f7c668f7268cdc5f36768b3 100644 +--- a/src/responder/nss/nss_protocol_sid.c ++++ b/src/responder/nss/nss_protocol_sid.c +@@ -532,7 +532,7 @@ nss_protocol_fill_name_list(struct nss_ctx *nss_ctx, + return ret; + } + +- tmp_str = nss_get_name_from_msg(result->domain, result->msgs[c]); ++ tmp_str = sss_get_name_from_msg(result->domain, result->msgs[c]); + if (tmp_str == NULL) { + return EINVAL; + } +diff --git a/src/responder/nss/nss_utils.c b/src/responder/nss/nss_utils.c +index 2cd9c33b42f7e018ea89d2df206637f35646489e..b4950e5a6eaec6a4511f7251dcf2e623c0177230 100644 +--- a/src/responder/nss/nss_utils.c ++++ b/src/responder/nss/nss_utils.c +@@ -27,33 +27,6 @@ + #include "responder/nss/nss_private.h" + + const char * +-nss_get_name_from_msg(struct sss_domain_info *domain, +- struct ldb_message *msg) +-{ +- const char *name; +- +- /* If domain has a view associated we return overridden name +- * if possible. */ +- if (DOM_HAS_VIEWS(domain)) { +- name = ldb_msg_find_attr_as_string(msg, OVERRIDE_PREFIX SYSDB_NAME, +- NULL); +- if (name != NULL) { +- return name; +- } +- } +- +- /* Otherwise we try to return name override from +- * Default Truest View for trusted users. */ +- name = ldb_msg_find_attr_as_string(msg, SYSDB_DEFAULT_OVERRIDE_NAME, NULL); +- if (name != NULL) { +- return name; +- } +- +- /* If no override is found we return the original name. */ +- return ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); +-} +- +-const char * + nss_get_pwfield(struct nss_ctx *nctx, + struct sss_domain_info *dom) + { +diff --git a/src/util/usertools.c b/src/util/usertools.c +index 7b87c567a6c2dc7e9c267407434b2a7a9edeaa00..5dfe6d7765b8032c7447de75e10c6c2a1d4c49ec 100644 +--- a/src/util/usertools.c ++++ b/src/util/usertools.c +@@ -816,3 +816,70 @@ done: + talloc_free(tmp_ctx); + return outname; + } ++ ++const char * ++sss_get_name_from_msg(struct sss_domain_info *domain, ++ struct ldb_message *msg) ++{ ++ const char *name; ++ ++ /* If domain has a view associated we return overridden name ++ * if possible. */ ++ if (DOM_HAS_VIEWS(domain)) { ++ name = ldb_msg_find_attr_as_string(msg, OVERRIDE_PREFIX SYSDB_NAME, ++ NULL); ++ if (name != NULL) { ++ return name; ++ } ++ } ++ ++ /* Otherwise we try to return name override from ++ * Default Truest View for trusted users. */ ++ name = ldb_msg_find_attr_as_string(msg, SYSDB_DEFAULT_OVERRIDE_NAME, NULL); ++ if (name != NULL) { ++ return name; ++ } ++ ++ /* If no override is found we return the original name. */ ++ return ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); ++} ++ ++int sss_output_fqname(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ const char *name, ++ char override_space, ++ char **_output_name) ++{ ++ TALLOC_CTX *tmp_ctx = NULL; ++ errno_t ret; ++ char *output_name; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ output_name = sss_output_name(tmp_ctx, name, domain->case_preserve, ++ override_space); ++ if (output_name == NULL) { ++ ret = EIO; ++ goto done; ++ } ++ ++ if (domain->fqnames) { ++ output_name = sss_tc_fqname(tmp_ctx, domain->names, ++ domain, output_name); ++ if (output_name == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "sss_tc_fqname failed\n"); ++ ret = EIO; ++ goto done; ++ } ++ } ++ ++ *_output_name = talloc_steal(mem_ctx, output_name); ++ ret = EOK; ++done: ++ talloc_zfree(tmp_ctx); ++ return ret; ++} +diff --git a/src/util/util.h b/src/util/util.h +index 4ef13ced48addc19403402d7d880176da24ceec6..5ba4c36ca88e325c20a3b1ecc8080a11ca276dcf 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -304,6 +304,15 @@ char *sss_output_name(TALLOC_CTX *mem_ctx, + bool case_sensitive, + const char replace_space); + ++int sss_output_fqname(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ const char *name, ++ char override_space, ++ char **_output_name); ++ ++const char *sss_get_name_from_msg(struct sss_domain_info *domain, ++ struct ldb_message *msg); ++ + /* from backup-file.c */ + int backup_file(const char *src, int dbglvl); + +-- +2.9.3 + diff --git a/SOURCES/0123-SYSDB-Fix-uninitialized-scalar-variable.patch b/SOURCES/0123-SYSDB-Fix-uninitialized-scalar-variable.patch deleted file mode 100644 index d9897ba..0000000 --- a/SOURCES/0123-SYSDB-Fix-uninitialized-scalar-variable.patch +++ /dev/null @@ -1,35 +0,0 @@ -From d6ecd69f63496446d23252426de41523ebe2bbf6 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Mon, 29 Aug 2016 09:13:49 +0200 -Subject: [PATCH 123/126] SYSDB: Fix uninitialized scalar variable -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The boolean variable newly_created could be used uninitialized -in done section in case of failure. The variable was firstly initialized -to true after succesfull execution of function sysdb_cache_create_empty. - -Uninitialized variable usually means true for boolean variable. - -Reviewed-by: Fabiano Fidêncio ---- - src/db/sysdb_init.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c -index c387c1b12c116f38d5a13f1adeac5ef64d593af8..d110aa7a2878e47650db177cfd342d0ac32248ab 100644 ---- a/src/db/sysdb_init.c -+++ b/src/db/sysdb_init.c -@@ -545,7 +545,7 @@ static errno_t sysdb_cache_connect_helper(TALLOC_CTX *mem_ctx, - const char *version = NULL; - int ret; - struct ldb_context *ldb; -- bool newly_created; -+ bool newly_created = false; - - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { --- -2.4.11 - diff --git a/SOURCES/0124-CACHE_REQ-Add-a-new-cache_req_ncache_filter_fn-plugi.patch b/SOURCES/0124-CACHE_REQ-Add-a-new-cache_req_ncache_filter_fn-plugi.patch new file mode 100644 index 0000000..fd0780e --- /dev/null +++ b/SOURCES/0124-CACHE_REQ-Add-a-new-cache_req_ncache_filter_fn-plugi.patch @@ -0,0 +1,322 @@ +From da437bb72fc6ab072fc9b3e6d6809bac323de1e2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 25 Apr 2017 14:14:05 +0200 +Subject: [PATCH 124/127] CACHE_REQ: Add a new cache_req_ncache_filter_fn() + plugin function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This function will be responsible for filtering out all the results that +we have that are also present in the negative cache. + +This is useful mainly for plugins which don't use name as an input token +but can still be affected by filter_{users,groups} options. + +For now this new function is not being used anywhere. + +Related: +https://pagure.io/SSSD/sssd/issue/3362 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +(cherry picked from commit f24ee5cca4cd43e7edf26fec453fbd99392bbe4b) +--- + src/responder/common/cache_req/cache_req_plugin.h | 13 +++++++++++++ + .../common/cache_req/plugins/cache_req_enum_groups.c | 1 + + src/responder/common/cache_req/plugins/cache_req_enum_svc.c | 1 + + .../common/cache_req/plugins/cache_req_enum_users.c | 1 + + .../common/cache_req/plugins/cache_req_group_by_filter.c | 1 + + .../common/cache_req/plugins/cache_req_group_by_id.c | 1 + + .../common/cache_req/plugins/cache_req_group_by_name.c | 1 + + .../common/cache_req/plugins/cache_req_host_by_name.c | 1 + + .../common/cache_req/plugins/cache_req_initgroups_by_name.c | 1 + + .../common/cache_req/plugins/cache_req_initgroups_by_upn.c | 1 + + .../common/cache_req/plugins/cache_req_netgroup_by_name.c | 1 + + .../common/cache_req/plugins/cache_req_object_by_id.c | 1 + + .../common/cache_req/plugins/cache_req_object_by_name.c | 1 + + .../common/cache_req/plugins/cache_req_object_by_sid.c | 1 + + .../common/cache_req/plugins/cache_req_svc_by_name.c | 1 + + .../common/cache_req/plugins/cache_req_svc_by_port.c | 1 + + .../common/cache_req/plugins/cache_req_user_by_cert.c | 1 + + .../common/cache_req/plugins/cache_req_user_by_filter.c | 1 + + .../common/cache_req/plugins/cache_req_user_by_id.c | 1 + + .../common/cache_req/plugins/cache_req_user_by_name.c | 1 + + .../common/cache_req/plugins/cache_req_user_by_upn.c | 1 + + 21 files changed, 33 insertions(+) + +diff --git a/src/responder/common/cache_req/cache_req_plugin.h b/src/responder/common/cache_req/cache_req_plugin.h +index e0b619528f6aa31a10a5b48c3c5acc96de90caa1..8117325506b2951c3966fa50506ed0d55273ee81 100644 +--- a/src/responder/common/cache_req/cache_req_plugin.h ++++ b/src/responder/common/cache_req/cache_req_plugin.h +@@ -93,6 +93,18 @@ typedef errno_t + struct cache_req_data *data); + + /** ++ * Filter the result through the negative cache. ++ * ++ * This is useful for plugins which don't use name as an input ++ * token but can be affected by filter_users and filter_groups ++ * options. ++ */ ++typedef errno_t ++(*cache_req_ncache_filter_fn)(struct sss_nc_ctx *ncache, ++ struct sss_domain_info *domain, ++ const char *name); ++ ++/** + * Add an object into global negative cache. + * + * @return EOK If everything went fine. +@@ -207,6 +219,7 @@ struct cache_req_plugin { + cache_req_global_ncache_add_fn global_ncache_add_fn; + cache_req_ncache_check_fn ncache_check_fn; + cache_req_ncache_add_fn ncache_add_fn; ++ cache_req_ncache_filter_fn ncache_filter_fn; + cache_req_lookup_fn lookup_fn; + cache_req_dp_send_fn dp_send_fn; + cache_req_dp_recv_fn dp_recv_fn; +diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c +index 49ce3508e678862e4389657187b9659ce90fbd1c..11ce9e90ff28f77078b025a44593a44be8f1f5c5 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c ++++ b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c +@@ -75,6 +75,7 @@ const struct cache_req_plugin cache_req_enum_groups = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = NULL, + .ncache_add_fn = NULL, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_enum_groups_lookup, + .dp_send_fn = cache_req_enum_groups_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +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 499b994738d62707b4e86d5a8383e3e2b82e8c57..72b2f1a7d2d2e02ce1a995098d1f26003444bddb 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 +@@ -76,6 +76,7 @@ const struct cache_req_plugin cache_req_enum_svc = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = NULL, + .ncache_add_fn = NULL, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_enum_svc_lookup, + .dp_send_fn = cache_req_enum_svc_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_users.c b/src/responder/common/cache_req/plugins/cache_req_enum_users.c +index b635354be6e9d2e2e2af1a6f867ac68e6cf7f085..e0647a0102d9568abdcebfbf0fb99fc2624d5565 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_enum_users.c ++++ b/src/responder/common/cache_req/plugins/cache_req_enum_users.c +@@ -75,6 +75,7 @@ const struct cache_req_plugin cache_req_enum_users = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = NULL, + .ncache_add_fn = NULL, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_enum_users_lookup, + .dp_send_fn = cache_req_enum_users_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +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 4377a476c36e5e03c8533bc62335b84fa1cee3ff..aa89953b88313605041cce599999fc5bbc741525 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 +@@ -131,6 +131,7 @@ const struct cache_req_plugin cache_req_group_by_filter = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = NULL, + .ncache_add_fn = NULL, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_group_by_filter_lookup, + .dp_send_fn = cache_req_group_by_filter_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +index ad5b7d890a42f29b586ab8e0943fef3dfab1162d..5613bf67c6acd1b2ace00cf75221462f45ef6743 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +@@ -144,6 +144,7 @@ const struct cache_req_plugin cache_req_group_by_id = { + .global_ncache_add_fn = cache_req_group_by_id_global_ncache_add, + .ncache_check_fn = cache_req_group_by_id_ncache_check, + .ncache_add_fn = NULL, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_group_by_id_lookup, + .dp_send_fn = cache_req_group_by_id_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +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 de1e8f9442273acf386a2278b06f28ee63a7e3c6..7706051818590af77da75d3e4c7f671c89170f82 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 +@@ -194,6 +194,7 @@ const struct cache_req_plugin cache_req_group_by_name = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = cache_req_group_by_name_ncache_check, + .ncache_add_fn = cache_req_group_by_name_ncache_add, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_group_by_name_lookup, + .dp_send_fn = cache_req_group_by_name_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c +index 1171cd63fac5cc1d36b31bf8a069f059705cae90..9cb32f6b18327873ba4b96fa177e8295be461db0 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c +@@ -92,6 +92,7 @@ const struct cache_req_plugin cache_req_host_by_name = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = NULL, + .ncache_add_fn = NULL, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_host_by_name_lookup, + .dp_send_fn = cache_req_host_by_name_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +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 f100aefe5c92279cde7e3209c7f48f5e2b35f135..75ac44e1ad36238f01342eced9188d07daa50720 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 +@@ -209,6 +209,7 @@ const struct cache_req_plugin cache_req_initgroups_by_name = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = cache_req_initgroups_by_name_ncache_check, + .ncache_add_fn = cache_req_initgroups_by_name_ncache_add, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_initgroups_by_name_lookup, + .dp_send_fn = cache_req_initgroups_by_name_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c +index 266ec7b8a28d496d9603bd9b6cdfef268ffa8559..b6fb43ee02d2f041fb3d992b375ae65a02db8b03 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c ++++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c +@@ -120,6 +120,7 @@ const struct cache_req_plugin cache_req_initgroups_by_upn = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = cache_req_initgroups_by_upn_ncache_check, + .ncache_add_fn = cache_req_initgroups_by_upn_ncache_add, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_initgroups_by_upn_lookup, + .dp_send_fn = cache_req_initgroups_by_upn_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +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 ab3e553d3ecb8ae09094dcfc938ed0ac01925327..4d8bb18579a286042b00528190dadd52fdd7c75c 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 +@@ -128,6 +128,7 @@ const struct cache_req_plugin cache_req_netgroup_by_name = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = cache_req_netgroup_by_name_ncache_check, + .ncache_add_fn = cache_req_netgroup_by_name_ncache_add, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_netgroup_by_name_lookup, + .dp_send_fn = cache_req_netgroup_by_name_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +index 9557bd15270b2eb1a0671f9ef91033efac29c3ac..ff3d0e67862be365c56ab24396b4982e8addded0 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +@@ -111,6 +111,7 @@ const struct cache_req_plugin cache_req_object_by_id = { + .global_ncache_add_fn = cache_req_object_by_id_global_ncache_add, + .ncache_check_fn = cache_req_object_by_id_ncache_check, + .ncache_add_fn = NULL, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_object_by_id_lookup, + .dp_send_fn = cache_req_object_by_id_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +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 e236d1fa4aadcd87b192d34ebaf5f9ad8908b6c2..854d0b83c420ebebcb5e0e079c707081fa313632 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 +@@ -204,6 +204,7 @@ const struct cache_req_plugin cache_req_object_by_name = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = cache_req_object_by_name_ncache_check, + .ncache_add_fn = cache_req_object_by_name_ncache_add, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_object_by_name_lookup, + .dp_send_fn = cache_req_object_by_name_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c +index dfec79da07d669165205a767cab22c2254686134..039a79df7bb1ab213ce4334835e9fc18e6d0faac 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c ++++ b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c +@@ -120,6 +120,7 @@ const struct cache_req_plugin cache_req_object_by_sid = { + .global_ncache_add_fn = cache_req_object_by_sid_global_ncache_add, + .ncache_check_fn = cache_req_object_by_sid_ncache_check, + .ncache_add_fn = NULL, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_object_by_sid_lookup, + .dp_send_fn = cache_req_object_by_sid_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +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 b2bfb26ffed1a60ed8389fa89b0e728c8c6cf76c..4c32d9977cc06e43eed3a90e7dcf107e91efefb5 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 +@@ -152,6 +152,7 @@ const struct cache_req_plugin cache_req_svc_by_name = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = cache_req_svc_by_name_ncache_check, + .ncache_add_fn = cache_req_svc_by_name_ncache_add, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_svc_by_name_lookup, + .dp_send_fn = cache_req_svc_by_name_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +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 0e48437f4b64d26112be88af1eebc20f012b70fd..1e998f642c766d15d3f6fe777aa5c789629508e2 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 +@@ -125,6 +125,7 @@ const struct cache_req_plugin cache_req_svc_by_port = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = cache_req_svc_by_port_ncache_check, + .ncache_add_fn = cache_req_svc_by_port_ncache_add, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_svc_by_port_lookup, + .dp_send_fn = cache_req_svc_by_port_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c +index 286a34db276e0098060982c572e2a68ceceebf60..7a0c7d8ce1644f1c41b64c6903e4e20eb3c2c081 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c +@@ -94,6 +94,7 @@ const struct cache_req_plugin cache_req_user_by_cert = { + .global_ncache_add_fn = cache_req_user_by_cert_global_ncache_add, + .ncache_check_fn = cache_req_user_by_cert_ncache_check, + .ncache_add_fn = NULL, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_user_by_cert_lookup, + .dp_send_fn = cache_req_user_by_cert_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +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 c476814373cd784bf8dbbea1da7b010afe5bb4e4..dd3f42e855389ecc73690e4d18c4977253b108a6 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 +@@ -131,6 +131,7 @@ const struct cache_req_plugin cache_req_user_by_filter = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = NULL, + .ncache_add_fn = NULL, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_user_by_filter_lookup, + .dp_send_fn = cache_req_user_by_filter_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +index 9ba73292e5dc518e86c6e00e7e493d6871f28e70..b14b3738aa7721723f524ebd46301a3a9a1c712f 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +@@ -144,6 +144,7 @@ const struct cache_req_plugin cache_req_user_by_id = { + .global_ncache_add_fn = cache_req_user_by_id_global_ncache_add, + .ncache_check_fn = cache_req_user_by_id_ncache_check, + .ncache_add_fn = NULL, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_user_by_id_lookup, + .dp_send_fn = cache_req_user_by_id_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +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 15da7d0d20b1ac97511a226daecc8ef7e7d2e7e4..2e49de938d0af50089d0cf49860441c2b6ea679c 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 +@@ -199,6 +199,7 @@ const struct cache_req_plugin cache_req_user_by_name = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = cache_req_user_by_name_ncache_check, + .ncache_add_fn = cache_req_user_by_name_ncache_add, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_user_by_name_lookup, + .dp_send_fn = cache_req_user_by_name_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c b/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c +index 40a097b1634d2b2d089b7feb377ea2389a58672c..b8bcd241ed79c510aca214ad3788215ae2997d20 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c +@@ -125,6 +125,7 @@ const struct cache_req_plugin cache_req_user_by_upn = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = cache_req_user_by_upn_ncache_check, + .ncache_add_fn = cache_req_user_by_upn_ncache_add, ++ .ncache_filter_fn = NULL, + .lookup_fn = cache_req_user_by_upn_lookup, + .dp_send_fn = cache_req_user_by_upn_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +-- +2.9.3 + diff --git a/SOURCES/0124-PROXY-Use-right-name-in-ldap-filter.patch b/SOURCES/0124-PROXY-Use-right-name-in-ldap-filter.patch deleted file mode 100644 index 77703a5..0000000 --- a/SOURCES/0124-PROXY-Use-right-name-in-ldap-filter.patch +++ /dev/null @@ -1,51 +0,0 @@ -From d2636b0f34d6e4ff7cf99a44db8317fd485a3783 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Fri, 26 Aug 2016 14:57:22 +0200 -Subject: [PATCH 124/126] PROXY: Use right name in ldap filter - -We used internal fq name in ldap filter -with id_provider proxy to files and auth provider -ldap - -[sssd[be[LDAP]]] [sdap_get_generic_ext_step] - (0x0400): calling ldap_search_ext with - [(&(uid=testuser1@ldap)(objectclass=posixAccount))][dc=example,dc=com]. - -Reviewed-by: Jakub Hrozek ---- - src/providers/ldap/ldap_auth.c | 11 ++++++++--- - 1 file changed, 8 insertions(+), 3 deletions(-) - -diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c -index 35f16b0d4a6f8e566b0cf63b65ba46f31e7c1bcd..00d38284e428eea42254820fd08ee4fb125235a6 100644 ---- a/src/providers/ldap/ldap_auth.c -+++ b/src/providers/ldap/ldap_auth.c -@@ -361,7 +361,7 @@ shadow_fail: - - /* ==Get-User-DN========================================================== */ - struct get_user_dn_state { -- const char *username; -+ char *username; - - char *orig_dn; - }; -@@ -386,9 +386,14 @@ static struct tevent_req *get_user_dn_send(TALLOC_CTX *memctx, - req = tevent_req_create(memctx, &state, struct get_user_dn_state); - if (!req) return NULL; - -- state->username = username; -+ ret = sss_parse_internal_fqname(state, username, -+ &state->username, NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "Cannot parse %s\n", username); -+ goto done; -+ } - -- ret = sss_filter_sanitize(state, username, &clean_name); -+ ret = sss_filter_sanitize(state, state->username, &clean_name); - if (ret != EOK) { - goto done; - } --- -2.4.11 - diff --git a/SOURCES/0125-CACHE_REQ_RESULT-Introduce-cache_req_create_ldb_resu.patch b/SOURCES/0125-CACHE_REQ_RESULT-Introduce-cache_req_create_ldb_resu.patch new file mode 100644 index 0000000..2508964 --- /dev/null +++ b/SOURCES/0125-CACHE_REQ_RESULT-Introduce-cache_req_create_ldb_resu.patch @@ -0,0 +1,92 @@ +From a2bfa4d2074cacc5d30f17a3b3af260ec9eaaa59 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Thu, 27 Apr 2017 11:24:45 +0200 +Subject: [PATCH 125/127] CACHE_REQ_RESULT: Introduce + cache_req_create_ldb_result_from_msg_list() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Similarly to what cache_req_create_ldb_result_from_msg() does this new +function creates a new ldb_result from a list of ldb_message. + +It's going to be used in the follow-up patch where some messages from +ldb_result may be filtered and then a new ldb_result has to be created. + +Related: +https://pagure.io/SSSD/sssd/issue/3362 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +(cherry picked from commit 180e0b282be6aeb047c4b24b46e0b56afba1fdc8) +--- + src/responder/common/cache_req/cache_req_private.h | 5 ++++ + src/responder/common/cache_req/cache_req_result.c | 35 ++++++++++++++++++++++ + 2 files changed, 40 insertions(+) + +diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h +index 851005c389f994b1bd2d04cda9b68df8b18492cc..c0ee5f969f2a171b8a6eb396b3d14b593d157b76 100644 +--- a/src/responder/common/cache_req/cache_req_private.h ++++ b/src/responder/common/cache_req/cache_req_private.h +@@ -137,6 +137,11 @@ cache_req_create_and_add_result(TALLOC_CTX *mem_ctx, + size_t *_num_results); + + struct ldb_result * ++cache_req_create_ldb_result_from_msg_list(TALLOC_CTX *mem_ctx, ++ struct ldb_message **ldb_msgs, ++ size_t ldb_msg_count); ++ ++struct ldb_result * + cache_req_create_ldb_result_from_msg(TALLOC_CTX *mem_ctx, + struct ldb_message *ldb_msg); + +diff --git a/src/responder/common/cache_req/cache_req_result.c b/src/responder/common/cache_req/cache_req_result.c +index e20ae5653acf22a2e0190ef6a88836c7fab9868e..366ba748082336c7c752b576cfd7b8fb8cd82fcf 100644 +--- a/src/responder/common/cache_req/cache_req_result.c ++++ b/src/responder/common/cache_req/cache_req_result.c +@@ -122,6 +122,41 @@ cache_req_create_and_add_result(TALLOC_CTX *mem_ctx, + } + + struct ldb_result * ++cache_req_create_ldb_result_from_msg_list(TALLOC_CTX *mem_ctx, ++ struct ldb_message **ldb_msgs, ++ size_t ldb_msg_count) ++{ ++ struct ldb_result *ldb_result; ++ ++ if (ldb_msgs == NULL || ldb_msgs[0] == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "No message set!\n"); ++ return NULL; ++ } ++ ++ ldb_result = talloc_zero(NULL, struct ldb_result); ++ if (ldb_result == NULL) { ++ return NULL; ++ } ++ ++ ldb_result->extended = NULL; ++ ldb_result->controls = NULL; ++ ldb_result->refs = NULL; ++ ldb_result->count = ldb_msg_count; ++ ldb_result->msgs = talloc_zero_array(ldb_result, struct ldb_message *, ++ ldb_msg_count + 1); ++ if (ldb_result->msgs == NULL) { ++ talloc_free(ldb_result); ++ return NULL; ++ } ++ ++ for (size_t i = 0; i < ldb_msg_count; i++) { ++ ldb_result->msgs[i] = talloc_steal(ldb_result->msgs, ldb_msgs[i]); ++ } ++ ++ return ldb_result; ++} ++ ++struct ldb_result * + cache_req_create_ldb_result_from_msg(TALLOC_CTX *mem_ctx, + struct ldb_message *ldb_msg) + { +-- +2.9.3 + diff --git a/SOURCES/0125-SYSDB-Fix-error-handling-in-sysdb_get_user_members_r.patch b/SOURCES/0125-SYSDB-Fix-error-handling-in-sysdb_get_user_members_r.patch deleted file mode 100644 index f2581b1..0000000 --- a/SOURCES/0125-SYSDB-Fix-error-handling-in-sysdb_get_user_members_r.patch +++ /dev/null @@ -1,50 +0,0 @@ -From fde5249cee996276492886697be570b9e698e454 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Tue, 30 Aug 2016 15:37:43 +0200 -Subject: [PATCH 125/126] SYSDB: Fix error handling in - sysdb_get_user_members_recursively -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We ignored failures from sysdb_search_entry - -Reviewed-by: Petr Čech ---- - src/db/sysdb_ops.c | 3 +++ - src/db/sysdb_views.c | 5 ++++- - 2 files changed, 7 insertions(+), 1 deletion(-) - -diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c -index 44fb5b70e6d33fffbca5824f831a3229254ecb57..e4c8e1e285e3bc49710f71c896ba9a30c742d4fa 100644 ---- a/src/db/sysdb_ops.c -+++ b/src/db/sysdb_ops.c -@@ -4738,6 +4738,9 @@ errno_t sysdb_get_user_members_recursively(TALLOC_CTX *mem_ctx, - - ret = sysdb_search_entry(tmp_ctx, dom->sysdb, base_dn, LDB_SCOPE_SUBTREE, - filter, attrs, &count, &msgs); -+ if (ret != EOK) { -+ goto done; -+ } - - res = talloc_zero(tmp_ctx, struct ldb_result); - if (res == NULL) { -diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c -index 79f513d13ba41212a6cd84e1d9e609df6acba29c..9dc48f5b6c414bbc7c64bcd1fe73553f388588bd 100644 ---- a/src/db/sysdb_views.c -+++ b/src/db/sysdb_views.c -@@ -1374,7 +1374,10 @@ errno_t sysdb_add_group_member_overrides(struct sss_domain_info *domain, - - ret = sysdb_get_user_members_recursively(tmp_ctx, domain, obj->dn, - &res_members); -- if (ret != EOK) { -+ if (ret == ENOENT) { -+ ret = EOK; -+ goto done; -+ } else if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "sysdb_get_user_members_recursively failed.\n"); - goto done; --- -2.4.11 - diff --git a/SOURCES/0126-CACHE_REQ-Make-use-of-cache_req_ncache_filter_fn.patch b/SOURCES/0126-CACHE_REQ-Make-use-of-cache_req_ncache_filter_fn.patch new file mode 100644 index 0000000..d36136a --- /dev/null +++ b/SOURCES/0126-CACHE_REQ-Make-use-of-cache_req_ncache_filter_fn.patch @@ -0,0 +1,392 @@ +From 4c3780ced1b1507ebd8c3d0b91a3ef50b74e0b52 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 25 Apr 2017 16:33:58 +0200 +Subject: [PATCH 126/127] CACHE_REQ: Make use of cache_req_ncache_filter_fn() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch makes use of cache_req_ncache_filter_fn() in order to process +the result of a cache_req search and then filter out all the results +that are present in the negative cache. + +The "post cache_req search" result processing is done basically in two +different cases: +- plugins which don't use name as an input token (group_by_id, user_by_id + and object_by_id), but still can be affected by filter_{users,groups} + options; +- plugins responsible for groups and users enumeration (enum_groups and + enum_users); + +Resolves: +https://pagure.io/SSSD/sssd/issue/3362 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +(cherry picked from commit 4ef0b19a5e8a327443d027e57487c8a1e4f654ce) +--- + src/responder/common/cache_req/cache_req_search.c | 124 +++++++++++++++++++-- + .../cache_req/plugins/cache_req_enum_groups.c | 10 +- + .../cache_req/plugins/cache_req_enum_users.c | 10 +- + .../cache_req/plugins/cache_req_group_by_id.c | 10 +- + .../cache_req/plugins/cache_req_object_by_id.c | 17 ++- + .../cache_req/plugins/cache_req_user_by_id.c | 10 +- + src/responder/nss/nss_protocol_grent.c | 12 -- + src/responder/nss/nss_protocol_pwent.c | 11 -- + 8 files changed, 165 insertions(+), 39 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c +index 8bc1530b341f587cb502fdf0ca3ed8d37cfb7d13..793dbc5042ae329b2cade5d1eb5a6d41102e264f 100644 +--- a/src/responder/common/cache_req/cache_req_search.c ++++ b/src/responder/common/cache_req/cache_req_search.c +@@ -84,6 +84,87 @@ static void cache_req_search_ncache_add(struct cache_req *cr) + return; + } + ++static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx, ++ struct cache_req *cr, ++ struct ldb_result *result, ++ struct ldb_result **_result) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_result *filtered_result; ++ struct ldb_message **msgs; ++ size_t msg_count; ++ const char *name; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ if (cr->plugin->ncache_filter_fn == NULL) { ++ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, ++ "This request type does not support filtering " ++ "result by negative cache\n"); ++ ++ *_result = talloc_steal(mem_ctx, result); ++ ++ ret = EOK; ++ goto done; ++ } ++ ++ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, ++ "Filtering out results by negative cache\n"); ++ ++ msgs = talloc_zero_array(tmp_ctx, struct ldb_message *, result->count); ++ msg_count = 0; ++ ++ for (size_t i = 0; i < result->count; i++) { ++ name = sss_get_name_from_msg(cr->domain, result->msgs[i]); ++ if (name == NULL) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, ++ "sss_get_name_from_msg() returned NULL, which should never " ++ "happen in this scenario!\n"); ++ ret = ERR_INTERNAL; ++ goto done; ++ } ++ ++ ret = cr->plugin->ncache_filter_fn(cr->ncache, cr->domain, name); ++ if (ret == EEXIST) { ++ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, ++ "[%s] filtered out! (negative cache)\n", ++ name); ++ continue; ++ } else if (ret != EOK && ret != ENOENT) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, ++ "Unable to check negative cache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ msgs[msg_count] = talloc_steal(msgs, result->msgs[i]); ++ msg_count++; ++ } ++ ++ if (msg_count == 0) { ++ ret = ENOENT; ++ goto done; ++ } ++ ++ filtered_result = cache_req_create_ldb_result_from_msg_list(tmp_ctx, msgs, ++ msg_count); ++ if (filtered_result == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ *_result = talloc_steal(mem_ctx, filtered_result); ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + static errno_t cache_req_search_cache(TALLOC_CTX *mem_ctx, + struct cache_req *cr, + struct ldb_result **_result) +@@ -338,10 +419,18 @@ static void cache_req_search_oob_done(struct tevent_req *subreq) + + static void cache_req_search_done(struct tevent_req *subreq) + { ++ TALLOC_CTX *tmp_ctx; + struct cache_req_search_state *state; + struct tevent_req *req; ++ struct ldb_result *result = NULL; + errno_t ret; + ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct cache_req_search_state); + +@@ -349,23 +438,36 @@ static void cache_req_search_done(struct tevent_req *subreq) + talloc_zfree(subreq); + + /* Get result from cache again. */ +- ret = cache_req_search_cache(state, state->cr, &state->result); +- if (ret == ENOENT) { +- /* Only store entry in negative cache if DP request succeeded +- * because only then we know that the entry does not exist. */ +- if (state->dp_success) { +- cache_req_search_ncache_add(state->cr); ++ ret = cache_req_search_cache(tmp_ctx, state->cr, &result); ++ if (ret != EOK) { ++ if (ret == ENOENT) { ++ /* Only store entry in negative cache if DP request succeeded ++ * because only then we know that the entry does not exist. */ ++ if (state->dp_success) { ++ cache_req_search_ncache_add(state->cr); ++ } + } +- tevent_req_error(req, ENOENT); +- return; +- } else if (ret != EOK) { +- tevent_req_error(req, ret); +- return; ++ goto done; ++ } ++ ++ /* ret == EOK */ ++ ret = cache_req_search_ncache_filter(state, state->cr, result, ++ &state->result); ++ if (ret != EOK) { ++ goto done; + } + + CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, + "Returning updated object [%s]\n", state->cr->debugobj); + ++done: ++ talloc_free(tmp_ctx); ++ ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ + tevent_req_done(req); + return; + } +diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c +index 11ce9e90ff28f77078b025a44593a44be8f1f5c5..15350ca8279bc77c73bcc4abe51c97a8a37cb8c8 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c ++++ b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c +@@ -55,6 +55,14 @@ cache_req_enum_groups_dp_send(TALLOC_CTX *mem_ctx, + SSS_DP_GROUP, NULL, 0, NULL); + } + ++static errno_t ++cache_req_enum_groups_ncache_filter(struct sss_nc_ctx *ncache, ++ struct sss_domain_info *domain, ++ const char *name) ++{ ++ return sss_ncache_check_group(ncache, domain, name); ++} ++ + const struct cache_req_plugin cache_req_enum_groups = { + .name = "Enumerate groups", + .attr_expiration = SYSDB_CACHE_EXPIRE, +@@ -75,7 +83,7 @@ const struct cache_req_plugin cache_req_enum_groups = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = NULL, + .ncache_add_fn = NULL, +- .ncache_filter_fn = NULL, ++ .ncache_filter_fn = cache_req_enum_groups_ncache_filter, + .lookup_fn = cache_req_enum_groups_lookup, + .dp_send_fn = cache_req_enum_groups_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_users.c b/src/responder/common/cache_req/plugins/cache_req_enum_users.c +index e0647a0102d9568abdcebfbf0fb99fc2624d5565..a3ddcdd45548a2fa7c367f3fb3be103c115dedb4 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_enum_users.c ++++ b/src/responder/common/cache_req/plugins/cache_req_enum_users.c +@@ -55,6 +55,14 @@ cache_req_enum_users_dp_send(TALLOC_CTX *mem_ctx, + SSS_DP_USER, NULL, 0, NULL); + } + ++static errno_t ++cache_req_enum_users_ncache_filter(struct sss_nc_ctx *ncache, ++ struct sss_domain_info *domain, ++ const char *name) ++{ ++ return sss_ncache_check_user(ncache, domain, name); ++} ++ + const struct cache_req_plugin cache_req_enum_users = { + .name = "Enumerate users", + .attr_expiration = SYSDB_CACHE_EXPIRE, +@@ -75,7 +83,7 @@ const struct cache_req_plugin cache_req_enum_users = { + .global_ncache_add_fn = NULL, + .ncache_check_fn = NULL, + .ncache_add_fn = NULL, +- .ncache_filter_fn = NULL, ++ .ncache_filter_fn = cache_req_enum_users_ncache_filter, + .lookup_fn = cache_req_enum_users_lookup, + .dp_send_fn = cache_req_enum_users_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +index 5613bf67c6acd1b2ace00cf75221462f45ef6743..5ca64283a781318bc4e4d6920fff989c3f3919b4 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +@@ -43,6 +43,14 @@ cache_req_group_by_id_ncache_check(struct sss_nc_ctx *ncache, + } + + static errno_t ++cache_req_group_by_id_ncache_filter(struct sss_nc_ctx *ncache, ++ struct sss_domain_info *domain, ++ const char *name) ++{ ++ return sss_ncache_check_group(ncache, domain, name); ++} ++ ++static errno_t + cache_req_group_by_id_global_ncache_add(struct sss_nc_ctx *ncache, + struct cache_req_data *data) + { +@@ -144,7 +152,7 @@ const struct cache_req_plugin cache_req_group_by_id = { + .global_ncache_add_fn = cache_req_group_by_id_global_ncache_add, + .ncache_check_fn = cache_req_group_by_id_ncache_check, + .ncache_add_fn = NULL, +- .ncache_filter_fn = NULL, ++ .ncache_filter_fn = cache_req_group_by_id_ncache_filter, + .lookup_fn = cache_req_group_by_id_lookup, + .dp_send_fn = cache_req_group_by_id_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +index ff3d0e67862be365c56ab24396b4982e8addded0..339bd4f5fef827acc1aa3c123d041e426d9e4782 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +@@ -50,6 +50,21 @@ cache_req_object_by_id_ncache_check(struct sss_nc_ctx *ncache, + } + + static errno_t ++cache_req_object_by_id_ncache_filter(struct sss_nc_ctx *ncache, ++ struct sss_domain_info *domain, ++ const char *name) ++{ ++ errno_t ret; ++ ++ ret = sss_ncache_check_user(ncache, domain, name); ++ if (ret == EEXIST) { ++ ret = sss_ncache_check_group(ncache, domain, name); ++ } ++ ++ return ret; ++} ++ ++static errno_t + cache_req_object_by_id_global_ncache_add(struct sss_nc_ctx *ncache, + struct cache_req_data *data) + { +@@ -111,7 +126,7 @@ const struct cache_req_plugin cache_req_object_by_id = { + .global_ncache_add_fn = cache_req_object_by_id_global_ncache_add, + .ncache_check_fn = cache_req_object_by_id_ncache_check, + .ncache_add_fn = NULL, +- .ncache_filter_fn = NULL, ++ .ncache_filter_fn = cache_req_object_by_id_ncache_filter, + .lookup_fn = cache_req_object_by_id_lookup, + .dp_send_fn = cache_req_object_by_id_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +index b14b3738aa7721723f524ebd46301a3a9a1c712f..913f9be5bcc2dfd074b52cb3b15fb6948826e831 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +@@ -43,6 +43,14 @@ cache_req_user_by_id_ncache_check(struct sss_nc_ctx *ncache, + } + + static errno_t ++cache_req_user_by_id_ncache_filter(struct sss_nc_ctx *ncache, ++ struct sss_domain_info *domain, ++ const char *name) ++{ ++ return sss_ncache_check_user(ncache, domain, name); ++} ++ ++static errno_t + cache_req_user_by_id_global_ncache_add(struct sss_nc_ctx *ncache, + struct cache_req_data *data) + { +@@ -144,7 +152,7 @@ const struct cache_req_plugin cache_req_user_by_id = { + .global_ncache_add_fn = cache_req_user_by_id_global_ncache_add, + .ncache_check_fn = cache_req_user_by_id_ncache_check, + .ncache_add_fn = NULL, +- .ncache_filter_fn = NULL, ++ .ncache_filter_fn = cache_req_user_by_id_ncache_filter, + .lookup_fn = cache_req_user_by_id_lookup, + .dp_send_fn = cache_req_user_by_id_dp_send, + .dp_recv_fn = cache_req_common_dp_recv +diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c +index 947463df93e188729959737efa4ac4f44a8459c4..ee228c722a153a1ba7aa8a1b30a1e551108424bb 100644 +--- a/src/responder/nss/nss_protocol_grent.c ++++ b/src/responder/nss/nss_protocol_grent.c +@@ -241,18 +241,6 @@ nss_protocol_fill_grent(struct nss_ctx *nss_ctx, + continue; + } + +- /* Check negative cache during enumeration. */ +- if (cmd_ctx->enumeration) { +- ret = sss_ncache_check_group(nss_ctx->rctx->ncache, +- result->domain, name->str); +- if (ret == EEXIST) { +- DEBUG(SSSDBG_TRACE_FUNC, +- "User [%s] filtered out! (negative cache)\n", +- name->str); +- continue; +- } +- } +- + /* Adjust packet size: gid, num_members + string fields. */ + + ret = sss_packet_grow(packet, 2 * sizeof(uint32_t) +diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c +index cb643f29e2d5f0a0c55c51afd9def73813061aa7..b355d4fc90397f51e82545e56940be850f144d49 100644 +--- a/src/responder/nss/nss_protocol_pwent.c ++++ b/src/responder/nss/nss_protocol_pwent.c +@@ -309,17 +309,6 @@ nss_protocol_fill_pwent(struct nss_ctx *nss_ctx, + continue; + } + +- /* Check negative cache during enumeration. */ +- if (cmd_ctx->enumeration) { +- ret = sss_ncache_check_user(nss_ctx->rctx->ncache, +- result->domain, name->str); +- if (ret == EEXIST) { +- DEBUG(SSSDBG_TRACE_FUNC, +- "User [%s] filtered out! (negative cache)\n", name->str); +- continue; +- } +- } +- + /* Adjust packet size: uid, gid + string fields. */ + + ret = sss_packet_grow(packet, 2 * sizeof(uint32_t) +-- +2.9.3 + diff --git a/SOURCES/0126-sdap_initgr_nested_get_membership_diff-use-fully-qua.patch b/SOURCES/0126-sdap_initgr_nested_get_membership_diff-use-fully-qua.patch deleted file mode 100644 index 0cb5cc4..0000000 --- a/SOURCES/0126-sdap_initgr_nested_get_membership_diff-use-fully-qua.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 16196f3248a32a7bd9e395b0fdc85249ca4201d7 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 30 Aug 2016 17:30:10 +0200 -Subject: [PATCH 126/126] sdap_initgr_nested_get_membership_diff: use - fully-qualified names - -I think this is a leftover from the change to use fully-qualified names -in sysdb. To verify this you can create a nested group in IPA. Without -this patch the id command will only show the groups the user is a direct -member of. With the patch the indirect groups memberships should be -shown as well. - -https://fedorahosted.org/sssd/ticket/3163 - -Reviewed-by: Jakub Hrozek ---- - src/providers/ldap/sdap_async_initgroups.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c -index 82c708c226bf1a645ff5a395947dfdbad71e0f1f..f9593f0dfaa2dc6e33fd6c9d1f0c9b78cad3a1d9 100644 ---- a/src/providers/ldap/sdap_async_initgroups.c -+++ b/src/providers/ldap/sdap_async_initgroups.c -@@ -1414,7 +1414,7 @@ sdap_initgr_nested_get_membership_diff(TALLOC_CTX *mem_ctx, - group_name, parents_count); - - if (parents_count > 0) { -- ret = sysdb_attrs_primary_name_list(dom, tmp_ctx, -+ ret = sysdb_attrs_primary_fqdn_list(dom, tmp_ctx, - ldap_parentlist, - parents_count, - opts->group_map[SDAP_AT_GROUP_NAME].name, --- -2.4.11 - diff --git a/SOURCES/0127-Revert-CONFIG-Use-default-config-when-none-provided.patch b/SOURCES/0127-Revert-CONFIG-Use-default-config-when-none-provided.patch deleted file mode 100644 index 623336d..0000000 --- a/SOURCES/0127-Revert-CONFIG-Use-default-config-when-none-provided.patch +++ /dev/null @@ -1,196 +0,0 @@ -From 17ba1565f6dc3874c554f37ca949ad284647141d Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 7 Sep 2016 17:21:19 +0200 -Subject: [PATCH 127/127] Revert "CONFIG: Use default config when none - provided" - -This reverts commit 59744cff6edb106ae799b2321cb8731edadf409a. ---- - Makefile.am | 10 ---------- - contrib/sssd.spec.in | 3 --- - src/confdb/confdb.h | 1 - - src/confdb/confdb_setup.c | 40 ++++------------------------------------ - src/examples/sssd-shadowutils | 6 ------ - src/examples/sssd.conf | 17 ----------------- - 6 files changed, 4 insertions(+), 73 deletions(-) - delete mode 100644 src/examples/sssd-shadowutils - delete mode 100644 src/examples/sssd.conf - -diff --git a/Makefile.am b/Makefile.am -index b8cd8b64ca8a130a5dd3107e1fb1445310192059..056c73bb265523705a0de16d4d5e078f516f566f 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -35,7 +35,6 @@ endif - - sssdlibexecdir = $(libexecdir)/sssd - sssdlibdir = $(libdir)/sssd --sssddefaultconfdir = $(sssdlibdir)/conf - ldblibdir = @ldblibdir@ - if BUILD_KRB5_LOCATOR_PLUGIN - krb5plugindir = @krb5pluginpath@ -@@ -85,7 +84,6 @@ pkgconfigdir = $(libdir)/pkgconfig - krb5rcachedir = @krb5rcachedir@ - sudolibdir = @sudolibpath@ - polkitdir = @polkitdir@ --pamconfdir = $(sysconfdir)/pam.d - systemtap_tapdir = @tapset_dir@ - - secdbpath = @secdbpath@ -@@ -464,7 +462,6 @@ AM_CPPFLAGS = \ - -DSSSDDATADIR=\"$(sssddatadir)\" \ - -DSSSD_LIBEXEC_PATH=\"$(sssdlibexecdir)\" \ - -DSSSD_CONF_DIR=\"$(sssdconfdir)\" \ -- -DSSSD_DEFAULT_CONF_DIR=\"$(sssddefaultconfdir)\" \ - -DSSS_NSS_MCACHE_DIR=\"$(mcpath)\" \ - -DSSS_NSS_SOCKET_NAME=\"$(pipepath)/nss\" \ - -DSSS_PAM_SOCKET_NAME=\"$(pipepath)/pam\" \ -@@ -1465,12 +1462,6 @@ dist_noinst_DATA += \ - src/sss_client/COPYING.LESSER \ - src/m4 - --dist_sssddefaultconf_DATA = \ -- src/examples/sssd.conf -- --dist_pamconf_DATA = \ -- src/examples/sssd-shadowutils -- - ###################### - # Command-line Tools # - ###################### -@@ -3972,7 +3963,6 @@ SSSD_USER_DIRS = \ - $(DESTDIR)$(gpocachepath) \ - $(DESTDIR)$(sssdconfdir) \ - $(DESTDIR)$(sssdconfdir)/conf.d \ -- $(DESTDIR)$(sssddefaultconfdir) \ - $(DESTDIR)$(logpath) \ - $(NULL) - -diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in -index cb68a73e85122b016de7df37bcf4fc232a10a2ac..4e24aa39c65ad698607615d93de8624e2e1832ff 100644 ---- a/contrib/sssd.spec.in -+++ b/contrib/sssd.spec.in -@@ -800,9 +800,6 @@ done - %dir %{_sysconfdir}/rwtab.d - %config(noreplace) %{_sysconfdir}/rwtab.d/sssd - %dir %{_datadir}/sssd --%{_sysconfdir}/pam.d/sssd-shadowutils --%{_libdir}/%{name}/conf/sssd.conf -- - %{_datadir}/sssd/cfg_rules.ini - %{_datadir}/sssd/sssd.api.conf - %{_datadir}/sssd/sssd.api.d -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index 72adbd80ea534eb0becd3e517c00b0c26d00444c..e8df280562d7014e0dc5d4fe5c3336eaba204537 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -40,7 +40,6 @@ - - #define CONFDB_DEFAULT_CFG_FILE_VER 2 - #define CONFDB_FILE "config.ldb" --#define SSSD_DEFAULT_CONFIG_FILE SSSD_DEFAULT_CONF_DIR"/sssd.conf" - #define SSSD_CONFIG_FILE SSSD_CONF_DIR"/sssd.conf" - #define CONFDB_DEFAULT_CONFIG_DIR SSSD_CONF_DIR"/conf.d" - #define SSSD_MIN_ID 1 -diff --git a/src/confdb/confdb_setup.c b/src/confdb/confdb_setup.c -index d6feab9000d54d2c3761de6d8e990053ade7e85f..a71d9dd1202824b3c9a7e69f1d8fa905ac1b8c02 100644 ---- a/src/confdb/confdb_setup.c -+++ b/src/confdb/confdb_setup.c -@@ -21,14 +21,12 @@ - - #include "config.h" - #include --#include - #include "util/util.h" - #include "db/sysdb.h" - #include "confdb.h" - #include "confdb_private.h" - #include "confdb_setup.h" - #include "util/sss_ini.h" --#include "tools/tools_util.h" - - - static int confdb_test(struct confdb_ctx *cdb) -@@ -161,41 +159,11 @@ static int confdb_init_db(const char *config_file, const char *config_dir, - DEBUG(SSSDBG_TRACE_FUNC, - "sss_ini_config_file_open failed: %s [%d]\n", strerror(ret), - ret); -- if (ret != ENOENT) { -- /* Anything other than ENOENT is unrecoverable */ -- goto done; -- } else { -- /* Copy the default configuration file to the standard location -- * and then retry -- */ -- ret = copy_file_secure(SSSD_DEFAULT_CONFIG_FILE, -- SSSD_CONFIG_FILE, -- 0600, -- getuid(), -- getgid(), -- false); -- if (ret != EOK) { -- DEBUG(SSSDBG_FATAL_FAILURE, -- "Could not copy default configuration: %s", -- sss_strerror(ret)); -- /* sss specific error denoting missing configuration file */ -- ret = ERR_MISSING_CONF; -- goto done; -- } -- -- /* Try again */ -- ret = sss_ini_config_file_open(init_data, config_file); -- if (ret != EOK) { -- DEBUG(SSSDBG_TRACE_FUNC, -- "sss_ini_config_file_open(default) failed: %s [%d]\n", -- strerror(ret), ret); -- if (ret == ENOENT) { -- /* sss specific error denoting missing configuration file */ -- ret = ERR_MISSING_CONF; -- } -- goto done; -- } -+ if (ret == ENOENT) { -+ /* sss specific error denoting missing configuration file */ -+ ret = ERR_MISSING_CONF; - } -+ goto done; - } - - ret = sss_ini_config_access_check(init_data); -diff --git a/src/examples/sssd-shadowutils b/src/examples/sssd-shadowutils -deleted file mode 100644 -index 626c7d075dfbf97dd91e259f94c6061689c83e9e..0000000000000000000000000000000000000000 ---- a/src/examples/sssd-shadowutils -+++ /dev/null -@@ -1,6 +0,0 @@ --#%PAM-1.0 --auth [success=done ignore=ignore default=die] pam_unix.so nullok try_first_pass --auth required pam_deny.so -- --account required pam_unix.so --account required pam_permit.so -diff --git a/src/examples/sssd.conf b/src/examples/sssd.conf -deleted file mode 100644 -index a851dbb7ecd5c3220fbd6a946a6c7be2822dbd27..0000000000000000000000000000000000000000 ---- a/src/examples/sssd.conf -+++ /dev/null -@@ -1,17 +0,0 @@ --[sssd] --config_file_version = 2 --services = nss, pam --domains = shadowutils -- --[nss] -- --[pam] -- --[domain/shadowutils] --id_provider = proxy --proxy_lib_name = files -- --auth_provider = proxy --proxy_pam_target = sssd-shadowutils -- --proxy_fast_alias = True --- -2.7.4 - diff --git a/SOURCES/0127-SERVER_MODE-Update-sdap-lists-for-each-ad_ctx.patch b/SOURCES/0127-SERVER_MODE-Update-sdap-lists-for-each-ad_ctx.patch new file mode 100644 index 0000000..772f302 --- /dev/null +++ b/SOURCES/0127-SERVER_MODE-Update-sdap-lists-for-each-ad_ctx.patch @@ -0,0 +1,81 @@ +From 9b9d3e2817fdcf16f2949641d4130b39856a4bf6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Fri, 28 Apr 2017 20:49:56 +0200 +Subject: [PATCH 127/127] SERVER_MODE: Update sdap lists for each ad_ctx + +We use separate AD context for each subdomain in the server mode. +Every such context has it's own sdap_domain list witch represents +sdap options such as filter and search bases for every domain. + +However AD context can only fully initialize sdap_domain structure +for the same domain for which the whole context was created, which +resulted in the other sdap_domain structures to be have automaticily +detected settings. This can cause problems if user is member of +groups from multiple domains. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3381 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 21f3d6124ea28218d02e1e345d38e2b948e4ec23) +--- + src/providers/ipa/ipa_subdomains_server.c | 36 +++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c +index b02ea67af964a03e5466067cdb2b3ba4498120eb..443d83824f329b9d8c3d8e820113e1029f832240 100644 +--- a/src/providers/ipa/ipa_subdomains_server.c ++++ b/src/providers/ipa/ipa_subdomains_server.c +@@ -870,6 +870,7 @@ static errno_t ipa_server_create_trusts_step(struct tevent_req *req) + { + struct tevent_req *subreq = NULL; + struct ipa_ad_server_ctx *trust_iter; ++ struct ipa_ad_server_ctx *trust_i; + struct ipa_server_create_trusts_state *state = NULL; + + state = tevent_req_data(req, struct ipa_server_create_trusts_state); +@@ -900,6 +901,41 @@ static errno_t ipa_server_create_trusts_step(struct tevent_req *req) + } + } + ++ /* Refresh all sdap_dom lists in all ipa_ad_server_ctx contexts */ ++ DLIST_FOR_EACH(trust_iter, state->id_ctx->server_mode->trusts) { ++ struct sdap_domain *sdom_a; ++ ++ sdom_a = sdap_domain_get(trust_iter->ad_id_ctx->sdap_id_ctx->opts, ++ trust_iter->dom); ++ if (sdom_a == NULL) { ++ continue; ++ } ++ ++ DLIST_FOR_EACH(trust_i, state->id_ctx->server_mode->trusts) { ++ struct sdap_domain *sdom_b; ++ ++ if (strcmp(trust_iter->dom->name, trust_i->dom->name) == 0) { ++ continue; ++ } ++ ++ sdom_b = sdap_domain_get(trust_i->ad_id_ctx->sdap_id_ctx->opts, ++ sdom_a->dom); ++ if (sdom_b == NULL) { ++ continue; ++ } ++ ++ /* Replace basedn and search bases from sdom_b with values ++ * from sdom_a */ ++ sdom_b->search_bases = sdom_a->search_bases; ++ sdom_b->user_search_bases = sdom_a->user_search_bases; ++ sdom_b->group_search_bases = sdom_a->group_search_bases; ++ sdom_b->netgroup_search_bases = sdom_a->netgroup_search_bases; ++ sdom_b->sudo_search_bases = sdom_a->sudo_search_bases; ++ sdom_b->service_search_bases = sdom_a->service_search_bases; ++ sdom_b->autofs_search_bases = sdom_a->autofs_search_bases; ++ } ++ } ++ + return EOK; + } + +-- +2.9.3 + diff --git a/SOURCES/0128-TOOLS-Fix-a-typo-in-groupadd.patch b/SOURCES/0128-TOOLS-Fix-a-typo-in-groupadd.patch deleted file mode 100644 index 4476896..0000000 --- a/SOURCES/0128-TOOLS-Fix-a-typo-in-groupadd.patch +++ /dev/null @@ -1,33 +0,0 @@ -From bac0f5a1d74d2dbedc5873592edbbdd791db2ede Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 6 Sep 2016 12:13:08 +0200 -Subject: [PATCH 128/135] TOOLS: Fix a typo in groupadd() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: -https://fedorahosted.org/sssd/ticket/3173 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 6be723a089a1e07a1cd19b4fa53fd142c13f0c69) ---- - src/tools/sss_sync_ops.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/tools/sss_sync_ops.c b/src/tools/sss_sync_ops.c -index a23a0b8c30366d2fb68554bfed184b8fce675e2b..39ef5bec96bd3942da8a8adfd21c99b03a77e551 100644 ---- a/src/tools/sss_sync_ops.c -+++ b/src/tools/sss_sync_ops.c -@@ -657,7 +657,7 @@ int groupadd(struct ops_ctx *data) - int ret; - - data->sysdb_fqname = sss_create_internal_fqname(data, -- data->sysdb_fqname, -+ data->name, - data->domain->name); - if (data->sysdb_fqname == NULL) { - return ENOMEM; --- -2.7.4 - diff --git a/SOURCES/0128-sss_nss_getlistbycert-return-results-from-multiple-d.patch b/SOURCES/0128-sss_nss_getlistbycert-return-results-from-multiple-d.patch new file mode 100644 index 0000000..26092f6 --- /dev/null +++ b/SOURCES/0128-sss_nss_getlistbycert-return-results-from-multiple-d.patch @@ -0,0 +1,348 @@ +From 71731d26dc4f2c36989779f327b0e9a399486e14 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 9 May 2017 16:57:43 +0200 +Subject: [PATCH] sss_nss_getlistbycert: return results from multiple domains +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently only the results from one domain were returned although all +domains were searched and the results were available. Unit tests are +updated to cover this case as well. + +Resolves https://pagure.io/SSSD/sssd/issue/3393 + +Reviewed-by: Pavel Březina +--- + src/responder/nss/nss_cmd.c | 87 +++++++++++++++++++++++++++++++++++- + src/responder/nss/nss_protocol.h | 6 +++ + src/responder/nss/nss_protocol_sid.c | 78 ++++++++++++++++++++++++++++++++ + src/tests/cmocka/test_nss_srv.c | 33 +++++++++----- + 4 files changed, 192 insertions(+), 12 deletions(-) + +diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c +index 1931bf62a686c7f30852dac547866609cf54a81b..a4727c18786a86c28b5415ba82295967a47a8ec0 100644 +--- a/src/responder/nss/nss_cmd.c ++++ b/src/responder/nss/nss_cmd.c +@@ -51,6 +51,7 @@ nss_cmd_ctx_create(TALLOC_CTX *mem_ctx, + } + + static void nss_getby_done(struct tevent_req *subreq); ++static void nss_getlistby_done(struct tevent_req *subreq); + + static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + enum cache_req_type type, +@@ -212,6 +213,89 @@ done: + return EOK; + } + ++static errno_t nss_getlistby_cert(struct cli_ctx *cli_ctx, ++ enum cache_req_type type) ++{ ++ struct nss_cmd_ctx *cmd_ctx; ++ struct tevent_req *subreq; ++ const char *cert; ++ errno_t ret; ++ ++ cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, NULL); ++ if (cmd_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ cmd_ctx->sid_id_type = SSS_ID_TYPE_UID; ++ ++ ret = nss_protocol_parse_cert(cli_ctx, &cert); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request message!\n"); ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Input cert: %s\n", get_last_x_chars(cert, 10)); ++ ++ subreq = cache_req_user_by_cert_send(cmd_ctx, cli_ctx->ev, cli_ctx->rctx, ++ cli_ctx->rctx->ncache, 0, ++ CACHE_REQ_ANY_DOM, NULL, ++ cert); ++ if (subreq == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ tevent_req_set_callback(subreq, nss_getlistby_done, cmd_ctx); ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(cmd_ctx); ++ return nss_protocol_done(cli_ctx, ret); ++ } ++ ++ return EOK; ++} ++ ++static void nss_getlistby_done(struct tevent_req *subreq) ++{ ++ struct cache_req_result **results; ++ struct nss_cmd_ctx *cmd_ctx; ++ errno_t ret; ++ struct cli_protocol *pctx; ++ ++ cmd_ctx = tevent_req_callback_data(subreq, struct nss_cmd_ctx); ++ ++ ret = cache_req_recv(cmd_ctx, subreq, &results); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert request failed.\n"); ++ goto done; ++ } ++ ++ pctx = talloc_get_type(cmd_ctx->cli_ctx->protocol_ctx, struct cli_protocol); ++ ++ ret = sss_packet_new(pctx->creq, 0, sss_packet_get_cmd(pctx->creq->in), ++ &pctx->creq->out); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = nss_protocol_fill_name_list_all_domains(cmd_ctx->nss_ctx, cmd_ctx, ++ pctx->creq->out, results); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ sss_packet_set_error(pctx->creq->out, EOK); ++ ++done: ++ nss_protocol_done(cmd_ctx->cli_ctx, ret); ++ talloc_free(cmd_ctx); ++} ++ + static errno_t nss_getby_cert(struct cli_ctx *cli_ctx, + enum cache_req_type type, + nss_protocol_fill_packet_fn fill_fn) +@@ -934,8 +1018,7 @@ static errno_t nss_cmd_getnamebycert(struct cli_ctx *cli_ctx) + + static errno_t nss_cmd_getlistbycert(struct cli_ctx *cli_ctx) + { +- return nss_getby_cert(cli_ctx, CACHE_REQ_USER_BY_CERT, +- nss_protocol_fill_name_list); ++ return nss_getlistby_cert(cli_ctx, CACHE_REQ_USER_BY_CERT); + } + + struct sss_cmd_table *get_nss_cmds(void) +diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h +index e4c0e52c0e642e885ef2c8423ea564beff7242cf..417b0891615dcb8771d49f7b2f4d276342ca3150 100644 +--- a/src/responder/nss/nss_protocol.h ++++ b/src/responder/nss/nss_protocol.h +@@ -181,6 +181,12 @@ nss_protocol_fill_name_list(struct nss_ctx *nss_ctx, + struct cache_req_result *result); + + errno_t ++nss_protocol_fill_name_list_all_domains(struct nss_ctx *nss_ctx, ++ struct nss_cmd_ctx *cmd_ctx, ++ struct sss_packet *packet, ++ struct cache_req_result **results); ++ ++errno_t + nss_protocol_fill_id(struct nss_ctx *nss_ctx, + struct nss_cmd_ctx *cmd_ctx, + struct sss_packet *packet, +diff --git a/src/responder/nss/nss_protocol_sid.c b/src/responder/nss/nss_protocol_sid.c +index d4b7ee22d7c68a9e6f7c668f7268cdc5f36768b3..61357c2bf92e2f15d978b64a15ad5bd5aa354445 100644 +--- a/src/responder/nss/nss_protocol_sid.c ++++ b/src/responder/nss/nss_protocol_sid.c +@@ -561,3 +561,81 @@ nss_protocol_fill_name_list(struct nss_ctx *nss_ctx, + + return EOK; + } ++ ++errno_t ++nss_protocol_fill_name_list_all_domains(struct nss_ctx *nss_ctx, ++ struct nss_cmd_ctx *cmd_ctx, ++ struct sss_packet *packet, ++ struct cache_req_result **results) ++{ ++ enum sss_id_type *id_types; ++ size_t rp = 0; ++ size_t body_len; ++ uint8_t *body; ++ errno_t ret; ++ struct sized_string *sz_names; ++ size_t len; ++ size_t c; ++ const char *tmp_str; ++ size_t d; ++ size_t total = 0; ++ size_t iter = 0; ++ ++ if (results == NULL) { ++ return EINVAL; ++ } ++ ++ for (d = 0; results[d] != NULL; d++) { ++ total += results[d]->count; ++ } ++ ++ sz_names = talloc_array(cmd_ctx, struct sized_string, total); ++ if (sz_names == NULL) { ++ return ENOMEM; ++ } ++ ++ id_types = talloc_array(cmd_ctx, enum sss_id_type, total); ++ if (id_types == NULL) { ++ return ENOMEM; ++ } ++ ++ len = 0; ++ for (d = 0; results[d] != NULL; d++) { ++ for (c = 0; c < results[d]->count; c++) { ++ ret = nss_get_id_type(cmd_ctx, results[d], &(id_types[iter])); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ tmp_str = sss_get_name_from_msg(results[d]->domain, ++ results[d]->msgs[c]); ++ if (tmp_str == NULL) { ++ return EINVAL; ++ } ++ to_sized_string(&(sz_names[iter]), tmp_str); ++ ++ len += sz_names[iter].len; ++ iter++; ++ } ++ } ++ ++ len += (2 + total) * sizeof(uint32_t); ++ ++ ret = sss_packet_grow(packet, len); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n"); ++ return ret; ++ } ++ ++ sss_packet_get_body(packet, &body, &body_len); ++ ++ SAFEALIGN_SET_UINT32(&body[rp], total, &rp); /* Num results. */ ++ SAFEALIGN_SET_UINT32(&body[rp], 0, &rp); /* Reserved. */ ++ for (c = 0; c < total; c++) { ++ SAFEALIGN_SET_UINT32(&body[rp], id_types[c], &rp); ++ SAFEALIGN_SET_STRING(&body[rp], sz_names[c].str, sz_names[c].len, ++ &rp); ++ } ++ ++ return EOK; ++} +diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c +index 8c72f44f1869558893627e1f2f91b5f3b96c6317..03b5bcc302322551a32f5b8cfe4b7698947abbe7 100644 +--- a/src/tests/cmocka/test_nss_srv.c ++++ b/src/tests/cmocka/test_nss_srv.c +@@ -3808,7 +3808,8 @@ static int test_nss_getnamebycert_check(uint32_t status, uint8_t *body, size_t b + return EOK; + } + +-static int test_nss_getlistbycert_check(uint32_t status, uint8_t *body, size_t blen) ++static int test_nss_getlistbycert_check_exp(uint32_t status, uint8_t *body, ++ size_t blen, size_t exp) + { + size_t rp = 0; + uint32_t id_type; +@@ -3817,13 +3818,13 @@ static int test_nss_getlistbycert_check(uint32_t status, uint8_t *body, size_t b + const char *name; + int found = 0; + const char *fq_name1 = "testcertuser@"TEST_DOM_NAME ; +- const char *fq_name2 = "testcertuser2@"TEST_DOM_NAME; ++ const char *fq_name2 = "testcertuser2@"TEST_SUBDOM_NAME; + + assert_int_equal(status, EOK); + + /* num_results and reserved */ + SAFEALIGN_COPY_UINT32(&num, body + rp, &rp); +- assert_in_range(num, 1, 2); ++ assert_int_equal(num, exp); + SAFEALIGN_COPY_UINT32(&reserved, body + rp, &rp); + assert_int_equal(reserved, 0); + +@@ -3858,6 +3859,17 @@ static int test_nss_getlistbycert_check(uint32_t status, uint8_t *body, size_t b + return EOK; + } + ++static int test_nss_getlistbycert_check_one(uint32_t status, uint8_t *body, ++ size_t blen) ++{ ++ return test_nss_getlistbycert_check_exp(status, body, blen, 1); ++} ++ ++static int test_nss_getlistbycert_check_two(uint32_t status, uint8_t *body, ++ size_t blen) ++{ ++ return test_nss_getlistbycert_check_exp(status, body, blen, 2); ++} + + static void test_nss_getnamebycert(void **state) + { +@@ -3949,7 +3961,7 @@ static void test_nss_getlistbycert(void **state) + der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size); + assert_non_null(der); + +- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); ++ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); + talloc_free(der); + assert_int_equal(ret, EOK); + +@@ -3967,7 +3979,7 @@ static void test_nss_getlistbycert(void **state) + /* Should go straight to back end, without contacting DP. */ + /* If there is only a single user mapped the result will look like the */ + /* result of getnamebycert. */ +- set_cmd_cb(test_nss_getlistbycert_check); ++ set_cmd_cb(test_nss_getlistbycert_check_one); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETLISTBYCERT, + nss_test_ctx->nss_cmds); + assert_int_equal(ret, EOK); +@@ -3990,7 +4002,7 @@ static void test_nss_getlistbycert_multi(void **state) + attrs = sysdb_new_attrs(nss_test_ctx); + assert_non_null(attrs); + +- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); ++ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); + assert_int_equal(ret, EOK); + + /* Prime the cache with two valid user */ +@@ -4004,11 +4016,11 @@ static void test_nss_getlistbycert_multi(void **state) + attrs = sysdb_new_attrs(nss_test_ctx); + assert_non_null(attrs); + +- ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); ++ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); + talloc_free(der); + assert_int_equal(ret, EOK); + +- ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, ++ ret = store_user(nss_test_ctx, nss_test_ctx->subdom, + &testbycert2, attrs, 0); + assert_int_equal(ret, EOK); + talloc_free(attrs); +@@ -4019,7 +4031,7 @@ static void test_nss_getlistbycert_multi(void **state) + + /* Query for that user, call a callback when command finishes */ + /* Should go straight to back end, without contacting DP */ +- set_cmd_cb(test_nss_getlistbycert_check); ++ set_cmd_cb(test_nss_getlistbycert_check_two); + ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETLISTBYCERT, + nss_test_ctx->nss_cmds); + assert_int_equal(ret, EOK); +@@ -4290,7 +4302,8 @@ int main(int argc, const char *argv[]) + cmocka_unit_test_setup_teardown(test_nss_getlistbycert, + nss_test_setup, nss_test_teardown), + cmocka_unit_test_setup_teardown(test_nss_getlistbycert_multi, +- nss_test_setup, nss_test_teardown), ++ nss_subdom_test_setup, ++ nss_subdom_test_teardown), + cmocka_unit_test_setup_teardown(test_nss_getsidbyname, + nss_test_setup, nss_test_teardown), + cmocka_unit_test_setup_teardown(test_nss_getsidbyupn, +-- +2.9.3 + diff --git a/SOURCES/0129-CACHE_REQ-Avoid-using-of-uninitialized-value.patch b/SOURCES/0129-CACHE_REQ-Avoid-using-of-uninitialized-value.patch new file mode 100644 index 0000000..d11d711 --- /dev/null +++ b/SOURCES/0129-CACHE_REQ-Avoid-using-of-uninitialized-value.patch @@ -0,0 +1,68 @@ +From 6a1da829eaa1eee3e854f0cadc0b6effff776ab4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 15 May 2017 11:54:00 +0200 +Subject: [PATCH 1/2] CACHE_REQ: Avoid using of uninitialized value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 4ef0b19a introduced the following warning, as "req" may be used +without being initialized: +src/responder/common/cache_req/cache_req_search.c: + In function 'cache_req_search_done': +src/responder/common/cache_req/cache_req_search.c:467:9: + error: 'req' may be used uninitialized in this function + [-Werror=maybe-uninitialized] + tevent_req_error(req, ret); + ^ +src/responder/common/cache_req/cache_req_search.c:424:24: + note: 'req' was declared here + struct tevent_req *req; + ^ +cc1: all warnings being treated as errors + +In order to fix the issue above, let's just allocate tmp_ctx after "req" +is already set. + +Related: +https://pagure.io/SSSD/sssd/issue/3362 + +Signed-off-by: Fabiano Fidêncio +Co-Author: Lukáš Slebodník +Reviewed-by: Sumit Bose +--- + src/responder/common/cache_req/cache_req_search.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c +index 793dbc5042ae329b2cade5d1eb5a6d41102e264f..70448a7639bc9f98d380b8edce9d130adfa0ceb2 100644 +--- a/src/responder/common/cache_req/cache_req_search.c ++++ b/src/responder/common/cache_req/cache_req_search.c +@@ -425,18 +425,18 @@ static void cache_req_search_done(struct tevent_req *subreq) + struct ldb_result *result = NULL; + errno_t ret; + +- tmp_ctx = talloc_new(NULL); +- if (tmp_ctx == NULL) { +- ret = ENOMEM; +- goto done; +- } +- + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct cache_req_search_state); + + state->dp_success = state->cr->plugin->dp_recv_fn(subreq, state->cr); + talloc_zfree(subreq); + ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ + /* Get result from cache again. */ + ret = cache_req_search_cache(tmp_ctx, state->cr, &result); + if (ret != EOK) { +-- +2.9.3 + diff --git a/SOURCES/0129-TOOLS-sss_groupshow-did-not-work.patch b/SOURCES/0129-TOOLS-sss_groupshow-did-not-work.patch deleted file mode 100644 index 7179654..0000000 --- a/SOURCES/0129-TOOLS-sss_groupshow-did-not-work.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 7d8269e8a885cc0344dc78951d2880edac32a02c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 6 Sep 2016 13:46:53 +0200 -Subject: [PATCH 129/135] TOOLS: sss_groupshow did not work -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -sss_groupshow used shortname to search -in sysdb database. We have to u e sysdb_fqname -(aka internal_fqname) format for all sysdb -oprations. - -Resolves: -https://fedorahosted.org/sssd/ticket/3175 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 5210c5d3a5a83b5d08396ee23d88f6ba0994097d) ---- - src/tools/sss_groupshow.c | 13 +++++++++++-- - 1 file changed, 11 insertions(+), 2 deletions(-) - -diff --git a/src/tools/sss_groupshow.c b/src/tools/sss_groupshow.c -index 41d7475cef1093a4cb214ec4b017db59e6c26fe2..5870cc802c70366c47a0d30cb0d9795cf6035bc5 100644 ---- a/src/tools/sss_groupshow.c -+++ b/src/tools/sss_groupshow.c -@@ -318,7 +318,7 @@ int group_show(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - bool recursive, -- const char *name, -+ const char *shortname, - struct group_info **res) - { - struct group_info *root; -@@ -326,11 +326,20 @@ int group_show(TALLOC_CTX *mem_ctx, - struct ldb_message *msg = NULL; - const char **group_members = NULL; - int nmembers = 0; -+ char *sysdb_fqname = NULL; - int ret; - int i; - -+ sysdb_fqname = sss_create_internal_fqname(mem_ctx, -+ shortname, -+ domain->name); -+ if (sysdb_fqname == NULL) { -+ return ENOMEM; -+ } -+ - /* First, search for the root group */ -- ret = sysdb_search_group_by_name(mem_ctx, domain, name, attrs, &msg); -+ ret = sysdb_search_group_by_name(mem_ctx, domain, sysdb_fqname, attrs, -+ &msg); - if (ret) { - DEBUG(SSSDBG_OP_FAILURE, - "Search failed: %s (%d)\n", strerror(ret), ret); --- -2.7.4 - diff --git a/SOURCES/0130-CACHE_REQ-Ensure-the-domains-are-updated-for-filter-.patch b/SOURCES/0130-CACHE_REQ-Ensure-the-domains-are-updated-for-filter-.patch new file mode 100644 index 0000000..1063c09 --- /dev/null +++ b/SOURCES/0130-CACHE_REQ-Ensure-the-domains-are-updated-for-filter-.patch @@ -0,0 +1,163 @@ +From 1a89fc33d1b9b1070c7ab83fb0314e538ac46736 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 3 May 2017 13:24:40 +0200 +Subject: [PATCH 2/2] CACHE_REQ: Ensure the domains are updated for "filter" + related calls +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As contacting the infopipe responder on a "filter" related call may lead +to the situation where the cr_domains' list is not populated yet (as the +domains and subdomains lists from the data provider are not processed +yet), let's explicitly call sss_dp_get_domains() for those cases and +avoid returning a wrong result to the caller. + +This situation may happen only because the schedule_get_domains_task(), +that's called when the infopipe responder is initialized, may take some +time to run/finish. + +While I'm not exactly sure whether it's the best solution to avoid the +"race", it seems to be sane enough to avoid the issues. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3387 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +--- + src/responder/common/cache_req/cache_req.c | 86 ++++++++++++++++++++++++++++-- + 1 file changed, 81 insertions(+), 5 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index 797325a30e6c1ed5f1d4b4c147c65391d5204b52..7d77eb7dd72a7ccf3d687eee8f746ab84176b487 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -698,6 +698,13 @@ static errno_t cache_req_process_input(TALLOC_CTX *mem_ctx, + struct cache_req *cr, + const char *domain); + ++static errno_t cache_req_update_domains(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct cache_req *cr, ++ const char *domain); ++ ++static void cache_req_domains_updated(struct tevent_req *subreq); ++ + static void cache_req_input_parsed(struct tevent_req *subreq); + + static errno_t cache_req_select_domains(struct tevent_req *req, +@@ -753,13 +760,13 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, + goto done; + } + ++ state->domain_name = domain; + ret = cache_req_process_input(state, req, cr, domain); + if (ret != EOK) { + goto done; + } + +- state->domain_name = domain; +- ret = cache_req_select_domains(req, domain); ++ ret = cache_req_select_domains(req, state->domain_name); + + done: + if (ret == EOK) { +@@ -780,14 +787,25 @@ static errno_t cache_req_process_input(TALLOC_CTX *mem_ctx, + { + struct tevent_req *subreq; + const char *default_domain; ++ errno_t ret; + + if (cr->data->name.input == NULL) { +- /* Input was not name, there is no need to process it further. */ +- return EOK; ++ /* Call cache_req_update_domains() in order to get a up to date list ++ * of domains and subdomains, if needed. Otherwise just return EOK as ++ * the input was not a name, thus there's no need to process it ++ * further. */ ++ return cache_req_update_domains(mem_ctx, req, cr, domain); + } + + if (cr->plugin->parse_name == false || domain != NULL) { +- /* We do not want to parse the name. */ ++ /* Call cache_req_update_domains() in order to get a up to date list ++ * of domains and subdomains, if needed. Otherwise, just use the input ++ * name as it is. */ ++ ret = cache_req_update_domains(mem_ctx, req, cr, domain); ++ if (ret != EOK) { ++ return ret; ++ } ++ + return cache_req_set_name(cr, cr->data->name.input); + } + +@@ -812,6 +830,64 @@ static errno_t cache_req_process_input(TALLOC_CTX *mem_ctx, + return EAGAIN; + } + ++static errno_t cache_req_update_domains(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct cache_req *cr, ++ const char *domain) ++{ ++ struct tevent_req *subreq; ++ ++ if (cr->rctx->get_domains_last_call.tv_sec != 0) { ++ return EOK; ++ } ++ ++ subreq = sss_dp_get_domains_send(mem_ctx, cr->rctx, false, domain); ++ if (subreq == NULL) { ++ return ENOMEM; ++ } ++ ++ tevent_req_set_callback(subreq, cache_req_domains_updated, req); ++ return EAGAIN; ++} ++ ++static void cache_req_domains_updated(struct tevent_req *subreq) ++{ ++ struct tevent_req *req; ++ struct cache_req_state *state; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct cache_req_state); ++ ++ ret = sss_dp_get_domains_recv(subreq); ++ talloc_free(subreq); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ if (state->cr->data->name.input == NULL) { ++ /* Input was not name, there is no need to process it further. */ ++ goto immediately; ++ } ++ ++ if (state->cr->plugin->parse_name == false || state->domain_name != NULL) { ++ /* We do not want to parse the name. */ ++ ret = cache_req_set_name(state->cr, state->cr->data->name.input); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ ++immediately: ++ ret = cache_req_select_domains(req, state->domain_name); ++ ++done: ++ if (ret != EOK && ret != EAGAIN) { ++ tevent_req_error(req, ret); ++ return; ++ } ++} ++ + static void cache_req_input_parsed(struct tevent_req *subreq) + { + struct tevent_req *req; +-- +2.9.3 + diff --git a/SOURCES/0130-TESTS-sss_groupadd-groupshow-regressions.patch b/SOURCES/0130-TESTS-sss_groupadd-groupshow-regressions.patch deleted file mode 100644 index 11e71cf..0000000 --- a/SOURCES/0130-TESTS-sss_groupadd-groupshow-regressions.patch +++ /dev/null @@ -1,78 +0,0 @@ -From cb355831d3f128688b33b9099ec047f8ef6a3234 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Tue, 6 Sep 2016 17:37:14 +0200 -Subject: [PATCH 130/135] TESTS: sss_groupadd/groupshow regressions -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Adds regression CI test for ticket #3173 and #3175. - -Resolves: -https://fedorahosted.org/sssd/ticket/3173 -https://fedorahosted.org/sssd/ticket/3175 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 20c2d76d9430a1fc069531ff537df046a74c8f61) ---- - src/tests/intg/test_local_domain.py | 28 +++++++++++++++++++++++++++- - 1 file changed, 27 insertions(+), 1 deletion(-) - -diff --git a/src/tests/intg/test_local_domain.py b/src/tests/intg/test_local_domain.py -index 31834b5b9ab93329ac5eb76e3676d6f89f5b996e..56e3812b113b36301d1ec6049e5a1210d3070442 100644 ---- a/src/tests/intg/test_local_domain.py -+++ b/src/tests/intg/test_local_domain.py -@@ -19,11 +19,13 @@ - import os - import stat - import pwd -+import grp - import time - import config - import signal - import subprocess - import pytest -+import ent - from util import unindent - - -@@ -90,6 +92,11 @@ def assert_nonexistent_user(name): - pwd.getpwnam(name) - - -+def assert_nonexistent_group(name): -+ with pytest.raises(KeyError): -+ grp.getgrnam(name) -+ -+ - def test_wrong_LC_ALL(local_domain_only): - """ - Regression test for ticket -@@ -106,4 +113,23 @@ def test_wrong_LC_ALL(local_domain_only): - # sss_userdel must remove the user despite wrong LC_ALL - subprocess.check_call(["sss_userdel", "foo", "-R"]) - assert_nonexistent_user("foo") -- os.environ["LC_LOCAL"] = oldvalue -+ os.environ["LC_ALL"] = oldvalue -+ -+ -+def test_sss_group_add_show_del(local_domain_only): -+ """ -+ Regression test for tickets -+ https://fedorahosted.org/sssd/ticket/3173 -+ https://fedorahosted.org/sssd/ticket/3175 -+ """ -+ -+ subprocess.check_call(["sss_groupadd", "foo", "-g", "10001"]) -+ -+ "This should not raise KeyError" -+ ent.assert_group_by_name("foo", dict(name="foo", gid=10001)) -+ -+ "sss_grupshow should return 0 with existing group name" -+ subprocess.check_call(["sss_groupshow", "foo"]) -+ -+ subprocess.check_call(["sss_groupdel", "foo"]) -+ assert_nonexistent_group("foo") --- -2.7.4 - diff --git a/SOURCES/0131-AD-SUBDOMAINS-Fix-search-bases-for-child-domains.patch b/SOURCES/0131-AD-SUBDOMAINS-Fix-search-bases-for-child-domains.patch new file mode 100644 index 0000000..50c99ed --- /dev/null +++ b/SOURCES/0131-AD-SUBDOMAINS-Fix-search-bases-for-child-domains.patch @@ -0,0 +1,102 @@ +From f994343e9ffc8f8d2917678ae61bcdf68c316a20 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Tue, 9 May 2017 11:21:02 +0200 +Subject: [PATCH 131/131] AD SUBDOMAINS: Fix search bases for child domains + +When using direct AD integration, child domains did not respect +the sssd.conf configuration of search bases. + +There were few issues all of which are fixed in this small +patch. + +First problem was that the sdap domain list was not properly +inherited from the parent in the child domains and the children +always created their own sdap domains lists that were disconnected +from the parent context and never used. + +Second issue was that the child domain did not call the function +to reinit the search bases after the sdap_domain was added to the +list of sdap domains. This caused that child domains always used +automatically detected search bases and never used the configured +ones even though they were properly read into the ID options +context attached to the subdomain. + +Also there has been an issue that the sdap search bases +were rewritten by the new child domain initialization +(this only happened with more than one child domain) +because the sdap domain list was 'updated' every time +a new child domain was initialized, which caused that +only the main domain and the last child domain had proper +search bases, the others only the auto-discovered ones +(because they were overwritten with the 'update'). + +Resolves: +https://pagure.io/SSSD/sssd/issue/3397 + +Reviewed-by: Sumit Bose +--- + src/providers/ad/ad_subdomains.c | 17 +++++++++++++++++ + src/providers/ldap/sdap_domain.c | 5 +++++ + 2 files changed, 22 insertions(+) + +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index ef166446e837c3f7cd824c1abf4b5cc587aec9da..c9b79dd9d6840802cddc067eef9d5110cf8d0778 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -221,6 +221,9 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, + ad_id_ctx->sdap_id_ctx->opts = ad_options->id; + ad_options->id_ctx = ad_id_ctx; + ++ /* We need to pass the sdap list from parent */ ++ ad_id_ctx->sdap_id_ctx->opts->sdom = id_ctx->sdap_id_ctx->opts->sdom; ++ + /* use AD plugin */ + srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res, + default_host_dbs, +@@ -257,6 +260,13 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, + ad_id_ctx->sdap_id_ctx->opts->idmap_ctx = + id_ctx->sdap_id_ctx->opts->idmap_ctx; + ++ ret = ad_set_search_bases(ad_options->id, sdom); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to set LDAP search bases for " ++ "domain '%s'. Will try to use automatically detected search " ++ "bases.", subdom->name); ++ } ++ + *_subdom_id_ctx = ad_id_ctx; + return EOK; + } +@@ -621,6 +631,13 @@ ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx, + return ret; + } + ++ ret = ad_set_search_bases(ctx->ad_id_ctx->ad_options->id, ctx->sdom); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "failed to set ldap search bases for " ++ "domain '%s'. will try to use automatically detected search " ++ "bases.", ctx->sdom->dom->name); ++ } ++ + DLIST_FOR_EACH(sditer, ctx->sdom) { + if (IS_SUBDOMAIN(sditer->dom) && sditer->pvt == NULL) { + ret = ad_subdom_ad_ctx_new(ctx->be_ctx, ctx->ad_id_ctx, +diff --git a/src/providers/ldap/sdap_domain.c b/src/providers/ldap/sdap_domain.c +index 5cba9df0fd5fb320a57adc39093283aed865f57f..d384b2e4a0ec3a7c8d0b05e0ce735feb2189085f 100644 +--- a/src/providers/ldap/sdap_domain.c ++++ b/src/providers/ldap/sdap_domain.c +@@ -154,6 +154,11 @@ sdap_domain_subdom_add(struct sdap_id_ctx *sdap_id_ctx, + parent->name, ret, strerror(ret)); + return ret; + } ++ } else if (sditer->search_bases != NULL) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "subdomain %s has already initialized search bases\n", ++ dom->name); ++ continue; + } else { + sdom = sditer; + } +-- +2.9.3 + diff --git a/SOURCES/0131-TOOLS-use-internal-fqdn-for-DN.patch b/SOURCES/0131-TOOLS-use-internal-fqdn-for-DN.patch deleted file mode 100644 index 9b77d88..0000000 --- a/SOURCES/0131-TOOLS-use-internal-fqdn-for-DN.patch +++ /dev/null @@ -1,57 +0,0 @@ -From bfbad5b20c8a34b545cea8df6c937125edf0e42c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Wed, 7 Sep 2016 10:58:25 +0200 -Subject: [PATCH 131/135] TOOLS: use internal fqdn for DN -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Use internal fqdn when creating sysdb group dn. - -Resolves: -https://fedorahosted.org/sssd/ticket/3178 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 5e2142b66589e5e50cb404fc972ed5418bbaa772) ---- - src/tools/sss_sync_ops.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/src/tools/sss_sync_ops.c b/src/tools/sss_sync_ops.c -index 39ef5bec96bd3942da8a8adfd21c99b03a77e551..a0291baeada49b9f21e040a54e303214d5a46332 100644 ---- a/src/tools/sss_sync_ops.c -+++ b/src/tools/sss_sync_ops.c -@@ -137,6 +137,7 @@ static int mod_groups_member(struct sss_domain_info *dom, - struct ldb_dn *parent_dn; - int ret; - int i; -+ char *grp_sysdb_fqname = NULL; - - tmpctx = talloc_new(NULL); - if (!tmpctx) { -@@ -145,13 +146,21 @@ static int mod_groups_member(struct sss_domain_info *dom, - - /* FIXME: add transaction around loop */ - for (i = 0; grouplist[i]; i++) { -+ grp_sysdb_fqname = sss_create_internal_fqname(tmpctx, grouplist[i], -+ dom->name); -+ if (grp_sysdb_fqname == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } - -- parent_dn = sysdb_group_dn(tmpctx, dom, grouplist[i]); -+ parent_dn = sysdb_group_dn(tmpctx, dom, grp_sysdb_fqname); - if (!parent_dn) { - ret = ENOMEM; - goto done; - } - -+ talloc_free(grp_sysdb_fqname); -+ - ret = sysdb_mod_group_member(dom, member_dn, parent_dn, optype); - if (ret) { - goto done; --- -2.7.4 - diff --git a/SOURCES/0132-KRB5-Advise-the-user-to-inspect-the-krb5_child.log-i.patch b/SOURCES/0132-KRB5-Advise-the-user-to-inspect-the-krb5_child.log-i.patch new file mode 100644 index 0000000..7eecef9 --- /dev/null +++ b/SOURCES/0132-KRB5-Advise-the-user-to-inspect-the-krb5_child.log-i.patch @@ -0,0 +1,39 @@ +From cf1bb5464609f5873685406f9e09e43de8738e42 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 22 May 2017 09:55:12 +0200 +Subject: [PATCH 132/135] KRB5: Advise the user to inspect the krb5_child.log + if the child doesn't return a valid response +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the child returns a runtime error, it is often not clear from the +domain debug logs what to do next. This patch adds a DEBUG message that +tells the admin to look into the krb5_child.log + +Resolves: +https://pagure.io/SSSD/sssd/issue/2955 + +Reviewed-by: Pavel Březina +(cherry picked from commit 7410f735b64937e0c2401c09b5cffc9c78b11849) +--- + src/providers/krb5/krb5_auth.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c +index 2faf18d17a735476c20f9cc27b15be4a39cadc5c..894bd41bde031ac33187bfa3b14202e9429a9198 100644 +--- a/src/providers/krb5/krb5_auth.c ++++ b/src/providers/krb5/krb5_auth.c +@@ -890,6 +890,9 @@ static void krb5_auth_done(struct tevent_req *subreq) + state->be_ctx->domain->pwd_expiration_warning, + &res); + if (ret) { ++ DEBUG(SSSDBG_IMPORTANT_INFO, ++ "The krb5_child process returned an error. Please inspect the " ++ "krb5_child.log file or the journal for more information\n"); + DEBUG(SSSDBG_OP_FAILURE, "Could not parse child response [%d]: %s\n", + ret, strerror(ret)); + goto done; +-- +2.9.3 + diff --git a/SOURCES/0132-TESTS-Test-for-sss_user-groupmod-a.patch b/SOURCES/0132-TESTS-Test-for-sss_user-groupmod-a.patch deleted file mode 100644 index af34532..0000000 --- a/SOURCES/0132-TESTS-Test-for-sss_user-groupmod-a.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 2eb23ddb5f03a71a329bf4874194455ff87e1806 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Wed, 7 Sep 2016 13:08:59 +0200 -Subject: [PATCH 132/135] TESTS: Test for sss_user/groupmod -a -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Regression tests for ticket #3178. - -Resolves: -https://fedorahosted.org/sssd/ticket/3178 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 7fa4964d84f41bd80a6d971ffaeef87a7c2f19be) ---- - src/tests/intg/test_local_domain.py | 36 ++++++++++++++++++++++++++++++++++++ - 1 file changed, 36 insertions(+) - -diff --git a/src/tests/intg/test_local_domain.py b/src/tests/intg/test_local_domain.py -index 56e3812b113b36301d1ec6049e5a1210d3070442..5e3e3d4d1cdc6db5d68a6e5b9d96d94c2c694b14 100644 ---- a/src/tests/intg/test_local_domain.py -+++ b/src/tests/intg/test_local_domain.py -@@ -133,3 +133,39 @@ def test_sss_group_add_show_del(local_domain_only): - - subprocess.check_call(["sss_groupdel", "foo"]) - assert_nonexistent_group("foo") -+ -+ -+def test_add_local_user_to_local_group(local_domain_only): -+ """ -+ Regression test for ticket -+ https://fedorahosted.org/sssd/ticket/3178 -+ """ -+ subprocess.check_call(["sss_groupadd", "-g", "10009", "group10009"]) -+ subprocess.check_call(["sss_useradd", "-u", "10009", "-M", "user10009"]) -+ subprocess.check_call(["sss_usermod", "-a", "group10009", "user10009"]) -+ -+ ent.assert_group_by_name( -+ "group10009", -+ dict(name="group10009", passwd="*", gid=10009, -+ mem=ent.contains_only("user10009"))) -+ -+ -+def test_add_local_group_to_local_group(local_domain_only): -+ """ -+ Regression test for tickets -+ https://fedorahosted.org/sssd/ticket/3178 -+ """ -+ subprocess.check_call(["sss_groupadd", "-g", "10009", "group_child"]) -+ subprocess.check_call(["sss_useradd", "-u", "10009", "-M", "user_child"]) -+ subprocess.check_call(["sss_usermod", "-a", "group_child", "user_child"]) -+ -+ subprocess.check_call(["sss_groupadd", "-g", "10008", "group_parent"]) -+ subprocess.check_call( -+ ["sss_groupmod", "-a", "group_parent", "group_child"]) -+ -+ # User from child_group is member of parent_group, so child_group's -+ # member must be also parent_group's member -+ ent.assert_group_by_name( -+ "group_parent", -+ dict(name="group_parent", passwd="*", gid=10008, -+ mem=ent.contains_only("user_child"))) --- -2.7.4 - diff --git a/SOURCES/0133-TOOLS-sss_mc_refresh_nested_group-short-fqname-usage.patch b/SOURCES/0133-TOOLS-sss_mc_refresh_nested_group-short-fqname-usage.patch deleted file mode 100644 index 6f8b54e..0000000 --- a/SOURCES/0133-TOOLS-sss_mc_refresh_nested_group-short-fqname-usage.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 1a1aaf46d1ee3ae4c9346c5c492520257c7c1b42 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Wed, 7 Sep 2016 14:43:13 +0200 -Subject: [PATCH 133/135] TOOLS: sss_mc_refresh_nested_group short/fqname usage -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We use shortname to refresh memory cache, but in case of nested groups, -we used internal_fqname to refresh parent groups. - -We also wrongly used the shortname for sysdb_search operation. -Which caused error message to be printed when sss_usermod -a or -sss_groupmod -a where called. - -Reviewed-by: Lukáš Slebodník ---- - src/tools/tools_mc_util.c | 66 +++++++++++++++++++++++++++++++++-------------- - 1 file changed, 47 insertions(+), 19 deletions(-) - -diff --git a/src/tools/tools_mc_util.c b/src/tools/tools_mc_util.c -index 2516a1981ddd965d4cae8c469ed79aaef8fa7193..716e3760f67d958f2139adbb49998d9e352d23f4 100644 ---- a/src/tools/tools_mc_util.c -+++ b/src/tools/tools_mc_util.c -@@ -293,62 +293,90 @@ errno_t sss_mc_refresh_group(const char *groupname) - return sss_mc_refresh_ent(groupname, SSS_TOOLS_GROUP); - } - --errno_t sss_mc_refresh_nested_group(struct tools_ctx *tctx, -- const char *name) -+static errno_t sss_mc_refresh_nested_group(struct tools_ctx *tctx, -+ const char *shortname) - { - errno_t ret; -- struct ldb_message *msg; -+ struct ldb_message *msg = NULL; - struct ldb_message_element *el; - const char *attrs[] = { SYSDB_MEMBEROF, - SYSDB_NAME, - NULL }; - size_t i; -- char *parent_name; -+ char *parent_internal_name; -+ char *parent_outname; -+ char *internal_name; -+ TALLOC_CTX *tmpctx; - -- ret = sss_mc_refresh_group(name); -+ tmpctx = talloc_new(tctx); -+ if (tmpctx == NULL) { -+ return ENOMEM; -+ } -+ -+ internal_name = sss_create_internal_fqname(tmpctx, shortname, -+ tctx->local->name); -+ if (internal_name == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = sss_mc_refresh_group(shortname); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, -- "Cannot refresh group %s from memory cache\n", name); -+ "Cannot refresh group %s from memory cache\n", shortname); - /* try to carry on */ - } - -- ret = sysdb_search_group_by_name(tctx, tctx->local, name, attrs, &msg); -+ ret = sysdb_search_group_by_name(tmpctx, tctx->local, internal_name, attrs, -+ &msg); - if (ret) { - DEBUG(SSSDBG_OP_FAILURE, - "Search failed: %s (%d)\n", strerror(ret), ret); -- return ret; -+ goto done; - } - - el = ldb_msg_find_element(msg, SYSDB_MEMBEROF); - if (!el || el->num_values == 0) { -- DEBUG(SSSDBG_TRACE_INTERNAL, "Group %s has no parents\n", name); -- talloc_free(msg); -- return EOK; -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Group %s has no parents\n", -+ internal_name); -+ ret = EOK; -+ goto done; - } - - /* This group is nested. We need to invalidate all its parents, too */ - for (i=0; i < el->num_values; i++) { -- ret = sysdb_group_dn_name(tctx->sysdb, tctx, -+ ret = sysdb_group_dn_name(tctx->sysdb, tmpctx, - (const char *) el->values[i].data, -- &parent_name); -+ &parent_internal_name); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, "Malformed DN [%s]? Skipping\n", - (const char *) el->values[i].data); -- talloc_free(parent_name); -+ talloc_free(parent_internal_name); - continue; - } - -- ret = sss_mc_refresh_group(parent_name); -- talloc_free(parent_name); -+ parent_outname = sss_output_name(tmpctx, parent_internal_name, -+ tctx->local->case_preserve, 0); -+ if (parent_outname == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = sss_mc_refresh_group(parent_outname); -+ talloc_free(parent_internal_name); -+ talloc_free(parent_outname); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, -- "Cannot refresh group %s from memory cache\n", name); -+ "Cannot refresh group %s from memory cache\n", parent_outname); - /* try to carry on */ - } - } - -- talloc_free(msg); -- return EOK; -+ ret = EOK; -+ -+done: -+ talloc_free(tmpctx); -+ return ret; - } - - errno_t sss_mc_refresh_grouplist(struct tools_ctx *tctx, --- -2.7.4 - diff --git a/SOURCES/0133-cache_req-use-the-right-negative-cache-for-initgroup.patch b/SOURCES/0133-cache_req-use-the-right-negative-cache-for-initgroup.patch new file mode 100644 index 0000000..52aa5dc --- /dev/null +++ b/SOURCES/0133-cache_req-use-the-right-negative-cache-for-initgroup.patch @@ -0,0 +1,40 @@ +From 04ef28b7cc49a71209551646b3a82518506f40a6 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 22 May 2017 14:58:01 +0200 +Subject: [PATCH 133/135] cache_req: use the right negative cache for + initgroups by upn +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 870b58a6cc6b5cf92a6503c1578e5c21617c8d40) +--- + src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c +index b6fb43ee02d2f041fb3d992b375ae65a02db8b03..dfb21ac1a0090a3ef9029b38f5b1e8bdda3440c6 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c ++++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c +@@ -66,7 +66,7 @@ cache_req_initgroups_by_upn_ncache_check(struct sss_nc_ctx *ncache, + struct sss_domain_info *domain, + struct cache_req_data *data) + { +- return sss_ncache_check_user(ncache, domain, data->name.lookup); ++ return sss_ncache_check_upn(ncache, domain, data->name.lookup); + } + + static errno_t +@@ -74,7 +74,7 @@ cache_req_initgroups_by_upn_ncache_add(struct sss_nc_ctx *ncache, + struct sss_domain_info *domain, + struct cache_req_data *data) + { +- return sss_ncache_set_user(ncache, false, domain, data->name.lookup); ++ return sss_ncache_set_upn(ncache, false, domain, data->name.lookup); + } + + static errno_t +-- +2.9.3 + diff --git a/SOURCES/0134-TESTS-Add-FQDN-variants-for-some-tests.patch b/SOURCES/0134-TESTS-Add-FQDN-variants-for-some-tests.patch deleted file mode 100644 index 109d2ef..0000000 --- a/SOURCES/0134-TESTS-Add-FQDN-variants-for-some-tests.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 28db1765c40137e9452b4aa27281a1deb25d1d36 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Wed, 7 Sep 2016 15:00:12 +0200 -Subject: [PATCH 134/135] TESTS: Add FQDN variants for some tests -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Adds FQDN variants of some already existing tests. - -Reviewed-by: Lukáš Slebodník ---- - src/tests/intg/test_local_domain.py | 83 +++++++++++++++++++++++++++++++++++++ - 1 file changed, 83 insertions(+) - -diff --git a/src/tests/intg/test_local_domain.py b/src/tests/intg/test_local_domain.py -index 5e3e3d4d1cdc6db5d68a6e5b9d96d94c2c694b14..b34e4a3d31cdbc1dc257d8fffcf0f5a07803b20c 100644 ---- a/src/tests/intg/test_local_domain.py -+++ b/src/tests/intg/test_local_domain.py -@@ -87,6 +87,27 @@ def local_domain_only(request): - return None - - -+@pytest.fixture -+def local_domain_only_fqdn(request): -+ conf = unindent("""\ -+ [sssd] -+ domains = LOCAL -+ services = nss -+ -+ [nss] -+ memcache_timeout = 0 -+ -+ [domain/LOCAL] -+ id_provider = local -+ min_id = 10000 -+ max_id = 20000 -+ use_fully_qualified_names = True -+ """).format(**locals()) -+ create_conf_fixture(request, conf) -+ create_sssd_fixture(request) -+ return None -+ -+ - def assert_nonexistent_user(name): - with pytest.raises(KeyError): - pwd.getpwnam(name) -@@ -169,3 +190,65 @@ def test_add_local_group_to_local_group(local_domain_only): - "group_parent", - dict(name="group_parent", passwd="*", gid=10008, - mem=ent.contains_only("user_child"))) -+ -+ -+def test_sss_group_add_show_del_fqdn(local_domain_only_fqdn): -+ """ -+ Regression test for tickets -+ https://fedorahosted.org/sssd/ticket/3173 -+ https://fedorahosted.org/sssd/ticket/3175 -+ """ -+ -+ subprocess.check_call(["sss_groupadd", "foo@LOCAL", "-g", "10001"]) -+ -+ "This should not raise KeyError" -+ ent.assert_group_by_name("foo@LOCAL", dict(name="foo@LOCAL", gid=10001)) -+ -+ "sss_grupshow should return 0 with existing group name" -+ subprocess.check_call(["sss_groupshow", "foo@LOCAL"]) -+ -+ subprocess.check_call(["sss_groupdel", "foo@LOCAL"]) -+ assert_nonexistent_group("foo@LOCAL") -+ -+ -+def test_add_local_user_to_local_group_fqdn(local_domain_only_fqdn): -+ """ -+ Regression test for ticket -+ https://fedorahosted.org/sssd/ticket/3178 -+ """ -+ subprocess.check_call( -+ ["sss_groupadd", "-g", "10009", "group10009@LOCAL"]) -+ subprocess.check_call( -+ ["sss_useradd", "-u", "10009", "-M", "user10009@LOCAL"]) -+ subprocess.check_call( -+ ["sss_usermod", "-a", "group10009@LOCAL", "user10009@LOCAL"]) -+ -+ ent.assert_group_by_name( -+ "group10009@LOCAL", -+ dict(name="group10009@LOCAL", passwd="*", gid=10009, -+ mem=ent.contains_only("user10009@LOCAL"))) -+ -+ -+def test_add_local_group_to_local_group_fqdn(local_domain_only_fqdn): -+ """ -+ Regression test for tickets -+ https://fedorahosted.org/sssd/ticket/3178 -+ """ -+ subprocess.check_call( -+ ["sss_groupadd", "-g", "10009", "group_child@LOCAL"]) -+ subprocess.check_call( -+ ["sss_useradd", "-u", "10009", "-M", "user_child@LOCAL"]) -+ subprocess.check_call( -+ ["sss_usermod", "-a", "group_child@LOCAL", "user_child@LOCAL"]) -+ -+ subprocess.check_call( -+ ["sss_groupadd", "-g", "10008", "group_parent@LOCAL"]) -+ subprocess.check_call( -+ ["sss_groupmod", "-a", "group_parent@LOCAL", "group_child@LOCAL"]) -+ -+ # User from child_group is member of parent_group, so child_group's -+ # member must be also parent_group's member -+ ent.assert_group_by_name( -+ "group_parent@LOCAL", -+ dict(name="group_parent@LOCAL", passwd="*", gid=10008, -+ mem=ent.contains_only("user_child@LOCAL"))) --- -2.7.4 - diff --git a/SOURCES/0134-test-make-sure-p11_child-is-build-for-pam-srv-tests.patch b/SOURCES/0134-test-make-sure-p11_child-is-build-for-pam-srv-tests.patch new file mode 100644 index 0000000..5fa1c16 --- /dev/null +++ b/SOURCES/0134-test-make-sure-p11_child-is-build-for-pam-srv-tests.patch @@ -0,0 +1,31 @@ +From 9e7bb71e02af7cf8fe8b593ddc762a09183ff32c Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 22 May 2017 15:04:17 +0200 +Subject: [PATCH 134/135] test: make sure p11_child is build for pam-srv-tests +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit ec9ac22d699a17d590b1d4ba9ba3750eb719f340) +--- + Makefile.am | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/Makefile.am b/Makefile.am +index 370d6442ec58a14946ad288a23c696f25ca98f47..a6279133b56dcd5bcbd1306ae8f2ce18d90c2c12 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2356,6 +2356,9 @@ nss_srv_tests_LDADD = \ + EXTRA_pam_srv_tests_DEPENDENCIES = \ + $(ldblib_LTLIBRARIES) \ + $(NULL) ++if HAVE_NSS ++EXTRA_pam_srv_tests_DEPENDENCIES += p11_child ++endif + pam_srv_tests_SOURCES = \ + $(TEST_MOCK_RESP_OBJ) \ + src/tests/cmocka/test_pam_srv.c \ +-- +2.9.3 + diff --git a/SOURCES/0135-KRB5-Send-the-output-username-not-internal-fqname-to.patch b/SOURCES/0135-KRB5-Send-the-output-username-not-internal-fqname-to.patch deleted file mode 100644 index a3368d4..0000000 --- a/SOURCES/0135-KRB5-Send-the-output-username-not-internal-fqname-to.patch +++ /dev/null @@ -1,155 +0,0 @@ -From 0f0480dd1c227a841542d621a778e23cf637a644 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 7 Sep 2016 12:07:36 +0200 -Subject: [PATCH 135/135] KRB5: Send the output username, not internal fqname - to krb5_child -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -krb5_child calls krb5_kuserok() during the access phase which checks if -a particular user is allowed to authenticate as a particular principal. -We used to pass the internal fqname to krb5_kuserok() which broke the -functionality and all users were denied access. - -This patch changes that to send the 'output' username to krb5_child, -because that's the username the system receives through getpwnam() or -getpwuid() anyway. The patch also adds a new structure member fo the -krb5child_req structure to avoid reusing the pd->user variable but have -an explicit one that serves as the input for the child process. - -Resolves: -https://fedorahosted.org/sssd/ticket/3172 - -Reviewed-by: Lukáš Slebodník ---- - src/providers/krb5/krb5_access.c | 10 ++++++++-- - src/providers/krb5/krb5_auth.c | 18 ++++++++++++++---- - src/providers/krb5/krb5_auth.h | 9 ++++++--- - src/providers/krb5/krb5_child_handler.c | 4 ++-- - 4 files changed, 30 insertions(+), 11 deletions(-) - -diff --git a/src/providers/krb5/krb5_access.c b/src/providers/krb5/krb5_access.c -index 3afb90150d77ef4ab2c1b5b79abb95d68eb131f6..be9068c0f9180f8de0de259aae368534effaf7fb 100644 ---- a/src/providers/krb5/krb5_access.c -+++ b/src/providers/krb5/krb5_access.c -@@ -51,6 +51,7 @@ struct tevent_req *krb5_access_send(TALLOC_CTX *mem_ctx, - int ret; - const char **attrs; - struct ldb_result *res; -+ struct sss_domain_info *dom; - - req = tevent_req_create(mem_ctx, &state, struct krb5_access_state); - if (req == NULL) { -@@ -64,8 +65,13 @@ struct tevent_req *krb5_access_send(TALLOC_CTX *mem_ctx, - state->krb5_ctx = krb5_ctx; - state->access_allowed = false; - -- ret = krb5_setup(state, pd, krb5_ctx, be_ctx->domain->case_sensitive, -- &state->kr); -+ ret = get_domain_or_subdomain(be_ctx, pd->domain, &dom); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "get_domain_or_subdomain failed.\n"); -+ goto done; -+ } -+ -+ ret = krb5_setup(state, pd, dom, krb5_ctx, &state->kr); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "krb5_setup failed.\n"); - goto done; -diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c -index dabf55cf24a8afda16fee6697120c7c6f088b796..f0f2280022a3ee951ccfa0040b616c48c3b25706 100644 ---- a/src/providers/krb5/krb5_auth.c -+++ b/src/providers/krb5/krb5_auth.c -@@ -174,8 +174,10 @@ done: - return ret; - } - --errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd, -- struct krb5_ctx *krb5_ctx, bool cs, -+errno_t krb5_setup(TALLOC_CTX *mem_ctx, -+ struct pam_data *pd, -+ struct sss_domain_info *dom, -+ struct krb5_ctx *krb5_ctx, - struct krb5child_req **_krb5_req) - { - struct krb5child_req *kr; -@@ -201,13 +203,21 @@ errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd, - kr->krb5_ctx = krb5_ctx; - - ret = get_krb_primary(krb5_ctx->name_to_primary, -- pd->user, cs, &mapped_name); -+ pd->user, dom->case_sensitive, &mapped_name); - if (ret == EOK) { - DEBUG(SSSDBG_TRACE_FUNC, "Setting mapped name to: %s\n", mapped_name); - kr->user = mapped_name; -+ kr->kuserok_user = mapped_name; - } else if (ret == ENOENT) { - DEBUG(SSSDBG_TRACE_ALL, "No mapping for: %s\n", pd->user); - kr->user = pd->user; -+ -+ kr->kuserok_user = sss_output_name(kr, kr->user, -+ dom->case_sensitive, 0); -+ if (kr->kuserok_user == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } - } else { - DEBUG(SSSDBG_CRIT_FAILURE, "get_krb_primary failed - %s:[%d]\n", - sss_strerror(ret), ret); -@@ -534,7 +544,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, - attrs[6] = SYSDB_AUTH_TYPE; - attrs[7] = NULL; - -- ret = krb5_setup(state, pd, krb5_ctx, state->domain->case_sensitive, -+ ret = krb5_setup(state, pd, state->domain, krb5_ctx, - &state->kr); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "krb5_setup failed.\n"); -diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h -index dbad061f0203b6383daeeab506bf9950d892ea4b..11bb595833269177b7e2c5fc6372d6a6fb6d93d2 100644 ---- a/src/providers/krb5/krb5_auth.h -+++ b/src/providers/krb5/krb5_auth.h -@@ -57,11 +57,14 @@ struct krb5child_req { - bool send_pac; - - const char *user; -+ const char *kuserok_user; - }; - --errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd, -- struct krb5_ctx *krb5_ctx, bool case_sensitive, -- struct krb5child_req **krb5_req); -+errno_t krb5_setup(TALLOC_CTX *mem_ctx, -+ struct pam_data *pd, -+ struct sss_domain_info *dom, -+ struct krb5_ctx *krb5_ctx, -+ struct krb5child_req **_krb5_req); - - struct tevent_req * - krb5_pam_handler_send(TALLOC_CTX *mem_ctx, -diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c -index 09a1e5f59494a5c07d5c9eefb94919ca9389cb27..1eec7261f00976b3725fee9323755edecd5409a5 100644 ---- a/src/providers/krb5/krb5_child_handler.c -+++ b/src/providers/krb5/krb5_child_handler.c -@@ -161,7 +161,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, - } - - if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { -- username_len = strlen(kr->pd->user); -+ username_len = strlen(kr->kuserok_user); - buf->size += sizeof(uint32_t) + username_len; - } - -@@ -217,7 +217,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, - - if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) { - SAFEALIGN_SET_UINT32(&buf->data[rp], username_len, &rp); -- safealign_memcpy(&buf->data[rp], kr->pd->user, username_len, &rp); -+ safealign_memcpy(&buf->data[rp], kr->kuserok_user, username_len, &rp); - } - - *io_buf = buf; --- -2.7.4 - diff --git a/SOURCES/0135-pam-properly-support-UPN-logon-names.patch b/SOURCES/0135-pam-properly-support-UPN-logon-names.patch new file mode 100644 index 0000000..54d6529 --- /dev/null +++ b/SOURCES/0135-pam-properly-support-UPN-logon-names.patch @@ -0,0 +1,163 @@ +From b6ba8bc43a0b5a448e4cd30bc406bd08c389e365 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 12 May 2017 10:40:21 +0200 +Subject: [PATCH 135/135] pam: properly support UPN logon names +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Many logon applications like /bin/login or sshd canonicalize the user +name before they call pam_start() and hence the UPN is not seen by +SSSD's pam responder. But some like e.g. gdm don't and authentication +might fail if a UPN is used. + +The reason is that currently the already parsed short name of the user +was used in the cache_req and hence the cache_req was not able to fall +back to the UPN lookup code. This patch uses the name originally +provided by the user as input to allow the fallback to the UPN lookup. + +Resolves https://pagure.io/SSSD/sssd/issue/3240 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 29d063505c07127f7747405b1a61d8f782673645) +--- + src/responder/pam/pamsrv_cmd.c | 4 +-- + src/tests/cmocka/test_pam_srv.c | 79 ++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 80 insertions(+), 3 deletions(-) + +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index 10a178f839ec011c09a6da4575efbb026f3f7700..36dba37964b71153435b4df5d5328de4361926e6 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1560,7 +1560,7 @@ static int pam_check_user_search(struct pam_auth_req *preq) + + data = cache_req_data_name(preq, + CACHE_REQ_INITGROUPS, +- preq->pd->user); ++ preq->pd->logon_name); + if (data == NULL) { + return ENOMEM; + } +@@ -1589,7 +1589,7 @@ static int pam_check_user_search(struct pam_auth_req *preq) + preq->cctx->rctx->ncache, + 0, + preq->req_dom_type, +- preq->pd->domain, ++ NULL, + data); + if (!dpreq) { + DEBUG(SSSDBG_CRIT_FAILURE, +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index d249b8f1ea48f1c17b461c3add9e8c63774e5f88..4d351a3707d2a49604595b728fff7705560c871a 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -518,6 +518,8 @@ static void mock_input_pam_ex(TALLOC_CTX *mem_ctx, + int ret; + size_t needed_size; + uint8_t *authtok; ++ char *s_name; ++ char *dom; + + if (name != NULL) { + pi.pam_user = name; +@@ -574,7 +576,13 @@ static void mock_input_pam_ex(TALLOC_CTX *mem_ctx, + will_return(__wrap_sss_packet_get_body, buf); + will_return(__wrap_sss_packet_get_body, buf_size); + +- mock_parse_inp(name, NULL, EOK); ++ if (strrchr(name, '@') == NULL) { ++ mock_parse_inp(name, NULL, EOK); ++ } else { ++ ret = sss_parse_internal_fqname(mem_ctx, name, &s_name, &dom); ++ mock_parse_inp(s_name, dom, EOK); ++ } ++ + if (contact_dp) { + mock_account_recv_simple(); + } +@@ -1582,6 +1590,71 @@ void test_pam_preauth_no_logon_name(void **state) + assert_int_equal(ret, EOK); + } + ++void test_pam_auth_no_upn_logon_name(void **state) ++{ ++ int ret; ++ ++ ret = sysdb_cache_password(pam_test_ctx->tctx->dom, ++ pam_test_ctx->pam_user_fqdn, ++ "12345"); ++ assert_int_equal(ret, EOK); ++ ++ mock_input_pam_ex(pam_test_ctx, "upn@"TEST_DOM_NAME, "12345", NULL, NULL, ++ true); ++ mock_account_recv_simple(); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ pam_test_ctx->exp_pam_status = PAM_USER_UNKNOWN; ++ set_cmd_cb(test_pam_simple_check); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_pam_auth_upn_logon_name(void **state) ++{ ++ int ret; ++ struct sysdb_attrs *attrs; ++ ++ ret = sysdb_cache_password(pam_test_ctx->tctx->dom, ++ pam_test_ctx->pam_user_fqdn, ++ "12345"); ++ assert_int_equal(ret, EOK); ++ attrs = sysdb_new_attrs(pam_test_ctx); ++ assert_non_null(attrs); ++ ret = sysdb_attrs_add_string(attrs, SYSDB_UPN, "upn@"TEST_DOM_NAME); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_set_user_attr(pam_test_ctx->tctx->dom, ++ pam_test_ctx->pam_user_fqdn, ++ attrs, ++ LDB_FLAG_MOD_ADD); ++ assert_int_equal(ret, EOK); ++ ++ mock_input_pam_ex(pam_test_ctx, "upn@"TEST_DOM_NAME, "12345", NULL, NULL, ++ true); ++ mock_account_recv_simple(); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ set_cmd_cb(test_pam_successful_offline_auth_check); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++ + static void set_cert_auth_param(struct pam_ctx *pctx, const char *dbpath) + { + pam_test_ctx->pctx->cert_auth = true; +@@ -2312,6 +2385,10 @@ int main(int argc, const char *argv[]) + pam_test_setup, pam_test_teardown), + cmocka_unit_test_setup_teardown(test_pam_preauth_no_logon_name, + pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_pam_auth_no_upn_logon_name, ++ pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_pam_auth_upn_logon_name, ++ pam_test_setup, pam_test_teardown), + cmocka_unit_test_setup_teardown(test_pam_cached_auth_success, + pam_cached_test_setup, + pam_test_teardown), +-- +2.9.3 + diff --git a/SOURCES/0136-KCM-Fix-the-per-client-serialization-queue.patch b/SOURCES/0136-KCM-Fix-the-per-client-serialization-queue.patch new file mode 100644 index 0000000..3cf4420 --- /dev/null +++ b/SOURCES/0136-KCM-Fix-the-per-client-serialization-queue.patch @@ -0,0 +1,334 @@ +From b31f75f44a9e1dc0521ec73176f89e05db4973ba Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Thu, 11 May 2017 16:24:24 +0200 +Subject: [PATCH 136/138] KCM: Fix the per-client serialization queue +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves: + https://pagure.io/SSSD/sssd/issue/3372 + +Fixes a race condition between one client request adding an operation to +the hash table value, which was previously a linked list of operations, +while another concurrent operation would remove the last remaining +linked list element through its callback. + +Instead, the hash table value is now a separate 'queue head' structure +which is only changed in a tevent request to make sure is is not +processes concurrently with adding to the queue (which is also a tevent +request). + +Reviewed-by: Pavel Březina +(cherry picked from commit fb51bb68e62de7bb8542f5d224994eb7143040a6) +--- + src/responder/kcm/kcmsrv_op_queue.c | 182 ++++++++++++++++++++++++------------ + 1 file changed, 122 insertions(+), 60 deletions(-) + +diff --git a/src/responder/kcm/kcmsrv_op_queue.c b/src/responder/kcm/kcmsrv_op_queue.c +index f6c425dd5b64877c8b7401e488dd6565157fc9b5..55c8b65d94f70979fe56fcc4d8747547a9cc9d33 100644 +--- a/src/responder/kcm/kcmsrv_op_queue.c ++++ b/src/responder/kcm/kcmsrv_op_queue.c +@@ -27,17 +27,23 @@ + + struct kcm_ops_queue_entry { + struct tevent_req *req; +- uid_t uid; + +- hash_table_t *wait_queue_hash; ++ struct kcm_ops_queue *queue; + +- struct kcm_ops_queue_entry *head; + struct kcm_ops_queue_entry *next; + struct kcm_ops_queue_entry *prev; + }; + ++struct kcm_ops_queue { ++ uid_t uid; ++ struct tevent_context *ev; ++ struct kcm_ops_queue_ctx *qctx; ++ ++ struct kcm_ops_queue_entry *head; ++}; ++ + struct kcm_ops_queue_ctx { +- /* UID: dlist of kcm_ops_queue_entry */ ++ /* UID:kcm_ops_queue */ + hash_table_t *wait_queue_hash; + }; + +@@ -45,8 +51,9 @@ struct kcm_ops_queue_ctx { + * Per-UID wait queue + * + * They key in the hash table is the UID of the peer. The value of each +- * hash table entry is a linked list of kcm_ops_queue_entry structures +- * which primarily hold the tevent request being queued. ++ * hash table entry is kcm_ops_queue structure which in turn contains a ++ * linked list of kcm_ops_queue_entry structures * which primarily hold the ++ * tevent request being queued. + */ + struct kcm_ops_queue_ctx *kcm_ops_queue_create(TALLOC_CTX *mem_ctx) + { +@@ -71,11 +78,45 @@ struct kcm_ops_queue_ctx *kcm_ops_queue_create(TALLOC_CTX *mem_ctx) + return queue_ctx; + } + +-static int kcm_op_queue_entry_destructor(struct kcm_ops_queue_entry *entry) ++void queue_removal_cb(struct tevent_context *ctx, ++ struct tevent_immediate *imm, ++ void *private_data) + { ++ struct kcm_ops_queue *kq = talloc_get_type(private_data, ++ struct kcm_ops_queue); + int ret; ++ hash_key_t key; ++ ++ talloc_free(imm); ++ ++ if (kq->head != NULL) { ++ DEBUG(SSSDBG_TRACE_LIBS, "The queue is no longer empty\n"); ++ return; ++ } ++ ++ key.type = HASH_KEY_ULONG; ++ key.ul = kq->uid; ++ ++ /* If this was the last entry, remove the key (the UID) from the ++ * hash table to signal the queue is empty ++ */ ++ ret = hash_delete(kq->qctx->wait_queue_hash, &key); ++ if (ret != HASH_SUCCESS) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to remove wait queue for user %"SPRIuid"\n", ++ kq->uid); ++ return; ++ } ++ ++ DEBUG(SSSDBG_FUNC_DATA, ++ "Removed queue for %"SPRIuid" \n", kq->uid); ++ talloc_free(kq); ++} ++ ++static int kcm_op_queue_entry_destructor(struct kcm_ops_queue_entry *entry) ++{ + struct kcm_ops_queue_entry *next_entry; +- hash_key_t key; ++ struct tevent_immediate *imm; + + if (entry == NULL) { + return 1; +@@ -85,22 +126,19 @@ static int kcm_op_queue_entry_destructor(struct kcm_ops_queue_entry *entry) + next_entry = entry->next; + + /* Remove the current entry from the queue */ +- DLIST_REMOVE(entry->head, entry); ++ DLIST_REMOVE(entry->queue->head, entry); + + if (next_entry == NULL) { +- key.type = HASH_KEY_ULONG; +- key.ul = entry->uid; +- +- /* If this was the last entry, remove the key (the UID) from the +- * hash table to signal the queue is empty ++ /* If there was no other entry, schedule removal of the queue. Do it ++ * in another tevent tick to avoid issues with callbacks invoking ++ * the descructor while another request is touching the queue + */ +- ret = hash_delete(entry->wait_queue_hash, &key); +- if (ret != HASH_SUCCESS) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to remove wait queue for user %"SPRIuid"\n", +- entry->uid); ++ imm = tevent_create_immediate(entry->queue); ++ if (imm == NULL) { + return 1; + } ++ ++ tevent_schedule_immediate(imm, entry->queue->ev, queue_removal_cb, entry->queue); + return 0; + } + +@@ -109,41 +147,33 @@ static int kcm_op_queue_entry_destructor(struct kcm_ops_queue_entry *entry) + return 0; + } + +-static errno_t kcm_op_queue_add(hash_table_t *wait_queue_hash, +- struct kcm_ops_queue_entry *entry, +- uid_t uid) ++static struct kcm_ops_queue *kcm_op_queue_get(struct kcm_ops_queue_ctx *qctx, ++ struct tevent_context *ev, ++ uid_t uid) + { + errno_t ret; + hash_key_t key; + hash_value_t value; +- struct kcm_ops_queue_entry *head = NULL; ++ struct kcm_ops_queue *kq; + + key.type = HASH_KEY_ULONG; + key.ul = uid; + +- ret = hash_lookup(wait_queue_hash, &key, &value); ++ ret = hash_lookup(qctx->wait_queue_hash, &key, &value); + switch (ret) { + case HASH_SUCCESS: +- /* The key with this UID already exists. Its value is request queue +- * for the UID, so let's just add the current request to the end +- * of the queue and wait for the previous requests to finish +- */ + if (value.type != HASH_VALUE_PTR) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected hash value type.\n"); +- return EINVAL; ++ return NULL; + } + +- head = talloc_get_type(value.ptr, struct kcm_ops_queue_entry); +- if (head == NULL) { ++ kq = talloc_get_type(value.ptr, struct kcm_ops_queue); ++ if (kq == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid queue pointer\n"); +- return EINVAL; ++ return NULL; + } + +- entry->head = head; +- DLIST_ADD_END(head, entry, struct kcm_ops_queue_entry *); +- +- DEBUG(SSSDBG_TRACE_LIBS, "Waiting in queue\n"); +- ret = EAGAIN; ++ DEBUG(SSSDBG_TRACE_LIBS, "Found existing queue for this ID\n"); + break; + + case HASH_ERROR_KEY_NOT_FOUND: +@@ -151,36 +181,41 @@ static errno_t kcm_op_queue_add(hash_table_t *wait_queue_hash, + * another one comes in and return EOK to run the current request + * immediatelly + */ +- entry->head = entry; ++ DEBUG(SSSDBG_TRACE_LIBS, "No existing queue for this ID\n"); ++ ++ kq = talloc_zero(qctx->wait_queue_hash, struct kcm_ops_queue); ++ if (kq == NULL) { ++ return NULL; ++ } ++ kq->uid = uid; ++ kq->qctx = qctx; ++ kq->ev = ev; + + value.type = HASH_VALUE_PTR; +- value.ptr = entry; ++ value.ptr = kq; + +- ret = hash_enter(wait_queue_hash, &key, &value); ++ ret = hash_enter(qctx->wait_queue_hash, &key, &value); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, "hash_enter failed.\n"); +- return EIO; ++ return NULL; + } +- +- DEBUG(SSSDBG_TRACE_LIBS, +- "Added a first request to the queue, running immediately\n"); +- ret = EOK; + break; + + default: + DEBUG(SSSDBG_CRIT_FAILURE, "hash_lookup failed.\n"); +- return EIO; ++ return NULL; + } + +- talloc_steal(wait_queue_hash, entry); +- talloc_set_destructor(entry, kcm_op_queue_entry_destructor); +- return ret; ++ return kq; + } + + struct kcm_op_queue_state { + struct kcm_ops_queue_entry *entry; + }; + ++static errno_t kcm_op_queue_add_req(struct kcm_ops_queue *kq, ++ struct tevent_req *req); ++ + /* + * Enqueue a request. + * +@@ -198,6 +233,7 @@ struct tevent_req *kcm_op_queue_send(TALLOC_CTX *mem_ctx, + { + errno_t ret; + struct tevent_req *req; ++ struct kcm_ops_queue *kq; + struct kcm_op_queue_state *state; + uid_t uid; + +@@ -208,22 +244,21 @@ struct tevent_req *kcm_op_queue_send(TALLOC_CTX *mem_ctx, + return NULL; + } + +- state->entry = talloc_zero(state, struct kcm_ops_queue_entry); +- if (state->entry == NULL) { +- ret = ENOMEM; +- goto immediate; +- } +- state->entry->req = req; +- state->entry->uid = uid; +- state->entry->wait_queue_hash = qctx->wait_queue_hash; +- + DEBUG(SSSDBG_FUNC_DATA, + "Adding request by %"SPRIuid" to the wait queue\n", uid); + +- ret = kcm_op_queue_add(qctx->wait_queue_hash, state->entry, uid); ++ kq = kcm_op_queue_get(qctx, ev, uid); ++ if (kq == NULL) { ++ ret = EIO; ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get queue [%d]: %s\n", ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ ret = kcm_op_queue_add_req(kq, req); + if (ret == EOK) { + DEBUG(SSSDBG_TRACE_LIBS, +- "Wait queue was empty, running immediately\n"); ++ "Queue was empty, running the request immediately\n"); + goto immediate; + } else if (ret != EAGAIN) { + DEBUG(SSSDBG_OP_FAILURE, +@@ -244,6 +279,33 @@ immediate: + return req; + } + ++static errno_t kcm_op_queue_add_req(struct kcm_ops_queue *kq, ++ struct tevent_req *req) ++{ ++ errno_t ret; ++ struct kcm_op_queue_state *state = tevent_req_data(req, ++ struct kcm_op_queue_state); ++ ++ state->entry = talloc_zero(kq->qctx->wait_queue_hash, struct kcm_ops_queue_entry); ++ if (state->entry == NULL) { ++ return ENOMEM; ++ } ++ state->entry->req = req; ++ state->entry->queue = kq; ++ talloc_set_destructor(state->entry, kcm_op_queue_entry_destructor); ++ ++ if (kq->head == NULL) { ++ /* First entry, will run callback at once */ ++ ret = EOK; ++ } else { ++ /* Will wait for the previous callbacks to finish */ ++ ret = EAGAIN; ++ } ++ ++ DLIST_ADD_END(kq->head, state->entry, struct kcm_ops_queue_entry *); ++ return ret; ++} ++ + /* + * The queue recv function is called when this request is 'activated'. The queue + * entry should be allocated on the same memory context as the enqueued request +-- +2.9.4 + diff --git a/SOURCES/0136-LDAP-Return-partial-results-from-adminlimit-exceeded.patch b/SOURCES/0136-LDAP-Return-partial-results-from-adminlimit-exceeded.patch deleted file mode 100644 index 806432b..0000000 --- a/SOURCES/0136-LDAP-Return-partial-results-from-adminlimit-exceeded.patch +++ /dev/null @@ -1,42 +0,0 @@ -From abbbcb79ff0c5b82d7a3acb324c3d44f87479837 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Mon, 12 Sep 2016 17:36:09 +0200 -Subject: [PATCH 136/140] LDAP: Return partial results from adminlimit exceeded -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: - https://fedorahosted.org/sssd/ticket/3185 - -Since commit c420ce830ac0b0b288a2a887ec2cfce5c748018c we try to move to -the next server on any error on the connection, which in case there is -only one server sends SSSD offline. - -It's more graceful to try to process the results, same as we already do -with sizelimit exceeded. - -Reviewed-by: Michal Židek -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 3319d964721396c07daba383ded6aaaf33ed6e3b) ---- - src/providers/ldap/sdap_async.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c -index 4195ba95d911f3956f8cca665310b4b92091e6cd..b8e04b9d8464d7c2c681080cba456c34b93b923a 100644 ---- a/src/providers/ldap/sdap_async.c -+++ b/src/providers/ldap/sdap_async.c -@@ -1526,7 +1526,8 @@ static void sdap_get_generic_op_finished(struct sdap_op *op, - sss_ldap_err2string(result), result, - errmsg ? errmsg : "no errmsg set"); - -- if (result == LDAP_SIZELIMIT_EXCEEDED) { -+ if (result == LDAP_SIZELIMIT_EXCEEDED -+ || result == LDAP_ADMINLIMIT_EXCEEDED) { - /* Try to return what we've got */ - - if ( ! (state->flags & SDAP_SRCH_FLG_SIZELIMIT_SILENT)) { --- -2.7.4 - diff --git a/SOURCES/0137-TESTS-Add-a-test-for-parallel-execution-of-klist.patch b/SOURCES/0137-TESTS-Add-a-test-for-parallel-execution-of-klist.patch new file mode 100644 index 0000000..25a3528 --- /dev/null +++ b/SOURCES/0137-TESTS-Add-a-test-for-parallel-execution-of-klist.patch @@ -0,0 +1,79 @@ +From 7930ee12093eae1e1ab9422c4f4f9f8c5661fcb9 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 23 May 2017 13:55:01 +0200 +Subject: [PATCH 137/138] TESTS: Add a test for parallel execution of klist +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Integration test for: + https://pagure.io/SSSD/sssd/issue/3372 + +With https://pagure.io/SSSD/sssd/issue/3372 still broken, the unit test +wold fail because one of the concurrent klist commands would trigger a +race condition in the KCM queue code, crashing the KCM responder. + +Reviewed-by: Pavel Březina +(cherry picked from commit 274489b092bba5fc81cb0f803843d56b267c5aaf) +--- + src/tests/intg/krb5utils.py | 6 +++++- + src/tests/intg/test_kcm.py | 22 ++++++++++++++++++++++ + 2 files changed, 27 insertions(+), 1 deletion(-) + +diff --git a/src/tests/intg/krb5utils.py b/src/tests/intg/krb5utils.py +index 775cffd0bbfa011f2d8ffc1169dccfef96d78fab..0349ff3829533088fb2263f84b19574127d6e809 100644 +--- a/src/tests/intg/krb5utils.py ++++ b/src/tests/intg/krb5utils.py +@@ -36,7 +36,7 @@ class Krb5Utils(object): + def __init__(self, krb5_conf_path): + self.krb5_conf_path = krb5_conf_path + +- def _run_in_env(self, args, stdin=None, extra_env=None): ++ def spawn_in_env(self, args, stdin=None, extra_env=None): + my_env = os.environ + my_env['KRB5_CONFIG'] = self.krb5_conf_path + +@@ -50,6 +50,10 @@ class Krb5Utils(object): + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) ++ return cmd ++ ++ def _run_in_env(self, args, stdin=None, extra_env=None): ++ cmd = self.spawn_in_env(args, stdin, extra_env) + out, err = cmd.communicate(stdin) + return cmd.returncode, out.decode('utf-8'), err.decode('utf-8') + +diff --git a/src/tests/intg/test_kcm.py b/src/tests/intg/test_kcm.py +index 11f80a1803b4ad9b8e8857bf9a8a244d4816f0a2..1ab2a1837687a6c2cf8676124b42538833550c91 100644 +--- a/src/tests/intg/test_kcm.py ++++ b/src/tests/intg/test_kcm.py +@@ -445,3 +445,25 @@ def test_kcm_sec_kdestroy_nocache(setup_for_kcm_sec, + setup_secrets): + testenv = setup_for_kcm_sec + exercise_subsidiaries(testenv) ++ ++def test_kcm_sec_parallel_klist(setup_for_kcm_sec, ++ setup_secrets): ++ """ ++ Test that parallel operations from a single UID are handled well. ++ Regression test for https://pagure.io/SSSD/sssd/issue/3372 ++ """ ++ testenv = setup_for_kcm_sec ++ ++ testenv.k5kdc.add_principal("alice", "alicepw") ++ out, _, _ = testenv.k5util.kinit("alice", "alicepw") ++ assert out == 0 ++ ++ ++ processes = [] ++ for i in range(0,10): ++ p = testenv.k5util.spawn_in_env(['klist', '-A']) ++ processes.append(p) ++ ++ for p in processes: ++ rc = p.wait() ++ assert rc == 0 +-- +2.9.4 + diff --git a/SOURCES/0137-TOOLS-sss_groupshow-fails-to-show-MPG.patch b/SOURCES/0137-TOOLS-sss_groupshow-fails-to-show-MPG.patch deleted file mode 100644 index 285ef6e..0000000 --- a/SOURCES/0137-TOOLS-sss_groupshow-fails-to-show-MPG.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 8125ddd951a9e66fb3b11e16489e003d32ce4890 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Mon, 12 Sep 2016 19:22:56 +0200 -Subject: [PATCH 137/140] TOOLS: sss_groupshow fails to show MPG -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The MPG search uses it's own search function -that used sysdb operation with shortname, -but it expects internal fqname. - -Resolves: -https://fedorahosted.org/sssd/ticket/3184 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 812bed08943df8bf3fd1ff9eabcaf5bedc635c92) ---- - src/tools/sss_groupshow.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/src/tools/sss_groupshow.c b/src/tools/sss_groupshow.c -index 5870cc802c70366c47a0d30cb0d9795cf6035bc5..00f6f12939b6bef2dd10085f8cf99304e87f1211 100644 ---- a/src/tools/sss_groupshow.c -+++ b/src/tools/sss_groupshow.c -@@ -553,13 +553,14 @@ int group_show_recurse(TALLOC_CTX *mem_ctx, - - static int group_show_mpg(TALLOC_CTX *mem_ctx, - struct sss_domain_info *domain, -- const char *name, -+ const char *shortname, - struct group_info **res) - { - const char *attrs[] = GROUP_SHOW_MPG_ATTRS; - struct ldb_message *msg; - struct group_info *info; - int ret; -+ char *sysdb_fqname; - - info = talloc_zero(mem_ctx, struct group_info); - if (!info) { -@@ -567,7 +568,14 @@ static int group_show_mpg(TALLOC_CTX *mem_ctx, - goto fail; - } - -- ret = sysdb_search_user_by_name(info, domain, name, attrs, &msg); -+ sysdb_fqname = sss_create_internal_fqname(mem_ctx, -+ shortname, -+ domain->name); -+ if (sysdb_fqname == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = sysdb_search_user_by_name(info, domain, sysdb_fqname, attrs, &msg); - if (ret) { - DEBUG(SSSDBG_OP_FAILURE, - "Search failed: %s (%d)\n", strerror(ret), ret); --- -2.7.4 - diff --git a/SOURCES/0138-TESTS-sss_groupshow-with-MPG.patch b/SOURCES/0138-TESTS-sss_groupshow-with-MPG.patch deleted file mode 100644 index e273877..0000000 --- a/SOURCES/0138-TESTS-sss_groupshow-with-MPG.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 6eb330b5370db40a55d18de2d932601d6b3128b2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Mon, 12 Sep 2016 19:25:13 +0200 -Subject: [PATCH 138/140] TESTS: sss_groupshow with MPG -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Regression test for ticket #3184 - -Resolves: -https://fedorahosted.org/sssd/ticket/3184 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit bb14556c1df503314644fc424fbbf95759791db9) ---- - src/tests/intg/test_local_domain.py | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/src/tests/intg/test_local_domain.py b/src/tests/intg/test_local_domain.py -index b34e4a3d31cdbc1dc257d8fffcf0f5a07803b20c..8e1d6fb2b69f5e6e033ae06d4bd52cc88e54872b 100644 ---- a/src/tests/intg/test_local_domain.py -+++ b/src/tests/intg/test_local_domain.py -@@ -118,6 +118,28 @@ def assert_nonexistent_group(name): - grp.getgrnam(name) - - -+def test_groupshow_mpg(local_domain_only): -+ """ -+ Regression test for ticket -+ https://fedorahosted.org/sssd/ticket/3184 -+ """ -+ subprocess.check_call(["sss_useradd", "foo", "-M"]) -+ -+ # The user's mpg has to be found (should return 0) -+ subprocess.check_call(["sss_groupshow", "foo"]) -+ -+ -+def test_groupshow_mpg_fqdn(local_domain_only_fqdn): -+ """ -+ Regression test for ticket (fq variant) -+ https://fedorahosted.org/sssd/ticket/3184 -+ """ -+ subprocess.check_call(["sss_useradd", "foo@LOCAL", "-M"]) -+ -+ # The user's mpg has to be found (should return 0) -+ subprocess.check_call(["sss_groupshow", "foo@LOCAL"]) -+ -+ - def test_wrong_LC_ALL(local_domain_only): - """ - Regression test for ticket --- -2.7.4 - diff --git a/SOURCES/0138-ipa-filter-IPA-users-from-extdom-lookups-by-certific.patch b/SOURCES/0138-ipa-filter-IPA-users-from-extdom-lookups-by-certific.patch new file mode 100644 index 0000000..f9689ea --- /dev/null +++ b/SOURCES/0138-ipa-filter-IPA-users-from-extdom-lookups-by-certific.patch @@ -0,0 +1,115 @@ +From e3b29c9f95d5a5ff007000b254143c337ef0b0dc Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 19 May 2017 12:52:47 +0200 +Subject: [PATCH 138/138] ipa: filter IPA users from extdom lookups by + certificate +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The extdom lookup by certificate will return the names of all matching +users, both from the IPA and trusted domains. The IPA users from the +list should not be looked up via the extdom plugin because they are +already lookup up directly. Additionally the lookup might fail and cause +an error which might prevent that the remaining users from the list are +looked up. + +Resolves https://pagure.io/SSSD/sssd/issue/3407 + +Reviewed-by: Pavel Březina +(cherry picked from commit eb7095099b2dd0afb1d028dbc15d8c5a897d90f8) +--- + src/providers/ipa/ipa_s2n_exop.c | 35 ++++++++++++++++++++++++++++++----- + 1 file changed, 30 insertions(+), 5 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index f5f4401f86615dc7f81f844e1096ad43e965c384..15904e0197919c34b1bce58b4bd2c070f99b67a7 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -792,6 +792,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, + char **name_list = NULL; + ber_len_t ber_len; + char *fq_name = NULL; ++ struct sss_domain_info *root_domain = NULL; + + if (retoid == NULL || retdata == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Missing OID or data.\n"); +@@ -965,6 +966,8 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, + goto done; + } + ++ root_domain = get_domains_head(dom); ++ + while (ber_peek_tag(ber, &ber_len) == LBER_SEQUENCE) { + tag = ber_scanf(ber, "{aa}", &domain_name, &name); + if (tag == LBER_ERROR) { +@@ -983,7 +986,12 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, + DEBUG(SSSDBG_TRACE_ALL, "[%s][%s][%s].\n", domain_name, name, + fq_name); + +- ret = add_string_to_list(attrs, fq_name, &name_list); ++ if (strcasecmp(root_domain->name, domain_name) != 0) { ++ ret = add_string_to_list(attrs, fq_name, &name_list); ++ } else { ++ DEBUG(SSSDBG_TRACE_ALL, ++ "[%s] from root domain, skipping.\n", fq_name); ++ } + ber_memfree(domain_name); + ber_memfree(name); + talloc_free(fq_name); +@@ -1228,7 +1236,7 @@ static errno_t ipa_s2n_get_list_step(struct tevent_req *req) + + break; + default: +- DEBUG(SSSDBG_OP_FAILURE, "Unexpected inoput type [%d].\n", ++ DEBUG(SSSDBG_OP_FAILURE, "Unexpected input type [%d].\n", + state->req_input.type); + return EINVAL; + } +@@ -1247,9 +1255,10 @@ static errno_t ipa_s2n_get_list_step(struct tevent_req *req) + + if (state->req_input.type == REQ_INP_NAME + && state->req_input.inp.name != NULL) { +- DEBUG(SSSDBG_TRACE_FUNC, "Sending request_type: [%s] for group [%s].\n", +- ipa_s2n_reqtype2str(state->request_type), +- state->list[state->list_idx]); ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Sending request_type: [%s] for object [%s].\n", ++ ipa_s2n_reqtype2str(state->request_type), ++ state->list[state->list_idx]); + } + + subreq = ipa_s2n_exop_send(state, state->ev, state->sh, need_v1, +@@ -1886,6 +1895,13 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + + if (state->simple_attrs->response_type == RESP_NAME_LIST + && state->req_input->type == REQ_INP_CERT) { ++ ++ if (state->simple_attrs->name_list == NULL) { ++ /* No results from sub-domains, nothing to do */ ++ ret = EOK; ++ goto done; ++ } ++ + state->mapped_attrs = sysdb_new_attrs(state); + if (state->mapped_attrs == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); +@@ -2640,6 +2656,15 @@ static void ipa_s2n_get_list_done(struct tevent_req *subreq) + return; + } + ++ if (state->attrs == NULL) { ++ /* If this is a request by certificate we are done */ ++ if (state->req_input->type == REQ_INP_CERT) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, EINVAL); ++ } ++ } ++ + ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR, + &sid_str); + if (ret == ENOENT) { +-- +2.9.4 + diff --git a/SOURCES/0139-TOOLS-sss_override-without-name-override.patch b/SOURCES/0139-TOOLS-sss_override-without-name-override.patch deleted file mode 100644 index b9114ef..0000000 --- a/SOURCES/0139-TOOLS-sss_override-without-name-override.patch +++ /dev/null @@ -1,67 +0,0 @@ -From e56e1396bab69d9498f4ec6a36e9e228ded90116 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Wed, 7 Sep 2016 17:09:53 +0200 -Subject: [PATCH 139/140] TOOLS: sss_override without name override -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -sss_override failed to export user/group overrides -if user had no overrides for name. - -Resolves: -https://fedorahosted.org/sssd/ticket/3179 - -Reviewed-by: Pavel Březina -(cherry picked from commit 07e7683f5a86991feaa764e2055116554ada1b93) ---- - src/tools/sss_override.c | 24 ++++++++++++++---------- - 1 file changed, 14 insertions(+), 10 deletions(-) - -diff --git a/src/tools/sss_override.c b/src/tools/sss_override.c -index d41da52e69acdb67b5a6d624254e3b89a8aa27b8..212bf9ab84b20d4777fc2601359fad58596bb7c4 100644 ---- a/src/tools/sss_override.c -+++ b/src/tools/sss_override.c -@@ -1159,12 +1159,14 @@ list_user_overrides(TALLOC_CTX *mem_ctx, - } - - fqname = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL); -- ret = sss_parse_internal_fqname(tmp_ctx, fqname, &name, NULL); -- if (ret != EOK) { -- ret = ERR_WRONG_NAME_FORMAT; -- goto done; -+ if (fqname != NULL) { -+ ret = sss_parse_internal_fqname(tmp_ctx, fqname, &name, NULL); -+ if (ret != EOK) { -+ ret = ERR_WRONG_NAME_FORMAT; -+ goto done; -+ } -+ objs[i].name = talloc_steal(objs, name); - } -- objs[i].name = talloc_steal(objs, name); - - objs[i].uid = ldb_msg_find_attr_as_uint(msgs[i], SYSDB_UIDNUM, 0); - objs[i].gid = ldb_msg_find_attr_as_uint(msgs[i], SYSDB_GIDNUM, 0); -@@ -1248,12 +1250,14 @@ list_group_overrides(TALLOC_CTX *mem_ctx, - talloc_steal(objs, objs[i].orig_name); - - fqname = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL); -- ret = sss_parse_internal_fqname(tmp_ctx, fqname, &name, NULL); -- if (ret != EOK) { -- ret = ERR_WRONG_NAME_FORMAT; -- goto done; -+ if (fqname != NULL) { -+ ret = sss_parse_internal_fqname(tmp_ctx, fqname, &name, NULL); -+ if (ret != EOK) { -+ ret = ERR_WRONG_NAME_FORMAT; -+ goto done; -+ } -+ objs[i].name = talloc_steal(objs, name); - } -- objs[i].name = talloc_steal(objs, name); - - objs[i].gid = ldb_msg_find_attr_as_uint(msgs[i], SYSDB_GIDNUM, 0); - } --- -2.7.4 - diff --git a/SOURCES/0139-krb5-accept-changed-principal-if-krb5_canonicalize-T.patch b/SOURCES/0139-krb5-accept-changed-principal-if-krb5_canonicalize-T.patch new file mode 100644 index 0000000..259a343 --- /dev/null +++ b/SOURCES/0139-krb5-accept-changed-principal-if-krb5_canonicalize-T.patch @@ -0,0 +1,50 @@ +From 04a1802749b6ebf72730357b06bf8cabe09ebb01 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 24 May 2017 16:10:26 +0200 +Subject: [PATCH 139/141] krb5: accept changed principal if + krb5_canonicalize=True + +Currently SSSD accepts significant changes in the principal only if +krb5_use_enterprise_principal=True. But canonicalization can lead to +similar changes so they should be accepted in this case as well. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3408 + +Reviewed-by: Robbie Harwood +(cherry picked from commit ca95807a9060e454ee68f6f30558d6f7ee968c39) +--- + src/providers/krb5/krb5_auth.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c +index 894bd41bde031ac33187bfa3b14202e9429a9198..03ea9d88cac67919d4b9ba3a1cf2efa208662195 100644 +--- a/src/providers/krb5/krb5_auth.c ++++ b/src/providers/krb5/krb5_auth.c +@@ -829,6 +829,7 @@ static void krb5_auth_done(struct tevent_req *subreq) + char *renew_interval_str; + time_t renew_interval_time = 0; + bool use_enterprise_principal; ++ bool canonicalize; + + ret = handle_child_recv(subreq, pd, &buf, &len); + talloc_zfree(subreq); +@@ -908,6 +909,7 @@ static void krb5_auth_done(struct tevent_req *subreq) + + use_enterprise_principal = dp_opt_get_bool(kr->krb5_ctx->opts, + KRB5_USE_ENTERPRISE_PRINCIPAL); ++ canonicalize = dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_CANONICALIZE); + + /* Check if the cases of our upn are correct and update it if needed. + * Fail if the upn differs by more than just the case for non-enterprise +@@ -915,6 +917,7 @@ static void krb5_auth_done(struct tevent_req *subreq) + if (res->correct_upn != NULL && + strcmp(kr->upn, res->correct_upn) != 0) { + if (strcasecmp(kr->upn, res->correct_upn) == 0 || ++ canonicalize == true || + use_enterprise_principal == true) { + talloc_free(kr->upn); + kr->upn = talloc_strdup(kr, res->correct_upn); +-- +2.9.4 + diff --git a/SOURCES/0140-IPA-Avoid-using-uninitialized-ret-value-when-skippin.patch b/SOURCES/0140-IPA-Avoid-using-uninitialized-ret-value-when-skippin.patch new file mode 100644 index 0000000..e6a08b1 --- /dev/null +++ b/SOURCES/0140-IPA-Avoid-using-uninitialized-ret-value-when-skippin.patch @@ -0,0 +1,30 @@ +From 4986fe8b68a3e14a30e8091353bf0679eb3c5e55 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 24 May 2017 21:24:20 +0200 +Subject: [PATCH 140/141] IPA: Avoid using uninitialized ret value when + skipping entries from the joined domain +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 3e3034199b44e01899ec7ba8152fef3738a0e093) +--- + src/providers/ipa/ipa_s2n_exop.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index 15904e0197919c34b1bce58b4bd2c070f99b67a7..3f5f9859554f0b98ecd3fdad31fd66274c5707b0 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -991,6 +991,7 @@ static errno_t s2n_response_to_attrs(TALLOC_CTX *mem_ctx, + } else { + DEBUG(SSSDBG_TRACE_ALL, + "[%s] from root domain, skipping.\n", fq_name); ++ ret = EOK; /* Free resources and continue in the loop */ + } + ber_memfree(domain_name); + ber_memfree(name); +-- +2.9.4 + diff --git a/SOURCES/0140-TEST-Add-regression-test-for-ticket-3179.patch b/SOURCES/0140-TEST-Add-regression-test-for-ticket-3179.patch deleted file mode 100644 index 18f80b9..0000000 --- a/SOURCES/0140-TEST-Add-regression-test-for-ticket-3179.patch +++ /dev/null @@ -1,203 +0,0 @@ -From d3e93eafcf3e484ee8ec092c59914018b42ea4ad Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michal=20=C5=BDidek?= -Date: Wed, 7 Sep 2016 18:23:16 +0200 -Subject: [PATCH 140/140] TEST: Add regression test for ticket #3179 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: -https://fedorahosted.org/sssd/ticket/3179 - -Reviewed-by: Lukáš Slebodník -Reviewed-by: Pavel Březina -(cherry picked from commit 1c72723cde8bea0d390b928c7cd29e48e7a7deab) ---- - src/tests/intg/ldap_local_override_test.py | 126 ++++++++++++++++++++++++++--- - 1 file changed, 114 insertions(+), 12 deletions(-) - -diff --git a/src/tests/intg/ldap_local_override_test.py b/src/tests/intg/ldap_local_override_test.py -index 046535c7727d0f2271f4b974f68ba0722222982b..832849713e1185e836f3dd6decf2deac79ab98dd 100644 ---- a/src/tests/intg/ldap_local_override_test.py -+++ b/src/tests/intg/ldap_local_override_test.py -@@ -205,27 +205,38 @@ def assert_user_default(): - ent.assert_passwd_by_name('user2@LDAP', user2) - - --def assert_user_overriden(): -+def assert_user_overriden(override_name=True): - -- user1 = dict(name='ov_user1', passwd='*', uid=10010, gid=20010, -+ if override_name: -+ name1 = "ov_user1" -+ name2 = "ov_user2" -+ else: -+ name1 = "user1" -+ name2 = "user2" -+ -+ user1 = dict(name=name1, passwd='*', uid=10010, gid=20010, - gecos='Overriden User 1', - dir='/home/ov/user1', - shell='/bin/ov_user1_shell') - -- user2 = dict(name='ov_user2', passwd='*', uid=10020, gid=20020, -+ user2 = dict(name=name2, passwd='*', uid=10020, gid=20020, - gecos='Overriden User 2', - dir='/home/ov/user2', - shell='/bin/ov_user2_shell') - - ent.assert_passwd_by_name('user1', user1) - ent.assert_passwd_by_name('user1@LDAP', user1) -- ent.assert_passwd_by_name('ov_user1', user1) -- ent.assert_passwd_by_name('ov_user1@LDAP', user1) -+ -+ if override_name: -+ ent.assert_passwd_by_name('ov_user1', user1) -+ ent.assert_passwd_by_name('ov_user1@LDAP', user1) - - ent.assert_passwd_by_name('user2', user2) - ent.assert_passwd_by_name('user2@LDAP', user2) -- ent.assert_passwd_by_name('ov_user2', user2) -- ent.assert_passwd_by_name('ov_user2@LDAP', user2) -+ -+ if override_name: -+ ent.assert_passwd_by_name('ov_user2', user2) -+ ent.assert_passwd_by_name('ov_user2@LDAP', user2) - - - # -@@ -514,6 +525,54 @@ def test_imp_exp_user_override(ldap_conn, env_imp_exp_user_override): - assert_user_overriden() - - -+# Regression test for bug 3179 -+ -+ -+def test_imp_exp_user_overrride_noname(ldap_conn, -+ env_two_users_and_group): -+ -+ # Override -+ subprocess.check_call(["sss_override", "user-add", "user1", -+ "-u", "10010", -+ "-g", "20010", -+ "-c", "Overriden User 1", -+ "-h", "/home/ov/user1", -+ "-s", "/bin/ov_user1_shell"]) -+ -+ subprocess.check_call(["sss_override", "user-add", "user2@LDAP", -+ "-u", "10020", -+ "-g", "20020", -+ "-c", "Overriden User 2", -+ "-h", "/home/ov/user2", -+ "-s", "/bin/ov_user2_shell"]) -+ -+ # Restart SSSD so the override might take effect -+ restart_sssd() -+ -+ # Assert entries are overriden -+ assert_user_overriden(override_name=False) -+ -+ # Export overrides -+ subprocess.check_call(["sss_override", "user-export", OVERRIDE_FILENAME]) -+ -+ # Drop all overrides -+ subprocess.check_call(["sss_override", "user-del", "user1"]) -+ subprocess.check_call(["sss_override", "user-del", "user2@LDAP"]) -+ -+ # Avoid hitting memory cache -+ time.sleep(2) -+ -+ # Assert entries are not overridden -+ assert_user_default() -+ -+ # Import overrides -+ subprocess.check_call(["sss_override", "user-import", -+ OVERRIDE_FILENAME]) -+ restart_sssd() -+ -+ assert_user_overriden(override_name=False) -+ -+ - # - # Override user-show - # -@@ -581,7 +640,7 @@ def test_find_user_override(ldap_conn, env_find_user_override): - # Common group asserts - # - --def assert_group_overriden(): -+def assert_group_overriden(override_name=True): - - # Assert entries are overridden - empty_group = dict(gid=3002, mem=ent.contains_only()) -@@ -589,13 +648,17 @@ def assert_group_overriden(): - - ent.assert_group_by_name("group", group) - ent.assert_group_by_name("group@LDAP", group) -- ent.assert_group_by_name("ov_group", group) -- ent.assert_group_by_name("ov_group@LDAP", group) -+ -+ if override_name: -+ ent.assert_group_by_name("ov_group", group) -+ ent.assert_group_by_name("ov_group@LDAP", group) - - ent.assert_group_by_name("empty_group", empty_group) - ent.assert_group_by_name("empty_group@LDAP", empty_group) -- ent.assert_group_by_name("ov_empty_group", empty_group) -- ent.assert_group_by_name("ov_empty_group@LDAP", empty_group) -+ -+ if override_name: -+ ent.assert_group_by_name("ov_empty_group", empty_group) -+ ent.assert_group_by_name("ov_empty_group@LDAP", empty_group) - - - def assert_group_default(): -@@ -841,6 +904,45 @@ def test_imp_exp_group_override(ldap_conn, env_imp_exp_group_override): - assert_group_overriden() - - -+# Regression test for bug 3179 -+ -+ -+def test_imp_exp_group_override_noname(ldap_conn, env_group_basic): -+ -+ # Override - do not use -n here) -+ subprocess.check_call(["sss_override", "group-add", "group", -+ "-g", "3001"]) -+ -+ subprocess.check_call(["sss_override", "group-add", "empty_group@LDAP", -+ "--gid", "3002"]) -+ -+ # Restart SSSD so the override might take effect -+ restart_sssd() -+ -+ # Assert entries are overridden -+ assert_group_overriden(override_name=False) -+ -+ # Export overrides -+ subprocess.check_call(["sss_override", "group-export", -+ OVERRIDE_FILENAME]) -+ -+ # Drop all overrides -+ subprocess.check_call(["sss_override", "group-del", "group"]) -+ subprocess.check_call(["sss_override", "group-del", "empty_group@LDAP"]) -+ -+ # Avoid hitting memory cache -+ time.sleep(2) -+ -+ assert_group_default() -+ -+ # Import overrides -+ subprocess.check_call(["sss_override", "group-import", -+ OVERRIDE_FILENAME]) -+ restart_sssd() -+ -+ assert_group_overriden(override_name=False) -+ -+ - # Regression test for bug #2802 - # sss_override segfaults when accidentally adding --help flag to some commands - --- -2.7.4 - diff --git a/SOURCES/0141-IPA-Return-from-function-after-marking-a-request-as-.patch b/SOURCES/0141-IPA-Return-from-function-after-marking-a-request-as-.patch new file mode 100644 index 0000000..1da145d --- /dev/null +++ b/SOURCES/0141-IPA-Return-from-function-after-marking-a-request-as-.patch @@ -0,0 +1,30 @@ +From 2ae1485566cbd2b095935aaf7e851d12d2de4513 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 24 May 2017 21:26:22 +0200 +Subject: [PATCH 141/141] IPA: Return from function after marking a request as + finished +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit eb404bcdbbff7e080a93d816e17b8cec04f79fc4) +--- + src/providers/ipa/ipa_s2n_exop.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index 3f5f9859554f0b98ecd3fdad31fd66274c5707b0..39ed17cbf0e8c523212084197e9f2963fed88dc8 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -2664,6 +2664,7 @@ static void ipa_s2n_get_list_done(struct tevent_req *subreq) + } else { + tevent_req_error(req, EINVAL); + } ++ return; + } + + ret = sysdb_attrs_get_string(state->attrs->sysdb_attrs, SYSDB_SID_STR, +-- +2.9.4 + diff --git a/SOURCES/0141-p11-only-set-PKCS11_LOGIN_TOKEN_NAME-if-gdm-smartcar.patch b/SOURCES/0141-p11-only-set-PKCS11_LOGIN_TOKEN_NAME-if-gdm-smartcar.patch deleted file mode 100644 index 2df0058..0000000 --- a/SOURCES/0141-p11-only-set-PKCS11_LOGIN_TOKEN_NAME-if-gdm-smartcar.patch +++ /dev/null @@ -1,267 +0,0 @@ -From 5000ad4c45d3cfb4ffa0d76d291c8b1b6c49b02b Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 31 Aug 2016 14:32:31 +0200 -Subject: [PATCH 141/143] p11: only set PKCS11_LOGIN_TOKEN_NAME if - gdm-smartcard is used - -Resolves https://fedorahosted.org/sssd/ticket/3165 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 71cd9f98150577224559bdc12c53c01ce6f2c3d9) ---- - src/responder/pam/pamsrv_p11.c | 33 +++++++++------ - src/tests/cmocka/test_pam_srv.c | 89 +++++++++++++++++++++++++++++++++++------ - 2 files changed, 97 insertions(+), 25 deletions(-) - -diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c -index a2514f6a1d699de3a245063f49db1b7e51a2b10b..22da33067d5c479153376927855dcd6b43322d8b 100644 ---- a/src/responder/pam/pamsrv_p11.c -+++ b/src/responder/pam/pamsrv_p11.c -@@ -505,7 +505,11 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - } - - /* The PKCS11_LOGIN_TOKEN_NAME environment variable is e.g. used by the Gnome -- * Settings Daemon to determine the name of the token used for login */ -+ * Settings Daemon to determine the name of the token used for login but it -+ * should be only set if SSSD is called by gdm-smartcard. Otherwise desktop -+ * components might assume that gdm-smartcard PAM stack is configured -+ * correctly which might not be the case e.g. if Smartcard authentication was -+ * used when running gdm-password. */ - #define PKCS11_LOGIN_TOKEN_ENV_NAME "PKCS11_LOGIN_TOKEN_NAME" - - errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, -@@ -553,19 +557,22 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, - return ret; - } - -- env = talloc_asprintf(pd, "%s=%s", PKCS11_LOGIN_TOKEN_ENV_NAME, token_name); -- if (env == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); -- return ENOMEM; -- } -+ if (strcmp(pd->service, "gdm-smartcard") == 0) { -+ env = talloc_asprintf(pd, "%s=%s", PKCS11_LOGIN_TOKEN_ENV_NAME, -+ token_name); -+ if (env == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); -+ return ENOMEM; -+ } - -- ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(env) + 1, -- (uint8_t *)env); -- talloc_free(env); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, -- "pam_add_response failed to add environment variable.\n"); -- return ret; -+ ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(env) + 1, -+ (uint8_t *)env); -+ talloc_free(env); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "pam_add_response failed to add environment variable.\n"); -+ return ret; -+ } - } - - return ret; -diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c -index 5de092d0f19318d1d6c773355dbb38e345600133..02199e6f121cab0784389256cdaac38baf9d73e3 100644 ---- a/src/tests/cmocka/test_pam_srv.c -+++ b/src/tests/cmocka/test_pam_srv.c -@@ -554,7 +554,7 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name, - } - - static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, -- const char *pin) -+ const char *pin, const char *service) - { - size_t buf_size; - uint8_t *m_buf; -@@ -576,7 +576,7 @@ static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, - pi.pam_authtok_type = SSS_AUTHTOK_TYPE_SC_PIN; - } - -- pi.pam_service = "login"; -+ pi.pam_service = service == NULL ? "login" : service; - pi.pam_service_size = strlen(pi.pam_service) + 1; - pi.pam_tty = "/dev/tty"; - pi.pam_tty_size = strlen(pi.pam_tty) + 1; -@@ -626,7 +626,8 @@ static int test_pam_simple_check(uint32_t status, uint8_t *body, size_t blen) - - #define PKCS11_LOGIN_TOKEN_ENV_NAME "PKCS11_LOGIN_TOKEN_NAME" - --static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen) -+static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, -+ size_t blen) - { - size_t rp = 0; - uint32_t val; -@@ -675,6 +676,44 @@ static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen) - return EOK; - } - -+static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen) -+{ -+ size_t rp = 0; -+ uint32_t val; -+ -+ assert_int_equal(status, 0); -+ -+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -+ assert_int_equal(val, pam_test_ctx->exp_pam_status); -+ -+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -+ assert_int_equal(val, 2); -+ -+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -+ assert_int_equal(val, SSS_PAM_DOMAIN_NAME); -+ -+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -+ assert_int_equal(val, 9); -+ -+ assert_int_equal(*(body + rp + val - 1), 0); -+ assert_string_equal(body + rp, TEST_DOM_NAME); -+ rp += val; -+ -+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -+ assert_int_equal(val, SSS_PAM_CERT_INFO); -+ -+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -+ assert_int_equal(val, (sizeof("pamuser") + sizeof(TEST_TOKEN_NAME))); -+ -+ assert_int_equal(*(body + rp + sizeof("pamuser") - 1), 0); -+ assert_string_equal(body + rp, "pamuser"); -+ rp += sizeof("pamuser"); -+ -+ assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0); -+ assert_string_equal(body + rp, TEST_TOKEN_NAME); -+ -+ return EOK; -+} - - static int test_pam_offline_chauthtok_check(uint32_t status, - uint8_t *body, size_t blen) -@@ -1438,7 +1477,7 @@ void test_pam_preauth_no_logon_name(void **state) - { - int ret; - -- mock_input_pam_cert(pam_test_ctx, NULL, NULL); -+ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL); - - will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); - will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -@@ -1465,7 +1504,7 @@ void test_pam_preauth_cert_nocert(void **state) - - set_cert_auth_param(pam_test_ctx->pctx, "/no/path"); - -- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL); -+ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL); - - will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); - will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -@@ -1544,7 +1583,7 @@ void test_pam_preauth_cert_nomatch(void **state) - - set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); - -- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL); -+ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL); - - will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); - will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -@@ -1566,7 +1605,7 @@ void test_pam_preauth_cert_match(void **state) - - set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); - -- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL); -+ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL); - - will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); - will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -@@ -1583,13 +1622,37 @@ void test_pam_preauth_cert_match(void **state) - assert_int_equal(ret, EOK); - } - -+/* Test if PKCS11_LOGIN_TOKEN_NAME is added for the gdm-smartcard service */ -+void test_pam_preauth_cert_match_gdm_smartcard(void **state) -+{ -+ int ret; -+ -+ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); -+ -+ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, "gdm-smartcard"); -+ -+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); -+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -+ mock_account_recv(0, 0, NULL, test_lookup_by_cert_cb, -+ discard_const(TEST_TOKEN_CERT)); -+ -+ set_cmd_cb(test_pam_cert_check_gdm_smartcard); -+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH, -+ pam_test_ctx->pam_cmds); -+ assert_int_equal(ret, EOK); -+ -+ /* Wait until the test finishes with EOK */ -+ ret = test_ev_loop(pam_test_ctx->tctx); -+ assert_int_equal(ret, EOK); -+} -+ - void test_pam_preauth_cert_match_wrong_user(void **state) - { - int ret; - - set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); - -- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL); -+ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL); - - will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); - will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -@@ -1613,7 +1676,7 @@ void test_pam_preauth_cert_no_logon_name(void **state) - - set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); - -- mock_input_pam_cert(pam_test_ctx, NULL, NULL); -+ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL); - - will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); - will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -@@ -1636,7 +1699,7 @@ void test_pam_preauth_no_cert_no_logon_name(void **state) - - set_cert_auth_param(pam_test_ctx->pctx, "/no/path"); - -- mock_input_pam_cert(pam_test_ctx, NULL, NULL); -+ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL); - - will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); - will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -@@ -1657,7 +1720,7 @@ void test_pam_preauth_cert_no_logon_name_no_match(void **state) - - set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); - -- mock_input_pam_cert(pam_test_ctx, NULL, NULL); -+ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL); - - will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); - will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -@@ -1679,7 +1742,7 @@ void test_pam_cert_auth(void **state) - - set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); - -- mock_input_pam_cert(pam_test_ctx, "pamuser", "123456"); -+ mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", NULL); - - will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); - will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); -@@ -1790,6 +1853,8 @@ int main(int argc, const char *argv[]) - pam_test_setup, pam_test_teardown), - cmocka_unit_test_setup_teardown(test_pam_preauth_cert_match, - pam_test_setup, pam_test_teardown), -+ cmocka_unit_test_setup_teardown(test_pam_preauth_cert_match_gdm_smartcard, -+ pam_test_setup, pam_test_teardown), - cmocka_unit_test_setup_teardown(test_pam_preauth_cert_match_wrong_user, - pam_test_setup, pam_test_teardown), - cmocka_unit_test_setup_teardown(test_pam_preauth_cert_no_logon_name, --- -2.7.4 - diff --git a/SOURCES/0142-HBAC-Do-not-rely-on-originalMemberOf-use-the-sysdb-m.patch b/SOURCES/0142-HBAC-Do-not-rely-on-originalMemberOf-use-the-sysdb-m.patch new file mode 100644 index 0000000..4669a77 --- /dev/null +++ b/SOURCES/0142-HBAC-Do-not-rely-on-originalMemberOf-use-the-sysdb-m.patch @@ -0,0 +1,175 @@ +From c7c087b5485d50e8689d31fd9d52af935ae398be Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Sun, 9 Apr 2017 20:50:47 +0200 +Subject: [PATCH 142/142] HBAC: Do not rely on originalMemberOf, use the sysdb + memberof links instead + +The IPA HBAC code used to read the group members from the +originalMemberOf attribute value for performance reasons. However, +especially on IPA clients trusting an AD domain, the originalMemberOf +attribute value is often not synchronized correctly. + +Instead of going through the work of maintaining both member/memberOf +and originalMemberOf, let's just do an ASQ search for the group names of +the groups the user is a member of in the cache and read their +SYSBD_NAME attribute. + +To avoid clashing between similarly-named groups in IPA and in AD, we +look at the container of the group. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3382 + +Reviewed-by: Sumit Bose +(cherry picked from commit c92e49144978ad3b6c9fffa8803ebdad8f6f5b18) +--- + src/providers/ipa/ipa_hbac_common.c | 97 +++++++++++++++++++++++++------------ + 1 file changed, 67 insertions(+), 30 deletions(-) + +diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c +index b99b75d322930f16412f6abd4cdf0d7e0b59c32c..ba677965a3eb68a54baf99b1875bca2acbb76c99 100644 +--- a/src/providers/ipa/ipa_hbac_common.c ++++ b/src/providers/ipa/ipa_hbac_common.c +@@ -507,15 +507,15 @@ hbac_eval_user_element(TALLOC_CTX *mem_ctx, + struct hbac_request_element **user_element) + { + errno_t ret; +- unsigned int i; + unsigned int num_groups = 0; + TALLOC_CTX *tmp_ctx; +- const char *member_dn; + struct hbac_request_element *users; +- struct ldb_message *msg; +- struct ldb_message_element *el; +- const char *attrs[] = { SYSDB_ORIG_MEMBEROF, NULL }; + char *shortname; ++ const char *fqgroupname = NULL; ++ struct sss_domain_info *ipa_domain; ++ struct ldb_dn *ipa_groups_basedn; ++ struct ldb_result *res; ++ int exp_comp; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) return ENOMEM; +@@ -533,56 +533,93 @@ hbac_eval_user_element(TALLOC_CTX *mem_ctx, + } + users->name = talloc_steal(users, shortname); + +- /* Read the originalMemberOf attribute +- * This will give us the list of both POSIX and +- * non-POSIX groups that this user belongs to. ++ ipa_domain = get_domains_head(domain); ++ if (ipa_domain == NULL) { ++ ret = EINVAL; ++ goto done; ++ } ++ ++ ipa_groups_basedn = ldb_dn_new_fmt(tmp_ctx, sysdb_ctx_get_ldb(domain->sysdb), ++ SYSDB_TMPL_GROUP_BASE, ipa_domain->name); ++ if (ipa_groups_basedn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* +1 because there will be a RDN preceding the base DN */ ++ exp_comp = ldb_dn_get_comp_num(ipa_groups_basedn) + 1; ++ ++ /* ++ * Get all the groups the user is a member of. ++ * This includes both POSIX and non-POSIX groups. + */ +- ret = sysdb_search_user_by_name(tmp_ctx, domain, username, +- attrs, &msg); ++ ret = sysdb_initgroups(tmp_ctx, domain, username, &res); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "Could not determine user memberships for [%s]\n", +- users->name); ++ "sysdb_asq_search failed [%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + +- el = ldb_msg_find_element(msg, SYSDB_ORIG_MEMBEROF); +- if (el == NULL || el->num_values == 0) { ++ if (res->count == 0) { ++ /* This should not happen at this point */ ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "User [%s] not found in cache.\n", username); ++ ret = ENOENT; ++ goto done; ++ } else if (res->count == 1) { ++ /* The first item is the user entry */ + DEBUG(SSSDBG_TRACE_LIBS, "No groups for [%s]\n", users->name); + ret = create_empty_grouplist(users); + goto done; + } + DEBUG(SSSDBG_TRACE_LIBS, +- "[%d] groups for [%s]\n", el->num_values, users->name); ++ "[%u] groups for [%s]\n", res->count - 1, username); + +- users->groups = talloc_array(users, const char *, el->num_values + 1); ++ /* This also includes the sentinel, b/c we'll skip the user entry below */ ++ users->groups = talloc_array(users, const char *, res->count); + if (users->groups == NULL) { + ret = ENOMEM; + goto done; + } + +- for (i = 0; i < el->num_values; i++) { +- member_dn = (const char *)el->values[i].data; ++ /* Start counting from 1 to exclude the user entry */ ++ for (size_t i = 1; i < res->count; i++) { ++ /* Only groups from the IPA domain can be referenced from HBAC rules. To ++ * avoid evaluating groups which might even have the same name, but come ++ * from a trusted domain, we first copy the DN to a temporary one.. ++ */ ++ if (ldb_dn_get_comp_num(res->msgs[i]->dn) != exp_comp ++ || ldb_dn_compare_base(ipa_groups_basedn, ++ res->msgs[i]->dn) != 0) { ++ DEBUG(SSSDBG_FUNC_DATA, ++ "Skipping non-IPA group %s\n", ++ ldb_dn_get_linearized(res->msgs[i]->dn)); ++ continue; ++ } + +- ret = get_ipa_groupname(users->groups, domain->sysdb, member_dn, +- &users->groups[num_groups]); +- if (ret != EOK && ret != ERR_UNEXPECTED_ENTRY_TYPE) { ++ fqgroupname = ldb_msg_find_attr_as_string(res->msgs[i], SYSDB_NAME, NULL); ++ if (fqgroupname == NULL) { + DEBUG(SSSDBG_MINOR_FAILURE, +- "Skipping malformed entry [%s]\n", member_dn); ++ "Skipping malformed entry [%s]\n", ++ ldb_dn_get_linearized(res->msgs[i]->dn)); + continue; +- } else if (ret == EOK) { +- DEBUG(SSSDBG_TRACE_LIBS, "Added group [%s] for user [%s]\n", +- users->groups[num_groups], users->name); +- num_groups++; ++ } ++ ++ ret = sss_parse_internal_fqname(tmp_ctx, fqgroupname, ++ &shortname, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Malformed name %s, skipping!\n", fqgroupname); + continue; + } +- /* Skip entries that are not groups */ +- DEBUG(SSSDBG_TRACE_INTERNAL, +- "Skipping non-group memberOf [%s]\n", member_dn); ++ ++ users->groups[num_groups] = talloc_steal(users->groups, shortname); ++ DEBUG(SSSDBG_TRACE_LIBS, "Added group [%s] for user [%s]\n", ++ users->groups[num_groups], users->name); ++ num_groups++; + } + users->groups[num_groups] = NULL; + +- if (num_groups < el->num_values) { ++ if (num_groups < (res->count - 1)) { + /* Shrink the array memory */ + users->groups = talloc_realloc(users, users->groups, const char *, + num_groups+1); +-- +2.9.4 + diff --git a/SOURCES/0142-p11-return-a-fully-qualified-name.patch b/SOURCES/0142-p11-return-a-fully-qualified-name.patch deleted file mode 100644 index 195b9cc..0000000 --- a/SOURCES/0142-p11-return-a-fully-qualified-name.patch +++ /dev/null @@ -1,100 +0,0 @@ -From e87e0059520de24047e8448a5b417393adc6c5b4 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 16 Sep 2016 11:47:40 +0200 -Subject: [PATCH 142/143] p11: return a fully-qualified name - -Related to https://fedorahosted.org/sssd/ticket/3165 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 3649b959709f1ab187092f054d4aace0798c98fa) ---- - src/responder/pam/pamsrv_p11.c | 20 +++++++++----------- - src/tests/cmocka/test_pam_srv.c | 16 ++++++++-------- - 2 files changed, 17 insertions(+), 19 deletions(-) - -diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c -index 22da33067d5c479153376927855dcd6b43322d8b..570bfe09d4385a038e7e03fcb64c72dd794774a6 100644 ---- a/src/responder/pam/pamsrv_p11.c -+++ b/src/responder/pam/pamsrv_p11.c -@@ -521,33 +521,31 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, - size_t msg_len; - size_t slot_len; - int ret; -- char *username; - - if (sysdb_username == NULL || token_name == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "Missing mandatory user or slot name.\n"); - return EINVAL; - } - -- ret = sss_parse_internal_fqname(pd, sysdb_username, &username, NULL); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot parse [%s]\n", sysdb_username); -- return ret; -- } -- -- user_len = strlen(username) + 1; -+ user_len = strlen(sysdb_username) + 1; - slot_len = strlen(token_name) + 1; - msg_len = user_len + slot_len; - - msg = talloc_zero_size(pd, msg_len); - if (msg == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n"); -- talloc_free(username); - return ENOMEM; - } - -- memcpy(msg, username, user_len); -+ /* sysdb_username is a fully-qualified name which is used by pam_sss when -+ * prompting the user for the PIN and as login name if it wasn't set by -+ * the PAM caller but has to be determined based on the inserted -+ * Smartcard. If this type of name is irritating at the PIN prompt or the -+ * re_expression config option was set in a way that user@domain cannot be -+ * handled anymore some more logic has to be added here. But for the time -+ * being I think using sysdb_username is fine. */ -+ memcpy(msg, sysdb_username, user_len); - memcpy(msg + user_len, token_name, slot_len); -- talloc_free(username); - - ret = pam_add_response(pd, SSS_PAM_CERT_INFO, msg_len, msg); - talloc_free(msg); -diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c -index 02199e6f121cab0784389256cdaac38baf9d73e3..4b2dea4be6a819b23afd243ba99cd9bd57c16c20 100644 ---- a/src/tests/cmocka/test_pam_srv.c -+++ b/src/tests/cmocka/test_pam_srv.c -@@ -664,11 +664,11 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, - assert_int_equal(val, SSS_PAM_CERT_INFO); - - SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -- assert_int_equal(val, (sizeof("pamuser") + sizeof(TEST_TOKEN_NAME))); -+ assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME) + sizeof(TEST_TOKEN_NAME))); - -- assert_int_equal(*(body + rp + sizeof("pamuser") - 1), 0); -- assert_string_equal(body + rp, "pamuser"); -- rp += sizeof("pamuser"); -+ assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0); -+ assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME); -+ rp += sizeof("pamuser@"TEST_DOM_NAME); - - assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0); - assert_string_equal(body + rp, TEST_TOKEN_NAME); -@@ -703,11 +703,11 @@ static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen) - assert_int_equal(val, SSS_PAM_CERT_INFO); - - SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); -- assert_int_equal(val, (sizeof("pamuser") + sizeof(TEST_TOKEN_NAME))); -+ assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME) + sizeof(TEST_TOKEN_NAME))); - -- assert_int_equal(*(body + rp + sizeof("pamuser") - 1), 0); -- assert_string_equal(body + rp, "pamuser"); -- rp += sizeof("pamuser"); -+ assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0); -+ assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME); -+ rp += sizeof("pamuser@"TEST_DOM_NAME); - - assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0); - assert_string_equal(body + rp, TEST_TOKEN_NAME); --- -2.7.4 - diff --git a/SOURCES/0143-VALIDATORS-Add-subdomain-section.patch b/SOURCES/0143-VALIDATORS-Add-subdomain-section.patch new file mode 100644 index 0000000..8b1c3c5 --- /dev/null +++ b/SOURCES/0143-VALIDATORS-Add-subdomain-section.patch @@ -0,0 +1,53 @@ +From 270121098caff2496da73795fe586ff734ae1e56 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Tue, 4 Apr 2017 18:01:02 +0200 +Subject: [PATCH 143/152] VALIDATORS: Add subdomain section +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add separate rule for subdomain sections. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3356 + +Reviewed-by: Lukáš Slebodník +--- + src/config/cfg_rules.ini | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index e47ff33242d6a9e5979fe0eb8eea14c2af28685a..4b30e8fc43b50844023e7fffa607a59530a302f0 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -11,7 +11,8 @@ section = ifp + section = secrets + section = kcm + section_re = ^secrets/users/[0-9]\+$ +-section_re = ^domain/.*$ ++section_re = ^domain/[^/\@]\+$ ++section_re = ^domain/[^/\@]\+/[^/\@]\+$ + section_re = ^application/.*$ + + [rule/allowed_sssd_options] +@@ -698,3 +699,17 @@ validator = ini_allowed_options + section_re = ^application/.*$ + + option = inherit_from ++ ++[rule/allowed_subdomain_options] ++validator = ini_allowed_options ++section_re = ^domain/[^/\@]\+/[^/\@]\+$ ++ ++option = ldap_search_base ++option = ldap_user_search_base ++option = ldap_group_search_base ++option = ldap_netgroup_search_base ++option = ldap_service_search_base ++option = ad_server ++option = ad_backup_server ++option = ad_site ++option = use_fully_qualified_names +-- +2.9.4 + diff --git a/SOURCES/0143-pam_sss-check-PKCS11_LOGIN_TOKEN_NAME.patch b/SOURCES/0143-pam_sss-check-PKCS11_LOGIN_TOKEN_NAME.patch deleted file mode 100644 index 1cd1c77..0000000 --- a/SOURCES/0143-pam_sss-check-PKCS11_LOGIN_TOKEN_NAME.patch +++ /dev/null @@ -1,109 +0,0 @@ -From b5a092b4b0e4f072f0f402146a83addb97cf2977 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 16 Sep 2016 11:48:18 +0200 -Subject: [PATCH 143/143] pam_sss: check PKCS11_LOGIN_TOKEN_NAME - -Check if PKCS11_LOGIN_TOKEN_NAME is set and prompt the user if the -matching Smartcard is not inserted. - -Related to https://fedorahosted.org/sssd/ticket/3165 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 35ba922bc51416f02877b53a6f25c04104ae5f03) ---- - src/sss_client/pam_sss.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 65 insertions(+) - -diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c -index fdb9c907644f1317b6f8e58619f01ad2753deafc..2049d5fb0c6092aaaa914385c79d02d8f44b447e 100644 ---- a/src/sss_client/pam_sss.c -+++ b/src/sss_client/pam_sss.c -@@ -1410,6 +1410,7 @@ done: - } - - #define SC_PROMPT_FMT "PIN for %s for user %s" -+ - static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) - { - int ret; -@@ -1691,6 +1692,62 @@ static int get_authtok_for_password_change(pam_handle_t *pamh, - return PAM_SUCCESS; - } - -+#define SC_ENTER_FMT "Please enter smart card labeled\n %s\nand press enter" -+ -+static int check_login_token_name(pam_handle_t *pamh, struct pam_items *pi, -+ bool quiet_mode) -+{ -+ int ret; -+ int pam_status; -+ char *login_token_name; -+ char *prompt = NULL; -+ size_t size; -+ char *answer = NULL; -+ -+ login_token_name = getenv("PKCS11_LOGIN_TOKEN_NAME"); -+ if (login_token_name == NULL) { -+ return PAM_SUCCESS; -+ } -+ -+ while (pi->token_name == NULL -+ || strcmp(login_token_name, pi->token_name) != 0) { -+ size = sizeof(SC_ENTER_FMT) + strlen(login_token_name); -+ prompt = malloc(size); -+ if (prompt == NULL) { -+ D(("malloc failed.")); -+ return ENOMEM; -+ } -+ -+ ret = snprintf(prompt, size, SC_ENTER_FMT, -+ login_token_name); -+ if (ret < 0 || ret >= size) { -+ D(("snprintf failed.")); -+ free(prompt); -+ return EFAULT; -+ } -+ -+ ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, -+ NULL, &answer); -+ free(prompt); -+ free(answer); -+ if (ret != PAM_SUCCESS) { -+ D(("do_pam_conversation failed.")); -+ return ret; -+ } -+ -+ pam_status = send_and_receive(pamh, pi, SSS_PAM_PREAUTH, quiet_mode); -+ if (pam_status != PAM_SUCCESS) { -+ D(("send_and_receive returned [%d] during pre-auth", pam_status)); -+ /* -+ * Since we are waiting for the right Smartcard to be inserted errors -+ * can be ignored here. -+ */ -+ } -+ } -+ -+ return PAM_SUCCESS; -+} -+ - static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh, - int pam_flags, int argc, const char **argv) - { -@@ -1758,6 +1815,14 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh, - } - } - -+ if (strcmp(pi.pam_service, "gdm-smartcard") == 0) { -+ ret = check_login_token_name(pamh, &pi, quiet_mode); -+ if (ret != PAM_SUCCESS) { -+ D(("check_login_token_name failed.\n")); -+ return ret; -+ } -+ } -+ - ret = get_authtok_for_authentication(pamh, &pi, flags); - if (ret != PAM_SUCCESS) { - D(("failed to get authentication token: %s", --- -2.7.4 - diff --git a/SOURCES/0144-VALIDATORS-Remove-application-section-domain.patch b/SOURCES/0144-VALIDATORS-Remove-application-section-domain.patch new file mode 100644 index 0000000..d644b35 --- /dev/null +++ b/SOURCES/0144-VALIDATORS-Remove-application-section-domain.patch @@ -0,0 +1,48 @@ +From 39864f9ce41ce892fe3cafb769584173299f49f7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Tue, 4 Apr 2017 19:07:12 +0200 +Subject: [PATCH 144/152] VALIDATORS: Remove application section domain +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Application domains can use the same options as normal domains section +with one more additional option. + +We could either duplicate all options from the domain section also in +the application domain section + add the one additional option or +add this one option to the domain section even though it is not meant +to be used there to avoid duplication of all domain options in the +rule for application section. + +It would be could to enhance the validators in libini to allow +something like 'include' section in order to avoid this issue +in the future. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3356 + +Reviewed-by: Lukáš Slebodník +--- + src/config/cfg_rules.ini | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 4b30e8fc43b50844023e7fffa607a59530a302f0..a30fe57e262716abeb2d2af9c3add326122ee4ca 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -694,10 +694,7 @@ option = ldap_user_uid_number + option = ldap_user_uuid + option = ldap_use_tokengroups + +-[rule/allowed_application_options] +-validator = ini_allowed_options +-section_re = ^application/.*$ +- ++# For application domains + option = inherit_from + + [rule/allowed_subdomain_options] +-- +2.9.4 + diff --git a/SOURCES/0144-sysdb-add-parent_dom-to-sysdb_get_direct_parents.patch b/SOURCES/0144-sysdb-add-parent_dom-to-sysdb_get_direct_parents.patch deleted file mode 100644 index 7cf09f2..0000000 --- a/SOURCES/0144-sysdb-add-parent_dom-to-sysdb_get_direct_parents.patch +++ /dev/null @@ -1,124 +0,0 @@ -From b368dca11e715400da64348a17049abf5b072f57 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 18 Oct 2016 14:59:19 +0200 -Subject: [PATCH 144/151] sysdb: add parent_dom to sysdb_get_direct_parents() - -Currently sysdb_get_direct_parents() only return direct parents from the -same domain as the child object. In setups with sub-domains this might -not be sufficient. A new option parent_dom is added which allows to -specify a domain the direct parents should be lookup up in. If it is -NULL the whole cache is searched. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 3dd4c3eca80e9223a65f3318821bd0fb5b45aedd) ---- - src/db/sysdb.h | 21 +++++++++++++++++++++ - src/db/sysdb_search.c | 7 ++++++- - src/providers/ldap/sdap_async_initgroups.c | 11 +++++++---- - 3 files changed, 34 insertions(+), 5 deletions(-) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 8713efa6e8fcc6fb620340fe152989a5dae58434..4164657c2b329a240d46fe3ecdfb4b2eefffc5b3 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -1135,8 +1135,29 @@ errno_t sysdb_remove_attrs(struct sss_domain_info *domain, - enum sysdb_member_type type, - char **remove_attrs); - -+/** -+ * @brief Return direct parents of an object in the cache -+ * -+ * @param[in] mem_ctx Memory context the result should be allocated -+ * on -+ * @param[in] dom domain the object is in -+ * @param[in] parent_dom domain which should be searched for direct -+ * parents if NULL all domains in the given cache -+ * are searched -+ * @param[in] mtype Type of the object, SYSDB_MEMBER_USER or -+ * SYSDB_MEMBER_GROUP -+ * @param[in] name Name of the object -+ * @param[out] _direct_parents List of names of the direct parent groups -+ * -+ * -+ * @return -+ * - EOK: success -+ * - EINVAL: wrong mtype -+ * - ENOMEM: Memory allocation failed -+ */ - errno_t sysdb_get_direct_parents(TALLOC_CTX *mem_ctx, - struct sss_domain_info *dom, -+ struct sss_domain_info *parent_dom, - enum sysdb_member_type mtype, - const char *name, - char ***_direct_parents); -diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c -index cfee5784dbadd692f30d0758e7e5c3c9fb2814cb..4d63c3838a49392bbf2a57aeb6f7740f4d4fbdcd 100644 ---- a/src/db/sysdb_search.c -+++ b/src/db/sysdb_search.c -@@ -1981,6 +1981,7 @@ done: - - errno_t sysdb_get_direct_parents(TALLOC_CTX *mem_ctx, - struct sss_domain_info *dom, -+ struct sss_domain_info *parent_dom, - enum sysdb_member_type mtype, - const char *name, - char ***_direct_parents) -@@ -2029,7 +2030,11 @@ errno_t sysdb_get_direct_parents(TALLOC_CTX *mem_ctx, - goto done; - } - -- basedn = sysdb_group_base_dn(tmp_ctx, dom); -+ if (parent_dom == NULL) { -+ basedn = sysdb_base_dn(dom->sysdb, tmp_ctx); -+ } else { -+ basedn = sysdb_group_base_dn(tmp_ctx, parent_dom); -+ } - if (!basedn) { - ret = ENOMEM; - goto done; -diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c -index f9593f0dfaa2dc6e33fd6c9d1f0c9b78cad3a1d9..77324d0ee9eb2ad2fc35c2098d6c9c23a62747c9 100644 ---- a/src/providers/ldap/sdap_async_initgroups.c -+++ b/src/providers/ldap/sdap_async_initgroups.c -@@ -1301,7 +1301,8 @@ sdap_initgr_store_user_memberships(struct sdap_initgr_nested_state *state) - } - } - -- ret = sysdb_get_direct_parents(tmp_ctx, state->dom, SYSDB_MEMBER_USER, -+ ret = sysdb_get_direct_parents(tmp_ctx, state->dom, state->dom, -+ SYSDB_MEMBER_USER, - state->username, &sysdb_parent_name_list); - if (ret) { - DEBUG(SSSDBG_CRIT_FAILURE, -@@ -1388,7 +1389,7 @@ sdap_initgr_nested_get_membership_diff(TALLOC_CTX *mem_ctx, - goto done; - } - -- ret = sysdb_get_direct_parents(tmp_ctx, dom, SYSDB_MEMBER_GROUP, -+ ret = sysdb_get_direct_parents(tmp_ctx, dom, dom, SYSDB_MEMBER_GROUP, - group_name, &sysdb_parents_names_list); - if (ret) { - DEBUG(SSSDBG_CRIT_FAILURE, -@@ -2070,7 +2071,8 @@ rfc2307bis_group_memberships_build(hash_entry_t *item, void *user_data) - goto done; - } - -- ret = sysdb_get_direct_parents(tmp_ctx, mstate->dom, SYSDB_MEMBER_GROUP, -+ ret = sysdb_get_direct_parents(tmp_ctx, mstate->dom, mstate->dom, -+ SYSDB_MEMBER_GROUP, - group_name, &sysdb_parents_names_list); - if (ret) { - DEBUG(SSSDBG_CRIT_FAILURE, -@@ -2130,7 +2132,8 @@ errno_t save_rfc2307bis_user_memberships( - } - in_transaction = true; - -- ret = sysdb_get_direct_parents(tmp_ctx, state->dom, SYSDB_MEMBER_USER, -+ ret = sysdb_get_direct_parents(tmp_ctx, state->dom, state->dom, -+ SYSDB_MEMBER_USER, - state->name, &sysdb_parent_name_list); - if (ret) { - DEBUG(SSSDBG_CRIT_FAILURE, --- -2.7.4 - diff --git a/SOURCES/0145-VALIDATORS-Escape-special-regex-chars.patch b/SOURCES/0145-VALIDATORS-Escape-special-regex-chars.patch new file mode 100644 index 0000000..d80f3cf --- /dev/null +++ b/SOURCES/0145-VALIDATORS-Escape-special-regex-chars.patch @@ -0,0 +1,35 @@ +From fc6bffc8523e6decf4656182f8caf72236e45c3d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Tue, 4 Apr 2017 20:06:40 +0200 +Subject: [PATCH 145/152] VALIDATORS: Escape special regex chars +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The rule allowed_domain_options did not work because +of bad regex. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3356 + +Reviewed-by: Lukáš Slebodník +--- + src/config/cfg_rules.ini | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index a30fe57e262716abeb2d2af9c3add326122ee4ca..628f2e0e0a040bad5128d00d9348aa91170ed704 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -295,7 +295,7 @@ option = responder_idle_timeout + + [rule/allowed_domain_options] + validator = ini_allowed_options +-section_re = ^(domain|application)/.*$ ++section_re = ^\(domain\|application\)/.*$ + + option = debug + option = debug_level +-- +2.9.4 + diff --git a/SOURCES/0145-sdap-make-some-nested-group-related-calls-public.patch b/SOURCES/0145-sdap-make-some-nested-group-related-calls-public.patch deleted file mode 100644 index abba383..0000000 --- a/SOURCES/0145-sdap-make-some-nested-group-related-calls-public.patch +++ /dev/null @@ -1,80 +0,0 @@ -From f0e6ed1942f1a4263a88a0c02d866d616448668f Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 18 Oct 2016 18:16:30 +0200 -Subject: [PATCH 145/151] sdap: make some nested group related calls public - -sdap_nested_groups_store() and rfc2307bis_nested_groups_send/recv() will -be reused for domain local group lookups. - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 49d3f0a487d55571b2bdc9d3f8280b304b964b9d) ---- - src/providers/ldap/sdap_async_initgroups.c | 12 ++---------- - src/providers/ldap/sdap_async_private.h | 16 ++++++++++++++++ - 2 files changed, 18 insertions(+), 10 deletions(-) - -diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c -index 77324d0ee9eb2ad2fc35c2098d6c9c23a62747c9..f1ba65a98b07a593b0e3a722d0b2c56c8e4b821e 100644 ---- a/src/providers/ldap/sdap_async_initgroups.c -+++ b/src/providers/ldap/sdap_async_initgroups.c -@@ -622,7 +622,7 @@ static int sdap_initgr_rfc2307_recv(struct tevent_req *req) - } - - /* ==Common code for pure RFC2307bis and IPA/AD========================= */ --static errno_t -+errno_t - sdap_nested_groups_store(struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - struct sdap_options *opts, -@@ -1558,14 +1558,6 @@ static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq); - static void sdap_initgr_rfc2307bis_done(struct tevent_req *subreq); - errno_t save_rfc2307bis_user_memberships( - struct sdap_initgr_rfc2307bis_state *state); --struct tevent_req *rfc2307bis_nested_groups_send( -- TALLOC_CTX *mem_ctx, struct tevent_context *ev, -- struct sdap_options *opts, struct sysdb_ctx *sysdb, -- struct sss_domain_info *dom, struct sdap_handle *sh, -- struct sdap_search_base **search_bases, -- struct sysdb_attrs **groups, size_t num_groups, -- hash_table_t *group_hash, size_t nesting); --static errno_t rfc2307bis_nested_groups_recv(struct tevent_req *req); - - static struct tevent_req *sdap_initgr_rfc2307bis_send( - TALLOC_CTX *memctx, -@@ -2616,7 +2608,7 @@ static void rfc2307bis_nested_groups_process(struct tevent_req *subreq) - tevent_req_set_callback(subreq, rfc2307bis_nested_groups_done, req); - } - --static errno_t rfc2307bis_nested_groups_recv(struct tevent_req *req) -+errno_t rfc2307bis_nested_groups_recv(struct tevent_req *req) - { - TEVENT_REQ_RETURN_ON_ERROR(req); - return EOK; -diff --git a/src/providers/ldap/sdap_async_private.h b/src/providers/ldap/sdap_async_private.h -index f09ddb71f48080251e61b8a850ccb8c9b5058331..4af4f7144d8855e4ed705f6a64e0a7818bc0b9a9 100644 ---- a/src/providers/ldap/sdap_async_private.h -+++ b/src/providers/ldap/sdap_async_private.h -@@ -157,4 +157,20 @@ errno_t sdap_check_ad_group_type(struct sss_domain_info *dom, - struct sysdb_attrs *group_attrs, - const char *group_name, - bool *_need_filter); -+ -+struct tevent_req *rfc2307bis_nested_groups_send( -+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, -+ struct sdap_options *opts, struct sysdb_ctx *sysdb, -+ struct sss_domain_info *dom, struct sdap_handle *sh, -+ struct sdap_search_base **search_bases, -+ struct sysdb_attrs **groups, size_t num_groups, -+ hash_table_t *group_hash, size_t nesting); -+errno_t rfc2307bis_nested_groups_recv(struct tevent_req *req); -+ -+errno_t sdap_nested_groups_store(struct sysdb_ctx *sysdb, -+ struct sss_domain_info *domain, -+ struct sdap_options *opts, -+ struct sysdb_attrs **groups, -+ unsigned long count); -+ - #endif /* _SDAP_ASYNC_PRIVATE_H_ */ --- -2.7.4 - diff --git a/SOURCES/0146-LDAP-AD-resolve-domain-local-groups-for-remote-users.patch b/SOURCES/0146-LDAP-AD-resolve-domain-local-groups-for-remote-users.patch deleted file mode 100644 index 3e2d38d..0000000 --- a/SOURCES/0146-LDAP-AD-resolve-domain-local-groups-for-remote-users.patch +++ /dev/null @@ -1,683 +0,0 @@ -From 2341059ba000d4fa87691f84bf3c39822b38aecb Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 18 Oct 2016 18:18:44 +0200 -Subject: [PATCH 146/151] LDAP/AD: resolve domain local groups for remote users - -If a user from a trusted domain in the same forest is a direct or -indirect member of domain local groups from the local domain those -memberships must be resolved as well. Since those domain local groups -are not valid in the trusted domain a DC from the trusted domain which -is used to lookup the user data is not aware of them. As a consequence -those memberships must be resolved against a local DC in a second step. - -Resolves https://fedorahosted.org/sssd/ticket/3206 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 25699846bd1c9f8bb513b6271eb4366ab682fbd2) ---- - src/db/sysdb.h | 2 + - src/providers/ldap/sdap_async_initgroups.c | 158 +++++++++- - src/providers/ldap/sdap_async_initgroups_ad.c | 407 ++++++++++++++++++++++++++ - src/providers/ldap/sdap_async_private.h | 10 + - 4 files changed, 570 insertions(+), 7 deletions(-) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index 4164657c2b329a240d46fe3ecdfb4b2eefffc5b3..a0279fb249e1258c9cb73a4fcab55e4b242c61f3 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -224,6 +224,8 @@ - SYSDB_OVERRIDE_DN, \ - SYSDB_OVERRIDE_OBJECT_DN, \ - SYSDB_DEFAULT_OVERRIDE_NAME, \ -+ SYSDB_UUID, \ -+ SYSDB_ORIG_DN, \ - NULL} - - #define SYSDB_GRSRC_ATTRS {SYSDB_NAME, SYSDB_GIDNUM, \ -diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c -index f1ba65a98b07a593b0e3a722d0b2c56c8e4b821e..8eaba261c49082d086df9f19464ac0f40fae71fb 100644 ---- a/src/providers/ldap/sdap_async_initgroups.c -+++ b/src/providers/ldap/sdap_async_initgroups.c -@@ -2317,6 +2317,7 @@ static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req) - struct sdap_rfc2307bis_nested_ctx *state = - tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx); - char *oc_list; -+ const char *class; - - tmp_ctx = talloc_new(state); - if (!tmp_ctx) { -@@ -2324,9 +2325,21 @@ static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req) - goto done; - } - -- ret = sdap_get_group_primary_name(state, state->opts, -- state->groups[state->group_iter], -- state->dom, &state->primary_name); -+ ret = sysdb_attrs_get_string(state->groups[state->group_iter], -+ SYSDB_OBJECTCLASS, &class); -+ if (ret == EOK) { -+ /* If there is a objectClass attribute the object is coming from the -+ * cache and the name attribute of the object already has the primary -+ * name. -+ * If the objectClass attribute is missing the object is coming from -+ * LDAP and we have to find the primary name first. */ -+ ret = sysdb_attrs_get_string(state->groups[state->group_iter], -+ SYSDB_NAME, &state->primary_name); -+ } else { -+ ret = sdap_get_group_primary_name(state, state->opts, -+ state->groups[state->group_iter], -+ state->dom, &state->primary_name); -+ } - if (ret != EOK) { - goto done; - } -@@ -3069,6 +3082,103 @@ fail: - tevent_req_error(req, ret); - } - -+static void sdap_ad_check_domain_local_groups_done(struct tevent_req *subreq); -+ -+errno_t sdap_ad_check_domain_local_groups(struct tevent_req *req) -+{ -+ struct sdap_get_initgr_state *state = tevent_req_data(req, -+ struct sdap_get_initgr_state); -+ int ret; -+ struct sdap_domain *local_sdom; -+ const char *orig_name; -+ const char *sysdb_name; -+ struct ldb_result *res; -+ struct tevent_req *subreq; -+ struct sysdb_attrs **groups; -+ -+ /* We only need to check for domain local groups in the AD case and if the -+ * user is not from our domain, i.e. if the user comes from a sub-domain. -+ */ -+ if (state->opts->schema_type != SDAP_SCHEMA_AD -+ || !IS_SUBDOMAIN(state->dom) -+ || !dp_target_enabled(state->id_ctx->be->provider, "ad", DPT_ID)) { -+ return EOK; -+ } -+ -+ local_sdom = sdap_domain_get(state->id_ctx->opts, state->dom->parent); -+ if (local_sdom == NULL || local_sdom->pvt == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "No ID ctx available for [%s].\n", -+ state->dom->parent->name); -+ return EINVAL; -+ } -+ -+ ret = sysdb_attrs_get_string(state->orig_user, SYSDB_NAME, &orig_name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing name in user object.\n"); -+ return ret; -+ } -+ -+ sysdb_name = sss_create_internal_fqname(state, orig_name, state->dom->name); -+ if (sysdb_name == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "sss_create_internal_fqname failed.\n"); -+ return ENOMEM; -+ } -+ -+ ret = sysdb_initgroups(state, state->dom, sysdb_name, &res); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_initgroups failed for user [%s].\n", -+ sysdb_name); -+ return ret; -+ } -+ -+ if (res->count == 0) { -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "sysdb_initgroups returned no results for user [%s].\n", -+ sysdb_name); -+ return EINVAL; -+ } -+ -+ /* The user object, the first entry in the res->msgs, is included as well -+ * to cover the case where the remote user is directly added to -+ * a domain local group. */ -+ ret = sysdb_msg2attrs(state, res->count, res->msgs, &groups); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_msg2attrs failed.\n"); -+ return ret; -+ } -+ -+ subreq = sdap_ad_get_domain_local_groups_send(state, state->ev, local_sdom, -+ state->opts, state->sysdb, state->dom->parent, -+ groups, res->count); -+ if (subreq == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "sdap_ad_get_domain_local_groups_send failed.\n"); -+ return ENOMEM; -+ } -+ -+ tevent_req_set_callback(subreq, sdap_ad_check_domain_local_groups_done, -+ req); -+ -+ return EAGAIN; -+} -+ -+static void sdap_ad_check_domain_local_groups_done(struct tevent_req *subreq) -+{ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ int ret; -+ -+ ret = sdap_ad_get_domain_local_groups_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ tevent_req_done(req); -+ -+ return; -+} -+ - static void sdap_get_initgr_pgid(struct tevent_req *req); - static void sdap_get_initgr_done(struct tevent_req *subreq) - { -@@ -3201,8 +3311,6 @@ static void sdap_get_initgr_done(struct tevent_req *subreq) - if (ret == EOK) { - DEBUG(SSSDBG_TRACE_FUNC, - "Primary group already cached, nothing to do.\n"); -- ret = EOK; -- goto done; - } else { - gid = talloc_asprintf(state, "%lu", (unsigned long)primary_gid); - if (gid == NULL) { -@@ -3219,10 +3327,28 @@ static void sdap_get_initgr_done(struct tevent_req *subreq) - goto done; - } - tevent_req_set_callback(subreq, sdap_get_initgr_pgid, req); -+ -+ talloc_free(tmp_ctx); -+ return; - } - -- talloc_free(tmp_ctx); -- return; -+ ret = sdap_ad_check_domain_local_groups(req); -+ if (ret == EAGAIN) { -+ DEBUG(SSSDBG_TRACE_ALL, -+ "Checking for domain local group memberships.\n"); -+ talloc_free(tmp_ctx); -+ return; -+ } else if (ret == EOK) { -+ DEBUG(SSSDBG_TRACE_ALL, -+ "No need to check for domain local group memberships.\n"); -+ } else { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sdap_ad_check_domain_local_groups failed, " -+ "meberships to domain local groups might be missing.\n"); -+ /* do not let the request fail completely because we already have at -+ * least "some" groups */ -+ ret = EOK; -+ } - - done: - talloc_free(tmp_ctx); -@@ -3247,7 +3373,25 @@ static void sdap_get_initgr_pgid(struct tevent_req *subreq) - return; - } - -+ ret = sdap_ad_check_domain_local_groups(req); -+ if (ret == EAGAIN) { -+ DEBUG(SSSDBG_TRACE_ALL, -+ "Checking for domain local group memberships.\n"); -+ return; -+ } else if (ret == EOK) { -+ DEBUG(SSSDBG_TRACE_ALL, -+ "No need to check for domain local group memberships.\n"); -+ } else { -+ DEBUG(SSSDBG_OP_FAILURE, "sdap_ad_check_domain_local_groups failed.\n"); -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sdap_ad_check_domain_local_groups failed, " -+ "meberships to domain local groups might be missing.\n"); -+ /* do not let the request fail completely because we already have at -+ * least "some" groups */ -+ } -+ - tevent_req_done(req); -+ return; - } - - int sdap_get_initgr_recv(struct tevent_req *req) -diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c -index ad54c1fb837eb4b8e123a1c230feb697eb37bb41..1fee4ab43a6c13803a088ffa4695dde7f39b3d2b 100644 ---- a/src/providers/ldap/sdap_async_initgroups_ad.c -+++ b/src/providers/ldap/sdap_async_initgroups_ad.c -@@ -1412,6 +1412,413 @@ static errno_t sdap_ad_tokengroups_initgr_posix_recv(struct tevent_req *req) - return EOK; - } - -+struct sdap_ad_get_domain_local_groups_state { -+ struct tevent_context *ev; -+ struct sdap_id_conn_ctx *conn; -+ struct sdap_options *opts; -+ struct sdap_id_op *op; -+ struct sysdb_ctx *sysdb; -+ struct sss_domain_info *dom; -+ int dp_error; -+ -+ struct sdap_search_base **search_bases; -+ struct sysdb_attrs **groups; -+ size_t num_groups; -+ hash_table_t *group_hash; -+}; -+ -+static void -+sdap_ad_get_domain_local_groups_connect_done(struct tevent_req *subreq); -+static void sdap_ad_get_domain_local_groups_done(struct tevent_req *subreq); -+ -+struct tevent_req * -+sdap_ad_get_domain_local_groups_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct sdap_domain *local_sdom, -+ struct sdap_options *opts, -+ struct sysdb_ctx *sysdb, -+ struct sss_domain_info *dom, -+ struct sysdb_attrs **groups, -+ size_t num_groups) -+{ -+ struct sdap_ad_get_domain_local_groups_state *state; -+ struct tevent_req *req; -+ struct tevent_req *subreq; -+ struct ad_id_ctx *ad_id_ctx; -+ errno_t ret; -+ -+ req = tevent_req_create(mem_ctx, &state, -+ struct sdap_ad_get_domain_local_groups_state); -+ if (req == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); -+ return NULL; -+ } -+ -+ state->ev = ev; -+ ad_id_ctx = talloc_get_type(local_sdom->pvt, struct ad_id_ctx); -+ state->conn = ad_id_ctx->ldap_ctx; -+ state->opts = opts; -+ state->sysdb = sysdb; -+ state->dom = dom; -+ state->search_bases = state->conn->id_ctx->opts->sdom->group_search_bases; -+ state->groups = groups; -+ state->num_groups = num_groups; -+ -+ ret = sss_hash_create(state, 32, &state->group_hash); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sss_hash_create failed.\n"); -+ goto fail; -+ } -+ -+ state->op = sdap_id_op_create(state, state->conn->conn_cache); -+ if (state->op == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n"); -+ ret = ENOMEM; -+ goto fail; -+ } -+ -+ subreq = sdap_id_op_connect_send(state->op, state, &ret); -+ if (subreq == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed.\n"); -+ goto fail; -+ } -+ -+ tevent_req_set_callback(subreq, -+ sdap_ad_get_domain_local_groups_connect_done, req); -+ -+ return req; -+ -+fail: -+ tevent_req_error(req, ret); -+ tevent_req_post(req, ev); -+ return req; -+} -+ -+static void -+sdap_ad_get_domain_local_groups_connect_done(struct tevent_req *subreq) -+{ -+ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct sdap_ad_get_domain_local_groups_state *state = tevent_req_data(req, -+ struct sdap_ad_get_domain_local_groups_state); -+ int dp_error = DP_ERR_FATAL; -+ int ret; -+ -+ ret = sdap_id_op_connect_recv(subreq, &dp_error); -+ talloc_zfree(subreq); -+ -+ if (ret != EOK) { -+ state->dp_error = dp_error; -+ tevent_req_error(req, ret); -+ return; -+ } -+ subreq = rfc2307bis_nested_groups_send(state, state->ev, state->opts, -+ state->sysdb, state->dom, -+ sdap_id_op_handle(state->op), -+ state->search_bases, -+ state->groups, state->num_groups, -+ state->group_hash, 0); -+ if (subreq == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "rfc2307bis_nested_groups_send failed.\n"); -+ state->dp_error = DP_ERR_FATAL; -+ tevent_req_error(req, ENOMEM); -+ return; -+ } -+ -+ tevent_req_set_callback(subreq, -+ sdap_ad_get_domain_local_groups_done, req); -+ -+ return; -+} -+ -+struct sdap_nested_group { -+ struct sysdb_attrs *group; -+ struct sysdb_attrs **ldap_parents; -+ size_t parents_count; -+}; -+ -+static errno_t -+sdap_ad_get_domain_local_groups_parse_parents(TALLOC_CTX *mem_ctx, -+ struct sdap_nested_group *gr, -+ struct sss_domain_info *dom, -+ struct sysdb_ctx *sysdb, -+ struct sdap_options *opts, -+ const char **_sysdb_name, -+ enum sysdb_member_type *_type, -+ char ***_add_list, -+ char ***_del_list) -+{ -+ int ret; -+ size_t c; -+ char **groupnamelist = NULL; -+ struct sysdb_attrs *groups[1]; -+ enum sysdb_member_type type; -+ const char *sysdb_name; -+ const char *group_name; -+ const char *class; -+ struct sss_domain_info *obj_dom; -+ char *local_groups_base_dn; -+ char **cached_local_parents = NULL; -+ char **add_list = NULL; -+ char **del_list = NULL; -+ TALLOC_CTX *tmp_ctx; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); -+ return ENOMEM; -+ } -+ -+ local_groups_base_dn = talloc_asprintf(tmp_ctx, SYSDB_TMPL_GROUP_BASE, -+ dom->name); -+ if (local_groups_base_dn == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ if (gr->parents_count != 0) { -+ /* Store the parents if needed */ -+ ret = sdap_nested_groups_store(sysdb, dom, opts, -+ gr->ldap_parents, gr->parents_count); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "Could not save groups [%d]: %s\n", -+ ret, strerror(ret)); -+ goto done; -+ } -+ -+ ret = sysdb_attrs_primary_fqdn_list(dom, tmp_ctx, -+ gr->ldap_parents, gr->parents_count, -+ opts->group_map[SDAP_AT_GROUP_NAME].name, -+ &groupnamelist); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_primary_fqdn_list failed.\n"); -+ goto done; -+ } -+ } -+ -+ ret = sysdb_attrs_get_string(gr->group, SYSDB_NAME, &sysdb_name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sysdb_attrs_get_string failed to get SYSDB_NAME, " -+ "skipping.\n"); -+ goto done; -+ } -+ -+ ret = sysdb_attrs_get_string(gr->group, SYSDB_OBJECTCLASS, &class); -+ if (ret != EOK) { -+ /* If objectclass is missing gr->group is a nested parent found during -+ * the nested group lookup. It might not already stored in the cache. -+ */ -+ DEBUG(SSSDBG_TRACE_LIBS, -+ "sysdb_attrs_get_string failed to get SYSDB_OBJECTCLASS " -+ "for [%s], assuming group.\n", sysdb_name); -+ -+ /* make sure group exists in cache */ -+ groups[0]= gr->group; -+ ret = sdap_nested_groups_store(sysdb, dom, opts, groups, 1); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "Could not save groups [%d]: %s\n", -+ ret, strerror(ret)); -+ goto done; -+ } -+ -+ /* Since the object is coming from LDAP it cannot have the internal -+ * fully-qualified name, so we can expand it unconditionally. */ -+ group_name = NULL; -+ ret = sysdb_attrs_primary_name(dom->sysdb, gr->group, -+ opts->group_map[SDAP_AT_GROUP_NAME].name, -+ &group_name); -+ if (ret != EOK || group_name == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "Could not determine primary name\n"); -+ group_name = sysdb_name; -+ } -+ -+ group_name = sss_create_internal_fqname(tmp_ctx, group_name, -+ dom->name); -+ if (group_name != NULL) { -+ sysdb_name = group_name; -+ } -+ -+ type = SYSDB_MEMBER_GROUP; -+ } else { -+ if (class != NULL && strcmp(class, SYSDB_USER_CLASS) == 0) { -+ type = SYSDB_MEMBER_USER; -+ } else { -+ type = SYSDB_MEMBER_GROUP; -+ } -+ } -+ -+ /* We need to get the cached list of groups form the local domain the -+ * object is a member of to compare them with the current list just -+ * retrieved (groupnamelist). Even if this list is empty we have to -+ * proceed because the membership might have been removed recently on the -+ * server. */ -+ -+ obj_dom = find_domain_by_object_name(get_domains_head(dom), -+ sysdb_name); -+ if (obj_dom == NULL) { -+ obj_dom = dom; -+ DEBUG(SSSDBG_OP_FAILURE, "Cannot find domain for [%s], " -+ "trying with local domain [%s].\n", -+ sysdb_name, obj_dom->name); -+ } -+ -+ ret = sysdb_get_direct_parents(tmp_ctx, obj_dom, dom, type, sysdb_name, -+ &cached_local_parents); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE,"sysdb_get_direct_parents failed.\n"); -+ goto done; -+ } -+ -+ if (cached_local_parents != NULL && cached_local_parents[0] == NULL) { -+ talloc_zfree(cached_local_parents); -+ } -+ -+ if (DEBUG_IS_SET(SSSDBG_TRACE_ALL)) { -+ if (cached_local_parents != NULL) { -+ for (c = 0; cached_local_parents[c] != NULL; c++) { -+ DEBUG(SSSDBG_TRACE_ALL, "[%s] cached_local_parents [%s].\n", -+ sysdb_name, cached_local_parents[c]); -+ } -+ } -+ -+ if (groupnamelist != NULL) { -+ for (c = 0; groupnamelist[c] != NULL; c++) { -+ DEBUG(SSSDBG_TRACE_ALL, "[%s] groupnamelist [%s].\n", -+ sysdb_name, groupnamelist[c]); -+ } -+ } -+ } -+ -+ ret = diff_string_lists(tmp_ctx, cached_local_parents, groupnamelist, -+ &del_list, &add_list, NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "diff_string_lists failed.\n"); -+ goto done; -+ } -+ -+ if (DEBUG_IS_SET(SSSDBG_TRACE_ALL)) { -+ if (add_list != NULL) { -+ for (c = 0; add_list[c] != NULL; c++) { -+ DEBUG(SSSDBG_TRACE_ALL, "add: [%s] will be member of [%s].\n", -+ sysdb_name, add_list[c]); -+ } -+ } -+ if (del_list != NULL) { -+ for (c = 0; del_list[c] != NULL; c++) { -+ DEBUG(SSSDBG_TRACE_ALL, "del: [%s] was member of [%s].\n", -+ sysdb_name, del_list[c]); -+ } -+ } -+ } -+ -+ *_type = type; -+ *_sysdb_name = talloc_steal(mem_ctx, sysdb_name); -+ *_add_list = talloc_steal(mem_ctx, groupnamelist); -+ *_del_list = talloc_steal(mem_ctx, del_list); -+ ret = EOK; -+ -+done: -+ talloc_free(tmp_ctx); -+ -+ return ret; -+} -+ -+static void sdap_ad_get_domain_local_groups_done(struct tevent_req *subreq) -+{ -+ -+ struct tevent_req *req = tevent_req_callback_data(subreq, -+ struct tevent_req); -+ struct sdap_ad_get_domain_local_groups_state *state = tevent_req_data(req, -+ struct sdap_ad_get_domain_local_groups_state); -+ int ret; -+ int hret; -+ unsigned long count; -+ hash_value_t *values = NULL; -+ struct sdap_nested_group *gr; -+ size_t c; -+ const char *sysdb_name = NULL; -+ enum sysdb_member_type type; -+ char **add_list = NULL; -+ char **del_list = NULL; -+ -+ ret = rfc2307bis_nested_groups_recv(subreq); -+ talloc_zfree(subreq); -+ if (ret != EOK) { -+ tevent_req_error(req, ret); -+ return; -+ } -+ -+ hret = hash_values(state->group_hash, &count, &values); -+ if (hret != HASH_SUCCESS) { -+ DEBUG(SSSDBG_OP_FAILURE, "hash_values failed.\n"); -+ ret = EIO; -+ goto done; -+ } -+ -+ for (c = 0; c < count; c++) { -+ gr = talloc_get_type(values[c].ptr, -+ struct sdap_nested_group); -+ -+ /* The values from the hash are either user or group objects returned -+ * by sysdb_initgroups() which where used to start the request or -+ * nested parents found during the request. The nested parents contain -+ * the processed LDAP data and can be identified by a missing -+ * objectclass attribute. */ -+ ret = sdap_ad_get_domain_local_groups_parse_parents(state, gr, -+ state->dom, -+ state->sysdb, -+ state->opts, -+ &sysdb_name, -+ &type, -+ &add_list, -+ &del_list); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "sdap_ad_get_domain_local_groups_parse_parents failed.\n"); -+ continue; -+ } -+ -+ if ((add_list == NULL && del_list == NULL) -+ || (add_list == NULL && del_list != NULL && del_list[0] == NULL) -+ || (add_list != NULL && add_list[0] == NULL && del_list == NULL) -+ || (add_list != NULL && add_list[0] == NULL -+ && del_list != NULL && del_list[0] == NULL) ) { -+ continue; -+ } -+ -+ DEBUG(SSSDBG_TRACE_INTERNAL, "Updating domain local memberships for %s\n", -+ sysdb_name); -+ ret = sysdb_update_members(state->dom, sysdb_name, type, -+ (const char *const *) add_list, -+ (const char *const *) del_list); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_members failed.\n"); -+ goto done; -+ } -+ } -+ -+ ret = EOK; -+done: -+ talloc_zfree(values); -+ -+ if (ret == EOK) { -+ tevent_req_done(req); -+ } else { -+ tevent_req_error(req, ret); -+ } -+ -+ return; -+} -+ -+errno_t sdap_ad_get_domain_local_groups_recv(struct tevent_req *req) -+{ -+ TEVENT_REQ_RETURN_ON_ERROR(req); -+ return EOK; -+} -+ - struct sdap_ad_tokengroups_initgroups_state { - bool use_id_mapping; - struct sss_domain_info *domain; -diff --git a/src/providers/ldap/sdap_async_private.h b/src/providers/ldap/sdap_async_private.h -index 4af4f7144d8855e4ed705f6a64e0a7818bc0b9a9..266bc03115e2bdd6a283f5f7da565fd00d3a77be 100644 ---- a/src/providers/ldap/sdap_async_private.h -+++ b/src/providers/ldap/sdap_async_private.h -@@ -173,4 +173,14 @@ errno_t sdap_nested_groups_store(struct sysdb_ctx *sysdb, - struct sysdb_attrs **groups, - unsigned long count); - -+struct tevent_req * -+sdap_ad_get_domain_local_groups_send(TALLOC_CTX *mem_ctx, -+ struct tevent_context *ev, -+ struct sdap_domain *local_sdom, -+ struct sdap_options *opts, -+ struct sysdb_ctx *sysdb, -+ struct sss_domain_info *dom, -+ struct sysdb_attrs **groups, -+ size_t num_groups); -+errno_t sdap_ad_get_domain_local_groups_recv(struct tevent_req *req); - #endif /* _SDAP_ASYNC_PRIVATE_H_ */ --- -2.7.4 - diff --git a/SOURCES/0146-TESTS-Add-unit-tests-for-cfg-validation.patch b/SOURCES/0146-TESTS-Add-unit-tests-for-cfg-validation.patch new file mode 100644 index 0000000..dae5f6c --- /dev/null +++ b/SOURCES/0146-TESTS-Add-unit-tests-for-cfg-validation.patch @@ -0,0 +1,328 @@ +From 897216b87352e9f80181be6f1a036163c599ba46 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Fri, 26 May 2017 19:58:48 +0200 +Subject: [PATCH 146/152] TESTS: Add unit tests for cfg validation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add infrastructure for unit tests for validators. + +Reviewed-by: Lukáš Slebodník +--- + Makefile.am | 16 +++ + src/tests/cmocka/test_config_check.c | 268 +++++++++++++++++++++++++++++++++++ + 2 files changed, 284 insertions(+) + create mode 100644 src/tests/cmocka/test_config_check.c + +diff --git a/Makefile.am b/Makefile.am +index a6279133b56dcd5bcbd1306ae8f2ce18d90c2c12..503c8cfd795b503f566431c08a56a56147180322 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -252,6 +252,7 @@ if HAVE_CMOCKA + dp_opt_tests \ + responder-get-domains-tests \ + sbus-internal-tests \ ++ config_check-tests \ + sss_sifp-tests \ + test_search_bases \ + test_ldap_auth \ +@@ -2429,6 +2430,21 @@ sbus_internal_tests_LDADD = \ + libsss_debug.la \ + libsss_test_common.la + ++config_check_tests_SOURCES = \ ++ src/tests/cmocka/test_config_check.c \ ++ $(NULL) ++config_check_tests_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(NULL) ++config_check_tests_LDADD = \ ++ $(CMOCKA_LIBS) \ ++ $(POPT_LIBS) \ ++ $(INI_CONFIG_LIBS) \ ++ $(TALLOC_LIBS) \ ++ $(SSSD_INTERNAL_LTLIBS) \ ++ libsss_test_common.la \ ++ $(NULL) ++ + test_find_uid_SOURCES = \ + src/tests/cmocka/test_find_uid.c \ + src/util/find_uid.c \ +diff --git a/src/tests/cmocka/test_config_check.c b/src/tests/cmocka/test_config_check.c +new file mode 100644 +index 0000000000000000000000000000000000000000..8fc0b01f3ef3fe03152efd979a3e96c21ba567cc +--- /dev/null ++++ b/src/tests/cmocka/test_config_check.c +@@ -0,0 +1,268 @@ ++/* ++ Authors: ++ Michal Zidek ++ ++ Copyright (C) 2017 Red Hat ++ ++ Config file validators test ++ ++ 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 . ++*/ ++ ++#include ++#include ++#include ++ ++#include "util/sss_ini.h" ++#include "tests/cmocka/common_mock.h" ++ ++#ifdef HAVE_LIBINI_CONFIG_V1_3 ++ ++#define RULES_PATH ABS_SRC_DIR"/src/config/cfg_rules.ini" ++ ++struct sss_ini_initdata { ++ char **error_list; ++ struct ref_array *ra_success_list; ++ struct ref_array *ra_error_list; ++ struct ini_cfgobj *sssd_config; ++ struct value_obj *obj; ++ const struct stat *cstat; ++ struct ini_cfgfile *file; ++}; ++ ++void config_check_test_common(const char *cfg_string, ++ size_t num_errors_expected, ++ const char **errors_expected) ++{ ++ struct sss_ini_initdata *init_data; ++ size_t num_errors; ++ char **strs; ++ int ret; ++ TALLOC_CTX *tmp_ctx; ++ ++ tmp_ctx = talloc_new(NULL); ++ assert_non_null(tmp_ctx); ++ ++ init_data = sss_ini_initdata_init(tmp_ctx); ++ ++ ret = ini_config_file_from_mem(discard_const(cfg_string), ++ strlen(cfg_string), ++ &init_data->file); ++ assert_int_equal(ret, EOK); ++ ++ ret = ini_config_create(&(init_data->sssd_config)); ++ assert_int_equal(ret, EOK); ++ ++ ret = ini_config_parse(init_data->file, ++ INI_STOP_ON_ANY, ++ INI_MV1S_OVERWRITE, ++ INI_PARSE_NOWRAP, ++ init_data->sssd_config); ++ assert_int_equal(ret, EOK); ++ ++ ret = sss_ini_call_validators_strs(tmp_ctx, init_data, ++ RULES_PATH, ++ &strs, &num_errors); ++ assert_int_equal(ret, EOK); ++ ++ /* Output from validators */ ++ for (int i = 0; i < num_errors; i++) { ++ /* Keep this printf loop for faster debugging */ ++ printf("%s\n", strs[i]); ++ } ++ ++ for (int i = 0; i < num_errors && i <= num_errors_expected; i++) { ++ assert_string_equal(strs[i], errors_expected[i]); ++ } ++ ++ /* Check if the number of errors is the same */ ++ assert_int_equal(num_errors_expected, num_errors); ++ ++ sss_ini_close_file(init_data); ++ sss_ini_config_destroy(init_data); ++ talloc_free(tmp_ctx); ++} ++ ++void config_check_test_bad_section_name(void **state) ++{ ++ char cfg_str[] = "[sssssssssssssd]"; ++ const char *expected_errors[] = { ++ "[rule/allowed_sections]: Section [sssssssssssssd] is not allowed. " ++ "Check for typos.", ++ }; ++ ++ config_check_test_common(cfg_str, 1, expected_errors); ++} ++ ++void config_check_test_bad_sssd_option_name(void **state) ++{ ++ char cfg_str[] = "[sssd]\n" ++ "debug_leTYPOvel = 10\n"; ++ const char *expected_errors[] = { ++ "[rule/allowed_sssd_options]: Attribute 'debug_leTYPOvel' is not " ++ "allowed in section 'sssd'. Check for typos.", ++ }; ++ ++ config_check_test_common(cfg_str, 1, expected_errors); ++} ++ ++void config_check_test_bad_pam_option_name(void **state) ++{ ++ char cfg_str[] = "[pam]\n" ++ "debug_leTYPOvel = 10\n"; ++ const char *expected_errors[] = { ++ "[rule/allowed_pam_options]: Attribute 'debug_leTYPOvel' is not " ++ "allowed in section 'pam'. Check for typos.", ++ }; ++ ++ config_check_test_common(cfg_str, 1, expected_errors); ++} ++ ++void config_check_test_bad_nss_option_name(void **state) ++{ ++ char cfg_str[] = "[nss]\n" ++ "debug_leTYPOvel = 10\n"; ++ const char *expected_errors[] = { ++ "[rule/allowed_nss_options]: Attribute 'debug_leTYPOvel' is not " ++ "allowed in section 'nss'. Check for typos.", ++ }; ++ ++ config_check_test_common(cfg_str, 1, expected_errors); ++} ++ ++void config_check_test_bad_pac_option_name(void **state) ++{ ++ char cfg_str[] = "[pac]\n" ++ "debug_leTYPOvel = 10\n"; ++ const char *expected_errors[] = { ++ "[rule/allowed_pac_options]: Attribute 'debug_leTYPOvel' is not " ++ "allowed in section 'pac'. Check for typos.", ++ }; ++ ++ config_check_test_common(cfg_str, 1, expected_errors); ++} ++ ++void config_check_test_bad_ifp_option_name(void **state) ++{ ++ char cfg_str[] = "[ifp]\n" ++ "debug_leTYPOvel = 10\n"; ++ const char *expected_errors[] = { ++ "[rule/allowed_ifp_options]: Attribute 'debug_leTYPOvel' is not " ++ "allowed in section 'ifp'. Check for typos.", ++ }; ++ ++ config_check_test_common(cfg_str, 1, expected_errors); ++} ++ ++void config_check_test_bad_domain_option_name(void **state) ++{ ++ char cfg_str[] = "[domain/A.test\n" ++ "debug_leTYPOvel = 10\n"; ++ const char *expected_errors[] = { ++ "[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not " ++ "allowed in section 'domain/A.test'. Check for typos.", ++ }; ++ ++ config_check_test_common(cfg_str, 1, expected_errors); ++} ++ ++void config_check_test_bad_appdomain_option_name(void **state) ++{ ++ char cfg_str[] = "[application/myapp\n" ++ "debug_leTYPOvel = 10\n"; ++ const char *expected_errors[] = { ++ "[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not " ++ "allowed in section 'application/myapp'. Check for typos.", ++ }; ++ ++ config_check_test_common(cfg_str, 1, expected_errors); ++} ++ ++void config_check_test_bad_subdom_option_name(void **state) ++{ ++ char cfg_str[] = "[domain/A.test/B.A.test]\n" ++ "debug_leTYPOvel = 10\n"; ++ const char *expected_errors[] = { ++ "[rule/allowed_sssd_options]: Attribute 'debug_leTYPOvel' is not " ++ "allowed in section 'domain/A.test/B.A.test'. Check for typos.", ++ }; ++ ++ config_check_test_common(cfg_str, 1, expected_errors); ++} ++ ++void config_check_test_good_sections(void **state) ++{ ++ char cfg_str[] = "[sssd]\n" ++ "[pam]\n" ++ "[nss]\n" ++ "[domain/testdom.test]\n" ++ "[domain/testdom.test/testsubdom.testdom.test]\n" ++ "[application/myapp]\n" ++ "[secrets]\n" ++ "[ifp]\n" ++ "[pac]\n"; ++ const char *expected_errors[] = { NULL }; ++ ++ config_check_test_common(cfg_str, 0, expected_errors); ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ poptContext pc; ++ int opt; ++ struct poptOption long_options[] = { ++ POPT_AUTOHELP ++ SSSD_DEBUG_OPTS ++ POPT_TABLEEND ++ }; ++ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test(config_check_test_bad_section_name), ++ cmocka_unit_test(config_check_test_bad_sssd_option_name), ++ cmocka_unit_test(config_check_test_bad_pam_option_name), ++ cmocka_unit_test(config_check_test_bad_nss_option_name), ++ cmocka_unit_test(config_check_test_bad_pac_option_name), ++ cmocka_unit_test(config_check_test_bad_ifp_option_name), ++ cmocka_unit_test(config_check_test_good_sections), ++ }; ++ ++ /* Set debug level to invalid value so we can decide if -d 0 was used. */ ++ debug_level = SSSDBG_INVALID; ++ ++ pc = poptGetContext(argv[0], argc, argv, long_options, 0); ++ while ((opt = poptGetNextOpt(pc)) != -1) { ++ switch (opt) { ++ default: ++ fprintf(stderr, "\nInvalid option %s: %s\n\n", ++ poptBadOption(pc, 0), poptStrerror(opt)); ++ poptPrintUsage(pc, stderr, 0); ++ return 1; ++ } ++ } ++ poptFreeContext(pc); ++ ++ DEBUG_CLI_INIT(debug_level); ++ tests_set_cwd(); ++ return cmocka_run_group_tests(tests, NULL, NULL); ++} ++ ++#else /* !HAVE_LIBINI_CONFIG_V1_3 */ ++ ++int main(int argc, const char *argv[]) ++{ ++ fprintf(stderr, "%s requires newer version of libini\n", argv[0]); ++ return 0; ++} ++ ++#endif /* HAVE_LIBINI_CONFIG_V1_3 */ +-- +2.9.4 + diff --git a/SOURCES/0147-IPA-Initialize-a-boolean-control-value.patch b/SOURCES/0147-IPA-Initialize-a-boolean-control-value.patch deleted file mode 100644 index 7a6ee0e..0000000 --- a/SOURCES/0147-IPA-Initialize-a-boolean-control-value.patch +++ /dev/null @@ -1,60 +0,0 @@ -From ffe5898f9588ba4ec3258807d377a82e52c38c67 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Tue, 4 Oct 2016 10:45:43 +0200 -Subject: [PATCH 147/149] IPA: Initialize a boolean control value -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -without this patch, valgrind was reporting: -==30955== Conditional jump or move depends on uninitialised value(s) -==30955== at 0xDBBACC3: ipa_subdomains_slave_search_done (ipa_subdomains.c:1111) -==30955== by 0xE73B34D: sdap_search_bases_ex_done (sdap_ops.c:222) -==30955== by 0xE6FFA98: sdap_get_generic_done (sdap_async.c:1872) -==30955== by 0xE6FF4E2: generic_ext_search_handler (sdap_async.c:1689) -==30955== by 0xE6FF840: sdap_get_and_parse_generic_done (sdap_async.c:1797) -==30955== by 0xE6FEFB5: sdap_get_generic_op_finished (sdap_async.c:1579) -==30955== by 0xE6FB1D2: sdap_process_message (sdap_async.c:353) -==30955== by 0xE6FAD51: sdap_process_result (sdap_async.c:197) -==30955== by 0xE6FAA14: sdap_ldap_next_result (sdap_async.c:145) -==30955== by 0x8E157FF: tevent_common_loop_timer_delay (tevent_timed.c:341) -==30955== by 0x8E16809: epoll_event_loop_once (tevent_epoll.c:911) -==30955== by 0x8E14F09: std_event_loop_once (tevent_standard.c:114) -==30955== - -Resolves: -https://fedorahosted.org/sssd/ticket/3213 - -Reviewed-by: Fabiano Fidêncio ---- - src/providers/ipa/ipa_subdomains.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c -index 4e5bceb8c761bf4476928168d620baf2beb62ad5..d02d2d5c05904c54c5e1997aece82f940b7334ee 100644 ---- a/src/providers/ipa/ipa_subdomains.c -+++ b/src/providers/ipa/ipa_subdomains.c -@@ -482,6 +482,11 @@ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx, - memset(handled, 0, sizeof(bool) * count); - h = 0; - -+ if (changes == NULL) { -+ return EINVAL; -+ } -+ *changes = false; -+ - /* check existing subdomains */ - for (dom = get_next_domain(parent, SSS_GND_DESCEND); - dom && IS_SUBDOMAIN(dom); /* if we get back to a parent, stop */ -@@ -1084,7 +1089,7 @@ static void ipa_subdomains_slave_search_done(struct tevent_req *subreq) - struct tevent_req *req; - struct sysdb_attrs **reply; - size_t reply_count; -- bool has_changes; -+ bool has_changes = false; - errno_t ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); --- -2.7.4 - diff --git a/SOURCES/0147-MAN-Fix-typo-in-trusted-domain-section.patch b/SOURCES/0147-MAN-Fix-typo-in-trusted-domain-section.patch new file mode 100644 index 0000000..3d015fc --- /dev/null +++ b/SOURCES/0147-MAN-Fix-typo-in-trusted-domain-section.patch @@ -0,0 +1,29 @@ +From 8a6087c3b53bbe26cb212e60af74da981529f57d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Tue, 30 May 2017 12:05:39 +0200 +Subject: [PATCH 147/152] MAN: Fix typo in trusted domain section +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Lukáš Slebodník +--- + src/man/sssd.conf.5.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index c4e30396f16c40db37af2f56ac218b6e37201ef7..a35f2807eac8bb89d6cb1dd0a48f738d71a7578f 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -2912,7 +2912,7 @@ ldap_user_extra_attrs = phone:telephoneNumber + + Some options used in the domain section can also be used in the + trusted domain section, that is, in a section called +- [domain/DOMAIN_NAME]/TRUSTED_DOMAIN_NAME]. ++ [domain/DOMAIN_NAME/TRUSTED_DOMAIN_NAME]. + Currently supported options in the trusted domain section are: + + ldap_search_base, +-- +2.9.4 + diff --git a/SOURCES/0148-IPA-AD-check-auth-ctx-before-using-it.patch b/SOURCES/0148-IPA-AD-check-auth-ctx-before-using-it.patch deleted file mode 100644 index d6ad243..0000000 --- a/SOURCES/0148-IPA-AD-check-auth-ctx-before-using-it.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 1083c5f195ecf29435f24e136cf6470992614494 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 8 Nov 2016 11:51:57 +0100 -Subject: [PATCH 148/149] IPA/AD: check auth ctx before using it - -In e6b6b9fa79c67d7d2698bc7e33d2e2f6bb53d483 a feature was introduced to -set the 'canonicalize' option in the system-wide Kerberos configuration -according to the settings in SSSD if the AD or IPA provider were used. -Unfortunately the patch implied that the auth provider is the same as -the id provider which might not always be the case. A different auth -provider caused a crash in the backend which is fixed by this patch. - -Resolves https://fedorahosted.org/sssd/ticket/3234 - -Reviewed-by: Petr Cech -(cherry picked from commit ea11ed3ea6291488dd762033246edc4ce3951aeb) ---- - src/providers/ad/ad_subdomains.c | 13 +++++++++++-- - src/providers/ipa/ipa_subdomains.c | 20 +++++++++++++++++--- - 2 files changed, 28 insertions(+), 5 deletions(-) - -diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c -index 52bf5361fa8de02c7165cbc3513a923ec018fc15..5e57d218c072a2627f165ae072cb761e1a146048 100644 ---- a/src/providers/ad/ad_subdomains.c -+++ b/src/providers/ad/ad_subdomains.c -@@ -618,14 +618,23 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *subdoms_ctx) - { - const char *path; - errno_t ret; -- bool canonicalize; -+ bool canonicalize = false; - - path = dp_opt_get_string(subdoms_ctx->ad_id_ctx->ad_options->basic, - AD_KRB5_CONFD_PATH); - -- canonicalize = dp_opt_get_bool( -+ if (subdoms_ctx->ad_id_ctx->ad_options->auth_ctx != NULL -+ && subdoms_ctx->ad_id_ctx->ad_options->auth_ctx->opts != NULL) { -+ canonicalize = dp_opt_get_bool( - subdoms_ctx->ad_id_ctx->ad_options->auth_ctx->opts, - KRB5_CANONICALIZE); -+ } else { -+ DEBUG(SSSDBG_CONF_SETTINGS, "Auth provider data is not available, " -+ "most probably because the auth provider " -+ "is not 'ad'. Kerberos configuration " -+ "snippet to set the 'canonicalize' option " -+ "will not be created.\n"); -+ } - - ret = sss_write_krb5_conf_snippet(path, canonicalize); - if (ret != EOK) { -diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c -index d02d2d5c05904c54c5e1997aece82f940b7334ee..eb1bc92691da9e82e07595ed84eea35fff78d1a5 100644 ---- a/src/providers/ipa/ipa_subdomains.c -+++ b/src/providers/ipa/ipa_subdomains.c -@@ -73,16 +73,30 @@ static errno_t - ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx) - { - errno_t ret; -+ bool canonicalize = false; - - DEBUG(SSSDBG_TRACE_INTERNAL, - "Re-initializing domain %s\n", ctx->be_ctx->domain->name); - -+ if (ctx->ipa_id_ctx->ipa_options->auth_ctx != NULL -+ && ctx->ipa_id_ctx->ipa_options->auth_ctx->krb5_auth_ctx != NULL -+ && ctx->ipa_id_ctx->ipa_options->auth_ctx->krb5_auth_ctx->opts != NULL -+ ) { -+ canonicalize = dp_opt_get_bool( -+ ctx->ipa_id_ctx->ipa_options->auth_ctx->krb5_auth_ctx->opts, -+ KRB5_CANONICALIZE); -+ } else { -+ DEBUG(SSSDBG_CONF_SETTINGS, "Auth provider data is not available, " -+ "most probably because the auth provider " -+ "is not 'ipa'. Kerberos configuration " -+ "snippet to set the 'canonicalize' option " -+ "will not be created.\n"); -+ } -+ - ret = sss_write_krb5_conf_snippet( - dp_opt_get_string(ctx->ipa_id_ctx->ipa_options->basic, - IPA_KRB5_CONFD_PATH), -- dp_opt_get_bool( -- ctx->ipa_id_ctx->ipa_options->auth_ctx->krb5_auth_ctx->opts, -- KRB5_CANONICALIZE)); -+ canonicalize); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, "sss_write_krb5_conf_snippet failed.\n"); - /* Just continue */ --- -2.7.4 - diff --git a/SOURCES/0148-VALIDATORS-Change-regex-for-app-domains.patch b/SOURCES/0148-VALIDATORS-Change-regex-for-app-domains.patch new file mode 100644 index 0000000..3ca41ad --- /dev/null +++ b/SOURCES/0148-VALIDATORS-Change-regex-for-app-domains.patch @@ -0,0 +1,36 @@ +From b32bb7226b89777063e4cd49373ce86353abd74c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Tue, 30 May 2017 13:17:45 +0200 +Subject: [PATCH 148/152] VALIDATORS: Change regex for app domains +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use the same restrictions for application domains that we use for +normal domain. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3356 + +Reviewed-by: Lukáš Slebodník +--- + src/config/cfg_rules.ini | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 628f2e0e0a040bad5128d00d9348aa91170ed704..2c8c0cb98ed039c374c827775798f61369c1521e 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -13,7 +13,8 @@ section = kcm + section_re = ^secrets/users/[0-9]\+$ + section_re = ^domain/[^/\@]\+$ + section_re = ^domain/[^/\@]\+/[^/\@]\+$ +-section_re = ^application/.*$ ++section_re = ^application/[^/\@]\+$ ++ + + [rule/allowed_sssd_options] + validator = ini_allowed_options +-- +2.9.4 + diff --git a/SOURCES/0149-Qualify-ghost-user-attribute-in-case-ldap_group_nest.patch b/SOURCES/0149-Qualify-ghost-user-attribute-in-case-ldap_group_nest.patch deleted file mode 100644 index 9809cf2..0000000 --- a/SOURCES/0149-Qualify-ghost-user-attribute-in-case-ldap_group_nest.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 362911a85e3aa244cdbdf75b8b4131bb26396d19 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 9 Nov 2016 11:59:10 +0100 -Subject: [PATCH 149/149] Qualify ghost user attribute in case - ldap_group_nesting_level is set to 0 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When the sssd is set to not resolve nested groups with RFC2307bis, then -the LDAP provider takes a different path. We didn't qualify the ghost -users in this case. - -Resolves: -https://fedorahosted.org/sssd/ticket/3236 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 538a7f1dd8339b90e0cfc64e7919a34d1d5c10d3) ---- - src/providers/ldap/sdap_async_groups.c | 15 +++++++++++---- - 1 file changed, 11 insertions(+), 4 deletions(-) - -diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c -index 72760b75acae4cb6ce15c72f16dae8e859d89847..49a1934b2604e6a6af8ee8e8b3d1f88d2029658d 100644 ---- a/src/providers/ldap/sdap_async_groups.c -+++ b/src/providers/ldap/sdap_async_groups.c -@@ -1659,7 +1659,7 @@ static void sdap_process_group_members(struct tevent_req *subreq) - struct sdap_process_group_state *state = - tevent_req_data(req, struct sdap_process_group_state); - struct ldb_message_element *el; -- uint8_t* name_string; -+ char *name_string; - - state->check_count--; - DEBUG(SSSDBG_TRACE_ALL, "Members remaining: %zu\n", state->check_count); -@@ -1685,11 +1685,18 @@ static void sdap_process_group_members(struct tevent_req *subreq) - goto next; - } - -- name_string = el[0].values[0].data; -+ name_string = sss_create_internal_fqname(state, -+ (const char *) el[0].values[0].data, -+ state->dom->name); -+ if (name_string == NULL) { -+ ret = ENOMEM; -+ goto next; -+ } -+ - state->ghost_dns->values[state->ghost_dns->num_values].data = -- talloc_steal(state->ghost_dns->values, name_string); -+ talloc_steal(state->ghost_dns->values, (uint8_t *) name_string); - state->ghost_dns->values[state->ghost_dns->num_values].length = -- strlen((char *)name_string); -+ strlen(name_string); - state->ghost_dns->num_values++; - - next: --- -2.7.4 - diff --git a/SOURCES/0149-VALIDATORS-Detect-inherit_from-in-normal-domain.patch b/SOURCES/0149-VALIDATORS-Detect-inherit_from-in-normal-domain.patch new file mode 100644 index 0000000..b99885a --- /dev/null +++ b/SOURCES/0149-VALIDATORS-Detect-inherit_from-in-normal-domain.patch @@ -0,0 +1,154 @@ +From b94b578fac8f94d42fd6fb691438d2dbe5248309 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Wed, 31 May 2017 14:21:02 +0200 +Subject: [PATCH 149/152] VALIDATORS: Detect inherit_from in normal domain +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds new sssd specific validator. In the future we +can add more checks in it, but currently it only checks if +the option inherit_from is used on normal domain and reports +error if it is. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3356 + +Reviewed-by: Lukáš Slebodník +--- + src/config/cfg_rules.ini | 3 ++ + src/tests/cmocka/test_config_check.c | 22 +++++++++++++++ + src/util/sss_ini.c | 53 +++++++++++++++++++++++++++++++++++- + 3 files changed, 77 insertions(+), 1 deletion(-) + +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 2c8c0cb98ed039c374c827775798f61369c1521e..744446478e5d5489cd86d8e15ce8e178cf5e3a91 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -711,3 +711,6 @@ option = ad_server + option = ad_backup_server + option = ad_site + option = use_fully_qualified_names ++ ++[rule/sssd_checks] ++validator = sssd_checks +diff --git a/src/tests/cmocka/test_config_check.c b/src/tests/cmocka/test_config_check.c +index 8fc0b01f3ef3fe03152efd979a3e96c21ba567cc..bab3226c004fb9495471af7c7d3f6861552d8a86 100644 +--- a/src/tests/cmocka/test_config_check.c ++++ b/src/tests/cmocka/test_config_check.c +@@ -217,6 +217,27 @@ void config_check_test_good_sections(void **state) + config_check_test_common(cfg_str, 0, expected_errors); + } + ++void config_check_test_inherit_from_in_normal_dom(void **state) ++{ ++ char cfg_str[] = "[domain/A.test]\n" ++ "inherit_from = domain\n"; ++ const char *expected_errors[] = { ++ "[rule/sssd_checks]: Attribute 'inherit_from' is not allowed in " ++ "section 'domain/A.test'. Check for typos.", ++ }; ++ ++ config_check_test_common(cfg_str, 1, expected_errors); ++} ++ ++void config_check_test_inherit_from_in_app_dom(void **state) ++{ ++ char cfg_str[] = "[application/A.test]\n" ++ "inherit_from = domain\n"; ++ const char *expected_errors[] = { NULL }; ++ ++ config_check_test_common(cfg_str, 0, expected_errors); ++} ++ + int main(int argc, const char *argv[]) + { + poptContext pc; +@@ -235,6 +256,7 @@ int main(int argc, const char *argv[]) + cmocka_unit_test(config_check_test_bad_pac_option_name), + cmocka_unit_test(config_check_test_bad_ifp_option_name), + cmocka_unit_test(config_check_test_good_sections), ++ cmocka_unit_test(config_check_test_inherit_from_in_normal_dom), + }; + + /* Set debug level to invalid value so we can decide if -d 0 was used. */ +diff --git a/src/util/sss_ini.c b/src/util/sss_ini.c +index e56006c05555d6e0c5e726e83771abce5a72b139..175a4cfaba7ea964aee174e928d5e3c1e81de638 100644 +--- a/src/util/sss_ini.c ++++ b/src/util/sss_ini.c +@@ -561,12 +561,63 @@ error: + } + + #ifdef HAVE_LIBINI_CONFIG_V1_3 ++/* Here we can put custom SSSD specific checks that can not be implemented ++ * using libini validators */ ++static int custom_sssd_checks(const char *rule_name, ++ struct ini_cfgobj *rules_obj, ++ struct ini_cfgobj *config_obj, ++ struct ini_errobj *errobj, ++ void **data) ++{ ++ char **cfg_sections = NULL; ++ int num_cfg_sections; ++ struct value_obj *vo = NULL; ++ char dom_prefix[] = "domain/"; ++ int ret; ++ ++ /* Get all sections in configuration */ ++ cfg_sections = ini_get_section_list(config_obj, &num_cfg_sections, &ret); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ /* Check if a normal domain section (not application domains) has option ++ * inherit_from and report error if it does */ ++ for (int i = 0; i < num_cfg_sections; i++) { ++ if (strncmp(dom_prefix, cfg_sections[i], strlen(dom_prefix)) == 0) { ++ ret = ini_get_config_valueobj(cfg_sections[i], ++ "inherit_from", ++ config_obj, ++ INI_GET_NEXT_VALUE, ++ &vo); ++ if (vo != NULL) { ++ ret = ini_errobj_add_msg(errobj, ++ "Attribute 'inherit_from' is not " ++ "allowed in section '%s'. Check for " ++ "typos.", ++ cfg_sections[i]); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ } ++ } ++ ++ ret = EOK; ++done: ++ ini_free_section_list(cfg_sections); ++ return EOK; ++} ++ + static int sss_ini_call_validators_errobj(struct sss_ini_initdata *data, + const char *rules_path, + struct ini_errobj *errobj) + { + int ret; + struct ini_cfgobj *rules_cfgobj = NULL; ++ struct ini_validator custom_sssd = { "sssd_checks", custom_sssd_checks, ++ NULL }; ++ struct ini_validator *sss_validators[] = { &custom_sssd, NULL }; + + ret = ini_rules_read_from_file(rules_path, &rules_cfgobj); + if (ret != EOK) { +@@ -575,7 +626,7 @@ static int sss_ini_call_validators_errobj(struct sss_ini_initdata *data, + goto done; + } + +- ret = ini_rules_check(rules_cfgobj, data->sssd_config, NULL, errobj); ++ ret = ini_rules_check(rules_cfgobj, data->sssd_config, sss_validators, errobj); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "ini_rules_check failed %d [%s]\n", ret, strerror(ret)); +-- +2.9.4 + diff --git a/SOURCES/0150-SYSDB-Split-sysdb_try_to_find_expected_dn-into-small.patch b/SOURCES/0150-SYSDB-Split-sysdb_try_to_find_expected_dn-into-small.patch deleted file mode 100644 index ee1e343..0000000 --- a/SOURCES/0150-SYSDB-Split-sysdb_try_to_find_expected_dn-into-small.patch +++ /dev/null @@ -1,342 +0,0 @@ -From 57a070724f42bb01b8bb3f866e906f40643e0421 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Fri, 28 Oct 2016 13:46:02 +0200 -Subject: [PATCH 150/151] SYSDB: Split sysdb_try_to_find_expected_dn() into - smaller functions - -The function sysdb_try_to_find_expected_dn was performing several matching -algorithms and thus it was getting big and hard to extend. This patch -doesn't contain any functional changes, only shuffles the code around -and splits the monolithic sysdb_try_to_find_expected_dn function into -smaller blocks. - -Reviewed-by: Sumit Bose -(cherry picked from commit e5a984093ad7921c83da75272cede2b0e52ba2d6) ---- - src/db/sysdb_subdomains.c | 278 +++++++++++++++++++++++++++++----------------- - 1 file changed, 179 insertions(+), 99 deletions(-) - -diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c -index ff83f914f31d566e050c74a3ef5f5745f8c93add..b011bad6c988db952622e7ddaabf015ec24e54ba 100644 ---- a/src/db/sysdb_subdomains.c -+++ b/src/db/sysdb_subdomains.c -@@ -1145,74 +1145,29 @@ done: - return ret; - } - --errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom, -- const char *domain_component_name, -- struct sysdb_attrs **usr_attrs, -- size_t count, -- struct sysdb_attrs **exp_usr) -+static errno_t match_cn_users(TALLOC_CTX *tmp_ctx, -+ struct sysdb_attrs **usr_attrs, -+ size_t count, -+ const char *dom_basedn, -+ struct sysdb_attrs **_result) - { -- char *dom_basedn; -- size_t dom_basedn_len; -- char *expected_basedn; -- size_t expected_basedn_len; -+ errno_t ret; -+ const char *orig_dn; - size_t dn_len; -- const char *orig_dn; -- size_t c = 0; -- int ret; -- TALLOC_CTX *tmp_ctx; -- struct ldb_context *ldb_ctx; -- struct ldb_dn *ldb_dom_basedn; -- int dom_basedn_comp_num; -- struct ldb_dn *ldb_dn; -- int dn_comp_num; -- const char *component_name; - struct sysdb_attrs *result = NULL; - const char *result_dn_str = NULL; -+ char *cn_users_basedn; -+ size_t cn_users_basedn_len; - -- if (dom == NULL || domain_component_name == NULL || usr_attrs == NULL -- || count == 0) { -- return EINVAL; -- } -- -- tmp_ctx = talloc_new(NULL); -- if (tmp_ctx == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); -- return ENOMEM; -- } -- -- ret = domain_to_basedn(tmp_ctx, dom->name, &dom_basedn); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, "domain_to_basedn failed.\n"); -- goto done; -- } -- expected_basedn = talloc_asprintf(tmp_ctx, "%s%s", "cn=users,", dom_basedn); -- if (expected_basedn == NULL) { -+ cn_users_basedn = talloc_asprintf(tmp_ctx, "%s%s", "cn=users,", dom_basedn); -+ if (cn_users_basedn == NULL) { - ret = ENOMEM; - goto done; - } -+ cn_users_basedn_len = strlen(cn_users_basedn); -+ DEBUG(SSSDBG_TRACE_ALL, "cn=users baseDN is [%s].\n", cn_users_basedn); - -- ldb_ctx = sysdb_ctx_get_ldb(dom->sysdb); -- if (ldb_ctx == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "Missing ldb context.\n"); -- ret = EINVAL; -- goto done; -- } -- -- ldb_dom_basedn = ldb_dn_new(tmp_ctx, ldb_ctx, dom_basedn); -- if (ldb_dom_basedn == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n"); -- ret = ENOMEM; -- goto done; -- } -- -- dom_basedn_comp_num = ldb_dn_get_comp_num(ldb_dom_basedn); -- dom_basedn_comp_num++; -- -- DEBUG(SSSDBG_TRACE_ALL, "Expected BaseDN is [%s].\n", expected_basedn); -- expected_basedn_len = strlen(expected_basedn); -- dom_basedn_len = strlen(dom_basedn); -- -- for (c = 0; c < count; c++) { -+ for (size_t c = 0; c < count; c++) { - ret = sysdb_attrs_get_string(usr_attrs[c], SYSDB_ORIG_DN, &orig_dn); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); -@@ -1220,9 +1175,9 @@ errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom, - } - dn_len = strlen(orig_dn); - -- if (dn_len > expected_basedn_len -- && strcasecmp(orig_dn + (dn_len - expected_basedn_len), -- expected_basedn) == 0) { -+ if (dn_len > cn_users_basedn_len -+ && strcasecmp(orig_dn + (dn_len - cn_users_basedn_len), -+ cn_users_basedn) == 0) { - DEBUG(SSSDBG_TRACE_ALL, - "Found matching dn [%s].\n", orig_dn); - if (result != NULL) { -@@ -1237,52 +1192,177 @@ errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom, - } - } - -- if (result == NULL) { -- for (c = 0; c < count; c++) { -- ret = sysdb_attrs_get_string(usr_attrs[c], SYSDB_ORIG_DN, &orig_dn); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); -+ ret = EOK; -+done: -+ *_result = result; -+ return ret; -+} -+ -+static errno_t match_non_dc_comp(TALLOC_CTX *tmp_ctx, -+ struct sss_domain_info *dom, -+ struct sysdb_attrs **usr_attrs, -+ size_t count, -+ struct ldb_dn *ldb_basedn, -+ const char *basedn, -+ const char *domain_component_name, -+ struct sysdb_attrs **_result) -+{ -+ errno_t ret; -+ const char *orig_dn; -+ size_t orig_dn_len; -+ size_t basedn_len; -+ struct ldb_context *ldb_ctx; -+ struct ldb_dn *ldb_orig_dn; -+ int dn_comp_num; -+ int basedn_comp_num; -+ const char *component_name; -+ struct sysdb_attrs *result = NULL; -+ const char *result_dn_str = NULL; -+ -+ ldb_ctx = sysdb_ctx_get_ldb(dom->sysdb); -+ if (ldb_ctx == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "Missing ldb context.\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ basedn_len = strlen(basedn); -+ -+ basedn_comp_num = ldb_dn_get_comp_num(ldb_basedn); -+ basedn_comp_num++; -+ -+ for (size_t c = 0; c < count; c++) { -+ ret = sysdb_attrs_get_string(usr_attrs[c], SYSDB_ORIG_DN, &orig_dn); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n"); -+ goto done; -+ } -+ orig_dn_len = strlen(orig_dn); -+ -+ if (orig_dn_len > basedn_len -+ /* Does the user's original DN with the non-domain part -+ * stripped match the domain base DN? -+ */ -+ && strcasecmp(orig_dn + (orig_dn_len - basedn_len), -+ basedn) == 0) { -+ ldb_orig_dn = ldb_dn_new(tmp_ctx, ldb_ctx, orig_dn); -+ if (ldb_orig_dn == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed"); -+ ret = ENOMEM; - goto done; - } -- dn_len = strlen(orig_dn); - -- if (dn_len > dom_basedn_len -- && strcasecmp(orig_dn + (dn_len - dom_basedn_len), -- dom_basedn) == 0) { -- ldb_dn = ldb_dn_new(tmp_ctx, ldb_ctx, orig_dn); -- if (ldb_dn == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed"); -- ret = ENOMEM; -- goto done; -- } -- -- dn_comp_num = ldb_dn_get_comp_num(ldb_dn); -- if (dn_comp_num > dom_basedn_comp_num) { -- component_name = ldb_dn_get_component_name(ldb_dn, -- (dn_comp_num - dom_basedn_comp_num)); -- DEBUG(SSSDBG_TRACE_ALL, "Comparing [%s] and [%s].\n", -- component_name, -- domain_component_name); -- if (component_name != NULL -- && strcasecmp(component_name, -- domain_component_name) != 0) { -- DEBUG(SSSDBG_TRACE_ALL, -- "Found matching dn [%s].\n", orig_dn); -- if (result != NULL) { -- DEBUG(SSSDBG_OP_FAILURE, -- "Found 2 matching DN [%s] and [%s], " -- "expecting only 1.\n", result_dn_str, orig_dn); -- ret = EINVAL; -- goto done; -- } -- result = usr_attrs[c]; -- result_dn_str = orig_dn; -+ dn_comp_num = ldb_dn_get_comp_num(ldb_orig_dn); -+ if (dn_comp_num > basedn_comp_num) { -+ component_name = ldb_dn_get_component_name(ldb_orig_dn, -+ (dn_comp_num - basedn_comp_num)); -+ DEBUG(SSSDBG_TRACE_ALL, "Comparing [%s] and [%s].\n", -+ component_name, -+ domain_component_name); -+ /* If the component is NOT a DC component, then the entry -+ * must come from our domain, perhaps from a child container. -+ * If it matched the DC component, the entry was from a child -+ * subdomain different from this one. -+ */ -+ if (component_name != NULL -+ && strcasecmp(component_name, -+ domain_component_name) != 0) { -+ DEBUG(SSSDBG_TRACE_ALL, -+ "Found matching dn [%s].\n", orig_dn); -+ if (result != NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Found 2 matching DN [%s] and [%s], " -+ "expecting only 1.\n", result_dn_str, orig_dn); -+ ret = EINVAL; -+ goto done; - } -+ result = usr_attrs[c]; -+ result_dn_str = orig_dn; - } - } - } - } - -+ ret = EOK; -+ *_result = result; -+done: -+ return ret; -+} -+ -+static errno_t match_basedn(TALLOC_CTX *tmp_ctx, -+ struct sss_domain_info *dom, -+ struct sysdb_attrs **usr_attrs, -+ size_t count, -+ const char *dom_basedn, -+ const char *domain_component_name, -+ struct sysdb_attrs **_result) -+{ -+ struct ldb_context *ldb_ctx; -+ struct ldb_dn *ldb_dom_basedn; -+ -+ ldb_ctx = sysdb_ctx_get_ldb(dom->sysdb); -+ if (ldb_ctx == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "Missing ldb context.\n"); -+ return EINVAL; -+ } -+ -+ -+ ldb_dom_basedn = ldb_dn_new(tmp_ctx, ldb_ctx, dom_basedn); -+ if (ldb_dom_basedn == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n"); -+ return ENOMEM; -+ } -+ -+ return match_non_dc_comp(tmp_ctx, dom, -+ usr_attrs, count, -+ ldb_dom_basedn, dom_basedn, -+ domain_component_name, -+ _result); -+} -+ -+errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom, -+ const char *domain_component_name, -+ struct sysdb_attrs **usr_attrs, -+ size_t count, -+ struct sysdb_attrs **exp_usr) -+{ -+ char *dom_basedn; -+ int ret; -+ TALLOC_CTX *tmp_ctx; -+ struct sysdb_attrs *result = NULL; -+ -+ if (dom == NULL || domain_component_name == NULL -+ || usr_attrs == NULL || count == 0) { -+ return EINVAL; -+ } -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); -+ return ENOMEM; -+ } -+ -+ ret = domain_to_basedn(tmp_ctx, dom->name, &dom_basedn); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "domain_to_basedn failed.\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ ret = match_cn_users(tmp_ctx, usr_attrs, count, dom_basedn, &result); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ if (result == NULL) { -+ ret = match_basedn(tmp_ctx, dom, usr_attrs, -+ count, dom_basedn, domain_component_name, -+ &result); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ - if (result == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "No matching DN found.\n"); - ret = ENOENT; --- -2.7.4 - diff --git a/SOURCES/0150-VALIDATOR-prevent-duplicite-report-from-subdomain-se.patch b/SOURCES/0150-VALIDATOR-prevent-duplicite-report-from-subdomain-se.patch new file mode 100644 index 0000000..8ce1bb0 --- /dev/null +++ b/SOURCES/0150-VALIDATOR-prevent-duplicite-report-from-subdomain-se.patch @@ -0,0 +1,36 @@ +From 03bfcf1746b163fa3fbce9f2741db77064ac84e7 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 31 May 2017 17:35:27 +0200 +Subject: [PATCH 150/152] VALIDATOR: prevent duplicite report from subdomain + sections +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Issues is subdomain sections e.g. "[domain/A.test/B.A.test]" were +reported twice. + +[rule/allowed_domain_options]: Attribute 'debug_leTYPOvel' is not allowed in section 'domain/A.test/B.A.test'. Check for typos. +[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not allowed in section 'domain/A.test/B.A.test'. Check for typos. + +Reviewed-by: Michal Židek +--- + src/config/cfg_rules.ini | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index 744446478e5d5489cd86d8e15ce8e178cf5e3a91..d6506b7c3cee13f7c5400a546deb787e755abc8b 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -296,7 +296,7 @@ option = responder_idle_timeout + + [rule/allowed_domain_options] + validator = ini_allowed_options +-section_re = ^\(domain\|application\)/.*$ ++section_re = ^\(domain\|application\)/[^/]\+$ + + option = debug + option = debug_level +-- +2.9.4 + diff --git a/SOURCES/0151-SYSDB-Augment-sysdb_try_to_find_expected_dn-to-match.patch b/SOURCES/0151-SYSDB-Augment-sysdb_try_to_find_expected_dn-to-match.patch deleted file mode 100644 index d4e0758..0000000 --- a/SOURCES/0151-SYSDB-Augment-sysdb_try_to_find_expected_dn-to-match.patch +++ /dev/null @@ -1,283 +0,0 @@ -From a315e923a930e743de51c05183de383245f1c83e Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Mon, 31 Oct 2016 21:39:57 +0100 -Subject: [PATCH 151/151] SYSDB: Augment sysdb_try_to_find_expected_dn to match - search base as well - -In cases where the domain name in sssd.conf does not match the AD -domain, our previous matching process wouldn't match. This patch -augments the matching as follows: - - the search base is known to sysdb_try_to_find_expected_dn and is - expected to be non-NULL - - the existing matching is ran first - - during the search base, matching, all the non-DC components are - stripped from the search base to 'canonicalize' the search base - - if only a single entry that matches with a non-DC DN component - (matching with a DC component would mean the DN comes from a - different domain) then this entry is a match and is returned - -Resolves: -https://fedorahosted.org/sssd/ticket/3199 - -Reviewed-by: Sumit Bose -(cherry picked from commit 24d8c85fae253f988165c112af208198cf48eef6) ---- - src/db/sysdb.h | 1 + - src/db/sysdb_subdomains.c | 99 ++++++++++++++++++++++++++++++ - src/providers/ldap/sdap_async_initgroups.c | 8 ++- - src/tests/cmocka/test_sysdb_subdomains.c | 43 +++++++++++-- - 4 files changed, 144 insertions(+), 7 deletions(-) - -diff --git a/src/db/sysdb.h b/src/db/sysdb.h -index a0279fb249e1258c9cb73a4fcab55e4b242c61f3..6a1bbf089206970892590e85ae1f5c741a79f969 100644 ---- a/src/db/sysdb.h -+++ b/src/db/sysdb.h -@@ -1296,6 +1296,7 @@ errno_t sysdb_handle_original_uuid(const char *orig_name, - - errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom, - const char *domain_component_name, -+ const char *ldap_search_base, - struct sysdb_attrs **usr_attrs, - size_t count, - struct sysdb_attrs **exp_usr); -diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c -index b011bad6c988db952622e7ddaabf015ec24e54ba..780140484f6f023bc6e8c12266e3b81ff016ec10 100644 ---- a/src/db/sysdb_subdomains.c -+++ b/src/db/sysdb_subdomains.c -@@ -1320,8 +1320,97 @@ static errno_t match_basedn(TALLOC_CTX *tmp_ctx, - _result); - } - -+static errno_t match_search_base(TALLOC_CTX *tmp_ctx, -+ struct sss_domain_info *dom, -+ const char *domain_component_name, -+ const char *domain_search_base, -+ struct sysdb_attrs **usr_attrs, -+ size_t count, -+ struct sysdb_attrs **_result) -+{ -+ errno_t ret; -+ bool ok; -+ const char *search_base; -+ struct ldb_context *ldb_ctx; -+ struct sysdb_attrs *result = NULL; -+ struct ldb_dn *ldb_search_base; -+ int search_base_comp_num; -+ int non_dc_comp_num; -+ const char *component_name; -+ -+ ldb_ctx = sysdb_ctx_get_ldb(dom->sysdb); -+ if (ldb_ctx == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "Missing ldb context.\n"); -+ ret = EINVAL; -+ goto done; -+ } -+ -+ ldb_search_base = ldb_dn_new(tmp_ctx, ldb_ctx, domain_search_base); -+ if (ldb_search_base == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ /* strip non-DC components from the search base */ -+ search_base_comp_num = ldb_dn_get_comp_num(ldb_search_base); -+ for (non_dc_comp_num = 0; -+ non_dc_comp_num < search_base_comp_num; -+ non_dc_comp_num++) { -+ -+ component_name = ldb_dn_get_component_name(ldb_search_base, -+ non_dc_comp_num); -+ if (strcasecmp(domain_component_name, component_name) == 0) { -+ break; -+ } -+ } -+ -+ if (non_dc_comp_num == search_base_comp_num) { -+ /* The search base does not have any non-DC components, the search wouldn't -+ * match anyway -+ */ -+ ret = EOK; -+ *_result = NULL; -+ goto done; -+ } -+ -+ ok = ldb_dn_remove_child_components(ldb_search_base, non_dc_comp_num); -+ if (!ok) { -+ ret = EINVAL; -+ goto done; -+ } -+ -+ search_base = ldb_dn_get_linearized(ldb_search_base); -+ if (search_base == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ ret = match_cn_users(tmp_ctx, usr_attrs, count, search_base, &result); -+ if (ret != EOK) { -+ goto done; -+ } -+ -+ if (result == NULL) { -+ ret = match_non_dc_comp(tmp_ctx, dom, -+ usr_attrs, count, -+ ldb_search_base, search_base, -+ domain_component_name, -+ &result); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ -+ ret = EOK; -+ *_result = result; -+done: -+ return ret; -+} -+ - errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom, - const char *domain_component_name, -+ const char *domain_search_base, - struct sysdb_attrs **usr_attrs, - size_t count, - struct sysdb_attrs **exp_usr) -@@ -1332,6 +1421,7 @@ errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom, - struct sysdb_attrs *result = NULL; - - if (dom == NULL || domain_component_name == NULL -+ || domain_search_base == NULL - || usr_attrs == NULL || count == 0) { - return EINVAL; - } -@@ -1364,6 +1454,15 @@ errno_t sysdb_try_to_find_expected_dn(struct sss_domain_info *dom, - } - - if (result == NULL) { -+ ret = match_search_base(tmp_ctx, dom, domain_component_name, -+ domain_search_base, usr_attrs, count, -+ &result); -+ if (ret != EOK) { -+ goto done; -+ } -+ } -+ -+ if (result == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "No matching DN found.\n"); - ret = ENOENT; - goto done; -diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c -index 8eaba261c49082d086df9f19464ac0f40fae71fb..1173f4a875a1ea79990ff491ee7f2512f8435ac7 100644 ---- a/src/providers/ldap/sdap_async_initgroups.c -+++ b/src/providers/ldap/sdap_async_initgroups.c -@@ -2947,7 +2947,13 @@ static void sdap_get_initgr_user(struct tevent_req *subreq) - DEBUG(SSSDBG_OP_FAILURE, - "Expected one user entry and got %zu\n", count); - -- ret = sysdb_try_to_find_expected_dn(state->dom, "dc", usr_attrs, count, -+ /* When matching against a search base, it's sufficient to pick only -+ * the first search base because all bases in a single domain would -+ * have the same DC= components -+ */ -+ ret = sysdb_try_to_find_expected_dn(state->dom, "dc", -+ state->sdom->search_bases[0]->basedn, -+ usr_attrs, count, - &state->orig_user); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, -diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c -index c9db56841e841472c81d00a79f475dbbd975ccb0..52056e0435d2793893f1a4e336f38acf7a70b2c0 100644 ---- a/src/tests/cmocka/test_sysdb_subdomains.c -+++ b/src/tests/cmocka/test_sysdb_subdomains.c -@@ -520,7 +520,9 @@ static void test_try_to_find_expected_dn(void **state) - int ret; - struct sysdb_attrs *result; - struct sysdb_attrs *usr_attrs[10] = { NULL }; -+ struct sysdb_attrs *dom_usr_attrs[10] = { NULL }; - struct sss_domain_info *dom; -+ char *dom_basedn; - struct subdom_test_ctx *test_ctx = - talloc_get_type(*state, struct subdom_test_ctx); - -@@ -528,6 +530,9 @@ static void test_try_to_find_expected_dn(void **state) - "child2.test_sysdb_subdomains_2", true); - assert_non_null(dom); - -+ ret = domain_to_basedn(test_ctx, dom->name, &dom_basedn); -+ assert_int_equal(ret, EOK); -+ - usr_attrs[0] = sysdb_new_attrs(test_ctx); - assert_non_null(usr_attrs[0]); - -@@ -535,13 +540,13 @@ static void test_try_to_find_expected_dn(void **state) - "uid=user,cn=abc,dc=c2,dc=child2,dc=test_sysdb_subdomains_2"); - assert_int_equal(ret, EOK); - -- ret = sysdb_try_to_find_expected_dn(NULL, NULL, NULL, 0, NULL); -+ ret = sysdb_try_to_find_expected_dn(NULL, NULL, NULL, NULL, 0, NULL); - assert_int_equal(ret, EINVAL); - -- ret = sysdb_try_to_find_expected_dn(dom, "dc", usr_attrs, 1, &result); -+ ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, usr_attrs, 1, &result); - assert_int_equal(ret, ENOENT); - -- ret = sysdb_try_to_find_expected_dn(dom, "xy", usr_attrs, 1, &result); -+ ret = sysdb_try_to_find_expected_dn(dom, "xy", dom_basedn, usr_attrs, 1, &result); - assert_int_equal(ret, EOK); - assert_ptr_equal(result, usr_attrs[0]); - -@@ -559,11 +564,11 @@ static void test_try_to_find_expected_dn(void **state) - "uid=user2,cn=abc,dc=c2,dc=child2,dc=test_sysdb_subdomains_2"); - assert_int_equal(ret, EOK); - -- ret = sysdb_try_to_find_expected_dn(dom, "dc", usr_attrs, 3, &result); -+ ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, usr_attrs, 3, &result); - assert_int_equal(ret, EOK); - assert_ptr_equal(result, usr_attrs[1]); - -- ret = sysdb_try_to_find_expected_dn(dom, "xy", usr_attrs, 3, &result); -+ ret = sysdb_try_to_find_expected_dn(dom, "xy", dom_basedn, usr_attrs, 3, &result); - assert_int_equal(ret, EINVAL); - - /* Make sure cn=users match is preferred */ -@@ -575,10 +580,36 @@ static void test_try_to_find_expected_dn(void **state) - "uid=user2,cn=abc,cn=users,dc=child2,dc=test_sysdb_subdomains_2"); - assert_int_equal(ret, EOK); - -- ret = sysdb_try_to_find_expected_dn(dom, "dc", usr_attrs, 3, &result); -+ ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, usr_attrs, 3, &result); - assert_int_equal(ret, EOK); - assert_ptr_equal(result, usr_attrs[2]); - -+ /* test a case where the domain name does not match the basedn */ -+ dom->name = discard_const("default"); -+ dom_usr_attrs[0] = usr_attrs[0]; -+ -+ ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, dom_usr_attrs, 1, &result); -+ assert_int_equal(ret, ENOENT); -+ -+ dom_usr_attrs[1] = usr_attrs[1]; -+ dom_usr_attrs[2] = usr_attrs[2]; -+ -+ /* Make sure cn=users match is preferred */ -+ ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, dom_usr_attrs, 3, &result); -+ assert_int_equal(ret, EOK); -+ assert_ptr_equal(result, dom_usr_attrs[2]); -+ -+ talloc_free(usr_attrs[2]); -+ usr_attrs[2] = sysdb_new_attrs(test_ctx); -+ assert_non_null(usr_attrs[2]); -+ ret = sysdb_attrs_add_string(usr_attrs[2], SYSDB_ORIG_DN, -+ "uid=user2,cn=abc,dc=c2,dc=child2,dc=test_sysdb_subdomains_2"); -+ assert_int_equal(ret, EOK); -+ -+ dom_usr_attrs[2] = usr_attrs[2]; -+ ret = sysdb_try_to_find_expected_dn(dom, "dc", dom_basedn, dom_usr_attrs, 3, &result); -+ assert_int_equal(ret, EOK); -+ assert_ptr_equal(result, usr_attrs[1]); - - talloc_free(usr_attrs[0]); - talloc_free(usr_attrs[1]); --- -2.7.4 - diff --git a/SOURCES/0151-test_config_check-Fix-few-issues.patch b/SOURCES/0151-test_config_check-Fix-few-issues.patch new file mode 100644 index 0000000..9e48ed1 --- /dev/null +++ b/SOURCES/0151-test_config_check-Fix-few-issues.patch @@ -0,0 +1,92 @@ +From 15f997c22228f4b87a841148bf05c6911107879c Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 31 May 2017 17:16:47 +0200 +Subject: [PATCH 151/152] test_config_check: Fix few issues +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +* enable few tests +* malformed configuration file due to missing closing ']' +* fix few expected failures +* add few sections into whitelist test +* crash in test if count of expected failures is different then real + value + +[ RUN ] config_check_test_bad_subdom_option_name +[rule/allowed_domain_options]: Attribute 'debug_leTYPOvel' is not allowed in section 'domain/A.test/B.A.test'. Check for typos. +[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not allowed in section 'domain/A.test/B.A.test'. Check for typos. +[ ERROR ] --- Test failed with exception: Segmentation fault(11) + +Reviewed-by: Michal Židek +--- + src/tests/cmocka/test_config_check.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/src/tests/cmocka/test_config_check.c b/src/tests/cmocka/test_config_check.c +index bab3226c004fb9495471af7c7d3f6861552d8a86..0066ebe77e9f174449461caebdb3359380bc19b5 100644 +--- a/src/tests/cmocka/test_config_check.c ++++ b/src/tests/cmocka/test_config_check.c +@@ -81,6 +81,7 @@ void config_check_test_common(const char *cfg_string, + /* Keep this printf loop for faster debugging */ + printf("%s\n", strs[i]); + } ++ assert_int_equal(num_errors, num_errors_expected); + + for (int i = 0; i < num_errors && i <= num_errors_expected; i++) { + assert_string_equal(strs[i], errors_expected[i]); +@@ -167,7 +168,7 @@ void config_check_test_bad_ifp_option_name(void **state) + + void config_check_test_bad_domain_option_name(void **state) + { +- char cfg_str[] = "[domain/A.test\n" ++ char cfg_str[] = "[domain/A.test]\n" + "debug_leTYPOvel = 10\n"; + const char *expected_errors[] = { + "[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not " +@@ -179,10 +180,10 @@ void config_check_test_bad_domain_option_name(void **state) + + void config_check_test_bad_appdomain_option_name(void **state) + { +- char cfg_str[] = "[application/myapp\n" ++ char cfg_str[] = "[application/myapp]\n" + "debug_leTYPOvel = 10\n"; + const char *expected_errors[] = { +- "[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not " ++ "[rule/allowed_domain_options]: Attribute 'debug_leTYPOvel' is not " + "allowed in section 'application/myapp'. Check for typos.", + }; + +@@ -194,7 +195,7 @@ void config_check_test_bad_subdom_option_name(void **state) + char cfg_str[] = "[domain/A.test/B.A.test]\n" + "debug_leTYPOvel = 10\n"; + const char *expected_errors[] = { +- "[rule/allowed_sssd_options]: Attribute 'debug_leTYPOvel' is not " ++ "[rule/allowed_subdomain_options]: Attribute 'debug_leTYPOvel' is not " + "allowed in section 'domain/A.test/B.A.test'. Check for typos.", + }; + +@@ -210,6 +211,8 @@ void config_check_test_good_sections(void **state) + "[domain/testdom.test/testsubdom.testdom.test]\n" + "[application/myapp]\n" + "[secrets]\n" ++ "[secrets/users/1000]\n" ++ "[ssh]\n" + "[ifp]\n" + "[pac]\n"; + const char *expected_errors[] = { NULL }; +@@ -255,8 +258,11 @@ int main(int argc, const char *argv[]) + cmocka_unit_test(config_check_test_bad_nss_option_name), + cmocka_unit_test(config_check_test_bad_pac_option_name), + cmocka_unit_test(config_check_test_bad_ifp_option_name), ++ cmocka_unit_test(config_check_test_bad_appdomain_option_name), ++ cmocka_unit_test(config_check_test_bad_subdom_option_name), + cmocka_unit_test(config_check_test_good_sections), + cmocka_unit_test(config_check_test_inherit_from_in_normal_dom), ++ cmocka_unit_test(config_check_test_inherit_from_in_app_dom), + }; + + /* Set debug level to invalid value so we can decide if -d 0 was used. */ +-- +2.9.4 + diff --git a/SOURCES/0152-KRB5-Fix-access_provider-krb5.patch b/SOURCES/0152-KRB5-Fix-access_provider-krb5.patch new file mode 100644 index 0000000..89845c7 --- /dev/null +++ b/SOURCES/0152-KRB5-Fix-access_provider-krb5.patch @@ -0,0 +1,81 @@ +From 3ee575c2852adb9d5a5c0a4616c082afc6779a8e Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Thu, 1 Jun 2017 09:51:31 +0200 +Subject: [PATCH 152/152] KRB5: Fix access_provider=krb5 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The domain type (posix or not) was being sent to the krb5_child always, +but the buffer only had enough space in case of authentication, not +authorization. Bug was introduced in the commit + 861ab44e8148208425b67c4711bc8fade10fd3ed + +This patch makes the buffer one uint32_t unit larger. + +To reproduce, just set up sssd.conf with: + access_provider = krb5 + +Without the patch, you would see messages like: + ==14111== Invalid write of size 2 + ==14111== at 0x4C3041B: memcpy@@GLIBC_2.14 (vg_replace_strmem.c:1018) + ==14111== by 0xE0EE275: safealign_memcpy (util_safealign.h:51) + ==14111== by 0xE0EECB3: create_send_buffer (krb5_child_handler.c:239) + ==14111== by 0xE0EFDDE: handle_child_send (krb5_child_handler.c:529) + ==14111== by 0xE0EDEDD: krb5_access_send (krb5_access.c:149) + ==14111== by 0xE0ED32F: krb5_pam_handler_send (krb5_auth.c:1250) + ==14111== by 0x418868: file_dp_request (dp_request.c:254) + ==14111== by 0x418976: dp_req_send (dp_request.c:300) + ==14111== by 0x41C25F: dp_pam_handler (dp_target_auth.c:219) + ==14111== by 0x52B3456: sbus_request_invoke_or_finish (sssd_dbus_request.c:71) + ==14111== by 0x52B0F37: sbus_message_handler_got_caller_id (sssd_dbus_interface.c:1048) + ==14111== by 0x923C923: tevent_common_loop_immediate (tevent_immediate.c:135) + ==14111== Address 0x126ab506 is 150 bytes inside a block of size 151 alloc'd + ==14111== at 0x4C2BBAD: malloc (vg_replace_malloc.c:299) + ==14111== by 0x944D7F4: __talloc_with_prefix (talloc.c:698) + ==14111== by 0x944D7F4: __talloc (talloc.c:739) + ==14111== by 0x944D7F4: _talloc_named_const (talloc.c:896) + ==14111== by 0x944D7F4: talloc_named_const (talloc.c:1675) + ==14111== by 0xE0EE7B6: create_send_buffer (krb5_child_handler.c:185) + ==14111== by 0xE0EFDDE: handle_child_send (krb5_child_handler.c:529) + ==14111== by 0xE0EDEDD: krb5_access_send (krb5_access.c:149) + ==14111== by 0xE0ED32F: krb5_pam_handler_send (krb5_auth.c:1250) + ==14111== by 0x418868: file_dp_request (dp_request.c:254) + ==14111== by 0x418976: dp_req_send (dp_request.c:300) + ==14111== by 0x41C25F: dp_pam_handler (dp_target_auth.c:219) + ==14111== by 0x52B3456: sbus_request_invoke_or_finish (sssd_dbus_request.c:71) + ==14111== by 0x52B0F37: sbus_message_handler_got_caller_id (sssd_dbus_interface.c:1048) + ==14111== by 0x923C923: tevent_common_loop_immediate (tevent_immediate.c:135) + +Resolves: +https://pagure.io/SSSD/sssd/issue/3418 + +Reviewed-by: Lukáš Slebodník +--- + src/providers/krb5/krb5_child_handler.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c +index 87e79a06e917aadb622455bccfc2e9c6769f70c2..11ac867e62d2ff96b827cf6d4ff341fc8ff0a286 100644 +--- a/src/providers/krb5/krb5_child_handler.c ++++ b/src/providers/krb5/krb5_child_handler.c +@@ -156,14 +156,14 @@ static errno_t create_send_buffer(struct krb5child_req *kr, + return ENOMEM; + } + +- buf->size = 8*sizeof(uint32_t) + strlen(kr->upn); ++ buf->size = 9*sizeof(uint32_t) + strlen(kr->upn); + + if (kr->pd->cmd == SSS_PAM_AUTHENTICATE || + kr->pd->cmd == SSS_PAM_PREAUTH || + kr->pd->cmd == SSS_CMD_RENEW || + kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM || + kr->pd->cmd == SSS_PAM_CHAUTHTOK) { +- buf->size += 5*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + ++ buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) + + sss_authtok_get_size(kr->pd->authtok); + + buf->size += sizeof(uint32_t); +-- +2.9.4 + diff --git a/SOURCES/0152-SYSDB-Adding-lowercase-sudoUser-form.patch b/SOURCES/0152-SYSDB-Adding-lowercase-sudoUser-form.patch deleted file mode 100644 index 504689e..0000000 --- a/SOURCES/0152-SYSDB-Adding-lowercase-sudoUser-form.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 81ae14a34ad568b39b0077cc88112941802df27d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Petr=20=C4=8Cech?= -Date: Wed, 12 Oct 2016 16:48:38 +0200 -Subject: [PATCH 152/153] SYSDB: Adding lowercase sudoUser form -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If domain is not case sensitive we add lowercase form of usernames -to sudoUser attributes. So we actually able to apply sudoRule on -user Administrator@... with login admnistrator@... - -Resolves: -https://fedorahosted.org/sssd/ticket/3203 - -Reviewed-by: Pavel Březina -(cherry picked from commit f4a1046bb88d7a0ab3617e49ae94bfa849d10645) ---- - src/db/sysdb_sudo.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 64 insertions(+) - -diff --git a/src/db/sysdb_sudo.c b/src/db/sysdb_sudo.c -index 601fb63f236a7ed9eede130fd8cf4c3a1559fc4b..4bd93ffc60caa1ce48b72ee207899da0c4196d61 100644 ---- a/src/db/sysdb_sudo.c -+++ b/src/db/sysdb_sudo.c -@@ -852,6 +852,65 @@ sysdb_sudo_add_sss_attrs(struct sysdb_attrs *rule, - return EOK; - } - -+static errno_t sysdb_sudo_add_lowered_users(struct sss_domain_info *domain, -+ struct sysdb_attrs *rule) -+{ -+ TALLOC_CTX *tmp_ctx; -+ const char **users = NULL; -+ const char *lowered = NULL; -+ errno_t ret; -+ -+ if (domain->case_sensitive == true || rule == NULL) { -+ return EOK; -+ } -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = sysdb_attrs_get_string_array(rule, SYSDB_SUDO_CACHE_AT_USER, tmp_ctx, -+ &users); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, "Unable to get %s attribute [%d]: %s\n", -+ SYSDB_SUDO_CACHE_AT_USER, ret, strerror(ret)); -+ goto done; -+ } -+ -+ if (users == NULL) { -+ ret = EOK; -+ goto done; -+ } -+ -+ for (int i = 0; users[i] != NULL; i++) { -+ lowered = sss_tc_utf8_str_tolower(tmp_ctx, users[i]); -+ if (lowered == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ if (strcmp(users[i], lowered) == 0) { -+ /* It protects us from adding duplicate. */ -+ continue; -+ } -+ -+ ret = sysdb_attrs_add_string(rule, SYSDB_SUDO_CACHE_AT_USER, lowered); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_OP_FAILURE, -+ "Unable to add %s attribute [%d]: %s\n", -+ SYSDB_SUDO_CACHE_AT_USER, ret, strerror(ret)); -+ goto done; -+ } -+ } -+ -+ ret = EOK; -+ -+done: -+ talloc_zfree(tmp_ctx); -+ return ret; -+} -+ - static errno_t - sysdb_sudo_store_rule(struct sss_domain_info *domain, - struct sysdb_attrs *rule, -@@ -868,6 +927,11 @@ sysdb_sudo_store_rule(struct sss_domain_info *domain, - - DEBUG(SSSDBG_TRACE_FUNC, "Adding sudo rule %s\n", name); - -+ ret = sysdb_sudo_add_lowered_users(domain, rule); -+ if (ret != EOK) { -+ return ret; -+ } -+ - ret = sysdb_sudo_add_sss_attrs(rule, name, cache_timeout, now); - if (ret != EOK) { - return ret; --- -2.7.4 - diff --git a/SOURCES/0153-BUILD-Improve-error-messages-for-optional-dependenci.patch b/SOURCES/0153-BUILD-Improve-error-messages-for-optional-dependenci.patch new file mode 100644 index 0000000..e06105d --- /dev/null +++ b/SOURCES/0153-BUILD-Improve-error-messages-for-optional-dependenci.patch @@ -0,0 +1,86 @@ +From 9581287c1b5e13a38182af12328ace781957a118 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 30 May 2017 14:40:07 +0200 +Subject: [PATCH 153/160] BUILD: Improve error messages for optional + dependencies + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 8ccc9b7c317cf5ee8f295b38bfc4c2b7d551f8f1) +--- + configure.ac | 2 +- + contrib/sssd.spec.in | 6 +++++- + src/external/libcurl.m4 | 6 +++++- + src/external/libjansson.m4 | 5 +++-- + 4 files changed, 14 insertions(+), 5 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 80d8ea9ff5785b0d76edbb04f454d0dd8c8a1e6d..e8fe1d47e1803cc570295cf6512a3363e63c51c5 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -197,7 +197,6 @@ m4_include([src/external/service.m4]) + + if test x$with_secrets = xyes; then + m4_include([src/external/libhttp_parser.m4]) +- m4_include([src/external/libjansson.m4]) + fi + + if test x$with_kcm = xyes; then +@@ -206,6 +205,7 @@ fi + + if test x$with_kcm = xyes -o x$with_secrets = xyes; then + m4_include([src/external/libcurl.m4]) ++ m4_include([src/external/libjansson.m4]) + fi + + # This variable is defined by external/libcurl.m4, but conditionals +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index 39a974edebba3dbcd7625d1729b4a7330eaa8a27..b19702d091862e25bea352901b85406ccda1db65 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -228,10 +228,14 @@ BuildRequires: systemtap-sdt-devel + %endif + %if (0%{?with_secrets} == 1) + BuildRequires: http-parser-devel +-BuildRequires: jansson-devel + %endif ++%if (0%{?with_kcm} == 1) + BuildRequires: libuuid-devel ++%endif ++%if (0%{?with_secrets} == 1 || 0%{?with_kcm} == 1) ++BuildRequires: jansson-devel + BuildRequires: libcurl-devel ++%endif + + %description + Provides a set of daemons to manage access to remote directories and +diff --git a/src/external/libcurl.m4 b/src/external/libcurl.m4 +index 42be308cd1e4b04e736daf887be9b75ea92db80e..94cea9ebe40f07c18452b8c2faf82e81e1dc766b 100644 +--- a/src/external/libcurl.m4 ++++ b/src/external/libcurl.m4 +@@ -1,5 +1,9 @@ + PKG_CHECK_MODULES([CURL], [libcurl], [found_libcurl=yes], +- [AC_MSG_ERROR([The libcurl development library was not found.])]) ++ [AC_MSG_ERROR([The libcurl development library was not found. ++You must have the header file curl/curl.h installed to build sssd ++with secrets and KCM responder. If you want to build sssd without these ++responders then specify --without-secrets --without-kcm when running configure. ++])]) + + AS_IF([test x"$found_libcurl" = xyes], + CFLAGS="$CFLAGS $CURL_CFLAGS" +diff --git a/src/external/libjansson.m4 b/src/external/libjansson.m4 +index 48a4a5fd8df4ac41312a596b5ebd5de7474e75f1..d87769848558efdd32325e01d8d222bb517b4c45 100644 +--- a/src/external/libjansson.m4 ++++ b/src/external/libjansson.m4 +@@ -13,5 +13,6 @@ AS_IF([test x"$found_jansson" != xyes], + [-L$sss_extra_libdir -ljanson])], + [AC_MSG_ERROR([ + You must have the header file jansson.h installed to build sssd +-with secrets responder. If you want to build sssd without secret responder +-then specify --without-secrets when running configure.])])]) ++with secrets and KCM responder. If you want to build sssd without these ++responders then specify --without-secrets --without-kcm when running configure. ++])])]) +-- +2.9.4 + diff --git a/SOURCES/0153-SYSDB-Fixing-of-sudorule-without-a-sudoUser.patch b/SOURCES/0153-SYSDB-Fixing-of-sudorule-without-a-sudoUser.patch deleted file mode 100644 index ea2bc3f..0000000 --- a/SOURCES/0153-SYSDB-Fixing-of-sudorule-without-a-sudoUser.patch +++ /dev/null @@ -1,47 +0,0 @@ -From aed255dd1ae6ec40ca15a53c38a13354dd5c88e8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Petr=20=C4=8Cech?= -Date: Wed, 16 Nov 2016 10:09:18 +0100 -Subject: [PATCH 153/153] SYSDB: Fixing of sudorule without a sudoUser - -This patch solved a regression caused by the recent patches -to lowercase sudoUser -- in case sudoUser is missing completely, -we abort the processing of this rule and all others. - -With this patch, we return ERR_MALFORMED_ENTRY and gracefully -skip the malformed rule instead. - -Resolves: -https://fedorahosted.org/sssd/ticket/3241 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 7e23edbaa7a6bbd0b461d5792535896b6a77928b) ---- - src/db/sysdb_sudo.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/src/db/sysdb_sudo.c b/src/db/sysdb_sudo.c -index 4bd93ffc60caa1ce48b72ee207899da0c4196d61..f5160f19012028f92723b9012fad85d803aa5137 100644 ---- a/src/db/sysdb_sudo.c -+++ b/src/db/sysdb_sudo.c -@@ -874,6 +874,7 @@ static errno_t sysdb_sudo_add_lowered_users(struct sss_domain_info *domain, - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "Unable to get %s attribute [%d]: %s\n", - SYSDB_SUDO_CACHE_AT_USER, ret, strerror(ret)); -+ ret = ERR_MALFORMED_ENTRY; - goto done; - } - -@@ -977,6 +978,10 @@ sysdb_sudo_store(struct sss_domain_info *domain, - /* Multiple CNs are error on server side, we can just ignore this - * rule and save the others. Loud debug message is in logs. */ - continue; -+ } else if (ret == ERR_MALFORMED_ENTRY) { -+ /* Attribute SYSDB_SUDO_CACHE_AT_USER is missing but we can -+ * continue with next sudoRule. */ -+ continue; - } else if (ret != EOK) { - goto done; - } --- -2.7.4 - diff --git a/SOURCES/0154-MONITOR-Do-not-set-up-watchdog-for-monitor.patch b/SOURCES/0154-MONITOR-Do-not-set-up-watchdog-for-monitor.patch deleted file mode 100644 index 20ec5e1..0000000 --- a/SOURCES/0154-MONITOR-Do-not-set-up-watchdog-for-monitor.patch +++ /dev/null @@ -1,73 +0,0 @@ -From c7edf2dabc1cc3fc5298c872babf60a3001dfc2f Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Mon, 7 Nov 2016 11:58:20 +0100 -Subject: [PATCH 154/154] MONITOR: Do not set up watchdog for monitor -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -It makes little sense to set up watchdog for monitor because there is no -entity that would restart the monitor. Therefore we should disable the -watchdog for monitor process. - -Resolves: -https://fedorahosted.org/sssd/ticket/3232 - -Reviewed-by: Lukáš Slebodník -(cherry picked from commit fbe6644aa28d93f492434950680c5618eb567712) ---- - src/monitor/monitor.c | 2 ++ - src/util/server.c | 11 +++++++---- - src/util/util.h | 1 + - 3 files changed, 10 insertions(+), 4 deletions(-) - -diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c -index 89dd0a91d1fbd41dd853cf8745de732b7059d02b..0f01580e01b6a0a9ab507a54183e5813133be5a9 100644 ---- a/src/monitor/monitor.c -+++ b/src/monitor/monitor.c -@@ -2880,6 +2880,8 @@ int main(int argc, const char *argv[]) - - /* we want a pid file check */ - flags |= FLAGS_PID_FILE; -+ /* the monitor should not run a watchdog on itself */ -+ flags |= FLAGS_NO_WATCHDOG; - - /* Open before server_setup() does to have logging - * during configuration checking */ -diff --git a/src/util/server.c b/src/util/server.c -index 953cd3d6171bf2fbcefd9b9138c679100d5153c3..013e572e6284b16534910088f7801219251896d8 100644 ---- a/src/util/server.c -+++ b/src/util/server.c -@@ -666,10 +666,13 @@ int server_setup(const char *name, int flags, - ret, strerror(ret)); - return ret; - } -- ret = setup_watchdog(ctx->event_ctx, watchdog_interval); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Watchdog setup failed.\n"); -- return ret; -+ -+ if ((flags & FLAGS_NO_WATCHDOG) == 0) { -+ ret = setup_watchdog(ctx->event_ctx, watchdog_interval); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Watchdog setup failed.\n"); -+ return ret; -+ } - } - - sss_log(SSS_LOG_INFO, "Starting up"); -diff --git a/src/util/util.h b/src/util/util.h -index 4449315f8b1a79ec915bc340b46188c440a27fa3..0cbd88bd5bdb7741148dcc40aeb5ee2abaa4ff98 100644 ---- a/src/util/util.h -+++ b/src/util/util.h -@@ -84,6 +84,7 @@ - #define FLAGS_INTERACTIVE 0x0002 - #define FLAGS_PID_FILE 0x0004 - #define FLAGS_GEN_CONF 0x0008 -+#define FLAGS_NO_WATCHDOG 0x0010 - - #define PIPE_INIT { -1, -1 } - --- -2.7.4 - diff --git a/SOURCES/0154-RESPONDER_COMMON-update-certmaps-in-responders.patch b/SOURCES/0154-RESPONDER_COMMON-update-certmaps-in-responders.patch new file mode 100644 index 0000000..0b1ddaa --- /dev/null +++ b/SOURCES/0154-RESPONDER_COMMON-update-certmaps-in-responders.patch @@ -0,0 +1,77 @@ +From d363bd0f829fa7af5f96c2b07b975b7b2c5fdcfa Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 2 May 2017 15:25:10 +0200 +Subject: [PATCH 154/160] RESPONDER_COMMON: update certmaps in responders +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Make certificate mapping data available to the responders. + +Related to https://pagure.io/SSSD/sssd/issue/3395 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 749963195393efa3a4f9b168dd02fbcc68976ba3) +--- + src/confdb/confdb.h | 3 +++ + src/responder/common/responder_get_domains.c | 23 +++++++++++++++++++++++ + 2 files changed, 26 insertions(+) + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 8719c239362b371fcdb1b78956bcddde871f141b..797353141edcccbf3341d161ca598c99492e54fe 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -351,6 +351,9 @@ struct sss_domain_info { + char *forest; + struct sss_domain_info *forest_root; + const char **upn_suffixes; ++ ++ struct certmap_info **certmaps; ++ bool user_name_hint; + }; + + /** +diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c +index 8c90b7773e248e1dd6d846c5050e1931fc50c786..155631676d9449f69865919e1b74ee9399607c27 100644 +--- a/src/responder/common/responder_get_domains.c ++++ b/src/responder/common/responder_get_domains.c +@@ -224,6 +224,26 @@ immediately: + return req; + } + ++static void sss_resp_update_certmaps(struct resp_ctx *rctx) ++{ ++ int ret; ++ struct certmap_info **certmaps; ++ bool user_name_hint; ++ struct sss_domain_info *dom; ++ ++ for (dom = rctx->domains; dom != NULL; dom = dom->next) { ++ ret = sysdb_get_certmap(dom, dom->sysdb, &certmaps, &user_name_hint); ++ if (ret == EOK) { ++ dom->user_name_hint = user_name_hint; ++ talloc_free(dom->certmaps); ++ dom->certmaps = certmaps; ++ } else { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_get_certmap failed for domain [%s].\n", dom->name); ++ } ++ } ++} ++ + static void + sss_dp_get_domains_process(struct tevent_req *subreq) + { +@@ -267,6 +287,9 @@ sss_dp_get_domains_process(struct tevent_req *subreq) + ret, sss_strerror(ret)); + goto fail; + } ++ ++ sss_resp_update_certmaps(state->rctx); ++ + tevent_req_done(req); + return; + } +-- +2.9.4 + diff --git a/SOURCES/0155-AUTOFS-Fix-offline-resolution-of-autofs-maps.patch b/SOURCES/0155-AUTOFS-Fix-offline-resolution-of-autofs-maps.patch deleted file mode 100644 index b8ccb04..0000000 --- a/SOURCES/0155-AUTOFS-Fix-offline-resolution-of-autofs-maps.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 3f911325b21c53d3a932c48bc1bac328ec716268 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Thu, 4 Aug 2016 17:58:32 +0200 -Subject: [PATCH 155/155] AUTOFS: Fix offline resolution of autofs maps -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If talking to the Data Provider failed, we never re-tried looking into -the cache. We should consult the cache on DP failures and return cached -results, if possible. - -Resolves: -https://fedorahosted.org/sssd/ticket/3080 - -Reviewed-by: Pavel Březina ---- - src/responder/autofs/autofssrv_cmd.c | 16 ++++++++++++---- - 1 file changed, 12 insertions(+), 4 deletions(-) - -diff --git a/src/responder/autofs/autofssrv_cmd.c b/src/responder/autofs/autofssrv_cmd.c -index 9666ab2d195a581f18eaa7ff9bbc4c8167a71b15..f5aa25a483c3b3352f40e8cc66dfd3a24a60af0d 100644 ---- a/src/responder/autofs/autofssrv_cmd.c -+++ b/src/responder/autofs/autofssrv_cmd.c -@@ -871,17 +871,25 @@ static void lookup_automntmap_cache_updated(uint16_t err_maj, uint32_t err_min, - if (err_maj) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Unable to get information from Data Provider\n" -- "Error: %u, %u, %s\n" -- "Will try to return what we have in cache\n", -+ "Error: %u, %u, %s\n" -+ "Will try to return what we have in cache\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg); -- /* Loop to the next domain if possible */ -+ -+ /* Try to fall back to cache */ -+ ret = lookup_automntmap_step(lookup_ctx); -+ if (ret == EOK) { -+ /* We have cached results to return */ -+ autofs_setent_notify(lookup_ctx->map, ret); -+ return; -+ } -+ -+ /* Otherwise try the next domain */ - if (dctx->cmd_ctx->check_next - && (dctx->domain = get_next_domain(dctx->domain, 0))) { - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - } - } - -- /* ok the backend returned, search to see if we have updated results */ - ret = lookup_automntmap_step(lookup_ctx); - if (ret != EOK) { - if (ret == EAGAIN) { --- -2.7.4 - diff --git a/SOURCES/0155-tests-fix-test_pam_preauth_cert_no_logon_name.patch b/SOURCES/0155-tests-fix-test_pam_preauth_cert_no_logon_name.patch new file mode 100644 index 0000000..dc6a41c --- /dev/null +++ b/SOURCES/0155-tests-fix-test_pam_preauth_cert_no_logon_name.patch @@ -0,0 +1,43 @@ +From 7487682e505735f2143ccecfc5e7e0fc2dac37f2 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 8 May 2017 15:28:20 +0200 +Subject: [PATCH 155/160] tests: fix test_pam_preauth_cert_no_logon_name() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently a name is provided for test_pam_preauth_cert_no_logon_name() +so it is not a no-logon-name test. This patch removes the name and adds +the now missing mocked reply manually. + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 89ff140d7ab92fce52d6730a7d27c8d73c7d9e4a) +--- + src/tests/cmocka/test_pam_srv.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index 4d351a3707d2a49604595b728fff7705560c871a..35afbdd81d004236885ee80914771ccb4b8acff4 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -1873,10 +1873,14 @@ void test_pam_preauth_cert_no_logon_name(void **state) + * Since there is a matching user the upcoming lookup by name will find + * the user entry. But since we force the lookup by name to go to the + * backend to make sure the group-membership data is up to date the +- * backend response has to be mocked twice and the second argument of +- * mock_input_pam_cert cannot be NULL but must match the user name. */ +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, ++ * backend response has to be mocked twice. ++ * Additionally sss_parse_inp_recv() must be mocked because the cache ++ * request will be done with the username found by the certificate ++ * lookup. */ ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, + test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); ++ mock_account_recv_simple(); ++ mock_parse_inp("pamuser", NULL, EOK); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +-- +2.9.4 + diff --git a/SOURCES/0156-Prevent-use-after-free-in-fd_input_available.patch b/SOURCES/0156-Prevent-use-after-free-in-fd_input_available.patch deleted file mode 100644 index ef0555c..0000000 --- a/SOURCES/0156-Prevent-use-after-free-in-fd_input_available.patch +++ /dev/null @@ -1,71 +0,0 @@ -From f8ecb57dcb7ce41b572cb67e6d2554296a54e738 Mon Sep 17 00:00:00 2001 -From: Carl Henrik Lunde -Date: Thu, 1 Dec 2016 00:09:00 +0100 -Subject: [PATCH 156/156] Prevent use after free in fd_input_available - -When both TEVENT_FD_WRITE and TEVENT_FD_READ are set, and an error/EOF -occurs when reading from the socket, we will get a use after free -in the second call ares_process_fd. The first call will free the watch -structure via a callback. - -Prevent this by calling ares_process_fd only once. - -Invalid read of size 4 - at fd_input_available (async_resolv.c:147) - by epoll_event_loop (tevent_epoll.c:728) - by epoll_event_loop_once (tevent_epoll.c:926) - by std_event_loop_once (tevent_standard.c:114) - by _tevent_loop_once (tevent.c:533) - by tevent_common_loop_wait (tevent.c:637) - by std_event_loop_wait (tevent_standard.c:140) - by server_loop (server.c:702) - by main (data_provider_be.c:587) - Address ... is 112 bytes inside a block of size 136 free'd - at free (vg_replace_malloc.c:530) - by _talloc_free_internal (talloc.c:1116) - by _talloc_free (talloc.c:1647) - by ares__close_sockets (ares__close_sockets.c:50) - by handle_error (ares_process.c:679) - by read_tcp_data (ares_process.c:391) - by processfds (ares_process.c:138) - by fd_input_available (async_resolv.c:144) - by epoll_event_loop (tevent_epoll.c:728) - by epoll_event_loop_once (tevent_epoll.c:926) - by std_event_loop_once (tevent_standard.c:114) - by _tevent_loop_once (tevent.c:533) - by tevent_common_loop_wait (tevent.c:637) - by std_event_loop_wait (tevent_standard.c:140) - by server_loop (server.c:702) - -Resolves: -https://fedorahosted.org/sssd/ticket/3250 - -Reviewed-by: Jakub Hrozek -(cherry picked from commit 9676b464dd428557ff5a648e1351a3972440396f) ---- - src/resolv/async_resolv.c | 9 +++------ - 1 file changed, 3 insertions(+), 6 deletions(-) - -diff --git a/src/resolv/async_resolv.c b/src/resolv/async_resolv.c -index 58d5c6e550bb34cbaa50517323133fad4f900980..e29f679423eeccae1c8fb7af5fdafc69f051741a 100644 ---- a/src/resolv/async_resolv.c -+++ b/src/resolv/async_resolv.c -@@ -140,12 +140,9 @@ fd_input_available(struct tevent_context *ev, struct tevent_fd *fde, - return; - } - -- if (flags & TEVENT_FD_READ) { -- ares_process_fd(watch->ctx->channel, watch->fd, ARES_SOCKET_BAD); -- } -- if (flags & TEVENT_FD_WRITE) { -- ares_process_fd(watch->ctx->channel, ARES_SOCKET_BAD, watch->fd); -- } -+ ares_process_fd(watch->ctx->channel, -+ flags & TEVENT_FD_READ ? watch->fd : ARES_SOCKET_BAD, -+ flags & TEVENT_FD_WRITE ? watch->fd : ARES_SOCKET_BAD); - } - - static void --- -2.9.3 - diff --git a/SOURCES/0156-pam_sss-add-support-for-SSS_PAM_CERT_INFO_WITH_HINT.patch b/SOURCES/0156-pam_sss-add-support-for-SSS_PAM_CERT_INFO_WITH_HINT.patch new file mode 100644 index 0000000..94c6f8e --- /dev/null +++ b/SOURCES/0156-pam_sss-add-support-for-SSS_PAM_CERT_INFO_WITH_HINT.patch @@ -0,0 +1,258 @@ +From 19cb2e2d826dc4e3c938c5a6b51a03338e80fa9e Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 8 May 2017 16:01:26 +0200 +Subject: [PATCH 156/160] pam_sss: add support for SSS_PAM_CERT_INFO_WITH_HINT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The new response type SSS_PAM_CERT_INFO_WITH_HINT is equivalent to +SSS_PAM_CERT_INFO but tells pam_sss to prompt for an option user name as +well. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3395 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit a192a1d72e92dae3e71e062b333e51a5095a0395) +--- + src/sss_client/pam_message.h | 1 + + src/sss_client/pam_sss.c | 129 ++++++++++++++++++++++++++++++++++++++----- + src/sss_client/sss_cli.h | 11 +++- + 3 files changed, 127 insertions(+), 14 deletions(-) + +diff --git a/src/sss_client/pam_message.h b/src/sss_client/pam_message.h +index 3f4a770ac08ee416ead2f215ab873e8eb277c9eb..f215392f6879f01a0ca12abc8807bac5fc1f1cbb 100644 +--- a/src/sss_client/pam_message.h ++++ b/src/sss_client/pam_message.h +@@ -63,6 +63,7 @@ struct pam_items { + char *token_name; + char *module_name; + char *key_id; ++ bool user_name_hint; + }; + + int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer); +diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c +index db0dcb9de7b893850bcea96a9cdf76dc0b36dcee..1c06079967e3d9076d537c3de8aba93e13f76d09 100644 +--- a/src/sss_client/pam_sss.c ++++ b/src/sss_client/pam_sss.c +@@ -982,6 +982,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, + + break; + case SSS_PAM_CERT_INFO: ++ case SSS_PAM_CERT_INFO_WITH_HINT: + if (buf[p + (len - 1)] != '\0') { + D(("cert info does not end with \\0.")); + break; +@@ -994,7 +995,19 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, + break; + } + +- if (pi->pam_user == NULL || *(pi->pam_user) == '\0') { ++ if (type == SSS_PAM_CERT_INFO && pi->cert_user == '\0') { ++ D(("Invalid CERT message")); ++ break; ++ } ++ ++ if (type == SSS_PAM_CERT_INFO_WITH_HINT) { ++ pi->user_name_hint = true; ++ } else { ++ pi->user_name_hint = false; ++ } ++ ++ if ((pi->pam_user == NULL || *(pi->pam_user) == '\0') ++ && pi->cert_user != '\0') { + ret = pam_set_item(pamh, PAM_USER, pi->cert_user); + if (ret != PAM_SUCCESS) { + D(("Failed to set PAM_USER during " +@@ -1469,7 +1482,7 @@ done: + return ret; + } + +-#define SC_PROMPT_FMT "PIN for %s for user %s" ++#define SC_PROMPT_FMT "PIN for %s" + + static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) + { +@@ -1478,32 +1491,108 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) + char *prompt; + size_t size; + size_t needed_size; ++ const struct pam_conv *conv; ++ const struct pam_message *mesg[2] = { NULL, NULL }; ++ struct pam_message m[2] = { { 0 }, { 0 } }; ++ struct pam_response *resp = NULL; + +- if (pi->token_name == NULL || *pi->token_name == '\0' +- || pi->cert_user == NULL || *pi->cert_user == '\0') { ++ if (pi->token_name == NULL || *pi->token_name == '\0') { + return EINVAL; + } + +- size = sizeof(SC_PROMPT_FMT) + strlen(pi->token_name) + +- strlen(pi->cert_user); ++ size = sizeof(SC_PROMPT_FMT) + strlen(pi->token_name); + prompt = malloc(size); + if (prompt == NULL) { + D(("malloc failed.")); + return ENOMEM; + } + +- ret = snprintf(prompt, size, SC_PROMPT_FMT, pi->token_name, pi->cert_user); ++ ret = snprintf(prompt, size, SC_PROMPT_FMT, pi->token_name); + if (ret < 0 || ret >= size) { + D(("snprintf failed.")); + free(prompt); + return EFAULT; + } + +- ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, NULL, &answer); +- free(prompt); +- if (ret != PAM_SUCCESS) { +- D(("do_pam_conversation failed.")); +- return ret; ++ if (pi->user_name_hint) { ++ ret = pam_get_item(pamh, PAM_CONV, (const void **)&conv); ++ if (ret != PAM_SUCCESS) { ++ return ret; ++ } ++ if (conv == NULL || conv->conv == NULL) { ++ logger(pamh, LOG_ERR, "No conversation function"); ++ return PAM_SYSTEM_ERR; ++ } ++ ++ m[0].msg_style = PAM_PROMPT_ECHO_OFF; ++ m[0].msg = prompt; ++ m[1].msg_style = PAM_PROMPT_ECHO_ON; ++ m[1].msg = "User name hint: "; ++ ++ mesg[0] = (const struct pam_message *)m; ++ /* The following assignment might look a bit odd but is recommended in the ++ * pam_conv man page to make sure that the second argument of the PAM ++ * conversation function can be interpreted in two different ways. ++ * Basically it is important that both the actual struct pam_message and ++ * the pointers to the struct pam_message are arrays. Since the assignment ++ * makes clear that mesg[] and (*mesg)[] are arrays it should be kept this ++ * way and not be replaced by other equivalent assignments. */ ++ mesg[1] = &((*mesg)[1]); ++ ++ ret = conv->conv(2, mesg, &resp, conv->appdata_ptr); ++ if (ret != PAM_SUCCESS) { ++ D(("Conversation failure: %s.", pam_strerror(pamh, ret))); ++ return ret; ++ } ++ ++ if (resp == NULL) { ++ D(("response expected, but resp==NULL")); ++ return PAM_SYSTEM_ERR; ++ } ++ ++ if (resp[0].resp == NULL || *(resp[0].resp) == '\0') { ++ D(("Missing PIN.")); ++ ret = PAM_CRED_INSUFFICIENT; ++ goto done; ++ } ++ ++ answer = strndup(resp[0].resp, MAX_AUTHTOK_SIZE); ++ _pam_overwrite((void *)resp[0].resp); ++ free(resp[0].resp); ++ resp[0].resp = NULL; ++ if (answer == NULL) { ++ D(("strndup failed")); ++ ret = PAM_BUF_ERR; ++ goto done; ++ } ++ ++ if (resp[1].resp != NULL && *(resp[1].resp) != '\0') { ++ ret = pam_set_item(pamh, PAM_USER, resp[1].resp); ++ free(resp[1].resp); ++ resp[1].resp = NULL; ++ if (ret != PAM_SUCCESS) { ++ D(("Failed to set PAM_USER with user name hint [%s]", ++ pam_strerror(pamh, ret))); ++ goto done; ++ } ++ ++ ret = pam_get_item(pamh, PAM_USER, (const void **)&(pi->pam_user)); ++ if (ret != PAM_SUCCESS) { ++ D(("Failed to get PAM_USER with user name hint [%s]", ++ pam_strerror(pamh, ret))); ++ goto done; ++ } ++ ++ pi->pam_user_size = strlen(pi->pam_user) + 1; ++ } ++ } else { ++ ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt, NULL, ++ &answer); ++ free(prompt); ++ if (ret != PAM_SUCCESS) { ++ D(("do_pam_conversation failed.")); ++ return ret; ++ } + } + + if (answer == NULL) { +@@ -1552,6 +1641,20 @@ done: + free(answer); + answer=NULL; + ++ if (resp != NULL) { ++ if (resp[0].resp != NULL) { ++ _pam_overwrite((void *)resp[0].resp); ++ free(resp[0].resp); ++ } ++ if (resp[1].resp != NULL) { ++ _pam_overwrite((void *)resp[1].resp); ++ free(resp[1].resp); ++ } ++ ++ free(resp); ++ resp = NULL; ++ } ++ + return ret; + } + +@@ -1680,7 +1783,7 @@ static int get_authtok_for_authentication(pam_handle_t *pamh, + ret = prompt_2fa(pamh, pi, _("First Factor: "), + _("Second Factor: ")); + } +- } else if (pi->cert_user != NULL) { ++ } else if (pi->token_name != NULL && *(pi->token_name) != '\0') { + ret = prompt_sc_pin(pamh, pi); + } else { + ret = prompt_password(pamh, pi, _("Password: ")); +diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h +index 59fee7a4eceb2c185e156e812af7f2f4c6b2a0dd..d4198407f2f86c6594aee6a2a43775e429692df0 100644 +--- a/src/sss_client/sss_cli.h ++++ b/src/sss_client/sss_cli.h +@@ -427,7 +427,13 @@ enum response_type { + * @param Three zero terminated strings, if one of the + * strings is missing the message will contain only + * an empty string (\0) for that component. */ +- SSS_PAM_CERT_INFO, ++ SSS_PAM_CERT_INFO, /**< A message indicating that Smartcard/certificate ++ * based authentication is available and contains ++ * details about the found Smartcard. ++ * @param user name, zero terminated ++ * @param token name, zero terminated ++ * @param PKCS#11 module name, zero terminated ++ * @param key id, zero terminated */ + SSS_OTP, /**< Indicates that the autotok was a OTP, so don't + * cache it. There is no message. + * @param None. */ +@@ -442,6 +448,9 @@ enum response_type { + * be used together with other prompting options + * to determine the type of prompting. + * @param None. */ ++ SSS_PAM_CERT_INFO_WITH_HINT, /**< Same as SSS_PAM_CERT_INFO but user name ++ * might be missing and should be prompted ++ * for. */ + }; + + /** +-- +2.9.4 + diff --git a/SOURCES/0157-SSH-Use-default_domain_suffix-for-users-authorized-k.patch b/SOURCES/0157-SSH-Use-default_domain_suffix-for-users-authorized-k.patch deleted file mode 100644 index cbfdcb1..0000000 --- a/SOURCES/0157-SSH-Use-default_domain_suffix-for-users-authorized-k.patch +++ /dev/null @@ -1,80 +0,0 @@ -From dfdd2fe5c177d70a0c5db383820f237ebc7e722f Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Thu, 24 Nov 2016 18:07:56 +0100 -Subject: [PATCH 157/157] SSH: Use default_domain_suffix for users' authorized - keys - -In commit eeecc48d22a28bb69da56f6ffd8824163fc9bf00 we disabled -default_domain_suffix for the SSH responder, but in a wrong way -- we -disabled the functionality completely, also for users, not only for -computers. This might have been correct at the time, since SSH keys in ID -overrides are a relatively new feature, but it's definitely not correct -in general. - -Instead, this patch restores the use of default_domain_suffix, but only -for looking up public keys of users, not of computers. - -Resolves: -https://fedorahosted.org/sssd/ticket/3259 - -Reviewed-by: Petr Cech -(cherry picked from commit ed71fba97dfcf5b3f0f1834c06660c481b9ab3ce) -(cherry picked from commit 2949fe58ac344c44d756ca309d4b2b7f3590cee3) ---- - src/responder/ssh/sshsrv_cmd.c | 12 ++++++++---- - 1 file changed, 8 insertions(+), 4 deletions(-) - -diff --git a/src/responder/ssh/sshsrv_cmd.c b/src/responder/ssh/sshsrv_cmd.c -index ab721d66e5299ba6810a599a15a10094d5792092..2e64893dfc2018727e6fc5fb80b47bd7eb1fac58 100644 ---- a/src/responder/ssh/sshsrv_cmd.c -+++ b/src/responder/ssh/sshsrv_cmd.c -@@ -36,7 +36,8 @@ - #include "responder/ssh/sshsrv_private.h" - - static errno_t --ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx); -+ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx, -+ char *default_domain); - - static errno_t - ssh_user_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx); -@@ -57,7 +58,7 @@ sss_ssh_cmd_get_user_pubkeys(struct cli_ctx *cctx) - cmd_ctx->cctx = cctx; - cmd_ctx->is_user = true; - -- ret = ssh_cmd_parse_request(cmd_ctx); -+ ret = ssh_cmd_parse_request(cmd_ctx, cctx->rctx->default_domain); - if (ret != EOK) { - goto done; - } -@@ -107,7 +108,7 @@ sss_ssh_cmd_get_host_pubkeys(struct cli_ctx *cctx) - cmd_ctx->cctx = cctx; - cmd_ctx->is_user = false; - -- ret = ssh_cmd_parse_request(cmd_ctx); -+ ret = ssh_cmd_parse_request(cmd_ctx, NULL); - if (ret != EOK) { - goto done; - } -@@ -681,7 +682,8 @@ done: - } - - static errno_t --ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx) -+ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx, -+ char *default_domain) - { - struct cli_protocol *pctx; - struct ssh_ctx *ssh_ctx; -@@ -754,6 +756,8 @@ ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx) - return EINVAL; - } - c += domain_len; -+ } else { -+ domain = default_domain; - } - - DEBUG(SSSDBG_TRACE_FUNC, --- -2.9.3 - diff --git a/SOURCES/0157-add_pam_cert_response-add-support-for-SSS_PAM_CERT_I.patch b/SOURCES/0157-add_pam_cert_response-add-support-for-SSS_PAM_CERT_I.patch new file mode 100644 index 0000000..a9a73fd --- /dev/null +++ b/SOURCES/0157-add_pam_cert_response-add-support-for-SSS_PAM_CERT_I.patch @@ -0,0 +1,104 @@ +From c5c6ba2546d350a7a01a9f44bb5df9c6652a1e06 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 8 May 2017 16:02:36 +0200 +Subject: [PATCH 157/160] add_pam_cert_response: add support for + SSS_PAM_CERT_INFO_WITH_HINT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related to https://pagure.io/SSSD/sssd/issue/3395 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 6073cfc40747cd6d3142f0f98b880fc390dd7aad) +--- + src/responder/pam/pamsrv.h | 2 +- + src/responder/pam/pamsrv_cmd.c | 3 ++- + src/responder/pam/pamsrv_p11.c | 21 +++++++++++++++------ + 3 files changed, 18 insertions(+), 8 deletions(-) + +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index b569748fe2a2005cee5df34bef55e803175492a9..57a37b72594f030995f5e22255eb7a8fcd63d10e 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -101,7 +101,7 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + + errno_t add_pam_cert_response(struct pam_data *pd, const char *user, + const char *token_name, const char *module_name, +- const char *key_id); ++ const char *key_id, enum response_type type); + + bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd); + +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index 36dba37964b71153435b4df5d5328de4361926e6..080cfafa709d63542fbf57d26fab11f0a367dea7 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1846,7 +1846,8 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) + ret = add_pam_cert_response(preq->pd, cert_user, + preq->token_name, + preq->module_name, +- preq->key_id); ++ preq->key_id, ++ SSS_PAM_CERT_INFO); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n"); + preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index 365300b9075983b603a6f9e91ba6f8f21706388f..4dce43800c3c6b026c545df35c846269cbb49610 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -580,7 +580,7 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + + errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, + const char *token_name, const char *module_name, +- const char *key_id) ++ const char *key_id, enum response_type type) + { + uint8_t *msg = NULL; + char *env = NULL; +@@ -590,14 +590,23 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, + size_t module_len; + size_t key_id_len; + int ret; ++ const char *username = ""; + +- if (sysdb_username == NULL || token_name == NULL || module_name == NULL +- || key_id == NULL) { ++ if (type != SSS_PAM_CERT_INFO && type != SSS_PAM_CERT_INFO_WITH_HINT) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid response type [%d].\n", type); ++ return EINVAL; ++ } ++ ++ if ((type == SSS_PAM_CERT_INFO && sysdb_username == NULL) ++ || token_name == NULL || module_name == NULL || key_id == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Missing mandatory user or slot name.\n"); + return EINVAL; + } + +- user_len = strlen(sysdb_username) + 1; ++ if (sysdb_username != NULL) { ++ username = sysdb_username; ++ } ++ user_len = strlen(username) + 1; + slot_len = strlen(token_name) + 1; + module_len = strlen(module_name) + 1; + key_id_len = strlen(key_id) + 1; +@@ -616,12 +625,12 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, + * re_expression config option was set in a way that user@domain cannot be + * handled anymore some more logic has to be added here. But for the time + * being I think using sysdb_username is fine. */ +- memcpy(msg, sysdb_username, user_len); ++ memcpy(msg, username, user_len); + memcpy(msg + user_len, token_name, slot_len); + memcpy(msg + user_len + slot_len, module_name, module_len); + memcpy(msg + user_len + slot_len + module_len, key_id, key_id_len); + +- ret = pam_add_response(pd, SSS_PAM_CERT_INFO, msg_len, msg); ++ ret = pam_add_response(pd, type, msg_len, msg); + talloc_free(msg); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +-- +2.9.4 + diff --git a/SOURCES/0158-PAM-send-user-name-hint-response-when-needed.patch b/SOURCES/0158-PAM-send-user-name-hint-response-when-needed.patch new file mode 100644 index 0000000..a444dcf --- /dev/null +++ b/SOURCES/0158-PAM-send-user-name-hint-response-when-needed.patch @@ -0,0 +1,335 @@ +From a531a785f57be7ae228ca04a7af606debd66eeb1 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 3 May 2017 16:30:12 +0200 +Subject: [PATCH 158/160] PAM: send user name hint response when needed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the PAM client didn't send a user name and promtusername is enable +the PAM responder will tell pam_sss to ask for an optional user name as +well. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3395 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 32474fa2f0a6dc09386bab405fc3461cb3dd12ac) +--- + src/responder/pam/pamsrv_cmd.c | 72 ++++++++++------ + src/tests/cmocka/test_pam_srv.c | 180 +++++++++++++++++++++++++++++----------- + 2 files changed, 177 insertions(+), 75 deletions(-) + +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index 080cfafa709d63542fbf57d26fab11f0a367dea7..49a05657e03feef564d6196029da4cacc2ab8eaf 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1414,7 +1414,7 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + struct cache_req_result **results; + struct pam_auth_req *preq = tevent_req_callback_data(req, + struct pam_auth_req); +- const char *cert_user; ++ const char *cert_user = NULL; + + ret = cache_req_recv(preq, req, &results); + talloc_zfree(req); +@@ -1439,35 +1439,55 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + goto done; + } + +- if (preq->cert_user_objs->count != 1) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "More than one user mapped to certificate.\n"); +- /* TODO: send pam response to ask for a user name */ +- ret = ERR_NO_CREDS; +- goto done; +- } +- cert_user = ldb_msg_find_attr_as_string( ++ if (preq->cert_user_objs->count == 1) { ++ cert_user = ldb_msg_find_attr_as_string( + preq->cert_user_objs->msgs[0], + SYSDB_NAME, NULL); ++ if (cert_user == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Certificate user object has not name.\n"); ++ ret = ENOENT; ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_FUNC_DATA, ++ "Found certificate user [%s].\n", cert_user); ++ ++ ret = sss_parse_name_for_domains(preq->pd, ++ preq->cctx->rctx->domains, ++ preq->cctx->rctx->default_domain, ++ cert_user, ++ &preq->pd->domain, ++ &preq->pd->user); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sss_parse_name_for_domains failed.\n"); ++ goto done; ++ } ++ } ++ ++ if (preq->cctx->rctx->domains->user_name_hint) { ++ ret = add_pam_cert_response(preq->pd, cert_user, ++ preq->token_name, ++ preq->module_name, ++ preq->key_id, ++ SSS_PAM_CERT_INFO_WITH_HINT); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n"); ++ preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; ++ } ++ ret = EOK; ++ preq->pd->pam_status = PAM_SUCCESS; ++ pam_reply(preq); ++ goto done; ++ } ++ ++ /* Without user name hints the certificate must map to single user ++ * if no login name was given */ + if (cert_user == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "Certificate user object has not name.\n"); +- ret = ENOENT; +- goto done; +- } +- +- DEBUG(SSSDBG_FUNC_DATA, "Found certificate user [%s].\n", +- cert_user); +- +- ret = sss_parse_name_for_domains(preq->pd, +- preq->cctx->rctx->domains, +- preq->cctx->rctx->default_domain, +- cert_user, +- &preq->pd->domain, +- &preq->pd->user); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "sss_parse_name_for_domains failed.\n"); ++ "More than one user mapped to certificate.\n"); ++ ret = ERR_NO_CREDS; + goto done; + } + +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index 35afbdd81d004236885ee80914771ccb4b8acff4..0f92f05417025e41a702127099d1d01e269412dc 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -747,57 +747,83 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, + return EOK; + } + ++static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, ++ enum response_type type, const char *name) ++{ ++ size_t rp = 0; ++ uint32_t val; ++ ++ assert_int_equal(status, 0); ++ ++ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); ++ assert_int_equal(val, pam_test_ctx->exp_pam_status); ++ ++ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); ++ if (name == NULL || *name == '\0') { ++ assert_int_equal(val, 1); ++ } else { ++ assert_int_equal(val, 2); ++ ++ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); ++ assert_int_equal(val, SSS_PAM_DOMAIN_NAME); ++ ++ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); ++ assert_int_equal(val, 9); ++ ++ assert_int_equal(*(body + rp + val - 1), 0); ++ assert_string_equal(body + rp, TEST_DOM_NAME); ++ rp += val; ++ } ++ ++ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); ++ assert_int_equal(val, type); ++ ++ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); ++ assert_int_equal(val, (strlen(name) + 1 ++ + sizeof(TEST_TOKEN_NAME) ++ + sizeof(TEST_MODULE_NAME) ++ + sizeof(TEST_KEY_ID))); ++ ++ assert_int_equal(*(body + rp + strlen(name)), 0); ++ assert_string_equal(body + rp, name); ++ rp += strlen(name) + 1; ++ ++ assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0); ++ assert_string_equal(body + rp, TEST_TOKEN_NAME); ++ rp += sizeof(TEST_TOKEN_NAME); ++ ++ assert_int_equal(*(body + rp + sizeof(TEST_MODULE_NAME) - 1), 0); ++ assert_string_equal(body + rp, TEST_MODULE_NAME); ++ rp += sizeof(TEST_MODULE_NAME); ++ ++ assert_int_equal(*(body + rp + sizeof(TEST_KEY_ID) - 1), 0); ++ assert_string_equal(body + rp, TEST_KEY_ID); ++ rp += sizeof(TEST_KEY_ID); ++ ++ assert_int_equal(rp, blen); ++ ++ return EOK; ++} ++ + static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen) + { +- size_t rp = 0; +- uint32_t val; +- +- assert_int_equal(status, 0); +- +- SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); +- assert_int_equal(val, pam_test_ctx->exp_pam_status); +- +- SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); +- assert_int_equal(val, 2); +- +- SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); +- assert_int_equal(val, SSS_PAM_DOMAIN_NAME); +- +- SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); +- assert_int_equal(val, 9); +- +- assert_int_equal(*(body + rp + val - 1), 0); +- assert_string_equal(body + rp, TEST_DOM_NAME); +- rp += val; +- +- SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); +- assert_int_equal(val, SSS_PAM_CERT_INFO); +- +- SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); +- assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME) +- + sizeof(TEST_TOKEN_NAME) +- + sizeof(TEST_MODULE_NAME) +- + sizeof(TEST_KEY_ID))); +- +- assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0); +- assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME); +- rp += sizeof("pamuser@"TEST_DOM_NAME); +- +- assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0); +- assert_string_equal(body + rp, TEST_TOKEN_NAME); +- rp += sizeof(TEST_TOKEN_NAME); +- +- assert_int_equal(*(body + rp + sizeof(TEST_MODULE_NAME) - 1), 0); +- assert_string_equal(body + rp, TEST_MODULE_NAME); +- rp += sizeof(TEST_MODULE_NAME); +- +- assert_int_equal(*(body + rp + sizeof(TEST_KEY_ID) - 1), 0); +- assert_string_equal(body + rp, TEST_KEY_ID); +- rp += sizeof(TEST_KEY_ID); +- +- assert_int_equal(rp, blen); +- +- return EOK; ++ return test_pam_cert_check_ex(status, body, blen, ++ SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME); ++} ++ ++static int test_pam_cert_check_with_hint(uint32_t status, uint8_t *body, ++ size_t blen) ++{ ++ return test_pam_cert_check_ex(status, body, blen, ++ SSS_PAM_CERT_INFO_WITH_HINT, ++ "pamuser@"TEST_DOM_NAME); ++} ++ ++static int test_pam_cert_check_with_hint_no_user(uint32_t status, uint8_t *body, ++ size_t blen) ++{ ++ return test_pam_cert_check_ex(status, body, blen, ++ SSS_PAM_CERT_INFO_WITH_HINT, ""); + } + + static int test_pam_offline_chauthtok_check(uint32_t status, +@@ -1895,6 +1921,33 @@ void test_pam_preauth_cert_no_logon_name(void **state) + assert_int_equal(ret, EOK); + } + ++void test_pam_preauth_cert_no_logon_name_with_hint(void **state) ++{ ++ int ret; ++ ++ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); ++ pam_test_ctx->rctx->domains->user_name_hint = true; ++ ++ /* If no logon name is given the user is looked by certificate first. ++ * Since user name hint is enabled we do not have to search the user ++ * during pre-auth and there is no need for an extra mocked response as in ++ * test_pam_preauth_cert_no_logon_name. */ ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, ++ test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ set_cmd_cb(test_pam_cert_check_with_hint); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ + void test_pam_preauth_cert_no_logon_name_double_cert(void **state) + { + int ret; +@@ -1917,6 +1970,29 @@ void test_pam_preauth_cert_no_logon_name_double_cert(void **state) + assert_int_equal(ret, EOK); + } + ++void test_pam_preauth_cert_no_logon_name_double_cert_with_hint(void **state) ++{ ++ int ret; ++ ++ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); ++ pam_test_ctx->rctx->domains->user_name_hint = true; ++ ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, ++ test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, false); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ set_cmd_cb(test_pam_cert_check_with_hint_no_user); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ + void test_pam_preauth_no_cert_no_logon_name(void **state) + { + int ret; +@@ -2426,8 +2502,14 @@ int main(int argc, const char *argv[]) + cmocka_unit_test_setup_teardown(test_pam_preauth_cert_no_logon_name, + pam_test_setup, pam_test_teardown), + cmocka_unit_test_setup_teardown( ++ test_pam_preauth_cert_no_logon_name_with_hint, ++ pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown( + test_pam_preauth_cert_no_logon_name_double_cert, + pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown( ++ test_pam_preauth_cert_no_logon_name_double_cert_with_hint, ++ pam_test_setup, pam_test_teardown), + cmocka_unit_test_setup_teardown(test_pam_preauth_no_cert_no_logon_name, + pam_test_setup, pam_test_teardown), + cmocka_unit_test_setup_teardown( +-- +2.9.4 + diff --git a/SOURCES/0158-SERVER-Set-the-process-group-during-server_setup.patch b/SOURCES/0158-SERVER-Set-the-process-group-during-server_setup.patch deleted file mode 100644 index 7fc6190..0000000 --- a/SOURCES/0158-SERVER-Set-the-process-group-during-server_setup.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 7e0a61d1c10f30e694f5f536b374c72f774b50a1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Sun, 8 Jan 2017 23:27:57 +0100 -Subject: [PATCH 158/160] SERVER: Set the process group during server_setup() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -By calling setpgid() in server_setup() we are able to kill the process -in the watchdog by simply doing kill(-getpid(), SIGTERM). - -However, in order to have it working properly the SELinux policy for -SSSD has to be updated and unless SSSD is ran with SELinux on permissive -mode, each of the responders and the monitor will trigger a similar -message: - - Jan 09 14:31:50 client1.ipa.example audit[11630]: AVC avc: denied - { setpgid } for pid=11630 comm="sssd_pac" - scontext=system_u:system_r:sssd_t:s0 - tcontext=system_u:system_r:sssd_t:s0 tclass=process permissive=0 - -It's important to say that till SELinux policy is fixed, we might end up -leaking some processes. - -Related: -https://fedorahosted.org/sssd/ticket/3266 - -Signed-off-by: Fabiano Fidêncio -Reviewed-by: Lukáš Slebodník -(cherry picked from commit 087162b85e191af51637904702813969b35eaadc) -(cherry picked from commit 442985a7af2262fab57f56c7a8cd40af10081610) ---- - src/monitor/monitor.c | 6 +++--- - src/util/server.c | 11 +++++++++++ - 2 files changed, 14 insertions(+), 3 deletions(-) - -diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c -index 0f01580e01b6a0a9ab507a54183e5813133be5a9..17e980dbf165634491a05012399945f2d21c2056 100644 ---- a/src/monitor/monitor.c -+++ b/src/monitor/monitor.c -@@ -1606,7 +1606,7 @@ static void monitor_quit(struct mt_ctx *mt_ctx, int ret) - "Terminating [%s][%d]\n", svc->name, svc->pid); - do { - errno = 0; -- kret = kill(svc->pid, SIGTERM); -+ kret = kill(-svc->pid, SIGTERM); - if (kret < 0) { - error = errno; - DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't kill [%s][%d]: [%s]\n", -@@ -1627,7 +1627,7 @@ static void monitor_quit(struct mt_ctx *mt_ctx, int ret) - "[%d][%s] while waiting for [%s]\n", - error, strerror(error), svc->name); - /* Forcibly kill this child */ -- kill(svc->pid, SIGKILL); -+ kill(-svc->pid, SIGKILL); - break; - } - } else if (pid != 0) { -@@ -1642,7 +1642,7 @@ static void monitor_quit(struct mt_ctx *mt_ctx, int ret) - DEBUG(SSSDBG_FATAL_FAILURE, - "Child [%s] did not exit cleanly\n", svc->name); - /* Forcibly kill this child */ -- kill(svc->pid, SIGKILL); -+ kill(-svc->pid, SIGKILL); - } - killed = true; - } -diff --git a/src/util/server.c b/src/util/server.c -index 013e572e6284b16534910088f7801219251896d8..d333c3c3c771c38005183831fc7a4b004a59a6c3 100644 ---- a/src/util/server.c -+++ b/src/util/server.c -@@ -460,6 +460,17 @@ int server_setup(const char *name, int flags, - struct logrotate_ctx *lctx; - char *locale; - int watchdog_interval; -+ pid_t my_pid; -+ -+ my_pid = getpid(); -+ ret = setpgid(my_pid, my_pid); -+ if (ret != EOK) { -+ ret = errno; -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Failed setting process group: %s[%d]. " -+ "We might leak processes in case of failure\n", -+ sss_strerror(ret), ret); -+ } - - ret = chown_debug_file(NULL, uid, gid); - if (ret != EOK) { --- -2.9.3 - diff --git a/SOURCES/0159-WATCHDOG-define-and-use-_MAX_TICKS-as-3.patch b/SOURCES/0159-WATCHDOG-define-and-use-_MAX_TICKS-as-3.patch deleted file mode 100644 index 9e2d757..0000000 --- a/SOURCES/0159-WATCHDOG-define-and-use-_MAX_TICKS-as-3.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 57404a6b7ca0d86ba661e358f3544a32ef4e15bc Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Mon, 15 Aug 2016 12:54:20 +0200 -Subject: [PATCH 159/160] WATCHDOG: define and use _MAX_TICKS as 3 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Instead of using the number 3 directly, let's introduce and use -WATCHDOG_MAX_TICKS. - -Reviewed-by: Petr Čech -(cherry picked from commit d7075a255a1f28e890539072e06d0140ffe0927c) ---- - src/util/util_watchdog.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/util/util_watchdog.c b/src/util/util_watchdog.c -index 1c27d73f13b3042ecb549a2184e1368e8339d199..c184fbd759bdbca4a9eae379ff0d87e2d1628470 100644 ---- a/src/util/util_watchdog.c -+++ b/src/util/util_watchdog.c -@@ -22,6 +22,7 @@ - #include "util/util.h" - - #define WATCHDOG_DEF_INTERVAL 10 -+#define WATCHDOG_MAX_TICKS 3 - - /* this is intentionally a global variable */ - struct watchdog_ctx { -@@ -75,9 +76,8 @@ static void watchdog_handler(int sig) - return; - } - -- /* if 3 ticks passed by kills itself */ -- -- if (__sync_add_and_fetch(&watchdog_ctx.ticks, 1) > 3) { -+ /* if a pre-defined number of ticks passed by kills itself */ -+ if (__sync_add_and_fetch(&watchdog_ctx.ticks, 1) > WATCHDOG_MAX_TICKS) { - DEBUG(SSSDBG_FATAL_FAILURE, - "Watchdog timer overflow, killing process!\n"); - orderly_shutdown(1); --- -2.9.3 - diff --git a/SOURCES/0159-sysdb-sysdb_get_certmap-allow-empty-certmap.patch b/SOURCES/0159-sysdb-sysdb_get_certmap-allow-empty-certmap.patch new file mode 100644 index 0000000..290bab5 --- /dev/null +++ b/SOURCES/0159-sysdb-sysdb_get_certmap-allow-empty-certmap.patch @@ -0,0 +1,105 @@ +From b435e510fb06af4e8f3cffd3730f43a6aff165fa Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 8 May 2017 17:30:06 +0200 +Subject: [PATCH 159/160] sysdb: sysdb_get_certmap() allow empty certmap +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since sysdb_get_certmap() returns the user name hint information as well +it should return a result even if there are no certmaps. + +Related to https://pagure.io/SSSD/sssd/issue/3395 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit ee7e72a65d323636600ffda271d5b5c4ddbc78b1) +--- + src/db/sysdb_certmap.c | 13 ++++++++----- + src/tests/cmocka/test_sysdb_certmap.c | 9 +++++---- + 2 files changed, 13 insertions(+), 9 deletions(-) + +diff --git a/src/db/sysdb_certmap.c b/src/db/sysdb_certmap.c +index 4917796b11c3967b4d147ebee7c7e83f09b872ce..2d89c08a07be6e8eaf853d6c50b206c5c53d5a37 100644 +--- a/src/db/sysdb_certmap.c ++++ b/src/db/sysdb_certmap.c +@@ -269,7 +269,7 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, + size_t d; + struct ldb_dn *container_dn = NULL; + int ret; +- struct certmap_info **maps; ++ struct certmap_info **maps = NULL; + TALLOC_CTX *tmp_ctx = NULL; + struct ldb_result *res; + const char *tmp_str; +@@ -320,7 +320,7 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, + + if (res->count == 0) { + DEBUG(SSSDBG_TRACE_FUNC, "No certificate maps found.\n"); +- ret = ENOENT; ++ ret = EOK; + goto done; + } + +@@ -377,7 +377,7 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, + SYSDB_CERTMAP_PRIORITY, + (uint64_t) -1); + if (tmp_uint != (uint64_t) -1) { +- if (tmp_uint >= UINT32_MAX) { ++ if (tmp_uint > UINT32_MAX) { + DEBUG(SSSDBG_OP_FAILURE, "Priority value [%lu] too large.\n", + (unsigned long) tmp_uint); + ret = EINVAL; +@@ -414,11 +414,14 @@ errno_t sysdb_get_certmap(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, + } + } + +- *certmaps = talloc_steal(mem_ctx, maps); +- *user_name_hint = hint; + ret = EOK; + + done: ++ if (ret == EOK) { ++ *certmaps = talloc_steal(mem_ctx, maps); ++ *user_name_hint = hint; ++ } ++ + talloc_free(tmp_ctx); + + return ret; +diff --git a/src/tests/cmocka/test_sysdb_certmap.c b/src/tests/cmocka/test_sysdb_certmap.c +index fb07165561779226935f436c308c85abfc305635..72edf5f53fd6d23d7279eaa496b3e798c06cb903 100644 +--- a/src/tests/cmocka/test_sysdb_certmap.c ++++ b/src/tests/cmocka/test_sysdb_certmap.c +@@ -88,8 +88,8 @@ static void test_sysdb_get_certmap_not_exists(void **state) + + ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, + &user_name_hint); +- assert_int_equal(ret, ENOENT); +- ++ assert_int_equal(ret, EOK); ++ assert_null(certmap); + } + + static void check_certmap(struct certmap_info *m, struct certmap_info *r, +@@ -134,7 +134,7 @@ static void test_sysdb_update_certmap(void **state) + int ret; + const char *domains[] = { "dom1.test", "dom2.test", "dom3.test", NULL }; + struct certmap_info map_a = { discard_const("map_a"), 11, discard_const("abc"), discard_const("def"), NULL }; +- struct certmap_info map_b = { discard_const("map_b"), 22, discard_const("abc"), NULL, domains }; ++ struct certmap_info map_b = { discard_const("map_b"), UINT_MAX, discard_const("abc"), NULL, domains }; + struct certmap_info *certmap_empty[] = { NULL }; + struct certmap_info *certmap_a[] = { &map_a, NULL }; + struct certmap_info *certmap_b[] = { &map_b, NULL }; +@@ -152,7 +152,8 @@ static void test_sysdb_update_certmap(void **state) + + ret = sysdb_get_certmap(ctctx, ctctx->tctx->sysdb, &certmap, + &user_name_hint); +- assert_int_equal(ret, ENOENT); ++ assert_int_equal(ret, EOK); ++ assert_null(certmap); + + ret = sysdb_update_certmap(ctctx->tctx->sysdb, certmap_a, false); + assert_int_equal(ret, EOK); +-- +2.9.4 + diff --git a/SOURCES/0160-WATCHDOG-Avoid-non-async-signal-safe-from-the-signal.patch b/SOURCES/0160-WATCHDOG-Avoid-non-async-signal-safe-from-the-signal.patch deleted file mode 100644 index 68c466e..0000000 --- a/SOURCES/0160-WATCHDOG-Avoid-non-async-signal-safe-from-the-signal.patch +++ /dev/null @@ -1,294 +0,0 @@ -From 6955a5c2a0abf38adace2553f21ea072416b1f61 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Wed, 7 Dec 2016 21:36:56 +0100 -Subject: [PATCH 160/160] WATCHDOG: Avoid non async-signal-safe from the - signal_handler -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -While debugging rhbz#1396912 a deadlock on sssd_be was noticed[0] and -it's been caused by the use of non async-signal-safe functions from the -signal_handler (please, see man 7 signal for more info about which are -the async-signal-safe functions that can be used). - -In order to work this situation around a pipe has been added to the -watchdog_ctx structure and, in case of clock screw, a single byte is -written to this pipe (which is an async-signal-safe operation) and the -logic currently done by the timer handler to reset the watchdog will be -done inside the fd handler in a safe way. - -With this patch we ended up losing some debug messages as -orderly_shutdown() has been replaced by kill(-getpgrp(), SIGTERM) (or -_exit(1) considering the cases where setting up the process group during -the server_setup() has failed). -Personally I don't think is worth the trouble to try to log those messages -properly in this specific case. - -It's really worth to mention that a proper fix the clock screw situation -should be implemented on samba's side, by having tevent using monotonic -(or boottime) clock. - -[0]: - [root@dusan ~]# pstack 17922 - #0 __lll_lock_wait_private () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95 - #1 0x00007fe707d04f93 in _L_lock_14932 () from /lib64/libc.so.6 - #2 0x00007fe707d02013 in __GI___libc_malloc (bytes=140630248638304, bytes@entry=15) at malloc.c:2891 - #3 0x00007fe707d0888a in __GI___strdup (s=0x7fe707dff4f7 "/etc/localtime") at strdup.c:42 - #4 0x00007fe707d31b61 in tzset_internal (always=, explicit=explicit@entry=1) at tzset.c:438 - #5 0x00007fe707d32523 in __tz_convert (timer=timer@entry=0x7ffcd5d2b090, use_localtime=use_localtime@entry=1, tp=tp@entry=0x7fe708041d40 <_tmbuf>) at tzset.c:621 - #6 0x00007fe707d30521 in __GI_localtime (t=t@entry=0x7ffcd5d2b090) at localtime.c:42 - #7 0x00007fe70886c7b0 in sss_vdebug_fn (file=, line=, function=0x7fe70bff27f0 <__FUNCTION__.9379> "watchdog_handler", level=16, flags=flags@entry=0, format=format@entry=0x7fe70bff2760 "Watchdog timer overflow, killing process!\n", ap=ap@entry=0x7ffcd5d2b130) at src/util/debug.c:248 - #8 0x00007fe70886c995 in sss_debug_fn (file=file@entry=0x7fe70bff263b "src/util/util_watchdog.c", line=line@entry=82, function=function@entry=0x7fe70bff27f0 <__FUNCTION__.9379> "watchdog_handler", level=level@entry=16, format=format@entry=0x7fe70bff2760 "Watchdog timer overflow, killing process!\n") at src/util/debug.c:284 - #9 0x00007fe70bfdb409 in watchdog_handler (sig=) at src/util/util_watchdog.c:81 - #10 - #11 0x00007fe707cff664 in _int_malloc (av=av@entry=0x7fe70803c760 , bytes=bytes@entry=151) at malloc.c:3494 - #12 0x00007fe707d01fbc in __GI___libc_malloc (bytes=bytes@entry=151) at malloc.c:2893 - #13 0x00007fe708450749 in __talloc_with_prefix (prefix_len=0, size=55, context=0x7fe718373210) at ../talloc.c:668 - #14 __talloc (size=55, context=0x7fe718373210) at ../talloc.c:708 - #15 _talloc_named_const (name=0x7fe70bb7015d "../common/ldb_pack.c:425", size=55, context=0x7fe718373210) at ../talloc.c:865 - #16 talloc_named_const (context=, size=size@entry=55, name=name@entry=0x7fe70bb7015d "../common/ldb_pack.c:425") at ../talloc.c:1606 - #17 0x00007fe70bb61803 in ldb_unpack_data_only_attr_list (ldb=ldb@entry=0x7fe70e4d52c0, data=data@entry=0x7ffcd5d2b990, message=0x7fe7184aa1e0, list=list@entry=0x0, list_size=list_size@entry=0, nb_elements_in_db=nb_elements_in_db@entry=0x0) at ../common/ldb_pack.c:425 - #18 0x00007fe70bb61a7d in ldb_unpack_data (ldb=ldb@entry=0x7fe70e4d52c0, data=data@entry=0x7ffcd5d2b990, message=) at ../common/ldb_pack.c:470 - #19 0x00007fe6fdc29b46 in ltdb_parse_data_unpack (key=..., data=..., private_data=0x7ffcd5d2ba70) at ../ldb_tdb/ldb_search.c:249 - #20 0x00007fe70a5e0a24 in tdb_parse_data (tdb=tdb@entry=0x7fe70e4eaa10, key=..., offset=15619748, len=414772, parser=parser@entry=0x7fe6fdc29b10 , private_data=private_data@entry=0x7ffcd5d2ba70) at ../common/io.c:637 - #21 0x00007fe70a5dc1fc in tdb_parse_record (tdb=0x7fe70e4eaa10, key=..., parser=parser@entry=0x7fe6fdc29b10 , private_data=private_data@entry=0x7ffcd5d2ba70) at ../common/tdb.c:253 - #22 0x00007fe6fdc29e7b in ltdb_search_dn1 (module=module@entry=0x7fe70e4eab50, dn=dn@entry=0x7fe7183c4940, msg=msg@entry=0x7fe7184aa1e0) at ../ldb_tdb/ldb_search.c:287 - #23 0x00007fe6fdc2acbb in ltdb_dn_list_load (module=module@entry=0x7fe70e4eab50, dn=dn@entry=0x7fe7183c4940, list=list@entry=0x7fe7183c3a30) at ../ldb_tdb/ldb_index.c:181 - #24 0x00007fe6fdc2bbbb in ltdb_index_add1 (module=module@entry=0x7fe70e4eab50, dn=dn@entry=0x7fe7183bf3e0 "name=testuser7045@domain.com,cn=users,cn=DOMAIN.COM,cn=sysdb", v_idx=v_idx@entry=0, el=, el=) at ../ldb_tdb/ldb_index.c:1134 - #25 0x00007fe6fdc2c62c in ltdb_index_add_el (el=0x7fe7184aa3e0, dn=0x7fe7183bf3e0 "name=testuser7045@domain.com,cn=users,cn=DOMAIN.COM,cn=sysdb", module=0x7fe70e4eab50) at ../ldb_tdb/ldb_index.c:1180 - #26 ltdb_index_add_element (module=module@entry=0x7fe70e4eab50, dn=, el=el@entry=0x7fe7184aa3e0) at ../ldb_tdb/ldb_index.c:1290 - #27 0x00007fe6fdc290bb in ltdb_modify_internal (module=module@entry=0x7fe70e4eab50, msg=0x7fe7183bf0c0, req=req@entry=0x7fe7183bdc10) at ../ldb_tdb/ldb_tdb.c:903 - #28 0x00007fe6fdc2958a in ltdb_modify (ctx=0x7fe7183c2950, ctx=0x7fe7183c2950) at ../ldb_tdb/ldb_tdb.c:998 - #29 ltdb_callback (ev=, te=, t=..., private_data=) at ../ldb_tdb/ldb_tdb.c:1380 - #30 0x00007fe708664b4f in tevent_common_loop_timer_delay (ev=ev@entry=0x7fe70e4d2890) at ../tevent_timed.c:341 - #31 0x00007fe708665b5a in epoll_event_loop_once (ev=0x7fe70e4d2890, location=) at ../tevent_epoll.c:911 - #32 0x00007fe708664257 in std_event_loop_once (ev=0x7fe70e4d2890, location=0x7fe70bb72ec5 "../common/ldb.c:631") at ../tevent_standard.c:114 - #33 0x00007fe70866040d in _tevent_loop_once (ev=ev@entry=0x7fe70e4d2890, location=location@entry=0x7fe70bb72ec5 "../common/ldb.c:631") at ../tevent.c:533 - #34 0x00007fe70bb6bc4f in ldb_wait (handle=0x7fe7183c4530, type=) at ../common/ldb.c:631 - #35 0x00007fe70bb6c793 in ldb_autotransaction_request (ldb=0x7fe70e4d52c0, req=0x7fe7183bdc10) at ../common/ldb.c:573 - #36 0x00007fe70bb6d263 in ldb_modify (ldb=ldb@entry=0x7fe70e4d52c0, message=) at ../common/ldb.c:1655 - #37 0x00007fe70bfa2ab5 in sysdb_set_cache_entry_attr (ldb=0x7fe70e4d52c0, entry_dn=entry_dn@entry=0x7fe7183c4760, attrs=attrs@entry=0x7fe7183bf680, mod_op=mod_op@entry=2) at src/db/sysdb_ops.c:1159 - #38 0x00007fe70bfa304d in sysdb_rep_ts_entry_attr (sysdb=0x7fe70e4eadd0, attrs=0x7fe7183bf680, entry_dn=0x7fe7183c4760) at src/db/sysdb_ops.c:1218 - #39 sysdb_set_ts_entry_attr (sysdb=sysdb@entry=0x7fe70e4eadd0, entry_dn=entry_dn@entry=0x7fe7183c4760, attrs=attrs@entry=0x7fe7183bb840, mod_op=mod_op@entry=2) at src/db/sysdb_ops.c:1248 - #40 0x00007fe70bfa4aa9 in sysdb_set_entry_attr (sysdb=0x7fe70e4eadd0, entry_dn=0x7fe7183c4760, attrs=attrs@entry=0x7fe7183bb840, mod_op=mod_op@entry=2) at src/db/sysdb_ops.c:1199 - #41 0x00007fe70bfa4b5f in sysdb_set_user_attr (domain=domain@entry=0x7fe70e4d62f0, name=name@entry=0x7fe7183c01f0 "testuser7045@domain.com", attrs=attrs@entry=0x7fe7183bb840, mod_op=mod_op@entry=2) at src/db/sysdb_ops.c:1285 - #42 0x00007fe70bfa58c3 in sysdb_add_user (domain=domain@entry=0x7fe70e4d62f0, name=name@entry=0x7fe7183c01f0 "testuser7045@domain.com", uid=uid@entry=1415408147, gid=, gid@entry=1415400513, gecos=gecos@entry=0x7fe710465d00 "Test User7045", homedir=homedir@entry=0x0, shell=shell@entry=0x0, orig_dn=orig_dn@entry=0x7fe710465940 "CN=Test User7045,OU=Sales,DC=DOMAIN,DC=COM", attrs=attrs@entry=0x7fe7183bb840, cache_timeout=cache_timeout@entry=5400, now=now@entry=1481105315) at src/db/sysdb_ops.c:1928 - #43 0x00007fe70bfab271 in sysdb_store_new_user (now=1481105315, cache_timeout=5400, attrs=0x7fe7183bb840, orig_dn=0x7fe710465940 "CN=Test User7045,OU=Sales,DC=DOMAIN,DC=COM", shell=0x0, homedir=0x0, gecos=0x7fe710465d00 "Test User7045", gid=1415400513, uid=1415408147, name=0x7fe7183c01f0 "testuser7045@domain.com", domain=0x7fe70e4d62f0) at src/db/sysdb_ops.c:2549 - #44 sysdb_store_user (domain=domain@entry=0x7fe70e4d62f0, name=0x7fe7183c01f0 "testuser7045@domain.com", pwd=pwd@entry=0x0, uid=1415408147, gid=1415400513, gecos=gecos@entry=0x7fe710465d00 "Test User7045", homedir=homedir@entry=0x0, shell=shell@entry=0x0, orig_dn=orig_dn@entry=0x7fe710465940 "CN=Test User7045,OU=Sales,DC=DOMAIN,DC=COM", attrs=attrs@entry=0x7fe7183bb840, remove_attrs=0x7fe7183c08a0, cache_timeout=cache_timeout@entry=5400, now=now@entry=1481105315) at src/db/sysdb_ops.c:2499 - #45 0x00007fe6fba0d9f9 in sdap_save_user (memctx=memctx@entry=0x7fe70e544ee0, opts=opts@entry=0x7fe70e518400, dom=dom@entry=0x7fe70e4d62f0, attrs=, _usn_value=_usn_value@entry=0x7ffcd5d2c260, now=now@entry=1481105315) at src/providers/ldap/sdap_async_users.c:509 - #46 0x00007fe6fba0df9a in sdap_save_users (memctx=memctx@entry=0x7fe70e544e40, sysdb=0x7fe70e4eadd0, dom=0x7fe70e4d62f0, opts=0x7fe70e518400, users=, num_users=10006, _usn_value=_usn_value@entry=0x7fe70e544e60) at src/providers/ldap/sdap_async_users.c:572 - #47 0x00007fe6fba0e460 in sdap_get_users_done (subreq=) at src/providers/ldap/sdap_async_users.c:938 - #48 0x00007fe6fba0c9d5 in sdap_search_user_process (subreq=0x0) at src/providers/ldap/sdap_async_users.c:814 - #49 0x00007fe6fba07379 in generic_ext_search_handler (subreq=0x0, opts=) at src/providers/ldap/sdap_async.c:1689 - #50 0x00007fe6fba0991b in sdap_get_generic_op_finished (op=, reply=, error=, pvt=) at src/providers/ldap/sdap_async.c:1621 - #51 0x00007fe6fba083cd in sdap_process_message (ev=, sh=, msg=0x7fe70e5f9ce0) at src/providers/ldap/sdap_async.c:353 - #52 sdap_process_result (ev=, pvt=) at src/providers/ldap/sdap_async.c:197 - #53 0x00007fe708664b4f in tevent_common_loop_timer_delay (ev=ev@entry=0x7fe70e4cbc30) at ../tevent_timed.c:341 - #54 0x00007fe708665b5a in epoll_event_loop_once (ev=0x7fe70e4cbc30, location=) at ../tevent_epoll.c:911 - #55 0x00007fe708664257 in std_event_loop_once (ev=0x7fe70e4cbc30, location=0x7fe70bfee8e7 "src/util/server.c:702") at ../tevent_standard.c:114 - #56 0x00007fe70866040d in _tevent_loop_once (ev=ev@entry=0x7fe70e4cbc30, location=location@entry=0x7fe70bfee8e7 "src/util/server.c:702") at ../tevent.c:533 - #57 0x00007fe7086605ab in tevent_common_loop_wait (ev=0x7fe70e4cbc30, location=0x7fe70bfee8e7 "src/util/server.c:702") at ../tevent.c:637 - #58 0x00007fe7086641f7 in std_event_loop_wait (ev=0x7fe70e4cbc30, location=0x7fe70bfee8e7 "src/util/server.c:702") at ../tevent_standard.c:140 - #59 0x00007fe70bfd1993 in server_loop (main_ctx=0x7fe70e4cd080) at src/util/server.c:702 - #60 0x00007fe70c84cb82 in main (argc=8, argv=) at src/providers/data_provider_be.c:587 - -Resolves: -https://fedorahosted.org/sssd/ticket/3266 - -Signed-off-by: Fabiano Fidêncio -Reviewed-by: Pavel Březina -Reviewed-by: Jakub Hrozek -Reviewed-by: Simo Sorce -(cherry picked from commit e6a5f8c58539fc31fd81fac89cfc85703b4250ea) -(cherry picked from commit 0606a71b698c4acf954ba7284e62acbd0aa5e52d) ---- - src/util/util_watchdog.c | 118 ++++++++++++++++++++++++++++++++++++++--------- - 1 file changed, 96 insertions(+), 22 deletions(-) - -diff --git a/src/util/util_watchdog.c b/src/util/util_watchdog.c -index c184fbd759bdbca4a9eae379ff0d87e2d1628470..0df85b71c0b078dc2dfd23a39df82d1a10bad7d6 100644 ---- a/src/util/util_watchdog.c -+++ b/src/util/util_watchdog.c -@@ -23,6 +23,7 @@ - - #define WATCHDOG_DEF_INTERVAL 10 - #define WATCHDOG_MAX_TICKS 3 -+#define DEFAULT_BUFFER_SIZE 4096 - - /* this is intentionally a global variable */ - struct watchdog_ctx { -@@ -35,32 +36,27 @@ struct watchdog_ctx { - struct tevent_context *ev; - int input_interval; - time_t timestamp; -+ struct tevent_fd *tfd; -+ int pipefd[2]; - } watchdog_ctx; - --static bool watchdog_detect_timeshift(void) -+static void watchdog_detect_timeshift(void) - { - time_t prev_time; - time_t cur_time; -- errno_t ret; - - prev_time = watchdog_ctx.timestamp; - cur_time = watchdog_ctx.timestamp = time(NULL); - if (cur_time < prev_time) { - /* Time shift detected. We need to restart watchdog. */ -- DEBUG(SSSDBG_IMPORTANT_INFO, "Time shift detected, " -- "restarting watchdog!\n"); -- teardown_watchdog(); -- ret = setup_watchdog(watchdog_ctx.ev, watchdog_ctx.input_interval); -- if (ret != EOK) { -- DEBUG(SSSDBG_FATAL_FAILURE, "Unable to restart watchdog " -- "[%d]: %s\n", ret, sss_strerror(ret)); -- orderly_shutdown(1); -+ if (write(watchdog_ctx.pipefd[1], "1", 1) != 1) { -+ if (getpid() == getpgrp()) { -+ kill(-getpgrp(), SIGTERM); -+ } else { -+ _exit(1); -+ } - } -- -- return true; - } -- -- return false; - } - - /* the watchdog is purposefully *not* handled by the tevent -@@ -70,17 +66,16 @@ static bool watchdog_detect_timeshift(void) - * signals either */ - static void watchdog_handler(int sig) - { -- /* Do not count ticks if time shift was detected -- * since watchdog was restarted. */ -- if (watchdog_detect_timeshift()) { -- return; -- } -+ -+ watchdog_detect_timeshift(); - - /* if a pre-defined number of ticks passed by kills itself */ - if (__sync_add_and_fetch(&watchdog_ctx.ticks, 1) > WATCHDOG_MAX_TICKS) { -- DEBUG(SSSDBG_FATAL_FAILURE, -- "Watchdog timer overflow, killing process!\n"); -- orderly_shutdown(1); -+ if (getpid() == getpgrp()) { -+ kill(-getpgrp(), SIGTERM); -+ } else { -+ _exit(1); -+ } - } - } - -@@ -109,10 +104,67 @@ static void watchdog_event_handler(struct tevent_context *ev, - } - } - -+static errno_t watchdog_fd_recv_data(int fd) -+{ -+ ssize_t len; -+ char buffer[DEFAULT_BUFFER_SIZE]; -+ errno_t ret; -+ -+ errno = 0; -+ len = read(fd, buffer, DEFAULT_BUFFER_SIZE); -+ if (len == -1) { -+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { -+ return EAGAIN; -+ } else { -+ ret = errno; -+ DEBUG(SSSDBG_CRIT_FAILURE, -+ "write failed [%d]: %s\n", ret, strerror(ret)); -+ return ret; -+ } -+ } -+ -+ return EOK; -+} -+ -+static void watchdog_fd_read_handler(struct tevent_context *ev, -+ struct tevent_fd *fde, -+ uint16_t flags, -+ void *data) -+{ -+ errno_t ret; -+ -+ ret = watchdog_fd_recv_data(watchdog_ctx.pipefd[0]); -+ switch(ret) { -+ case EAGAIN: -+ DEBUG(SSSDBG_TRACE_ALL, -+ "Interrupted before any data could be read, retry later.\n"); -+ return; -+ case EOK: -+ /* all fine */ -+ break; -+ default: -+ DEBUG(SSSDBG_FATAL_FAILURE, -+ "Failed to receive data [%d]: %s. " -+ "orderly_shutdown() will be called.\n", ret, strerror(ret)); -+ orderly_shutdown(1); -+ } -+ -+ DEBUG(SSSDBG_IMPORTANT_INFO, "Time shift detected, " -+ "restarting watchdog!\n"); -+ teardown_watchdog(); -+ ret = setup_watchdog(watchdog_ctx.ev, watchdog_ctx.input_interval); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to restart watchdog " -+ "[%d]: %s\n", ret, sss_strerror(ret)); -+ orderly_shutdown(1); -+ } -+} -+ - int setup_watchdog(struct tevent_context *ev, int interval) - { - struct sigevent sev; - struct itimerspec its; -+ struct tevent_fd *tfd; - int signum = SIGRTMIN; - int ret; - -@@ -142,6 +194,21 @@ int setup_watchdog(struct tevent_context *ev, int interval) - watchdog_ctx.input_interval = interval; - watchdog_ctx.timestamp = time(NULL); - -+ ret = pipe(watchdog_ctx.pipefd); -+ if (ret == -1) { -+ ret = errno; -+ DEBUG(SSSDBG_FATAL_FAILURE, -+ "pipe failed [%d] [%s].\n", ret, strerror(ret)); -+ return ret; -+ } -+ -+ sss_fd_nonblocking(watchdog_ctx.pipefd[0]); -+ sss_fd_nonblocking(watchdog_ctx.pipefd[1]); -+ -+ tfd = tevent_add_fd(ev, (TALLOC_CTX *)ev, watchdog_ctx.pipefd[0], -+ TEVENT_FD_READ, watchdog_fd_read_handler, NULL); -+ watchdog_ctx.tfd = tfd; -+ - /* Start the timer */ - /* we give 1 second head start to the watchdog event */ - its.it_value.tv_sec = interval + 1; -@@ -178,6 +245,13 @@ void teardown_watchdog(void) - ret, strerror(ret)); - } - -+ /* Free the tevent_fd */ -+ talloc_zfree(watchdog_ctx.tfd); -+ -+ /* Close the pipefds */ -+ PIPE_FD_CLOSE(watchdog_ctx.pipefd[0]); -+ PIPE_FD_CLOSE(watchdog_ctx.pipefd[1]); -+ - /* and kill the watchdog event */ - talloc_free(watchdog_ctx.te); - } --- -2.9.3 - diff --git a/SOURCES/0160-sssctl-show-user-name-used-for-authentication-in-use.patch b/SOURCES/0160-sssctl-show-user-name-used-for-authentication-in-use.patch new file mode 100644 index 0000000..6680a3b --- /dev/null +++ b/SOURCES/0160-sssctl-show-user-name-used-for-authentication-in-use.patch @@ -0,0 +1,53 @@ +From 6edf41eba3cec8aa40dffaf639cd5c7756db310e Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 10 May 2017 17:13:48 +0200 +Subject: [PATCH 160/160] sssctl: show user name used for authentication in + user-checks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since there are cases where the user name is not entered directly but +determined by other means the user-checks should show the name of the +user used for authentication. + +Related to https://pagure.io/SSSD/sssd/issue/3395 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit b130adaa3934d0531aca0f32961ab8b4cc720820) +--- + src/tools/sssctl/sssctl_user_checks.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/src/tools/sssctl/sssctl_user_checks.c b/src/tools/sssctl/sssctl_user_checks.c +index 7c7b564bd29100382c9bbef7a3131c379e9aa97e..d5cd8a1b42e84aa96df95ed39905c864a38212b7 100644 +--- a/src/tools/sssctl/sssctl_user_checks.c ++++ b/src/tools/sssctl/sssctl_user_checks.c +@@ -200,6 +200,8 @@ errno_t sssctl_user_checks(struct sss_cmdline *cmdline, + const char *action = DEFAULT_ACTION; + const char *service = DEFAULT_SERVICE; + int ret; ++ int pret; ++ const char *pam_user = NULL; + size_t c; + char **pam_env; + +@@ -246,7 +248,14 @@ errno_t sssctl_user_checks(struct sss_cmdline *cmdline, + if ( strncmp(action, "auth", 4)== 0 ) { + fprintf(stdout, _("testing pam_authenticate\n\n")); + ret = pam_authenticate(pamh, 0); +- fprintf(stderr, _("pam_authenticate: %s\n\n"), pam_strerror(pamh, ret)); ++ pret = pam_get_item(pamh, PAM_USER, (const void **) &pam_user); ++ if (pret != PAM_SUCCESS) { ++ fprintf(stderr, _("pam_get_item failed: %s\n"), pam_strerror(pamh, ++ pret)); ++ pam_user = "- not available -"; ++ } ++ fprintf(stderr, _("pam_authenticate for user [%s]: %s\n\n"), pam_user, ++ pam_strerror(pamh, ret)); + } else if ( strncmp(action, "chau", 4)== 0 ) { + fprintf(stdout, _("testing pam_chauthtok\n\n")); + ret = pam_chauthtok(pamh, 0); +-- +2.9.4 + diff --git a/SOURCES/0161-RESP-Provide-a-reusable-request-to-fully-resolve-inc.patch b/SOURCES/0161-RESP-Provide-a-reusable-request-to-fully-resolve-inc.patch new file mode 100644 index 0000000..cc83129 --- /dev/null +++ b/SOURCES/0161-RESP-Provide-a-reusable-request-to-fully-resolve-inc.patch @@ -0,0 +1,267 @@ +From be1f9a082eb28b3346135cbe399f7f909c8a50ce Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 24 May 2017 17:34:55 +0200 +Subject: [PATCH 161/166] RESP: Provide a reusable request to fully resolve + incomplete groups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +After initgroups, the group objects might not be complete, but just +stubs that contain the SID and the GID. If the caller needs to know the +group names as well, this request allows them to iterate over the list +of the groups and resolve them one-by-one. + +Reviewed-by: Pavel Březina +--- + src/responder/common/responder.h | 14 +++ + src/responder/common/responder_utils.c | 206 +++++++++++++++++++++++++++++++++ + 2 files changed, 220 insertions(+) + +diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h +index dfe1ec455e355de263c3550306e53fea3ada85df..c09ecd4931c9e197fbdfb7835eb72f49cc6f6d3f 100644 +--- a/src/responder/common/responder.h ++++ b/src/responder/common/responder.h +@@ -414,4 +414,18 @@ int sized_domain_name(TALLOC_CTX *mem_ctx, + const char *member_name, + struct sized_string **_name); + ++/* Given a ldb_result structure that contains a result of sysdb_initgroups ++ * where some groups might be just 'stubs' that don't have a name, but only ++ * a SID and a GID, resolve those incomplete groups into full group objects ++ */ ++struct tevent_req *resp_resolve_group_names_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct resp_ctx *rctx, ++ struct sss_domain_info *dom, ++ struct ldb_result *initgr_res); ++ ++int resp_resolve_group_names_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct ldb_result **_initgr_named_res); ++ + #endif /* __SSS_RESPONDER_H__ */ +diff --git a/src/responder/common/responder_utils.c b/src/responder/common/responder_utils.c +index b02212dfd87c2b7c2ca6108d46f939447f0eaa25..7f5c0573087e9c6c885ae158d0677994fd538e2a 100644 +--- a/src/responder/common/responder_utils.c ++++ b/src/responder/common/responder_utils.c +@@ -23,6 +23,7 @@ + #include + + #include "responder/common/responder.h" ++#include "responder/common/cache_req/cache_req.h" + #include "util/util.h" + + static inline bool +@@ -193,3 +194,208 @@ char *sss_resp_create_fqname(TALLOC_CTX *mem_ctx, + talloc_free(tmp_ctx); + return name; + } ++ ++struct resp_resolve_group_names_state { ++ struct tevent_context *ev; ++ struct resp_ctx *rctx; ++ struct sss_domain_info *dom; ++ struct ldb_result *initgr_res; ++ ++ bool needs_refresh; ++ unsigned int group_iter; ++ ++ struct ldb_result *initgr_named_res; ++}; ++ ++static void resp_resolve_group_done(struct tevent_req *subreq); ++static errno_t resp_resolve_group_next(struct tevent_req *req); ++static errno_t resp_resolve_group_reread_names(struct resp_resolve_group_names_state *state); ++ ++struct tevent_req *resp_resolve_group_names_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct resp_ctx *rctx, ++ struct sss_domain_info *dom, ++ struct ldb_result *initgr_res) ++{ ++ struct resp_resolve_group_names_state *state; ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct resp_resolve_group_names_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ state->ev = ev; ++ state->rctx = rctx; ++ state->dom = dom; ++ state->initgr_res = initgr_res; ++ ++ ret = resp_resolve_group_next(req); ++ if (ret == EOK) { ++ goto immediate; ++ } else if (ret != EAGAIN) { ++ goto immediate; ++ } ++ ++ return req; ++ ++immediate: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ return req; ++} ++ ++static bool ++resp_resolve_group_needs_refresh(struct resp_resolve_group_names_state *state) ++{ ++ /* Refresh groups that have a non-zero GID, ++ * but are marked as non-POSIX ++ */ ++ bool is_posix; ++ uint64_t gid; ++ struct ldb_message *group_msg; ++ ++ group_msg = state->initgr_res->msgs[state->group_iter]; ++ ++ is_posix = ldb_msg_find_attr_as_bool(group_msg, SYSDB_POSIX, false); ++ gid = ldb_msg_find_attr_as_uint64(group_msg, SYSDB_GIDNUM, 0); ++ ++ if (is_posix == false && gid != 0) { ++ return true; ++ } ++ ++ return false; ++} ++ ++static errno_t resp_resolve_group_next(struct tevent_req *req) ++{ ++ struct cache_req_data *data; ++ uint64_t gid; ++ struct tevent_req *subreq; ++ struct resp_resolve_group_names_state *state; ++ ++ state = tevent_req_data(req, struct resp_resolve_group_names_state); ++ ++ while (state->group_iter < state->initgr_res->count ++ && !resp_resolve_group_needs_refresh(state)) { ++ state->group_iter++; ++ } ++ ++ if (state->group_iter >= state->initgr_res->count) { ++ /* All groups were refreshed */ ++ return EOK; ++ } ++ ++ /* Fire a request */ ++ gid = ldb_msg_find_attr_as_uint64(state->initgr_res->msgs[state->group_iter], ++ SYSDB_GIDNUM, 0); ++ if (gid == 0) { ++ return EINVAL; ++ } ++ ++ data = cache_req_data_id_attrs(state, CACHE_REQ_GROUP_BY_ID, gid, NULL); ++ if (data == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set cache request data!\n"); ++ return ENOMEM; ++ } ++ ++ subreq = cache_req_send(state, ++ state->ev, ++ state->rctx, ++ state->rctx->ncache, ++ 0, ++ CACHE_REQ_ANY_DOM, ++ NULL, ++ data); ++ if (subreq == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send cache request!\n"); ++ return ENOMEM; ++ } ++ ++ tevent_req_set_callback(subreq, resp_resolve_group_done, req); ++ return EAGAIN; ++} ++ ++static void resp_resolve_group_done(struct tevent_req *subreq) ++{ ++ struct resp_resolve_group_names_state *state; ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct resp_resolve_group_names_state); ++ ++ ret = cache_req_single_domain_recv(state, subreq, NULL); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to refresh group\n"); ++ /* Try to refresh the others on error */ ++ } ++ ++ state->group_iter++; ++ state->needs_refresh = true; ++ ++ ret = resp_resolve_group_next(req); ++ if (ret == EOK) { ++ ret = resp_resolve_group_reread_names(state); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ DEBUG(SSSDBG_TRACE_FUNC, "All groups are refreshed, done\n"); ++ tevent_req_done(req); ++ return; ++ } else if (ret != EAGAIN) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ /* Continue refreshing.. */ ++} ++ ++static errno_t ++resp_resolve_group_reread_names(struct resp_resolve_group_names_state *state) ++{ ++ errno_t ret; ++ const char *username; ++ ++ /* re-read reply in case any groups were renamed */ ++ /* msgs[0] is the user entry */ ++ username = sss_view_ldb_msg_find_attr_as_string(state->dom, ++ state->initgr_res->msgs[0], ++ SYSDB_NAME, ++ NULL); ++ if (username == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "A user with no name?\n"); ++ return EINVAL; ++ } ++ ++ ret = sysdb_initgroups_with_views(state, ++ state->dom, ++ username, ++ &state->initgr_named_res); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Cannot re-read the group names\n"); ++ return ret; ++ } ++ ++ return EOK; ++} ++ ++int resp_resolve_group_names_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct ldb_result **_initgr_named_res) ++{ ++ struct resp_resolve_group_names_state *state = NULL; ++ state = tevent_req_data(req, struct resp_resolve_group_names_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *_initgr_named_res = talloc_steal(mem_ctx, state->initgr_named_res); ++ return EOK; ++} +-- +2.9.4 + diff --git a/SOURCES/0161-TESTS-Extending-sysdb-sudo-store-tests.patch b/SOURCES/0161-TESTS-Extending-sysdb-sudo-store-tests.patch deleted file mode 100644 index 23939a1..0000000 --- a/SOURCES/0161-TESTS-Extending-sysdb-sudo-store-tests.patch +++ /dev/null @@ -1,225 +0,0 @@ -From e2f39220bc1cbfc87bbe41e84042ab8be9d046ec Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Petr=20=C4=8Cech?= -Date: Thu, 13 Oct 2016 09:31:52 +0200 -Subject: [PATCH 161/162] TESTS: Extending sysdb sudo store tests -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We covered diference between case sensitive and case insensitive -domains. If domain is case insensitive we add lowercase form of -sudoUser to local sysdb cache. - -Resolves: -https://fedorahosted.org/sssd/ticket/3203 - -Reviewed-by: Pavel Březina -(cherry picked from commit 23637e2fd2b1fe42bdd2335893a11ac8016f56bc) -(cherry picked from commit 143b1dcbbe865a139616a22b139e19bd772e46f0) ---- - src/tests/cmocka/test_sysdb_sudo.c | 168 ++++++++++++++++++++++++++++++++++++- - 1 file changed, 167 insertions(+), 1 deletion(-) - -diff --git a/src/tests/cmocka/test_sysdb_sudo.c b/src/tests/cmocka/test_sysdb_sudo.c -index 889de72371ac724de7c791d889a670cf25a36968..f21ff3655efbdc5b66a1fdbc24a51ec8174c3c8c 100644 ---- a/src/tests/cmocka/test_sysdb_sudo.c -+++ b/src/tests/cmocka/test_sysdb_sudo.c -@@ -44,7 +44,7 @@ struct test_user { - const char *name; - uid_t uid; - gid_t gid; --} users[] = { { "test_user1", 1001, 1001 }, -+} users[] = { { "test_USER1", 1001, 1001 }, - { "test_user2", 1002, 1002 }, - { "test_user3", 1003, 1003 } }; - -@@ -104,6 +104,29 @@ static void create_rule_attrs(struct sysdb_attrs *rule, int i) - assert_int_equal(ret, EOK); - } - -+static void create_rule_attrs_multiple_sudoUser(struct sysdb_attrs *rule) -+{ -+ errno_t ret; -+ -+ ret = sysdb_attrs_add_string_safe(rule, SYSDB_SUDO_CACHE_AT_CN, -+ rules[0].name); -+ assert_int_equal(ret, EOK); -+ -+ ret = sysdb_attrs_add_string_safe(rule, SYSDB_SUDO_CACHE_AT_HOST, -+ rules[0].host); -+ assert_int_equal(ret, EOK); -+ -+ ret = sysdb_attrs_add_string_safe(rule, SYSDB_SUDO_CACHE_AT_RUNASUSER, -+ rules[0].as_user); -+ assert_int_equal(ret, EOK); -+ -+ for (int i = 0; i < 3; i++ ) { -+ ret = sysdb_attrs_add_string_safe(rule, SYSDB_SUDO_CACHE_AT_USER, -+ users[i].name); -+ assert_int_equal(ret, EOK); -+ } -+} -+ - static int get_stored_rules_count(struct sysdb_test_ctx *test_ctx) - { - errno_t ret; -@@ -217,6 +240,143 @@ void test_store_sudo(void **state) - talloc_zfree(msgs); - } - -+void test_store_sudo_case_sensitive(void **state) -+{ -+ errno_t ret; -+ char *filter; -+ const char *attrs[] = { SYSDB_SUDO_CACHE_AT_CN, SYSDB_SUDO_CACHE_AT_HOST, -+ SYSDB_SUDO_CACHE_AT_RUNASUSER, -+ SYSDB_SUDO_CACHE_AT_USER, NULL }; -+ struct ldb_message **msgs = NULL; -+ size_t msgs_count; -+ const char *result; -+ struct ldb_message_element *element; -+ struct sysdb_attrs *rule; -+ struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state, -+ struct sysdb_test_ctx); -+ const char *lowered_name = sss_tc_utf8_str_tolower(test_ctx, users[0].name); -+ -+ rule = sysdb_new_attrs(test_ctx); -+ assert_non_null(rule); -+ create_rule_attrs_multiple_sudoUser(rule); -+ -+ test_ctx->tctx->dom->case_sensitive = true; -+ -+ ret = sysdb_sudo_store(test_ctx->tctx->dom, &rule, 1); -+ assert_int_equal(ret, EOK); -+ -+ filter = sysdb_sudo_filter_user(test_ctx, users[0].name, NULL, 0); -+ assert_non_null(filter); -+ -+ ret = sysdb_search_sudo_rules(test_ctx, test_ctx->tctx->dom, filter, -+ attrs, &msgs_count, &msgs); -+ assert_int_equal(ret, EOK); -+ -+ assert_int_equal(msgs_count, 1); -+ -+ result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_CN, NULL); -+ assert_non_null(result); -+ assert_string_equal(result, rules[0].name); -+ -+ result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_HOST, -+ NULL); -+ assert_non_null(result); -+ assert_string_equal(result, rules[0].host); -+ -+ result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_RUNASUSER, -+ NULL); -+ assert_non_null(result); -+ assert_string_equal(result, rules[0].as_user); -+ -+ ret = ldb_msg_check_string_attribute(msgs[0], SYSDB_SUDO_CACHE_AT_USER, -+ users[0].name); -+ assert_int_equal(ret, 1); -+ -+ ret = ldb_msg_check_string_attribute(msgs[0], SYSDB_SUDO_CACHE_AT_USER, -+ lowered_name); -+ assert_int_equal(ret, 0); -+ -+ ret = ldb_msg_check_string_attribute(msgs[0], SYSDB_SUDO_CACHE_AT_USER, -+ users[1].name); -+ assert_int_equal(ret, 1); -+ -+ ret = ldb_msg_check_string_attribute(msgs[0], SYSDB_SUDO_CACHE_AT_USER, -+ users[2].name); -+ assert_int_equal(ret, 1); -+ -+ element = ldb_msg_find_element(msgs[0], SYSDB_SUDO_CACHE_AT_USER); -+ assert_int_equal(element->num_values, 3); -+ -+ talloc_zfree(lowered_name); -+ talloc_zfree(rule); -+ talloc_zfree(filter); -+ talloc_zfree(msgs); -+} -+ -+void test_store_sudo_case_insensitive(void **state) -+{ -+ errno_t ret; -+ char *filter; -+ const char *attrs[] = { SYSDB_SUDO_CACHE_AT_CN, SYSDB_SUDO_CACHE_AT_HOST, -+ SYSDB_SUDO_CACHE_AT_RUNASUSER, -+ SYSDB_SUDO_CACHE_AT_USER, NULL }; -+ struct ldb_message **msgs = NULL; -+ size_t msgs_count; -+ const char *result; -+ struct ldb_message_element *element; -+ struct sysdb_attrs *rule; -+ struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state, -+ struct sysdb_test_ctx); -+ const char *lowered_name = sss_tc_utf8_str_tolower(test_ctx, users[0].name); -+ -+ rule = sysdb_new_attrs(test_ctx); -+ assert_non_null(rule); -+ create_rule_attrs_multiple_sudoUser(rule); -+ -+ test_ctx->tctx->dom->case_sensitive = false; -+ -+ ret = sysdb_sudo_store(test_ctx->tctx->dom, &rule, 1); -+ assert_int_equal(ret, EOK); -+ -+ filter = sysdb_sudo_filter_user(test_ctx, users[0].name, NULL, 0); -+ assert_non_null(filter); -+ -+ ret = sysdb_search_sudo_rules(test_ctx, test_ctx->tctx->dom, filter, -+ attrs, &msgs_count, &msgs); -+ assert_int_equal(ret, EOK); -+ -+ assert_int_equal(msgs_count, 1); -+ -+ result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_CN, NULL); -+ assert_non_null(result); -+ assert_string_equal(result, rules[0].name); -+ -+ result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_HOST, -+ NULL); -+ assert_non_null(result); -+ assert_string_equal(result, rules[0].host); -+ -+ result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_RUNASUSER, -+ NULL); -+ assert_non_null(result); -+ assert_string_equal(result, rules[0].as_user); -+ -+ for (int i = 0; i < 3; i++) { -+ ret = ldb_msg_check_string_attribute(msgs[0], SYSDB_SUDO_CACHE_AT_USER, -+ users[i].name); -+ assert_int_equal(ret, 1); -+ } -+ -+ /* test there is no duplication of lowercase forms */ -+ element = ldb_msg_find_element(msgs[0], SYSDB_SUDO_CACHE_AT_USER); -+ assert_int_equal(element->num_values, 4); -+ -+ talloc_zfree(lowered_name); -+ talloc_zfree(rule); -+ talloc_zfree(filter); -+ talloc_zfree(msgs); -+} -+ - void test_sudo_purge_by_filter(void **state) - { - errno_t ret; -@@ -648,6 +808,12 @@ int main(int argc, const char *argv[]) - cmocka_unit_test_setup_teardown(test_store_sudo, - test_sysdb_setup, - test_sysdb_teardown), -+ cmocka_unit_test_setup_teardown(test_store_sudo_case_sensitive, -+ test_sysdb_setup, -+ test_sysdb_teardown), -+ cmocka_unit_test_setup_teardown(test_store_sudo_case_insensitive, -+ test_sysdb_setup, -+ test_sysdb_teardown), - - /* sysdb_sudo_purge() */ - cmocka_unit_test_setup_teardown(test_sudo_purge_by_filter, --- -2.9.3 - diff --git a/SOURCES/0162-IFP-Only-format-the-output-name-to-the-short-version.patch b/SOURCES/0162-IFP-Only-format-the-output-name-to-the-short-version.patch new file mode 100644 index 0000000..b6c6eaa --- /dev/null +++ b/SOURCES/0162-IFP-Only-format-the-output-name-to-the-short-version.patch @@ -0,0 +1,121 @@ +From f5bee70057370c72ed111b50937e3252e36ccefb Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 9 May 2017 12:21:32 +0200 +Subject: [PATCH 162/166] IFP: Only format the output name to the short version + before output +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The ifp_user_get_attr_done() request handler was reused for both +GetUserGroups and GetUserAttrs requests. Yet, it performed output +formatting of name and nameAlias. + +This is bad, because the output formatting should really be done only +during output. Also, it broke any post-processing of the returned +message which the request might do later. + +Reviewed-by: Pavel Březina +--- + src/responder/ifp/ifpsrv_cmd.c | 64 ++++++++++++------------------------------ + 1 file changed, 18 insertions(+), 46 deletions(-) + +diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c +index e4d6c42ef35ef372472803d3d26b17d4181021a8..915f77e38e94c703f6c67e8d5fdcc59d189943be 100644 +--- a/src/responder/ifp/ifpsrv_cmd.c ++++ b/src/responder/ifp/ifpsrv_cmd.c +@@ -181,26 +181,6 @@ static void ifp_user_get_attr_process(struct tevent_req *req) + } + + static errno_t +-ifp_user_get_attr_replace_space(TALLOC_CTX *mem_ctx, +- struct ldb_message_element *el, +- const char sub) +-{ +- int i; +- +- for (i = 0; i < el->num_values; i++) { +- el->values[i].data = (uint8_t *) sss_replace_space(mem_ctx, +- (const char *) el->values[i].data, +- sub); +- if (el->values[i].data == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "sss_replace_space failed, skipping\n"); +- return ENOMEM; +- } +- } +- +- return EOK; +-} +- +-static errno_t + ifp_user_get_attr_handle_reply(struct sss_domain_info *domain, + struct ifp_req *ireq, + const char **attrs, +@@ -234,6 +214,24 @@ ifp_user_get_attr_handle_reply(struct sss_domain_info *domain, + } + + if (res->count > 0) { ++ ret = ifp_ldb_el_output_name(ireq->ifp_ctx->rctx, res->msgs[0], ++ SYSDB_NAME, domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot convert SYSDB_NAME to output format [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return sbus_request_finish(ireq->dbus_req, NULL); ++ } ++ ++ ret = ifp_ldb_el_output_name(ireq->ifp_ctx->rctx, res->msgs[0], ++ SYSDB_NAME_ALIAS, domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot convert SYSDB_NAME_ALIAS to output format [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return sbus_request_finish(ireq->dbus_req, NULL); ++ } ++ + for (ai = 0; attrs[ai]; ai++) { + el = sss_view_ldb_msg_find_element(domain, res->msgs[0], attrs[ai]); + if (el == NULL || el->num_values == 0) { +@@ -243,18 +241,6 @@ ifp_user_get_attr_handle_reply(struct sss_domain_info *domain, + continue; + } + +- /* Normalize white space in user names */ +- if (ireq->ifp_ctx->rctx->override_space != '\0' && +- strcmp(attrs[ai], SYSDB_NAME) == 0) { +- ret = ifp_user_get_attr_replace_space(ireq, el, +- ireq->ifp_ctx->rctx->override_space); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, "Cannot normalize %s\n", +- attrs[ai]); +- continue; +- } +- } +- + ret = ifp_add_ldb_el_to_dict(&iter_dict, el); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, +@@ -575,20 +561,6 @@ static void ifp_user_get_attr_done(struct tevent_req *subreq) + } + } + +- ret = ifp_ldb_el_output_name(state->rctx, state->res->msgs[0], +- SYSDB_NAME, state->dom); +- if (ret != EOK) { +- tevent_req_error(req, ret); +- return; +- } +- +- ret = ifp_ldb_el_output_name(state->rctx, state->res->msgs[0], +- SYSDB_NAME_ALIAS, state->dom); +- if (ret != EOK) { +- tevent_req_error(req, ret); +- return; +- } +- + tevent_req_done(req); + } + +-- +2.9.4 + diff --git a/SOURCES/0162-SUDO-Only-store-lowercased-attribute-value-once.patch b/SOURCES/0162-SUDO-Only-store-lowercased-attribute-value-once.patch deleted file mode 100644 index 7435a9f..0000000 --- a/SOURCES/0162-SUDO-Only-store-lowercased-attribute-value-once.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 68cf1c69d2a19caca93d838745389f005ad66f5c Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Sun, 5 Feb 2017 20:25:23 +0100 -Subject: [PATCH 162/162] SUDO: Only store lowercased attribute value once -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The current code doesn't handle the situation where lowercasing the -sudoUser attribute would yield the same value again. - -For example: - sudoUser: TUSER - sudoUser tuser -would break. - -This patch switches to using the utility function -sysdb_attrs_add_lower_case_string() which already checks for duplicates. - -Resolves: -https://fedorahosted.org/sssd/ticket/3301 - -Reviewed-by: Fabiano Fidêncio -Reviewed-by: Pavel Březina -(cherry picked from commit a5ecc93abb01cece628fdef04ebad43bba267419) -(cherry picked from commit d5ddca8b44d00b92d4a70ea90d48247635a4e1ca) ---- - src/db/sysdb_sudo.c | 17 +++-------------- - src/tests/cmocka/test_sysdb_sudo.c | 5 +++++ - 2 files changed, 8 insertions(+), 14 deletions(-) - -diff --git a/src/db/sysdb_sudo.c b/src/db/sysdb_sudo.c -index f5160f19012028f92723b9012fad85d803aa5137..97a1bee99c0255579f42cc7263d3d755429cd417 100644 ---- a/src/db/sysdb_sudo.c -+++ b/src/db/sysdb_sudo.c -@@ -857,7 +857,6 @@ static errno_t sysdb_sudo_add_lowered_users(struct sss_domain_info *domain, - { - TALLOC_CTX *tmp_ctx; - const char **users = NULL; -- const char *lowered = NULL; - errno_t ret; - - if (domain->case_sensitive == true || rule == NULL) { -@@ -884,19 +883,9 @@ static errno_t sysdb_sudo_add_lowered_users(struct sss_domain_info *domain, - } - - for (int i = 0; users[i] != NULL; i++) { -- lowered = sss_tc_utf8_str_tolower(tmp_ctx, users[i]); -- if (lowered == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n"); -- ret = ENOMEM; -- goto done; -- } -- -- if (strcmp(users[i], lowered) == 0) { -- /* It protects us from adding duplicate. */ -- continue; -- } -- -- ret = sysdb_attrs_add_string(rule, SYSDB_SUDO_CACHE_AT_USER, lowered); -+ ret = sysdb_attrs_add_lower_case_string(rule, true, -+ SYSDB_SUDO_CACHE_AT_USER, -+ users[i]); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "Unable to add %s attribute [%d]: %s\n", -diff --git a/src/tests/cmocka/test_sysdb_sudo.c b/src/tests/cmocka/test_sysdb_sudo.c -index f21ff3655efbdc5b66a1fdbc24a51ec8174c3c8c..34afe120d97e99e3213a85bf7489a5e0f6309e4b 100644 ---- a/src/tests/cmocka/test_sysdb_sudo.c -+++ b/src/tests/cmocka/test_sysdb_sudo.c -@@ -335,6 +335,11 @@ void test_store_sudo_case_insensitive(void **state) - - test_ctx->tctx->dom->case_sensitive = false; - -+ ret = sysdb_attrs_add_lower_case_string(rule, false, -+ SYSDB_SUDO_CACHE_AT_USER, -+ users[0].name); -+ assert_int_equal(ret, EOK); -+ - ret = sysdb_sudo_store(test_ctx->tctx->dom, &rule, 1); - assert_int_equal(ret, EOK); - --- -2.9.3 - diff --git a/SOURCES/0163-IFP-Resolve-group-names-from-GIDs-if-required.patch b/SOURCES/0163-IFP-Resolve-group-names-from-GIDs-if-required.patch new file mode 100644 index 0000000..b33cbba --- /dev/null +++ b/SOURCES/0163-IFP-Resolve-group-names-from-GIDs-if-required.patch @@ -0,0 +1,204 @@ +From 3891e94330a5df632a8db1a6f1d642cf2fa96579 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 24 May 2017 21:32:28 +0200 +Subject: [PATCH 163/166] IFP: Resolve group names from GIDs if required +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The AD provider only converts SIDs to GIDs during initgroups +to improve performance. But this is not sufficient for the +org.freedesktop.sssd.infopipe.GetUserGroups method, which needs to return +names. + +We need to resolve the GIDs to names ourselves in that method. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3392 + +Reviewed-by: Pavel Březina +--- + src/responder/ifp/ifpsrv_cmd.c | 115 +++++++++++++++++++++++++++++++---------- + 1 file changed, 89 insertions(+), 26 deletions(-) + +diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c +index 915f77e38e94c703f6c67e8d5fdcc59d189943be..70728e1bb656fd032b7f1c240683e8aa3b91a726 100644 +--- a/src/responder/ifp/ifpsrv_cmd.c ++++ b/src/responder/ifp/ifpsrv_cmd.c +@@ -259,7 +259,18 @@ ifp_user_get_attr_handle_reply(struct sss_domain_info *domain, + return sbus_request_finish(ireq->dbus_req, reply); + } + ++struct ifp_user_get_groups_state { ++ struct resp_ctx *rctx; ++ ++ struct ifp_attr_req *group_attr_req; ++ ++ struct ldb_result *res; ++ struct ldb_result *res_names; ++ struct sss_domain_info *dom; ++}; ++ + static void ifp_user_get_groups_process(struct tevent_req *req); ++static void ifp_user_get_groups_names_resolved(struct tevent_req *req); + static errno_t ifp_user_get_groups_reply(struct sss_domain_info *domain, + struct ifp_req *ireq, + struct ldb_result *res); +@@ -269,7 +280,7 @@ int ifp_user_get_groups(struct sbus_request *dbus_req, + { + struct ifp_req *ireq; + struct ifp_ctx *ifp_ctx; +- struct ifp_attr_req *group_req; ++ struct ifp_user_get_groups_state *state; + struct tevent_req *req; + errno_t ret; + +@@ -284,68 +295,120 @@ int ifp_user_get_groups(struct sbus_request *dbus_req, + return ifp_req_create_handle_failure(dbus_req, ret); + } + +- group_req = talloc_zero(ireq, struct ifp_attr_req); +- if (group_req == NULL) { ++ state = talloc_zero(ireq, struct ifp_user_get_groups_state); ++ if (state == NULL) { + return sbus_request_finish(dbus_req, NULL); + } +- group_req->ireq = ireq; +- group_req->name = arg_user; ++ state->rctx = ifp_ctx->rctx; + +- group_req->attrs = talloc_zero_array(group_req, const char *, 2); +- if (group_req->attrs == NULL) { ++ state->group_attr_req = talloc_zero(state, struct ifp_attr_req); ++ if (state->group_attr_req == NULL) { + return sbus_request_finish(dbus_req, NULL); + } ++ state->group_attr_req->ireq = ireq; ++ state->group_attr_req->name = arg_user; + +- group_req->attrs[0] = talloc_strdup(group_req->attrs, SYSDB_MEMBEROF); +- if (group_req->attrs[0] == NULL) { ++ state->group_attr_req->attrs = talloc_zero_array(state->group_attr_req, ++ const char *, 2); ++ if (state->group_attr_req->attrs == NULL) { ++ return sbus_request_finish(dbus_req, NULL); ++ } ++ ++ state->group_attr_req->attrs[0] = talloc_strdup(state->group_attr_req->attrs, ++ SYSDB_MEMBEROF); ++ if (state->group_attr_req->attrs[0] == NULL) { + return sbus_request_finish(dbus_req, NULL); + } + + DEBUG(SSSDBG_FUNC_DATA, + "Looking up groups of user [%s] on behalf of %"PRIi64"\n", +- group_req->name, group_req->ireq->dbus_req->client); ++ state->group_attr_req->name, ++ state->group_attr_req->ireq->dbus_req->client); + + req = ifp_user_get_attr_send(ireq, ifp_ctx->rctx, + ifp_ctx->rctx->ncache, SSS_DP_INITGROUPS, +- group_req->name, group_req->attrs); ++ state->group_attr_req->name, ++ state->group_attr_req->attrs); + if (req == NULL) { + return sbus_request_finish(dbus_req, NULL); + } +- tevent_req_set_callback(req, ifp_user_get_groups_process, group_req); ++ tevent_req_set_callback(req, ++ ifp_user_get_groups_process, ++ state); + return EOK; + } + + static void ifp_user_get_groups_process(struct tevent_req *req) + { +- struct ifp_attr_req *group_req; ++ struct ifp_user_get_groups_state *state; ++ struct ifp_attr_req *group_attr_req; + errno_t ret; +- struct ldb_result *res; +- struct sss_domain_info *dom; + +- group_req = tevent_req_callback_data(req, struct ifp_attr_req); ++ state = tevent_req_callback_data(req, struct ifp_user_get_groups_state); ++ group_attr_req = state->group_attr_req; + +- ret = ifp_user_get_attr_recv(group_req, req, &res, &dom); ++ ret = ifp_user_get_attr_recv(group_attr_req, req, &state->res, &state->dom); + talloc_zfree(req); + if (ret == ENOENT) { +- sbus_request_fail_and_finish(group_req->ireq->dbus_req, +- sbus_error_new(group_req->ireq->dbus_req, ++ sbus_request_fail_and_finish(group_attr_req->ireq->dbus_req, ++ sbus_error_new(group_attr_req->ireq->dbus_req, + DBUS_ERROR_FAILED, + "No such user\n")); + return; + } else if (ret != EOK) { +- sbus_request_fail_and_finish(group_req->ireq->dbus_req, +- sbus_error_new(group_req->ireq->dbus_req, ++ sbus_request_fail_and_finish(group_attr_req->ireq->dbus_req, ++ sbus_error_new(group_attr_req->ireq->dbus_req, + DBUS_ERROR_FAILED, + "Failed to read attribute\n")); + return; + } + +- ret = ifp_user_get_groups_reply(dom, group_req->ireq, res); ++ req = resp_resolve_group_names_send(state, ++ state->rctx->ev, ++ state->rctx, ++ state->dom, ++ state->res); ++ if (req == NULL) { ++ sbus_request_finish(group_attr_req->ireq->dbus_req, NULL); ++ return; ++ } ++ tevent_req_set_callback(req, ++ ifp_user_get_groups_names_resolved, ++ state); ++} ++ ++static void ifp_user_get_groups_names_resolved(struct tevent_req *req) ++{ ++ struct ifp_user_get_groups_state *state; ++ struct ifp_attr_req *group_attr_req; ++ errno_t ret; ++ ++ state = tevent_req_callback_data(req, struct ifp_user_get_groups_state); ++ group_attr_req = state->group_attr_req; ++ ++ ret = resp_resolve_group_names_recv(state, req, &state->res_names); ++ talloc_zfree(req); + if (ret != EOK) { +- sbus_request_fail_and_finish(group_req->ireq->dbus_req, +- sbus_error_new(group_req->ireq->dbus_req, +- DBUS_ERROR_FAILED, +- "Failed to build a reply\n")); ++ sbus_request_fail_and_finish(group_attr_req->ireq->dbus_req, ++ sbus_error_new(group_attr_req->ireq->dbus_req, ++ DBUS_ERROR_FAILED, ++ "Failed to resolve groupnames\n")); ++ return; ++ } ++ ++ if (state->res_names == NULL) { ++ state->res_names = state->res; ++ } ++ ++ ret = ifp_user_get_groups_reply(state->dom, ++ group_attr_req->ireq, ++ state->res_names); ++ if (ret != EOK) { ++ sbus_request_fail_and_finish(group_attr_req->ireq->dbus_req, ++ sbus_error_new( ++ group_attr_req->ireq->dbus_req, ++ DBUS_ERROR_FAILED, ++ "Failed to build a reply\n")); + return; + } + } +-- +2.9.4 + diff --git a/SOURCES/0163-UTIL-Store-UPN-suffixes-when-creating-a-new-subdomai.patch b/SOURCES/0163-UTIL-Store-UPN-suffixes-when-creating-a-new-subdomai.patch deleted file mode 100644 index 9418081..0000000 --- a/SOURCES/0163-UTIL-Store-UPN-suffixes-when-creating-a-new-subdomai.patch +++ /dev/null @@ -1,138 +0,0 @@ -From c860682bca53bbafe34b6c22ba151faf18ad2ace Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Thu, 2 Mar 2017 13:52:54 +0100 -Subject: [PATCH 163/163] UTIL: Store UPN suffixes when creating a new - subdomain - -We used to store UPN suffixes pointer into the domain structure only if -the domain changed, not when a new domain was created. As an effect, the -enterprise principals flag was not enabled unless a domain changed, -preventing logins with enterprise principals. - -Reviewed-by: Sumit Bose -(cherry picked from commit 8718ff9ccd29f6431bfa8630bfa3576b2692c9ee) ---- - src/db/sysdb_private.h | 1 + - src/db/sysdb_subdomains.c | 11 ++++++++++- - src/tests/cmocka/test_fqnames.c | 2 +- - src/tests/cmocka/test_nss_srv.c | 2 +- - src/tests/sysdb-tests.c | 8 ++++---- - 5 files changed, 17 insertions(+), 7 deletions(-) - -diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h -index b6bf3706e6b9e49d8dd4984f3334b317d17ed9bf..bfd24799950ab3b31d57df11b8f91c0b2572f13a 100644 ---- a/src/db/sysdb_private.h -+++ b/src/db/sysdb_private.h -@@ -190,6 +190,7 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, - bool mpg, - bool enumerate, - const char *forest, -+ const char **upn_suffixes, - uint32_t trust_direction); - - /* Helper functions to deal with the timestamp cache should not be used -diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c -index 780140484f6f023bc6e8c12266e3b81ff016ec10..4f326405f955abd462f892e6013a8c24764afd55 100644 ---- a/src/db/sysdb_subdomains.c -+++ b/src/db/sysdb_subdomains.c -@@ -32,6 +32,7 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, - bool mpg, - bool enumerate, - const char *forest, -+ const char **upn_suffixes, - uint32_t trust_direction) - { - struct sss_domain_info *dom; -@@ -108,6 +109,14 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, - } - } - -+ if (upn_suffixes != NULL) { -+ dom->upn_suffixes = dup_string_list(dom, upn_suffixes); -+ if (dom->upn_suffixes == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "Failed to copy UPN upn_suffixes.\n"); -+ goto fail; -+ } -+ } -+ - dom->enumerate = enumerate; - dom->fqnames = true; - dom->mpg = mpg; -@@ -442,7 +451,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain) - if (dom == NULL) { - dom = new_subdomain(domain, domain, name, realm, - flat, id, mpg, enumerate, forest, -- trust_direction); -+ upn_suffixes, trust_direction); - if (dom == NULL) { - ret = ENOMEM; - goto done; -diff --git a/src/tests/cmocka/test_fqnames.c b/src/tests/cmocka/test_fqnames.c -index f4cdd80ef94584fe4eb1f0578bf388da3ead824c..19788248a39774bb4509363145ac4ce0815b7d28 100644 ---- a/src/tests/cmocka/test_fqnames.c -+++ b/src/tests/cmocka/test_fqnames.c -@@ -309,7 +309,7 @@ static int parse_name_test_setup(void **state) - * discovered - */ - test_ctx->subdom = new_subdomain(dom, dom, SUBDOMNAME, NULL, SUBFLATNAME, -- NULL, false, false, NULL, 0); -+ NULL, false, false, NULL, NULL, 0); - assert_non_null(test_ctx->subdom); - - check_leaks_push(test_ctx); -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index 41425e76f3b76fafa917f33fcfef0946f2f71c7d..5eee82d78f4e4ab4dcdc0dcdfb24c2e7d017acf5 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -3084,7 +3084,7 @@ static int nss_subdom_test_setup(void **state) - - subdomain = new_subdomain(nss_test_ctx, nss_test_ctx->tctx->dom, - testdom[0], testdom[1], testdom[2], testdom[3], -- false, false, NULL, 0); -+ false, false, NULL, NULL, 0); - assert_non_null(subdomain); - - ret = sysdb_subdomain_store(nss_test_ctx->tctx->sysdb, -diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c -index d1450015cb0f0b073045e7b6031423e3f5494d78..6fd1988668124dc2dc922b41d3f7387c6d00c486 100644 ---- a/src/tests/sysdb-tests.c -+++ b/src/tests/sysdb-tests.c -@@ -1395,7 +1395,7 @@ START_TEST (test_sysdb_get_user_attr_subdomain) - /* Create subdomain */ - subdomain = new_subdomain(test_ctx, test_ctx->domain, - "test.sub", "TEST.SUB", "test", "S-3", -- false, false, NULL, 0); -+ false, false, NULL, NULL, 0); - fail_if(subdomain == NULL, "Failed to create new subdomain."); - - ret = sss_names_init_from_args(test_ctx, -@@ -5468,7 +5468,7 @@ START_TEST(test_sysdb_subdomain_store_user) - - subdomain = new_subdomain(test_ctx, test_ctx->domain, - testdom[0], testdom[1], testdom[2], testdom[3], -- false, false, NULL, 0); -+ false, false, NULL, NULL, 0); - fail_unless(subdomain != NULL, "Failed to create new subdomin."); - ret = sysdb_subdomain_store(test_ctx->sysdb, - testdom[0], testdom[1], testdom[2], testdom[3], -@@ -5547,7 +5547,7 @@ START_TEST(test_sysdb_subdomain_user_ops) - - subdomain = new_subdomain(test_ctx, test_ctx->domain, - testdom[0], testdom[1], testdom[2], testdom[3], -- false, false, NULL, 0); -+ false, false, NULL, NULL, 0); - fail_unless(subdomain != NULL, "Failed to create new subdomin."); - ret = sysdb_subdomain_store(test_ctx->sysdb, - testdom[0], testdom[1], testdom[2], testdom[3], -@@ -5620,7 +5620,7 @@ START_TEST(test_sysdb_subdomain_group_ops) - - subdomain = new_subdomain(test_ctx, test_ctx->domain, - testdom[0], testdom[1], testdom[2], testdom[3], -- false, false, NULL, 0); -+ false, false, NULL, NULL, 0); - fail_unless(subdomain != NULL, "Failed to create new subdomin."); - ret = sysdb_subdomain_store(test_ctx->sysdb, - testdom[0], testdom[1], testdom[2], testdom[3], --- -2.9.3 - diff --git a/SOURCES/0164-Move-sized_output_name-and-sized_domain_name-into-re.patch b/SOURCES/0164-Move-sized_output_name-and-sized_domain_name-into-re.patch deleted file mode 100644 index dd5e219..0000000 --- a/SOURCES/0164-Move-sized_output_name-and-sized_domain_name-into-re.patch +++ /dev/null @@ -1,272 +0,0 @@ -From ed3bdd8998c5e0e18f9b8cfefa9acd00b8531585 Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 19 Apr 2017 17:44:40 +0200 -Subject: [PATCH 164/165] Move sized_output_name() and sized_domain_name() into - responder common code -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -These functions are used to format a name into a format that the user -configured for output, including case sensitiveness, replacing -whitespace and qualified format. They were used only in the NSS -responder, which typically returns strings to the NSS client library and -then the user. - -But it makes sense to just reuse the same code in the IFP responder as -well, since it does essentially the same job. - -The patch also renames sized_member_name to sized_domain_name. -Previously, the function was only used to format a group member, the IFP -responder would use the same function to format a group the user is a -member of. - -Related to: - https://pagure.io/SSSD/sssd/issue/3268 - -Reviewed-by: Pavel Březina -(cherry picked from commit 7c074ba2f923985ab0d4f9d6a5e01ff3f2f0a7a8) ---- - src/responder/common/responder.h | 21 ++++++++ - src/responder/common/responder_common.c | 90 +++++++++++++++++++++++++++++++++ - src/responder/nss/nsssrv_cmd.c | 89 +------------------------------- - 3 files changed, 112 insertions(+), 88 deletions(-) - -diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h -index 9e3b2fdbda4e30b859df597374fc7d490b1720e5..fd6a67ba72f28f52d6cc1bbad16e1a7245462c93 100644 ---- a/src/responder/common/responder.h -+++ b/src/responder/common/responder.h -@@ -358,4 +358,25 @@ char *sss_resp_create_fqname(TALLOC_CTX *mem_ctx, - bool name_is_upn, - const char *orig_name); - -+/** -+ * Helper functions to format output names -+ */ -+ -+/* Format orig_name into a sized_string in output format as prescribed -+ * by the name_dom domain -+ */ -+int sized_output_name(TALLOC_CTX *mem_ctx, -+ struct resp_ctx *rctx, -+ const char *orig_name, -+ struct sss_domain_info *name_dom, -+ struct sized_string **_name); -+ -+/* Format orig_name into a sized_string in output format as prescribed -+ * by the domain read from the fully qualified name. -+ */ -+int sized_domain_name(TALLOC_CTX *mem_ctx, -+ struct resp_ctx *rctx, -+ const char *member_name, -+ struct sized_string **_name); -+ - #endif /* __SSS_RESPONDER_H__ */ -diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c -index c604c64a652221521ec7114b8588186f087eb11a..1db8a2283f3e96bccebe9a8443d5d04b9d5f4a54 100644 ---- a/src/responder/common/responder_common.c -+++ b/src/responder/common/responder_common.c -@@ -1248,3 +1248,93 @@ void responder_set_fd_limit(rlim_t fd_limit) - "Proceeding with system values\n"); - } - } -+ -+/** -+ * Helper functions to format output names -+ */ -+int sized_output_name(TALLOC_CTX *mem_ctx, -+ struct resp_ctx *rctx, -+ const char *orig_name, -+ struct sss_domain_info *name_dom, -+ struct sized_string **_name) -+{ -+ TALLOC_CTX *tmp_ctx = NULL; -+ errno_t ret; -+ char *username; -+ struct sized_string *name; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ username = sss_output_name(tmp_ctx, orig_name, name_dom->case_preserve, -+ rctx->override_space); -+ if (username == NULL) { -+ ret = EIO; -+ goto done; -+ } -+ -+ if (name_dom->fqnames) { -+ username = sss_tc_fqname(tmp_ctx, name_dom->names, name_dom, username); -+ if (username == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "sss_replace_space failed\n"); -+ ret = EIO; -+ goto done; -+ } -+ } -+ -+ name = talloc_zero(tmp_ctx, struct sized_string); -+ if (name == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ to_sized_string(name, username); -+ name->str = talloc_steal(name, username); -+ *_name = talloc_steal(mem_ctx, name); -+ ret = EOK; -+done: -+ talloc_zfree(tmp_ctx); -+ return ret; -+} -+ -+int sized_domain_name(TALLOC_CTX *mem_ctx, -+ struct resp_ctx *rctx, -+ const char *member_name, -+ struct sized_string **_name) -+{ -+ TALLOC_CTX *tmp_ctx = NULL; -+ errno_t ret; -+ char *domname; -+ struct sss_domain_info *member_dom; -+ -+ tmp_ctx = talloc_new(NULL); -+ if (tmp_ctx == NULL) { -+ return ENOMEM; -+ } -+ -+ ret = sss_parse_internal_fqname(tmp_ctx, member_name, NULL, &domname); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "sss_parse_internal_fqname failed\n"); -+ goto done; -+ } -+ -+ if (domname == NULL) { -+ ret = ERR_WRONG_NAME_FORMAT; -+ goto done; -+ } -+ -+ member_dom = find_domain_by_name(get_domains_head(rctx->domains), -+ domname, true); -+ if (member_dom == NULL) { -+ ret = ERR_DOMAIN_NOT_FOUND; -+ goto done; -+ } -+ -+ ret = sized_output_name(mem_ctx, rctx, member_name, -+ member_dom, _name); -+done: -+ talloc_free(tmp_ctx); -+ return ret; -+} -diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c -index b64cea2a53ec6032904237b0afc1377022c2c804..0a9dd301266d4db1be1977cc8c337abde7cd79f5 100644 ---- a/src/responder/nss/nsssrv_cmd.c -+++ b/src/responder/nss/nsssrv_cmd.c -@@ -253,93 +253,6 @@ static const char *get_shell_override(TALLOC_CTX *mem_ctx, - return talloc_strdup(mem_ctx, NOLOGIN_SHELL); - } - --static int sized_output_name(TALLOC_CTX *mem_ctx, -- struct resp_ctx *rctx, -- const char *orig_name, -- struct sss_domain_info *name_dom, -- struct sized_string **_name) --{ -- TALLOC_CTX *tmp_ctx = NULL; -- errno_t ret; -- char *username; -- struct sized_string *name; -- -- tmp_ctx = talloc_new(NULL); -- if (tmp_ctx == NULL) { -- return ENOMEM; -- } -- -- username = sss_output_name(tmp_ctx, orig_name, name_dom->case_preserve, -- rctx->override_space); -- if (username == NULL) { -- ret = EIO; -- goto done; -- } -- -- if (name_dom->fqnames) { -- username = sss_tc_fqname(tmp_ctx, name_dom->names, name_dom, username); -- if (username == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "sss_replace_space failed\n"); -- ret = EIO; -- goto done; -- } -- } -- -- name = talloc_zero(tmp_ctx, struct sized_string); -- if (name == NULL) { -- ret = ENOMEM; -- goto done; -- } -- -- to_sized_string(name, username); -- name->str = talloc_steal(name, username); -- *_name = talloc_steal(mem_ctx, name); -- ret = EOK; --done: -- talloc_zfree(tmp_ctx); -- return ret; --} -- --static int sized_member_name(TALLOC_CTX *mem_ctx, -- struct resp_ctx *rctx, -- const char *member_name, -- struct sized_string **_name) --{ -- TALLOC_CTX *tmp_ctx = NULL; -- errno_t ret; -- char *domname; -- struct sss_domain_info *member_dom; -- -- tmp_ctx = talloc_new(NULL); -- if (tmp_ctx == NULL) { -- return ENOMEM; -- } -- -- ret = sss_parse_internal_fqname(tmp_ctx, member_name, NULL, &domname); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "sss_parse_internal_fqname failed\n"); -- goto done; -- } -- -- if (domname == NULL) { -- ret = ERR_WRONG_NAME_FORMAT; -- goto done; -- } -- -- member_dom = find_domain_by_name(get_domains_head(rctx->domains), -- domname, true); -- if (member_dom == NULL) { -- ret = ERR_DOMAIN_NOT_FOUND; -- goto done; -- } -- -- ret = sized_output_name(mem_ctx, rctx, member_name, -- member_dom, _name); --done: -- talloc_free(tmp_ctx); -- return ret; --} -- - static int fill_pwent(struct sss_packet *packet, - struct sss_domain_info *dom, - struct nss_ctx *nctx, -@@ -2727,7 +2640,7 @@ static int fill_members(struct sss_packet *packet, - } - } - -- ret = sized_member_name(tmp_ctx, rctx, fqname, &name); -+ ret = sized_domain_name(tmp_ctx, rctx, fqname, &name); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sized_member_name failed: %d\n", ret); - goto done; --- -2.9.3 - diff --git a/SOURCES/0164-ldap-handle-certmap-errors-gracefully.patch b/SOURCES/0164-ldap-handle-certmap-errors-gracefully.patch new file mode 100644 index 0000000..caebbc1 --- /dev/null +++ b/SOURCES/0164-ldap-handle-certmap-errors-gracefully.patch @@ -0,0 +1,56 @@ +From 85b74b966ec1d417ce76b05cbf3351b20c0981b2 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 17 May 2017 15:43:25 +0200 +Subject: [PATCH 164/166] ldap: handle certmap errors gracefully + +Currently the LDAP user lookup request errors out if e.g. there is no +matching rule for a certificate. This might cause the related domain to +go offline. + +With this patch the request returns that no user was found for the given +certificate but overall result is that the request finishes +successfully. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3405 + +Reviewed-by: Jakub Hrozek +--- + src/providers/ldap/ldap_id.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index 7400dc1f57e30cc6ae5f939ffa628a1e9dd47e06..557712e8dc2b2bde664b4054fa2f8eb39df84d73 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -258,6 +258,27 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "sss_cert_derb64_to_ldap_filter failed.\n"); ++ ++ /* Typically sss_cert_derb64_to_ldap_filter() will fail if there ++ * is no mapping rule matching the current certificate. But this ++ * just means that no matching user can be found so we can finish ++ * the request with this result. Even if ++ * sss_cert_derb64_to_ldap_filter() would fail for other reason ++ * there is no need to return an error which might cause the ++ * domain go offline. */ ++ ++ if (noexist_delete) { ++ ret = sysdb_remove_cert(state->domain, filter_value); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Ignoring error while removing user certificate " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ } ++ } ++ ++ ret = EOK; ++ state->sdap_ret = ENOENT; ++ state->dp_error = DP_ERR_OK; + goto done; + } + +-- +2.9.4 + diff --git a/SOURCES/0165-IFP-Use-sized_domain_name-to-format-the-groups-the-u.patch b/SOURCES/0165-IFP-Use-sized_domain_name-to-format-the-groups-the-u.patch deleted file mode 100644 index 6a83760..0000000 --- a/SOURCES/0165-IFP-Use-sized_domain_name-to-format-the-groups-the-u.patch +++ /dev/null @@ -1,95 +0,0 @@ -From e32d3a1074a64a1976047fb9fcd0defac439f97c Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Wed, 19 Apr 2017 17:46:03 +0200 -Subject: [PATCH 165/165] IFP: Use sized_domain_name to format the groups the - user is a member of -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Resolves: - https://pagure.io/SSSD/sssd/issue/3268 - -Uses the common function sized_domain_name() to format a group the user -is a member of to the appropriate format. - -To see the code is working correctly, run: - dbus-send --system --print-reply --dest=org.freedesktop.sssd.infopipe - /org/freedesktop/sssd/infopipe - org.freedesktop.sssd.infopipe.GetUserGroups - string:trusted_user - -Where trusted_user is a user from a trusted domain that is a member of groups -from the joined domain and a trusted domain as well. The groups from the -joined domain should not be qualified, the groups from the trusted -domain should be qualified. - -Reviewed-by: Pavel Březina -(cherry picked from commit c9a73bb6ffa010ef206896a0d1c2801bc056fa45) ---- - src/responder/ifp/ifpsrv_cmd.c | 29 +++++++++++++++-------------- - 1 file changed, 15 insertions(+), 14 deletions(-) - -diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c -index 97fad47e90c2155fc7243e68a7110ba9fd28aa39..f14a41da096edd2ace40c6faf8fb6f6dc3b503fe 100644 ---- a/src/responder/ifp/ifpsrv_cmd.c -+++ b/src/responder/ifp/ifpsrv_cmd.c -@@ -369,10 +369,11 @@ ifp_user_get_groups_reply(struct sss_domain_info *domain, - struct ifp_req *ireq, - struct ldb_result *res) - { -- int i, num; -+ int i, gri, num; - const char *name; - const char **groupnames; -- char *out_name; -+ struct sized_string *group_name; -+ errno_t ret; - - /* one less, the first one is the user entry */ - num = res->count - 1; -@@ -381,6 +382,7 @@ ifp_user_get_groups_reply(struct sss_domain_info *domain, - return sbus_request_finish(ireq->dbus_req, NULL); - } - -+ gri = 0; - for (i = 0; i < num; i++) { - name = sss_view_ldb_msg_find_attr_as_string(domain, - res->msgs[i + 1], -@@ -390,22 +392,21 @@ ifp_user_get_groups_reply(struct sss_domain_info *domain, - continue; - } - -- out_name = sss_output_name(ireq, name, domain->case_preserve, -- ireq->ifp_ctx->rctx->override_space); -- if (out_name == NULL) { -+ ret = sized_domain_name(ireq, ireq->ifp_ctx->rctx, name, &group_name); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "Unable to get sized name for %s [%d]: %s\n", -+ name, ret, sss_strerror(ret)); - continue; - } - -- if (domain->fqnames) { -- groupnames[i] = sss_tc_fqname(groupnames, domain->names, -- domain, out_name); -- if (out_name == NULL) { -- DEBUG(SSSDBG_CRIT_FAILURE, "sss_tc_fqname failed\n"); -- continue; -- } -- } else { -- groupnames[i] = talloc_steal(groupnames, out_name); -+ groupnames[gri] = talloc_strndup(groupnames, -+ group_name->str, group_name->len); -+ if (groupnames[gri] == NULL) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "talloc_strndup failed\n"); -+ continue; - } -+ gri++; - - DEBUG(SSSDBG_TRACE_FUNC, "Adding group %s\n", groupnames[i]); - } --- -2.9.3 - diff --git a/SOURCES/0165-SECRETS-Fix-warning-Wpointer-bool-conversion.patch b/SOURCES/0165-SECRETS-Fix-warning-Wpointer-bool-conversion.patch new file mode 100644 index 0000000..0a3ecf7 --- /dev/null +++ b/SOURCES/0165-SECRETS-Fix-warning-Wpointer-bool-conversion.patch @@ -0,0 +1,53 @@ +From 0e1416e65c99aca947e589bfa56d5bc832c023d6 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Sat, 27 May 2017 14:39:45 +0200 +Subject: [PATCH 165/166] SECRETS: Fix warning Wpointer-bool-conversion + +Debug messages would always say that verify_peer and verify_host +are enabled. Even though they would be explicitly disabled. + +src/responder/secrets/proxy.c:143:18: error: + address of 'cfg->verify_peer' will always evaluate to + 'true' [-Werror,-Wpointer-bool-conversion] + (&cfg->verify_peer ? "true" : "false")); + ~~~~~^~~~~~~~~~~ ~ +src/util/debug.h:108:32: note: expanded from macro 'DEBUG' + format, ##__VA_ARGS__); \ + ^~~~~~~~~~~ +src/responder/secrets/proxy.c:149:18: error: + address of 'cfg->verify_host' will always evaluate to + 'true' [-Werror,-Wpointer-bool-conversion] + (&cfg->verify_host ? "true" : "false")); + ~~~~~^~~~~~~~~~~ ~ +src/util/debug.h:108:32: note: expanded from macro 'DEBUG' + format, ##__VA_ARGS__); \ + ^~~~~~~~~~~ + +Reviewed-by: Jakub Hrozek +--- + src/responder/secrets/proxy.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c +index 9c2aa425d414728d10aa830f640632e98def3c1c..a4e97f83ef406e71a1e6509a6b719c47afdfd5b8 100644 +--- a/src/responder/secrets/proxy.c ++++ b/src/responder/secrets/proxy.c +@@ -140,13 +140,13 @@ static int proxy_sec_get_cfg(struct proxy_context *pctx, + true, &cfg->verify_peer); + if (ret) goto done; + DEBUG(SSSDBG_CONF_SETTINGS, "verify_peer: %s\n", +- (&cfg->verify_peer ? "true" : "false")); ++ cfg->verify_peer ? "true" : "false"); + + ret = confdb_get_bool(pctx->cdb, secreq->cfg_section, "verify_host", + true, &cfg->verify_host); + if (ret) goto done; + DEBUG(SSSDBG_CONF_SETTINGS, "verify_host: %s\n", +- (&cfg->verify_host ? "true" : "false")); ++ cfg->verify_host ? "true" : "false"); + + ret = proxy_get_config_string(pctx, cfg, false, secreq, + "capath", &cfg->capath); +-- +2.9.4 + diff --git a/SOURCES/0166-IPA-Fix-the-PAM-error-code-that-auth-code-expects-to.patch b/SOURCES/0166-IPA-Fix-the-PAM-error-code-that-auth-code-expects-to.patch new file mode 100644 index 0000000..f9eb273 --- /dev/null +++ b/SOURCES/0166-IPA-Fix-the-PAM-error-code-that-auth-code-expects-to.patch @@ -0,0 +1,50 @@ +From 62cebc27bd0bdb2c12531203fd79f231e96eab7b Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 2 Jun 2017 11:17:18 +0200 +Subject: [PATCH 166/166] IPA: Fix the PAM error code that auth code expects to + start migration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Recent patches which adds support for PKINIT in krb5_child changed a +return code which is used to indicate to the IPA provider that password +migration should be tried. + +With this patch krb5_child properly returns PAM_CRED_ERR as expected by +the IPA provider in this case. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3394 + +Reviewed-by: Simo Sorce +Reviewed-by: Lukáš Slebodník +--- + src/providers/krb5/krb5_child.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index cbbc892bee0365892ac66d3654c974d325166b60..3cd8bfba76a35acd2c885ee2aac4765a6c1cc03c 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -1540,6 +1540,17 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, + if (kerr != 0) { + KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); + ++ /* Special case for IPA password migration */ ++ if (kr->pd->cmd == SSS_PAM_AUTHENTICATE ++ && kerr == KRB5_PREAUTH_FAILED ++ && kr->pkinit_prompting == false ++ && kr->password_prompting == false ++ && kr->otp == false ++ && sss_authtok_get_type(kr->pd->authtok) ++ == SSS_AUTHTOK_TYPE_PASSWORD) { ++ return ERR_CREDS_INVALID; ++ } ++ + /* If during authentication either the MIT Kerberos pkinit + * pre-auth module is missing or no Smartcard is inserted and only + * pkinit is available KRB5_PREAUTH_FAILED is returned. +-- +2.9.4 + diff --git a/SOURCES/0166-LDAP-AD-Do-not-fail-in-case-rfc2307bis_nested_groups.patch b/SOURCES/0166-LDAP-AD-Do-not-fail-in-case-rfc2307bis_nested_groups.patch deleted file mode 100644 index d04aedf..0000000 --- a/SOURCES/0166-LDAP-AD-Do-not-fail-in-case-rfc2307bis_nested_groups.patch +++ /dev/null @@ -1,49 +0,0 @@ -From b9460652c3ab86b1b0cfe1e8ea868e6e0bb492ad Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= -Date: Mon, 1 May 2017 14:49:50 +0200 -Subject: [PATCH 166/166] LDAP/AD: Do not fail in case - rfc2307bis_nested_groups_recv() returns ENOENT -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Commit 25699846 introduced a regression seen when an initgroup lookup is -done and there's no nested groups involved. - -In this scenario the whole lookup fails due to an ENOENT returned by -rfc2307bis_nested_groups_recv(), which leads to the user removal from -sysdb causing some authentication issues. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3331 - -Signed-off-by: Fabiano Fidêncio -Reviewed-by: Sumit Bose -(cherry picked from commit df4b24bed15f45bf286fb0102fd397218fdd4186) -(cherry picked from commit 4540d9f6817c78eef7b6e2d79245434811b59ad9) ---- - src/providers/ldap/sdap_async_initgroups_ad.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c -index 1fee4ab43a6c13803a088ffa4695dde7f39b3d2b..904cffd820fa1f0aeb86929b41b0d7523f36d315 100644 ---- a/src/providers/ldap/sdap_async_initgroups_ad.c -+++ b/src/providers/ldap/sdap_async_initgroups_ad.c -@@ -1746,7 +1746,13 @@ static void sdap_ad_get_domain_local_groups_done(struct tevent_req *subreq) - - ret = rfc2307bis_nested_groups_recv(subreq); - talloc_zfree(subreq); -- if (ret != EOK) { -+ if (ret == ENOENT) { -+ /* In case of ENOENT we can just proceed without making -+ * sdap_get_initgr_user() fail because there's no nested -+ * groups for this user/group. */ -+ ret = EOK; -+ goto done; -+ } else if (ret != EOK) { - tevent_req_error(req, ret); - return; - } --- -2.9.3 - diff --git a/SOURCES/0167-HBAC-Do-not-rely-on-originalMemberOf-use-the-sysdb-m.patch b/SOURCES/0167-HBAC-Do-not-rely-on-originalMemberOf-use-the-sysdb-m.patch deleted file mode 100644 index 343c654..0000000 --- a/SOURCES/0167-HBAC-Do-not-rely-on-originalMemberOf-use-the-sysdb-m.patch +++ /dev/null @@ -1,175 +0,0 @@ -From bef2586e998a3fa2a85475d19e8cf257383b79db Mon Sep 17 00:00:00 2001 -From: Jakub Hrozek -Date: Sun, 9 Apr 2017 20:50:47 +0200 -Subject: [PATCH 167/167] HBAC: Do not rely on originalMemberOf, use the sysdb - memberof links instead - -The IPA HBAC code used to read the group members from the -originalMemberOf attribute value for performance reasons. However, -especially on IPA clients trusting an AD domain, the originalMemberOf -attribute value is often not synchronized correctly. - -Instead of going through the work of maintaining both member/memberOf -and originalMemberOf, let's just do an ASQ search for the group names of -the groups the user is a member of in the cache and read their -SYSBD_NAME attribute. - -To avoid clashing between similarly-named groups in IPA and in AD, we -look at the container of the group. - -Resolves: -https://pagure.io/SSSD/sssd/issue/3382 - -Reviewed-by: Sumit Bose -(cherry picked from commit c92e49144978ad3b6c9fffa8803ebdad8f6f5b18) ---- - src/providers/ipa/ipa_hbac_common.c | 97 +++++++++++++++++++++++++------------ - 1 file changed, 67 insertions(+), 30 deletions(-) - -diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c -index b99b75d322930f16412f6abd4cdf0d7e0b59c32c..ba677965a3eb68a54baf99b1875bca2acbb76c99 100644 ---- a/src/providers/ipa/ipa_hbac_common.c -+++ b/src/providers/ipa/ipa_hbac_common.c -@@ -507,15 +507,15 @@ hbac_eval_user_element(TALLOC_CTX *mem_ctx, - struct hbac_request_element **user_element) - { - errno_t ret; -- unsigned int i; - unsigned int num_groups = 0; - TALLOC_CTX *tmp_ctx; -- const char *member_dn; - struct hbac_request_element *users; -- struct ldb_message *msg; -- struct ldb_message_element *el; -- const char *attrs[] = { SYSDB_ORIG_MEMBEROF, NULL }; - char *shortname; -+ const char *fqgroupname = NULL; -+ struct sss_domain_info *ipa_domain; -+ struct ldb_dn *ipa_groups_basedn; -+ struct ldb_result *res; -+ int exp_comp; - - tmp_ctx = talloc_new(mem_ctx); - if (tmp_ctx == NULL) return ENOMEM; -@@ -533,56 +533,93 @@ hbac_eval_user_element(TALLOC_CTX *mem_ctx, - } - users->name = talloc_steal(users, shortname); - -- /* Read the originalMemberOf attribute -- * This will give us the list of both POSIX and -- * non-POSIX groups that this user belongs to. -+ ipa_domain = get_domains_head(domain); -+ if (ipa_domain == NULL) { -+ ret = EINVAL; -+ goto done; -+ } -+ -+ ipa_groups_basedn = ldb_dn_new_fmt(tmp_ctx, sysdb_ctx_get_ldb(domain->sysdb), -+ SYSDB_TMPL_GROUP_BASE, ipa_domain->name); -+ if (ipa_groups_basedn == NULL) { -+ ret = ENOMEM; -+ goto done; -+ } -+ -+ /* +1 because there will be a RDN preceding the base DN */ -+ exp_comp = ldb_dn_get_comp_num(ipa_groups_basedn) + 1; -+ -+ /* -+ * Get all the groups the user is a member of. -+ * This includes both POSIX and non-POSIX groups. - */ -- ret = sysdb_search_user_by_name(tmp_ctx, domain, username, -- attrs, &msg); -+ ret = sysdb_initgroups(tmp_ctx, domain, username, &res); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, -- "Could not determine user memberships for [%s]\n", -- users->name); -+ "sysdb_asq_search failed [%d]: %s\n", ret, sss_strerror(ret)); - goto done; - } - -- el = ldb_msg_find_element(msg, SYSDB_ORIG_MEMBEROF); -- if (el == NULL || el->num_values == 0) { -+ if (res->count == 0) { -+ /* This should not happen at this point */ -+ DEBUG(SSSDBG_MINOR_FAILURE, -+ "User [%s] not found in cache.\n", username); -+ ret = ENOENT; -+ goto done; -+ } else if (res->count == 1) { -+ /* The first item is the user entry */ - DEBUG(SSSDBG_TRACE_LIBS, "No groups for [%s]\n", users->name); - ret = create_empty_grouplist(users); - goto done; - } - DEBUG(SSSDBG_TRACE_LIBS, -- "[%d] groups for [%s]\n", el->num_values, users->name); -+ "[%u] groups for [%s]\n", res->count - 1, username); - -- users->groups = talloc_array(users, const char *, el->num_values + 1); -+ /* This also includes the sentinel, b/c we'll skip the user entry below */ -+ users->groups = talloc_array(users, const char *, res->count); - if (users->groups == NULL) { - ret = ENOMEM; - goto done; - } - -- for (i = 0; i < el->num_values; i++) { -- member_dn = (const char *)el->values[i].data; -+ /* Start counting from 1 to exclude the user entry */ -+ for (size_t i = 1; i < res->count; i++) { -+ /* Only groups from the IPA domain can be referenced from HBAC rules. To -+ * avoid evaluating groups which might even have the same name, but come -+ * from a trusted domain, we first copy the DN to a temporary one.. -+ */ -+ if (ldb_dn_get_comp_num(res->msgs[i]->dn) != exp_comp -+ || ldb_dn_compare_base(ipa_groups_basedn, -+ res->msgs[i]->dn) != 0) { -+ DEBUG(SSSDBG_FUNC_DATA, -+ "Skipping non-IPA group %s\n", -+ ldb_dn_get_linearized(res->msgs[i]->dn)); -+ continue; -+ } - -- ret = get_ipa_groupname(users->groups, domain->sysdb, member_dn, -- &users->groups[num_groups]); -- if (ret != EOK && ret != ERR_UNEXPECTED_ENTRY_TYPE) { -+ fqgroupname = ldb_msg_find_attr_as_string(res->msgs[i], SYSDB_NAME, NULL); -+ if (fqgroupname == NULL) { - DEBUG(SSSDBG_MINOR_FAILURE, -- "Skipping malformed entry [%s]\n", member_dn); -+ "Skipping malformed entry [%s]\n", -+ ldb_dn_get_linearized(res->msgs[i]->dn)); - continue; -- } else if (ret == EOK) { -- DEBUG(SSSDBG_TRACE_LIBS, "Added group [%s] for user [%s]\n", -- users->groups[num_groups], users->name); -- num_groups++; -+ } -+ -+ ret = sss_parse_internal_fqname(tmp_ctx, fqgroupname, -+ &shortname, NULL); -+ if (ret != EOK) { -+ DEBUG(SSSDBG_MINOR_FAILURE, "Malformed name %s, skipping!\n", fqgroupname); - continue; - } -- /* Skip entries that are not groups */ -- DEBUG(SSSDBG_TRACE_INTERNAL, -- "Skipping non-group memberOf [%s]\n", member_dn); -+ -+ users->groups[num_groups] = talloc_steal(users->groups, shortname); -+ DEBUG(SSSDBG_TRACE_LIBS, "Added group [%s] for user [%s]\n", -+ users->groups[num_groups], users->name); -+ num_groups++; - } - users->groups[num_groups] = NULL; - -- if (num_groups < el->num_values) { -+ if (num_groups < (res->count - 1)) { - /* Shrink the array memory */ - users->groups = talloc_realloc(users, users->groups, const char *, - num_groups+1); --- -2.9.4 - diff --git a/SOURCES/0167-pam_sss-Fix-checking-of-empty-string-cert_user.patch b/SOURCES/0167-pam_sss-Fix-checking-of-empty-string-cert_user.patch new file mode 100644 index 0000000..b8e2d31 --- /dev/null +++ b/SOURCES/0167-pam_sss-Fix-checking-of-empty-string-cert_user.patch @@ -0,0 +1,52 @@ +From 1ac8b82addfa0a4c94321d5cb72b7991755e61f8 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Fri, 2 Jun 2017 11:56:55 +0200 +Subject: [PATCH 167/169] pam_sss: Fix checking of empty string cert_user +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +src/sss_client/pam_sss.c: In function ‘eval_response’: +src/sss_client/pam_sss.c:998:64: error: comparison between pointer and zero character constant [-Werror=pointer-compare] + if (type == SSS_PAM_CERT_INFO && pi->cert_user == '\0') { + ^~ +src/sss_client/pam_sss.c:998:50: note: did you mean to dereference the pointer? + if (type == SSS_PAM_CERT_INFO && pi->cert_user == '\0') { + ^ +src/sss_client/pam_sss.c:1010:42: error: comparison between pointer and zero character constant [-Werror=pointer-compare] + && pi->cert_user != '\0') { + ^~ +src/sss_client/pam_sss.c:1010:28: note: did you mean to dereference the pointer? + && pi->cert_user != '\0') { + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit c62dc2ac02253e130991db0f6acd60ce1a2753f1) +--- + src/sss_client/pam_sss.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c +index 1c06079967e3d9076d537c3de8aba93e13f76d09..9732459e6fb7ce01c9445c423cf0a583ca36e036 100644 +--- a/src/sss_client/pam_sss.c ++++ b/src/sss_client/pam_sss.c +@@ -995,7 +995,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, + break; + } + +- if (type == SSS_PAM_CERT_INFO && pi->cert_user == '\0') { ++ if (type == SSS_PAM_CERT_INFO && *pi->cert_user == '\0') { + D(("Invalid CERT message")); + break; + } +@@ -1007,7 +1007,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, + } + + if ((pi->pam_user == NULL || *(pi->pam_user) == '\0') +- && pi->cert_user != '\0') { ++ && *pi->cert_user != '\0') { + ret = pam_set_item(pamh, PAM_USER, pi->cert_user); + if (ret != PAM_SUCCESS) { + D(("Failed to set PAM_USER during " +-- +2.9.4 + diff --git a/SOURCES/0168-CACHE_REQ-Simplify-_search_ncache_filter.patch b/SOURCES/0168-CACHE_REQ-Simplify-_search_ncache_filter.patch new file mode 100644 index 0000000..67e6f57 --- /dev/null +++ b/SOURCES/0168-CACHE_REQ-Simplify-_search_ncache_filter.patch @@ -0,0 +1,124 @@ +From 992a6410a3100cc64f9f2ea674fda9151fa5d474 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 29 May 2017 14:58:33 +0200 +Subject: [PATCH 168/169] CACHE_REQ: Simplify _search_ncache_filter() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let's make the result and input/output argument for +_search_ncache_filter() and free it inside the function whenever it's +needed instead of leaving this responsibility for the caller. + +Related: +https://pagure.io/SSSD/sssd/issue/3362 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Pavel Březina +(cherry picked from commit c8193b1602cf44740b59f5dfcdc5330508c0c365) +--- + src/responder/common/cache_req/cache_req_search.c | 27 ++++++----------------- + 1 file changed, 7 insertions(+), 20 deletions(-) + +diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c +index 70448a7639bc9f98d380b8edce9d130adfa0ceb2..d3aaa7542ddfd28716fbf9cdcedfeadb649dbaa0 100644 +--- a/src/responder/common/cache_req/cache_req_search.c ++++ b/src/responder/common/cache_req/cache_req_search.c +@@ -86,7 +86,6 @@ static void cache_req_search_ncache_add(struct cache_req *cr) + + static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx, + struct cache_req *cr, +- struct ldb_result *result, + struct ldb_result **_result) + { + TALLOC_CTX *tmp_ctx; +@@ -106,8 +105,6 @@ static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx, + "This request type does not support filtering " + "result by negative cache\n"); + +- *_result = talloc_steal(mem_ctx, result); +- + ret = EOK; + goto done; + } +@@ -115,11 +112,11 @@ static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx, + CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, + "Filtering out results by negative cache\n"); + +- msgs = talloc_zero_array(tmp_ctx, struct ldb_message *, result->count); ++ msgs = talloc_zero_array(tmp_ctx, struct ldb_message *, (*_result)->count); + msg_count = 0; + +- for (size_t i = 0; i < result->count; i++) { +- name = sss_get_name_from_msg(cr->domain, result->msgs[i]); ++ for (size_t i = 0; i < (*_result)->count; i++) { ++ name = sss_get_name_from_msg(cr->domain, (*_result)->msgs[i]); + if (name == NULL) { + CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, + "sss_get_name_from_msg() returned NULL, which should never " +@@ -141,7 +138,7 @@ static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx, + goto done; + } + +- msgs[msg_count] = talloc_steal(msgs, result->msgs[i]); ++ msgs[msg_count] = talloc_steal(msgs, (*_result)->msgs[i]); + msg_count++; + } + +@@ -157,6 +154,7 @@ static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx, + goto done; + } + ++ talloc_zfree(*_result); + *_result = talloc_steal(mem_ctx, filtered_result); + ret = EOK; + +@@ -419,10 +417,8 @@ static void cache_req_search_oob_done(struct tevent_req *subreq) + + static void cache_req_search_done(struct tevent_req *subreq) + { +- TALLOC_CTX *tmp_ctx; + struct cache_req_search_state *state; + struct tevent_req *req; +- struct ldb_result *result = NULL; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); +@@ -431,14 +427,8 @@ static void cache_req_search_done(struct tevent_req *subreq) + state->dp_success = state->cr->plugin->dp_recv_fn(subreq, state->cr); + talloc_zfree(subreq); + +- tmp_ctx = talloc_new(NULL); +- if (tmp_ctx == NULL) { +- ret = ENOMEM; +- goto done; +- } +- + /* Get result from cache again. */ +- ret = cache_req_search_cache(tmp_ctx, state->cr, &result); ++ ret = cache_req_search_cache(state, state->cr, &state->result); + if (ret != EOK) { + if (ret == ENOENT) { + /* Only store entry in negative cache if DP request succeeded +@@ -451,8 +441,7 @@ static void cache_req_search_done(struct tevent_req *subreq) + } + + /* ret == EOK */ +- ret = cache_req_search_ncache_filter(state, state->cr, result, +- &state->result); ++ ret = cache_req_search_ncache_filter(state, state->cr, &state->result); + if (ret != EOK) { + goto done; + } +@@ -461,8 +450,6 @@ static void cache_req_search_done(struct tevent_req *subreq) + "Returning updated object [%s]\n", state->cr->debugobj); + + done: +- talloc_free(tmp_ctx); +- + if (ret != EOK) { + tevent_req_error(req, ret); + return; +-- +2.9.4 + diff --git a/SOURCES/0169-CACHE_REQ_SEARCH-Check-for-filtered-users-groups-als.patch b/SOURCES/0169-CACHE_REQ_SEARCH-Check-for-filtered-users-groups-als.patch new file mode 100644 index 0000000..6d53d21 --- /dev/null +++ b/SOURCES/0169-CACHE_REQ_SEARCH-Check-for-filtered-users-groups-als.patch @@ -0,0 +1,61 @@ +From 79f389eb400eddc133824b079f8bd49ced24643b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 17 May 2017 14:43:39 +0200 +Subject: [PATCH 169/169] CACHE_REQ_SEARCH: Check for filtered users/groups + also on cache_req_send() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +cache_req_send() may take some shortcuts in case the object is found in +the cache and it's still valid. + +This behaviour may lead to exposing filtered users and groups when +they're searched by their uid/gid. + +A solution for this issue was proposed on 4ef0b19a but, unfortunately, +didn't take into consideration that this shortcut could be taken. + +There are basically two really easy ways to test this issue: + 1) Using enumeration: + - Set "enumerate = True" in the domain section + - restart SSSD cleaning up the cache; + - getent passwd + - Wait a little bit till the entry_negative_timeout is expired + - getent passwd + + 2) Not using enumeration: + - getent passwd + - Wait a little bit till the entry_negative_timeout is expired + - getent passwd + +A test covering this code path will be added in the follow-up commit. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3362 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Pavel Březina +(cherry picked from commit 4c09cd008967c5c0ec358dc658ffc6fc1cef2697) +--- + src/responder/common/cache_req/cache_req_search.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c +index d3aaa7542ddfd28716fbf9cdcedfeadb649dbaa0..56d0345cd8f98de574961d3c9628ae7a4c24f9be 100644 +--- a/src/responder/common/cache_req/cache_req_search.c ++++ b/src/responder/common/cache_req/cache_req_search.c +@@ -334,6 +334,10 @@ cache_req_search_send(TALLOC_CTX *mem_ctx, + + done: + if (ret == EOK) { ++ ret = cache_req_search_ncache_filter(state, cr, &state->result); ++ } ++ ++ if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); +-- +2.9.4 + diff --git a/SOURCES/0170-cache_req-Do-not-use-default_domain_suffix-with-netg.patch b/SOURCES/0170-cache_req-Do-not-use-default_domain_suffix-with-netg.patch new file mode 100644 index 0000000..78326bf --- /dev/null +++ b/SOURCES/0170-cache_req-Do-not-use-default_domain_suffix-with-netg.patch @@ -0,0 +1,34 @@ +From eb3f60eacc6279a6bd97eff7d7be0cc081a7bf9a Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Thu, 8 Jun 2017 12:32:44 +0200 +Subject: [PATCH 170/171] cache_req: Do not use default_domain_suffix with + netgroups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves: +https://pagure.io/SSSD/sssd/issue/3428 + +Reviewed-by: Pavel Březina +(cherry picked from commit c83e265bbb5b2f2aa4f0067263753c8403c383f9) +--- + src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +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 4d8bb18579a286042b00528190dadd52fdd7c75c..ef0775d0b8eac4d679450f436d8427cff9c04582 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 +@@ -112,7 +112,7 @@ const struct cache_req_plugin cache_req_netgroup_by_name = { + .name = "Netgroup by name", + .attr_expiration = SYSDB_CACHE_EXPIRE, + .parse_name = true, +- .ignore_default_domain = false, ++ .ignore_default_domain = true, + .bypass_cache = false, + .only_one_result = true, + .search_all_domains = false, +-- +2.9.4 + diff --git a/SOURCES/0171-krb5-disable-enterprise-principals-during-password-c.patch b/SOURCES/0171-krb5-disable-enterprise-principals-during-password-c.patch new file mode 100644 index 0000000..22655c1 --- /dev/null +++ b/SOURCES/0171-krb5-disable-enterprise-principals-during-password-c.patch @@ -0,0 +1,47 @@ +From 0956acb31884e87ef48c3be8c59960acfc03a547 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 8 Jun 2017 11:06:02 +0200 +Subject: [PATCH 171/171] krb5: disable enterprise principals during password + changes + +Currently using enterprise principals during password changes does not +work reliable. + +First there is a special behavior if canonicalization, which in general +should be used together with enterprise principals, is enabled with AD, +see https://pagure.io/SSSD/sssd/issue/1405 and +https://pagure.io/SSSD/sssd/issue/1615 for details. As a result of this +SSSD currently disables canonicalization during password changes. + +Additionally it looks like MIT Kerberos does not handle canonicalized +principals well, even if canonicalization is enabled, if not the default +krbtgt/REALM@REALM but kadmin/changepw@REALM is requested. Since it is +currently not clear what is the expected behavior here it make sense to +completely disable enterprise principals during password changes for the +time being. + +Resolves https://pagure.io/SSSD/sssd/issue/3426 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 614057ea85c05d3a6d4b62217a41b8b5db8d5d38) +--- + src/providers/krb5/krb5_child_handler.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c +index 11ac867e62d2ff96b827cf6d4ff341fc8ff0a286..0007f92a61ba711aed6be5ee28664e5f7de0f226 100644 +--- a/src/providers/krb5/krb5_child_handler.c ++++ b/src/providers/krb5/krb5_child_handler.c +@@ -143,7 +143,8 @@ static errno_t create_send_buffer(struct krb5child_req *kr, + return EINVAL; + } + +- if (kr->pd->cmd == SSS_CMD_RENEW || kr->is_offline) { ++ if (kr->pd->cmd == SSS_CMD_RENEW || kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ++ || kr->pd->cmd == SSS_PAM_CHAUTHTOK || kr->is_offline) { + use_enterprise_principal = false; + } else { + use_enterprise_principal = dp_opt_get_bool(kr->krb5_ctx->opts, +-- +2.9.4 + diff --git a/SOURCES/0172-pam_sss-Fix-leaking-of-memory-in-case-of-failures.patch b/SOURCES/0172-pam_sss-Fix-leaking-of-memory-in-case-of-failures.patch new file mode 100644 index 0000000..7c9d403 --- /dev/null +++ b/SOURCES/0172-pam_sss-Fix-leaking-of-memory-in-case-of-failures.patch @@ -0,0 +1,44 @@ +From c58aac42664dd1a04edb37b0874109a6a88d0da1 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 5 Jun 2017 09:43:46 +0200 +Subject: [PATCH 172/181] pam_sss: Fix leaking of memory in case of failures +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Found by coverity. + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 818d01b4a0d332fff06db33c0c985b8c0f1417c7) +--- + src/sss_client/pam_sss.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c +index 9732459e6fb7ce01c9445c423cf0a583ca36e036..303809b9ea05b5a8709c05ae230d5f289b57de31 100644 +--- a/src/sss_client/pam_sss.c ++++ b/src/sss_client/pam_sss.c +@@ -1517,10 +1517,12 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) + if (pi->user_name_hint) { + ret = pam_get_item(pamh, PAM_CONV, (const void **)&conv); + if (ret != PAM_SUCCESS) { ++ free(prompt); + return ret; + } + if (conv == NULL || conv->conv == NULL) { + logger(pamh, LOG_ERR, "No conversation function"); ++ free(prompt); + return PAM_SYSTEM_ERR; + } + +@@ -1540,6 +1542,7 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) + mesg[1] = &((*mesg)[1]); + + ret = conv->conv(2, mesg, &resp, conv->appdata_ptr); ++ free(prompt); + if (ret != PAM_SUCCESS) { + D(("Conversation failure: %s.", pam_strerror(pamh, ret))); + return ret; +-- +2.9.4 + diff --git a/SOURCES/0173-IFP-Add-domain-and-domainname-attributes-to-the-user.patch b/SOURCES/0173-IFP-Add-domain-and-domainname-attributes-to-the-user.patch new file mode 100644 index 0000000..be61e37 --- /dev/null +++ b/SOURCES/0173-IFP-Add-domain-and-domainname-attributes-to-the-user.patch @@ -0,0 +1,372 @@ +From a35b5c33a76857ad9223363e15558facec5c269d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 8 Jun 2017 11:46:25 +0200 +Subject: [PATCH 173/181] IFP: Add domain and domainname attributes to the user +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +org.freedekstop.sssd.infopipe.Users.User gets two new attributes: +- domain: object path of user's domain +- domainname: user's domain name + +org.freedekstop.sssd.infopipe.GetUserAttr can now request new attribute: +- domainname: user's domain name + +Resolves: +https://pagure.io/SSSD/sssd/issue/2714 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 37d2194cc9ea4d0254c88a3419e2376572562bab) +--- + src/responder/ifp/ifp_iface.c | 2 + + src/responder/ifp/ifp_iface.xml | 2 + + src/responder/ifp/ifp_iface_generated.c | 18 ++++++++ + src/responder/ifp/ifp_iface_generated.h | 4 ++ + src/responder/ifp/ifp_private.h | 4 ++ + src/responder/ifp/ifp_users.c | 46 ++++++++++++++++++++ + src/responder/ifp/ifp_users.h | 8 ++++ + src/responder/ifp/ifpsrv_cmd.c | 8 ++++ + src/responder/ifp/ifpsrv_util.c | 74 ++++++++++++++++++++++++++++++++- + src/tests/cmocka/test_ifp.c | 12 ++++-- + 10 files changed, 173 insertions(+), 5 deletions(-) + +diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c +index e413e74f955c067a0efbe385a08b4b2cc6f2bba1..3293b92d750d33b2ecf77a03098c5169d052c924 100644 +--- a/src/responder/ifp/ifp_iface.c ++++ b/src/responder/ifp/ifp_iface.c +@@ -104,6 +104,8 @@ struct iface_ifp_users_user iface_ifp_users_user = { + .get_loginShell = ifp_users_user_get_login_shell, + .get_uniqueID = ifp_users_user_get_unique_id, + .get_groups = ifp_users_user_get_groups, ++ .get_domain = ifp_users_user_get_domain, ++ .get_domainname = ifp_users_user_get_domainname, + .get_extraAttributes = ifp_users_user_get_extra_attributes + }; + +diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml +index 0a23f56907f64c4c24db3ec3c0a312adbdb3edc8..ce071bb999bd207b8cc81f054da80de52a13d3df 100644 +--- a/src/responder/ifp/ifp_iface.xml ++++ b/src/responder/ifp/ifp_iface.xml +@@ -188,6 +188,8 @@ + + + ++ ++ + + + +diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c +index 211646b6760d15e0df55ac20b9611b800b11d16c..51db4a9e5c7d72663f8845bd0da22d3f21526be8 100644 +--- a/src/responder/ifp/ifp_iface_generated.c ++++ b/src/responder/ifp/ifp_iface_generated.c +@@ -982,6 +982,24 @@ const struct sbus_property_meta iface_ifp_users_user__properties[] = { + NULL, /* no invoker */ + }, + { ++ "domain", /* name */ ++ "o", /* type */ ++ SBUS_PROPERTY_READABLE, ++ offsetof(struct iface_ifp_users_user, get_domain), ++ sbus_invoke_get_o, ++ 0, /* not writable */ ++ NULL, /* no invoker */ ++ }, ++ { ++ "domainname", /* name */ ++ "s", /* type */ ++ SBUS_PROPERTY_READABLE, ++ offsetof(struct iface_ifp_users_user, get_domainname), ++ sbus_invoke_get_s, ++ 0, /* not writable */ ++ NULL, /* no invoker */ ++ }, ++ { + "extraAttributes", /* name */ + "a{sas}", /* type */ + SBUS_PROPERTY_READABLE, +diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h +index e69fc3a3efc6bdcef5d6539790908795818cd857..76f729fcb268e9c07668b3a5ee5bbd7d0b44ca16 100644 +--- a/src/responder/ifp/ifp_iface_generated.h ++++ b/src/responder/ifp/ifp_iface_generated.h +@@ -88,6 +88,8 @@ + #define IFACE_IFP_USERS_USER_LOGINSHELL "loginShell" + #define IFACE_IFP_USERS_USER_UNIQUEID "uniqueID" + #define IFACE_IFP_USERS_USER_GROUPS "groups" ++#define IFACE_IFP_USERS_USER_DOMAIN "domain" ++#define IFACE_IFP_USERS_USER_DOMAINNAME "domainname" + #define IFACE_IFP_USERS_USER_EXTRAATTRIBUTES "extraAttributes" + + /* constants for org.freedesktop.sssd.infopipe.Groups */ +@@ -288,6 +290,8 @@ struct iface_ifp_users_user { + void (*get_loginShell)(struct sbus_request *, void *data, const char **); + void (*get_uniqueID)(struct sbus_request *, void *data, const char **); + void (*get_groups)(struct sbus_request *, void *data, const char ***, int *); ++ void (*get_domain)(struct sbus_request *, void *data, const char **); ++ void (*get_domainname)(struct sbus_request *, void *data, const char **); + void (*get_extraAttributes)(struct sbus_request *, void *data, hash_table_t **); + }; + +diff --git a/src/responder/ifp/ifp_private.h b/src/responder/ifp/ifp_private.h +index e800070a59f77f8ce58a2fc402e616bb773e996b..a6e5701b8d1ebb27af0c35fa3ebe0c6c00d16bd6 100644 +--- a/src/responder/ifp/ifp_private.h ++++ b/src/responder/ifp/ifp_private.h +@@ -70,6 +70,10 @@ errno_t ifp_req_create(struct sbus_request *dbus_req, + /* Returns an appropriate DBus error for specific ifp_req_create failures */ + int ifp_req_create_handle_failure(struct sbus_request *dbus_req, errno_t err); + ++errno_t ifp_add_value_to_dict(DBusMessageIter *iter_dict, ++ const char *key, ++ const char *value); ++ + errno_t ifp_add_ldb_el_to_dict(DBusMessageIter *iter_dict, + struct ldb_message_element *el); + const char ** +diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c +index 188194f2ab356d0e67b0f26b003f3a9ce48e6acd..90b947ed9ca345fbeba6772c90f898451a0868aa 100644 +--- a/src/responder/ifp/ifp_users.c ++++ b/src/responder/ifp/ifp_users.c +@@ -1328,6 +1328,52 @@ void ifp_users_user_get_groups(struct sbus_request *sbus_req, + *_size = num_groups; + } + ++void ifp_users_user_get_domain(struct sbus_request *sbus_req, ++ void *data, ++ const char **_out) ++{ ++ const char *domainname; ++ ++ *_out = NULL; ++ ifp_users_user_get_domainname(sbus_req, data, &domainname); ++ ++ if (domainname == NULL) { ++ return; ++ } ++ ++ *_out = sbus_opath_compose(sbus_req, IFP_PATH_DOMAINS, ++ domainname); ++} ++ ++void ifp_users_user_get_domainname(struct sbus_request *sbus_req, ++ void *data, ++ const char **_out) ++{ ++ struct ifp_ctx *ifp_ctx; ++ struct sss_domain_info *domain; ++ errno_t ret; ++ ++ *_out = NULL; ++ ++ ifp_ctx = talloc_get_type(data, struct ifp_ctx); ++ if (ifp_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid pointer!\n"); ++ return; ++ } ++ ++ if (!ifp_is_user_attr_allowed(ifp_ctx, "domainname")) { ++ DEBUG(SSSDBG_TRACE_ALL, "Attribute domainname is not allowed\n"); ++ return; ++ } ++ ++ ret = ifp_users_user_get(sbus_req, ifp_ctx, &domain, NULL); ++ if (ret != EOK) { ++ return; ++ } ++ ++ *_out = domain->name; ++} ++ + void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, + void *data, + hash_table_t **_out) +diff --git a/src/responder/ifp/ifp_users.h b/src/responder/ifp/ifp_users.h +index f8fefeb7f658b6e0a5f72371da1b025d69e6f412..715a8bc31996bfd93c21dbe263f2567bd0b50b03 100644 +--- a/src/responder/ifp/ifp_users.h ++++ b/src/responder/ifp/ifp_users.h +@@ -103,6 +103,14 @@ void ifp_users_user_get_groups(struct sbus_request *sbus_req, + const char ***_out, + int *_size); + ++void ifp_users_user_get_domain(struct sbus_request *sbus_req, ++ void *data, ++ const char **_out); ++ ++void ifp_users_user_get_domainname(struct sbus_request *sbus_req, ++ void *data, ++ const char **_out); ++ + void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req, + void *data, + hash_table_t **_out); +diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c +index 70728e1bb656fd032b7f1c240683e8aa3b91a726..d86aed57206ba8f0a6facbd64051fa7c901513f3 100644 +--- a/src/responder/ifp/ifpsrv_cmd.c ++++ b/src/responder/ifp/ifpsrv_cmd.c +@@ -233,6 +233,14 @@ ifp_user_get_attr_handle_reply(struct sss_domain_info *domain, + } + + for (ai = 0; attrs[ai]; ai++) { ++ if (strcmp(attrs[ai], "domainname") == 0) { ++ ret = ifp_add_value_to_dict(&iter_dict, "domainname", ++ domain->name); ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot add attribute %s to message\n", attrs[ai]); ++ continue; ++ } ++ + el = sss_view_ldb_msg_find_element(domain, res->msgs[0], attrs[ai]); + if (el == NULL || el->num_values == 0) { + DEBUG(SSSDBG_MINOR_FAILURE, +diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c +index 5866d30d8a5845c21f5b05fc5de150162eba747e..643881515fb4805ae93ba56c3bca9d1da7796319 100644 +--- a/src/responder/ifp/ifpsrv_util.c ++++ b/src/responder/ifp/ifpsrv_util.c +@@ -29,7 +29,7 @@ + #define IFP_USER_DEFAULT_ATTRS {SYSDB_NAME, SYSDB_UIDNUM, \ + SYSDB_GIDNUM, SYSDB_GECOS, \ + SYSDB_HOMEDIR, SYSDB_SHELL, \ +- "groups", \ ++ "groups", "domain", "domainname", \ + NULL} + + errno_t ifp_req_create(struct sbus_request *dbus_req, +@@ -100,6 +100,78 @@ int ifp_req_create_handle_failure(struct sbus_request *dbus_req, errno_t err) + "Cannot create IFP request\n")); + } + ++errno_t ifp_add_value_to_dict(DBusMessageIter *iter_dict, ++ const char *key, ++ const char *value) ++{ ++ DBusMessageIter iter_dict_entry; ++ DBusMessageIter iter_dict_val; ++ DBusMessageIter iter_array; ++ dbus_bool_t dbret; ++ ++ if (value == NULL || key == NULL) { ++ return EINVAL; ++ } ++ ++ dbret = dbus_message_iter_open_container(iter_dict, ++ DBUS_TYPE_DICT_ENTRY, NULL, ++ &iter_dict_entry); ++ if (!dbret) { ++ return ENOMEM; ++ } ++ ++ /* Start by appending the key */ ++ dbret = dbus_message_iter_append_basic(&iter_dict_entry, ++ DBUS_TYPE_STRING, &key); ++ if (!dbret) { ++ return ENOMEM; ++ } ++ ++ dbret = dbus_message_iter_open_container(&iter_dict_entry, ++ DBUS_TYPE_VARIANT, ++ DBUS_TYPE_ARRAY_AS_STRING ++ DBUS_TYPE_STRING_AS_STRING, ++ &iter_dict_val); ++ if (!dbret) { ++ return ENOMEM; ++ } ++ ++ /* Open container for values */ ++ dbret = dbus_message_iter_open_container(&iter_dict_val, ++ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, ++ &iter_array); ++ if (!dbret) { ++ return ENOMEM; ++ } ++ ++ dbret = dbus_message_iter_append_basic(&iter_array, ++ DBUS_TYPE_STRING, ++ &value); ++ if (!dbret) { ++ return ENOMEM; ++ } ++ ++ dbret = dbus_message_iter_close_container(&iter_dict_val, ++ &iter_array); ++ if (!dbret) { ++ return ENOMEM; ++ } ++ ++ dbret = dbus_message_iter_close_container(&iter_dict_entry, ++ &iter_dict_val); ++ if (!dbret) { ++ return ENOMEM; ++ } ++ ++ dbret = dbus_message_iter_close_container(iter_dict, ++ &iter_dict_entry); ++ if (!dbret) { ++ return ENOMEM; ++ } ++ ++ return EOK; ++} ++ + errno_t ifp_add_ldb_el_to_dict(DBusMessageIter *iter_dict, + struct ldb_message_element *el) + { +diff --git a/src/tests/cmocka/test_ifp.c b/src/tests/cmocka/test_ifp.c +index 21c5475d1c74cd8325815653166bef194ea84f7b..45f718341222c6803a65130741590e10e7aded84 100644 +--- a/src/tests/cmocka/test_ifp.c ++++ b/src/tests/cmocka/test_ifp.c +@@ -269,7 +269,7 @@ void test_attr_acl(void **state) + const char *exp_defaults[] = { SYSDB_NAME, SYSDB_UIDNUM, + SYSDB_GIDNUM, SYSDB_GECOS, + SYSDB_HOMEDIR, SYSDB_SHELL, +- "groups", NULL }; ++ "groups", "domain", "domainname", NULL }; + attr_parse_test(exp_defaults, NULL); + + /* Test adding some attributes to the defaults */ +@@ -277,13 +277,14 @@ void test_attr_acl(void **state) + SYSDB_NAME, SYSDB_UIDNUM, + SYSDB_GIDNUM, SYSDB_GECOS, + SYSDB_HOMEDIR, SYSDB_SHELL, +- "groups", NULL }; ++ "groups", "domain", "domainname", NULL }; + attr_parse_test(exp_add, "+telephoneNumber, +streetAddress"); + + /* Test removing some attributes to the defaults */ + const char *exp_rm[] = { SYSDB_NAME, + SYSDB_GIDNUM, SYSDB_GECOS, + SYSDB_HOMEDIR, "groups", ++ "domain", "domainname", + NULL }; + attr_parse_test(exp_rm, "-"SYSDB_SHELL ",-"SYSDB_UIDNUM); + +@@ -292,6 +293,7 @@ void test_attr_acl(void **state) + SYSDB_NAME, SYSDB_UIDNUM, + SYSDB_GIDNUM, SYSDB_GECOS, + SYSDB_HOMEDIR, "groups", ++ "domain", "domainname", + NULL }; + attr_parse_test(exp_add_rm, "+telephoneNumber, -"SYSDB_SHELL); + +@@ -299,7 +301,8 @@ void test_attr_acl(void **state) + const char *exp_add_rm_override[] = { SYSDB_NAME, SYSDB_UIDNUM, + SYSDB_GIDNUM, SYSDB_GECOS, + SYSDB_HOMEDIR, SYSDB_SHELL, +- "groups", NULL }; ++ "groups", "domain", ++ "domainname", NULL }; + attr_parse_test(exp_add_rm_override, + "+telephoneNumber, -telephoneNumber, +telephoneNumber"); + +@@ -307,7 +310,8 @@ void test_attr_acl(void **state) + const char *rm_all[] = { NULL }; + attr_parse_test(rm_all, "-"SYSDB_NAME ", -"SYSDB_UIDNUM + ", -"SYSDB_GIDNUM ", -"SYSDB_GECOS +- ", -"SYSDB_HOMEDIR ", -"SYSDB_SHELL", -groups"); ++ ", -"SYSDB_HOMEDIR ", -"SYSDB_SHELL", -groups, " ++ "-domain, -domainname"); + + /* Malformed list */ + attr_parse_test(NULL, "missing_plus_or_minus"); +-- +2.9.4 + diff --git a/SOURCES/0174-IFP-Fix-error-handling-in-ifp_user_get_attr_handle_r.patch b/SOURCES/0174-IFP-Fix-error-handling-in-ifp_user_get_attr_handle_r.patch new file mode 100644 index 0000000..4d39c22 --- /dev/null +++ b/SOURCES/0174-IFP-Fix-error-handling-in-ifp_user_get_attr_handle_r.patch @@ -0,0 +1,39 @@ +From 271679e7a7c0c50e39c7a0989dbae77385475c60 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 14 Jun 2017 18:25:21 +0200 +Subject: [PATCH 174/181] IFP: Fix error handling in + ifp_user_get_attr_handle_reply() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This bug was introduced in 37d2194cc9ea4d0254c88a3419e2376572562bab + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 15a76bb7bd9791a3ed1ae416f70753d32c6ff599) +--- + src/responder/ifp/ifpsrv_cmd.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c +index d86aed57206ba8f0a6facbd64051fa7c901513f3..fc9161e82e906ac7dde2712ffc7c0cbb58c519b7 100644 +--- a/src/responder/ifp/ifpsrv_cmd.c ++++ b/src/responder/ifp/ifpsrv_cmd.c +@@ -236,9 +236,11 @@ ifp_user_get_attr_handle_reply(struct sss_domain_info *domain, + if (strcmp(attrs[ai], "domainname") == 0) { + ret = ifp_add_value_to_dict(&iter_dict, "domainname", + domain->name); +- DEBUG(SSSDBG_MINOR_FAILURE, +- "Cannot add attribute %s to message\n", attrs[ai]); +- continue; ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot add attribute domainname to message\n"); ++ continue; ++ } + } + + el = sss_view_ldb_msg_find_element(domain, res->msgs[0], attrs[ai]); +-- +2.9.4 + diff --git a/SOURCES/0175-SYSDB-Return-ERR_NO_TS-when-there-s-no-timestamp-cac.patch b/SOURCES/0175-SYSDB-Return-ERR_NO_TS-when-there-s-no-timestamp-cac.patch new file mode 100644 index 0000000..748f9e8 --- /dev/null +++ b/SOURCES/0175-SYSDB-Return-ERR_NO_TS-when-there-s-no-timestamp-cac.patch @@ -0,0 +1,76 @@ +From 10b75d84300726e5e311b0488352b891f106d631 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 24 May 2017 00:35:23 +0200 +Subject: [PATCH 175/181] SYSDB: Return ERR_NO_TS when there's no timestamp + cache present +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This change affects sysdb_search_ts_{users,groups} functions and is +mainly needed in order to avoid breaking our current tests due to the +changes planned for fixing https://pagure.io/SSSD/sssd/issue/3369. + +Related: +https://pagure.io/SSSD/sssd/issue/3369 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 01c6bb9b47401f9f14c4cfe5c5f03fce2e63629b) +--- + src/db/sysdb_ops.c | 4 ++-- + src/db/sysdb_search.c | 8 ++++++++ + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 4d7b2abd8026c90aaf4e7be687102e459cf3690e..12f8095d2edc60ffab09c92d64f968892c577bbf 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -3520,7 +3520,7 @@ int sysdb_search_ts_users(TALLOC_CTX *mem_ctx, + ZERO_STRUCT(*res); + + if (domain->sysdb->ldb_ts == NULL) { +- return ENOENT; ++ return ERR_NO_TS; + } + + ret = sysdb_cache_search_users(mem_ctx, domain, domain->sysdb->ldb_ts, +@@ -3737,7 +3737,7 @@ int sysdb_search_ts_groups(TALLOC_CTX *mem_ctx, + ZERO_STRUCT(*res); + + if (domain->sysdb->ldb_ts == NULL) { +- return ENOENT; ++ return ERR_NO_TS; + } + + ret = sysdb_cache_search_groups(mem_ctx, domain, domain->sysdb->ldb_ts, +diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c +index 474bc08f0b2fe3b0289cbea96fbf2619ced271e7..6b4b51383d89788052ab7e4b572e86abba5330db 100644 +--- a/src/db/sysdb_search.c ++++ b/src/db/sysdb_search.c +@@ -587,6 +587,10 @@ int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx, + ret = sysdb_search_ts_users(tmp_ctx, domain, ts_filter, + sysdb_ts_cache_attrs, + &ts_res); ++ if (ret == ERR_NO_TS) { ++ ret = ENOENT; ++ } ++ + if (ret != EOK && ret != ENOENT) { + goto done; + } +@@ -1088,6 +1092,10 @@ int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx, + ret = sysdb_search_ts_groups(tmp_ctx, domain, ts_filter, + sysdb_ts_cache_attrs, + &ts_res); ++ if (ret == ERR_NO_TS) { ++ ret = ENOENT; ++ } ++ + if (ret != EOK && ret != ENOENT) { + goto done; + } +-- +2.9.4 + diff --git a/SOURCES/0176-SYSDB-Internally-expose-sysdb_search_ts_matches.patch b/SOURCES/0176-SYSDB-Internally-expose-sysdb_search_ts_matches.patch new file mode 100644 index 0000000..38fdfa6 --- /dev/null +++ b/SOURCES/0176-SYSDB-Internally-expose-sysdb_search_ts_matches.patch @@ -0,0 +1,90 @@ +From 67e592572e655f19326cf821bbbe43411e8c7b06 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 23 May 2017 22:44:24 +0200 +Subject: [PATCH 176/181] SYSDB: Internally expose sysdb_search_ts_matches() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This function will be used in the follow-up patches. As it's going to be +"exposed", let's also rename it from search_ts_matches() to +sysdb_search_ts_matches(). + +Related: +https://pagure.io/SSSD/sssd/issue/3369 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 347be58e1769ba90b49a7e5ec1678ef66987f6cd) +--- + src/db/sysdb_private.h | 7 +++++++ + src/db/sysdb_search.c | 20 ++++++++++---------- + 2 files changed, 17 insertions(+), 10 deletions(-) + +diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h +index dfddd2dda9e593bd02d52dee7d06f520a11bbdf6..433220dcc0c35366dbbee41525e6c5932eb897f9 100644 +--- a/src/db/sysdb_private.h ++++ b/src/db/sysdb_private.h +@@ -260,6 +260,13 @@ int sysdb_search_ts_groups(TALLOC_CTX *mem_ctx, + const char **attrs, + struct ldb_result *res); + ++errno_t sysdb_search_ts_matches(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ const char *attrs[], ++ struct ldb_result *ts_res, ++ const char *filter, ++ struct ldb_result **_res); ++ + /* Compares the modifyTimestamp attribute between old_entry and + * new_entry. Returns true if they differ (or either entry is missing + * the attribute) and false if the attribute is the same +diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c +index 6b4b51383d89788052ab7e4b572e86abba5330db..0c04b84a584e047a0ba8243c9216547ea2791e60 100644 +--- a/src/db/sysdb_search.c ++++ b/src/db/sysdb_search.c +@@ -482,12 +482,12 @@ done: + return ret; + } + +-static errno_t search_ts_matches(TALLOC_CTX *mem_ctx, +- struct sysdb_ctx *sysdb, +- const char *attrs[], +- struct ldb_result *ts_res, +- const char *filter, +- struct ldb_result **_res) ++errno_t sysdb_search_ts_matches(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ const char *attrs[], ++ struct ldb_result *ts_res, ++ const char *filter, ++ struct ldb_result **_res) + { + char *dn_filter; + TALLOC_CTX *tmp_ctx = NULL; +@@ -595,8 +595,8 @@ int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res, +- name_filter, &ts_cache_res); ++ ret = sysdb_search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res, ++ name_filter, &ts_cache_res); + if (ret != EOK && ret != ENOENT) { + goto done; + } +@@ -1100,8 +1100,8 @@ int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res, +- name_filter, &ts_cache_res); ++ ret = sysdb_search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res, ++ name_filter, &ts_cache_res); + if (ret != EOK && ret != ENOENT) { + goto done; + } +-- +2.9.4 + diff --git a/SOURCES/0177-SYSDB-Make-the-usage-of-the-filter-more-generic-for-.patch b/SOURCES/0177-SYSDB-Make-the-usage-of-the-filter-more-generic-for-.patch new file mode 100644 index 0000000..89eb87a --- /dev/null +++ b/SOURCES/0177-SYSDB-Make-the-usage-of-the-filter-more-generic-for-.patch @@ -0,0 +1,157 @@ +From 7d926fb2e8fe21e3fa51bc341189d33658600daf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 24 May 2017 11:52:23 +0200 +Subject: [PATCH 177/181] SYSDB: Make the usage of the filter more generic for + search_ts_matches() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In order to make this function re-usable in different parts of our code, +let's start passing an already built filter to it instead of having the +specific code building the name filter there. + +Related: +https://pagure.io/SSSD/sssd/issue/3369 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 8ad57e17779b3ec60246ac58c1691ee15745084c) +--- + src/db/sysdb_search.c | 67 +++++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 54 insertions(+), 13 deletions(-) + +diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c +index 0c04b84a584e047a0ba8243c9216547ea2791e60..f488442afcc6eef114437a7110722759f86fe19e 100644 +--- a/src/db/sysdb_search.c ++++ b/src/db/sysdb_search.c +@@ -489,7 +489,6 @@ errno_t sysdb_search_ts_matches(TALLOC_CTX *mem_ctx, + const char *filter, + struct ldb_result **_res) + { +- char *dn_filter; + TALLOC_CTX *tmp_ctx = NULL; + struct ldb_result *res; + errno_t ret; +@@ -501,7 +500,7 @@ errno_t sysdb_search_ts_matches(TALLOC_CTX *mem_ctx, + } + + tmp_ctx = talloc_new(NULL); +- if (!tmp_ctx) { ++ if (tmp_ctx == NULL) { + return ENOMEM; + } + +@@ -511,7 +510,43 @@ errno_t sysdb_search_ts_matches(TALLOC_CTX *mem_ctx, + goto done; + } + +- dn_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(|", SYSDB_NAME, filter); ++ ret = ldb_search(sysdb->ldb, tmp_ctx, &res, NULL, ++ LDB_SCOPE_SUBTREE, attrs, "%s", filter); ++ if (ret) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ *_res = talloc_steal(mem_ctx, res); ++ ret = EOK; ++ ++done: ++ talloc_zfree(tmp_ctx); ++ return ret; ++} ++ ++static errno_t sysdb_enum_dn_filter(TALLOC_CTX *mem_ctx, ++ struct ldb_result *ts_res, ++ const char *name_filter, ++ char **_dn_filter) ++{ ++ TALLOC_CTX *tmp_ctx = NULL; ++ char *dn_filter; ++ errno_t ret; ++ ++ if (ts_res->count == 0) { ++ *_dn_filter = NULL; ++ ret = EOK; ++ goto done; ++ } ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(|", SYSDB_NAME, ++ name_filter); + if (dn_filter == NULL) { + ret = ENOMEM; + goto done; +@@ -535,15 +570,9 @@ errno_t sysdb_search_ts_matches(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = ldb_search(sysdb->ldb, tmp_ctx, &res, NULL, +- LDB_SCOPE_SUBTREE, attrs, "%s", dn_filter); +- if (ret) { +- ret = sysdb_error_to_errno(ret); +- goto done; +- } +- ++ *_dn_filter = talloc_steal(mem_ctx, dn_filter); + ret = EOK; +- *_res = talloc_steal(mem_ctx, res); ++ + done: + talloc_zfree(tmp_ctx); + return ret; +@@ -558,6 +587,7 @@ int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx, + TALLOC_CTX *tmp_ctx; + static const char *attrs[] = SYSDB_PW_ATTRS; + char *filter = NULL; ++ char *dn_filter = NULL; + const char *ts_filter = NULL; + struct ldb_dn *base_dn; + struct ldb_result *res; +@@ -595,8 +625,13 @@ int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx, + goto done; + } + ++ ret = sysdb_enum_dn_filter(tmp_ctx, &ts_res, name_filter, &dn_filter); ++ if (ret != EOK) { ++ goto done; ++ } ++ + ret = sysdb_search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res, +- name_filter, &ts_cache_res); ++ dn_filter, &ts_cache_res); + if (ret != EOK && ret != ENOENT) { + goto done; + } +@@ -1052,6 +1087,7 @@ int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx, + const char *filter = NULL; + const char *ts_filter = NULL; + const char *base_filter; ++ char *dn_filter = NULL; + struct ldb_dn *base_dn; + struct ldb_result *res; + struct ldb_result ts_res; +@@ -1100,8 +1136,13 @@ int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx, + goto done; + } + ++ ret = sysdb_enum_dn_filter(tmp_ctx, &ts_res, name_filter, &dn_filter); ++ if (ret != EOK) { ++ goto done; ++ } ++ + ret = sysdb_search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res, +- name_filter, &ts_cache_res); ++ dn_filter, &ts_cache_res); + if (ret != EOK && ret != ENOENT) { + goto done; + } +-- +2.9.4 + diff --git a/SOURCES/0178-SYSDB_OPS-Mark-an-entry-as-expired-also-in-the-times.patch b/SOURCES/0178-SYSDB_OPS-Mark-an-entry-as-expired-also-in-the-times.patch new file mode 100644 index 0000000..b4cbbf8 --- /dev/null +++ b/SOURCES/0178-SYSDB_OPS-Mark-an-entry-as-expired-also-in-the-times.patch @@ -0,0 +1,55 @@ +From 891e9c7cb924830334a42864ef2582e545f42723 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 29 May 2017 13:32:59 +0200 +Subject: [PATCH 178/181] SYSDB_OPS: Mark an entry as expired also in the + timestamp cache +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As the cleanup task will start using new methods for searching the users +and groups which have to be cleaned up, SSSD starts relying more in a +more consistent state of the timestamp cache on pretty much everything +related to the cleanup task. + +One of the things that would cause SSSD some problems is not having the +ghost user expired in the persistent cache but not in the timestamp +cache. + +With this patch, the entry is also expired in the timestamp cache when +it's present. + +Related: +https://pagure.io/SSSD/sssd/issue/3369 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 9883d1e2913ff0c1db479f1ece8148e03155c7f3) +--- + src/db/sysdb_ops.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 12f8095d2edc60ffab09c92d64f968892c577bbf..ae26470487f859fe1de1dc364b6a05b9793a0545 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -5065,6 +5065,15 @@ errno_t sysdb_mark_entry_as_expired_ldb_dn(struct sss_domain_info *dom, + goto done; + } + ++ if (dom->sysdb->ldb_ts != NULL) { ++ ret = ldb_modify(dom->sysdb->ldb_ts, msg); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Could not mark an entry as expired in the timestamp cache\n"); ++ /* non-fatal */ ++ } ++ } ++ + ret = EOK; + + done: +-- +2.9.4 + diff --git a/SOURCES/0179-SYSDB_OPS-Invalidate-a-cache-entry-also-in-the-ts_ca.patch b/SOURCES/0179-SYSDB_OPS-Invalidate-a-cache-entry-also-in-the-ts_ca.patch new file mode 100644 index 0000000..e6512c2 --- /dev/null +++ b/SOURCES/0179-SYSDB_OPS-Invalidate-a-cache-entry-also-in-the-ts_ca.patch @@ -0,0 +1,49 @@ +From 256e1b4162832570e10a85579d2b14ed7b54b7f2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 29 May 2017 13:29:26 +0200 +Subject: [PATCH 179/181] SYSDB_OPS: Invalidate a cache entry also in the + ts_cache +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Similarly to what has been in the previous commit (expiring an entry +also in the timestamp cache), we should do the same when invalidating an +entry. + +Related: +https://pagure.io/SSSD/sssd/issue/3369 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +(cherry picked from commit a71f1a655dcc2ca6dc16bb8eb1c4c9e24cfe2c3e) +--- + src/db/sysdb_ops.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index ae26470487f859fe1de1dc364b6a05b9793a0545..ed936f0cb1a37155aabef96db1d267eb03ec0ed9 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -5160,6 +5160,17 @@ int sysdb_invalidate_cache_entry(struct sss_domain_info *domain, + goto done; + } + ++ if (sysdb->ldb_ts != NULL) { ++ ret = sysdb_set_cache_entry_attr(sysdb->ldb_ts, entry_dn, ++ attrs, SYSDB_MOD_REP); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot set attrs in the timestamp cache for %s, %d [%s]\n", ++ ldb_dn_get_linearized(entry_dn), ret, sss_strerror(ret)); ++ /* non-fatal */ ++ } ++ } ++ + DEBUG(SSSDBG_FUNC_DATA, + "Cache entry [%s] has been invalidated.\n", + ldb_dn_get_linearized(entry_dn)); +-- +2.9.4 + diff --git a/SOURCES/0180-SYSDB-Introduce-_search_-users-groups-_by_timestamp.patch b/SOURCES/0180-SYSDB-Introduce-_search_-users-groups-_by_timestamp.patch new file mode 100644 index 0000000..5bfa491 --- /dev/null +++ b/SOURCES/0180-SYSDB-Introduce-_search_-users-groups-_by_timestamp.patch @@ -0,0 +1,278 @@ +From 11c34233ac7385c6f2a65c5cc57dfefb1cae48cd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 7 Jun 2017 15:07:10 +0200 +Subject: [PATCH 180/181] SYSDB: Introduce + _search_{users,groups}_by_timestamp() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +These new two sysdb methods are going to be used, at least for now, +uniquely and exclusively in the cleanup task. + +The reason for adding those is that during the cleanup task a timestamp +search is done in the persistent cache, which doesn't have the updated +timestamps, returning then a wrong result that ends up in having all the +users being removed from the cache. + +The persistent cache doesn't have its entries' timestamps updated +because those are kept updated in the timestamp cache, therefore these +new two methods end up doing: +- if the timestamp cache is present: + - search for the entries solely in the timestamp cache; + - get the needed attributes from these entries from the persistent + cache; +- otherwise: + - search for the entries in the persistent cache; + - merge its results with timestamp cache's results; + +Related: +https://pagure.io/SSSD/sssd/issue/3369 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 41708e1e500e7cada3d3e606aa2b8b9869a5c734) +--- + src/db/sysdb.h | 14 +++++ + src/db/sysdb_ops.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 192 insertions(+) + +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 62c561be9452a284a8ddf8ebb45720265852c8b0..21d6cf4fc90a050e203e1609be5ee267a618dda9 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -1142,6 +1142,13 @@ int sysdb_search_users(TALLOC_CTX *mem_ctx, + size_t *msgs_count, + struct ldb_message ***msgs); + ++int sysdb_search_users_by_timestamp(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ const char *sub_filter, ++ const char **attrs, ++ size_t *_msgs_count, ++ struct ldb_message ***_msgs); ++ + int sysdb_delete_user(struct sss_domain_info *domain, + const char *name, uid_t uid); + +@@ -1152,6 +1159,13 @@ int sysdb_search_groups(TALLOC_CTX *mem_ctx, + size_t *msgs_count, + struct ldb_message ***msgs); + ++int sysdb_search_groups_by_timestamp(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ const char *sub_filter, ++ const char **attrs, ++ size_t *_msgs_count, ++ struct ldb_message ***_msgs); ++ + int sysdb_delete_group(struct sss_domain_info *domain, + const char *name, gid_t gid); + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index ed936f0cb1a37155aabef96db1d267eb03ec0ed9..7ca6575ce75dab7805236c9f48dbf28a2f3946d2 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -374,6 +374,58 @@ enum sysdb_obj_type { + SYSDB_GROUP + }; + ++static errno_t cleanup_dn_filter(TALLOC_CTX *mem_ctx, ++ struct ldb_result *ts_res, ++ const char *object_class, ++ const char *filter, ++ char **_dn_filter) ++{ ++ TALLOC_CTX *tmp_ctx; ++ char *dn_filter; ++ errno_t ret; ++ ++ if (ts_res->count == 0) { ++ *_dn_filter = NULL; ++ return EOK; ++ } ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn_filter = talloc_asprintf(tmp_ctx, "(&(%s)%s(|", object_class, filter); ++ if (dn_filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (size_t i = 0; i < ts_res->count; i++) { ++ dn_filter = talloc_asprintf_append( ++ dn_filter, ++ "(%s=%s)", ++ SYSDB_DN, ++ ldb_dn_get_linearized(ts_res->msgs[i]->dn)); ++ if (dn_filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ dn_filter = talloc_asprintf_append(dn_filter, "))"); ++ if (dn_filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ *_dn_filter = talloc_steal(mem_ctx, dn_filter); ++ ret = EOK; ++ ++done: ++ talloc_zfree(tmp_ctx); ++ return ret; ++} ++ + static int sysdb_search_by_name(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *name, +@@ -3503,6 +3555,69 @@ int sysdb_search_users(TALLOC_CTX *mem_ctx, + attrs); + } + ++int sysdb_search_users_by_timestamp(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ const char *sub_filter, ++ const char **attrs, ++ size_t *_msgs_count, ++ struct ldb_message ***_msgs) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_result *res; ++ struct ldb_result ts_res; ++ struct ldb_message **msgs; ++ size_t msgs_count; ++ char *dn_filter = NULL; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sysdb_search_ts_users(tmp_ctx, domain, sub_filter, NULL, &ts_res); ++ if (ret == ERR_NO_TS) { ++ ret = sysdb_cache_search_users(tmp_ctx, domain, domain->sysdb->ldb, ++ sub_filter, attrs, &msgs_count, &msgs); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = sysdb_merge_msg_list_ts_attrs(domain->sysdb, msgs_count, msgs, attrs); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ goto immediately; ++ } else if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = cleanup_dn_filter(tmp_ctx, &ts_res, SYSDB_UC, sub_filter, &dn_filter); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = sysdb_search_ts_matches(tmp_ctx, domain->sysdb, attrs, ++ &ts_res, dn_filter, &res); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ msgs_count = res->count; ++ msgs = res->msgs; ++ ++immediately: ++ *_msgs_count = msgs_count; ++ *_msgs = talloc_steal(mem_ctx, msgs); ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + int sysdb_search_ts_users(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *sub_filter, +@@ -3720,6 +3835,69 @@ int sysdb_search_groups(TALLOC_CTX *mem_ctx, + attrs); + } + ++int sysdb_search_groups_by_timestamp(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ const char *sub_filter, ++ const char **attrs, ++ size_t *_msgs_count, ++ struct ldb_message ***_msgs) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_result *res; ++ struct ldb_result ts_res; ++ struct ldb_message **msgs; ++ size_t msgs_count; ++ char *dn_filter = NULL; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sysdb_search_ts_groups(tmp_ctx, domain, sub_filter, NULL, &ts_res); ++ if (ret == ERR_NO_TS) { ++ ret = sysdb_cache_search_groups(tmp_ctx, domain, domain->sysdb->ldb, ++ sub_filter, attrs, &msgs_count, &msgs); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = sysdb_merge_msg_list_ts_attrs(domain->sysdb, msgs_count, msgs, attrs); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ goto immediately; ++ } else if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = cleanup_dn_filter(tmp_ctx, &ts_res, SYSDB_GC, sub_filter, &dn_filter); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = sysdb_search_ts_matches(tmp_ctx, domain->sysdb, attrs, ++ &ts_res, dn_filter, &res); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ msgs_count = res->count; ++ msgs = res->msgs; ++ ++immediately: ++ *_msgs_count = msgs_count; ++ *_msgs = talloc_steal(mem_ctx, msgs); ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + int sysdb_search_ts_groups(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + const char *sub_filter, +-- +2.9.4 + diff --git a/SOURCES/0181-LDAP_ID_CLEANUP-Use-sysdb_search_-_by_timestamp.patch b/SOURCES/0181-LDAP_ID_CLEANUP-Use-sysdb_search_-_by_timestamp.patch new file mode 100644 index 0000000..7bba059 --- /dev/null +++ b/SOURCES/0181-LDAP_ID_CLEANUP-Use-sysdb_search_-_by_timestamp.patch @@ -0,0 +1,48 @@ +From b96c69f0ab0ecd55b734c167763c3bfe2357c448 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 7 Jun 2017 15:17:15 +0200 +Subject: [PATCH 181/181] LDAP_ID_CLEANUP: Use sysdb_search_*_by_timestamp() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use the appropriate methods for searching users and groups bv timestamp. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3369 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 05e579691b51ac2f81ab0c828ff6fe57bd86a8b6) +--- + src/providers/ldap/ldap_id_cleanup.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c +index cde2ad81873d46edd5e05c4a701ea1742a012bd0..c85ce45918cf938a95ff85c31bfe0541f9ddd052 100644 +--- a/src/providers/ldap/ldap_id_cleanup.c ++++ b/src/providers/ldap/ldap_id_cleanup.c +@@ -219,7 +219,8 @@ static int cleanup_users(struct sdap_options *opts, + goto done; + } + +- ret = sysdb_search_users(tmpctx, dom, subfilter, attrs, &count, &msgs); ++ ret = sysdb_search_users_by_timestamp(tmpctx, dom, subfilter, attrs, ++ &count, &msgs); + if (ret == ENOENT) { + count = 0; + } else if (ret != EOK) { +@@ -394,7 +395,8 @@ static int cleanup_groups(TALLOC_CTX *memctx, + goto done; + } + +- ret = sysdb_search_groups(tmpctx, domain, subfilter, attrs, &count, &msgs); ++ ret = sysdb_search_groups_by_timestamp(tmpctx, domain, subfilter, attrs, ++ &count, &msgs); + if (ret == ENOENT) { + count = 0; + } else if (ret != EOK) { +-- +2.9.4 + diff --git a/SOURCES/0182-krb5-use-plain-principal-if-password-is-expired.patch b/SOURCES/0182-krb5-use-plain-principal-if-password-is-expired.patch new file mode 100644 index 0000000..4802ef1 --- /dev/null +++ b/SOURCES/0182-krb5-use-plain-principal-if-password-is-expired.patch @@ -0,0 +1,66 @@ +From b7aa85ea053aa78fa23de98d6c48e155f0cc06bc Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 12 Jun 2017 14:42:47 +0200 +Subject: [PATCH 182/182] krb5: use plain principal if password is expired +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Similar as in https://pagure.io/SSSD/sssd/issue/3426 enterprise +principals should be avoided while requesting a kadmin/changepw@REALM +principal for a password change. + +Resolves https://pagure.io/SSSD/sssd/issue/3419 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 7e2ec7caa2d1c17e475fff78c5025496b8695509) +--- + src/providers/krb5/krb5_child.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index 3cd8bfba76a35acd2c885ee2aac4765a6c1cc03c..3a76b900444dea50ec0b783496e22d25aad797ab 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -64,6 +64,7 @@ struct cli_opts { + struct krb5_req { + krb5_context ctx; + krb5_principal princ; ++ krb5_principal princ_orig; + char* name; + krb5_creds *creds; + bool otp; +@@ -1975,7 +1976,7 @@ static errno_t tgt_req_child(struct krb5_req *kr) + } + + set_changepw_options(kr->options); +- kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, ++ kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ_orig, + password_or_responder(password), + sss_krb5_prompter, kr, 0, + SSSD_KRB5_CHANGEPW_PRINCIPAL, +@@ -2303,6 +2304,8 @@ static int krb5_cleanup(struct krb5_req *kr) + sss_krb5_free_unparsed_name(kr->ctx, kr->name); + if (kr->princ != NULL) + krb5_free_principal(kr->ctx, kr->princ); ++ if (kr->princ_orig != NULL) ++ krb5_free_principal(kr->ctx, kr->princ_orig); + if (kr->ctx != NULL) + krb5_free_context(kr->ctx); + +@@ -2847,6 +2850,12 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline) + return kerr; + } + ++ kerr = krb5_parse_name(kr->ctx, kr->upn, &kr->princ_orig); ++ if (kerr != 0) { ++ KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); ++ return kerr; ++ } ++ + kerr = krb5_unparse_name(kr->ctx, kr->princ, &kr->name); + if (kerr != 0) { + KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); +-- +2.9.4 + diff --git a/SOURCES/0183-RESPONDER-Use-fqnames-as-output-when-needed.patch b/SOURCES/0183-RESPONDER-Use-fqnames-as-output-when-needed.patch new file mode 100644 index 0000000..1af69a1 --- /dev/null +++ b/SOURCES/0183-RESPONDER-Use-fqnames-as-output-when-needed.patch @@ -0,0 +1,279 @@ +From 48b30d5a62e6af3d1f2b28eac3a2d39efa4349f1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 19 Jun 2017 09:05:00 +0200 +Subject: [PATCH 183/186] RESPONDER: Use fqnames as output when needed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As some regressions have been caused by not handling properly naming +conflicts when using shortnames, last explicitly use fully qualified +names as output in the following situations: +- domain resolution order is set; +- a trusted domain has been using `use_fully_qualified_name = false` + +In both cases we want to ensure that even handling shortnames as input, +the output will always be fully qualified. + +As part of this patch, our tests ended up being modified to reflect the +changes done. In other words, the tests related to shortnames now return +expect as return a fully qualified name for trusted domains. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3403 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 86526891366c4bc3e1ee861143b736d2670a6ba8) +--- + src/confdb/confdb.h | 1 + + src/db/sysdb_subdomains.c | 7 ++ + src/responder/common/cache_req/cache_req_domain.c | 14 +++ + src/responder/common/cache_req/cache_req_domain.h | 8 ++ + src/tests/cmocka/test_nss_srv.c | 104 +++++++++------------- + src/util/usertools.c | 2 +- + 6 files changed, 72 insertions(+), 64 deletions(-) + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 797353141edcccbf3341d161ca598c99492e54fe..32a422155abef428e8a75fc83a5fe14620c7028e 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -291,6 +291,7 @@ struct sss_domain_info { + bool enumerate; + char **sd_enumerate; + bool fqnames; ++ bool output_fqnames; + bool mpg; + bool ignore_group_members; + uint32_t id_min; +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index e2a4f7bb1fcdf20b6b7e04efc7f396d1c3d08f0f..2789cc4949fb7be9ad272d7613ed18a64fa8a20a 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -129,6 +129,13 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, + dom->mpg = mpg; + dom->state = DOM_ACTIVE; + ++ /* use fully qualified names as output in order to avoid causing ++ * conflicts with users who have the same name and either the ++ * shortname user resolution is enabled or the trusted domain has ++ * been explicitly set to use non-fully qualified names as input. ++ */ ++ dom->output_fqnames = true; ++ + /* If the parent domain filters out group members, the subdomain should + * as well if configured */ + inherit_option = string_in_list(CONFDB_DOMAIN_IGNORE_GROUP_MEMBERS, +diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c +index 2c238c9966d322bb542fa2047313ee9e5144edee..b5f7f6c2ffabdbd92ee46b3020cee6ef7fec32d8 100644 +--- a/src/responder/common/cache_req/cache_req_domain.c ++++ b/src/responder/common/cache_req/cache_req_domain.c +@@ -136,6 +136,12 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, + cr_domain->fqnames = + cache_req_domain_use_fqnames(dom, enforce_non_fqnames); + ++ /* when using the domain resolution order, using shortnames as ++ * input is allowed by default. However, we really want to use ++ * the fully qualified name as output in order to avoid ++ * conflicts whith users who have the very same name. */ ++ cr_domain->domain->output_fqnames = true; ++ + DLIST_ADD_END(cr_domains, cr_domain, + struct cache_req_domain *); + break; +@@ -159,6 +165,14 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, + cr_domain->fqnames = + cache_req_domain_use_fqnames(dom, enforce_non_fqnames); + ++ /* when using the domain resolution order, using shortnames as input ++ * is allowed by default. However, we really want to use the fully ++ * qualified name as output in order to avoid conflicts whith users ++ * who have the very same name. */ ++ if (resolution_order != NULL) { ++ cr_domain->domain->output_fqnames = true; ++ } ++ + DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *); + } + +diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h +index 5bcbb9b493caf05bf71aac5cf7633ded91f22e73..3780a5d8d88d76e100738d28d1dd0e697edf5eae 100644 +--- a/src/responder/common/cache_req/cache_req_domain.h ++++ b/src/responder/common/cache_req/cache_req_domain.h +@@ -35,6 +35,14 @@ struct cache_req_domain * + cache_req_domain_get_domain_by_name(struct cache_req_domain *domains, + const char *name); + ++/* ++ * This function may have a side effect of setting the output_fqnames' domain ++ * property when it's called. ++ * ++ * It happens as the output_fqnames' domain property must only be set depending ++ * on whether a domain resolution order is set or not, and the saner place to ++ * set it to all domains is when flattening those (thus, in this function). ++ */ + errno_t + cache_req_domain_new_list_from_domain_resolution_order( + TALLOC_CTX *mem_ctx, +diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c +index 03b5bcc302322551a32f5b8cfe4b7698947abbe7..ccedf96beaecfaa4232bbe456d5e5a8394098483 100644 +--- a/src/tests/cmocka/test_nss_srv.c ++++ b/src/tests/cmocka/test_nss_srv.c +@@ -1648,29 +1648,23 @@ static int test_nss_getgrnam_members_check_subdom(uint32_t status, + tmp_ctx = talloc_new(nss_test_ctx); + assert_non_null(tmp_ctx); + +- 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[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]); ++ 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; +- } ++ 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); + + assert_int_equal(status, EOK); + +@@ -1744,15 +1738,11 @@ static int test_nss_getgrnam_check_mix_dom(uint32_t status, + tmp_ctx = talloc_new(nss_test_ctx); + assert_non_null(tmp_ctx); + +- 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[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] = testmember1.pw_name; + exp_members[2] = testmember2.pw_name; + +@@ -1840,15 +1830,12 @@ static int test_nss_getgrnam_check_mix_dom_fqdn(uint32_t status, + tmp_ctx = talloc_new(nss_test_ctx); + assert_non_null(tmp_ctx); + +- 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[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->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); +@@ -1961,37 +1948,28 @@ static int test_nss_getgrnam_check_mix_subdom(uint32_t status, + tmp_ctx = talloc_new(nss_test_ctx); + assert_non_null(tmp_ctx); + +- 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[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; +- } ++ 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]); + + /* Important: this member is from a non-qualified domain, so his name will + * not be qualified either + */ + exp_members[2] = testmember1.pw_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; +- } ++ 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); + + assert_int_equal(status, EOK); + +diff --git a/src/util/usertools.c b/src/util/usertools.c +index 5dfe6d7765b8032c7447de75e10c6c2a1d4c49ec..83131da1cac25e60a5ec3fffa995a545673e53b9 100644 +--- a/src/util/usertools.c ++++ b/src/util/usertools.c +@@ -867,7 +867,7 @@ int sss_output_fqname(TALLOC_CTX *mem_ctx, + goto done; + } + +- if (domain->fqnames) { ++ if (domain->output_fqnames || domain->fqnames) { + output_name = sss_tc_fqname(tmp_ctx, domain->names, + domain, output_name); + if (output_name == NULL) { +-- +2.9.4 + diff --git a/SOURCES/0184-DOMAIN-Add-sss_domain_info_-get-set-_output_fqnames.patch b/SOURCES/0184-DOMAIN-Add-sss_domain_info_-get-set-_output_fqnames.patch new file mode 100644 index 0000000..e6bd53b --- /dev/null +++ b/SOURCES/0184-DOMAIN-Add-sss_domain_info_-get-set-_output_fqnames.patch @@ -0,0 +1,128 @@ +From 3fc92dcfbd67f82d26d7db46026f1fa1b69e2c70 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 20 Jun 2017 14:22:48 +0200 +Subject: [PATCH 184/186] DOMAIN: Add + sss_domain_info_{get,set}_output_fqnames() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let's avoid setting a domain's property directly from cr_domain code. + +In order to do so, let's introduce a setter, which may help us in the +future whenever we decide to make sss_domain_info an opaque structure. + +For completeness, a getter has also been introduced and used in the +usertools code. + +Related: +https://pagure.io/SSSD/sssd/issue/3403 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Jakub Hrozek +(cherry picked from commit fa2fc8a2908619031292eaf375eb1a510b8b2eba) +--- + src/confdb/confdb.h | 5 ++++- + src/responder/common/cache_req/cache_req_domain.c | 4 ++-- + src/util/domain_info_utils.c | 11 +++++++++++ + src/util/usertools.c | 2 +- + src/util/util.h | 5 +++++ + 5 files changed, 23 insertions(+), 4 deletions(-) + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 32a422155abef428e8a75fc83a5fe14620c7028e..2ba1bc47ee11f699726cefaf7c3335d2a8afee49 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -291,7 +291,6 @@ struct sss_domain_info { + bool enumerate; + char **sd_enumerate; + bool fqnames; +- bool output_fqnames; + bool mpg; + bool ignore_group_members; + uint32_t id_min; +@@ -355,6 +354,10 @@ struct sss_domain_info { + + struct certmap_info **certmaps; + bool user_name_hint; ++ ++ /* Do not use the _output_fqnames property directly in new code, but rather ++ * use sss_domain_info_{get,set}_output_fqnames(). */ ++ bool output_fqnames; + }; + + /** +diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c +index b5f7f6c2ffabdbd92ee46b3020cee6ef7fec32d8..c2b5abb74f3bd3d5055f29a4523f29b05feb2014 100644 +--- a/src/responder/common/cache_req/cache_req_domain.c ++++ b/src/responder/common/cache_req/cache_req_domain.c +@@ -140,7 +140,7 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, + * input is allowed by default. However, we really want to use + * the fully qualified name as output in order to avoid + * conflicts whith users who have the very same name. */ +- cr_domain->domain->output_fqnames = true; ++ sss_domain_info_set_output_fqnames(cr_domain->domain, true); + + DLIST_ADD_END(cr_domains, cr_domain, + struct cache_req_domain *); +@@ -170,7 +170,7 @@ cache_req_domain_new_list_from_string_list(TALLOC_CTX *mem_ctx, + * qualified name as output in order to avoid conflicts whith users + * who have the very same name. */ + if (resolution_order != NULL) { +- cr_domain->domain->output_fqnames = true; ++ sss_domain_info_set_output_fqnames(cr_domain->domain, true); + } + + DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *); +diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c +index 541058a16d585155b3b51511740f7db45281e2fd..45c74f089d0fdeaf6b5b50d7e5058df1716ff777 100644 +--- a/src/util/domain_info_utils.c ++++ b/src/util/domain_info_utils.c +@@ -904,3 +904,14 @@ const char *sss_domain_type_str(struct sss_domain_info *dom) + } + return "Unknown"; + } ++ ++void sss_domain_info_set_output_fqnames(struct sss_domain_info *domain, ++ bool output_fqnames) ++{ ++ domain->output_fqnames = output_fqnames; ++} ++ ++bool sss_domain_info_get_output_fqnames(struct sss_domain_info *domain) ++{ ++ return domain->output_fqnames; ++} +diff --git a/src/util/usertools.c b/src/util/usertools.c +index 83131da1cac25e60a5ec3fffa995a545673e53b9..33f4f7811c843704fff32db3a9ac54b3438f9d37 100644 +--- a/src/util/usertools.c ++++ b/src/util/usertools.c +@@ -867,7 +867,7 @@ int sss_output_fqname(TALLOC_CTX *mem_ctx, + goto done; + } + +- if (domain->output_fqnames || domain->fqnames) { ++ if (sss_domain_info_get_output_fqnames(domain) || domain->fqnames) { + output_name = sss_tc_fqname(tmp_ctx, domain->names, + domain, output_name); + if (output_name == NULL) { +diff --git a/src/util/util.h b/src/util/util.h +index 5ba4c36ca88e325c20a3b1ecc8080a11ca276dcf..72d4116e1206e9cc69715edc45bf5b9b91e37e6b 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -571,6 +571,11 @@ errno_t sssd_domain_init(TALLOC_CTX *mem_ctx, + const char *db_path, + struct sss_domain_info **_domain); + ++void sss_domain_info_set_output_fqnames(struct sss_domain_info *domain, ++ bool output_fqname); ++ ++bool sss_domain_info_get_output_fqnames(struct sss_domain_info *domain); ++ + #define IS_SUBDOMAIN(dom) ((dom)->parent != NULL) + + #define DOM_HAS_VIEWS(dom) ((dom)->has_views) +-- +2.9.4 + diff --git a/SOURCES/0185-GPO-Fix-typo-in-DEBUG-message.patch b/SOURCES/0185-GPO-Fix-typo-in-DEBUG-message.patch new file mode 100644 index 0000000..fa94e3d --- /dev/null +++ b/SOURCES/0185-GPO-Fix-typo-in-DEBUG-message.patch @@ -0,0 +1,27 @@ +From ab8afcc8befcfa436008da41944cf258513631e6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Wed, 7 Jun 2017 14:37:42 +0200 +Subject: [PATCH 185/186] GPO: Fix typo in DEBUG message + +Reviewed-by: Jakub Hrozek +(cherry picked from commit b1d34059533eb50f6e5a4ac7b6fa1bb6fa60a445) +--- + src/providers/ad/ad_gpo.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c +index a8196b4d637eff86a01b342821592bffc214f1ab..2ee284bdc71fcec1c73997f785f7c2c7f387f0b3 100644 +--- a/src/providers/ad/ad_gpo.c ++++ b/src/providers/ad/ad_gpo.c +@@ -2110,7 +2110,7 @@ ad_gpo_process_gpo_done(struct tevent_req *subreq) + &state->num_dacl_filtered_gpos); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +- "Unable to filter GPO list by DACKL: [%d](%s)\n", ++ "Unable to filter GPO list by DACL: [%d](%s)\n", + ret, sss_strerror(ret)); + goto done; + } +-- +2.9.4 + diff --git a/SOURCES/0186-SDAP-Update-parent-sdap_list.patch b/SOURCES/0186-SDAP-Update-parent-sdap_list.patch new file mode 100644 index 0000000..431f35a --- /dev/null +++ b/SOURCES/0186-SDAP-Update-parent-sdap_list.patch @@ -0,0 +1,97 @@ +From 69b69d84ca9fd3453fa83281fc90e34f413a32f9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Wed, 14 Jun 2017 19:02:10 +0200 +Subject: [PATCH 186/186] SDAP: Update parent sdap_list + +Update parent sdap_list with newly created subdomain sdap domain. + +Preiously, we inherited the parent sdap_list and used it also in the +subdomain's context (this was introduced recently with commit +c4ddb9ccab670f9c0d0377680237b62f9f91c496), but it caused problems +that were difficult to debug (we somewhere rewrite part of the list +incorrectly). + +This patch reverses to the previous bahavior, where every subdomain +has it's own sdap_list, however this time the parrent domain's +sdap_list is updated so that it has correct information about +search bases of the child domains. + +We should ideally have just one sdap_list to avoid the updating +completely, but this would require more refactoring in the sdap +code. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3421 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 630aea13063c4b242b3433d16ca4346a1a38429b) +--- + src/providers/ad/ad_subdomains.c | 38 +++++++++++++++++++++++++++++++++++--- + 1 file changed, 35 insertions(+), 3 deletions(-) + +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index c9b79dd9d6840802cddc067eef9d5110cf8d0778..e35041c5ad73cb0fcaaaad96333fc17dd3a17638 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -141,6 +141,35 @@ static bool is_domain_enabled(const char *domain, + } + + static errno_t ++update_parent_sdap_list(struct sdap_domain *parent_list, ++ struct sdap_domain *child_sdap) ++{ ++ struct sdap_domain *sditer; ++ ++ DLIST_FOR_EACH(sditer, parent_list) { ++ if (sditer->dom == child_sdap->dom) { ++ break; ++ } ++ } ++ ++ if (sditer == NULL) { ++ /* Nothing to do */ ++ return EOK; ++ } ++ ++ /* Update the search bases */ ++ sditer->search_bases = child_sdap->search_bases; ++ sditer->user_search_bases = child_sdap->user_search_bases; ++ sditer->group_search_bases = child_sdap->group_search_bases; ++ sditer->netgroup_search_bases = child_sdap->netgroup_search_bases; ++ sditer->sudo_search_bases = child_sdap->sudo_search_bases; ++ sditer->service_search_bases = child_sdap->service_search_bases; ++ sditer->autofs_search_bases = child_sdap->autofs_search_bases; ++ ++ return EOK; ++} ++ ++static errno_t + ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, + struct ad_id_ctx *id_ctx, + struct sss_domain_info *subdom, +@@ -221,9 +250,6 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, + ad_id_ctx->sdap_id_ctx->opts = ad_options->id; + ad_options->id_ctx = ad_id_ctx; + +- /* We need to pass the sdap list from parent */ +- ad_id_ctx->sdap_id_ctx->opts->sdom = id_ctx->sdap_id_ctx->opts->sdom; +- + /* use AD plugin */ + srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res, + default_host_dbs, +@@ -267,6 +293,12 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, + "bases.", subdom->name); + } + ++ ret = update_parent_sdap_list(id_ctx->sdap_id_ctx->opts->sdom, ++ sdom); ++ if (ret != EOK) { ++ return ret; ++ } ++ + *_subdom_id_ctx = ad_id_ctx; + return EOK; + } +-- +2.9.4 + diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec index ae74e0a..533bdf8 100644 --- a/SPECS/sssd.spec +++ b/SPECS/sssd.spec @@ -19,7 +19,7 @@ %global with_krb5_localauth_plugin 1 -%global libwbc_alternatives_version 0.12 +%global libwbc_alternatives_version 0.13 %global libwbc_lib_version %{libwbc_alternatives_version}.0 %global libwbc_alternatives_suffix %nil %if 0%{?__isa_bits} == 64 @@ -31,183 +31,210 @@ %global enable_systemtap_opt --enable-systemtap %endif +%if (0%{?fedora} >= 23 || 0%{?rhel} >= 7) + %global with_kcm 1 + %global with_kcm_option --with-kcm +%else + %global with_kcm_option --without-kcm +%endif + Name: sssd -Version: 1.14.0 -Release: 43%{?dist}.18 +Version: 1.15.2 +Release: 50%{?dist} Group: Applications/System Summary: System Security Services Daemon License: GPLv3+ -URL: http://fedorahosted.org/sssd/ -Source0: https://fedorahosted.org/released/sssd/%{name}-%{version}.tar.gz +URL: https://pagure.io/SSSD/sssd/ +Source0: https://releases.pagure.org/SSSD/sssd/sssd-%{version}.tar.gz BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) ### Patches ### -Patch0001: 0001-SYSDB-Fixing-DB-update.patch -Patch0002: 0002-sssctl-Fix-error-handling-after-memory-allocation-fa.patch -Patch0003: 0003-sssctl-config-check-access-check-report.patch -Patch0004: 0004-FO-Set-port-to-NOT_WORKING-when-trying-a-next-server.patch -Patch0005: 0005-sssctl-Fix-format-string-for-size_t.patch -Patch0006: 0006-doxygen-Fix-path-to-header-file-ipa_hbac.h.patch -Patch0007: 0007-ipa_hbac-Fix-documentation-for-hbac_enable_debug.patch -Patch0008: 0008-sssctl-Fix-warning-maybe-uninitialized.patch -Patch0009: 0009-NOUPSTREAM-Bundle-http-parser.patch -Patch0010: 0010-MAN-Update-description-of-sssctl.patch -Patch0011: 0011-nss-srv-tests-Fix-prototype-of-wrapped-ncache-functi.patch -Patch0012: 0012-TOOLS-Prevent-dereference-of-null-pointer.patch -Patch0013: 0013-config-override_space-is-monitor-s-option.patch -Patch0014: 0014-config-Fix-user_attributes.patch -Patch0015: 0015-sysdb-tests-Fix-cast-from-pointer-to-integer.patch -Patch0016: 0016-PROVIDERS-Setting-right-u-g-id-if-unprivileged.patch -Patch0017: 0017-config-Allow-timeout-for-all-sevices.patch -Patch0018: 0018-config-Add-config_file_version-to-schema.patch -Patch0019: 0019-dyndns-Add-checks-for-NULL.patch -Patch0020: 0020-sdap-Fix-ldap_rfc_2307_fallback_to_local_users.patch -Patch0021: 0021-test_utils-Clean-files-after-sss_write_krb5_conf_sni.patch -Patch0022: 0022-IPA-read-ipaNTAdditionalSuffixes-for-master-and-trus.patch -Patch0023: 0023-sysdb-add-UPN-suffix-support-for-the-master-domain.patch -Patch0024: 0024-sysdb-make-subdomain-calls-aware-of-upn_suffixes.patch -Patch0025: 0025-DP-add-dp_get_module_data.patch -Patch0026: 0026-IPA-add-ipa_init_get_krb5_auth_ctx.patch -Patch0027: 0027-IPA-enable-enterprise-principals-if-server-supports-.patch -Patch0028: 0028-views-allow-override-added-for-non-default-views-at-.patch -Patch0029: 0029-sssctl-move-filter-creation-to-separate-function.patch -Patch0030: 0030-sssctl-improve-readability-of-a-condition.patch -Patch0031: 0031-sssctl-Use-localtime-for-time-stamps.patch -Patch0032: 0032-SECRETS-Log-message-for-failures-with-removing-file.patch -Patch0033: 0033-IPA-fix-capaths-output.patch -Patch0034: 0034-UTIL-make-domain-mapping-content-testable.patch -Patch0035: 0035-tests-add-tests-for-sss_get_domain_mappings_content.patch -Patch0036: 0036-Amend-debug-messages-after-failure-of-unlink.patch -Patch0037: 0037-SYSDB-Do-not-try-to-modify-ts-cache-for-unsupported-.patch -Patch0038: 0038-AD-avoid-memory-leak-in-netlogon_get_domain_info-and.patch -Patch0039: 0039-AD-netlogon_get_domain_info-allow-missing-arguments-.patch -Patch0040: 0040-tests-add-tests-for-netlogon_get_domain_info.patch -Patch0041: 0041-AD-replace-ad_get_client_site_parse_ndr-with-netlogo.patch -Patch0042: 0042-sysdb_master_domain_add_info-properly-set-do_update.patch -Patch0043: 0043-SYSDB-Removing-of-duplication-of-sysdb_ts_cache_attr.patch -Patch0044: 0044-test_utils-Fixing-assignment-discards-const-qualifie.patch -Patch0045: 0045-IPA-make-ipa_resolve_user_list_-send-recv-public-and.patch -Patch0046: 0046-IPA-expand-ghost-members-of-AD-groups-in-server-mode.patch -Patch0047: 0047-sysdb-add-sysdb_get_user_members_recursively.patch -Patch0048: 0048-views-properly-override-group-member-names.patch -Patch0049: 0049-IPA-fix-lookup-by-UPN-for-subdomains.patch -Patch0050: 0050-LDAP-allow-multiple-user-principals.patch -Patch0051: 0051-LDAP-new-attribute-option-ldap_user_email.patch -Patch0052: 0052-sysdb-include-email-in-UPN-searches.patch -Patch0053: 0053-LDAP-include-email-in-UPN-searches.patch -Patch0054: 0054-NSS-add-user-email-to-fill_orig.patch -Patch0055: 0055-utils-add-is_email_from_domain.patch -Patch0056: 0056-LDAP-IPA-add-local-email-address-to-aliases.patch -Patch0057: 0057-NSS-continue-with-UPN-email-search-if-name-was-not-f.patch -Patch0058: 0058-PAM-continue-with-UPN-email-search-if-name-was-not-f.patch -Patch0059: 0059-NSS-use-different-neg-cache-name-for-UPN-searches.patch -Patch0060: 0060-PAM-Fix-domain-for-UPN-based-lookups.patch -Patch0061: 0061-SDAP-add-special-handling-for-IPA-Kerberos-enterpris.patch -Patch0062: 0062-SDAP-add-enterprise-principal-strings-for-user-searc.patch -Patch0063: 0063-LDAP-Fix-storing-initgroups-for-users-with-no-supple.patch -Patch0064: 0064-LDAP-Changing-of-confusing-debug-message.patch -Patch0065: 0065-LDAP-Use-FQDN-when-linking-parent-LDAP-groups.patch -Patch0066: 0066-sssctl-Consistent-commands-naming.patch -Patch0067: 0067-SDAP-sanitize-member-name-before-using-in-filter.patch -Patch0068: 0068-SDAP-sysdb_search_users-does-not-set-users_count-for.patch -Patch0069: 0069-SYSDB-Sanitize-dn-in-sysdb_get_user_members_recursiv.patch -Patch0070: 0070-SYSDB-Fix-setting-dataExpireTimestamp-if-sysdb-is-su.patch -Patch0071: 0071-Revert-LDAP-Lookup-services-by-all-protocols-unless-.patch -Patch0072: 0072-PROVIDER-Conversion-empty-string-from-D-Bus-to-NULL.patch -Patch0073: 0073-LDAP-Fix-Dereference-after-NULL-check.patch -Patch0074: 0074-LDAP-Fixing-wrong-pam-error-code-for-passwd.patch -Patch0075: 0075-PAM-Do-not-act-on-ldb_message-in-case-of-a-failure.patch -Patch0076: 0076-IPA-Check-the-return-value-of-sss_parse_internal_fqn.patch -Patch0077: 0077-DP-Initialize-D-Bus-as-soon-as-possible.patch -Patch0078: 0078-sssctl-Generic-help-for-cache-upgrade-and-config-che.patch -Patch0079: 0079-NSS-Do-not-check-local-users-with-disabled-local_neg.patch -Patch0080: 0080-config_schema-Add-ldap_user_email-to-schema.patch -Patch0081: 0081-NSS-Use-correct-name-for-invalidating-memory-cache.patch -Patch0082: 0082-SYSDB-Avoid-optimisation-with-modifyTimestamp-for-us.patch -Patch0083: 0083-SIMPLE-Do-not-parse-names-on-startup.patch -Patch0084: 0084-SIMPLE-Fail-on-any-error-parsing-the-access-control-.patch -Patch0085: 0085-SIMPLE-Make-the-DP-handlers-testable.patch -Patch0086: 0086-TESTS-Use-the-DP-handlers-in-simple-provider-tests-a.patch -Patch0087: 0087-gpo-gPCMachineExtensionNames-with-just-whitespaces.patch -Patch0088: 0088-sss_ini-Change-debug-level-of-config-error-msgs.patch -Patch0089: 0089-CONFIG-full_name_format-is-an-allowed-option-for-all.patch -Patch0090: 0090-CONFIG-re_expression-is-an-allowed-option-for-all-do.patch -Patch0091: 0091-rdp-add-ability-to-forward-reply-to-the-client-reque.patch -Patch0092: 0092-sbus-add-sbus_request_reply_error.patch -Patch0093: 0093-sbus-add-utility-function-to-simplify-message-and-re.patch -Patch0094: 0094-sssctl-use-talloc-with-sifp.patch -Patch0095: 0095-failover-mark-subdomain-service-with-sd_-prefix.patch -Patch0096: 0096-sssctl-print-active-server-and-server-list.patch -Patch0097: 0097-sifp-fix-coverity-warning.patch -Patch0098: 0098-sbus-allow-freeing-msg-through-dbus-api-when-using-t.patch -Patch0099: 0099-PROXY-Do-not-abuse-data-provider-interface.patch -Patch0100: 0100-DP-Remove-old-data-provider-interface.patch -Patch0101: 0101-NSS-Remove-unused-functions.patch -Patch0102: 0102-LDAP-Fixing-of-removing-netgroup-from-cache.patch -Patch0103: 0103-AD_PROVIDER-Add-ad_enabled_domains-option.patch -Patch0104: 0104-AD_PROVIDER-Initializing-of-ad_enabled_domains.patch -Patch0105: 0105-AD_PROVIDER-ad_enabled_domains-only-master.patch -Patch0106: 0106-AD_PROVIDER-ad_enabled_domains-other-then-master.patch -Patch0107: 0107-TESTS-Adding-tests-for-ad_enabled_domains-option.patch -Patch0109: 0109-UTIL-Use-sss_atomic_read_s-in-generate_csprng_buffer.patch -Patch0110: 0110-SECRETS-Use-sss_atomic_read-write-for-better-readabi.patch -Patch0111: 0111-BUILD-Ship-systemd-service-file-for-sssd-secrets.patch -Patch0112: 0112-DP-Add-log-message-for-get-account-info.patch -Patch0113: 0113-LDAP-Log-autofs-rfc2307-config-changes-only-with-ena.patch -Patch0114: 0114-SSSCTL-More-helpful-error-message-when-InfoPipe-is-d.patch -Patch0115: 0115-sdap-Skip-exact-duplicates-when-extending-maps.patch -Patch0116: 0116-watchdog-cope-with-time-shift.patch -Patch0117: 0117-PROXY-Use-the-fqname-when-converting-to-lowercase.patch -Patch0118: 0118-BUILD-Allow-to-read-private-pipes-for-root.patch -Patch0119: 0119-SYSDB-Rework-sysdb_cache_connect.patch -Patch0120: 0120-SYSDB-Remove-the-timestamp-cache-for-a-newly-created.patch -Patch0121: 0121-SECRETS-Return-ENOENT-when_deleting-a-non-existent-s.patch -Patch0122: 0122-IPA-Parse-qualified-names-when-guessing-AD-user-prin.patch -Patch0123: 0123-SYSDB-Fix-uninitialized-scalar-variable.patch -Patch0124: 0124-PROXY-Use-right-name-in-ldap-filter.patch -Patch0125: 0125-SYSDB-Fix-error-handling-in-sysdb_get_user_members_r.patch -Patch0126: 0126-sdap_initgr_nested_get_membership_diff-use-fully-qua.patch -Patch0127: 0127-Revert-CONFIG-Use-default-config-when-none-provided.patch -Patch0128: 0128-TOOLS-Fix-a-typo-in-groupadd.patch -Patch0129: 0129-TOOLS-sss_groupshow-did-not-work.patch -Patch0130: 0130-TESTS-sss_groupadd-groupshow-regressions.patch -Patch0131: 0131-TOOLS-use-internal-fqdn-for-DN.patch -Patch0132: 0132-TESTS-Test-for-sss_user-groupmod-a.patch -Patch0133: 0133-TOOLS-sss_mc_refresh_nested_group-short-fqname-usage.patch -Patch0134: 0134-TESTS-Add-FQDN-variants-for-some-tests.patch -Patch0135: 0135-KRB5-Send-the-output-username-not-internal-fqname-to.patch -Patch0136: 0136-LDAP-Return-partial-results-from-adminlimit-exceeded.patch -Patch0137: 0137-TOOLS-sss_groupshow-fails-to-show-MPG.patch -Patch0138: 0138-TESTS-sss_groupshow-with-MPG.patch -Patch0139: 0139-TOOLS-sss_override-without-name-override.patch -Patch0140: 0140-TEST-Add-regression-test-for-ticket-3179.patch -Patch0141: 0141-p11-only-set-PKCS11_LOGIN_TOKEN_NAME-if-gdm-smartcar.patch -Patch0142: 0142-p11-return-a-fully-qualified-name.patch -Patch0143: 0143-pam_sss-check-PKCS11_LOGIN_TOKEN_NAME.patch -Patch0144: 0144-sysdb-add-parent_dom-to-sysdb_get_direct_parents.patch -Patch0145: 0145-sdap-make-some-nested-group-related-calls-public.patch -Patch0146: 0146-LDAP-AD-resolve-domain-local-groups-for-remote-users.patch -Patch0147: 0147-IPA-Initialize-a-boolean-control-value.patch -Patch0148: 0148-IPA-AD-check-auth-ctx-before-using-it.patch -Patch0149: 0149-Qualify-ghost-user-attribute-in-case-ldap_group_nest.patch -Patch0150: 0150-SYSDB-Split-sysdb_try_to_find_expected_dn-into-small.patch -Patch0151: 0151-SYSDB-Augment-sysdb_try_to_find_expected_dn-to-match.patch -Patch0152: 0152-SYSDB-Adding-lowercase-sudoUser-form.patch -Patch0153: 0153-SYSDB-Fixing-of-sudorule-without-a-sudoUser.patch -Patch0154: 0154-MONITOR-Do-not-set-up-watchdog-for-monitor.patch -Patch0155: 0155-AUTOFS-Fix-offline-resolution-of-autofs-maps.patch -Patch0156: 0156-Prevent-use-after-free-in-fd_input_available.patch -Patch0157: 0157-SSH-Use-default_domain_suffix-for-users-authorized-k.patch -Patch0158: 0158-SERVER-Set-the-process-group-during-server_setup.patch -Patch0159: 0159-WATCHDOG-define-and-use-_MAX_TICKS-as-3.patch -Patch0160: 0160-WATCHDOG-Avoid-non-async-signal-safe-from-the-signal.patch -Patch0161: 0161-TESTS-Extending-sysdb-sudo-store-tests.patch -Patch0162: 0162-SUDO-Only-store-lowercased-attribute-value-once.patch -Patch0163: 0163-UTIL-Store-UPN-suffixes-when-creating-a-new-subdomai.patch -Patch0164: 0164-Move-sized_output_name-and-sized_domain_name-into-re.patch -Patch0165: 0165-IFP-Use-sized_domain_name-to-format-the-groups-the-u.patch -Patch0166: 0166-LDAP-AD-Do-not-fail-in-case-rfc2307bis_nested_groups.patch -Patch0167: 0167-HBAC-Do-not-rely-on-originalMemberOf-use-the-sysdb-m.patch +Patch0001: 0001-MAN-Mention-sssd-secrets-in-SEE-ALSO-section.patch +Patch0002: 0002-split_on_separator-move-to-a-separate-file.patch +Patch0003: 0003-util-move-string_in_list-to-util_ext.patch +Patch0004: 0004-certmap-add-new-library-libsss_certmap.patch +Patch0005: 0005-certmap-add-placeholder-for-OpenSSL-implementation.patch +Patch0006: 0006-sysdb-add-sysdb_attrs_copy.patch +Patch0007: 0007-sdap_get_users_send-new-argument-mapped_attrs.patch +Patch0008: 0008-LDAP-always-store-the-certificate-from-the-request.patch +Patch0009: 0009-sss_cert_derb64_to_ldap_filter-add-sss_certmap-suppo.patch +Patch0010: 0010-sysdb-add-certmap-related-calls.patch +Patch0011: 0011-IPA-add-certmap-support.patch +Patch0012: 0012-nss-idmap-add-sss_nss_getlistbycert.patch +Patch0013: 0013-nss-allow-larger-buffer-for-certificate-based-reques.patch +Patch0014: 0014-IPA-Add-s2n-request-to-string-function.patch +Patch0015: 0015-IPA-Enhance-debug-logging-for-ipa-s2n-operations.patch +Patch0016: 0016-UTIL-iobuf-Make-input-parameter-for-the-readonly-ope.patch +Patch0017: 0017-UTIL-Fix-a-typo-in-the-tcurl-test-tool.patch +Patch0018: 0018-UTIL-Add-SAFEALIGN_COPY_UINT8_CHECK.patch +Patch0019: 0019-UTIL-Add-utility-macro-cli_creds_get_gid.patch +Patch0020: 0020-UTIL-Add-type-specific-getsetters-to-sss_iobuf.patch +Patch0021: 0021-UTIL-krb5-principal-un-marshalling.patch +Patch0022: 0022-KCM-Initial-responder-build-and-packaging.patch +Patch0023: 0023-KCM-request-parsing-and-sending-a-reply.patch +Patch0024: 0024-KCM-Implement-an-internal-ccache-storage-and-retriev.patch +Patch0025: 0025-KCM-Add-a-in-memory-credential-storage.patch +Patch0026: 0026-KCM-Implement-KCM-server-operations.patch +Patch0027: 0027-MAN-Add-a-manual-page-for-sssd-kcm.patch +Patch0028: 0028-TESTS-Add-integration-tests-for-the-KCM-responder.patch +Patch0029: 0029-SECRETS-Create-DB-path-before-the-operation-itself.patch +Patch0030: 0030-SECRETS-Return-a-nicer-error-message-on-request-with.patch +Patch0031: 0031-SECRETS-Store-ccaches-in-secrets-for-the-KCM-respond.patch +Patch0032: 0032-TCURL-Support-HTTP-POST-for-creating-containers.patch +Patch0033: 0033-KCM-Store-ccaches-in-secrets.patch +Patch0034: 0034-KCM-Make-the-secrets-ccache-back-end-configurable-ma.patch +Patch0035: 0035-KCM-Queue-requests-by-the-same-UID.patch +Patch0036: 0036-KCM-Idle-terminate-the-responder-if-the-secrets-back.patch +Patch0037: 0037-CONFIGURE-Fix-fallback-if-pkg-config-for-uuid-is-mis.patch +Patch0038: 0038-intg-fix-configure-failure-with-strict-cflags.patch +Patch0039: 0039-intg-Remove-bashism-from-intgcheck-prepare.patch +Patch0040: 0040-UTIL-Introduce-subdomain_create_conf_path.patch +Patch0041: 0041-SUBDOMAINS-Allow-use_fully_qualified_names-for-subdo.patch +Patch0042: 0042-CACHE_REQ-Descend-into-subdomains-on-lookups.patch +Patch0043: 0043-NSS-TESTS-Fix-subdomains-attribution.patch +Patch0044: 0044-NSS-TESTS-Improve-setup-teardown-for-subdomains-test.patch +Patch0045: 0045-NSS-TESTS-Include-searches-for-non-fqnames-members-o.patch +Patch0046: 0046-SYSDB-Add-methods-to-deal-with-the-domain-s-resoluti.patch +Patch0047: 0047-SYSDB-TESTS-Add-tests-for-the-domain-s-resolution-or.patch +Patch0048: 0048-IPA-Get-ipaDomainsResolutionOrder-from-ipaConfig.patch +Patch0049: 0049-IPA_SUBDOMAINS-Rename-_refresh_view-to-_refresh_view.patch +Patch0050: 0050-IPA-Get-ipaDomainsResolutionOrder-from-IPA-ID-View.patch +Patch0051: 0051-DLINKLIST-Add-DLIST_FOR_EACH_SAFE-macro.patch +Patch0052: 0052-CACHE_REQ-Make-use-of-domainResolutionOrder.patch +Patch0053: 0053-UTIL-Expose-replace_char-as-sss_replace_char.patch +Patch0054: 0054-Add-domain_resolution_order-config-option.patch +Patch0055: 0055-ssh-handle-binary-keys-correctly.patch +Patch0056: 0056-ssh-add-support-for-certificates-from-non-default-vi.patch +Patch0057: 0057-krb5-return-to-responder-that-pkinit-is-not-availabl.patch +Patch0058: 0058-IPA-add-mapped-attributes-to-user-from-trusted-domai.patch +Patch0059: 0059-IPA-lookup-AD-users-by-certificates-on-IPA-clients.patch +Patch0060: 0060-IPA-enable-AD-user-lookup-by-certificate.patch +Patch0061: 0061-CONFDB-Introduce-SSSD-domain-type-to-distinguish-POS.patch +Patch0062: 0062-CONFDB-Allow-configuring-application-sections-as-non.patch +Patch0063: 0063-CACHE_REQ-Domain-type-selection-in-cache_req.patch +Patch0064: 0064-IFP-Search-both-POSIX-and-non-POSIX-domains.patch +Patch0065: 0065-IFP-ListByName-Don-t-crash-when-no-results-are-found.patch +Patch0066: 0066-PAM-Remove-unneeded-memory-context.patch +Patch0067: 0067-PAM-Add-application-services.patch +Patch0068: 0068-SYSDB-Allow-storing-non-POSIX-users.patch +Patch0069: 0069-SYSDB-Only-generate-new-UID-in-local-domain.patch +Patch0070: 0070-LDAP-save-non-POSIX-users-in-application-domains.patch +Patch0071: 0071-LDAP-Relax-search-filters-in-application-domains.patch +Patch0072: 0072-KRB5-Authenticate-users-in-a-non-POSIX-domain-using-.patch +Patch0073: 0073-KCM-Fix-off-by-one-error-in-secrets-key-parsing.patch +Patch0074: 0074-tcurl-add-support-for-ssl-and-raw-output.patch +Patch0075: 0075-tcurl-test-refactor-so-new-options-can-be-added-more.patch +Patch0076: 0076-tcurl-test-add-support-for-raw-output.patch +Patch0077: 0077-tcurl-test-add-support-for-tls-settings.patch +Patch0078: 0078-tcurl-add-support-for-http-basic-auth.patch +Patch0079: 0079-tcurl-test-allow-to-set-custom-headers.patch +Patch0080: 0080-tcurl-test-add-support-for-client-certificate.patch +Patch0081: 0081-ci-do-not-build-secrets-on-rhel6.patch +Patch0082: 0082-build-make-curl-required-by-secrets.patch +Patch0083: 0083-secrets-use-tcurl-in-proxy-provider.patch +Patch0084: 0084-secrets-remove-http-parser-code-in-proxy-provider.patch +Patch0085: 0085-secrets-allow-to-configure-certificate-check.patch +Patch0086: 0086-secrets-support-HTTP-basic-authentication-with-proxy.patch +Patch0087: 0087-secrets-fix-debug-message.patch +Patch0088: 0088-secrets-always-add-Content-Length-header.patch +Patch0089: 0089-sss_iobuf-fix-read-shadows-a-global-declaration.patch +Patch0090: 0090-configure-fix-typo.patch +Patch0091: 0091-pam_test_client-add-service-and-environment-to-PAM-t.patch +Patch0092: 0092-pam_test_client-add-SSSD-getpwnam-lookup.patch +Patch0093: 0093-sss_sifp-update-method-names.patch +Patch0094: 0094-pam_test_client-add-InfoPipe-user-lookup.patch +Patch0095: 0095-sssctl-integrate-pam_test_client-into-sssctl.patch +Patch0096: 0096-i18n-adding-sssctl-files.patch +Patch0097: 0097-responders-do-not-leak-selinux-context-on-clients-de.patch +Patch0098: 0098-ipa_s2n_get_acct_info_send-provide-correct-req_input.patch +Patch0099: 0099-config-check-Message-when-sssd.conf-is-missing.patch +Patch0100: 0100-sbus-check-connection-for-NULL-before-unregister-it.patch +Patch0101: 0101-selinux-Do-not-fail-if-SELinux-is-not-managed.patch +Patch0102: 0102-UTIL-Use-max-15-characters-for-AD-host-UPN.patch +Patch0103: 0103-Move-sized_output_name-and-sized_domain_name-into-re.patch +Patch0104: 0104-IFP-Use-sized_domain_name-to-format-the-groups-the-u.patch +Patch0105: 0105-RESPONDER-Fallback-to-global-domain-resolution-order.patch +Patch0106: 0106-NSS-TESTS-Improve-non-fqnames-tests.patch +Patch0107: 0107-CACHE_REQ-Allow-configurationless-shortname-lookups.patch +Patch0108: 0108-CACHE_REQ_DOMAIN-Add-some-comments-to-cache_req_doma.patch +Patch0109: 0109-RESPONDER_COMMON-Improve-domaiN_resolution_order-deb.patch +Patch0110: 0110-CACHE_REQ_DOMAIN-debug-the-set-domain-resolution-ord.patch +Patch0111: 0111-SECRETS-remove-unused-variable.patch +Patch0112: 0112-IPA-Improve-DEBUG-message-if-a-group-has-no-ipaNTSec.patch +Patch0113: 0113-IPA-Improve-s2n-debug-message-for-missing-ipaNTSecur.patch +Patch0114: 0114-CONFDB-Fix-standalone-application-domains.patch +Patch0115: 0115-utils-add-sss_domain_is_forest_root.patch +Patch0116: 0116-ad-handle-forest-root-not-listed-in-ad_enabled_domai.patch +Patch0117: 0117-SDAP-Fix-handling-of-search-bases.patch +Patch0118: 0118-overrides-add-certificates-to-mapped-attribute.patch +Patch0119: 0119-AD-Make-ad_account_can_shortcut-reusable-by-SSSD-on-.patch +Patch0120: 0120-LDAP-AD-Do-not-fail-in-case-rfc2307bis_nested_groups.patch +Patch0121: 0121-PAM-check-matching-certificates-from-all-domains.patch +Patch0122: 0122-DP-Reduce-Data-Provider-log-level-noise.patch +Patch0123: 0123-NSS-Move-output-name-formatting-to-utils.patch +Patch0124: 0124-CACHE_REQ-Add-a-new-cache_req_ncache_filter_fn-plugi.patch +Patch0125: 0125-CACHE_REQ_RESULT-Introduce-cache_req_create_ldb_resu.patch +Patch0126: 0126-CACHE_REQ-Make-use-of-cache_req_ncache_filter_fn.patch +Patch0127: 0127-SERVER_MODE-Update-sdap-lists-for-each-ad_ctx.patch +Patch0128: 0128-sss_nss_getlistbycert-return-results-from-multiple-d.patch +Patch0129: 0129-CACHE_REQ-Avoid-using-of-uninitialized-value.patch +Patch0130: 0130-CACHE_REQ-Ensure-the-domains-are-updated-for-filter-.patch +Patch0131: 0131-AD-SUBDOMAINS-Fix-search-bases-for-child-domains.patch +Patch0132: 0132-KRB5-Advise-the-user-to-inspect-the-krb5_child.log-i.patch +Patch0133: 0133-cache_req-use-the-right-negative-cache-for-initgroup.patch +Patch0134: 0134-test-make-sure-p11_child-is-build-for-pam-srv-tests.patch +Patch0135: 0135-pam-properly-support-UPN-logon-names.patch +Patch0136: 0136-KCM-Fix-the-per-client-serialization-queue.patch +Patch0137: 0137-TESTS-Add-a-test-for-parallel-execution-of-klist.patch +Patch0138: 0138-ipa-filter-IPA-users-from-extdom-lookups-by-certific.patch +Patch0139: 0139-krb5-accept-changed-principal-if-krb5_canonicalize-T.patch +Patch0140: 0140-IPA-Avoid-using-uninitialized-ret-value-when-skippin.patch +Patch0141: 0141-IPA-Return-from-function-after-marking-a-request-as-.patch +Patch0142: 0142-HBAC-Do-not-rely-on-originalMemberOf-use-the-sysdb-m.patch +Patch0143: 0143-VALIDATORS-Add-subdomain-section.patch +Patch0144: 0144-VALIDATORS-Remove-application-section-domain.patch +Patch0145: 0145-VALIDATORS-Escape-special-regex-chars.patch +Patch0146: 0146-TESTS-Add-unit-tests-for-cfg-validation.patch +Patch0147: 0147-MAN-Fix-typo-in-trusted-domain-section.patch +Patch0148: 0148-VALIDATORS-Change-regex-for-app-domains.patch +Patch0149: 0149-VALIDATORS-Detect-inherit_from-in-normal-domain.patch +Patch0150: 0150-VALIDATOR-prevent-duplicite-report-from-subdomain-se.patch +Patch0151: 0151-test_config_check-Fix-few-issues.patch +Patch0152: 0152-KRB5-Fix-access_provider-krb5.patch +Patch0153: 0153-BUILD-Improve-error-messages-for-optional-dependenci.patch +Patch0154: 0154-RESPONDER_COMMON-update-certmaps-in-responders.patch +Patch0155: 0155-tests-fix-test_pam_preauth_cert_no_logon_name.patch +Patch0156: 0156-pam_sss-add-support-for-SSS_PAM_CERT_INFO_WITH_HINT.patch +Patch0157: 0157-add_pam_cert_response-add-support-for-SSS_PAM_CERT_I.patch +Patch0158: 0158-PAM-send-user-name-hint-response-when-needed.patch +Patch0159: 0159-sysdb-sysdb_get_certmap-allow-empty-certmap.patch +Patch0160: 0160-sssctl-show-user-name-used-for-authentication-in-use.patch +Patch0161: 0161-RESP-Provide-a-reusable-request-to-fully-resolve-inc.patch +Patch0162: 0162-IFP-Only-format-the-output-name-to-the-short-version.patch +Patch0163: 0163-IFP-Resolve-group-names-from-GIDs-if-required.patch +Patch0164: 0164-ldap-handle-certmap-errors-gracefully.patch +Patch0165: 0165-SECRETS-Fix-warning-Wpointer-bool-conversion.patch +Patch0166: 0166-IPA-Fix-the-PAM-error-code-that-auth-code-expects-to.patch +Patch0167: 0167-pam_sss-Fix-checking-of-empty-string-cert_user.patch +Patch0168: 0168-CACHE_REQ-Simplify-_search_ncache_filter.patch +Patch0169: 0169-CACHE_REQ_SEARCH-Check-for-filtered-users-groups-als.patch +Patch0170: 0170-cache_req-Do-not-use-default_domain_suffix-with-netg.patch +Patch0171: 0171-krb5-disable-enterprise-principals-during-password-c.patch +Patch0172: 0172-pam_sss-Fix-leaking-of-memory-in-case-of-failures.patch +Patch0173: 0173-IFP-Add-domain-and-domainname-attributes-to-the-user.patch +Patch0174: 0174-IFP-Fix-error-handling-in-ifp_user_get_attr_handle_r.patch +Patch0175: 0175-SYSDB-Return-ERR_NO_TS-when-there-s-no-timestamp-cac.patch +Patch0176: 0176-SYSDB-Internally-expose-sysdb_search_ts_matches.patch +Patch0177: 0177-SYSDB-Make-the-usage-of-the-filter-more-generic-for-.patch +Patch0178: 0178-SYSDB_OPS-Mark-an-entry-as-expired-also-in-the-times.patch +Patch0179: 0179-SYSDB_OPS-Invalidate-a-cache-entry-also-in-the-ts_ca.patch +Patch0180: 0180-SYSDB-Introduce-_search_-users-groups-_by_timestamp.patch +Patch0181: 0181-LDAP_ID_CLEANUP-Use-sysdb_search_-_by_timestamp.patch +Patch0182: 0182-krb5-use-plain-principal-if-password-is-expired.patch +Patch0183: 0183-RESPONDER-Use-fqnames-as-output-when-needed.patch +Patch0184: 0184-DOMAIN-Add-sss_domain_info_-get-set-_output_fqnames.patch +Patch0185: 0185-GPO-Fix-typo-in-DEBUG-message.patch +Patch0186: 0186-SDAP-Update-parent-sdap_list.patch #This patch should not be removed in RHEL-7 Patch999: 0999-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-spec @@ -283,6 +310,9 @@ BuildRequires: samba4-devel >= 4.0.0-59beta2 BuildRequires: libsmbclient-devel BuildRequires: systemtap-sdt-devel BuildRequires: jansson-devel +BuildRequires: http-parser-devel +BuildRequires: curl-devel +BuildRequires: libuuid-devel %description Provides a set of daemons to manage access to remote directories and @@ -299,10 +329,9 @@ Summary: Common files for the SSSD Group: Applications/System License: GPLv3+ # Conflicts +Conflicts: selinux-policy < 3.10.0-46 Conflicts: sssd < 1.10.0-8%{?dist}.beta2 - # Requires -Requires: selinux-policy >= 3.13.1-102.el7_3.15 Requires: sssd-client%{?_isa} = %{version}-%{release} Requires: libsss_idmap%{?_isa} = %{version}-%{release} Requires: libsss_sudo%{?_isa} = %{version}-%{release} @@ -310,8 +339,11 @@ Requires: libsss_autofs%{?_isa} = %{version}-%{release} Requires(post): systemd-units chkconfig Requires(preun): systemd-units chkconfig Requires(postun): systemd-units chkconfig -Requires(pre): shadow-utils - +# sssd-common owns sssd.service file and is restarted in posttrans +# libwbclient alternative might break restarting sssd +# gpo_child -> libsmbclient -> samba-client-libs -> libwbclient +OrderWithRequires: libwbclient +OrderWithRequires: sssd-libwbclient ### Provides ### Provides: libsss_sudo-devel = %{version}-%{release} @@ -421,7 +453,6 @@ License: GPLv3+ Conflicts: sssd < 1.10.0-8.beta2 Requires: cyrus-sasl-gssapi%{?_isa} Requires: sssd-common = %{version}-%{release} -Requires(pre): shadow-utils %description krb5-common Provides helper processes that the LDAP and Kerberos back ends can use for @@ -474,9 +505,6 @@ Requires: sssd-common = %{version}-%{release} Requires: sssd-krb5-common = %{version}-%{release} Requires: bind-utils Requires: sssd-common-pac = %{version}-%{release} -# In order for libwbclient to be upgraded before sssd-ad and sets up the -# alternatives symlink -Requires: libwbclient >= 4.2.3-1 %description ad Provides the Active Directory back end that the SSSD can utilize to fetch @@ -578,7 +606,6 @@ be used by Python applications. Summary: The D-Bus responder of the SSSD Group: Applications/System License: GPLv3+ -BuildRequires: augeas-devel Requires: sssd-common = %{version}-%{release} %description dbus @@ -638,7 +665,7 @@ Conflicts: libwbclient-devel < 4.1.12 Development libraries for the SSSD libwbclient implementation. %package winbind-idmap -Summary: SSSSD's idmap_sss Backend for Winbind +Summary: SSSD's idmap_sss Backend for Winbind Group: Applications/System License: GPLv3+ and LGPLv3+ @@ -646,6 +673,37 @@ License: GPLv3+ and LGPLv3+ The idmap_sss module provides a way for Winbind to call SSSD to map UIDs/GIDs and SIDs. +%package -n libsss_certmap +Summary: SSSD Certficate Mapping Library +Group: Development/Libraries +License: LGPLv3+ +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description -n libsss_certmap +Library to map certificates to users based on rules + +%package -n libsss_certmap-devel +Summary: SSSD Certficate Mapping Library +Group: Development/Libraries +License: LGPLv3+ +Requires: libsss_certmap = %{version}-%{release} + +%description -n libsss_certmap-devel +Library to map certificates to users based on rules + +%if (0%{?with_kcm} == 1) +%package kcm +Summary: An implementation of a Kerberos KCM server +Group: Applications/System +License: GPLv3+ +Requires: sssd-common = %{version}-%{release} + +%description kcm +An implementation of a Kerberos KCM server. Use this package if you want to +use the KCM: Kerberos credentials cache. +%endif + %prep # Update timestamps on the files touched by a patch, to avoid non-equal # .pyc/.pyo files across the multilib peers within a build, where "Level" @@ -694,7 +752,8 @@ autoreconf -ivf --without-python3-bindings \ --with-ad-gpo-default=permissive \ %{?enable_polkit_rules_option} \ - %{?enable_systemtap_opt} + %{?enable_systemtap_opt} \ + %{?with_kcm_option} make %{?_smp_mflags} all docs @@ -707,7 +766,7 @@ unset CK_TIMEOUT_MULTIPLIER make install DESTDIR=$RPM_BUILD_ROOT -if [ ! -f %{buildroot}/%{_libdir}/%{name}/modules/libwbclient.so.%{libwbc_lib_version}] +if [ ! -f $RPM_BUILD_ROOT/%{_libdir}/%{name}/modules/libwbclient.so.%{libwbc_lib_version} ] then echo "Expected libwbclient version not found, please check if version has changed." exit -1 @@ -730,11 +789,6 @@ install -m644 src/examples/rwtab $RPM_BUILD_ROOT%{_sysconfdir}/rwtab.d/sssd mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/cifs-utils %endif -# Replace sysv init script with systemd unit file -rm -f $RPM_BUILD_ROOT/%{_initrddir}/%{name} -mkdir -p $RPM_BUILD_ROOT/%{_unitdir}/ -cp src/sysv/systemd/sssd.service $RPM_BUILD_ROOT/%{_unitdir}/ - # Remove .la files created by libtool find $RPM_BUILD_ROOT -name "*.la" -exec rm -f {} \; @@ -748,11 +802,12 @@ do echo %{python_sitelib}/`basename $file` >> python_sssdconfig.lang done -touch sssd_tools.lang -touch sssd_client.lang -for provider in ldap krb5 ipa ad proxy +touch sssd.lang +for subpackage in sssd_ldap sssd_krb5 sssd_ipa sssd_ad sssd_proxy sssd_tools \ + sssd_client sssd_dbus sssd_winbind_idmap \ + libsss_certmap sssd_kcm do - touch sssd_$provider.lang + touch $subpackage.lang done for man in `find $RPM_BUILD_ROOT/%{_mandir}/??/man?/ -type f | sed -e "s#$RPM_BUILD_ROOT/%{_mandir}/##"` @@ -762,9 +817,15 @@ do sss_cache*) echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd.lang ;; + sss_ssh*) + echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd.lang + ;; sss_*) echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_tools.lang ;; + sssctl*) + echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_tools.lang + ;; sssd_krb5_*) echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_client.lang ;; @@ -786,6 +847,18 @@ do sssd-proxy*) echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_proxy.lang ;; + sssd-ifp*) + echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_dbus.lang + ;; + sssd-kcm*) + echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_kcm.lang + ;; + idmap_sss*) + echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_winbind_idmap.lang + ;; + sss-certmap*) + echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> libsss_certmap.lang + ;; *) echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd.lang ;; @@ -796,28 +869,40 @@ done echo "sssd.lang:" cat sssd.lang -echo "sssd_client.lang:" -cat sssd_client.lang - -echo "sssd_tools.lang:" -cat sssd_tools.lang +echo "python_sssdconfig.lang:" +cat python_sssdconfig.lang -for provider in ldap krb5 ipa ad proxy +for subpackage in sssd_ldap sssd_krb5 sssd_ipa sssd_ad sssd_proxy sssd_tools \ + sssd_client sssd_dbus sssd_winbind_idmap \ + libsss_certmap sssd_kcm do - echo "sssd_$provider.lang:" - cat sssd_$provider.lang + echo "$subpackage.lang:" + cat $subpackage.lang done %files %defattr(-,root,root,-) -%doc COPYING +%license COPYING %files common -f sssd.lang %defattr(-,root,root,-) -%doc COPYING +%license COPYING %doc src/examples/sssd-example.conf %{_sbindir}/sssd %{_unitdir}/sssd.service +%{_unitdir}/sssd-autofs.socket +%{_unitdir}/sssd-autofs.service +%{_unitdir}/sssd-nss.socket +%{_unitdir}/sssd-nss.service +%{_unitdir}/sssd-pac.socket +%{_unitdir}/sssd-pac.service +%{_unitdir}/sssd-pam.socket +%{_unitdir}/sssd-pam-priv.socket +%{_unitdir}/sssd-pam.service +%{_unitdir}/sssd-ssh.socket +%{_unitdir}/sssd-ssh.service +%{_unitdir}/sssd-sudo.socket +%{_unitdir}/sssd-sudo.service %{_unitdir}/sssd-secrets.socket %{_unitdir}/sssd-secrets.service @@ -829,9 +914,12 @@ done %{_libexecdir}/%{servicename}/sssd_secrets %{_libexecdir}/%{servicename}/sssd_ssh %{_libexecdir}/%{servicename}/sssd_sudo -%attr(4750,root,sssd) %{_libexecdir}/%{servicename}/p11_child +%{_libexecdir}/%{servicename}/p11_child +%{_libexecdir}/%{servicename}/sssd_check_socket_activated_responders %dir %{_libdir}/%{name} +# The files provider is intentionally packaged in -common +%{_libdir}/%{name}/libsss_files.so %{_libdir}/%{name}/libsss_simple.so #Internal shared libraries @@ -876,6 +964,8 @@ done %dir %{_sysconfdir}/rwtab.d %config(noreplace) %{_sysconfdir}/rwtab.d/sssd %dir %{_datadir}/sssd +%{_sysconfdir}/pam.d/sssd-shadowutils +%{_libdir}/%{name}/conf/sssd.conf %{_datadir}/sssd/cfg_rules.ini %{_datadir}/sssd/sssd.api.conf @@ -883,8 +973,10 @@ done %{_mandir}/man1/sss_ssh_authorizedkeys.1* %{_mandir}/man1/sss_ssh_knownhostsproxy.1* %{_mandir}/man5/sssd.conf.5* +%{_mandir}/man5/sssd-files.5* %{_mandir}/man5/sssd-simple.5* %{_mandir}/man5/sssd-sudo.5* +%{_mandir}/man5/sssd-secrets.5* %{_mandir}/man5/sss_rpcidmapd.5* %{_mandir}/man8/sssd.8* %{_mandir}/man8/sss_cache.8* @@ -905,31 +997,31 @@ done %files ldap -f sssd_ldap.lang %defattr(-,root,root,-) -%doc COPYING +%license COPYING %{_libdir}/%{name}/libsss_ldap.so %{_mandir}/man5/sssd-ldap.5* %files krb5-common %defattr(-,root,root,-) -%doc COPYING +%license COPYING %attr(755,sssd,sssd) %dir %{pubconfpath}/krb5.include.d %attr(4750,root,sssd) %{_libexecdir}/%{servicename}/ldap_child %attr(4750,root,sssd) %{_libexecdir}/%{servicename}/krb5_child %files krb5 -f sssd_krb5.lang %defattr(-,root,root,-) -%doc COPYING +%license COPYING %{_libdir}/%{name}/libsss_krb5.so %{_mandir}/man5/sssd-krb5.5* %files common-pac %defattr(-,root,root,-) -%doc COPYING +%license COPYING %{_libexecdir}/%{servicename}/sssd_pac %files ipa -f sssd_ipa.lang %defattr(-,root,root,-) -%doc COPYING +%license COPYING %attr(700,sssd,sssd) %dir %{keytabdir} %{_libdir}/%{name}/libsss_ipa.so %attr(4750,root,sssd) %{_libexecdir}/%{servicename}/selinux_child @@ -937,26 +1029,26 @@ done %files ad -f sssd_ad.lang %defattr(-,root,root,-) -%doc COPYING +%license COPYING %{_libdir}/%{name}/libsss_ad.so %{_libexecdir}/%{servicename}/gpo_child %{_mandir}/man5/sssd-ad.5* %files proxy %defattr(-,root,root,-) -%doc COPYING +%license COPYING %attr(4750,root,sssd) %{_libexecdir}/%{servicename}/proxy_child %{_libdir}/%{name}/libsss_proxy.so -%files dbus +%files dbus -f sssd_dbus.lang %defattr(-,root,root,-) -%doc COPYING +%license COPYING %{_libexecdir}/%{servicename}/sssd_ifp %{_mandir}/man5/sssd-ifp.5* +%{_unitdir}/sssd-ifp.service # InfoPipe DBus plumbing %{_sysconfdir}/dbus-1/system.d/org.freedesktop.sssd.infopipe.conf %{_datadir}/dbus-1/system-services/org.freedesktop.sssd.infopipe.service -%{_libdir}/%{name}/libsss_config.so %files -n libsss_simpleifp %defattr(-,root,root,-) @@ -972,7 +1064,7 @@ done %files client -f sssd_client.lang %defattr(-,root,root,-) -%doc src/sss_client/COPYING src/sss_client/COPYING.LESSER +%license src/sss_client/COPYING src/sss_client/COPYING.LESSER %{_libdir}/libnss_sss.so.2 %{_libdir}/security/pam_sss.so %{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so @@ -993,18 +1085,18 @@ done %files -n libsss_sudo %defattr(-,root,root,-) -%doc src/sss_client/COPYING +%license src/sss_client/COPYING %{_libdir}/libsss_sudo.so* %files -n libsss_autofs %defattr(-,root,root,-) -%doc src/sss_client/COPYING src/sss_client/COPYING.LESSER +%license src/sss_client/COPYING src/sss_client/COPYING.LESSER %dir %{_libdir}/%{name}/modules %{_libdir}/%{name}/modules/libsss_autofs.so %files tools -f sssd_tools.lang %defattr(-,root,root,-) -%doc COPYING +%license COPYING %{_sbindir}/sss_useradd %{_sbindir}/sss_userdel %{_sbindir}/sss_usermod @@ -1045,7 +1137,7 @@ done %files -n libsss_idmap %defattr(-,root,root,-) -%doc src/sss_client/COPYING src/sss_client/COPYING.LESSER +%license src/sss_client/COPYING src/sss_client/COPYING.LESSER %{_libdir}/libsss_idmap.so.* %files -n libsss_idmap-devel @@ -1057,7 +1149,7 @@ done %files -n libipa_hbac %defattr(-,root,root,-) -%doc src/sss_client/COPYING src/sss_client/COPYING.LESSER +%license src/sss_client/COPYING src/sss_client/COPYING.LESSER %{_libdir}/libipa_hbac.so.* %files -n libipa_hbac-devel @@ -1069,7 +1161,7 @@ done %files -n libsss_nss_idmap %defattr(-,root,root,-) -%doc src/sss_client/COPYING src/sss_client/COPYING.LESSER +%license src/sss_client/COPYING src/sss_client/COPYING.LESSER %{_libdir}/libsss_nss_idmap.so.* %files -n libsss_nss_idmap-devel @@ -1099,11 +1191,24 @@ done %{_libdir}/%{name}/modules/libwbclient.so %{_libdir}/pkgconfig/wbclient_sssd.pc -%files winbind-idmap +%files winbind-idmap -f sssd_winbind_idmap.lang %dir %{_libdir}/samba/idmap %{_libdir}/samba/idmap/sss.so %{_mandir}/man8/idmap_sss.8* +%files -n libsss_certmap -f libsss_certmap.lang +%defattr(-,root,root,-) +%license src/sss_client/COPYING src/sss_client/COPYING.LESSER +%{_libdir}/libsss_certmap.so.* +%{_mandir}/man5/sss-certmap.5* + +%files -n libsss_certmap-devel +%defattr(-,root,root,-) +%doc certmap_doc/html +%{_includedir}/sss_certmap.h +%{_libdir}/libsss_certmap.so +%{_libdir}/pkgconfig/sss_certmap.pc + %pre ipa getent group sssd >/dev/null || groupadd -r sssd getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd @@ -1112,23 +1217,80 @@ getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "Us getent group sssd >/dev/null || groupadd -r sssd getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd +%if (0%{?with_kcm} == 1) +%files kcm -f sssd_kcm.lang +%{_libexecdir}/%{servicename}/sssd_kcm +%dir %{_sysconfdir}/krb5.conf.d +%config(noreplace) %{_sysconfdir}/krb5.conf.d/kcm_default_ccache +%{_unitdir}/sssd-kcm.socket +%{_unitdir}/sssd-kcm.service +%{_mandir}/man8/sssd-kcm.8* +%endif + %pre common getent group sssd >/dev/null || groupadd -r sssd getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd -/bin/systemctl status sssd.service >/dev/null 2>&1 && touch /var/tmp/sssd.upgrade || : +/bin/systemctl is-active --quiet sssd.service && touch /var/tmp/sssd_is_running || : %post common %systemd_post sssd.service +%systemd_post sssd-autofs.socket +%systemd_post sssd-nss.socket +%systemd_post sssd-pac.socket +%systemd_post sssd-pam.socket +%systemd_post sssd-pam-priv.socket %systemd_post sssd-secrets.socket +%systemd_post sssd-ssh.socket +%systemd_post sssd-sudo.socket %preun common %systemd_preun sssd.service +%systemd_preun sssd-autofs.socket +%systemd_preun sssd-nss.socket +%systemd_preun sssd-pac.socket +%systemd_preun sssd-pam.socket +%systemd_preun sssd-pam-priv.socket %systemd_preun sssd-secrets.socket +%systemd_preun sssd-ssh.socket +%systemd_preun sssd-sudo.socket %postun common -%systemd_postun_with_restart sssd.service +%systemd_postun_with_restart sssd-autofs.socket +%systemd_postun_with_restart sssd-autofs.service +%systemd_postun_with_restart sssd-nss.socket +%systemd_postun_with_restart sssd-nss.service +%systemd_postun_with_restart sssd-pac.socket +%systemd_postun_with_restart sssd-pac.service +%systemd_postun_with_restart sssd-pam.socket +%systemd_postun_with_restart sssd-pam-priv.socket +%systemd_postun_with_restart sssd-pam.service %systemd_postun_with_restart sssd-secrets.socket %systemd_postun_with_restart sssd-secrets.service +%systemd_postun_with_restart sssd-ssh.socket +%systemd_postun_with_restart sssd-ssh.service +%systemd_postun_with_restart sssd-sudo.socket +%systemd_postun_with_restart sssd-sudo.service + +%post dbus +%systemd_post sssd-ifp.service + +%preun dbus +%systemd_preun sssd-ifp.service + +%postun dbus +%systemd_postun_with_restart sssd-ifp.service + +%if (0%{?with_kcm} == 1) +%post kcm +%systemd_post sssd-kcm.socket + +%preun kcm +%systemd_preun sssd-kcm.socket + +%postun kcm +%systemd_postun_with_restart sssd-kcm.socket +%systemd_postun_with_restart sssd-kcm.service +%endif %if (0%{?with_cifs_utils_plugin} == 1) %post client @@ -1165,6 +1327,10 @@ fi %postun -n libsss_simpleifp -p /sbin/ldconfig +%post -n libsss_certmap -p /sbin/ldconfig + +%postun -n libsss_certmap -p /sbin/ldconfig + %post libwbclient %{_sbindir}/update-alternatives \ --install %{_libdir}/libwbclient.so.%{libwbc_alternatives_version} \ @@ -1193,85 +1359,296 @@ if [ $1 -eq 0 ]; then fi %posttrans common -/bin/systemctl daemon-reload >/dev/null 2>&1 || : -if [ -f /var/tmp/sssd.upgrade ]; then - /bin/systemctl restart sssd.service >/dev/null 2>&1 || : -else - /bin/systemctl try-restart sssd.service >/dev/null 2>&1 || : -fi -/usr/bin/rm -f /var/tmp/sssd.upgrade || : +%systemd_postun_with_restart sssd.service +# After changing order of sssd-common and *libwbclient, +# older version of sssd will restart sssd.service in postun scriptlet +# It failed due to missing alternative to libwbclient. Start it again. +/bin/systemctl is-active --quiet sssd.service || { + if [ -f /var/tmp/sssd_is_running ]; then + systemctl start sssd.service >/dev/null 2>&1; + rm -f /var/tmp/sssd_is_running; + fi +} %changelog -* Fri May 26 2017 Jakub Hrozek - 1.14.0-43.18 -- Resolves: rhbz#1456013 - sssd intermittently failing to resolve groups +* Wed Jun 21 2017 Jakub Hrozek - 1.15.2-50 +- Resolves: rhbz#1457926 - Wrong search base used when SSSD is directly + connected to AD child domain + +* Wed Jun 21 2017 Jakub Hrozek - 1.15.2-49 +- Resolves: rhbz#1450107 - SSSD doesn't handle conflicts between users + from trusted domains with the same name when + shortname user resolution is enabled + +* Fri Jun 16 2017 Jakub Hrozek - 1.15.2-48 +- Resolves: rhbz#1459846 - krb5: properly handle 'password expired' + information retured by the KDC during + PKINIT/Smartcard authentication + +* Thu Jun 15 2017 Jakub Hrozek - 1.15.2-47 +- Resolves: rhbz#1430415 - ldap_purge_cache_timeout in RHEL7.3 invalidate + most of the entries once the cleanup task kicks in + +* Thu Jun 15 2017 Jakub Hrozek - 1.15.2-46 +- Resolves: rhbz#1455254 - Make domain available as user attribute + +* Thu Jun 8 2017 Jakub Hrozek - 1.15.2-45 +- Resolves: rhbz#1449731 - IPA client cannot change AD Trusted User password + +* Thu Jun 8 2017 Jakub Hrozek - 1.15.2-44 +- Resolves: rhbz#1457927 - getent failed to fetch netgroup information + after changing default_domain_suffix to + ADdomin in /etc/sssd/sssd.conf + +* Mon Jun 5 2017 Jakub Hrozek - 1.15.2-43 +- Resolves: rhbz#1440132 - fiter_users and filter_groups stop working + properly in v 1.15 + +* Mon Jun 5 2017 Jakub Hrozek - 1.15.2-42 +- Resolves: rhbz#1449728 - LDAP to IPA migration doesn't work in master + +* Mon Jun 5 2017 Jakub Hrozek - 1.15.2-41 +- Resolves: rhbz#1445445 - Smart card login fails if same cert mapped to + IdM user and AD user + +* Mon Jun 5 2017 Jakub Hrozek - 1.15.2-40 +- Resolves: rhbz#1449729 - org.freedesktop.sssd.infopipe.GetUserGroups + does not resolve groups into names with AD + +* Thu Jun 1 2017 Jakub Hrozek - 1.15.2-39 +- Resolves: rhbz#1450094 - Properly support IPA's promptusername config + option + +* Thu Jun 1 2017 Jakub Hrozek - 1.15.2-38 +- Resolves: rhbz#1457644 - Segfault in access_provider = krb5 is set in + sssd.conf due to an off-by-one error when + constructing the child send buffer +- Resolves: rhbz#1456531 - Option name typos are not detected with validator + function of sssctl config-check command in domain + sections + +* Fri May 26 2017 Jakub Hrozek - 1.15.2-37 +- Resolves: rhbz#1428906 - sssd intermittently failing to resolve groups for an AD user in IPA-AD trust environment. -* Fri May 12 2017 Jakub Hrozek - 1.14.0-43.17 -- Resolves: rhbz#1450125 - Wrong pam return code for user from subdomain +* Fri May 26 2017 Jakub Hrozek - 1.15.2-36 +- Resolves: rhbz#1389796 - Smartcard authentication with UPN as logon name + might fail +- Fix Coverity issues in patches for rhbz#1445445 + +* Wed May 24 2017 Jakub Hrozek - 1.15.2-35 +- Resolves: rhbz#1445445 - Smart card login fails if same cert mapped to + IdM user and AD user + +* Wed May 24 2017 Jakub Hrozek - 1.15.2-34 +- Resolves: rhbz#1446302 - crash in sssd-kcm due to a race-condition + between two concurrent requests + +* Tue May 23 2017 Jakub Hrozek - 1.15.2-33 +- Resolves: rhbz#1389796 - Smartcard authentication with UPN as logon name might fail + +* Tue May 23 2017 Jakub Hrozek - 1.15.2-32 +- Resolves: rhbz#1306707 - Need better debug message when krb5_child + returns an unhandled error, leading to a + System Error PAM code + +* Mon May 22 2017 Jakub Hrozek - 1.15.2-31 +- Resolves: rhbz#1446535 - Group resolution does not work in subdomain + without ad_server option + +* Wed May 17 2017 Sumit Bose - 1.15.2-30 +- Resolves: rhbz#1449726 - sss_nss_getlistbycert() does not return results from + multiple domains +- Resolves: rhbz#1447098 - sssd unable to search dbus for ipa user by + certificate +- Additional patch for rhbz#1440132 + +* Thu May 11 2017 Jakub Hrozek - 1.15.2-29 +- Reapply patch by Lukas Slebodnik to fix upgrade issues with libwbclient +- Resolves: rhbz#1439457 - SSSD does not start after upgrade from 7.3 to 7.4 +- Resolves: rhbz#1449107 - error: %pre(sssd-common-1.15.2-26.el7.x86_64) + scriptlet failed, exit status 3 + +* Thu May 11 2017 Jakub Hrozek - 1.15.2-28 +- Resolves: rhbz#1440132 - fiter_users and filter_groups stop working + properly in v 1.15 +- Also apply an additional patch for rhbz#1441545 + +* Thu May 4 2017 Jakub Hrozek - 1.15.2-25 +- Resolves: rhbz#1445445 - Smart card login fails if same cert mapped to + IdM user and AD user + +* Wed May 3 2017 Jakub Hrozek - 1.15.2-24 +- Resolves: rhbz#1434992 - Wrong pam return code for user from subdomain with ad_access_filter -* Tue May 2 2017 Jakub Hrozek - 1.14.0-43.16 -- Resolves: rhbz#1446085 - D-Bus interface of sssd is giving inappropriate +* Wed May 3 2017 Lukas Slebodnik - 1.15.2-23 +- Resolves: rhbz#1430494 - expect sss_ssh_authorizedkeys and + sss_ssh_knownhostsproxy manuals to be packaged + into sssd-common package + +* Tue May 2 2017 Jakub Hrozek - 1.15.2-22 +- Resolves: rhbz#1427749 - SSSD in server mode iterates over all domains + for group-by-GID requests, causing unnecessary + searches + +* Tue May 2 2017 Jakub Hrozek - 1.15.2-21 +- Resolves: rhbz#1446139 - Infopipe method ListByCertificate does not + return the users with overrides + +* Tue May 2 2017 Jakub Hrozek - 1.15.2-20 +- Resolves: rhbz#1441545 - With multiple subdomain sections id command + output for user is not displayed for both domains + +* Tue May 2 2017 Jakub Hrozek - 1.15.2-19 +- Resolves: rhbz#1428866 - Using ad_enabled_domains configuration option + in sssd.conf causes nameservice lookups to fail. + +* Tue May 2 2017 Jakub Hrozek - 1.15.2-18 +- Remove an unused variable from the sssd-secrets responder +- Related: rhbz#1398701 - [sssd-secrets] https proxy talks plain http +- Improve two DEBUG messages in the client trust code to aid troubleshooting +- Fix standalone application domains +- Related: rhbz#1425891 - Support delivering non-POSIX users and groups + through the IFP and PAM interfaces + +* Wed Apr 26 2017 Jakub Hrozek - 1.15.2-17 +- Allow completely server-side unqualified name resolution if the domain order is set, + do not require any client-side changes +- Related: rhbz#1330196 - [RFE] Short name input format with SSSD for users from + all domains when domain autodiscovery is used or when + IPA client resolves trusted AD domain users + +* Mon Apr 24 2017 Jakub Hrozek - 1.15.2-16 +- Resolves: rhbz#1402532 - D-Bus interface of sssd is giving inappropriate group information for trusted AD users -* Wed Apr 26 2017 Jakub Hrozek - 1.14.0-43.15 -- Resolves: rhbz#1445821 - sssd does not evaluate AD UPN suffixes which - results in failed user logins - -* Wed Feb 15 2017 Jakub Hrozek - 1.14.0-43.14 -- Resolves: rhbz#1422183 - Fails to accept any sudo rules if there are +* Thu Apr 13 2017 Jakub Hrozek - 1.15.2-15 +- Resolves: rhbz#1431858 - Wrong principal found with ad provider and long + host name + +* Wed Apr 12 2017 Jakub Hrozek - 1.15.2-14 +- Resolves: rhbz#1415167 - pam_acct_mgmt with pam_sss.so fails in + unprivileged container unless + selinux_provider = none is used + +* Wed Apr 12 2017 Jakub Hrozek - 1.15.2-13 +- Resolves: rhbz#1438388 - [abrt] [faf] sssd: unknown function(): + /usr/libexec/sssd/sssd_pam killed by 6 + +* Tue Apr 11 2017 Jakub Hrozek - 1.15.2-12 +- Resolves: rhbz#1432112 - sssctl config-check does not give any error + when default configuration file is not present + +* Tue Apr 11 2017 Jakub Hrozek - 1.15.2-11 +- Resolves: rhbz#1438374 - [abrt] [faf] sssd: vfprintf(): + /usr/libexec/sssd/sssd_be killed by 11 + +* Tue Apr 11 2017 Jakub Hrozek - 1.15.2-10 +- Resolves: rhbz#1427195 - sssd_nss consumes more memory until restarted + or machine swaps + +* Mon Apr 10 2017 Jakub Hrozek - 1.15.2-9 +- Resolves: rhbz#1414023 - Create troubleshooting tool to determine if a + failure is in SSSD or not when using layered + products like RH-SSO/CFME etc + +* Thu Mar 30 2017 Jakub Hrozek - 1.15.2-8 +- Resolves: rhbz#1398701 - [sssd-secrets] https proxy talks plain http + +* Thu Mar 30 2017 Jakub Hrozek - 1.15.2-7 +- Fix off-by-one error in the KCM responder +- Related: rhbz#1396012 - [RFE] KCM ccache daemon in SSSD + +* Thu Mar 30 2017 Jakub Hrozek - 1.15.2-6 +- Resolves: rhbz#1425891 - Support delivering non-POSIX users and groups + through the IFP and PAM interfaces + +* Wed Mar 29 2017 Jakub Hrozek - 1.15.2-5 +- Resolves: rhbz#1434991 - Issue processing ssh keys from certificates in + ssh respoder + +* Wed Mar 29 2017 Jakub Hrozek - 1.15.2-4 +- Resolves: rhbz#1330196 - [RFE] Short name input format with SSSD for + users from all domains when domain autodiscovery + is used or when IPA client resolves trusted AD + domain users +- Also backport some buildtime fixes for the KCM responder +- Related: rhbz#1396012 - [RFE] KCM ccache daemon in SSSD + +* Mon Mar 27 2017 Jakub Hrozek - 1.15.2-3 +- Resolves: rhbz#1396012 - [RFE] KCM ccache daemon in SSSD + +* Thu Mar 23 2017 Jakub Hrozek - 1.15.2-2 +- Resolves: rhbz#1340711 - [RFE] Use one smartcard and certificate for + authentication to distinct logon accounts + +* Wed Mar 15 2017 Jakub Hrozek - 1.15.2-1 +- Update to upstream 1.15.2 +- https://docs.pagure.org/SSSD.sssd/users/relnotes/notes_1_15_2.html +- Resolves: rhbz#1418728 - IPA - sudo does not handle associated conflict + entries +- Resolves: rhbz#1386748 - sssd doesn't update PTR records if A/PTR zones + are configured as non-secure and secure +- Resolves: rhbz#1214491 - [RFE] Make it possible to configure AD subdomain + in the SSSD server mode + +* Thu Mar 9 2017 Fabiano Fidêncio - 1.15.1-2 +- Drop "NOUPSTREAM: Bundle http-parser" patch + Related: rhbz#1393819 - New package: http-parser + +* Sat Mar 4 2017 Jakub Hrozek - 1.15.1-1 +- Update to upstream 1.15.1 +- https://docs.pagure.org/SSSD.sssd/users/relnotes/notes_1_15_1.html +- Resolves: rhbz#1327085 - Don't prompt for password if there is already + one on the stack +- Resolves: rhbz#1378722 - [RFE] Make GETSIDBYNAME and GETORIGBYNAME + request aware of UPNs and aliases +- Resolves: rhbz#1405075 - [RFE] Add PKINIT support to SSSD Kerberos provider +- Resolves: rhbz#1416526 - Need correction in sssd-krb5 man page +- Resolves: rhbz#1418752 - pam_sss crashes in do_pam_conversation if no + conversation function is provided by the + client app +- Resolves: rhbz#1419356 - Fails to accept any sudo rules if there are two user entries in an ldap role with the same - sudo user. - -* Fri Feb 3 2017 Jakub Hrozek - 1.14.0-43.13 -- Resolves: rhbz#1418943 - If a long-running task (e.g. enumeration) blocks the - sssd_be process, sssd_be can deadlock -- Also Require a new-enough version of selinux-policy so that setpgid() by sssd - is allowed - -* Wed Jan 11 2017 Jakub Hrozek - 1.14.0-43.12 -- Resolves: rhbz#1405584 - SSH: default_domain_suffix is not being used - for users' authorized keys - -* Tue Dec 13 2016 Jakub Hrozek - 1.14.0-43.11 -- Resolves: rhbz#1404340 - Use-after free in resolver in case the fd is + sudo user +- Resolves: rhbz#1421622 - SSSD - Users/Groups are cached as mixed-case + resulting in users unable to sign in + +* Wed Feb 1 2017 Jakub Hrozek - 1.15.0-2 +- Fix several packaging issues, notably the p11_child is no longer setuid + and the libwbclient used a wrong version number in the symlink + +* Mon Jan 30 2017 Jakub Hrozek - 1.15.0-1 +- Update to upstream 1.15.0 +- Resolves: rhbz#1393824 - Rebase SSSD to version 1.15 +- Resolves: rhbz#1407960 - wbcLookupSid() fails in pdomain is NULL +- Resolves: rhbz#1406437 - sssctl netgroup-show Cannot allocate memory +- Resolves: rhbz#1400422 - Use-after free in resolver in case the fd is writeable and readable at the same time - -* Fri Nov 25 2016 Jakub Hrozek - 1.14.0-43.10 -- Resolves: rhbz#1398673 - autofs map resolution doesn't work offline - -* Thu Nov 24 2016 Jakub Hrozek - 1.14.0-43.9 -- Resolves: rhbz#1398169 - sssd fails to start after upgrading to RHEL 7.3 - -* Wed Nov 23 2016 Jakub Hrozek - 1.14.0-43.8 -- Resolves: rhbz#1392946 - sudo: ignore case on case insensitive domains - -* Wed Nov 23 2016 Jakub Hrozek - 1.14.0-43.7 -- Resolves: rhbz#1393730 - No supplementary groups are resolved for users +- Resolves: rhbz#1393085 - bz - ldap group names don't resolve after + upgrading sssd to 1.14.0 if ldap_nesting_level is set to 0 +- Resolves: rhbz#1392444 - sssd_be keeps crashing +- Resolves: rhbz#1392441 - sssd fails to start after upgrading to RHEL 7.3 +- Resolves: rhbz#1382602 - autofs map resolution doesn't work offline +- Resolves: rhbz#1380436 - sudo: ignore case on case insensitive domains +- Resolves: rhbz#1378251 - Typo In SSSD-AD Man Page +- Resolves: rhbz#1373427 - Clock skew makes SSSD return System Error +- Resolves: rhbz#1306707 - Need better handling of "Server not found in + Kerberos database" +- Resolves: rhbz#1297462 - Don't include 'enable_only=sssd' in the localauth + plugin config + +* Mon Nov 7 2016 Jakub Hrozek - 1.14.0-46 +- Resolves: rhbz#1382598 - IPA: Uninitialized variable during subdomain check + +* Mon Nov 7 2016 Jakub Hrozek - 1.14.0-45 +- Resolves: rhbz#1378911 - No supplementary groups are resolved for users in nested OUs when domain stanza differs from AD domain -* Fri Nov 18 2016 Jakub Hrozek - 1.14.0-43.6 -- Related: rhbz#1396486 - bz - ldap group names don't resolve after - upgrading sssd to 1.14.0 if ldap_nesting_level - is set to 0 - -* Fri Nov 18 2016 Jakub Hrozek - 1.14.0-43.5 -- Related: rhbz#1396485 - sssd_be keeps crashing - -* Mon Nov 14 2016 Jakub Hrozek - 1.14.0-43.4 -- Revert the fix for ignoring sudoUser case as it breaks processing - of rules that completely lack a sudoUser attribute -- Related: rhbz#1392946 - sudo: ignore case on case insensitive domains - -* Wed Nov 9 2016 Jakub Hrozek - 1.14.0-43.3 -- Resolves: rhbz#1392946 - sudo: ignore case on case insensitive domains - -* Tue Nov 8 2016 Jakub Hrozek - 1.14.0-43.2 -- Resolves: rhbz#1392893 - IPA: Uninitialized variable during subdomain check - -* Mon Nov 7 2016 Jakub Hrozek - 1.14.0-43.1 -- Resolves: rhbz#1392896 - AD provider: SSSD does not retrieve a domain-local +* Mon Nov 7 2016 Jakub Hrozek - 1.14.0-44 +- Resolves: rhbz#1372075 - AD provider: SSSD does not retrieve a domain-local group with the AD provider when following AGGUDLP group structure across domains @@ -2447,7 +2824,7 @@ fi - Related: rhbz#991065 * Wed Jul 31 2013 Jakub Hrozek - 1.10.1-5 -- Resolves: #906427 - Do not use %{_lib} in specfile for the nss and +- Resolves: #906427 - Do not use %%{_lib} in specfile for the nss and pam libraries * Wed Jul 31 2013 Jakub Hrozek - 1.10.1-4