From b833e0904625dcee1a3888509e0b13091931c467 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Mar 30 2021 11:25:29 +0000 Subject: import sssd-2.4.0-8.el8 --- diff --git a/.gitignore b/.gitignore index 5e4ac2c..56d81dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/sssd-2.3.0.tar.gz +SOURCES/sssd-2.4.0.tar.gz diff --git a/.sssd.metadata b/.sssd.metadata index 1dea3e7..54e9039 100644 --- a/.sssd.metadata +++ b/.sssd.metadata @@ -1 +1 @@ -61b8704c33ea80104fa9d94017c704e333c3c552 SOURCES/sssd-2.3.0.tar.gz +abcf616bf894d54623bf2541afdc7018e5d150aa SOURCES/sssd-2.4.0.tar.gz diff --git a/SOURCES/0001-SYSDB-merge_res_sysdb_attrs-fixed-to-avoid-NULL-ptr-.patch b/SOURCES/0001-SYSDB-merge_res_sysdb_attrs-fixed-to-avoid-NULL-ptr-.patch new file mode 100644 index 0000000..bc47f70 --- /dev/null +++ b/SOURCES/0001-SYSDB-merge_res_sysdb_attrs-fixed-to-avoid-NULL-ptr-.patch @@ -0,0 +1,64 @@ +From ff24d1538af88f83d0a3cc2817952cf70e7ca580 Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Sun, 22 Nov 2020 17:44:07 +0100 +Subject: [PATCH] SYSDB: merge_res_sysdb_attrs() fixed to avoid NULL ptr in + msgs[] +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This helps to avoid sssd_be segfaults at be_refresh_get_values_ex() due to NULL +ptrs in results of sysdb_search_with_ts_attr() + +Resolves: https://github.com/SSSD/sssd/issues/5412 + +Reviewed-by: Pavel Březina +--- + src/db/sysdb_search.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c +index e616fd5bc..4ff65c1ae 100644 +--- a/src/db/sysdb_search.c ++++ b/src/db/sysdb_search.c +@@ -221,6 +221,7 @@ static errno_t merge_res_sysdb_attrs(TALLOC_CTX *mem_ctx, + const char *attrs[]) + { + errno_t ret; ++ size_t ts_cache_res_count = 0; + struct ldb_result *ts_cache_res = NULL; + + if (ts_res == NULL || ctx->ldb_ts == NULL) { +@@ -231,7 +232,6 @@ static errno_t merge_res_sysdb_attrs(TALLOC_CTX *mem_ctx, + if (ts_cache_res == NULL) { + return ENOMEM; + } +- ts_cache_res->count = ts_res->count; + ts_cache_res->msgs = talloc_zero_array(ts_cache_res, + struct ldb_message *, + ts_res->count); +@@ -244,15 +244,18 @@ static errno_t merge_res_sysdb_attrs(TALLOC_CTX *mem_ctx, + ret = merge_msg_sysdb_attrs(ts_cache_res->msgs, + ctx, + ts_res->msgs[c], +- &ts_cache_res->msgs[c], attrs); +- if (ret != EOK) { ++ &ts_cache_res->msgs[ts_cache_res_count], ++ attrs); ++ if ((ret != EOK) || (ts_cache_res->msgs[ts_cache_res_count] == NULL)) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Cannot merge sysdb cache values for %s\n", + ldb_dn_get_linearized(ts_res->msgs[c]->dn)); +- /* non-fatal, we just get only the non-timestamp attrs */ ++ /* non-fatal, just skip */ + continue; + } ++ ts_cache_res_count += 1; + } ++ ts_cache_res->count = ts_cache_res_count; + + *_ts_cache_res = ts_cache_res; + return EOK; +-- +2.21.3 + diff --git a/SOURCES/0001-ad_gpo_ndr.c-more-ndr-updates.patch b/SOURCES/0001-ad_gpo_ndr.c-more-ndr-updates.patch deleted file mode 100644 index 52ba2f4..0000000 --- a/SOURCES/0001-ad_gpo_ndr.c-more-ndr-updates.patch +++ /dev/null @@ -1,114 +0,0 @@ -From a7c755672cd277497da3df4714f6d9457b6ac5ae Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 28 May 2020 15:02:43 +0200 -Subject: [PATCH] ad_gpo_ndr.c: more ndr updates -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This patch add another update to the ndr code which was previously -updated by commit c031adde4f532f39845a0efd78693600f1f8b2f4 and -1fdd8fa2fded1985fbfc6aa67394eebcdbb6a2fc. - -As missing update in ndr_pull_security_ace() cased -a failure in ad_gpo_parse_sd(). A unit-test for ad_gpo_parse_sd() was -added to prevent similar issues in future. - -Resolves: https://github.com/SSSD/sssd/issues/5183 - -Reviewed-by: Pavel Březina ---- - src/providers/ad/ad_gpo_ndr.c | 1 + - src/tests/cmocka/test_ad_gpo.c | 57 ++++++++++++++++++++++++++++++++++ - 2 files changed, 58 insertions(+) - -diff --git a/src/providers/ad/ad_gpo_ndr.c b/src/providers/ad/ad_gpo_ndr.c -index acd7b77c8..71d6d40f2 100644 ---- a/src/providers/ad/ad_gpo_ndr.c -+++ b/src/providers/ad/ad_gpo_ndr.c -@@ -317,6 +317,7 @@ ndr_pull_security_ace(struct ndr_pull *ndr, - ndr->offset += pad; - } - if (ndr_flags & NDR_BUFFERS) { -+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->object, r->type)); - NDR_CHECK(ndr_pull_security_ace_object_ctr - (ndr, NDR_BUFFERS, &r->object)); - } -diff --git a/src/tests/cmocka/test_ad_gpo.c b/src/tests/cmocka/test_ad_gpo.c -index 97f70408a..d1f7a6915 100644 ---- a/src/tests/cmocka/test_ad_gpo.c -+++ b/src/tests/cmocka/test_ad_gpo.c -@@ -347,6 +347,60 @@ void test_ad_gpo_ace_includes_host_sid_true(void **state) - group_size, ace_dom_sid, true); - } - -+uint8_t test_sid_data[] = { -+0x01, 0x00, 0x04, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x34, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, -+0xbd, 0x00, 0x0e, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, -+0xda, 0x0e, 0xba, 0x60, 0x0f, 0xa2, 0xf4, 0x55, 0xb5, 0x57, 0x47, 0xf8, 0x00, 0x02, 0x00, 0x00, -+0x00, 0x0a, 0x24, 0x00, 0xff, 0x00, 0x0f, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, -+0x15, 0x00, 0x00, 0x00, 0xda, 0x0e, 0xba, 0x60, 0x0f, 0xa2, 0xf4, 0x55, 0xb5, 0x57, 0x47, 0xf8, -+0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0xbd, 0x00, 0x0e, 0x00, 0x01, 0x05, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0xda, 0x0e, 0xba, 0x60, 0x0f, 0xa2, 0xf4, 0x55, -+0xb5, 0x57, 0x47, 0xf8, 0x07, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x24, 0x00, 0xff, 0x00, 0x0f, 0x00, -+0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0xda, 0x0e, 0xba, 0x60, -+0x0f, 0xa2, 0xf4, 0x55, 0xb5, 0x57, 0x47, 0xf8, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, -+0xbd, 0x00, 0x0e, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, -+0xda, 0x0e, 0xba, 0x60, 0x0f, 0xa2, 0xf4, 0x55, 0xb5, 0x57, 0x47, 0xf8, 0x00, 0x02, 0x00, 0x00, -+0x00, 0x0a, 0x14, 0x00, 0xff, 0x00, 0x0f, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, -+0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0xff, 0x00, 0x0f, 0x00, 0x01, 0x01, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x94, 0x00, 0x02, 0x00, -+0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0b, 0x00, 0x00, 0x00, 0x05, 0x02, 0x28, 0x00, -+0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x8f, 0xfd, 0xac, 0xed, 0xb3, 0xff, 0xd1, 0x11, -+0xb4, 0x1d, 0x00, 0xa0, 0xc9, 0x68, 0xf9, 0x39, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, -+0x0b, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x94, 0x00, 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, -+0x00, 0x00, 0x00, 0x05, 0x09, 0x00, 0x00, 0x00 -+}; -+ -+void test_ad_gpo_parse_sd(void **state) -+{ -+ int ret; -+ struct security_descriptor *sd = NULL; -+ -+ ret = ad_gpo_parse_sd(test_ctx, NULL, 0, &sd); -+ assert_int_equal(ret, EINVAL); -+ -+ ret = ad_gpo_parse_sd(test_ctx, test_sid_data, sizeof(test_sid_data), &sd); -+ assert_int_equal(ret, EOK); -+ assert_non_null(sd); -+ assert_int_equal(sd->revision, 1); -+ assert_int_equal(sd->type, 39940); -+ assert_null(sd->owner_sid); -+ assert_null(sd->group_sid); -+ assert_null(sd->sacl); -+ assert_non_null(sd->dacl); -+ assert_int_equal(sd->dacl->revision, 4); -+ assert_int_equal(sd->dacl->size, 308); -+ assert_int_equal(sd->dacl->num_aces, 10); -+ assert_int_equal(sd->dacl->aces[0].type, 0); -+ assert_int_equal(sd->dacl->aces[0].flags, 0); -+ assert_int_equal(sd->dacl->aces[0].size, 36); -+ assert_int_equal(sd->dacl->aces[0].access_mask, 917693); -+ /* There are more components and ACEs in the security_descriptor struct -+ * which are not checked here. */ -+ -+ talloc_free(sd); -+} -+ - int main(int argc, const char *argv[]) - { - poptContext pc; -@@ -385,6 +439,9 @@ int main(int argc, const char *argv[]) - cmocka_unit_test_setup_teardown(test_ad_gpo_ace_includes_host_sid_true, - ad_gpo_test_setup, - ad_gpo_test_teardown), -+ cmocka_unit_test_setup_teardown(test_ad_gpo_parse_sd, -+ ad_gpo_test_setup, -+ ad_gpo_test_teardown), - }; - - /* Set debug level to invalid value so we can decide if -d 0 was used. */ --- -2.21.1 - diff --git a/SOURCES/0002-KCM-perf-improvements.patch b/SOURCES/0002-KCM-perf-improvements.patch new file mode 100644 index 0000000..3734ebe --- /dev/null +++ b/SOURCES/0002-KCM-perf-improvements.patch @@ -0,0 +1,3226 @@ +From 19c0cfe38670cc56219f0d9acdc2b3363e92616c Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Fri, 4 Dec 2020 12:09:57 +0100 +Subject: [PATCH] Squashed commit of the following: +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 325de5a5bb97ba026be6d22492bea8ab2605f1b5 +Author: Pavel Březina +Date: Thu Nov 26 12:07:06 2020 +0100 + + secrets: remove base64 enctype + + This was added as part of KCM performance improvements but never used. + Ldb is fully capable of holding binary data without the need for base64 + encoding so this is not needed. + + Reviewed-by: Alexey Tikhonov + +commit 39277cdadd317b0ab86cdd37de0616bc3eecbe6a +Author: Pavel Březina +Date: Thu Nov 26 11:55:39 2020 +0100 + + secrets: move attrs names to macros + + Reviewed-by: Alexey Tikhonov + +commit 9c1b51d057390fb5b26151f814a480911cda4cc9 +Author: Pavel Březina +Date: Thu Nov 26 11:47:24 2020 +0100 + + secrets: default to "plaintext" if "enctype" attr is missing + + This is a sane fallback behavior, however it should not happen since + the attribute should be always present. + + Reviewed-by: Alexey Tikhonov + +commit bf127d4f3f42e5b2afe25e512211439bc12a9904 +Author: Pavel Březina +Date: Tue Nov 3 13:35:33 2020 +0100 + + secrets: fix may_payload_size exceeded debug message + + The unit is bytes (B) not bits (b) and the conversion of the input + payload size to KiB was wrong (multiplying bytes * 1024). + + Reviewed-by: Alexey Tikhonov + +commit c3b314db57c34f64aaca7d74e76a9a955288bb51 +Author: Pavel Březina +Date: Mon Oct 19 12:40:07 2020 +0200 + + kcm: store credentials list in hash table to avoid cache lookups + + Iteration over ccache requires CRED_UUID_LIST and then calling + CRED_BY_UUID for each uuid in the obtained list. Each CRED_BY_UUID + operation invoked ldb_search and decryption. This was a substantional + bottle neck. + + Resolves: https://github.com/SSSD/sssd/issues/5349 + + :fixes: KCM performance has improved dramatically for cases where + large amount of credentials are stored in the ccache. + + Reviewed-by: Alexey Tikhonov + +commit a370553c90c2ed6df3b94c169c4960a6f978031f +Author: Pavel Březina +Date: Thu Oct 29 14:57:53 2020 +0100 + + sss_ptr_hash: fix double free for circular dependencies + + If the hash table delete callback deletes the stored item, + we can end up in double free in case when we try to override + an existing item (hash_enter(key) where key already exists). + + ```c + static void delete_cb(hash_entry_t *item, + hash_destroy_enum deltype, + void *pvt) + { + talloc_free(item->value.ptr); + } + + hash_enter(key); + hash_enter(key); + ``` + + The doble free it self is fine, since it is done via talloc destructor + and talloc can cope with that. However, the hash table fails to store + the new entry because hash_delete is called twice. + + ``` + _sss_ptr_hash_add -> hash_enter -> hash_delete(old) -> delete_cb -> sss_ptr_hash_value_destructor -> hash_delete + ``` + + Reviewed-by: Alexey Tikhonov + +commit 241ee30da12f564803793ee2b14c1522aabd9235 +Author: Pavel Březina +Date: Fri Oct 16 15:36:51 2020 +0200 + + kcm: add per-connection data to be shared between requests + + Resolves: https://github.com/SSSD/sssd/issues/5349 + + Reviewed-by: Alexey Tikhonov + +commit 194447d35c11eb914f54719491dc5cfaab01b9a1 +Author: Pavel Březina +Date: Tue Oct 27 16:21:31 2020 +0100 + + kcm: use binary format to store ccache instead of json + + JSON is computationally complex and the parser is a bottleneck which + consumes about 10% of time. It also create the ccache unnecessary + large because it requires lots of unneded character and base64 + encoding. + + Binary format is fast, simple and small. + + This is backwards compatible and there is no need to destroy existing + ccache. It will be stored in binary format at first write to the cache. + + Resolves: https://github.com/SSSD/sssd/issues/5349 + + Reviewed-by: Alexey Tikhonov + +commit f17740d831e16449495fff4ec57cc4800aaac83d +Author: Pavel Březina +Date: Tue Oct 27 17:09:43 2020 +0100 + + kcm: add spaces around operators in kcmsrv_ccache_key.c + + Reviewed-by: Alexey Tikhonov + +commit 15069a647ed6c7f1ead42baa1d421d953c9bc557 +Author: Pavel Březina +Date: Tue Oct 27 16:37:05 2020 +0100 + + kcm: avoid suppression of cppcheck warning + + Reviewed-by: Alexey Tikhonov + +commit e63a15038ac9c186626e4fdf681a6492031d1e40 +Author: Pavel Březina +Date: Tue Oct 27 16:18:11 2020 +0100 + + kcm: move sec key parser to separate file so it can be shared + + Reviewed-by: Alexey Tikhonov + +commit 9b1631defdcaa3ea7e87889eb136e7fa935ab4ce +Author: Pavel Březina +Date: Thu Oct 22 13:34:52 2020 +0200 + + kcm: add json suffix to existing searialization functions + + Reviewed-by: Alexey Tikhonov + +commit b6cc661b9f4162e590137430e945aa321fc13121 +Author: Pavel Březina +Date: Fri Oct 23 13:10:13 2020 +0200 + + iobuf: add more iobuf functions + + These will be used in later patches. + + Reviewed-by: Alexey Tikhonov + +commit ed08ba0023e63024bf1c52ae3f6596b9d804d0a5 +Author: Pavel Březina +Date: Thu Oct 22 12:18:38 2020 +0200 + + secrets: accept binary data instead of string + + Currently, both KCM and secrets responders store JSON formatted string + in the secrets database. One of the next commits makes KCM to store + binary format instead of JSON string to improve performance. We need + to be able to distinguish the formats to keep KCM update compatible + with existing ccache and also to keep secrets responder working. + + Secrets responder test had to be ammended to fit into a new maximum + payload which is now reduced by one byte for the secrets responder + to hold the ending zero of a secret string. + + This is a corner case in a long deprecated responder that is not even + built by default and has no known consumers so it is fine to fast fix + the test. + + Reviewed-by: Alexey Tikhonov + +commit 908c15af9a9f8f0556a588e368e4a0b2e24ace1b +Author: Pavel Březina +Date: Thu Oct 22 11:18:12 2020 +0200 + + secrets: allow to specify secret's data format + + Currently, both KCM and secrets responders store JSON formatted string + in the secrets database. One of the next commits makes KCM to store + binary format instead of JSON string to improve performance. We need + to be able to distinguish the formats to keep KCM update compatible + with existing ccache and also to keep secrets responder working. + + Reviewed-by: Alexey Tikhonov + +commit 74fdaa64b27e88a6e0f153f8cb59989c572d4294 +Author: Pavel Březina +Date: Tue Oct 27 16:45:22 2020 +0100 + + kcm: avoid multiple debug messages if sss_sec_put fails + + sec_put() already logs a message if the underlaying function fails + so this debug message is really unnecessary. + + Reviewed-by: Alexey Tikhonov + +commit b8f28d9aa9d862cf504691c9c3f92941a63fb0a4 +Author: Pavel Březina +Date: Mon Oct 19 12:59:48 2020 +0200 + + kcm: disable encryption + + Encryption was a huge bottleneck for the secdb backend. This is + backwards compatible and there is no need to destroy existing + ccache. It will be stored unencrypted at first write to the cache. + + Note that the encryption did not provide any security as the cache + is accessible only by root and the master key is stored together + with the cache. So once someone gains access to the file it can + be easily decrypted. Additionaly, there was also no encryption at + the memory level. + + Resolves: https://github.com/SSSD/sssd/issues/5349 + + Reviewed-by: Alexey Tikhonov + +commit 8edcea8c377e85d037e83065c1904fa4b92c4a39 +Author: Pavel Březina +Date: Fri Oct 16 15:33:42 2020 +0200 + + kcm: avoid name confusion in GET_CRED_UUID_LIST handlers + + The function name did not follow best practices and it got easily confused + with `kcm_op_get_cred_by_uuid_getbyname_done`. + + ``` + kcm_op_get_cred_uuid_getbyname_done + kcm_op_get_cred_by_uuid_getbyname_done + ``` + + Reviewed-by: Alexey Tikhonov + +commit 47a316c850107f12d406f27abb216e26383dfab7 +Author: Pavel Březina +Date: Mon Sep 14 12:44:57 2020 +0200 + + kcm: fix typos in debug messages + + Reviewed-by: Alexey Tikhonov +--- + Makefile.am | 14 +- + src/responder/kcm/kcmsrv_ccache.c | 66 ++++ + src/responder/kcm/kcmsrv_ccache.h | 47 ++- + src/responder/kcm/kcmsrv_ccache_binary.c | 308 ++++++++++++++++++ + src/responder/kcm/kcmsrv_ccache_json.c | 149 +-------- + src/responder/kcm/kcmsrv_ccache_key.c | 144 ++++++++ + src/responder/kcm/kcmsrv_ccache_mem.c | 30 +- + src/responder/kcm/kcmsrv_ccache_secdb.c | 128 +++----- + src/responder/kcm/kcmsrv_ccache_secrets.c | 9 +- + src/responder/kcm/kcmsrv_cmd.c | 23 +- + src/responder/kcm/kcmsrv_ops.c | 252 ++++++++++---- + src/responder/kcm/kcmsrv_ops.h | 8 + + src/responder/secrets/local.c | 5 +- + src/shared/safealign.h | 4 + + ...n_marshalling.c => test_kcm_marshalling.c} | 147 +++++++-- + src/tests/cmocka/test_sss_ptr_hash.c | 39 +++ + src/tests/cmocka/test_utils.c | 3 + + src/tests/cmocka/test_utils.h | 1 + + src/tests/intg/test_secrets.py | 3 +- + src/tests/multihost/basic/test_kcm.py | 12 +- + src/util/secrets/sec_pvt.h | 2 +- + src/util/secrets/secrets.c | 290 ++++++++++++----- + src/util/secrets/secrets.h | 20 +- + src/util/sss_iobuf.c | 141 ++++++++ + src/util/sss_iobuf.h | 46 +++ + src/util/sss_ptr_hash.c | 20 ++ + 26 files changed, 1457 insertions(+), 454 deletions(-) + create mode 100644 src/responder/kcm/kcmsrv_ccache_binary.c + create mode 100644 src/responder/kcm/kcmsrv_ccache_key.c + rename src/tests/cmocka/{test_kcm_json_marshalling.c => test_kcm_marshalling.c} (71%) + +diff --git a/Makefile.am b/Makefile.am +index 97aa1ec66..430b4e842 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -311,7 +311,7 @@ endif # HAVE_INOTIFY + + if BUILD_KCM + non_interactive_cmocka_based_tests += \ +- test_kcm_json \ ++ test_kcm_marshalling \ + test_kcm_queue \ + $(NULL) + endif # BUILD_KCM +@@ -1817,8 +1817,10 @@ 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_binary.c \ + src/responder/kcm/kcmsrv_ccache_mem.c \ + src/responder/kcm/kcmsrv_ccache_json.c \ ++ src/responder/kcm/kcmsrv_ccache_key.c \ + src/responder/kcm/kcmsrv_ccache_secdb.c \ + src/responder/kcm/kcmsrv_ops.c \ + src/responder/kcm/kcmsrv_op_queue.c \ +@@ -3927,18 +3929,20 @@ test_sssd_krb5_locator_plugin_LDADD = \ + $(NULL) + + if BUILD_KCM +-test_kcm_json_SOURCES = \ +- src/tests/cmocka/test_kcm_json_marshalling.c \ ++test_kcm_marshalling_SOURCES = \ ++ src/tests/cmocka/test_kcm_marshalling.c \ ++ src/responder/kcm/kcmsrv_ccache_binary.c \ + src/responder/kcm/kcmsrv_ccache_json.c \ ++ src/responder/kcm/kcmsrv_ccache_key.c \ + src/responder/kcm/kcmsrv_ccache.c \ + src/util/sss_krb5.c \ + src/util/sss_iobuf.c \ + $(NULL) +-test_kcm_json_CFLAGS = \ ++test_kcm_marshalling_CFLAGS = \ + $(AM_CFLAGS) \ + $(UUID_CFLAGS) \ + $(NULL) +-test_kcm_json_LDADD = \ ++test_kcm_marshalling_LDADD = \ + $(JANSSON_LIBS) \ + $(UUID_LIBS) \ + $(KRB5_LIBS) \ +diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c +index 66e2752ba..60eacd451 100644 +--- a/src/responder/kcm/kcmsrv_ccache.c ++++ b/src/responder/kcm/kcmsrv_ccache.c +@@ -28,6 +28,9 @@ + #include "responder/kcm/kcmsrv_ccache_pvt.h" + #include "responder/kcm/kcmsrv_ccache_be.h" + ++static struct kcm_cred *kcm_cred_dup(TALLOC_CTX *mem_ctx, ++ struct kcm_cred *crd); ++ + static int kcm_cc_destructor(struct kcm_ccache *cc) + { + if (cc == NULL) { +@@ -94,6 +97,33 @@ done: + return ret; + } + ++struct kcm_ccache *kcm_cc_dup(TALLOC_CTX *mem_ctx, ++ const struct kcm_ccache *cc) ++{ ++ struct kcm_ccache *dup; ++ struct kcm_cred *crd_dup; ++ struct kcm_cred *crd; ++ ++ dup = talloc_zero(mem_ctx, struct kcm_ccache); ++ if (dup == NULL) { ++ return NULL; ++ } ++ memcpy(dup, cc, sizeof(struct kcm_ccache)); ++ ++ dup->creds = NULL; ++ DLIST_FOR_EACH(crd, cc->creds) { ++ crd_dup = kcm_cred_dup(dup, crd); ++ if (crd_dup == NULL) { ++ talloc_free(dup); ++ return NULL; ++ } ++ ++ DLIST_ADD(dup->creds, crd_dup); ++ } ++ ++ return dup; ++} ++ + const char *kcm_cc_get_name(struct kcm_ccache *cc) + { + return cc ? cc->name : NULL; +@@ -204,6 +234,22 @@ struct kcm_cred *kcm_cred_new(TALLOC_CTX *mem_ctx, + return kcreds; + } + ++static struct kcm_cred *kcm_cred_dup(TALLOC_CTX *mem_ctx, ++ struct kcm_cred *crd) ++{ ++ struct kcm_cred *dup; ++ ++ dup = talloc_zero(mem_ctx, struct kcm_cred); ++ if (dup == NULL) { ++ return NULL; ++ } ++ ++ uuid_copy(dup->uuid, crd->uuid); ++ dup->cred_blob = crd->cred_blob; ++ ++ return dup; ++} ++ + /* Add a cred to ccache */ + errno_t kcm_cc_store_creds(struct kcm_ccache *cc, + struct kcm_cred *crd) +@@ -213,6 +259,26 @@ errno_t kcm_cc_store_creds(struct kcm_ccache *cc, + return EOK; + } + ++errno_t kcm_cc_set_header(struct kcm_ccache *cc, ++ const char *sec_key, ++ struct cli_creds *client) ++{ ++ errno_t ret; ++ ++ ret = sec_key_parse(cc, sec_key, &cc->name, cc->uuid); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ /* 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); ++ ++ return EOK; ++} ++ + errno_t kcm_cred_get_uuid(struct kcm_cred *crd, uuid_t _uuid) + { + if (crd == NULL) { +diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h +index d629923fa..77cf8f61d 100644 +--- a/src/responder/kcm/kcmsrv_ccache.h ++++ b/src/responder/kcm/kcmsrv_ccache.h +@@ -72,6 +72,13 @@ errno_t kcm_cc_new(TALLOC_CTX *mem_ctx, + krb5_principal princ, + struct kcm_ccache **_cc); + ++/* ++ * Duplicate the ccache. Only ccache and credentials are duplicated, ++ * but their data are a shallow copy. ++ */ ++struct kcm_ccache *kcm_cc_dup(TALLOC_CTX *mem_ctx, ++ const struct kcm_ccache *cc); ++ + /* + * Returns true if a client can access a ccache. + * +@@ -100,6 +107,11 @@ struct kcm_cred *kcm_cred_new(TALLOC_CTX *mem_ctx, + errno_t kcm_cc_store_creds(struct kcm_ccache *cc, + struct kcm_cred *crd); + ++/* Set cc header information from sec key and client */ ++errno_t kcm_cc_set_header(struct kcm_ccache *cc, ++ const char *sec_key, ++ struct cli_creds *client); ++ + errno_t kcm_cred_get_uuid(struct kcm_cred *crd, uuid_t uuid); + + /* +@@ -320,6 +332,11 @@ bool sec_key_match_name(const char *sec_key, + bool sec_key_match_uuid(const char *sec_key, + uuid_t uuid); + ++errno_t sec_key_parse(TALLOC_CTX *mem_ctx, ++ const char *sec_key, ++ const char **_name, ++ uuid_t uuid); ++ + const char *sec_key_get_name(const char *sec_key); + + errno_t sec_key_get_uuid(const char *sec_key, +@@ -333,16 +350,30 @@ const char *sec_key_create(TALLOC_CTX *mem_ctx, + * 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 sec_kv_to_ccache_json(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, ++errno_t kcm_ccache_to_sec_input_json(TALLOC_CTX *mem_ctx, ++ struct kcm_ccache *cc, ++ struct sss_iobuf **_payload); ++ ++/* ++ * sec_key is a concatenation of the ccache's UUID and name ++ * sec_value is the binary representation of ccache. ++ */ ++errno_t sec_kv_to_ccache_binary(TALLOC_CTX *mem_ctx, ++ const char *sec_key, ++ struct sss_iobuf *sec_value, + struct cli_creds *client, +- struct sss_iobuf **_payload); ++ struct kcm_ccache **_cc); ++ ++/* Convert a kcm_ccache to its binary representation. */ ++errno_t kcm_ccache_to_sec_input_binary(TALLOC_CTX *mem_ctx, ++ struct kcm_ccache *cc, ++ struct sss_iobuf **_payload); + + #endif /* _KCMSRV_CCACHE_H_ */ +diff --git a/src/responder/kcm/kcmsrv_ccache_binary.c b/src/responder/kcm/kcmsrv_ccache_binary.c +new file mode 100644 +index 000000000..7bfdbf13b +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_ccache_binary.c +@@ -0,0 +1,308 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2020 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 "config.h" ++ ++#include ++#include ++ ++#include "util/util.h" ++#include "util/util_creds.h" ++#include "util/crypto/sss_crypto.h" ++#include "responder/kcm/kcmsrv_ccache_pvt.h" ++ ++static errno_t krb_data_to_bin(krb5_data *data, struct sss_iobuf *buf) ++{ ++ return sss_iobuf_write_varlen(buf, (uint8_t *)data->data, data->length); ++} ++ ++static errno_t princ_to_bin(krb5_principal princ, struct sss_iobuf *buf) ++{ ++ errno_t ret; ++ ++ if (princ == NULL) { ++ return sss_iobuf_write_uint8(buf, 0); ++ } ++ ++ /* Mark that principal is not empty. */ ++ ret = sss_iobuf_write_uint8(buf, 1); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = krb_data_to_bin(&princ->realm, buf); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = sss_iobuf_write_int32(buf, princ->type); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = sss_iobuf_write_int32(buf, princ->length); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ for (krb5_int32 i = 0; i < princ->length; i++) { ++ ret = krb_data_to_bin(&princ->data[i], buf); ++ if (ret != EOK) { ++ return ret; ++ } ++ } ++ ++ return EOK; ++} ++ ++static errno_t creds_to_bin(struct kcm_cred *creds, struct sss_iobuf *buf) ++{ ++ struct kcm_cred *crd; ++ uint32_t count = 0; ++ errno_t ret; ++ ++ DLIST_FOR_EACH(crd, creds) { ++ count++; ++ } ++ ++ ret = sss_iobuf_write_uint32(buf, count); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ DLIST_FOR_EACH(crd, creds) { ++ ret = sss_iobuf_write_len(buf, (uint8_t *)crd->uuid, sizeof(uuid_t)); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = sss_iobuf_write_iobuf(buf, crd->cred_blob); ++ if (ret != EOK) { ++ return ret; ++ } ++ } ++ ++ return EOK; ++} ++ ++errno_t kcm_ccache_to_sec_input_binary(TALLOC_CTX *mem_ctx, ++ struct kcm_ccache *cc, ++ struct sss_iobuf **_payload) ++{ ++ struct sss_iobuf *buf; ++ errno_t ret; ++ ++ buf = sss_iobuf_init_empty(mem_ctx, sizeof(krb5_principal_data), 0); ++ if (buf == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sss_iobuf_write_int32(buf, cc->kdc_offset); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = princ_to_bin(cc->client, buf); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = creds_to_bin(cc->creds, buf); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ *_payload = buf; ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(buf); ++ } ++ ++ return ret; ++} ++ ++static errno_t bin_to_krb_data(TALLOC_CTX *mem_ctx, ++ struct sss_iobuf *buf, ++ krb5_data *out) ++{ ++ uint8_t *data; ++ size_t len; ++ errno_t ret; ++ ++ ret = sss_iobuf_read_varlen(mem_ctx, buf, &data, &len); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ out->magic = 0; ++ out->data = (char*)data; ++ out->length = len; ++ ++ return EOK; ++} ++ ++static errno_t bin_to_princ(TALLOC_CTX *mem_ctx, ++ struct sss_iobuf *buf, ++ krb5_principal *_princ) ++{ ++ krb5_principal princ; ++ uint8_t non_empty; ++ krb5_int32 i; ++ errno_t ret; ++ ++ ret = sss_iobuf_read_uint8(buf, &non_empty); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ if (non_empty == 0) { ++ *_princ = NULL; ++ return EOK; ++ } ++ ++ princ = talloc_zero(mem_ctx, struct krb5_principal_data); ++ if (princ == NULL) { ++ return ENOMEM; ++ } ++ princ->magic = KV5M_PRINCIPAL; ++ ++ ret = bin_to_krb_data(princ, buf, &princ->realm); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = sss_iobuf_read_int32(buf, &princ->type); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = sss_iobuf_read_int32(buf, &princ->length); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ princ->data = talloc_zero_array(princ, krb5_data, princ->length); ++ if (princ->length > 0 && princ->data == NULL) { ++ return ENOMEM; ++ } ++ ++ for (i = 0; i < princ->length; i++) { ++ ret = bin_to_krb_data(princ, buf, &princ->data[i]); ++ if (ret != EOK) { ++ return ret; ++ } ++ } ++ ++ *_princ = princ; ++ ++ return EOK; ++} ++ ++static errno_t bin_to_creds(TALLOC_CTX *mem_ctx, ++ struct sss_iobuf *buf, ++ struct kcm_cred **_creds) ++{ ++ struct kcm_cred *creds = NULL; ++ struct kcm_cred *crd; ++ struct sss_iobuf *cred_blob; ++ uint32_t count; ++ uuid_t uuid; ++ errno_t ret; ++ ++ ret = sss_iobuf_read_uint32(buf, &count); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ for (uint32_t i = 0; i < count; i++) { ++ ret = sss_iobuf_read_len(buf, sizeof(uuid_t), (uint8_t*)uuid); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = sss_iobuf_read_iobuf(NULL, buf, &cred_blob); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ crd = kcm_cred_new(mem_ctx, uuid, cred_blob); ++ if (crd == NULL) { ++ talloc_free(cred_blob); ++ return ENOMEM; ++ } ++ ++ DLIST_ADD(creds, crd); ++ } ++ ++ *_creds = creds; ++ ++ return EOK; ++} ++ ++errno_t sec_kv_to_ccache_binary(TALLOC_CTX *mem_ctx, ++ const char *sec_key, ++ struct sss_iobuf *sec_value, ++ struct cli_creds *client, ++ struct kcm_ccache **_cc) ++{ ++ struct kcm_ccache *cc; ++ errno_t ret; ++ ++ cc = talloc_zero(mem_ctx, struct kcm_ccache); ++ if (cc == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = kcm_cc_set_header(cc, sec_key, client); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot store ccache header [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sss_iobuf_read_int32(sec_value, &cc->kdc_offset); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = bin_to_princ(cc, sec_value, &cc->client); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = bin_to_creds(cc, sec_value, &cc->creds); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ *_cc = cc; ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(cc); ++ } ++ ++ return ret; ++} +diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c +index f78e9f58c..e790cbea3 100644 +--- a/src/responder/kcm/kcmsrv_ccache_json.c ++++ b/src/responder/kcm/kcmsrv_ccache_json.c +@@ -37,12 +37,6 @@ + */ + #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) \ +@@ -51,119 +45,6 @@ + idx++) + #endif + +-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 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, +- uuid_t uuid) +-{ +- char uuid_str[UUID_STR_SIZE]; +- +- if (!sec_key_valid(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 (!sec_key_valid(sec_key)) { +- 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 (!sec_key_valid(sec_key)) { +- return NULL; +- } +- +- return sec_key + UUID_STR_SIZE; +-} +- +-bool sec_key_match_name(const char *sec_key, +- const char *name) +-{ +- if (!sec_key_valid(sec_key) || name == NULL) { +- 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; +- +- /* `key_uuid` is output arg and isn't read in sec_key_get_uuid() but +- * since libuuid is opaque for cppcheck it generates false positive here +- */ +- /* cppcheck-suppress uninitvar */ +- 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: +@@ -460,10 +341,9 @@ static errno_t ccache_to_sec_val(TALLOC_CTX *mem_ctx, + return EOK; + } + +-errno_t kcm_ccache_to_sec_input(TALLOC_CTX *mem_ctx, +- struct kcm_ccache *cc, +- struct cli_creds *client, +- struct sss_iobuf **_payload) ++errno_t kcm_ccache_to_sec_input_json(TALLOC_CTX *mem_ctx, ++ struct kcm_ccache *cc, ++ struct sss_iobuf **_payload) + { + errno_t ret; + const char *value; +@@ -897,11 +777,11 @@ static errno_t sec_json_value_to_ccache(struct kcm_ccache *cc, + * 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 sec_kv_to_ccache_json(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; +@@ -911,7 +791,7 @@ errno_t sec_kv_to_ccache(TALLOC_CTX *mem_ctx, + ret = sec_value_to_json(sec_value, &root); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "Cannot store secret to JSN [%d]: %s\n", ++ "Cannot store secret to JSON [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } +@@ -928,16 +808,9 @@ errno_t sec_kv_to_ccache(TALLOC_CTX *mem_ctx, + 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); ++ ret = kcm_cc_set_header(cc, sec_key, client); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Cannt parse secret key [%d]: %s\n", ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot store ccache header [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } +diff --git a/src/responder/kcm/kcmsrv_ccache_key.c b/src/responder/kcm/kcmsrv_ccache_key.c +new file mode 100644 +index 000000000..59d60453c +--- /dev/null ++++ b/src/responder/kcm/kcmsrv_ccache_key.c +@@ -0,0 +1,144 @@ ++/* ++ SSSD ++ ++ Copyright (C) Red Hat, 2020 ++ ++ 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" ++ ++/* ++ * The secrets store is a key-value store at heart. We store the UUID ++ * and the name in the key to allow easy lookups by either part. ++ */ ++#define SEC_KEY_SEPARATOR '-' ++ ++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 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; ++} ++ ++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 (!sec_key_valid(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 (!sec_key_valid(sec_key)) { ++ 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 (!sec_key_valid(sec_key)) { ++ return NULL; ++ } ++ ++ return sec_key + UUID_STR_SIZE; ++} ++ ++bool sec_key_match_name(const char *sec_key, ++ const char *name) ++{ ++ if (!sec_key_valid(sec_key) || name == NULL) { ++ 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; ++ ++ /* Clear uuid value to avoid cppcheck warning. */ ++ uuid_clear(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; ++} +diff --git a/src/responder/kcm/kcmsrv_ccache_mem.c b/src/responder/kcm/kcmsrv_ccache_mem.c +index baa698054..0e3a7b239 100644 +--- a/src/responder/kcm/kcmsrv_ccache_mem.c ++++ b/src/responder/kcm/kcmsrv_ccache_mem.c +@@ -49,24 +49,6 @@ struct ccdb_mem { + 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) +@@ -417,7 +399,11 @@ static struct tevent_req *ccdb_mem_getbyuuid_send(TALLOC_CTX *mem_ctx, + + ccwrap = memdb_get_by_uuid(memdb, client, uuid); + if (ccwrap != NULL) { +- state->cc = kcm_ccache_dup(state, ccwrap->cc); ++ /* 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 ++ */ ++ state->cc = kcm_cc_dup(state, ccwrap->cc); + if (state->cc == NULL) { + ret = ENOMEM; + goto immediate; +@@ -470,7 +456,11 @@ static struct tevent_req *ccdb_mem_getbyname_send(TALLOC_CTX *mem_ctx, + + ccwrap = memdb_get_by_name(memdb, client, name); + if (ccwrap != NULL) { +- state->cc = kcm_ccache_dup(state, ccwrap->cc); ++ /* 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 ++ */ ++ state->cc = kcm_cc_dup(state, ccwrap->cc); + if (state->cc == NULL) { + ret = ENOMEM; + goto immediate; +diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c +index ed1c8247f..726711ac4 100644 +--- a/src/responder/kcm/kcmsrv_ccache_secdb.c ++++ b/src/responder/kcm/kcmsrv_ccache_secdb.c +@@ -35,15 +35,16 @@ + #define KCM_SECDB_CCACHE_FMT KCM_SECDB_BASE_FMT"ccache/" + #define KCM_SECDB_DFL_FMT KCM_SECDB_BASE_FMT"default" + +-static errno_t sec_get_b64(TALLOC_CTX *mem_ctx, +- struct sss_sec_req *req, +- struct sss_iobuf **_buf) ++static errno_t sec_get(TALLOC_CTX *mem_ctx, ++ struct sss_sec_req *req, ++ struct sss_iobuf **_buf, ++ char **_datatype) + { + errno_t ret; + TALLOC_CTX *tmp_ctx; +- char *b64_sec; ++ char *datatype; + uint8_t *data; +- size_t data_size; ++ size_t len; + struct sss_iobuf *buf; + + tmp_ctx = talloc_new(mem_ctx); +@@ -51,101 +52,61 @@ static errno_t sec_get_b64(TALLOC_CTX *mem_ctx, + return ENOMEM; + } + +- ret = sss_sec_get(tmp_ctx, req, &b64_sec); ++ ret = sss_sec_get(tmp_ctx, req, &data, &len, &datatype); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot retrieve the secret [%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + +- data = sss_base64_decode(tmp_ctx, b64_sec, &data_size); +- if (data == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot decode secret from base64\n"); +- ret = EIO; +- goto done; +- } +- +- buf = sss_iobuf_init_readonly(tmp_ctx, data, data_size); ++ buf = sss_iobuf_init_steal(tmp_ctx, data, len); + if (buf == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init the iobuf\n"); + ret = EIO; + goto done; + } + +- ret = EOK; + *_buf = talloc_steal(mem_ctx, buf); ++ if (_datatype != NULL) { ++ *_datatype = talloc_steal(mem_ctx, datatype); ++ } ++ ++ ret = EOK; ++ + done: + talloc_free(tmp_ctx); + return ret; + } + +-static errno_t sec_put_b64(TALLOC_CTX *mem_ctx, +- struct sss_sec_req *req, +- struct sss_iobuf *buf) ++static errno_t sec_put(TALLOC_CTX *mem_ctx, ++ struct sss_sec_req *req, ++ struct sss_iobuf *buf) + { + errno_t ret; +- TALLOC_CTX *tmp_ctx; +- char *secret; + +- tmp_ctx = talloc_new(mem_ctx); +- if (tmp_ctx == NULL) { +- return ENOMEM; +- } +- +- secret = sss_base64_encode(tmp_ctx, +- sss_iobuf_get_data(buf), +- sss_iobuf_get_size(buf)); +- if (secret == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot encode secret to base64\n"); +- ret = EIO; +- goto done; +- } +- +- ret = sss_sec_put(req, secret); ++ ret = sss_sec_put(req, sss_iobuf_get_data(buf), sss_iobuf_get_size(buf), ++ SSS_SEC_PLAINTEXT, "binary"); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot write the secret [%d]: %s\n", ret, sss_strerror(ret)); +- goto done; + } + +- ret = EOK; +-done: +- talloc_free(tmp_ctx); + return ret; + } + +-static errno_t sec_update_b64(TALLOC_CTX *mem_ctx, +- struct sss_sec_req *req, +- struct sss_iobuf *buf) ++static errno_t sec_update(TALLOC_CTX *mem_ctx, ++ struct sss_sec_req *req, ++ struct sss_iobuf *buf) + { + errno_t ret; +- TALLOC_CTX *tmp_ctx; +- char *secret; +- +- tmp_ctx = talloc_new(mem_ctx); +- if (tmp_ctx == NULL) { +- return ENOMEM; +- } +- +- secret = sss_base64_encode(tmp_ctx, +- sss_iobuf_get_data(buf), +- sss_iobuf_get_size(buf)); +- if (secret == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot encode secret to base64\n"); +- ret = EIO; +- goto done; +- } + +- ret = sss_sec_update(req, secret); ++ ret = sss_sec_update(req, sss_iobuf_get_data(buf), sss_iobuf_get_size(buf), ++ SSS_SEC_PLAINTEXT, "binary"); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot write the secret [%d]: %s\n", ret, sss_strerror(ret)); +- goto done; + } + +- ret = EOK; +-done: +- talloc_free(tmp_ctx); + return ret; + } + +@@ -206,7 +167,7 @@ static errno_t kcm_ccache_to_secdb_kv(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = kcm_ccache_to_sec_input(mem_ctx, cc, client, &payload); ++ ret = kcm_ccache_to_sec_input_binary(mem_ctx, cc, &payload); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot convert ccache to a secret [%d][%s]\n", ret, sss_strerror(ret)); +@@ -480,6 +441,7 @@ static errno_t secdb_get_cc(TALLOC_CTX *mem_ctx, + struct kcm_ccache *cc = NULL; + struct sss_sec_req *sreq = NULL; + struct sss_iobuf *ccbuf; ++ char *datatype; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { +@@ -493,22 +455,23 @@ static errno_t secdb_get_cc(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sec_get_b64(tmp_ctx, sreq, &ccbuf); ++ ret = sec_get(tmp_ctx, sreq, &ccbuf, &datatype); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot get the secret [%d][%s]\n", ret, sss_strerror(ret)); + goto done; + } + +- ret = sec_kv_to_ccache(tmp_ctx, +- secdb_key, +- (const char *) sss_iobuf_get_data(ccbuf), +- client, +- &cc); ++ if (strcmp(datatype, "binary") == 0) { ++ ret = sec_kv_to_ccache_binary(tmp_ctx, secdb_key, ccbuf, client, &cc); ++ } else { ++ ret = sec_kv_to_ccache_json(tmp_ctx, secdb_key, ++ (const char *)sss_iobuf_get_data(ccbuf), ++ client, &cc); ++ } + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Cannot convert JSON keyval to ccache blob [%d]: %s\n", +- ret, sss_strerror(ret)); ++ DEBUG(SSSDBG_OP_FAILURE, "Cannot convert %s data to ccache " ++ "[%d]: %s\n", datatype, ret, sss_strerror(ret)); + goto done; + } + +@@ -746,11 +709,11 @@ static struct tevent_req *ccdb_secdb_set_default_send(TALLOC_CTX *mem_ctx, + goto immediate; + } + +- ret = sss_sec_get(state, sreq, &cur_default); ++ ret = sss_sec_get(state, sreq, (uint8_t**)&cur_default, NULL, NULL); + if (ret == ENOENT) { +- ret = sec_put_b64(state, sreq, iobuf); ++ ret = sec_put(state, sreq, iobuf); + } else if (ret == EOK) { +- ret = sec_update_b64(state, sreq, iobuf); ++ ret = sec_update(state, sreq, iobuf); + } + + if (ret != EOK) { +@@ -804,7 +767,7 @@ static struct tevent_req *ccdb_secdb_get_default_send(TALLOC_CTX *mem_ctx, + goto immediate; + } + +- ret = sec_get_b64(state, sreq, &dfl_iobuf); ++ ret = sec_get(state, sreq, &dfl_iobuf, NULL); + if (ret == ENOENT) { + uuid_clear(state->uuid); + ret = EOK; +@@ -1230,9 +1193,8 @@ static struct tevent_req *ccdb_secdb_create_send(TALLOC_CTX *mem_ctx, + goto immediate; + } + +- ret = sec_put_b64(state, ccache_req, ccache_payload); ++ ret = sec_put(state, ccache_req, ccache_payload); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Failed to add the payload\n"); + goto immediate; + } + +@@ -1298,7 +1260,7 @@ static struct tevent_req *ccdb_secdb_mod_send(TALLOC_CTX *mem_ctx, + goto immediate; + } + +- ret = kcm_ccache_to_sec_input(state, cc, client, &payload); ++ ret = kcm_ccache_to_sec_input_binary(state, cc, &payload); + if (ret != EOK) { + goto immediate; + } +@@ -1308,7 +1270,7 @@ static struct tevent_req *ccdb_secdb_mod_send(TALLOC_CTX *mem_ctx, + goto immediate; + } + +- ret = sec_update_b64(state, sreq, payload); ++ ret = sec_update(state, sreq, payload); + if (ret != EOK) { + goto immediate; + } +@@ -1374,7 +1336,7 @@ static struct tevent_req *ccdb_secdb_store_cred_send(TALLOC_CTX *mem_ctx, + goto immediate; + } + +- ret = kcm_ccache_to_sec_input(state, cc, client, &payload); ++ ret = kcm_ccache_to_sec_input_binary(state, cc, &payload); + if (ret != EOK) { + goto immediate; + } +@@ -1384,7 +1346,7 @@ static struct tevent_req *ccdb_secdb_store_cred_send(TALLOC_CTX *mem_ctx, + goto immediate; + } + +- ret = sec_update_b64(state, sreq, payload); ++ ret = sec_update(state, sreq, payload); + if (ret != EOK) { + goto immediate; + } +diff --git a/src/responder/kcm/kcmsrv_ccache_secrets.c b/src/responder/kcm/kcmsrv_ccache_secrets.c +index 440ab3bb9..f3d69842c 100644 +--- a/src/responder/kcm/kcmsrv_ccache_secrets.c ++++ b/src/responder/kcm/kcmsrv_ccache_secrets.c +@@ -195,7 +195,7 @@ static errno_t kcm_ccache_to_sec_kv(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = kcm_ccache_to_sec_input(mem_ctx, cc, client, &payload); ++ ret = kcm_ccache_to_sec_input_json(mem_ctx, cc, &payload); + if (ret != EOK) { + goto done; + } +@@ -489,11 +489,8 @@ static void sec_get_done(struct tevent_req *subreq) + return; + } + +- ret = sec_kv_to_ccache(state, +- state->sec_key, +- sec_value, +- state->client, +- &state->cc); ++ ret = sec_kv_to_ccache_json(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", +diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c +index 421bf4bc5..a1aa9aa20 100644 +--- a/src/responder/kcm/kcmsrv_cmd.c ++++ b/src/responder/kcm/kcmsrv_cmd.c +@@ -314,7 +314,7 @@ static void kcm_reply_error(struct cli_ctx *cctx, + krb5_error_code kerr; + + DEBUG(SSSDBG_OP_FAILURE, +- "KCM operation returs failure [%d]: %s\n", ++ "KCM operation returns failure [%d]: %s\n", + retcode, sss_strerror(retcode)); + kerr = sss2krb5_error(retcode); + +@@ -373,13 +373,16 @@ static errno_t kcm_cmd_dispatch(struct kcm_ctx *kctx, + { + struct tevent_req *req; + struct cli_ctx *cctx; ++ struct kcm_conn_data *conn_data; + + cctx = req_ctx->cctx; ++ conn_data = talloc_get_type(cctx->state_ctx, struct kcm_conn_data); + + req = kcm_cmd_send(req_ctx, + cctx->ev, + kctx->qctx, + req_ctx->kctx->kcm_data, ++ conn_data, + req_ctx->cctx->creds, + &req_ctx->op_io.request, + req_ctx->op_io.op); +@@ -492,7 +495,7 @@ static void kcm_recv(struct cli_ctx *cctx) + int ret; + + kctx = talloc_get_type(cctx->rctx->pvt_ctx, struct kcm_ctx); +- req = talloc_get_type(cctx->state_ctx, struct kcm_req_ctx); ++ req = talloc_get_type(cctx->protocol_ctx, struct kcm_req_ctx); + if (req == NULL) { + /* A new request comes in, setup data structures. */ + req = kcm_new_req(cctx, kctx); +@@ -503,7 +506,17 @@ static void kcm_recv(struct cli_ctx *cctx) + return; + } + +- cctx->state_ctx = req; ++ cctx->protocol_ctx = req; ++ } ++ ++ /* Shared data between requests that originates in the same connection. */ ++ if (cctx->state_ctx == NULL) { ++ cctx->state_ctx = talloc_zero(cctx, struct kcm_conn_data); ++ if (cctx->state_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set up client state\n"); ++ talloc_free(cctx); ++ return; ++ } + } + + ret = kcm_recv_data(req, cctx->cfd, &req->reqbuf); +@@ -558,7 +571,7 @@ 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); ++ req = talloc_get_type(cctx->protocol_ctx, struct kcm_req_ctx); + + ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_len); + if (ret != EOK) { +@@ -604,7 +617,7 @@ static void kcm_send(struct cli_ctx *cctx) + DEBUG(SSSDBG_TRACE_INTERNAL, "All data sent!\n"); + TEVENT_FD_NOT_WRITEABLE(cctx->cfde); + TEVENT_FD_READABLE(cctx->cfde); +- talloc_zfree(cctx->state_ctx); ++ talloc_zfree(cctx->protocol_ctx); + return; + } + +diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c +index 6ac66c150..f458c724b 100644 +--- a/src/responder/kcm/kcmsrv_ops.c ++++ b/src/responder/kcm/kcmsrv_ops.c +@@ -22,9 +22,11 @@ + #include "config.h" + + #include ++#include + + #include "util/sss_iobuf.h" + #include "util/sss_krb5.h" ++#include "util/sss_ptr_hash.h" + #include "util/util_creds.h" + #include "responder/kcm/kcm.h" + #include "responder/kcm/kcmsrv_pvt.h" +@@ -38,6 +40,7 @@ + + struct kcm_op_ctx { + struct kcm_resp_ctx *kcm_data; ++ struct kcm_conn_data *conn_data; + struct cli_creds *client; + + struct sss_iobuf *input; +@@ -86,6 +89,7 @@ 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 kcm_conn_data *conn_data, + struct cli_creds *client, + struct kcm_data *input, + struct kcm_op *op) +@@ -135,6 +139,7 @@ struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx, + } + + state->op_ctx->kcm_data = kcm_data; ++ state->op_ctx->conn_data = conn_data; + state->op_ctx->client = client; + + state->op_ctx->input = sss_iobuf_init_readonly(state->op_ctx, +@@ -1071,8 +1076,75 @@ static void kcm_op_get_principal_getbyname_done(struct tevent_req *subreq) + tevent_req_done(req); + } + ++static void ++kcm_creds_table_delete_cb(hash_entry_t *item, ++ hash_destroy_enum deltype, ++ void *pvt) ++{ ++ /* Delete the old credential if it is being overwritten. */ ++ talloc_free(item->value.ptr); ++} ++ ++/* Store credentials in a hash table. ++ * ++ * If the table already exist we add the new credentials to the table and ++ * overwrite the ones that already exist. This allows us to correctly serve ++ * also parallel GET_CRED_UUID_LIST requests from the same connection since ++ * it will have its own uuid list and cursor on the client side and we make ++ * all uuid (old, updated and newly added) available. ++ */ ++static errno_t ++kcm_creds_to_table(TALLOC_CTX *mem_ctx, ++ struct kcm_cred *creds, ++ hash_table_t **_table) ++{ ++ char str[UUID_STR_SIZE]; ++ uuid_t uuid; ++ errno_t ret; ++ ++ if (*_table == NULL) { ++ *_table = sss_ptr_hash_create(mem_ctx, kcm_creds_table_delete_cb, NULL); ++ if (*_table == NULL) { ++ return ENOMEM; ++ } ++ } ++ ++ for (struct kcm_cred *crd = creds; ++ 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; ++ } ++ uuid_unparse(uuid, str); ++ ++ ret = sss_ptr_hash_add_or_override(*_table, str, crd, struct kcm_cred); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ talloc_steal(*_table, crd); ++ } ++ ++ return EOK; ++} ++ ++static struct kcm_cred * ++kcm_creds_lookup(hash_table_t *table, uuid_t uuid) ++{ ++ char str[UUID_STR_SIZE]; ++ ++ if (uuid == NULL) { ++ return NULL; ++ } ++ ++ uuid_unparse(uuid, str); ++ return sss_ptr_hash_lookup(table, str, struct kcm_cred); ++} ++ + /* (name) -> (uuid, ...) */ +-static void kcm_op_get_cred_uuid_getbyname_done(struct tevent_req *subreq); ++static void kcm_op_get_cred_uuid_list_getbyname_done(struct tevent_req *subreq); + + static struct tevent_req * + kcm_op_get_cred_uuid_list_send(TALLOC_CTX *mem_ctx, +@@ -1106,7 +1178,7 @@ kcm_op_get_cred_uuid_list_send(TALLOC_CTX *mem_ctx, + ret = ENOMEM; + goto immediate; + } +- tevent_req_set_callback(subreq, kcm_op_get_cred_uuid_getbyname_done, req); ++ tevent_req_set_callback(subreq, kcm_op_get_cred_uuid_list_getbyname_done, req); + return req; + + immediate: +@@ -1115,17 +1187,20 @@ immediate: + return req; + } + +-static void kcm_op_get_cred_uuid_getbyname_done(struct tevent_req *subreq) ++static void kcm_op_get_cred_uuid_list_getbyname_done(struct tevent_req *subreq) + { + errno_t ret; + struct kcm_ccache *cc; + struct kcm_cred *crd; ++ struct kcm_conn_data *conn_data; + 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); + ++ conn_data = state->op_ctx->conn_data; ++ + ret = kcm_ccdb_getbyname_recv(subreq, state, &cc); + talloc_zfree(subreq); + if (ret != EOK) { +@@ -1137,12 +1212,20 @@ static void kcm_op_get_cred_uuid_getbyname_done(struct tevent_req *subreq) + } + + if (cc == NULL) { +- DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that UUID\n"); ++ DEBUG(SSSDBG_MINOR_FAILURE, "No ccache by that name\n"); + state->op_ret = ERR_NO_CREDS; + tevent_req_done(req); + return; + } + ++ ret = kcm_creds_to_table(conn_data, kcm_cc_get_cred(cc), &conn_data->creds); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to build credentials hash table " ++ "[%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)) { +@@ -1169,6 +1252,34 @@ static void kcm_op_get_cred_uuid_getbyname_done(struct tevent_req *subreq) + tevent_req_done(req); + } + ++static errno_t ++kcm_op_get_cred_by_uuid_reply(struct kcm_cred *crd, ++ struct sss_iobuf *reply) ++{ ++ struct sss_iobuf *cred_blob; ++ errno_t ret; ++ ++ cred_blob = kcm_cred_get_creds(crd); ++ if (cred_blob == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Credentials lack the creds blob\n"); ++ return ERR_NO_CREDS; ++ } ++ ++ ret = sss_iobuf_write_len(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)); ++ } ++ ++ return ret; ++} ++ ++struct kcm_op_get_cred_by_uuid_state { ++ struct kcm_op_common_state common; ++ uuid_t uuid; ++}; ++ + /* (name, uuid) -> (cred) */ + static void kcm_op_get_cred_by_uuid_getbyname_done(struct tevent_req *subreq); + +@@ -1179,20 +1290,51 @@ kcm_op_get_cred_by_uuid_send(TALLOC_CTX *mem_ctx, + { + struct tevent_req *req = NULL; + struct tevent_req *subreq = NULL; +- struct kcm_op_common_state *state = NULL; ++ struct kcm_op_get_cred_by_uuid_state *state; ++ struct kcm_cred *crd; + errno_t ret; + const char *name; + +- req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state); ++ req = tevent_req_create(mem_ctx, &state, ++ struct kcm_op_get_cred_by_uuid_state); + if (req == NULL) { + return NULL; + } +- state->op_ctx = op_ctx; ++ state->common.op_ctx = op_ctx; + + ret = sss_iobuf_read_stringz(op_ctx->input, &name); + if (ret != EOK) { + goto immediate; + } ++ ++ ret = sss_iobuf_read_len(state->common.op_ctx->input, UUID_BYTES, ++ state->uuid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Cannot read input UUID [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto immediate; ++ } ++ ++ if (op_ctx->conn_data->creds != NULL) { ++ crd = kcm_creds_lookup(op_ctx->conn_data->creds, state->uuid); ++ if (crd == NULL) { ++ /* This should not happen, it can only happen if wrong UUID was ++ * requested which suggests bug in the caller application. */ ++ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that UUID\n"); ++ kcm_debug_uuid(state->uuid); ++ state->common.op_ret = ERR_KCM_CC_END; ++ ret = EOK; ++ goto immediate; ++ } else { ++ ret = kcm_op_get_cred_by_uuid_reply(crd, op_ctx->reply); ++ if (ret == ERR_NO_CREDS) { ++ state->common.op_ret = ret; ++ ret = EOK; ++ } ++ goto immediate; ++ } ++ } ++ + DEBUG(SSSDBG_TRACE_LIBS, "Returning creds by UUID for %s\n", name); + + subreq = kcm_ccdb_getbyname_send(state, ev, +@@ -1207,7 +1349,11 @@ kcm_op_get_cred_by_uuid_send(TALLOC_CTX *mem_ctx, + return req; + + immediate: +- tevent_req_error(req, ret); ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } + tevent_req_post(req, ev); + return req; + } +@@ -1216,14 +1362,14 @@ 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); ++ struct kcm_op_get_cred_by_uuid_state *state = tevent_req_data(req, ++ struct kcm_op_get_cred_by_uuid_state); + errno_t ret; + struct kcm_ccache *cc; + struct kcm_cred *crd; +- uuid_t uuid_in; +- uuid_t uuid; +- struct sss_iobuf *cred_blob; ++ struct kcm_conn_data *conn_data; ++ ++ conn_data = state->common.op_ctx->conn_data; + + ret = kcm_ccdb_getbyname_recv(subreq, state, &cc); + talloc_zfree(subreq); +@@ -1235,67 +1381,43 @@ static void kcm_op_get_cred_by_uuid_getbyname_done(struct tevent_req *subreq) + 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); ++ ret = kcm_creds_to_table(conn_data, kcm_cc_get_cred(cc), &conn_data->creds); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Cannot read input UUID [%d]: %s\n", +- ret, sss_strerror(ret)); ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to build credentials hash table " ++ "[%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 (conn_data->creds != NULL) { ++ crd = kcm_creds_lookup(conn_data->creds, state->uuid); ++ if (crd == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that UUID\n"); ++ kcm_debug_uuid(state->uuid); ++ state->common.op_ret = ERR_KCM_CC_END; ++ } else { ++ ret = kcm_op_get_cred_by_uuid_reply(crd, state->common.op_ctx->reply); ++ if (ret != EOK && ret != ERR_NO_CREDS) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ state->common.op_ret = ret; + } +- +- 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; +- } ++ tevent_req_done(req); ++} + +- 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; +- } ++static errno_t kcm_op_get_cred_by_uuid_recv(struct tevent_req *req, ++ uint32_t *_op_ret) ++{ ++ struct kcm_op_get_cred_by_uuid_state *state; + +- 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 = tevent_req_data(req, struct kcm_op_get_cred_by_uuid_state); + +- state->op_ret = EOK; +- tevent_req_done(req); ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ *_op_ret = state->common.op_ret; ++ return EOK; + } + + /* (name, flags, credtag) -> () */ +@@ -1468,7 +1590,7 @@ static void kcm_op_get_cache_by_uuid_done(struct tevent_req *subreq) + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +- "Cannot get ccahe by UUID [%d]: %s\n", ++ "Cannot get ccache by UUID [%d]: %s\n", + ret, sss_strerror(ret)); + tevent_req_error(req, ret); + return; +@@ -2153,7 +2275,7 @@ static struct kcm_op kcm_optable[] = { + { "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 }, ++ { "GET_CRED_BY_UUID", kcm_op_get_cred_by_uuid_send, kcm_op_get_cred_by_uuid_recv }, + { "REMOVE_CRED", kcm_op_remove_cred_send, NULL }, + { "SET_FLAGS", NULL, NULL }, + { "CHOWN", NULL, NULL }, +diff --git a/src/responder/kcm/kcmsrv_ops.h b/src/responder/kcm/kcmsrv_ops.h +index 67d9f8602..ab6c13791 100644 +--- a/src/responder/kcm/kcmsrv_ops.h ++++ b/src/responder/kcm/kcmsrv_ops.h +@@ -24,6 +24,7 @@ + + #include "config.h" + ++#include + #include + #include "util/sss_iobuf.h" + #include "responder/kcm/kcmsrv_pvt.h" +@@ -32,10 +33,17 @@ struct kcm_op; + struct kcm_op *kcm_get_opt(uint16_t opcode); + const char *kcm_opt_name(struct kcm_op *op); + ++struct kcm_conn_data { ++ /* Credentials obtained by GET_CRED_UUID_LIST. We use to improve performance ++ * by avoiding ccache lookups in GET_CRED_BY_UUID. */ ++ hash_table_t *creds; ++}; ++ + 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 kcm_conn_data *conn_data, + struct cli_creds *client, + struct kcm_data *input, + struct kcm_op *op); +diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c +index eb37c08b7..252ef3a1d 100644 +--- a/src/responder/secrets/local.c ++++ b/src/responder/secrets/local.c +@@ -134,7 +134,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, + break; + } + +- ret = sss_sec_get(state, ssec_req, &secret); ++ ret = sss_sec_get(state, ssec_req, (uint8_t**)&secret, NULL, NULL); + if (ret) goto done; + + if (body_is_json) { +@@ -168,7 +168,8 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, + } + if (ret) goto done; + +- ret = sss_sec_put(ssec_req, secret); ++ ret = sss_sec_put(ssec_req, (uint8_t *)secret, strlen(secret) + 1, ++ SSS_SEC_MASTERKEY, "simple"); + if (ret) goto done; + break; + +diff --git a/src/shared/safealign.h b/src/shared/safealign.h +index b00c37f5b..35909faa2 100644 +--- a/src/shared/safealign.h ++++ b/src/shared/safealign.h +@@ -97,6 +97,10 @@ safealign_memcpy(void *dest, const void *src, size_t n, size_t *counter) + #define SAFEALIGN_SETMEM_UINT16(dest, value, pctr) \ + SAFEALIGN_SETMEM_VALUE(dest, value, uint16_t, pctr) + ++/* SAFEALIGN_SETMEM_UINT8(void *dest, uint8_t value, size_t *pctr) */ ++#define SAFEALIGN_SETMEM_UINT8(dest, value, pctr) \ ++ SAFEALIGN_SETMEM_VALUE(dest, value, uint8_t, pctr) ++ + /* These macros are the same as their equivalents without _CHECK suffix, + * but additionally make the caller return EINVAL immediately if *pctr + * would exceed len. */ +diff --git a/src/tests/cmocka/test_kcm_json_marshalling.c b/src/tests/cmocka/test_kcm_marshalling.c +similarity index 71% +rename from src/tests/cmocka/test_kcm_json_marshalling.c +rename to src/tests/cmocka/test_kcm_marshalling.c +index 48ee92bd6..cebebac80 100644 +--- a/src/tests/cmocka/test_kcm_json_marshalling.c ++++ b/src/tests/cmocka/test_kcm_marshalling.c +@@ -154,7 +154,7 @@ static void assert_cc_equal(struct kcm_ccache *cc1, + assert_cc_offset_equal(cc1, cc2); + } + +-static void test_kcm_ccache_marshall_unmarshall(void **state) ++static void test_kcm_ccache_marshall_unmarshall_json(void **state) + { + struct kcm_marshalling_test_ctx *test_ctx = talloc_get_type(*state, + struct kcm_marshalling_test_ctx); +@@ -182,10 +182,7 @@ static void test_kcm_ccache_marshall_unmarshall(void **state) + &cc); + assert_int_equal(ret, EOK); + +- ret = kcm_ccache_to_sec_input(test_ctx, +- cc, +- &owner, +- &payload); ++ ret = kcm_ccache_to_sec_input_json(test_ctx, cc, &payload); + assert_int_equal(ret, EOK); + + data = sss_iobuf_get_data(payload); +@@ -196,25 +193,19 @@ static void test_kcm_ccache_marshall_unmarshall(void **state) + key = sec_key_create(test_ctx, name, uuid); + assert_non_null(key); + +- ret = sec_kv_to_ccache(test_ctx, +- key, +- (const char *) data, +- &owner, +- &cc2); ++ ret = sec_kv_to_ccache_json(test_ctx, key, (const char *)data, &owner, ++ &cc2); + 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); ++ ret = sec_kv_to_ccache_json(test_ctx, TEST_UUID_STR "-", (const char *)data, ++ &owner, &cc2); + assert_int_equal(ret, EINVAL); + } + +-static void test_kcm_ccache_no_princ(void **state) ++static void test_kcm_ccache_no_princ_json(void **state) + { + struct kcm_marshalling_test_ctx *test_ctx = talloc_get_type(*state, + struct kcm_marshalling_test_ctx); +@@ -246,10 +237,7 @@ static void test_kcm_ccache_no_princ(void **state) + princ = kcm_cc_get_client_principal(cc); + assert_null(princ); + +- ret = kcm_ccache_to_sec_input(test_ctx, +- cc, +- &owner, +- &payload); ++ ret = kcm_ccache_to_sec_input_json(test_ctx, cc, &payload); + assert_int_equal(ret, EOK); + + data = sss_iobuf_get_data(payload); +@@ -260,11 +248,110 @@ static void test_kcm_ccache_no_princ(void **state) + key = sec_key_create(test_ctx, name, uuid); + assert_non_null(key); + +- ret = sec_kv_to_ccache(test_ctx, +- key, +- (const char *) data, +- &owner, +- &cc2); ++ ret = sec_kv_to_ccache_json(test_ctx, key, (const char *)data, &owner, ++ &cc2); ++ assert_int_equal(ret, EOK); ++ ++ assert_cc_equal(cc, cc2); ++} ++ ++static void test_kcm_ccache_marshall_unmarshall_binary(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; ++ struct sss_iobuf *payload; ++ const char *name; ++ const char *key; ++ uint8_t *data; ++ uuid_t uuid; ++ ++ 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_binary(test_ctx, cc, &payload); ++ assert_int_equal(ret, EOK); ++ ++ data = sss_iobuf_get_data(payload); ++ assert_non_null(data); ++ ++ ret = kcm_cc_get_uuid(cc, uuid); ++ assert_int_equal(ret, EOK); ++ key = sec_key_create(test_ctx, name, uuid); ++ assert_non_null(key); ++ ++ sss_iobuf_cursor_reset(payload); ++ ret = sec_kv_to_ccache_binary(test_ctx, key, payload, &owner, &cc2); ++ assert_int_equal(ret, EOK); ++ ++ assert_cc_equal(cc, cc2); ++ ++ /* This key is exactly one byte shorter than it should be */ ++ sss_iobuf_cursor_reset(payload); ++ ret = sec_kv_to_ccache_binary(test_ctx, TEST_UUID_STR "-", payload, &owner, ++ &cc2); ++ assert_int_equal(ret, EINVAL); ++} ++ ++static void test_kcm_ccache_no_princ_binary(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; ++ const char *name; ++ struct kcm_ccache *cc; ++ krb5_principal princ; ++ struct kcm_ccache *cc2; ++ struct sss_iobuf *payload; ++ const char *key; ++ uint8_t *data; ++ uuid_t uuid; ++ ++ 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, ++ NULL, ++ &cc); ++ assert_int_equal(ret, EOK); ++ ++ princ = kcm_cc_get_client_principal(cc); ++ assert_null(princ); ++ ++ ret = kcm_ccache_to_sec_input_binary(test_ctx, cc, &payload); ++ assert_int_equal(ret, EOK); ++ ++ data = sss_iobuf_get_data(payload); ++ assert_non_null(data); ++ ++ ret = kcm_cc_get_uuid(cc, uuid); ++ assert_int_equal(ret, EOK); ++ key = sec_key_create(test_ctx, name, uuid); ++ assert_non_null(key); ++ ++ sss_iobuf_cursor_reset(payload); ++ ret = sec_kv_to_ccache_binary(test_ctx, key, payload, &owner, &cc2); + assert_int_equal(ret, EOK); + + assert_cc_equal(cc, cc2); +@@ -340,10 +427,16 @@ int main(int argc, const char *argv[]) + }; + + const struct CMUnitTest tests[] = { +- cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall, ++ cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall_binary, ++ setup_kcm_marshalling, ++ teardown_kcm_marshalling), ++ cmocka_unit_test_setup_teardown(test_kcm_ccache_no_princ_binary, ++ setup_kcm_marshalling, ++ teardown_kcm_marshalling), ++ cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall_json, + setup_kcm_marshalling, + teardown_kcm_marshalling), +- cmocka_unit_test_setup_teardown(test_kcm_ccache_no_princ, ++ cmocka_unit_test_setup_teardown(test_kcm_ccache_no_princ_json, + setup_kcm_marshalling, + teardown_kcm_marshalling), + cmocka_unit_test(test_sec_key_get_uuid), +diff --git a/src/tests/cmocka/test_sss_ptr_hash.c b/src/tests/cmocka/test_sss_ptr_hash.c +index 1458238f5..31cf8b705 100644 +--- a/src/tests/cmocka/test_sss_ptr_hash.c ++++ b/src/tests/cmocka/test_sss_ptr_hash.c +@@ -91,6 +91,45 @@ void test_sss_ptr_hash_with_free_cb(void **state) + assert_int_equal(free_counter, MAX_ENTRIES_AMOUNT*2); + } + ++void test_sss_ptr_hash_overwrite_with_free_cb(void **state) ++{ ++ hash_table_t *table; ++ int free_counter = 0; ++ unsigned long count; ++ char *payload; ++ char *value; ++ errno_t ret; ++ ++ table = sss_ptr_hash_create(global_talloc_context, ++ free_payload_cb, ++ &free_counter); ++ assert_non_null(table); ++ ++ payload = talloc_strdup(table, "test_value1"); ++ assert_non_null(payload); ++ talloc_set_name_const(payload, "char"); ++ ret = sss_ptr_hash_add_or_override(table, "test", payload, char); ++ assert_int_equal(ret, 0); ++ count = hash_count(table); ++ assert_int_equal(count, 1); ++ value = sss_ptr_hash_lookup(table, "test", char); ++ assert_ptr_equal(value, payload); ++ ++ ++ payload = talloc_strdup(table, "test_value2"); ++ assert_non_null(payload); ++ talloc_set_name_const(payload, "char"); ++ ret = sss_ptr_hash_add_or_override(table, "test", payload, char); ++ assert_int_equal(ret, 0); ++ count = hash_count(table); ++ assert_int_equal(count, 1); ++ value = sss_ptr_hash_lookup(table, "test", char); ++ assert_ptr_equal(value, payload); ++ ++ talloc_free(table); ++ assert_int_equal(free_counter, 2); ++} ++ + struct table_wrapper + { + hash_table_t **table; +diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c +index d77a972c1..d258622fb 100644 +--- a/src/tests/cmocka/test_utils.c ++++ b/src/tests/cmocka/test_utils.c +@@ -2144,6 +2144,9 @@ int main(int argc, const char *argv[]) + cmocka_unit_test_setup_teardown(test_sss_ptr_hash_with_free_cb, + setup_leak_tests, + teardown_leak_tests), ++ cmocka_unit_test_setup_teardown(test_sss_ptr_hash_overwrite_with_free_cb, ++ setup_leak_tests, ++ teardown_leak_tests), + cmocka_unit_test_setup_teardown(test_sss_ptr_hash_with_lookup_cb, + setup_leak_tests, + teardown_leak_tests), +diff --git a/src/tests/cmocka/test_utils.h b/src/tests/cmocka/test_utils.h +index 44b9479f9..458bcb750 100644 +--- a/src/tests/cmocka/test_utils.h ++++ b/src/tests/cmocka/test_utils.h +@@ -35,6 +35,7 @@ void test_concatenate_string_array(void **state); + + /* from src/tests/cmocka/test_sss_ptr_hash.c */ + void test_sss_ptr_hash_with_free_cb(void **state); ++void test_sss_ptr_hash_overwrite_with_free_cb(void **state); + void test_sss_ptr_hash_with_lookup_cb(void **state); + void test_sss_ptr_hash_without_cb(void **state); + +diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py +index 00933fb34..18d722c13 100644 +--- a/src/tests/intg/test_secrets.py ++++ b/src/tests/intg/test_secrets.py +@@ -438,7 +438,8 @@ def run_quota_test(cli, max_secrets, max_payload_size): + KILOBYTE = 1024 + kb_payload_size = max_payload_size * KILOBYTE + +- sec_value = "x" * kb_payload_size ++ # Adjust payload size to hold terminal zero byte. ++ sec_value = "x" * (kb_payload_size - 1) + + cli.set_secret("foo", sec_value) + +diff --git a/src/tests/multihost/basic/test_kcm.py b/src/tests/multihost/basic/test_kcm.py +index e5d315827..6f65431f8 100644 +--- a/src/tests/multihost/basic/test_kcm.py ++++ b/src/tests/multihost/basic/test_kcm.py +@@ -310,6 +310,12 @@ class TestSanityKCM(object): + set_param(multihost, 'kcm', 'max_ccache_size', '1') + self._restart_kcm(multihost) + +- with pytest.raises(paramiko.ssh_exception.AuthenticationException): +- ssh_foo3 = SSHClient(multihost.master[0].sys_hostname, +- username='foo3', password='Secret123') ++ # We use kinit to exceed the maximum ccache size as it creates payload ++ # of 1280 bytes by acquiring tgt and also some control credentials. ++ # SSH authentication is not sufficient as it stores only tgt. ++ ssh_foo3 = SSHClient(multihost.master[0].sys_hostname, ++ username='foo3', password='Secret123') ++ (_, _, exit_status) = ssh_foo3.execute_cmd( ++ 'kinit foo3@EXAMPLE.TEST', 'Secret123' ++ ) ++ assert exit_status != 0 +diff --git a/src/util/secrets/sec_pvt.h b/src/util/secrets/sec_pvt.h +index 92e2b8b25..0e77a660e 100644 +--- a/src/util/secrets/sec_pvt.h ++++ b/src/util/secrets/sec_pvt.h +@@ -33,7 +33,7 @@ + #define SSS_SEC_KCM_BASEPATH "/kcm/" + + struct sss_sec_data { +- char *data; ++ uint8_t *data; + size_t length; + }; + +diff --git a/src/util/secrets/secrets.c b/src/util/secrets/secrets.c +index d701face0..c6310b585 100644 +--- a/src/util/secrets/secrets.c ++++ b/src/util/secrets/secrets.c +@@ -36,9 +36,14 @@ + #define SECRETS_BASEDN "cn=secrets" + #define KCM_BASEDN "cn=kcm" + +-#define LOCAL_SIMPLE_FILTER "(type=simple)" ++#define LOCAL_SIMPLE_FILTER "(|(type=simple)(type=binary))" + #define LOCAL_CONTAINER_FILTER "(type=container)" + ++#define SEC_ATTR_SECRET "secret" ++#define SEC_ATTR_ENCTYPE "enctype" ++#define SEC_ATTR_TYPE "type" ++#define SEC_ATTR_CTIME "creationTime" ++ + typedef int (*url_mapper_fn)(TALLOC_CTX *mem_ctx, + const char *url, + uid_t client, +@@ -63,90 +68,136 @@ static struct sss_sec_quota default_kcm_quota = { + .containers_nest_level = DEFAULT_SEC_CONTAINERS_NEST_LEVEL, + }; + +-static int local_decrypt(struct sss_sec_ctx *sctx, TALLOC_CTX *mem_ctx, +- const char *secret, const char *enctype, +- char **plain_secret) ++static const char *sss_sec_enctype_to_str(enum sss_sec_enctype enctype) + { +- char *output; ++ switch (enctype) { ++ case SSS_SEC_PLAINTEXT: ++ return "plaintext"; ++ case SSS_SEC_MASTERKEY: ++ return "masterkey"; ++ default: ++ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: unknown encryption type %d\n", ++ enctype); ++ return "unknown"; ++ } ++} + +- if (enctype && strcmp(enctype, "masterkey") == 0) { +- DEBUG(SSSDBG_TRACE_INTERNAL, "Decrypting with masterkey\n"); ++static enum sss_sec_enctype sss_sec_str_to_enctype(const char *str) ++{ ++ if (strcmp("plaintext", str) == 0) { ++ return SSS_SEC_PLAINTEXT; ++ } + +- struct sss_sec_data _secret; +- size_t outlen; +- int ret; ++ if (strcmp("masterkey", str) == 0) { ++ return SSS_SEC_MASTERKEY; ++ } ++ ++ return SSS_SEC_ENCTYPE_SENTINEL; ++} + +- _secret.data = (char *)sss_base64_decode(mem_ctx, secret, +- &_secret.length); ++static int local_decrypt(struct sss_sec_ctx *sctx, ++ TALLOC_CTX *mem_ctx, ++ uint8_t *secret, ++ size_t secret_len, ++ enum sss_sec_enctype enctype, ++ uint8_t **_output, ++ size_t *_output_len) ++{ ++ struct sss_sec_data _secret; ++ uint8_t *output; ++ size_t output_len; ++ int ret; ++ ++ switch (enctype) { ++ case SSS_SEC_PLAINTEXT: ++ output = talloc_memdup(mem_ctx, secret, secret_len); ++ output_len = secret_len; ++ break; ++ case SSS_SEC_MASTERKEY: ++ _secret.data = (uint8_t *)sss_base64_decode(mem_ctx, ++ (const char *)secret, ++ &_secret.length); + if (!_secret.data) { + DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed\n"); + return EINVAL; + } + ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Decrypting with masterkey\n"); + ret = sss_decrypt(mem_ctx, AES256CBC_HMAC_SHA256, +- (uint8_t *)sctx->master_key.data, ++ sctx->master_key.data, + sctx->master_key.length, +- (uint8_t *)_secret.data, _secret.length, +- (uint8_t **)&output, &outlen); ++ _secret.data, _secret.length, ++ &output, &output_len); + talloc_free(_secret.data); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, + "sss_decrypt failed [%d]: %s\n", ret, sss_strerror(ret)); + return ret; + } ++ break; ++ default: ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unknown encryption type '%d'\n", enctype); ++ return EINVAL; ++ } + +- if (((strnlen(output, outlen) + 1) != outlen) || +- output[outlen - 1] != '\0') { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Output length mismatch or output not NULL-terminated\n"); +- talloc_free(output); +- return EIO; +- } +- } else { +- DEBUG(SSSDBG_TRACE_INTERNAL, "Unexpected enctype (not 'masterkey')\n"); +- output = talloc_strdup(mem_ctx, secret); +- if (!output) return ENOMEM; ++ if (output == NULL) { ++ return ENOMEM; + } + +- *plain_secret = output; ++ *_output = output; ++ *_output_len = output_len; ++ + return EOK; + } + +-static int local_encrypt(struct sss_sec_ctx *sec_ctx, TALLOC_CTX *mem_ctx, +- const char *secret, const char *enctype, +- char **ciphertext) ++static int local_encrypt(struct sss_sec_ctx *sec_ctx, ++ TALLOC_CTX *mem_ctx, ++ uint8_t *secret, ++ size_t secret_len, ++ enum sss_sec_enctype enctype, ++ uint8_t **_output, ++ size_t *_output_len) + { + struct sss_sec_data _secret; +- char *output; ++ uint8_t *output; ++ size_t output_len; ++ char *b64; + int ret; + +- if (enctype == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "No encryption type\n"); +- return EINVAL; +- } ++ switch (enctype) { ++ case SSS_SEC_PLAINTEXT: ++ output = talloc_memdup(mem_ctx, secret, secret_len); ++ output_len = secret_len; ++ break; ++ case SSS_SEC_MASTERKEY: ++ ret = sss_encrypt(mem_ctx, AES256CBC_HMAC_SHA256, ++ sec_ctx->master_key.data, ++ sec_ctx->master_key.length, ++ secret, secret_len, ++ &_secret.data, &_secret.length); ++ if (ret) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sss_encrypt failed [%d]: %s\n", ret, sss_strerror(ret)); ++ return ret; ++ } + +- if (strcmp(enctype, "masterkey") != 0) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unknown encryption type '%s'\n", enctype); ++ b64 = sss_base64_encode(mem_ctx, _secret.data, _secret.length); ++ output = (uint8_t*)b64; ++ output_len = strlen(b64) + 1; ++ talloc_free(_secret.data); ++ break; ++ default: ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unknown encryption type '%d'\n", enctype); + return EINVAL; + } + +- ret = sss_encrypt(mem_ctx, AES256CBC_HMAC_SHA256, +- (uint8_t *)sec_ctx->master_key.data, +- sec_ctx->master_key.length, +- (const uint8_t *)secret, strlen(secret) + 1, +- (uint8_t **)&_secret.data, &_secret.length); +- if (ret) { +- DEBUG(SSSDBG_OP_FAILURE, +- "sss_encrypt failed [%d]: %s\n", ret, sss_strerror(ret)); +- return ret; ++ if (output == NULL) { ++ return ENOMEM; + } + +- output = sss_base64_encode(mem_ctx, +- (uint8_t *)_secret.data, _secret.length); +- talloc_free(_secret.data); +- if (!output) return ENOMEM; ++ *_output = output; ++ *_output_len = output_len; + +- *ciphertext = output; + return EOK; + } + +@@ -338,14 +389,14 @@ static int local_check_max_payload_size(struct sss_sec_req *req, + return EOK; + } + +- max_payload_size = req->quota->max_payload_size * 1024; /* kb */ ++ max_payload_size = req->quota->max_payload_size * 1024; /* KiB */ + if (payload_size > max_payload_size) { + DEBUG(SSSDBG_OP_FAILURE, +- "Secrets' payload size [%d kb (%d)] exceeds the maximum allowed " +- "payload size [%d kb (%d)]\n", +- payload_size * 1024, /* kb */ ++ "Secrets' payload size [%d KiB (%d B)] exceeds the maximum " ++ "allowed payload size [%d KiB (%d B)]\n", ++ payload_size / 1024, /* KiB */ + payload_size, +- req->quota->max_payload_size, /* kb */ ++ req->quota->max_payload_size, /* KiB */ + max_payload_size); + + return ERR_SEC_PAYLOAD_SIZE_IS_TOO_LARGE; +@@ -404,7 +455,7 @@ static int local_db_create(struct sss_sec_req *req) + ret = local_db_check_containers_nest_level(req, msg->dn); + if (ret != EOK) goto done; + +- ret = ldb_msg_add_string(msg, "type", "container"); ++ ret = ldb_msg_add_string(msg, SEC_ATTR_TYPE, "container"); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "ldb_msg_add_string failed adding type:container [%d]: %s\n", +@@ -412,7 +463,7 @@ static int local_db_create(struct sss_sec_req *req) + goto done; + } + +- ret = ldb_msg_add_fmt(msg, "creationTime", "%lu", time(NULL)); ++ ret = ldb_msg_add_fmt(msg, SEC_ATTR_CTIME, "%lu", time(NULL)); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "ldb_msg_add_string failed adding creationTime [%d]: %s\n", +@@ -892,7 +943,7 @@ errno_t sss_sec_list(TALLOC_CTX *mem_ctx, + size_t *_num_keys) + { + TALLOC_CTX *tmp_ctx; +- static const char *attrs[] = { "secret", NULL }; ++ static const char *attrs[] = { SEC_ATTR_SECRET, NULL }; + struct ldb_result *res; + char **keys; + int ret; +@@ -951,13 +1002,21 @@ done: + + errno_t sss_sec_get(TALLOC_CTX *mem_ctx, + struct sss_sec_req *req, +- char **_secret) ++ uint8_t **_secret, ++ size_t *_secret_len, ++ char **_datatype) + { + TALLOC_CTX *tmp_ctx; +- static const char *attrs[] = { "secret", "enctype", NULL }; ++ static const char *attrs[] = { SEC_ATTR_SECRET, SEC_ATTR_ENCTYPE, ++ SEC_ATTR_TYPE, NULL }; + struct ldb_result *res; +- const char *attr_secret; ++ const struct ldb_val *attr_secret; + const char *attr_enctype; ++ const char *attr_datatype; ++ enum sss_sec_enctype enctype; ++ char *datatype; ++ uint8_t *secret; ++ size_t secret_len; + int ret; + + if (req == NULL || _secret == NULL) { +@@ -996,21 +1055,38 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx, + goto done; + } + +- attr_secret = ldb_msg_find_attr_as_string(res->msgs[0], "secret", NULL); ++ attr_secret = ldb_msg_find_ldb_val(res->msgs[0], SEC_ATTR_SECRET); + if (!attr_secret) { + DEBUG(SSSDBG_CRIT_FAILURE, "The 'secret' attribute is missing\n"); + ret = ENOENT; + goto done; + } + +- attr_enctype = ldb_msg_find_attr_as_string(res->msgs[0], "enctype", NULL); ++ attr_enctype = ldb_msg_find_attr_as_string(res->msgs[0], SEC_ATTR_ENCTYPE, ++ "plaintext"); ++ enctype = sss_sec_str_to_enctype(attr_enctype); ++ ret = local_decrypt(req->sctx, tmp_ctx, attr_secret->data, ++ attr_secret->length, enctype, &secret, &secret_len); ++ if (ret) goto done; + +- if (attr_enctype) { +- ret = local_decrypt(req->sctx, mem_ctx, attr_secret, attr_enctype, _secret); +- if (ret) goto done; +- } else { +- *_secret = talloc_strdup(mem_ctx, attr_secret); ++ if (_datatype != NULL) { ++ attr_datatype = ldb_msg_find_attr_as_string(res->msgs[0], SEC_ATTR_TYPE, ++ "simple"); ++ datatype = talloc_strdup(tmp_ctx, attr_datatype); ++ if (datatype == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ *_datatype = talloc_steal(mem_ctx, datatype); + } ++ ++ *_secret = talloc_steal(mem_ctx, secret); ++ ++ if (_secret_len) { ++ *_secret_len = secret_len; ++ } ++ + ret = EOK; + + done: +@@ -1019,11 +1095,13 @@ done: + } + + errno_t sss_sec_put(struct sss_sec_req *req, +- const char *secret) ++ uint8_t *secret, ++ size_t secret_len, ++ enum sss_sec_enctype enctype, ++ const char *datatype) + { + struct ldb_message *msg; +- const char *enctype = "masterkey"; +- char *enc_secret; ++ struct ldb_val enc_secret; + int ret; + + if (req == NULL || secret == NULL) { +@@ -1064,7 +1142,7 @@ errno_t sss_sec_put(struct sss_sec_req *req, + goto done; + } + +- ret = local_check_max_payload_size(req, strlen(secret)); ++ ret = local_check_max_payload_size(req, secret_len); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "local_check_max_payload_size failed [%d]: %s\n", +@@ -1072,22 +1150,24 @@ errno_t sss_sec_put(struct sss_sec_req *req, + goto done; + } + +- ret = local_encrypt(req->sctx, msg, secret, enctype, &enc_secret); ++ ret = local_encrypt(req->sctx, msg, secret, secret_len, enctype, ++ &enc_secret.data, &enc_secret.length); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "local_encrypt failed [%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + +- ret = ldb_msg_add_string(msg, "type", "simple"); ++ ret = ldb_msg_add_string(msg, SEC_ATTR_TYPE, datatype); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +- "ldb_msg_add_string failed adding type:simple [%d]: %s\n", +- ret, sss_strerror(ret)); ++ "ldb_msg_add_string failed adding type:%s [%d]: %s\n", ++ datatype, ret, sss_strerror(ret)); + goto done; + } + +- ret = ldb_msg_add_string(msg, "enctype", enctype); ++ ret = ldb_msg_add_string(msg, SEC_ATTR_ENCTYPE, ++ sss_sec_enctype_to_str(enctype)); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "ldb_msg_add_string failed adding enctype [%d]: %s\n", +@@ -1095,7 +1175,7 @@ errno_t sss_sec_put(struct sss_sec_req *req, + goto done; + } + +- ret = ldb_msg_add_string(msg, "secret", enc_secret); ++ ret = ldb_msg_add_value(msg, SEC_ATTR_SECRET, &enc_secret, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "ldb_msg_add_string failed adding secret [%d]: %s\n", +@@ -1103,7 +1183,7 @@ errno_t sss_sec_put(struct sss_sec_req *req, + goto done; + } + +- ret = ldb_msg_add_fmt(msg, "creationTime", "%lu", time(NULL)); ++ ret = ldb_msg_add_fmt(msg, SEC_ATTR_CTIME, "%lu", time(NULL)); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "ldb_msg_add_string failed adding creationTime [%d]: %s\n", +@@ -1132,11 +1212,13 @@ done: + } + + errno_t sss_sec_update(struct sss_sec_req *req, +- const char *secret) ++ uint8_t *secret, ++ size_t secret_len, ++ enum sss_sec_enctype enctype, ++ const char *datatype) + { + struct ldb_message *msg; +- const char *enctype = "masterkey"; +- char *enc_secret; ++ struct ldb_val enc_secret; + int ret; + + if (req == NULL || secret == NULL) { +@@ -1177,7 +1259,7 @@ errno_t sss_sec_update(struct sss_sec_req *req, + goto done; + } + +- ret = local_check_max_payload_size(req, strlen(secret)); ++ ret = local_check_max_payload_size(req, secret_len); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "local_check_max_payload_size failed [%d]: %s\n", +@@ -1185,15 +1267,49 @@ errno_t sss_sec_update(struct sss_sec_req *req, + goto done; + } + +- ret = local_encrypt(req->sctx, msg, secret, enctype, &enc_secret); ++ ret = local_encrypt(req->sctx, msg, secret, secret_len, enctype, ++ &enc_secret.data, &enc_secret.length); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "local_encrypt failed [%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + ++ ret = ldb_msg_add_empty(msg, SEC_ATTR_ENCTYPE, LDB_FLAG_MOD_REPLACE, NULL); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "ldb_msg_add_empty failed: [%s]\n", ldb_strerror(ret)); ++ ret = EIO; ++ goto done; ++ } ++ ++ ret = ldb_msg_add_string(msg, SEC_ATTR_ENCTYPE, ++ sss_sec_enctype_to_str(enctype)); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "ldb_msg_add_string failed adding enctype [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = ldb_msg_add_empty(msg, SEC_ATTR_TYPE, LDB_FLAG_MOD_REPLACE, NULL); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "ldb_msg_add_empty failed: [%s]\n", ldb_strerror(ret)); ++ ret = EIO; ++ goto done; ++ } ++ ++ ret = ldb_msg_add_string(msg, SEC_ATTR_TYPE, datatype); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "ldb_msg_add_string failed adding type:%s [%d]: %s\n", ++ datatype, ret, sss_strerror(ret)); ++ goto done; ++ } ++ + /* FIXME - should we have a lastUpdate timestamp? */ +- ret = ldb_msg_add_empty(msg, "secret", LDB_FLAG_MOD_REPLACE, NULL); ++ ret = ldb_msg_add_empty(msg, SEC_ATTR_SECRET, LDB_FLAG_MOD_REPLACE, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(SSSDBG_MINOR_FAILURE, + "ldb_msg_add_empty failed: [%s]\n", ldb_strerror(ret)); +@@ -1201,7 +1317,7 @@ errno_t sss_sec_update(struct sss_sec_req *req, + goto done; + } + +- ret = ldb_msg_add_string(msg, "secret", enc_secret); ++ ret = ldb_msg_add_value(msg, SEC_ATTR_SECRET, &enc_secret, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(SSSDBG_MINOR_FAILURE, + "ldb_msg_add_string failed: [%s]\n", ldb_strerror(ret)); +diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h +index 9cf397516..f79bfaa4b 100644 +--- a/src/util/secrets/secrets.h ++++ b/src/util/secrets/secrets.h +@@ -43,6 +43,12 @@ + #define DEFAULT_SEC_KCM_MAX_UID_SECRETS 64 + #define DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE 65536 + ++enum sss_sec_enctype { ++ SSS_SEC_PLAINTEXT, ++ SSS_SEC_MASTERKEY, ++ SSS_SEC_ENCTYPE_SENTINEL ++}; ++ + struct sss_sec_ctx; + + struct sss_sec_req; +@@ -88,13 +94,21 @@ errno_t sss_sec_list(TALLOC_CTX *mem_ctx, + + errno_t sss_sec_get(TALLOC_CTX *mem_ctx, + struct sss_sec_req *req, +- char **_secret); ++ uint8_t **_secret, ++ size_t *_secret_len, ++ char **_datatype); + + errno_t sss_sec_put(struct sss_sec_req *req, +- const char *secret); ++ uint8_t *secret, ++ size_t secret_len, ++ enum sss_sec_enctype enctype, ++ const char *datatype); + + errno_t sss_sec_update(struct sss_sec_req *req, +- const char *secret); ++ uint8_t *secret, ++ size_t secret_len, ++ enum sss_sec_enctype enctype, ++ const char *datatype); + + errno_t sss_sec_create_container(struct sss_sec_req *req); + +diff --git a/src/util/sss_iobuf.c b/src/util/sss_iobuf.c +index 518713e4c..3056a7b0d 100644 +--- a/src/util/sss_iobuf.c ++++ b/src/util/sss_iobuf.c +@@ -66,6 +66,30 @@ struct sss_iobuf *sss_iobuf_init_readonly(TALLOC_CTX *mem_ctx, + return iobuf; + } + ++struct sss_iobuf *sss_iobuf_init_steal(TALLOC_CTX *mem_ctx, ++ uint8_t *data, ++ size_t size) ++{ ++ struct sss_iobuf *iobuf; ++ ++ iobuf = talloc_zero(mem_ctx, struct sss_iobuf); ++ if (iobuf == NULL) { ++ return NULL; ++ } ++ ++ iobuf->data = talloc_steal(iobuf, data); ++ iobuf->size = size; ++ iobuf->capacity = size; ++ iobuf->dp = 0; ++ ++ return iobuf; ++} ++ ++void sss_iobuf_cursor_reset(struct sss_iobuf *iobuf) ++{ ++ iobuf->dp = 0; ++} ++ + size_t sss_iobuf_get_len(struct sss_iobuf *iobuf) + { + if (iobuf == NULL) { +@@ -223,6 +247,109 @@ errno_t sss_iobuf_write_len(struct sss_iobuf *iobuf, + return EOK; + } + ++errno_t sss_iobuf_read_varlen(TALLOC_CTX *mem_ctx, ++ struct sss_iobuf *iobuf, ++ uint8_t **_out, ++ size_t *_len) ++{ ++ uint8_t *out; ++ uint32_t len; ++ size_t slen; ++ errno_t ret; ++ ++ if (iobuf == NULL || _out == NULL || _len == NULL) { ++ return EINVAL; ++ } ++ ++ ret = sss_iobuf_read_uint32(iobuf, &len); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ if (len == 0) { ++ *_out = NULL; ++ *_len = 0; ++ return EOK; ++ } ++ ++ out = talloc_array(mem_ctx, uint8_t, len); ++ if (out == NULL) { ++ return ENOMEM; ++ } ++ ++ slen = len; ++ ret = sss_iobuf_read_len(iobuf, slen, out); ++ if (ret != EOK) { ++ talloc_free(out); ++ return ret; ++ } ++ ++ *_out = out; ++ *_len = slen; ++ ++ return EOK; ++} ++ ++errno_t sss_iobuf_write_varlen(struct sss_iobuf *iobuf, ++ uint8_t *data, ++ size_t len) ++{ ++ errno_t ret; ++ ++ if (iobuf == NULL || (data == NULL && len != 0)) { ++ return EINVAL; ++ } ++ ++ ret = sss_iobuf_write_uint32(iobuf, len); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ if (len == 0) { ++ return EOK; ++ } ++ ++ return sss_iobuf_write_len(iobuf, data, len); ++} ++ ++errno_t sss_iobuf_read_iobuf(TALLOC_CTX *mem_ctx, ++ struct sss_iobuf *iobuf, ++ struct sss_iobuf **_out) ++{ ++ struct sss_iobuf *out; ++ uint8_t *data; ++ size_t len; ++ errno_t ret; ++ ++ ret = sss_iobuf_read_varlen(NULL, iobuf, &data, &len); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ out = sss_iobuf_init_steal(mem_ctx, data, len); ++ if (out == NULL) { ++ return ENOMEM; ++ } ++ ++ *_out = out; ++ ++ return EOK; ++} ++ ++errno_t sss_iobuf_write_iobuf(struct sss_iobuf *iobuf, ++ struct sss_iobuf *data) ++{ ++ return sss_iobuf_write_varlen(iobuf, data->data, data->size); ++} ++ ++errno_t sss_iobuf_read_uint8(struct sss_iobuf *iobuf, ++ uint8_t *_val) ++{ ++ SAFEALIGN_COPY_UINT8_CHECK(_val, iobuf_ptr(iobuf), ++ iobuf->capacity, &iobuf->dp); ++ return EOK; ++} ++ + errno_t sss_iobuf_read_uint32(struct sss_iobuf *iobuf, + uint32_t *_val) + { +@@ -239,6 +366,20 @@ errno_t sss_iobuf_read_int32(struct sss_iobuf *iobuf, + return EOK; + } + ++errno_t sss_iobuf_write_uint8(struct sss_iobuf *iobuf, ++ uint8_t val) ++{ ++ errno_t ret; ++ ++ ret = ensure_bytes(iobuf, sizeof(uint8_t)); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ SAFEALIGN_SETMEM_UINT8(iobuf_ptr(iobuf), val, &iobuf->dp); ++ return EOK; ++} ++ + errno_t sss_iobuf_write_uint32(struct sss_iobuf *iobuf, + uint32_t val) + { +diff --git a/src/util/sss_iobuf.h b/src/util/sss_iobuf.h +index cc3dfd1e9..159fbc0b9 100644 +--- a/src/util/sss_iobuf.h ++++ b/src/util/sss_iobuf.h +@@ -50,6 +50,29 @@ struct sss_iobuf *sss_iobuf_init_readonly(TALLOC_CTX *mem_ctx, + const uint8_t *data, + size_t size); + ++/* ++ * @brief Allocate an IO buffer with a fixed size, stealing input data. ++ * ++ * This function is useful for parsing an input buffer from an existing ++ * buffer pointed to by data. ++ * ++ * The iobuf assumes ownership of the data buffer. ++ * ++ * @param[in] mem_ctx The talloc context that owns the iobuf ++ * @param[in] data The data to initialize the IO buffer with. ++ * @param[in] size The size of the data buffer ++ * ++ * @return The newly created buffer on success or NULL on an error. ++ */ ++struct sss_iobuf *sss_iobuf_init_steal(TALLOC_CTX *mem_ctx, ++ uint8_t *data, ++ size_t size); ++ ++/* ++ * @brief Reset internal cursor of the IO buffer (seek to the start) ++ */ ++void sss_iobuf_cursor_reset(struct sss_iobuf *iobuf); ++ + /* + * @brief Returns the number of bytes currently stored in the iobuf + * +@@ -131,6 +154,28 @@ errno_t sss_iobuf_write_len(struct sss_iobuf *iobuf, + uint8_t *buf, + size_t len); + ++errno_t sss_iobuf_read_varlen(TALLOC_CTX *mem_ctx, ++ struct sss_iobuf *iobuf, ++ uint8_t **_out, ++ size_t *_len); ++ ++errno_t sss_iobuf_write_varlen(struct sss_iobuf *iobuf, ++ uint8_t *data, ++ size_t len); ++ ++errno_t sss_iobuf_read_iobuf(TALLOC_CTX *mem_ctx, ++ struct sss_iobuf *iobuf, ++ struct sss_iobuf **_out); ++ ++errno_t sss_iobuf_write_iobuf(struct sss_iobuf *iobuf, ++ struct sss_iobuf *data); ++ ++errno_t sss_iobuf_read_uint8(struct sss_iobuf *iobuf, ++ uint8_t *_val); ++ ++errno_t sss_iobuf_write_uint8(struct sss_iobuf *iobuf, ++ uint8_t val); ++ + errno_t sss_iobuf_read_uint32(struct sss_iobuf *iobuf, + uint32_t *_val); + +@@ -148,4 +193,5 @@ errno_t sss_iobuf_read_stringz(struct sss_iobuf *iobuf, + + errno_t sss_iobuf_write_stringz(struct sss_iobuf *iobuf, + const char *str); ++ + #endif /* __SSS_IOBUF_H_ */ +diff --git a/src/util/sss_ptr_hash.c b/src/util/sss_ptr_hash.c +index 6409236c7..e3805dac4 100644 +--- a/src/util/sss_ptr_hash.c ++++ b/src/util/sss_ptr_hash.c +@@ -54,6 +54,7 @@ struct sss_ptr_hash_value { + hash_table_t *table; + const char *key; + void *payload; ++ bool delete_in_progress; + }; + + static int +@@ -61,12 +62,22 @@ sss_ptr_hash_value_destructor(struct sss_ptr_hash_value *value) + { + hash_key_t table_key; + ++ /* Do not call hash_delete() if we got here from hash delete callback when ++ * the callback calls talloc_free(payload) which frees the value. This ++ * should not happen since talloc will avoid circular free but let's be ++ * over protective here. */ ++ if (value->delete_in_progress) { ++ return 0; ++ } ++ ++ value->delete_in_progress = true; + if (value->table && value->key) { + table_key.type = HASH_KEY_STRING; + table_key.str = discard_const_p(char, value->key); + if (hash_delete(value->table, &table_key) != HASH_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, + "failed to delete entry with key '%s'\n", value->key); ++ value->delete_in_progress = false; + } + } + +@@ -127,6 +138,15 @@ sss_ptr_hash_delete_cb(hash_entry_t *item, + callback_entry.key = item->key; + callback_entry.value.type = HASH_VALUE_PTR; + callback_entry.value.ptr = value->payload; ++ ++ /* Delete the value in case this callback has been called directly ++ * from dhash (overwriting existing entry) instead of hash_delete() ++ * in value's destructor. */ ++ if (!value->delete_in_progress) { ++ talloc_set_destructor(value, NULL); ++ talloc_free(value); ++ } ++ + /* Even if execution is already in the context of + * talloc_free(payload) -> talloc_free(value) -> ... + * there still might be legitimate reasons to execute callback. +-- +2.21.3 + diff --git a/SOURCES/0002-test-avoid-endian-issues-in-network-tests.patch b/SOURCES/0002-test-avoid-endian-issues-in-network-tests.patch deleted file mode 100644 index 9a6d266..0000000 --- a/SOURCES/0002-test-avoid-endian-issues-in-network-tests.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 532b75c937d767caf60bb00f1a525ae7f6c70cc6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pavel=20B=C5=99ezina?= -Date: Wed, 20 May 2020 12:07:13 +0200 -Subject: [PATCH] test: avoid endian issues in network tests - -Reviewed-by: Alexey Tikhonov ---- - src/tests/cmocka/test_nss_srv.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c -index 2c91d0a23..3cd7809cf 100644 ---- a/src/tests/cmocka/test_nss_srv.c -+++ b/src/tests/cmocka/test_nss_srv.c -@@ -35,6 +35,7 @@ - #include "util/util_sss_idmap.h" - #include "util/crypto/sss_crypto.h" - #include "util/crypto/nss/nss_util.h" -+#include "util/sss_endian.h" - #include "db/sysdb_private.h" /* new_subdomain() */ - #include "db/sysdb_iphosts.h" - #include "db/sysdb_ipnetworks.h" -@@ -5308,7 +5309,13 @@ struct netent test_netent = { - .n_name = discard_const("test_network"), - .n_aliases = discard_const(test_netent_aliases), - .n_addrtype = AF_INET, -+#if (__BYTE_ORDER == __LITTLE_ENDIAN) - .n_net = 0x04030201 /* 1.2.3.4 */ -+#elif (__BYTE_ORDER == __BIG_ENDIAN) -+ .n_net = 0x01020304 /* 1.2.3.4 */ -+#else -+ #error "unknow endianess" -+#endif - }; - - static void mock_input_netbyname(const char *name) --- -2.21.1 - diff --git a/SOURCES/0003-DEBUG-journal_send-was-made-static.patch b/SOURCES/0003-DEBUG-journal_send-was-made-static.patch new file mode 100644 index 0000000..faa9c9e --- /dev/null +++ b/SOURCES/0003-DEBUG-journal_send-was-made-static.patch @@ -0,0 +1,29 @@ +From 833034f5332d2492d413a9c97fded1480b58bf14 Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Wed, 21 Oct 2020 18:47:32 +0200 +Subject: [PATCH 3/4] DEBUG: journal_send() was made static +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Tomáš Halman +--- + src/util/debug.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/util/debug.c b/src/util/debug.c +index 1d5f75e4d..c162987b9 100644 +--- a/src/util/debug.c ++++ b/src/util/debug.c +@@ -201,7 +201,7 @@ static void debug_printf(const char *format, ...) + } + + #ifdef WITH_JOURNALD +-errno_t journal_send(const char *file, ++static errno_t journal_send(const char *file, + long line, + const char *function, + int level, +-- +2.21.3 + diff --git a/SOURCES/0003-sssctl-sssctl-config-check-alternative-config-file.patch b/SOURCES/0003-sssctl-sssctl-config-check-alternative-config-file.patch deleted file mode 100644 index 9934c57..0000000 --- a/SOURCES/0003-sssctl-sssctl-config-check-alternative-config-file.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 61f4aaa56ea876fb75c1366c938818b7799408ab Mon Sep 17 00:00:00 2001 -From: Tomas Halman -Date: Wed, 29 Apr 2020 16:40:36 +0200 -Subject: [PATCH] sssctl: sssctl config-check alternative config file - -The sssctl config-check now allows to specify alternative config -file so it can be tested before rewriting system configuration. - - sssctl config-check -c ./sssd.conf - -Configuration snippets are looked up in the same place under -conf.d directory. It would be in ./conf.d/ for the example above. - -Resolves: -https://github.com/SSSD/sssd/issues/5142 - -Reviewed-by: Pawel Polawski ---- - src/confdb/confdb.h | 6 ++-- - src/tools/sssctl/sssctl_config.c | 56 ++++++++++++++++++++++++++++---- - 2 files changed, 53 insertions(+), 9 deletions(-) - -diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h -index 0a5593232..a2b58e12a 100644 ---- a/src/confdb/confdb.h -+++ b/src/confdb/confdb.h -@@ -40,8 +40,10 @@ - - #define CONFDB_DEFAULT_CFG_FILE_VER 2 - #define CONFDB_FILE "config.ldb" --#define SSSD_CONFIG_FILE SSSD_CONF_DIR"/sssd.conf" --#define CONFDB_DEFAULT_CONFIG_DIR SSSD_CONF_DIR"/conf.d" -+#define SSSD_CONFIG_FILE_NAME "sssd.conf" -+#define SSSD_CONFIG_FILE SSSD_CONF_DIR"/"SSSD_CONFIG_FILE_NAME -+#define CONFDB_DEFAULT_CONFIG_DIR_NAME "conf.d" -+#define CONFDB_DEFAULT_CONFIG_DIR SSSD_CONF_DIR"/"CONFDB_DEFAULT_CONFIG_DIR_NAME - #define SSSD_MIN_ID 1 - #define SSSD_LOCAL_MINID 1000 - #define CONFDB_DEFAULT_SHELL_FALLBACK "/bin/sh" -diff --git a/src/tools/sssctl/sssctl_config.c b/src/tools/sssctl/sssctl_config.c -index 74395b61c..de9f3de6e 100644 ---- a/src/tools/sssctl/sssctl_config.c -+++ b/src/tools/sssctl/sssctl_config.c -@@ -34,6 +34,29 @@ - - - #ifdef HAVE_LIBINI_CONFIG_V1_3 -+ -+static char *sssctl_config_snippet_path(TALLOC_CTX *ctx, const char *path) -+{ -+ char *tmp = NULL; -+ const char delimiter = '/'; -+ char *dpos = NULL; -+ -+ tmp = talloc_strdup(ctx, path); -+ if (!tmp) { -+ return NULL; -+ } -+ -+ dpos = strrchr(tmp, delimiter); -+ if (dpos != NULL) { -+ ++dpos; -+ *dpos = '\0'; -+ } else { -+ *tmp = '\0'; -+ } -+ -+ return talloc_strdup_append(tmp, CONFDB_DEFAULT_CONFIG_DIR_NAME); -+} -+ - errno_t sssctl_config_check(struct sss_cmdline *cmdline, - struct sss_tool_ctx *tool_ctx, - void *pvt) -@@ -47,8 +70,15 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline, - size_t num_ra_error, num_ra_success; - char **strs = NULL; - TALLOC_CTX *tmp_ctx = NULL; -- -- ret = sss_tool_popt(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL, NULL, NULL); -+ const char *config_path = NULL; -+ const char *config_snippet_path = NULL; -+ struct poptOption long_options[] = { -+ {"config", 'c', POPT_ARG_STRING, &config_path, -+ 0, _("Specify a non-default config file"), NULL}, -+ POPT_TABLEEND -+ }; -+ -+ ret = sss_tool_popt(cmdline, long_options, SSS_TOOL_OPT_OPTIONAL, NULL, NULL); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); - return ret; -@@ -62,17 +92,29 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline, - goto done; - } - -+ if (config_path != NULL) { -+ config_snippet_path = sssctl_config_snippet_path(tmp_ctx, config_path); -+ if (config_snippet_path == NULL) { -+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create snippet path\n"); -+ ret = ENOMEM; -+ goto done; -+ } -+ } else { -+ config_path = SSSD_CONFIG_FILE; -+ config_snippet_path = CONFDB_DEFAULT_CONFIG_DIR; -+ } -+ - ret = sss_ini_read_sssd_conf(init_data, -- SSSD_CONFIG_FILE, -- CONFDB_DEFAULT_CONFIG_DIR); -+ config_path, -+ config_snippet_path); - - if (ret == ERR_INI_OPEN_FAILED) { -- PRINT("Failed to open %s\n", SSSD_CONFIG_FILE); -+ PRINT("Failed to open %s\n", config_path); - goto done; - } - - if (!sss_ini_exists(init_data)) { -- PRINT("File %1$s does not exist.\n", SSSD_CONFIG_FILE); -+ PRINT("File %1$s does not exist.\n", config_path); - } - - if (ret == ERR_INI_INVALID_PERMISSION) { -@@ -83,7 +125,7 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline, - - if (ret == ERR_INI_PARSE_FAILED) { - PRINT("Failed to load configuration from %s.\n", -- SSSD_CONFIG_FILE); -+ config_path); - goto done; - } - --- -2.21.1 - diff --git a/SOURCES/0004-DEBUG-fixes-program-identifier-as-seen-in-syslog.patch b/SOURCES/0004-DEBUG-fixes-program-identifier-as-seen-in-syslog.patch new file mode 100644 index 0000000..8352ea6 --- /dev/null +++ b/SOURCES/0004-DEBUG-fixes-program-identifier-as-seen-in-syslog.patch @@ -0,0 +1,71 @@ +From 18233532b72e62452eac6886652fa633ba055d8c Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Wed, 21 Oct 2020 19:20:03 +0200 +Subject: [PATCH 4/4] DEBUG: fixes program identifier as seen in syslog +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 225fe9950f2807d5fb226f6b3be1ff4cefd731f0 changed `debug_prg_name` +to accomodate needs of own SSSD logs, but this affected journal/syslog +as well. + +This patch amends situation: + - journal messages gets "umbrella" identifier "sssd[]" + - syslog uses default which is program name + +Resolves: https://github.com/SSSD/sssd/issues/5384 + +Reviewed-by: Tomáš Halman +--- + src/util/debug.c | 2 +- + src/util/sss_log.c | 12 +++--------- + 2 files changed, 4 insertions(+), 10 deletions(-) + +diff --git a/src/util/debug.c b/src/util/debug.c +index c162987b9..f05b26500 100644 +--- a/src/util/debug.c ++++ b/src/util/debug.c +@@ -250,7 +250,7 @@ static errno_t journal_send(const char *file, + "MESSAGE=%s", message, + "PRIORITY=%i", LOG_DEBUG, + "SSSD_DOMAIN=%s", domain, +- "SSSD_PRG_NAME=%s", debug_prg_name, ++ "SSSD_PRG_NAME=sssd[%s]", debug_prg_name, + "SSSD_DEBUG_LEVEL=%x", level, + NULL); + ret = -res; +diff --git a/src/util/sss_log.c b/src/util/sss_log.c +index 48e73dbea..c6b7435c6 100644 +--- a/src/util/sss_log.c ++++ b/src/util/sss_log.c +@@ -107,7 +107,7 @@ static void sss_log_internal(int priority, int facility, const char *format, + "SSSD_DOMAIN=%s", domain, + "PRIORITY=%i", syslog_priority, + "SYSLOG_FACILITY=%i", LOG_FAC(facility), +- "SYSLOG_IDENTIFIER=%s", debug_prg_name, ++ "SYSLOG_IDENTIFIER=sssd[%s]", debug_prg_name, + NULL); + + free(message); +@@ -118,15 +118,9 @@ static void sss_log_internal(int priority, int facility, const char *format, + static void sss_log_internal(int priority, int facility, const char *format, + va_list ap) + { +- int syslog_priority; +- +- syslog_priority = sss_to_syslog(priority); +- +- openlog(debug_prg_name, 0, facility); +- +- vsyslog(syslog_priority, format, ap); ++ int syslog_priority = sss_to_syslog(priority); + +- closelog(); ++ vsyslog(facility|syslog_priority, format, ap); + } + + #endif /* WITH_JOURNALD */ +-- +2.21.3 + diff --git a/SOURCES/0005-negcache-make-sure-domain-config-does-not-leak-into-.patch b/SOURCES/0005-negcache-make-sure-domain-config-does-not-leak-into-.patch new file mode 100644 index 0000000..8aeda8b --- /dev/null +++ b/SOURCES/0005-negcache-make-sure-domain-config-does-not-leak-into-.patch @@ -0,0 +1,36 @@ +From 0e1bcf77bd73baa0fea64830eb1f4f65a63c7afe Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 8 Oct 2020 12:18:41 +0200 +Subject: [PATCH 5/8] negcache: make sure domain config does not leak into + global + +Resolves: https://github.com/SSSD/sssd/issues/5238 + +Reviewed-by: Alexey Tikhonov +--- + src/responder/common/negcache.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c +index ce1c0ab8c..139218420 100644 +--- a/src/responder/common/negcache.c ++++ b/src/responder/common/negcache.c +@@ -1050,6 +1050,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + } + } + ++ talloc_zfree(filter_list); + /* Populate non domain-specific negative cache user entries */ + ret = confdb_get_string_as_list(cdb, tmpctx, CONFDB_NSS_CONF_ENTRY, + CONFDB_NSS_FILTER_USERS, &filter_list); +@@ -1185,6 +1186,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + } + } + ++ talloc_zfree(filter_list); + /* Populate non domain-specific negative cache group entries */ + ret = confdb_get_string_as_list(cdb, tmpctx, CONFDB_NSS_CONF_ENTRY, + CONFDB_NSS_FILTER_GROUPS, &filter_list); +-- +2.21.3 + diff --git a/SOURCES/0006-utils-add-SSS_GND_SUBDOMAINS-flag-for-get_next_domai.patch b/SOURCES/0006-utils-add-SSS_GND_SUBDOMAINS-flag-for-get_next_domai.patch new file mode 100644 index 0000000..e3aeec3 --- /dev/null +++ b/SOURCES/0006-utils-add-SSS_GND_SUBDOMAINS-flag-for-get_next_domai.patch @@ -0,0 +1,106 @@ +From 385af99ff4d5a75d0c1edc9ad830da3eb7478295 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 8 Oct 2020 17:57:29 +0200 +Subject: [PATCH 6/8] utils: add SSS_GND_SUBDOMAINS flag for get_next_domain() + +To allow to only iterate over a singel domain an its sub-domains a new +flag is added to get_next_domain(). + +Resolves: https://github.com/SSSD/sssd/issues/5238 + +Reviewed-by: Alexey Tikhonov +--- + src/tests/cmocka/test_utils.c | 31 +++++++++++++++++++++++++++++++ + src/util/domain_info_utils.c | 10 +++++++--- + src/util/util.h | 4 ++++ + 3 files changed, 42 insertions(+), 3 deletions(-) + +diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c +index 945f5cb44..d77a972c1 100644 +--- a/src/tests/cmocka/test_utils.c ++++ b/src/tests/cmocka/test_utils.c +@@ -877,6 +877,37 @@ static void test_get_next_domain_flags(void **state) + + dom = get_next_domain(dom, gnd_flags); + assert_null(dom); ++ ++ /* Descend only to subdomains */ ++ gnd_flags = SSS_GND_SUBDOMAINS | SSS_GND_INCLUDE_DISABLED; ++ ++ dom = get_next_domain(test_ctx->dom_list, gnd_flags); ++ assert_non_null(dom); ++ assert_string_equal(dom->name, "sub1a"); ++ ++ dom = get_next_domain(dom, gnd_flags); ++ assert_null(dom); ++ ++ dom = find_domain_by_name_ex(test_ctx->dom_list, "dom2", true, ++ SSS_GND_ALL_DOMAINS); ++ assert_non_null(dom); ++ assert_string_equal(dom->name, "dom2"); ++ ++ dom = get_next_domain(dom, gnd_flags); ++ assert_non_null(dom); ++ assert_string_equal(dom->name, "sub2a"); ++ ++ dom = get_next_domain(dom, gnd_flags); ++ assert_non_null(dom); ++ assert_string_equal(dom->name, "sub2b"); ++ ++ dom = get_next_domain(dom, gnd_flags); ++ assert_null(dom); ++ ++ /* Expect NULL if the domain has no sub-domains */ ++ test_ctx->dom_list->subdomains = NULL; ++ dom = get_next_domain(test_ctx->dom_list, gnd_flags); ++ assert_null(dom); + } + + struct name_init_test_ctx { +diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c +index aa3582f03..4d4726daa 100644 +--- a/src/util/domain_info_utils.c ++++ b/src/util/domain_info_utils.c +@@ -39,16 +39,20 @@ struct sss_domain_info *get_next_domain(struct sss_domain_info *domain, + uint32_t gnd_flags) + { + struct sss_domain_info *dom; +- bool descend = gnd_flags & SSS_GND_DESCEND; ++ bool descend = gnd_flags & (SSS_GND_DESCEND | SSS_GND_SUBDOMAINS); + bool include_disabled = gnd_flags & SSS_GND_INCLUDE_DISABLED; ++ bool only_subdomains = gnd_flags & SSS_GND_SUBDOMAINS; + + dom = domain; + while (dom) { + if (descend && dom->subdomains) { + dom = dom->subdomains; +- } else if (dom->next) { ++ } else if (dom->next && only_subdomains && IS_SUBDOMAIN(dom)) { + dom = dom->next; +- } else if (descend && IS_SUBDOMAIN(dom) && dom->parent->next) { ++ } else if (dom->next && !only_subdomains) { ++ dom = dom->next; ++ } else if (descend && !only_subdomains && IS_SUBDOMAIN(dom) ++ && dom->parent->next) { + dom = dom->parent->next; + } else { + dom = NULL; +diff --git a/src/util/util.h b/src/util/util.h +index fbcac5cd0..581c0edfb 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -565,7 +565,11 @@ struct sss_domain_info *get_domains_head(struct sss_domain_info *domain); + + #define SSS_GND_DESCEND 0x01 + #define SSS_GND_INCLUDE_DISABLED 0x02 ++/* Descend to sub-domains of current domain but do not go to next parent */ ++#define SSS_GND_SUBDOMAINS 0x04 + #define SSS_GND_ALL_DOMAINS (SSS_GND_DESCEND | SSS_GND_INCLUDE_DISABLED) ++#define SSS_GND_ALL_SUBDOMAINS (SSS_GND_SUBDOMAINS | SSS_GND_INCLUDE_DISABLED) ++ + struct sss_domain_info *get_next_domain(struct sss_domain_info *domain, + uint32_t gnd_flags); + struct sss_domain_info *find_domain_by_name(struct sss_domain_info *domain, +-- +2.21.3 + diff --git a/SOURCES/0007-negcache-make-sure-short-names-are-added-to-sub-doma.patch b/SOURCES/0007-negcache-make-sure-short-names-are-added-to-sub-doma.patch new file mode 100644 index 0000000..9d405fc --- /dev/null +++ b/SOURCES/0007-negcache-make-sure-short-names-are-added-to-sub-doma.patch @@ -0,0 +1,443 @@ +From 0dc81a52e2836010974e9f71b1f3e47c20fd498d Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 9 Oct 2020 11:56:21 +0200 +Subject: [PATCH 7/8] negcache: make sure short names are added to sub-domains + +If short names are used with filter_users or filter_groups in a +[domain/...] section they should be added to the sub-domains of this +domain as well. + +Resolves: https://github.com/SSSD/sssd/issues/5238 + +Reviewed-by: Alexey Tikhonov +--- + src/responder/common/negcache.c | 105 +++++++------ + src/tests/cmocka/test_negcache.c | 254 +++++++++++++++++++++++++++++++ + 2 files changed, 312 insertions(+), 47 deletions(-) + +diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c +index 139218420..9ee39ce3e 100644 +--- a/src/responder/common/negcache.c ++++ b/src/responder/common/negcache.c +@@ -971,6 +971,7 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + char *name = NULL; + struct sss_domain_info *dom = NULL; + struct sss_domain_info *domain_list = rctx->domains; ++ struct sss_domain_info *ddom; + char *domainname = NULL; + char *conf_path = NULL; + TALLOC_CTX *tmpctx = talloc_new(NULL); +@@ -1013,39 +1014,44 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + continue; + } + +- if (domainname && strcmp(domainname, dom->name)) { +- DEBUG(SSSDBG_TRACE_FUNC, +- "Mismatch between domain name (%s) and name " +- "set in FQN (%s), assuming %s is UPN\n", +- dom->name, domainname, filter_list[i]); +- ret = sss_ncache_set_upn(ncache, true, dom, filter_list[i]); ++ /* Check domain and its sub-domains */ ++ for (ddom = dom; ddom != NULL; ++ ddom = get_next_domain(ddom, SSS_GND_ALL_SUBDOMAINS)) { ++ ++ if (domainname && strcmp(domainname, ddom->name)) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Mismatch between domain name (%s) and name " ++ "set in FQN (%s), assuming %s is UPN\n", ++ ddom->name, domainname, filter_list[i]); ++ ret = sss_ncache_set_upn(ncache, true, ddom, filter_list[i]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sss_ncache_set_upn failed (%d [%s]), ignored\n", ++ ret, sss_strerror(ret)); ++ } ++ continue; ++ } ++ ++ fqname = sss_create_internal_fqname(tmpctx, name, ddom->name); ++ if (fqname == NULL) { ++ continue; ++ } ++ ++ ret = sss_ncache_set_upn(ncache, true, ddom, fqname); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "sss_ncache_set_upn failed (%d [%s]), ignored\n", + ret, sss_strerror(ret)); + } +- continue; +- } +- +- fqname = sss_create_internal_fqname(tmpctx, name, dom->name); +- if (fqname == NULL) { +- continue; +- } +- +- ret = sss_ncache_set_upn(ncache, true, dom, fqname); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "sss_ncache_set_upn failed (%d [%s]), ignored\n", +- ret, sss_strerror(ret)); +- } +- ret = sss_ncache_set_user(ncache, true, dom, fqname); +- talloc_zfree(fqname); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to store permanent user filter for [%s]" +- " (%d [%s])\n", filter_list[i], +- ret, sss_strerror(ret)); +- continue; ++ ret = sss_ncache_set_user(ncache, true, ddom, fqname); ++ talloc_zfree(fqname); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to store permanent user filter for [%s]" ++ " (%d [%s])\n", filter_list[i], ++ ret, sss_strerror(ret)); ++ continue; ++ } + } + } + } +@@ -1161,27 +1167,32 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + continue; + } + +- if (domainname && strcmp(domainname, dom->name)) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Mismatch between domain name (%s) and name " +- "set in FQN (%s), skipping group %s\n", +- dom->name, domainname, name); +- continue; +- } ++ /* Check domain and its sub-domains */ ++ for (ddom = dom; ++ ddom != NULL && (ddom == dom || ddom->parent != NULL); ++ ddom = get_next_domain(ddom, SSS_GND_ALL_DOMAINS)) { ++ if (domainname && strcmp(domainname, ddom->name)) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Mismatch between domain name (%s) and name " ++ "set in FQN (%s), skipping group %s\n", ++ ddom->name, domainname, name); ++ continue; ++ } + +- fqname = sss_create_internal_fqname(tmpctx, name, dom->name); +- if (fqname == NULL) { +- continue; +- } ++ fqname = sss_create_internal_fqname(tmpctx, name, ddom->name); ++ if (fqname == NULL) { ++ continue; ++ } + +- ret = sss_ncache_set_group(ncache, true, dom, fqname); +- talloc_zfree(fqname); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to store permanent group filter for [%s]" +- " (%d [%s])\n", filter_list[i], +- ret, strerror(ret)); +- continue; ++ ret = sss_ncache_set_group(ncache, true, ddom, fqname); ++ talloc_zfree(fqname); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to store permanent group filter for [%s]" ++ " (%d [%s])\n", filter_list[i], ++ ret, strerror(ret)); ++ continue; ++ } + } + } + } +diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c +index b3a379227..fb306b110 100644 +--- a/src/tests/cmocka/test_negcache.c ++++ b/src/tests/cmocka/test_negcache.c +@@ -119,6 +119,8 @@ static int setup(void **state) + int ret; + struct test_state *ts; + ++ test_dom_suite_setup(TESTS_PATH); ++ + ts = talloc(NULL, struct test_state); + assert_non_null(ts); + +@@ -133,6 +135,7 @@ static int setup(void **state) + static int teardown(void **state) + { + struct test_state *ts = talloc_get_type_abort(*state, struct test_state); ++ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME); + talloc_free(ts); + return 0; + } +@@ -921,6 +924,255 @@ static void test_sss_ncache_reset_prepopulate(void **state) + assert_int_equal(ret, EEXIST); + } + ++/* The main purpose of test_sss_ncache_short_name_in_domain is to test that ++ * short names in the filter_users or filter_groups options in a [domain/...] ++ * section are properly added to the related sub-domains as well (if there are ++ * any) and not added to domains from other [domain/...] sections. For ++ * completeness entries with fully-qualified names of the parent and the ++ * sub-domain and the generic UPN are added as well. ++ * ++ * The result should of course be independent of the present domains. To ++ * verify this the domains are added one after the other and the negative ++ * cache is repopulated each time. ++ * ++ * With the given domains, users and group we have to following expectations: ++ * - the short name entry will be added to the domain and all sub-domains as ++ * name and as upn by expanding it to a fully-qualified name with the ++ * domain name or sub-domain name respectively ++ * - the fully-qualified name from the parent domain is added as name and upn ++ * to the parent domain and as upn to all sub-domains ++ * - the fully-qualified name from the sub-domain is added as name to the ++ * sub-domain and as upn to the parent and all sub-domains ++ * - the generic upn is nowhere added as name and as upn to the parent and all ++ * sub-domains ++ * - none of the names is added to a different parent domain ++ * ++ * The following table should illustrated the expectations: ++ * ++ * user (name): ++ * | shortuser | parentu@TEST_DOM_NAME | subdomu@subTEST_DOM_NAME | upn@upn.dom ++ *-----------------+-----------+-----------------------+--------------------------+------------ ++ * TEST_DOM_NAME | PRESENT | PRESENT | MISSING | MISSING ++ * subTEST_DOM_NAME| PRESENT | MISSING | PRESENT | MISSING ++ * TEST_DOM_NAME2 | MISSING | MISSING | MISSING | MISSING ++ * ++ * user (upn): ++ * | shortuser | parentu@TEST_DOM_NAME | subdomu@subTEST_DOM_NAME | upn@upn.dom ++ *-----------------+-----------+-----------------------+--------------------------+------------ ++ * TEST_DOM_NAME | PRESENT | PRESENT | PRESENT | PRESENT ++ * subTEST_DOM_NAME| PRESENT | PRESENT | PRESENT | PRESENT ++ * TEST_DOM_NAME2 | MISSING | MISSING | MISSING | MISSING ++ * ++ * ++ * ++ * groups: ++ * | shortgroup | parentg@TEST_DOM_NAME | subdomg@subTEST_DOM_NAME ++ *-----------------+------------+-----------------------+------------------------- ++ * TEST_DOM_NAME | PRESENT | PRESENT | MISSING ++ * subTEST_DOM_NAME| PRESENT | MISSING | PRESENT ++ * TEST_DOM_NAME2 | MISSING | MISSING | MISSING ++ * ++ * ++ * The following expect_*() implement checks for the expextations: ++ */ ++ ++static void expect_in_parent(struct sss_nc_ctx *ncache, ++ struct sss_domain_info *dom) ++{ ++ int ret; ++ ++ ret = check_user_in_ncache(ncache, dom, "shortuser"); ++ assert_int_equal(ret, EEXIST); ++ ret = sss_ncache_check_upn(ncache, dom, "shortuser@"TEST_DOM_NAME); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = check_user_in_ncache(ncache, dom, "parentu"); ++ assert_int_equal(ret, EEXIST); ++ ret = sss_ncache_check_upn(ncache, dom, "parentu@"TEST_DOM_NAME); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = check_user_in_ncache(ncache, dom, "subdomu"); ++ assert_int_equal(ret, ENOENT); ++ ret = sss_ncache_check_upn(ncache, dom, "subdomu@sub"TEST_DOM_NAME); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = check_user_in_ncache(ncache, dom, "upn"); ++ assert_int_equal(ret, ENOENT); ++ ret = sss_ncache_check_upn(ncache, dom, "upn@upn.dom"); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = check_group_in_ncache(ncache, dom, "shortgroup"); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = check_group_in_ncache(ncache, dom, "parentg"); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = check_group_in_ncache(ncache, dom, "subdomg"); ++ assert_int_equal(ret, ENOENT); ++} ++ ++static void expect_in_subdomain(struct sss_nc_ctx *ncache, ++ struct sss_domain_info *sub_dom) ++{ ++ int ret; ++ ++ ret = check_user_in_ncache(ncache, sub_dom, "shortuser"); ++ assert_int_equal(ret, EEXIST); ++ ret = sss_ncache_check_upn(ncache, sub_dom, "shortuser@sub"TEST_DOM_NAME); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = check_user_in_ncache(ncache, sub_dom, "subdomu"); ++ assert_int_equal(ret, EEXIST); ++ ret = sss_ncache_check_upn(ncache, sub_dom, "subdomu@sub"TEST_DOM_NAME); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = check_user_in_ncache(ncache, sub_dom, "upn"); ++ assert_int_equal(ret, ENOENT); ++ ret = sss_ncache_check_upn(ncache, sub_dom, "upn@upn.dom"); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = check_user_in_ncache(ncache, sub_dom, "parentu"); ++ assert_int_equal(ret, ENOENT); ++ ret = sss_ncache_check_upn(ncache, sub_dom, "parentu@"TEST_DOM_NAME); ++ assert_int_equal(ret, EEXIST); ++ ++ ++ ret = check_group_in_ncache(ncache, sub_dom, "shortgroup"); ++ assert_int_equal(ret, EEXIST); ++ ++ ret = check_group_in_ncache(ncache, sub_dom, "parentg"); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = check_group_in_ncache(ncache, sub_dom, "subdomg"); ++ assert_int_equal(ret, EEXIST); ++} ++static void expect_no_entries_in_dom(struct sss_nc_ctx *ncache, ++ struct sss_domain_info *dom2) ++{ ++ int ret; ++ ++ ret = check_user_in_ncache(ncache, dom2, "shortuser"); ++ assert_int_equal(ret, ENOENT); ++ ret = sss_ncache_check_upn(ncache, dom2, "shortuser"TEST_DOM_NAME); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = check_user_in_ncache(ncache, dom2, "parentu"); ++ assert_int_equal(ret, ENOENT); ++ ret = sss_ncache_check_upn(ncache, dom2, "parentu@"TEST_DOM_NAME); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = check_user_in_ncache(ncache, dom2, "subdomu"); ++ assert_int_equal(ret, ENOENT); ++ ret = sss_ncache_check_upn(ncache, dom2, "subdomu@sub"TEST_DOM_NAME); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = check_user_in_ncache(ncache, dom2, "upn"); ++ assert_int_equal(ret, ENOENT); ++ ret = sss_ncache_check_upn(ncache, dom2, "upn@upn.dom"); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = check_group_in_ncache(ncache, dom2, "shortgroup"); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = check_group_in_ncache(ncache, dom2, "parentg"); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = check_group_in_ncache(ncache, dom2, "subdomg"); ++ assert_int_equal(ret, ENOENT); ++} ++ ++static void test_sss_ncache_short_name_in_domain(void **state) ++{ ++ int ret; ++ struct test_state *ts; ++ struct tevent_context *ev; ++ struct sss_nc_ctx *ncache; ++ struct sss_test_ctx *tc; ++ struct sss_domain_info *dom; ++ struct sss_domain_info *dom2; ++ struct sss_domain_info *sub_dom; ++ ++ struct sss_test_conf_param params[] = { ++ { "filter_users", "shortuser, parentu@"TEST_DOM_NAME", " ++ "subdomu@sub"TEST_DOM_NAME", upn@upn.dom" }, ++ { "filter_groups", "shortgroup, parentg@"TEST_DOM_NAME", " ++ "subdomg@sub"TEST_DOM_NAME }, ++ { NULL, NULL }, ++ }; ++ ++ const char *nss_filter_users[] = { params[0].value, NULL}; ++ const char *nss_filter_groups[] = { params[1].value, NULL}; ++ ++ ts = talloc_get_type_abort(*state, struct test_state); ++ ++ ev = tevent_context_init(ts); ++ assert_non_null(ev); ++ ++ dom = talloc_zero(ts, struct sss_domain_info); ++ assert_non_null(dom); ++ dom->name = discard_const_p(char, TEST_DOM_NAME); ++ sss_domain_set_state(dom, DOM_ACTIVE); ++ ++ ts->nctx = mock_nctx(ts); ++ assert_non_null(ts->nctx); ++ ++ tc = create_dom_test_ctx(ts, TESTS_PATH, TEST_CONF_DB, ++ TEST_DOM_NAME, TEST_ID_PROVIDER, params); ++ assert_non_null(tc); ++ ++ ret = confdb_add_param(tc->confdb, true, "config/domain/"TEST_DOM_NAME, ++ "filter_users", nss_filter_users); ++ assert_int_equal(ret, EOK); ++ ++ ret = confdb_add_param(tc->confdb, true, "config/domain"TEST_DOM_NAME, ++ "filter_groups", nss_filter_groups); ++ assert_int_equal(ret, EOK); ++ ++ ncache = ts->ctx; ++ ts->rctx = mock_rctx(ts, ev, dom, ts->nctx); ++ assert_non_null(ts->rctx); ++ ts->rctx->cdb = tc->confdb; ++ ++ ret = sss_names_init(ts, tc->confdb, TEST_DOM_NAME, &dom->names); ++ assert_int_equal(ret, EOK); ++ ++ ret = sss_ncache_reset_repopulate_permanent(ts->rctx, ncache); ++ assert_int_equal(ret, EOK); ++ ++ /* Add another domain */ ++ dom2 = talloc_zero(ts, struct sss_domain_info); ++ assert_non_null(dom2); ++ dom2->name = discard_const_p(char, TEST_DOM_NAME"2"); ++ sss_domain_set_state(dom2, DOM_ACTIVE); ++ dom->next = dom2; ++ dom2->names = dom->names; ++ ++ expect_in_parent(ncache, dom); ++ expect_no_entries_in_dom(ncache, dom2); ++ ++ ret = sss_ncache_reset_repopulate_permanent(ts->rctx, ncache); ++ assert_int_equal(ret, EOK); ++ ++ expect_in_parent(ncache, dom); ++ expect_no_entries_in_dom(ncache, dom2); ++ ++ /* Add a sub domain */ ++ sub_dom = talloc_zero(ts, struct sss_domain_info); ++ assert_non_null(sub_dom); ++ sub_dom->name = discard_const_p(char, "sub"TEST_DOM_NAME); ++ sss_domain_set_state(sub_dom, DOM_ACTIVE); ++ sub_dom->parent = dom; ++ dom->subdomains = sub_dom; ++ sub_dom->names = dom->names; ++ ++ ret = sss_ncache_reset_repopulate_permanent(ts->rctx, ncache); ++ assert_int_equal(ret, EOK); ++ ++ expect_in_parent(ncache, dom); ++ expect_in_subdomain(ncache, sub_dom); ++ expect_no_entries_in_dom(ncache, dom2); ++} ++ + static void test_sss_ncache_reset(void **state) + { + errno_t ret; +@@ -1083,6 +1335,8 @@ int main(void) + setup, teardown), + cmocka_unit_test_setup_teardown(test_sss_ncache_reset_prepopulate, + setup, teardown), ++ cmocka_unit_test_setup_teardown(test_sss_ncache_short_name_in_domain, ++ setup, teardown), + cmocka_unit_test_setup_teardown(test_sss_ncache_reset, + setup, teardown), + cmocka_unit_test_setup_teardown(test_sss_ncache_locate_uid_gid, +-- +2.21.3 + diff --git a/SOURCES/0008-negcache-do-not-use-default_domain_suffix.patch b/SOURCES/0008-negcache-do-not-use-default_domain_suffix.patch new file mode 100644 index 0000000..17ce2db --- /dev/null +++ b/SOURCES/0008-negcache-do-not-use-default_domain_suffix.patch @@ -0,0 +1,154 @@ +From fa4b46e7de7297da3c0e37913eab8cba7f103629 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 9 Oct 2020 15:26:39 +0200 +Subject: [PATCH 8/8] negcache: do not use default_domain_suffix + +When splitting the names from the filter_users and filter_groups options +do not use the default_domain_suffix because it will hide that the +original name is a short name and should be added everywhere. + +Additionally this patch fixes a typo where sss_parse_name() was used +instead of sss_parse_name_for_domains(). + +Resolves: https://github.com/SSSD/sssd/issues/5238 + +Reviewed-by: Alexey Tikhonov +--- + src/responder/common/negcache.c | 29 +++++++++++++++-------------- + src/tests/cmocka/test_negcache.c | 22 ++++++++++++++++++++-- + 2 files changed, 35 insertions(+), 16 deletions(-) + +diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c +index 9ee39ce3e..59e8ad7e7 100644 +--- a/src/responder/common/negcache.c ++++ b/src/responder/common/negcache.c +@@ -1000,13 +1000,13 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + + for (i = 0; (filter_list && filter_list[i]); i++) { + ret = sss_parse_name_for_domains(tmpctx, domain_list, +- rctx->default_domain, ++ NULL, + filter_list[i], + &domainname, &name); + if (ret == EAGAIN) { + DEBUG(SSSDBG_MINOR_FAILURE, +- "cannot add [%s] to negcache because the required or " +- "default domain are not known yet\n", filter_list[i]); ++ "Can add [%s] only as UPN to negcache because the " ++ "required domain is not known yet\n", filter_list[i]); + } else if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Invalid name in filterUsers list: [%s] (%d)\n", +@@ -1066,12 +1066,12 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + + for (i = 0; (filter_list && filter_list[i]); i++) { + ret = sss_parse_name_for_domains(tmpctx, domain_list, +- rctx->default_domain, filter_list[i], ++ NULL, filter_list[i], + &domainname, &name); + if (ret == EAGAIN) { + DEBUG(SSSDBG_MINOR_FAILURE, +- "Cannot add [%s] to negcache because the required or " +- "default domain are not known yet\n", filter_list[i]); ++ "Can add [%s] only as UPN to negcache because the " ++ "required domain is not known yet\n", filter_list[i]); + } else if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Invalid name in filterUsers list: [%s] (%d)\n", +@@ -1158,9 +1158,12 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + if (ret != EOK) goto done; + + for (i = 0; (filter_list && filter_list[i]); i++) { +- ret = sss_parse_name(tmpctx, dom->names, filter_list[i], +- &domainname, &name); ++ ret = sss_parse_name_for_domains(tmpctx, domain_list, ++ NULL, filter_list[i], ++ &domainname, &name); + if (ret != EOK) { ++ /* Groups do not have UPNs, so domain names, if present, ++ * must be known */ + DEBUG(SSSDBG_CRIT_FAILURE, + "Invalid name in filterGroups list: [%s] (%d)\n", + filter_list[i], ret); +@@ -1207,13 +1210,11 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache, + + for (i = 0; (filter_list && filter_list[i]); i++) { + ret = sss_parse_name_for_domains(tmpctx, domain_list, +- rctx->default_domain, filter_list[i], ++ NULL, filter_list[i], + &domainname, &name); +- if (ret == EAGAIN) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- "Cannot add [%s] to negcache because the required or " +- "default domain are not known yet\n", filter_list[i]); +- } else if (ret != EOK) { ++ if (ret != EOK) { ++ /* Groups do not have UPNs, so domain names, if present, ++ * must be known */ + DEBUG(SSSDBG_CRIT_FAILURE, + "Invalid name in filterGroups list: [%s] (%d)\n", + filter_list[i], ret); +diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c +index fb306b110..30218d52a 100644 +--- a/src/tests/cmocka/test_negcache.c ++++ b/src/tests/cmocka/test_negcache.c +@@ -933,7 +933,9 @@ static void test_sss_ncache_reset_prepopulate(void **state) + * + * The result should of course be independent of the present domains. To + * verify this the domains are added one after the other and the negative +- * cache is repopulated each time. ++ * cache is repopulated each time. The result should be also independent of ++ * the setting of default_domain_suffix option which is tested by ++ * test_sss_ncache_short_name_in_domain_with_prefix. + * + * With the given domains, users and group we have to following expectations: + * - the short name entry will be added to the domain and all sub-domains as +@@ -1081,7 +1083,8 @@ static void expect_no_entries_in_dom(struct sss_nc_ctx *ncache, + assert_int_equal(ret, ENOENT); + } + +-static void test_sss_ncache_short_name_in_domain(void **state) ++static void run_sss_ncache_short_name_in_domain(void **state, ++ bool use_default_domain_prefix) + { + int ret; + struct test_state *ts; +@@ -1131,6 +1134,9 @@ static void test_sss_ncache_short_name_in_domain(void **state) + ncache = ts->ctx; + ts->rctx = mock_rctx(ts, ev, dom, ts->nctx); + assert_non_null(ts->rctx); ++ if (use_default_domain_prefix) { ++ ts->rctx->default_domain = discard_const(TEST_DOM_NAME); ++ } + ts->rctx->cdb = tc->confdb; + + ret = sss_names_init(ts, tc->confdb, TEST_DOM_NAME, &dom->names); +@@ -1173,6 +1179,16 @@ static void test_sss_ncache_short_name_in_domain(void **state) + expect_no_entries_in_dom(ncache, dom2); + } + ++static void test_sss_ncache_short_name_in_domain(void **state) ++{ ++ run_sss_ncache_short_name_in_domain(state, false); ++} ++ ++static void test_sss_ncache_short_name_in_domain_with_prefix(void **state) ++{ ++ run_sss_ncache_short_name_in_domain(state, true); ++} ++ + static void test_sss_ncache_reset(void **state) + { + errno_t ret; +@@ -1337,6 +1353,8 @@ int main(void) + setup, teardown), + cmocka_unit_test_setup_teardown(test_sss_ncache_short_name_in_domain, + setup, teardown), ++ cmocka_unit_test_setup_teardown(test_sss_ncache_short_name_in_domain_with_prefix, ++ setup, teardown), + cmocka_unit_test_setup_teardown(test_sss_ncache_reset, + setup, teardown), + cmocka_unit_test_setup_teardown(test_sss_ncache_locate_uid_gid, +-- +2.21.3 + diff --git a/SOURCES/0009-kcm-decode-base64-encoded-secret-on-upgrade-path.patch b/SOURCES/0009-kcm-decode-base64-encoded-secret-on-upgrade-path.patch new file mode 100644 index 0000000..032f1c4 --- /dev/null +++ b/SOURCES/0009-kcm-decode-base64-encoded-secret-on-upgrade-path.patch @@ -0,0 +1,43 @@ +From 18b98836ef8e337992f0ecb239a32b9c3cedb750 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 9 Dec 2020 14:07:22 +0100 +Subject: [PATCH] kcm: decode base64 encoded secret on upgrade path + +Previous unefficient code encoded the secret multiple times: + secret -> base64 -> masterkey -> base64 + +To allow smooth upgrade for already existant ccache we need to also decode +the secret if it is still in the old format (type == simple). Otherwise +users are not able to log in. + +Resolves: https://github.com/SSSD/sssd/issues/5349 + +Reviewed-by: Alexey Tikhonov +--- + src/responder/kcm/kcmsrv_ccache_secdb.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c +index 726711ac4..ea5c8f9ee 100644 +--- a/src/responder/kcm/kcmsrv_ccache_secdb.c ++++ b/src/responder/kcm/kcmsrv_ccache_secdb.c +@@ -59,6 +59,16 @@ static errno_t sec_get(TALLOC_CTX *mem_ctx, + goto done; + } + ++ if (strcmp(datatype, "simple") == 0) { ++ /* The secret is stored in b64 encoding, we need to decode it first. */ ++ data = sss_base64_decode(tmp_ctx, (const char*)data, &len); ++ if (data == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot decode secret from base64\n"); ++ ret = EIO; ++ goto done; ++ } ++ } ++ + buf = sss_iobuf_init_steal(tmp_ctx, data, len); + if (buf == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init the iobuf\n"); +-- +2.21.3 + diff --git a/SOURCES/0010-nss-check-if-groups-are-filtered-during-initgroups.patch b/SOURCES/0010-nss-check-if-groups-are-filtered-during-initgroups.patch new file mode 100644 index 0000000..8e76f9a --- /dev/null +++ b/SOURCES/0010-nss-check-if-groups-are-filtered-during-initgroups.patch @@ -0,0 +1,112 @@ +From c87b2208b9a58c12eeceb5b8ccf9c34dcd835b8d Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 17 Nov 2020 12:59:23 +0100 +Subject: [PATCH] nss: check if groups are filtered during initgroups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If groups are filtered, i.e. SSSD should not handle them, they should +not appear in the group list returned by an initgroups request. + +Resolves: https://github.com/SSSD/sssd/issues/5403 + +Reviewed-by: Pavel Březina +--- + src/responder/nss/nss_protocol_grent.c | 35 ++++++++++++++++++++++++++ + src/tests/intg/test_ldap.py | 12 +++++++++ + 2 files changed, 47 insertions(+) + +diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c +index 8f1d3fe81..135b392f7 100644 +--- a/src/responder/nss/nss_protocol_grent.c ++++ b/src/responder/nss/nss_protocol_grent.c +@@ -326,6 +326,34 @@ done: + return EOK; + } + ++static bool is_group_filtered(struct sss_nc_ctx *ncache, ++ struct sss_domain_info *domain, ++ const char *grp_name, gid_t gid) ++{ ++ int ret; ++ ++ if (grp_name == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Group with gid [%"SPRIgid"] has no name, this should never " ++ "happen, trying to continue without.\n", gid); ++ } else { ++ ret = sss_ncache_check_group(ncache, domain, grp_name); ++ if (ret == EEXIST) { ++ DEBUG(SSSDBG_TRACE_FUNC, "Group [%s] is filtered out! " ++ "(negative cache)", grp_name); ++ return true; ++ } ++ } ++ ret = sss_ncache_check_gid(ncache, domain, gid); ++ if (ret == EEXIST) { ++ DEBUG(SSSDBG_TRACE_FUNC, "Group [%"SPRIgid"] is filtered out! " ++ "(negative cache)", gid); ++ return true; ++ } ++ ++ return false; ++} ++ + errno_t + nss_protocol_fill_initgr(struct nss_ctx *nss_ctx, + struct nss_cmd_ctx *cmd_ctx, +@@ -344,6 +372,7 @@ nss_protocol_fill_initgr(struct nss_ctx *nss_ctx, + size_t body_len; + size_t rp; + gid_t gid; ++ const char *grp_name; + gid_t orig_gid; + errno_t ret; + int i; +@@ -392,6 +421,8 @@ nss_protocol_fill_initgr(struct nss_ctx *nss_ctx, + gid = sss_view_ldb_msg_find_attr_as_uint64(domain, msg, SYSDB_GIDNUM, + 0); + posix = ldb_msg_find_attr_as_string(msg, SYSDB_POSIX, NULL); ++ grp_name = sss_view_ldb_msg_find_attr_as_string(domain, msg, SYSDB_NAME, ++ NULL); + + if (gid == 0) { + if (posix != NULL && strcmp(posix, "FALSE") == 0) { +@@ -404,6 +435,10 @@ nss_protocol_fill_initgr(struct nss_ctx *nss_ctx, + } + } + ++ if (is_group_filtered(nss_ctx->rctx->ncache, domain, grp_name, gid)) { ++ continue; ++ } ++ + SAFEALIGN_COPY_UINT32(&body[rp], &gid, &rp); + num_results++; + +diff --git a/src/tests/intg/test_ldap.py b/src/tests/intg/test_ldap.py +index 194d7d9cc..6a78c960f 100644 +--- a/src/tests/intg/test_ldap.py ++++ b/src/tests/intg/test_ldap.py +@@ -1190,6 +1190,18 @@ def test_nss_filters(ldap_conn, sanity_nss_filter): + with pytest.raises(KeyError): + grp.getgrgid(14) + ++ # test initgroups - user1 is member of group_two_one_user_groups (2019) ++ # which is filtered out ++ (res, errno, gids) = sssd_id.call_sssd_initgroups("user1", 2001) ++ assert res == sssd_id.NssReturnCode.SUCCESS ++ ++ user_with_group_ids = [2001, 2012, 2015, 2017, 2018] ++ assert sorted(gids) == sorted(user_with_group_ids), \ ++ "result: %s\n expected %s" % ( ++ ", ".join(["%s" % s for s in sorted(gids)]), ++ ", ".join(["%s" % s for s in sorted(user_with_group_ids)]) ++ ) ++ + + @pytest.fixture + def sanity_nss_filter_cached(request, ldap_conn): +-- +2.21.3 + diff --git a/SOURCES/0011-ifp-fix-use-after-free.patch b/SOURCES/0011-ifp-fix-use-after-free.patch new file mode 100644 index 0000000..8e42b4d --- /dev/null +++ b/SOURCES/0011-ifp-fix-use-after-free.patch @@ -0,0 +1,36 @@ +From 81e757b7b1d69893b5725f9c148c55d89c779e7b Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 3 Nov 2020 10:12:15 +0100 +Subject: [PATCH] ifp: fix use-after-free +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The variable fqdn is pointing to some data from state->res->msgs[0]. But +before fqdn is used in the next search state->res and the memory +hierarchy below is freed. As a result the location where fqdn is pointing +to might hold the expected data or other data and the search will fail +intermittently. + +Resolves: https://github.com/SSSD/sssd/issues/5382 + +Reviewed-by: Pavel Březina +--- + src/responder/ifp/ifpsrv_cmd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c +index 9f20bf2db..d95618127 100644 +--- a/src/responder/ifp/ifpsrv_cmd.c ++++ b/src/responder/ifp/ifpsrv_cmd.c +@@ -128,6 +128,7 @@ static void ifp_user_get_attr_done(struct tevent_req *subreq) + tevent_req_error(req, ERR_INTERNAL); + return; + } ++ fqdn = talloc_steal(state, fqdn); + + if (state->search_type == SSS_DP_USER) { + /* throw away the result and perform attr search */ +-- +2.21.3 + diff --git a/SOURCES/0012-ifp-fix-original-fix-use-after-free.patch b/SOURCES/0012-ifp-fix-original-fix-use-after-free.patch new file mode 100644 index 0000000..8e87526 --- /dev/null +++ b/SOURCES/0012-ifp-fix-original-fix-use-after-free.patch @@ -0,0 +1,38 @@ +From 3b158934cbb8f87cbfaf1650389b8dcd654b92ca Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 19 Nov 2020 18:05:00 +0100 +Subject: [PATCH] ifp: fix original fix use-after-free + +The original fix stole the fqdn too earlier. Only for SSS_DP_USER +requests the steal is important. For other request where the first +result is returned to the caller the original version +might even cause issues since the name does not belong to the memory +hierarchy of the result anymore. + +Resolves: https://github.com/SSSD/sssd/issues/5382 + +Reviewed-by: Alexey Tikhonov +--- + src/responder/ifp/ifpsrv_cmd.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/responder/ifp/ifpsrv_cmd.c b/src/responder/ifp/ifpsrv_cmd.c +index d95618127..8cf1ec84c 100644 +--- a/src/responder/ifp/ifpsrv_cmd.c ++++ b/src/responder/ifp/ifpsrv_cmd.c +@@ -128,10 +128,10 @@ static void ifp_user_get_attr_done(struct tevent_req *subreq) + tevent_req_error(req, ERR_INTERNAL); + return; + } +- fqdn = talloc_steal(state, fqdn); + + if (state->search_type == SSS_DP_USER) { +- /* throw away the result and perform attr search */ ++ /* throw away the result but keep the fqdn and perform attr search */ ++ fqdn = talloc_steal(state, fqdn); + talloc_zfree(state->res); + + ret = sysdb_get_user_attr_with_views(state, state->dom, fqdn, +-- +2.21.3 + diff --git a/SOURCES/0013-pam_sss-use-unique-id-for-gdm-choice-list.patch b/SOURCES/0013-pam_sss-use-unique-id-for-gdm-choice-list.patch new file mode 100644 index 0000000..c374782 --- /dev/null +++ b/SOURCES/0013-pam_sss-use-unique-id-for-gdm-choice-list.patch @@ -0,0 +1,68 @@ +From 1b9b7f5a635ede8eee90d13bfe0e1f87e51191a9 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 13 Nov 2020 12:59:39 +0100 +Subject: [PATCH 13/16] pam_sss: use unique id for gdm choice list + +Currently the key-id read from the Smartcard is used as key value for +the gdm choice list dialog. Since it might be possible that multiple +certificates use the same key and hence the same key-id this is not a +suitable value. + +With this patch the string representation of a numerical counter is used. + +Resolves: https://github.com/SSSD/sssd/issues/5400 + +Reviewed-by: Alexey Tikhonov +--- + src/sss_client/pam_sss.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c +index b844d257e..04dfdb55d 100644 +--- a/src/sss_client/pam_sss.c ++++ b/src/sss_client/pam_sss.c +@@ -128,6 +128,7 @@ struct cert_auth_info { + char *key_id; + char *prompt_str; + char *pam_cert_user; ++ char *choice_list_id; + struct cert_auth_info *prev; + struct cert_auth_info *next; + }; +@@ -141,6 +142,7 @@ static void free_cai(struct cert_auth_info *cai) + free(cai->module_name); + free(cai->key_id); + free(cai->prompt_str); ++ free(cai->choice_list_id); + free(cai); + } + } +@@ -1698,7 +1700,15 @@ static int prompt_multi_cert_gdm(pam_handle_t *pamh, struct pam_items *pi) + ret = ENOMEM; + goto done; + } +- request->list.items[c].key = cai->key_id; ++ free(cai->choice_list_id); ++ ret = asprintf(&cai->choice_list_id, "%zu", c); ++ if (ret == -1) { ++ cai->choice_list_id = NULL; ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ request->list.items[c].key = cai->choice_list_id; + request->list.items[c++].text = prompt; + } + +@@ -1719,7 +1729,7 @@ static int prompt_multi_cert_gdm(pam_handle_t *pamh, struct pam_items *pi) + } + + DLIST_FOR_EACH(cai, pi->cert_list) { +- if (strcmp(response->key, cai->key_id) == 0) { ++ if (strcmp(response->key, cai->choice_list_id) == 0) { + pam_info(pamh, "Certificate ‘%s’ selected", cai->key_id); + pi->selected_cert = cai; + ret = 0; +-- +2.21.3 + diff --git a/SOURCES/0014-authtok-add-label-to-Smartcard-token.patch b/SOURCES/0014-authtok-add-label-to-Smartcard-token.patch new file mode 100644 index 0000000..741fc5d --- /dev/null +++ b/SOURCES/0014-authtok-add-label-to-Smartcard-token.patch @@ -0,0 +1,1072 @@ +From 8b6be52e95e953ae0431676de0b8c8be7a3262bc Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 13 Nov 2020 18:05:14 +0100 +Subject: [PATCH 14/16] authtok: add label to Smartcard token + +The key-id might not be sufficient to identify a certificate on a +Smartcard since it is possible that multiple certificates will use the +same key. + +This patch adds the certificate label to the Smartcard authtok item to +resolve the ambiguity if the key-id is used for multiple certificates. + +Resolves: https://github.com/SSSD/sssd/issues/5400 + +Reviewed-by: Alexey Tikhonov +--- + src/p11_child/p11_child.h | 3 +- + src/p11_child/p11_child_common.c | 12 +++-- + src/p11_child/p11_child_openssl.c | 16 +++++-- + src/providers/krb5/krb5_child.c | 14 +++++- + src/responder/pam/pamsrv_cmd.c | 5 +- + src/responder/pam/pamsrv_p11.c | 8 +++- + src/sss_client/pam_sss.c | 3 ++ + src/tests/cmocka/test_authtok.c | 36 +++++++++------ + src/tests/cmocka/test_pam_srv.c | 65 ++++++++++++++------------ + src/util/authtok-utils.c | 30 ++++++++++-- + src/util/authtok-utils.h | 11 ++++- + src/util/authtok.c | 77 +++++++++++++++++++++++++------ + src/util/authtok.h | 14 +++++- + 13 files changed, 214 insertions(+), 80 deletions(-) + +diff --git a/src/p11_child/p11_child.h b/src/p11_child/p11_child.h +index 0b53e70c5..9c0cefe05 100644 +--- a/src/p11_child/p11_child.h ++++ b/src/p11_child/p11_child.h +@@ -68,7 +68,8 @@ bool do_verification_b64(struct p11_ctx *p11_ctx, const char *cert_b64); + errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx, + enum op_mode mode, const char *pin, + const char *module_name_in, const char *token_name_in, +- const char *key_id_in, const char *uri, char **_multi); ++ const char *key_id_in, const char *label, ++ const char *uri, char **_multi); + + errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts, + struct cert_verify_opts **cert_verify_opts); +diff --git a/src/p11_child/p11_child_common.c b/src/p11_child/p11_child_common.c +index 236d7dac4..f17de1a9e 100644 +--- a/src/p11_child/p11_child_common.c ++++ b/src/p11_child/p11_child_common.c +@@ -60,7 +60,8 @@ static int do_work(TALLOC_CTX *mem_ctx, enum op_mode mode, const char *ca_db, + bool wait_for_card, + const char *cert_b64, const char *pin, + const char *module_name, const char *token_name, +- const char *key_id, const char *uri, char **multi) ++ const char *key_id, const char *label, const char *uri, ++ char **multi) + { + int ret; + struct p11_ctx *p11_ctx; +@@ -91,7 +92,7 @@ static int do_work(TALLOC_CTX *mem_ctx, enum op_mode mode, const char *ca_db, + } + } else { + ret = do_card(mem_ctx, p11_ctx, mode, pin, +- module_name, token_name, key_id, uri, multi); ++ module_name, token_name, key_id, label, uri, multi); + } + + done: +@@ -158,6 +159,7 @@ int main(int argc, const char *argv[]) + char *module_name = NULL; + char *token_name = NULL; + char *key_id = NULL; ++ char *label = NULL; + char *cert_b64 = NULL; + bool wait_for_card = false; + char *uri = NULL; +@@ -194,6 +196,8 @@ int main(int argc, const char *argv[]) + _("Token name for authentication"), NULL}, + {"key_id", 0, POPT_ARG_STRING, &key_id, 0, + _("Key ID for authentication"), NULL}, ++ {"label", 0, POPT_ARG_STRING, &label, 0, ++ _("Label for authentication"), NULL}, + {"certificate", 0, POPT_ARG_STRING, &cert_b64, 0, + _("certificate to verify, base64 encoded"), NULL}, + {"uri", 0, POPT_ARG_STRING, &uri, 0, +@@ -340,6 +344,7 @@ int main(int argc, const char *argv[]) + } + talloc_steal(main_ctx, debug_prg_name); + ++ /* We do not require the label, but it is recommended */ + if (mode == OP_AUTH && (module_name == NULL || token_name == NULL + || key_id == NULL)) { + DEBUG(SSSDBG_FATAL_FAILURE, +@@ -369,7 +374,8 @@ int main(int argc, const char *argv[]) + } + + ret = do_work(main_ctx, mode, ca_db, cert_verify_opts, wait_for_card, +- cert_b64, pin, module_name, token_name, key_id, uri, &multi); ++ cert_b64, pin, module_name, token_name, key_id, label, uri, ++ &multi); + if (ret != 0) { + DEBUG(SSSDBG_OP_FAILURE, "do_work failed.\n"); + goto fail; +diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c +index 04b3e1467..d81a1a9ea 100644 +--- a/src/p11_child/p11_child_openssl.c ++++ b/src/p11_child/p11_child_openssl.c +@@ -1587,7 +1587,8 @@ static errno_t wait_for_card(CK_FUNCTION_LIST *module, CK_SLOT_ID *slot_id) + errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx, + enum op_mode mode, const char *pin, + const char *module_name_in, const char *token_name_in, +- const char *key_id_in, const char *uri_str, char **_multi) ++ const char *key_id_in, const char *label_in, ++ const char *uri_str, char **_multi) + { + int ret; + size_t c; +@@ -1845,11 +1846,13 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx, + DLIST_FOR_EACH(item, all_cert_list) { + /* Check if we found the certificates we needed for authentication or + * the requested ones for pre-auth. For authentication all attributes +- * must be given and match, for pre-auth only the given ones must +- * match. */ +- DEBUG(SSSDBG_TRACE_ALL, "%s %s %s %s %s %s.\n", ++ * except the label must be given and match. The label is optional for ++ * authentication but if given it must match as well. For pre-auth ++ * only the given ones must match. */ ++ DEBUG(SSSDBG_TRACE_ALL, "%s %s %s %s %s %s %s.\n", + module_name_in, module_file_name, token_name_in, token_name, +- key_id_in, item->id); ++ key_id_in, label_in == NULL ? "- no label given-" : label_in, ++ item->id); + + if ((mode == OP_AUTH + && module_name_in != NULL +@@ -1857,6 +1860,9 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx, + && key_id_in != NULL + && item->id != NULL + && strcmp(key_id_in, item->id) == 0 ++ && (label_in == NULL ++ || (label_in != NULL && item->label != NULL ++ && strcmp(label_in, item->label) == 0)) + && strcmp(token_name_in, token_name) == 0 + && strcmp(module_name_in, module_file_name) == 0) + || (mode == OP_PREAUTH +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index 6e2bf6d75..cab7b27a2 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -714,7 +714,7 @@ static krb5_error_code answer_pkinit(krb5_context ctx, + kerr = sss_authtok_get_sc(kr->pd->authtok, &pin, NULL, + &token_name, NULL, + &module_name, NULL, +- NULL, NULL); ++ NULL, NULL, NULL, NULL); + if (kerr != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "sss_authtok_get_sc failed.\n"); +@@ -1226,11 +1226,12 @@ static errno_t get_pkinit_identity(TALLOC_CTX *mem_ctx, + const char *token_name; + const char *module_name; + const char *key_id; ++ const char *label; + + ret = sss_authtok_get_sc(authtok, NULL, NULL, + &token_name, NULL, + &module_name, NULL, +- &key_id, NULL); ++ &key_id, NULL, &label, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc failed.\n"); + return ret; +@@ -1267,6 +1268,15 @@ static errno_t get_pkinit_identity(TALLOC_CTX *mem_ctx, + } + } + ++ if (label != NULL && *label != '\0') { ++ identity = talloc_asprintf_append(identity, ":certlabel=%s", label); ++ if (identity == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "talloc_asprintf_append failed.\n"); ++ return ENOMEM; ++ } ++ } ++ + *_identity = identity; + + DEBUG(SSSDBG_TRACE_ALL, "Using pkinit identity [%s].\n", identity); +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index 9ea488be4..d3f092b2b 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1258,7 +1258,7 @@ static errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *p + || sss_authtok_get_type(pd->authtok) + == SSS_AUTHTOK_TYPE_SC_KEYPAD)) { + ret = sss_authtok_get_sc(pd->authtok, NULL, NULL, NULL, NULL, NULL, +- NULL, &key_id, NULL); ++ NULL, &key_id, NULL, NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc failed.\n"); + goto done; +@@ -2274,7 +2274,8 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) + SSS_AUTHTOK_TYPE_SC_PIN, NULL, 0, + sss_cai_get_token_name(preq->current_cert), 0, + sss_cai_get_module_name(preq->current_cert), 0, +- sss_cai_get_key_id(preq->current_cert), 0); ++ sss_cai_get_key_id(preq->current_cert), 0, ++ sss_cai_get_label(preq->current_cert), 0); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "sss_authtok_set_sc failed, Smartcard " +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index abc987804..23f94927a 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -727,6 +727,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + const char *module_name = NULL; + const char *token_name = NULL; + const char *key_id = NULL; ++ const char *label = NULL; + + req = tevent_req_create(mem_ctx, &state, struct pam_check_cert_state); + if (req == NULL) { +@@ -766,7 +767,8 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + if (sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_SC_PIN + || sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_SC_KEYPAD) { + ret = sss_authtok_get_sc(pd->authtok, NULL, NULL, &token_name, NULL, +- &module_name, NULL, &key_id, NULL); ++ &module_name, NULL, &key_id, NULL, ++ &label, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc failed.\n"); + goto done; +@@ -784,6 +786,10 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + extra_args[arg_c++] = key_id; + extra_args[arg_c++] = "--key_id"; + } ++ if (label != NULL && *label != '\0') { ++ extra_args[arg_c++] = label; ++ extra_args[arg_c++] = "--label"; ++ } + } + + if (pd->cmd == SSS_PAM_AUTHENTICATE) { +diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c +index 04dfdb55d..cffbfa770 100644 +--- a/src/sss_client/pam_sss.c ++++ b/src/sss_client/pam_sss.c +@@ -126,6 +126,7 @@ struct cert_auth_info { + char *token_name; + char *module_name; + char *key_id; ++ char *label; + char *prompt_str; + char *pam_cert_user; + char *choice_list_id; +@@ -1962,6 +1963,7 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) + ret = sss_auth_pack_sc_blob(answer, 0, cai->token_name, 0, + cai->module_name, 0, + cai->key_id, 0, ++ cai->label, 0, + NULL, 0, &needed_size); + if (ret != EAGAIN) { + D(("sss_auth_pack_sc_blob failed.")); +@@ -1979,6 +1981,7 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi) + ret = sss_auth_pack_sc_blob(answer, 0, cai->token_name, 0, + cai->module_name, 0, + cai->key_id, 0, ++ cai->label, 0, + (uint8_t *) pi->pam_authtok, needed_size, + &needed_size); + if (ret != EOK) { +diff --git a/src/tests/cmocka/test_authtok.c b/src/tests/cmocka/test_authtok.c +index a8f5bdee7..a31014eb6 100644 +--- a/src/tests/cmocka/test_authtok.c ++++ b/src/tests/cmocka/test_authtok.c +@@ -451,25 +451,27 @@ void test_sss_authtok_sc_blobs(void **state) + size_t module_name_len; + const char *key_id; + size_t key_id_len; ++ const char *label; ++ size_t label_len; + + ts = talloc_get_type_abort(*state, struct test_state); + + ret = sss_auth_pack_sc_blob("abc", 0, "defg", 0, "hijkl", 0, "mnopqr", 0, +- NULL, 0, &needed_size); ++ "stuvw", 0, NULL, 0, &needed_size); + assert_int_equal(ret, EAGAIN); + + buf = talloc_size(ts, needed_size); + assert_non_null(buf); + + ret = sss_auth_pack_sc_blob("abc", 0, "defg", 0, "hijkl", 0, "mnopqr", 0, +- buf, needed_size, &needed_size); ++ "stuvw", 0, buf, needed_size, &needed_size); + assert_int_equal(ret, EOK); + + #if __BYTE_ORDER == __LITTLE_ENDIAN +- assert_memory_equal(buf, "\4\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0abc\0defg\0hijkl\0mnopqr\0", ++ assert_memory_equal(buf, "\4\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0\6\0\0\0abc\0defg\0hijkl\0mnopqr\0stuvw\0", + needed_size); + #else +- assert_memory_equal(buf, "\0\0\0\4\0\0\0\5\0\0\0\6\0\0\0\7abc\0defg\0hijkl\0mnopqr\0", ++ assert_memory_equal(buf, "\0\0\0\4\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0\6abc\0defg\0hijkl\0mnopqr\0stuvw\0", + needed_size); + #endif + +@@ -485,7 +487,8 @@ void test_sss_authtok_sc_blobs(void **state) + ret = sss_authtok_get_sc(ts->authtoken, &pin, &pin_len, + &token_name, &token_name_len, + &module_name, &module_name_len, +- &key_id, &key_id_len); ++ &key_id, &key_id_len, ++ &label, &label_len); + assert_int_equal(ret, EOK); + assert_int_equal(pin_len, 3); + assert_string_equal(pin, "abc"); +@@ -495,11 +498,14 @@ void test_sss_authtok_sc_blobs(void **state) + assert_string_equal(module_name, "hijkl"); + assert_int_equal(key_id_len, 6); + assert_string_equal(key_id, "mnopqr"); ++ assert_int_equal(label_len, 5); ++ assert_string_equal(label, "stuvw"); + + ret = sss_authtok_get_sc(ts->authtoken, NULL, NULL, + &token_name, &token_name_len, + &module_name, &module_name_len, +- &key_id, &key_id_len); ++ &key_id, &key_id_len, ++ &label, &label_len); + assert_int_equal(ret, EOK); + assert_int_equal(token_name_len, 4); + assert_string_equal(token_name, "defg"); +@@ -507,15 +513,19 @@ void test_sss_authtok_sc_blobs(void **state) + assert_string_equal(module_name, "hijkl"); + assert_int_equal(key_id_len, 6); + assert_string_equal(key_id, "mnopqr"); ++ assert_int_equal(label_len, 5); ++ assert_string_equal(label, "stuvw"); + + ret = sss_authtok_get_sc(ts->authtoken, NULL, NULL, + &token_name, NULL, + &module_name, NULL, +- &key_id, NULL); ++ &key_id, NULL, ++ &label, NULL); + assert_int_equal(ret, EOK); + assert_string_equal(token_name, "defg"); + assert_string_equal(module_name, "hijkl"); + assert_string_equal(key_id, "mnopqr"); ++ assert_string_equal(label, "stuvw"); + + sss_authtok_set_empty(ts->authtoken); + talloc_free(buf); +@@ -608,14 +618,14 @@ void test_sss_authtok_sc_pin(void **state) + assert_int_equal(sss_authtok_get_type(ts->authtoken), + SSS_AUTHTOK_TYPE_SC_PIN); + size = sss_authtok_get_size(ts->authtoken); +- assert_int_equal(size, 28); ++ assert_int_equal(size, 33); + #if __BYTE_ORDER == __LITTLE_ENDIAN + assert_memory_equal(sss_authtok_get_data(ts->authtoken), +- "\11\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" "12345678\0\0\0\0", ++ "\11\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" "12345678\0\0\0\0\0", + size); + #else + assert_memory_equal(sss_authtok_get_data(ts->authtoken), +- "\0\0\0\11\0\0\0\1\0\0\0\1\0\0\0\1" "12345678\0\0\0\0", ++ "\0\0\0\11\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "12345678\0\0\0\0\0", + size); + #endif + +@@ -624,14 +634,14 @@ void test_sss_authtok_sc_pin(void **state) + assert_int_equal(sss_authtok_get_type(ts->authtoken), + SSS_AUTHTOK_TYPE_SC_PIN); + size = sss_authtok_get_size(ts->authtoken); +- assert_int_equal(size, 25); ++ assert_int_equal(size, 30); + #if __BYTE_ORDER == __LITTLE_ENDIAN + assert_memory_equal(sss_authtok_get_data(ts->authtoken), +- "\6\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" "12345\0\0\0\0", ++ "\6\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" "12345\0\0\0\0\0", + size); + #else + assert_memory_equal(sss_authtok_get_data(ts->authtoken), +- "\0\0\0\6\0\0\0\1\0\0\0\1\0\0\0\1" "12345\0\0\0\0", ++ "\0\0\0\6\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "12345\0\0\0\0\0", + size); + #endif + +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index 326deaf1f..cb05042de 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -536,7 +536,7 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, + static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, + const char *pin, const char *token_name, + const char *module_name, const char *key_id, +- const char *service, ++ const char *label, const char *service, + acct_cb_t acct_cb, const char *cert) + { + size_t buf_size; +@@ -556,14 +556,14 @@ static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, + + if (pin != NULL) { + ret = sss_auth_pack_sc_blob(pin, 0, token_name, 0, module_name, 0, +- key_id, 0, NULL, 0, &needed_size); ++ key_id, 0, label, 0, NULL, 0, &needed_size); + assert_int_equal(ret, EAGAIN); + + pi.pam_authtok = malloc(needed_size); + assert_non_null(pi.pam_authtok); + + ret = sss_auth_pack_sc_blob(pin, 0, token_name, 0, module_name, 0, +- key_id, 0, ++ key_id, 0, label, 0, + (uint8_t *)pi.pam_authtok, needed_size, + &needed_size); + assert_int_equal(ret, EOK); +@@ -1766,7 +1766,7 @@ void test_pam_preauth_no_logon_name(void **state) + int ret; + + mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +- NULL); ++ NULL, NULL); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -1862,7 +1862,7 @@ void test_pam_preauth_cert_nocert(void **state) + unsetenv("SOFTHSM2_CONF"); + + mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, +- NULL, NULL); ++ NULL, NULL, NULL); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2004,7 +2004,7 @@ void test_pam_preauth_cert_nomatch(void **state) + set_cert_auth_param(pam_test_ctx->pctx, CA_DB); + + mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, +- test_lookup_by_cert_cb, NULL); ++ NULL, test_lookup_by_cert_cb, NULL); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2026,7 +2026,7 @@ void test_pam_preauth_cert_match(void **state) + set_cert_auth_param(pam_test_ctx->pctx, CA_DB); + + mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, +- test_lookup_by_cert_cb, SSSD_TEST_CERT_0001); ++ NULL, test_lookup_by_cert_cb, SSSD_TEST_CERT_0001); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2048,7 +2048,7 @@ void test_pam_preauth_cert_match_gdm_smartcard(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, CA_DB); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, + "gdm-smartcard", test_lookup_by_cert_cb, + SSSD_TEST_CERT_0001); + +@@ -2072,7 +2072,7 @@ void test_pam_preauth_cert_match_wrong_user(void **state) + set_cert_auth_param(pam_test_ctx->pctx, CA_DB); + + mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, +- test_lookup_by_cert_wrong_user_cb, ++ NULL, test_lookup_by_cert_wrong_user_cb, + SSSD_TEST_CERT_0001); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2104,7 +2104,7 @@ void test_pam_preauth_cert_no_logon_name(void **state) + * request will be done with the username found by the certificate + * lookup. */ + mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, +- test_lookup_by_cert_cb, SSSD_TEST_CERT_0001); ++ NULL, test_lookup_by_cert_cb, SSSD_TEST_CERT_0001); + mock_account_recv_simple(); + mock_parse_inp("pamuser", NULL, EOK); + mock_parse_inp("pamuser", NULL, EOK); +@@ -2134,7 +2134,7 @@ void test_pam_preauth_cert_no_logon_name_with_hint(void **state) + * 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, NULL, NULL, NULL, +- test_lookup_by_cert_cb, SSSD_TEST_CERT_0001); ++ NULL, test_lookup_by_cert_cb, SSSD_TEST_CERT_0001); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2155,7 +2155,7 @@ void test_pam_preauth_cert_no_logon_name_double_cert(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, CA_DB); + +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_double_cb, SSSD_TEST_CERT_0001); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2178,7 +2178,7 @@ void test_pam_preauth_cert_no_logon_name_double_cert_with_hint(void **state) + set_cert_auth_param(pam_test_ctx->pctx, CA_DB); + pam_test_ctx->rctx->domains->user_name_hint = true; + +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_double_cb, SSSD_TEST_CERT_0001); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2201,7 +2201,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, NULL, NULL, NULL, NULL, NULL, +- NULL); ++ NULL, NULL); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2223,7 +2223,7 @@ void test_pam_preauth_cert_no_logon_name_no_match(void **state) + set_cert_auth_param(pam_test_ctx->pctx, CA_DB); + + mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, +- test_lookup_by_cert_cb, NULL); ++ NULL, test_lookup_by_cert_cb, NULL); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2252,7 +2252,8 @@ void test_pam_cert_auth(void **state) + * in the cache and no second request to the backend is needed. */ + mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token", + TEST_MODULE_NAME, +- "C554C9F82C2A9D58B70921C143304153A8A42F17", NULL, ++ "C554C9F82C2A9D58B70921C143304153A8A42F17", ++ "SSSD test cert 0001", NULL, + test_lookup_by_cert_cb, SSSD_TEST_CERT_0001); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); +@@ -2289,7 +2290,8 @@ void test_pam_ecc_cert_auth(void **state) + mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", + "SSSD Test ECC Token", + TEST_MODULE_NAME, +- "190E513C9A3DFAACDE5D2D0592F0FDFF559C10CB", NULL, ++ "190E513C9A3DFAACDE5D2D0592F0FDFF559C10CB", ++ "SSSD test ECC cert 0001", NULL, + test_lookup_by_cert_cb, SSSD_TEST_ECC_CERT_0001); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); +@@ -2324,7 +2326,8 @@ void test_pam_cert_auth_no_logon_name(void **state) + * in the cache and no second request to the backend is needed. */ + mock_input_pam_cert(pam_test_ctx, NULL, "123456", "SSSD Test Token", + TEST_MODULE_NAME, +- "C554C9F82C2A9D58B70921C143304153A8A42F17", NULL, ++ "C554C9F82C2A9D58B70921C143304153A8A42F17", ++ "SSSD test cert 0001", NULL, + test_lookup_by_cert_cb, SSSD_TEST_CERT_0001); + + mock_account_recv_simple(); +@@ -2360,7 +2363,7 @@ void test_pam_cert_auth_no_logon_name_no_key_id(void **state) + * to the user entry the lookup by certificate will already find the user + * in the cache and no second request to the backend is needed. */ + mock_input_pam_cert(pam_test_ctx, NULL, "123456", "SSSD Test Token", +- TEST_MODULE_NAME, NULL, NULL, ++ TEST_MODULE_NAME, NULL, NULL, NULL, + NULL, NULL); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); +@@ -2387,7 +2390,8 @@ void test_pam_cert_auth_double_cert(void **state) + + mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token", + TEST_MODULE_NAME, +- "C554C9F82C2A9D58B70921C143304153A8A42F17", NULL, ++ "C554C9F82C2A9D58B70921C143304153A8A42F17", ++ "SSSD test cert 0001", NULL, + test_lookup_by_cert_double_cb, SSSD_TEST_CERT_0001); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); +@@ -2416,7 +2420,7 @@ void test_pam_cert_preauth_2certs_one_mapping(void **state) + ret = test_lookup_by_cert_cb(discard_const(SSSD_TEST_CERT_0001)); + assert_int_equal(ret, EOK); + mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, +- test_lookup_by_cert_cb, NULL); ++ NULL, test_lookup_by_cert_cb, NULL); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2439,7 +2443,7 @@ void test_pam_cert_preauth_2certs_two_mappings(void **state) + putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_two.conf")); + + mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, +- test_lookup_by_cert_cb_2nd_cert_same_user, ++ NULL, test_lookup_by_cert_cb_2nd_cert_same_user, + SSSD_TEST_CERT_0001); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2464,7 +2468,8 @@ void test_pam_cert_auth_2certs_one_mapping(void **state) + + mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token", + TEST_MODULE_NAME, +- "C554C9F82C2A9D58B70921C143304153A8A42F17", NULL, ++ "C554C9F82C2A9D58B70921C143304153A8A42F17", ++ "SSSD test cert 0001", NULL, + test_lookup_by_cert_double_cb, SSSD_TEST_CERT_0001); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); +@@ -2498,7 +2503,7 @@ void test_pam_cert_preauth_uri_token1(void **state) + putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_2tokens.conf")); + + mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, +- test_lookup_by_cert_cb, SSSD_TEST_CERT_0001); ++ NULL, test_lookup_by_cert_cb, SSSD_TEST_CERT_0001); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2528,7 +2533,7 @@ void test_pam_cert_preauth_uri_token2(void **state) + putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_2tokens.conf")); + + mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, +- test_lookup_by_cert_cb, SSSD_TEST_CERT_0002); ++ NULL, test_lookup_by_cert_cb, SSSD_TEST_CERT_0002); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2567,7 +2572,7 @@ void test_pam_preauth_expired_crl_file(void **state) + set_cert_auth_param(pam_test_ctx->pctx, CA_DB); + + mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, +- NULL, NULL); ++ NULL, NULL, NULL); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2599,7 +2604,7 @@ void test_pam_preauth_expired_crl_file_soft(void **state) + set_cert_auth_param(pam_test_ctx->pctx, CA_DB); + + mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, +- test_lookup_by_cert_cb, SSSD_TEST_CERT_0001); ++ NULL, test_lookup_by_cert_cb, SSSD_TEST_CERT_0001); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2632,7 +2637,7 @@ void test_pam_preauth_ocsp(void **state) + putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_ocsp.conf")); + + mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, +- NULL, NULL); ++ NULL, NULL, NULL); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2674,7 +2679,7 @@ void test_pam_preauth_ocsp_no_ocsp(void **state) + putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_ocsp.conf")); + + mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, +- test_lookup_by_cert_cb, SSSD_TEST_CERT_0005); ++ NULL, test_lookup_by_cert_cb, SSSD_TEST_CERT_0005); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2708,7 +2713,7 @@ void test_pam_preauth_ocsp_soft_ocsp(void **state) + putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_ocsp.conf")); + + mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, +- test_lookup_by_cert_cb, SSSD_TEST_CERT_0005); ++ NULL, test_lookup_by_cert_cb, SSSD_TEST_CERT_0005); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +diff --git a/src/util/authtok-utils.c b/src/util/authtok-utils.c +index e50f86741..e76bd17c5 100644 +--- a/src/util/authtok-utils.c ++++ b/src/util/authtok-utils.c +@@ -77,6 +77,7 @@ errno_t sss_auth_pack_sc_blob(const char *pin, size_t pin_len, + const char *token_name, size_t token_name_len, + const char *module_name, size_t module_name_len, + const char *key_id, size_t key_id_len, ++ const char *label, size_t label_len, + uint8_t *buf, size_t buf_len, + size_t *_sc_blob_len) + { +@@ -88,7 +89,8 @@ errno_t sss_auth_pack_sc_blob(const char *pin, size_t pin_len, + || (pin_len != 0 && pin == NULL) + || (token_name_len != 0 && token_name == NULL) + || (module_name_len != 0 && module_name == NULL) +- || (key_id_len != 0 && key_id == NULL)) { ++ || (key_id_len != 0 && key_id == NULL) ++ || (label_len != 0 && label == NULL)) { + return EINVAL; + } + +@@ -113,6 +115,11 @@ errno_t sss_auth_pack_sc_blob(const char *pin, size_t pin_len, + key_id_len = 0; + } + ++ if (label == NULL) { ++ label = ""; ++ label_len = 0; ++ } ++ + /* len should not include the trailing \0 */ + if (pin_len == 0 || pin[pin_len - 1] == '\0') { + pin_len = strlen(pin); +@@ -130,8 +137,12 @@ errno_t sss_auth_pack_sc_blob(const char *pin, size_t pin_len, + key_id_len = strlen(key_id); + } + +- *_sc_blob_len = pin_len + token_name_len + module_name_len + key_id_len + 4 +- + 4 * sizeof(uint32_t); ++ if (label_len == 0 || label[label_len - 1] == '\0') { ++ label_len = strlen(label); ++ } ++ ++ *_sc_blob_len = pin_len + token_name_len + module_name_len + key_id_len ++ + label_len + 5 + 5 * sizeof(uint32_t); + if (buf == NULL || buf_len < *_sc_blob_len) { + return EAGAIN; + } +@@ -145,6 +156,8 @@ errno_t sss_auth_pack_sc_blob(const char *pin, size_t pin_len, + SAFEALIGN_COPY_UINT32(buf + c, &tmp_uint32_t, &c); + tmp_uint32_t = (uint32_t) key_id_len + 1; + SAFEALIGN_COPY_UINT32(buf + c, &tmp_uint32_t, &c); ++ tmp_uint32_t = (uint32_t) label_len + 1; ++ SAFEALIGN_COPY_UINT32(buf + c, &tmp_uint32_t, &c); + + memcpy(buf + c, pin, pin_len); + buf[c + pin_len] = '\0'; +@@ -160,6 +173,10 @@ errno_t sss_auth_pack_sc_blob(const char *pin, size_t pin_len, + + memcpy(buf + c, key_id, key_id_len); + buf[c + key_id_len] = '\0'; ++ c += key_id_len +1; ++ ++ memcpy(buf + c, label, label_len); ++ buf[c + label_len] = '\0'; + + return 0; + } +@@ -171,6 +188,7 @@ const char *sss_auth_get_pin_from_sc_blob(uint8_t *blob, size_t blob_len) + uint32_t token_name_len; + uint32_t module_name_len; + uint32_t key_id_len; ++ uint32_t label_len; + + if (blob == NULL || blob_len == 0) { + return NULL; +@@ -184,9 +202,11 @@ const char *sss_auth_get_pin_from_sc_blob(uint8_t *blob, size_t blob_len) + SAFEALIGN_COPY_UINT32(&token_name_len, blob + c, &c); + SAFEALIGN_COPY_UINT32(&module_name_len, blob + c, &c); + SAFEALIGN_COPY_UINT32(&key_id_len, blob + c, &c); ++ SAFEALIGN_COPY_UINT32(&label_len, blob + c, &c); + +- if (blob_len != 4 * sizeof(uint32_t) + pin_len + token_name_len +- + module_name_len + key_id_len) { ++ if (blob_len != 5 * sizeof(uint32_t) + pin_len + token_name_len ++ + module_name_len + key_id_len ++ + label_len) { + return NULL; + } + +diff --git a/src/util/authtok-utils.h b/src/util/authtok-utils.h +index 714c8187e..f3b268f78 100644 +--- a/src/util/authtok-utils.h ++++ b/src/util/authtok-utils.h +@@ -39,6 +39,9 @@ + * @param[in] key_id Key ID of the certificate + * @param[in] key_id_len Length of the key id of the certificate, if 0 + * strlen() will be called internally ++ * @param[in] label Label of the certificate ++ * @param[in] label_len Length of the label of the certificate, if 0 ++ * strlen() will be called internally + * @param[in] buf memory buffer of size buf_len, may be NULL + * @param[in] buf_len size of memory buffer buf + * +@@ -53,6 +56,7 @@ errno_t sss_auth_pack_sc_blob(const char *pin, size_t pin_len, + const char *token_name, size_t token_name_len, + const char *module_name, size_t module_name_len, + const char *key_id, size_t key_id_len, ++ const char *label, size_t label_len, + uint8_t *buf, size_t buf_len, + size_t *_sc_blob_len); + /** +@@ -112,6 +116,10 @@ errno_t sss_auth_unpack_2fa_blob(TALLOC_CTX *mem_ctx, + * @param[out] _token_name_len Length of the token name + * @param[out] _module_name Name of PKCS#11 module, null terminated + * @param[out] _module_name_len Length of the module name ++ * @param[out] _key_id Key ID of the certificate, null terminated ++ * @param[out] _key_id_len Length of the key ID ++ * @param[out] _labe l Label of the certificate, null terminated ++ * @param[out] _label_len Length of the label + * + * @return EOK on success + * EINVAL if input data is not consistent +@@ -122,7 +130,8 @@ errno_t sss_auth_unpack_sc_blob(TALLOC_CTX *mem_ctx, + char **pin, size_t *_pin_len, + char **token_name, size_t *_token_name_len, + char **module_name, size_t *_module_name_len, +- char **key_id, size_t *_key_id_len); ++ char **key_id, size_t *_key_id_len, ++ char **label, size_t *_label_len); + + /** + * @brief Return a pointer to the PIN string in the memory buffer +diff --git a/src/util/authtok.c b/src/util/authtok.c +index f8b44d6d6..7254ed1da 100644 +--- a/src/util/authtok.c ++++ b/src/util/authtok.c +@@ -503,7 +503,8 @@ errno_t sss_authtok_set_sc(struct sss_auth_token *tok, + const char *pin, size_t pin_len, + const char *token_name, size_t token_name_len, + const char *module_name, size_t module_name_len, +- const char *key_id, size_t key_id_len) ++ const char *key_id, size_t key_id_len, ++ const char *label, size_t label_len) + { + int ret; + size_t needed_size; +@@ -518,7 +519,7 @@ errno_t sss_authtok_set_sc(struct sss_auth_token *tok, + + ret = sss_auth_pack_sc_blob(pin, pin_len, token_name, token_name_len, + module_name, module_name_len, +- key_id, key_id_len, NULL, 0, ++ key_id, key_id_len, label, label_len, NULL, 0, + &needed_size); + if (ret != EAGAIN) { + DEBUG(SSSDBG_OP_FAILURE, "sss_auth_pack_sc_blob failed.\n"); +@@ -533,7 +534,7 @@ errno_t sss_authtok_set_sc(struct sss_auth_token *tok, + + ret = sss_auth_pack_sc_blob(pin, pin_len, token_name, token_name_len, + module_name, module_name_len, +- key_id, key_id_len, tok->data, ++ key_id, key_id_len, label, label_len, tok->data, + needed_size, &needed_size); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_auth_pack_sc_blob failed.\n"); +@@ -560,6 +561,8 @@ errno_t sss_authtok_set_sc_from_blob(struct sss_auth_token *tok, + size_t module_name_len; + char *key_id = NULL; + size_t key_id_len; ++ char *label = NULL; ++ size_t label_len; + TALLOC_CTX *tmp_ctx; + + if (tok == NULL) { +@@ -579,7 +582,7 @@ errno_t sss_authtok_set_sc_from_blob(struct sss_auth_token *tok, + ret = sss_auth_unpack_sc_blob(tmp_ctx, data, len, &pin, &pin_len, + &token_name, &token_name_len, + &module_name, &module_name_len, +- &key_id, &key_id_len); ++ &key_id, &key_id_len, &label, &label_len); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_auth_unpack_sc_blob failed.\n"); + goto done; +@@ -588,7 +591,7 @@ errno_t sss_authtok_set_sc_from_blob(struct sss_auth_token *tok, + ret = sss_authtok_set_sc(tok, SSS_AUTHTOK_TYPE_SC_PIN, pin, pin_len, + token_name, token_name_len, + module_name, module_name_len, +- key_id, key_id_len); ++ key_id, key_id_len, label, label_len); + + done: + talloc_free(tmp_ctx); +@@ -607,7 +610,7 @@ errno_t sss_authtok_set_sc_pin(struct sss_auth_token *tok, const char *pin, + } + + return sss_authtok_set_sc(tok, SSS_AUTHTOK_TYPE_SC_PIN, pin, len, +- NULL, 0, NULL, 0, NULL, 0); ++ NULL, 0, NULL, 0, NULL, 0, NULL, 0); + } + + errno_t sss_authtok_get_sc_pin(struct sss_auth_token *tok, const char **_pin, +@@ -625,7 +628,8 @@ errno_t sss_authtok_get_sc_pin(struct sss_auth_token *tok, const char **_pin, + return ENOENT; + case SSS_AUTHTOK_TYPE_SC_PIN: + ret = sss_authtok_get_sc(tok, &pin, &pin_len, +- NULL, NULL, NULL, NULL, NULL, NULL); ++ NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc failed.\n"); + return ret; +@@ -663,13 +667,15 @@ errno_t sss_auth_unpack_sc_blob(TALLOC_CTX *mem_ctx, + char **pin, size_t *_pin_len, + char **token_name, size_t *_token_name_len, + char **module_name, size_t *_module_name_len, +- char **key_id, size_t *_key_id_len) ++ char **key_id, size_t *_key_id_len, ++ char **label, size_t *_label_len) + { + size_t c; + uint32_t pin_len; + uint32_t token_name_len; + uint32_t module_name_len; + uint32_t key_id_len; ++ uint32_t label_len; + + c = 0; + +@@ -678,14 +684,16 @@ errno_t sss_auth_unpack_sc_blob(TALLOC_CTX *mem_ctx, + token_name_len = 0; + module_name_len = 0; + key_id_len = 0; ++ label_len = 0; + } else if (blob_len > 0 + && strnlen((const char *) blob, blob_len) == blob_len - 1) { + pin_len = blob_len; + token_name_len = 0; + module_name_len = 0; + key_id_len = 0; ++ label_len = 0; + } else { +- if (blob_len < 4 * sizeof(uint32_t)) { ++ if (blob_len < 5 * sizeof(uint32_t)) { + DEBUG(SSSDBG_CRIT_FAILURE, "Blob too small.\n"); + return EINVAL; + } +@@ -694,9 +702,11 @@ errno_t sss_auth_unpack_sc_blob(TALLOC_CTX *mem_ctx, + SAFEALIGN_COPY_UINT32(&token_name_len, blob + c, &c); + SAFEALIGN_COPY_UINT32(&module_name_len, blob + c, &c); + SAFEALIGN_COPY_UINT32(&key_id_len, blob + c, &c); ++ SAFEALIGN_COPY_UINT32(&label_len, blob + c, &c); + +- if (blob_len != 4 * sizeof(uint32_t) + pin_len + token_name_len +- + module_name_len + key_id_len) { ++ if (blob_len != 5 * sizeof(uint32_t) + pin_len + token_name_len ++ + module_name_len + key_id_len ++ + label_len) { + DEBUG(SSSDBG_CRIT_FAILURE, "Blob size mismatch.\n"); + return EINVAL; + } +@@ -756,6 +766,25 @@ errno_t sss_auth_unpack_sc_blob(TALLOC_CTX *mem_ctx, + *key_id = NULL; + } + ++ if (label_len != 0) { ++ *label = talloc_strndup(mem_ctx, ++ (const char *) blob + c + pin_len ++ + token_name_len ++ + module_name_len ++ + key_id_len, ++ label_len); ++ if (*label == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); ++ talloc_free(*pin); ++ talloc_free(*token_name); ++ talloc_free(*module_name); ++ talloc_free(*key_id); ++ return ENOMEM; ++ } ++ } else { ++ *label = NULL; ++ } ++ + /* Re-calculate length for the case where \0 was missing in the blob */ + if (_pin_len != NULL) { + *_pin_len = (*pin == NULL) ? 0 : strlen(*pin); +@@ -771,6 +800,10 @@ errno_t sss_auth_unpack_sc_blob(TALLOC_CTX *mem_ctx, + *_key_id_len = (*key_id == NULL) ? 0 : strlen(*key_id); + } + ++ if (_label_len != NULL) { ++ *_label_len = (*label == NULL) ? 0 : strlen(*label); ++ } ++ + return EOK; + } + +@@ -778,13 +811,15 @@ errno_t sss_authtok_get_sc(struct sss_auth_token *tok, + const char **_pin, size_t *_pin_len, + const char **_token_name, size_t *_token_name_len, + const char **_module_name, size_t *_module_name_len, +- const char **_key_id, size_t *_key_id_len) ++ const char **_key_id, size_t *_key_id_len, ++ const char **_label, size_t *_label_len) + { + size_t c = 0; + size_t pin_len; + size_t token_name_len; + size_t module_name_len; + size_t key_id_len; ++ size_t label_len; + uint32_t tmp_uint32_t; + + if (!tok) { +@@ -796,7 +831,7 @@ errno_t sss_authtok_get_sc(struct sss_auth_token *tok, + return (tok->type == SSS_AUTHTOK_TYPE_EMPTY) ? ENOENT : EACCES; + } + +- if (tok->length < 4 * sizeof(uint32_t)) { ++ if (tok->length < 5 * sizeof(uint32_t)) { + DEBUG(SSSDBG_CRIT_FAILURE, "Blob too small.\n"); + return EINVAL; + } +@@ -809,9 +844,12 @@ errno_t sss_authtok_get_sc(struct sss_auth_token *tok, + module_name_len = tmp_uint32_t -1; + SAFEALIGN_COPY_UINT32(&tmp_uint32_t, tok->data + c, &c); + key_id_len = tmp_uint32_t -1; ++ SAFEALIGN_COPY_UINT32(&tmp_uint32_t, tok->data + c, &c); ++ label_len = tmp_uint32_t -1; + +- if (tok->length != 4 * sizeof(uint32_t) + 4 + pin_len + token_name_len +- + module_name_len + key_id_len) { ++ if (tok->length != 5 * sizeof(uint32_t) + 5 + pin_len + token_name_len ++ + module_name_len + key_id_len ++ + label_len) { + DEBUG(SSSDBG_CRIT_FAILURE, "Blob size mismatch.\n"); + return EINVAL; + } +@@ -846,5 +884,14 @@ errno_t sss_authtok_get_sc(struct sss_auth_token *tok, + *_key_id_len = key_id_len; + } + ++ if (_label != NULL) { ++ *_label = (const char *) tok->data + c + pin_len + 1 ++ + token_name_len + 1 + module_name_len + 1 ++ + key_id_len + 1; ++ } ++ if (_label_len != NULL) { ++ *_label_len = label_len; ++ } ++ + return EOK; + } +diff --git a/src/util/authtok.h b/src/util/authtok.h +index f70c9da13..6fd3e9ef0 100644 +--- a/src/util/authtok.h ++++ b/src/util/authtok.h +@@ -296,6 +296,10 @@ void sss_authtok_set_sc_keypad(struct sss_auth_token *tok); + * terminated string containing the PKCS#11 key id + * @param key_id_len The length of the key id string, if set to 0 it will be + * calculated ++ * @param label A pointer to a const char *, that will point to a null ++ * terminated string containing the PKCS#11 label ++ * @param label_len The length of the label string, if set to 0 it will be ++ * calculated + * + * @return EOK on success + * EINVAL unexpected or inval input +@@ -306,7 +310,8 @@ errno_t sss_authtok_set_sc(struct sss_auth_token *tok, + const char *pin, size_t pin_len, + const char *token_name, size_t token_name_len, + const char *module_name, size_t module_name_len, +- const char *key_id, size_t key_id_len); ++ const char *key_id, size_t key_id_len, ++ const char *label, size_t label_len); + /** + * @brief Set a Smart Card authentication data, replacing any previous data + * +@@ -342,6 +347,10 @@ errno_t sss_authtok_set_sc_from_blob(struct sss_auth_token *tok, + * a null terminated string holding the PKCS#11 + * key id, may not be modified or freed + * @param[out] _key_id_len Length of the PKCS#11 key id ++ * @param[out] _label A pointer to a const char *, that will point to ++ * a null terminated string holding the PKCS#11 ++ * label, may not be modified or freed ++ * @param[out] _label_len Length of the PKCS#11 label + * + * Any of the output pointers may be NULL if the caller does not need the + * specific item. +@@ -356,7 +365,8 @@ errno_t sss_authtok_get_sc(struct sss_auth_token *tok, + const char **_pin, size_t *_pin_len, + const char **_token_name, size_t *_token_name_len, + const char **_module_name, size_t *_module_name_len, +- const char **_key_id, size_t *_key_id_len); ++ const char **_key_id, size_t *_key_id_len, ++ const char **_label, size_t *_label_len); + + + /** +-- +2.21.3 + diff --git a/SOURCES/0015-pam_sss-add-certificate-label-to-reply-to-pam_sss.patch b/SOURCES/0015-pam_sss-add-certificate-label-to-reply-to-pam_sss.patch new file mode 100644 index 0000000..88fcc9f --- /dev/null +++ b/SOURCES/0015-pam_sss-add-certificate-label-to-reply-to-pam_sss.patch @@ -0,0 +1,208 @@ +From b8800d3e1b43f2eb28b2df7adb2bcb323bf2d1f1 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Sat, 14 Nov 2020 17:52:35 +0100 +Subject: [PATCH 15/16] pam_sss: add certificate label to reply to pam_sss + +Add the certificate label to the data send back and forth to the pam +module to avoid the ambiguity if two certificates use the same key. + +Resolves: https://github.com/SSSD/sssd/issues/5400 + +Reviewed-by: Alexey Tikhonov +--- + src/responder/pam/pamsrv_p11.c | 13 ++++++++++--- + src/sss_client/pam_sss.c | 15 +++++++++++++++ + src/tests/cmocka/test_pam_srv.c | 20 ++++++++++++++++---- + 3 files changed, 41 insertions(+), 7 deletions(-) + +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index 23f94927a..e1fd72e64 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -1086,11 +1086,13 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, + const char *token_name; + const char *module_name; + const char *key_id; ++ const char *label; + char *prompt; + size_t user_len; + size_t token_len; + size_t module_len; + size_t key_id_len; ++ size_t label_len; + size_t prompt_len; + size_t nss_name_len; + const char *username = ""; +@@ -1113,16 +1115,18 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, + token_name = sss_cai_get_token_name(cert_info); + module_name = sss_cai_get_module_name(cert_info); + key_id = sss_cai_get_key_id(cert_info); ++ label = sss_cai_get_label(cert_info); + + user_len = strlen(username) + 1; + token_len = strlen(token_name) + 1; + module_len = strlen(module_name) + 1; + key_id_len = strlen(key_id) + 1; ++ label_len = strlen(label) + 1; + prompt_len = strlen(prompt) + 1; + nss_name_len = strlen(nss_username) +1; + +- msg_len = user_len + token_len + module_len + key_id_len + prompt_len +- + nss_name_len; ++ msg_len = user_len + token_len + module_len + key_id_len + label_len ++ + prompt_len + nss_name_len; + + msg = talloc_zero_size(mem_ctx, msg_len); + if (msg == NULL) { +@@ -1136,8 +1140,11 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, + memcpy(msg + user_len + token_len, module_name, module_len); + memcpy(msg + user_len + token_len + module_len, key_id, key_id_len); + memcpy(msg + user_len + token_len + module_len + key_id_len, ++ label, label_len); ++ memcpy(msg + user_len + token_len + module_len + key_id_len + label_len, + prompt, prompt_len); +- memcpy(msg + user_len + token_len + module_len + key_id_len + prompt_len, ++ memcpy(msg + user_len + token_len + module_len + key_id_len + label_len ++ + prompt_len, + nss_username, nss_name_len); + talloc_free(prompt); + +diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c +index cffbfa770..c539d6de6 100644 +--- a/src/sss_client/pam_sss.c ++++ b/src/sss_client/pam_sss.c +@@ -142,6 +142,7 @@ static void free_cai(struct cert_auth_info *cai) + free(cai->token_name); + free(cai->module_name); + free(cai->key_id); ++ free(cai->label); + free(cai->prompt_str); + free(cai->choice_list_id); + free(cai); +@@ -936,6 +937,20 @@ static int parse_cert_info(struct pam_items *pi, uint8_t *buf, size_t len, + goto done; + } + ++ cai->label = strdup((char *) &buf[*p + offset]); ++ if (cai->label == NULL) { ++ D(("strdup failed")); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ offset += strlen(cai->label) + 1; ++ if (offset >= len) { ++ D(("Cert message size mismatch")); ++ ret = EINVAL; ++ goto done; ++ } ++ + cai->prompt_str = strdup((char *) &buf[*p + offset]); + if (cai->prompt_str == NULL) { + D(("strdup failed")); +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index cb05042de..5506fbf34 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -62,13 +62,16 @@ + #define TEST_TOKEN_NAME "SSSD Test Token" + #define TEST_TOKEN2_NAME "SSSD Test Token Number 2" + #define TEST_KEY_ID "C554C9F82C2A9D58B70921C143304153A8A42F17" ++#define TEST_LABEL "SSSD test cert 0001" + #define TEST_MODULE_NAME SOFTHSM2_PATH + #define TEST_PROMPT "SSSD test cert 0001\nCN=SSSD test cert 0001,OU=SSSD test,O=SSSD" + #define TEST2_PROMPT "SSSD test cert 0002\nCN=SSSD test cert 0002,OU=SSSD test,O=SSSD" + #define TEST5_PROMPT "SSSD test cert 0005\nCN=SSSD test cert 0005,OU=SSSD test,O=SSSD" + + #define TEST2_KEY_ID "5405842D56CF31F0BB025A695C5F3E907051C5B9" ++#define TEST2_LABEL "SSSD test cert 0002" + #define TEST5_KEY_ID "1195833C424AB00297F582FC43FFFFAB47A64CC9" ++#define TEST5_LABEL "SSSD test cert 0005" + + static char CACHED_AUTH_TIMEOUT_STR[] = "4"; + static const int CACHED_AUTH_TIMEOUT = 4; +@@ -673,6 +676,7 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) + + sizeof(TEST_KEY_ID) ++ + sizeof(TEST_LABEL) + + sizeof(TEST_PROMPT) + + sizeof("pamuser"))); + +@@ -692,6 +696,10 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, + assert_string_equal(body + rp, TEST_KEY_ID); + rp += sizeof(TEST_KEY_ID); + ++ assert_int_equal(*(body + rp + sizeof(TEST_LABEL) - 1), 0); ++ assert_string_equal(body + rp, TEST_LABEL); ++ rp += sizeof(TEST_LABEL); ++ + assert_int_equal(*(body + rp + sizeof(TEST_PROMPT) - 1), 0); + assert_string_equal(body + rp, TEST_PROMPT); + rp += sizeof(TEST_PROMPT); +@@ -740,6 +748,7 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + TEST_TOKEN_NAME, + TEST_MODULE_NAME, + TEST_KEY_ID, ++ TEST_LABEL, + TEST_PROMPT, + NULL, + NULL }; +@@ -749,6 +758,7 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + TEST_TOKEN_NAME, + TEST_MODULE_NAME, + TEST2_KEY_ID, ++ TEST2_LABEL, + TEST2_PROMPT, + NULL, + NULL }; +@@ -756,10 +766,10 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_int_equal(status, 0); + + check_strings[0] = name; +- check_strings[5] = nss_name; ++ check_strings[6] = nss_name; + check_len = check_string_array_len(check_strings); + check2_strings[0] = name; +- check2_strings[5] = nss_name; ++ check2_strings[6] = nss_name; + check2_len = check_string_array_len(check2_strings); + + +@@ -843,6 +853,7 @@ static int test_pam_cert2_token2_check_ex(uint32_t status, uint8_t *body, + TEST_TOKEN2_NAME, + TEST_MODULE_NAME, + TEST2_KEY_ID, ++ TEST2_LABEL, + TEST2_PROMPT, + NULL, + NULL }; +@@ -850,7 +861,7 @@ static int test_pam_cert2_token2_check_ex(uint32_t status, uint8_t *body, + assert_int_equal(status, 0); + + check2_strings[0] = name; +- check2_strings[5] = nss_name; ++ check2_strings[6] = nss_name; + check2_len = check_string_array_len(check2_strings); + + SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); +@@ -895,7 +906,7 @@ static int test_pam_cert_X_token_X_check_ex(uint32_t status, uint8_t *body, + assert_int_equal(status, 0); + + check_strings[0] = name; +- check_strings[5] = nss_name; ++ check_strings[6] = nss_name; + check_len = check_string_array_len(check_strings); + + SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); +@@ -946,6 +957,7 @@ static int test_pam_cert5_check(uint32_t status, uint8_t *body, size_t blen) + TEST_TOKEN_NAME, + TEST_MODULE_NAME, + TEST5_KEY_ID, ++ TEST5_LABEL, + TEST5_PROMPT, + NULL, + NULL }; +-- +2.21.3 + diff --git a/SOURCES/0016-add-tests-multiple-certs-same-id.patch b/SOURCES/0016-add-tests-multiple-certs-same-id.patch new file mode 100644 index 0000000..cd9cefd --- /dev/null +++ b/SOURCES/0016-add-tests-multiple-certs-same-id.patch @@ -0,0 +1,265 @@ +From f633f37e712cb0f7524a2ee257e15f34468149b4 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 3 Nov 2020 09:58:52 +0100 +Subject: [PATCH 16/16] add tests multiple certs same id + +Add unit test for the case that two certificates use the same key. + +Resolves: https://github.com/SSSD/sssd/issues/5400 + +Reviewed-by: Alexey Tikhonov +--- + src/tests/cmocka/test_pam_srv.c | 116 +++++++++++++++++++ + src/tests/test_CA/Makefile.am | 26 ++++- + src/tests/test_CA/SSSD_test_cert_0006.config | 20 ++++ + 3 files changed, 161 insertions(+), 1 deletion(-) + create mode 100644 src/tests/test_CA/SSSD_test_cert_0006.config + +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index 5506fbf34..8ca5abd43 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -40,12 +40,14 @@ + #include "tests/test_CA/SSSD_test_cert_x509_0001.h" + #include "tests/test_CA/SSSD_test_cert_x509_0002.h" + #include "tests/test_CA/SSSD_test_cert_x509_0005.h" ++#include "tests/test_CA/SSSD_test_cert_x509_0006.h" + + #include "tests/test_ECC_CA/SSSD_test_ECC_cert_x509_0001.h" + #else + #define SSSD_TEST_CERT_0001 "" + #define SSSD_TEST_CERT_0002 "" + #define SSSD_TEST_CERT_0005 "" ++#define SSSD_TEST_CERT_0006 "" + + #define SSSD_TEST_ECC_CERT_0001 "" + #endif +@@ -1093,6 +1095,13 @@ static int test_pam_creds_insufficient_check(uint32_t status, + return EOK; + } + ++static int test_pam_auth_err_check(uint32_t status, uint8_t *body, size_t blen) ++{ ++ /* PAM_AUTH_ERR is returned for different types of error, we use different ++ * names for the check functions to make the purpose more clear. */ ++ return test_pam_wrong_pw_offline_auth_check(status, body, blen); ++} ++ + static int test_pam_user_unknown_check(uint32_t status, + uint8_t *body, size_t blen) + { +@@ -2500,6 +2509,107 @@ void test_pam_cert_auth_2certs_one_mapping(void **state) + assert_int_equal(ret, EOK); + } + ++/* The following three tests cover a use case where multiple certificates are ++ * using the same key-pair. According to PKCS#11 specs "The CKA_ID field is ++ * intended to distinguish among multiple keys. In the case of public and ++ * private keys, this field assists in handling multiple keys held by the same ++ * subject; the key identifier for a public key and its corresponding private ++ * key should be the same. The key identifier should also be the same as for ++ * the corresponding certificate, if one exists. Cryptoki does not enforce ++ * these associations, however." As a result certificates sharing the same ++ * key-pair will have the same id on the Smartcard. This means a second ++ * parameter is needed to distinguish them. We use the label here. ++ * ++ * The first test makes sure authentication fails is the label is missing, the ++ * second and third test make sure that each certificate can be selected with ++ * the proper label. */ ++void test_pam_cert_auth_2certs_same_id_no_label(void **state) ++{ ++ int ret; ++ ++ set_cert_auth_param(pam_test_ctx->pctx, CA_DB); ++ putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_2certs_same_id.conf")); ++ ++ mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token", ++ TEST_MODULE_NAME, ++ "11111111", ++ NULL, NULL, ++ NULL, SSSD_TEST_CERT_0001); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ /* Assume backend cannot handle Smartcard credentials */ ++ pam_test_ctx->exp_pam_status = PAM_BAD_ITEM; ++ ++ set_cmd_cb(test_pam_auth_err_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_cert_auth_2certs_same_id_with_label_1(void **state) ++{ ++ int ret; ++ ++ set_cert_auth_param(pam_test_ctx->pctx, CA_DB); ++ putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_2certs_same_id.conf")); ++ ++ mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token", ++ TEST_MODULE_NAME, ++ "11111111", ++ "SSSD test cert 0001", NULL, ++ test_lookup_by_cert_double_cb, SSSD_TEST_CERT_0001); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ /* Assume backend cannot handle Smartcard credentials */ ++ pam_test_ctx->exp_pam_status = PAM_BAD_ITEM; ++ ++ set_cmd_cb(test_pam_simple_check_success); ++ 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_cert_auth_2certs_same_id_with_label_6(void **state) ++{ ++ int ret; ++ ++ set_cert_auth_param(pam_test_ctx->pctx, CA_DB); ++ putenv(discard_const("SOFTHSM2_CONF=" ABS_BUILD_DIR "/src/tests/test_CA/softhsm2_2certs_same_id.conf")); ++ ++ mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token", ++ TEST_MODULE_NAME, ++ "11111111", ++ "SSSD test cert 0006", NULL, ++ test_lookup_by_cert_double_cb, SSSD_TEST_CERT_0006); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ /* Assume backend cannot handle Smartcard credentials */ ++ pam_test_ctx->exp_pam_status = PAM_BAD_ITEM; ++ ++ set_cmd_cb(test_pam_simple_check_success); ++ 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_cert_preauth_uri_token1(void **state) + { + int ret; +@@ -3179,6 +3289,12 @@ int main(int argc, const char *argv[]) + pam_test_setup, pam_test_teardown), + cmocka_unit_test_setup_teardown(test_pam_cert_auth_2certs_one_mapping, + pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_pam_cert_auth_2certs_same_id_no_label, ++ pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_pam_cert_auth_2certs_same_id_with_label_1, ++ pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_pam_cert_auth_2certs_same_id_with_label_6, ++ pam_test_setup, pam_test_teardown), + cmocka_unit_test_setup_teardown(test_pam_cert_auth_no_logon_name, + pam_test_setup, pam_test_teardown), + cmocka_unit_test_setup_teardown(test_pam_cert_auth_no_logon_name_no_key_id, +diff --git a/src/tests/test_CA/Makefile.am b/src/tests/test_CA/Makefile.am +index 0e0122737..8765d0fd6 100644 +--- a/src/tests/test_CA/Makefile.am ++++ b/src/tests/test_CA/Makefile.am +@@ -6,6 +6,7 @@ dist_noinst_DATA = \ + SSSD_test_cert_0003.config \ + SSSD_test_cert_0004.config \ + SSSD_test_cert_0005.config \ ++ SSSD_test_cert_0006.config \ + SSSD_test_cert_key_0001.pem \ + SSSD_test_cert_key_0002.pem \ + SSSD_test_cert_key_0003.pem \ +@@ -25,7 +26,7 @@ pubkeys = $(addprefix SSSD_test_cert_pubsshkey_,$(addsuffix .pub,$(ids))) + pubkeys_h = $(addprefix SSSD_test_cert_pubsshkey_,$(addsuffix .h,$(ids))) + pkcs12 = $(addprefix SSSD_test_cert_pkcs12_,$(addsuffix .pem,$(ids))) + +-extra = softhsm2_none softhsm2_one softhsm2_two softhsm2_2tokens softhsm2_ocsp ++extra = softhsm2_none softhsm2_one softhsm2_two softhsm2_2tokens softhsm2_ocsp softhsm2_2certs_same_id + if HAVE_FAKETIME + extra += SSSD_test_CA_expired_crl.pem + endif +@@ -41,6 +42,14 @@ $(pwdfile): + SSSD_test_CA.pem: $(openssl_ca_key) $(openssl_ca_config) serial + $(OPENSSL) req -batch -config ${openssl_ca_config} -x509 -new -nodes -key $< -sha256 -days 1024 -set_serial 0 -extensions v3_ca -out $@ + ++# SSSD_test_cert_0006 should use the same key as SSSD_test_cert_0001 ++.INTERMEDIATE: SSSD_test_cert_req_0006.pem ++SSSD_test_cert_req_0006.pem: $(srcdir)/SSSD_test_cert_key_0001.pem $(srcdir)/SSSD_test_cert_0006.config ++ if [ $(shell grep -c req_exts $(srcdir)/SSSD_test_cert_0006.config) -eq 0 ]; then \ ++ $(OPENSSL) req -new -nodes -key $< -config $(srcdir)/SSSD_test_cert_0006.config -out $@ ; \ ++ else \ ++ $(OPENSSL) req -new -nodes -key $< -reqexts req_exts -config $(srcdir)/SSSD_test_cert_0006.config -out $@ ; \ ++ fi + + SSSD_test_cert_req_%.pem: $(srcdir)/SSSD_test_cert_key_%.pem $(srcdir)/SSSD_test_cert_%.config + if [ $(shell grep -c req_exts $(srcdir)/SSSD_test_cert_$*.config) -eq 0 ]; then \ +@@ -52,6 +61,9 @@ SSSD_test_cert_req_%.pem: $(srcdir)/SSSD_test_cert_key_%.pem $(srcdir)/SSSD_test + SSSD_test_cert_x509_%.pem: SSSD_test_cert_req_%.pem $(openssl_ca_config) SSSD_test_CA.pem + $(OPENSSL) ca -config ${openssl_ca_config} -batch -notext -keyfile $(openssl_ca_key) -in $< -days 200 -extensions usr_cert -out $@ + ++SSSD_test_cert_pkcs12_0006.pem: SSSD_test_cert_x509_0006.pem $(srcdir)/SSSD_test_cert_key_0001.pem $(pwdfile) ++ $(OPENSSL) pkcs12 -export -in SSSD_test_cert_x509_0006.pem -inkey $(srcdir)/SSSD_test_cert_key_0001.pem -nodes -passout file:$(pwdfile) -out $@ ++ + SSSD_test_cert_pkcs12_%.pem: SSSD_test_cert_x509_%.pem $(srcdir)/SSSD_test_cert_key_%.pem $(pwdfile) + $(OPENSSL) pkcs12 -export -in SSSD_test_cert_x509_$*.pem -inkey $(srcdir)/SSSD_test_cert_key_$*.pem -nodes -passout file:$(pwdfile) -out $@ + +@@ -130,6 +142,18 @@ softhsm2_ocsp.conf: + @echo "objectstore.backend = file" >> $@ + @echo "slots.removable = true" >> $@ + ++softhsm2_2certs_same_id: softhsm2_2certs_same_id.conf SSSD_test_cert_x509_0001.pem SSSD_test_cert_x509_0006.pem ++ mkdir $@ ++ SOFTHSM2_CONF=./$< $(SOFTHSM2_UTIL) --init-token --label "SSSD Test Token" --pin 123456 --so-pin 123456 --free ++ GNUTLS_PIN=123456 SOFTHSM2_CONF=./$< $(P11TOOL) --provider=$(SOFTHSM2_PATH) --write --no-mark-private --load-certificate=SSSD_test_cert_x509_0006.pem --login --label 'SSSD test cert 0006' --id '11111111' ++ GNUTLS_PIN=123456 SOFTHSM2_CONF=./$< $(P11TOOL) --provider=$(SOFTHSM2_PATH) --write --no-mark-private --load-certificate=SSSD_test_cert_x509_0001.pem --login --label 'SSSD test cert 0001' --id '11111111' ++ GNUTLS_PIN=123456 SOFTHSM2_CONF=./$< $(P11TOOL) --provider=$(SOFTHSM2_PATH) --write --load-privkey=$(srcdir)/SSSD_test_cert_key_0001.pem --login --label 'SSSD test cert 0001' --id '11111111' ++ ++softhsm2_2certs_same_id.conf: ++ @echo "directories.tokendir = "$(abs_top_builddir)"/src/tests/test_CA/softhsm2_2certs_same_id" > $@ ++ @echo "objectstore.backend = file" >> $@ ++ @echo "slots.removable = true" >> $@ ++ + CLEANFILES = \ + index.txt index.txt.attr \ + index.txt.attr.old index.txt.old \ +diff --git a/src/tests/test_CA/SSSD_test_cert_0006.config b/src/tests/test_CA/SSSD_test_cert_0006.config +new file mode 100644 +index 000000000..762de55cd +--- /dev/null ++++ b/src/tests/test_CA/SSSD_test_cert_0006.config +@@ -0,0 +1,20 @@ ++# This certificate is used in ++# - src/tests/cmocka/test_pam_srv.c ++# and should use the same key-pair as SSSD_test_cert_0001 ++[ req ] ++distinguished_name = req_distinguished_name ++prompt = no ++ ++[ req_distinguished_name ] ++O = SSSD ++OU = SSSD test ++CN = SSSD test cert 0006 ++ ++[ req_exts ] ++basicConstraints = CA:FALSE ++nsCertType = client, email ++nsComment = "SSSD test Certificate" ++subjectKeyIdentifier = hash ++keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment ++extendedKeyUsage = clientAuth, emailProtection ++subjectAltName = email:sssd-devel@lists.fedorahosted.org,URI:https://github.com/SSSD/sssd// +-- +2.21.3 + diff --git a/SOURCES/0017-data_provider_be-Add-random-offset-default.patch b/SOURCES/0017-data_provider_be-Add-random-offset-default.patch new file mode 100644 index 0000000..7574eec --- /dev/null +++ b/SOURCES/0017-data_provider_be-Add-random-offset-default.patch @@ -0,0 +1,53 @@ +From 1e9abd508ea5627465d528788645d4dbe53d7d31 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pawe=C5=82=20Po=C5=82awski?= +Date: Wed, 2 Dec 2020 03:00:26 +0100 +Subject: [PATCH 17/18] data_provider_be: Add random offset default + +Replace hardcoded default value of 30 with more meaningful +OFFLINE_TIMEOUT_RANDOM_OFFSET define. + +This value is used to calculate task timeout during offline +status checking by formula (from SSSD MAN page): + +new_interval = (old_interval * 2) + random_offset + +As it is explicite mentioned in documentation it should +be expressed in the code similar way. + +Reviewed-by: Iker Pedrosa +--- + src/providers/data_provider_be.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c +index 4c10d6b48..10421c6b4 100644 +--- a/src/providers/data_provider_be.c ++++ b/src/providers/data_provider_be.c +@@ -51,6 +51,7 @@ + #define ONLINE_CB_RETRY 3 + #define ONLINE_CB_RETRY_MAX_DELAY 4 + ++#define OFFLINE_TIMEOUT_RANDOM_OFFSET 30 + #define OFFLINE_TIMEOUT_DEFAULT 60 + #define OFFLINE_TIMEOUT_MAX_DEFAULT 3600 + +@@ -152,9 +153,13 @@ void be_mark_offline(struct be_ctx *ctx) + offline_timeout = get_offline_timeout(ctx); + offline_timeout_max = get_offline_timeout_max(ctx); + +- ret = be_ptask_create_sync(ctx, ctx, +- offline_timeout, offline_timeout, +- offline_timeout, 30, offline_timeout, ++ ret = be_ptask_create_sync(ctx, ++ ctx, ++ offline_timeout, ++ offline_timeout, ++ offline_timeout, ++ OFFLINE_TIMEOUT_RANDOM_OFFSET, ++ offline_timeout, + offline_timeout_max, + try_to_go_online, + ctx, "Check if online (periodic)", +-- +2.21.3 + diff --git a/SOURCES/0018-data_provider_be-MAN-page-update.patch b/SOURCES/0018-data_provider_be-MAN-page-update.patch new file mode 100644 index 0000000..15e4168 --- /dev/null +++ b/SOURCES/0018-data_provider_be-MAN-page-update.patch @@ -0,0 +1,59 @@ +From 171b664ec4a7c94583b35597bd7e1e72bf89d217 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pawe=C5=82=20Po=C5=82awski?= +Date: Wed, 2 Dec 2020 03:10:50 +0100 +Subject: [PATCH 18/18] data_provider_be: MAN page update + +Updated description of parameters: +* offline_timeout +* offline_timeout_max + +MAN page now explains that in some circumstances +corelation of offline_timeout and offline_timeout_max values +may lead to offline checking interval not incrementing. +This is a false positive error as in fact the value +just saturates almost instantly. + +Reviewed-by: Iker Pedrosa +--- + src/man/sssd.conf.5.xml | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index d637e2eaa..8b330de58 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -739,12 +739,12 @@ + offline_timeout + random_offset + + +- The random offset can increment up to 30 seconds. ++ The random offset value is from 0 to 30. + After each unsuccessful attempt to go online, + the new interval is recalculated by the following: + + +- new_interval = old_interval*2 + random_offset ++ new_interval = (old_interval * 2) + random_offset + + + Note that the maximum length of each interval +@@ -769,6 +769,16 @@ + + A value of 0 disables the incrementing behaviour. + ++ ++ The value of this parameter should be set in correlation ++ to offline_timeout parameter value. ++ ++ ++ With offline_timeout set to 60 (default value) there is no point ++ in setting offlinet_timeout_max to less than 120 as it will ++ saturate instantly. General rule here should be to set ++ offline_timeout_max to at least 4 times offline_timeout. ++ + + Although a value between 0 and offline_timeout may be + specified, it has the effect of overriding the +-- +2.21.3 + diff --git a/SOURCES/0019-logs-review.patch b/SOURCES/0019-logs-review.patch new file mode 100644 index 0000000..54fc132 --- /dev/null +++ b/SOURCES/0019-logs-review.patch @@ -0,0 +1,3410 @@ +From 69ef1cf763fca6b2c7174ddacf3f510c73cc27e6 Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Mon, 28 Dec 2020 19:36:48 +0100 +Subject: [PATCH] Squashed commit of the following: + +commit bd2f38abe95645b9b16b12d12dac6008b0d2a03b +Author: Alexey Tikhonov +Date: Tue Dec 15 18:47:25 2020 +0100 + + UTIL: find_domain_by_object_name_ex() changed log level + + It's up to user of this function to judge if fail to parse fqname is + a critical error. + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 0db68a1f95612fcbad18ca8107a4b170f446dd59 +Author: Alexey Tikhonov +Date: Tue Dec 15 17:26:09 2020 +0100 + + LDAP: sdap_save_grpmem(): log level changed + + There are legitimate reasons when sdap_save_grpmem() can be called + with `ignore_group_members = true` + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 00e3ac4a4f9b6c8da27daa3ed8c18664c99256bb +Author: Alexey Tikhonov +Date: Sun Dec 13 23:21:37 2020 +0100 + + LDAP: reduce log level in case of fail to store members of missing group (it might be built-in skipped intentionally) + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit dba7de0db3cbaee43ef06a1b7c847fbcf48f3708 +Author: Alexey Tikhonov +Date: Sun Dec 13 22:37:44 2020 +0100 + + SYSDB: changed logging in sysdb_get_real_name() + + Missing cache entry isn't an error. + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit e86599ba079611ed324ff1493a7173d11c1a7961 +Author: Alexey Tikhonov +Date: Sun Dec 13 22:22:36 2020 +0100 + + IPA: changed logging in ipa_get_subdom_acct_send() + + Frontends do not know what kind of lookup the backends support + so it is expected that they might send unsupported requests. + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit bf873598a9d4ac8256b20859c0d92fb509861b6b +Author: Alexey Tikhonov +Date: Sun Dec 13 20:29:07 2020 +0100 + + IPA: ignore failed group search in certain cases + + It's currently expected to see those messages with sudo or HBAC rules in play. + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 60b17be9e4f4865fe1774076808a6c783a7ec906 +Author: Alexey Tikhonov +Date: Sun Dec 13 19:36:56 2020 +0100 + + SYSDB: changed log level in sysdb_update_members_ex() + + Fail to add already existing member isn't critical. + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 9390af3c2d1b33e2b5ded0ea0c6c436b9776cedc +Author: Alexey Tikhonov +Date: Sat Dec 12 21:29:06 2020 +0100 + + IPA: reduce log level in apply_subdomain_homedir() + + Missing UID for SYSDB_GROUP_CLASS is not an error + (see commit message of e66517dcf63f1d4aaf866c22371dac7740ce0a48 for + additional details) + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 9215cf4e2519d5f085bf97f26a74d499090e46e1 +Author: Alexey Tikhonov +Date: Sat Dec 12 20:46:40 2020 +0100 + + CERTMAP: removed stray debug message + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 0986cf6ced8c4e09b8031d19eddffca679aca30c +Author: Alexey Tikhonov +Date: Thu Dec 3 21:06:31 2020 +0100 + + UTIL: fixed bug in server_setup() that prevented setting debug level to 0 explicitly + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 644453f8d93540a91236683015f3418d29c6d95a +Author: Alexey Tikhonov +Date: Tue Dec 1 13:03:03 2020 +0100 + + LOGS: default log level changed to <= SSSDBG_OP_FAILURE + + :config: New default value of `debug_level` is 0x0070 + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 4fe060abbe958c2f9b5aa44e489620063029aa0b +Author: Alexey Tikhonov +Date: Mon Nov 30 22:19:46 2020 +0100 + + FILES: reduced debug level in refresh_override_attrs() if case "No overrides, nothing to do" + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 29f243fd5b256efe3c7f4e4f0940c7d0ae6b4fa1 +Author: Alexey Tikhonov +Date: Mon Nov 30 22:07:01 2020 +0100 + + AD: reduced log level in case check_if_pac_is_available() can't find user entry. This is typical situation when, for example, INITGROUPS lookup is executed for uncached user. + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit ed6ec569780ad8203c4990faed5a9f0dc27dd12b +Author: Alexey Tikhonov +Date: Mon Nov 30 21:13:28 2020 +0100 + + SDAP: reduced log level in case group without members + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 26fdc3c8f0ae6493442ea291d9bf36ba148ef209 +Author: Alexey Tikhonov +Date: Mon Nov 30 21:06:19 2020 +0100 + + CACHE_REQ: reduced log level in cache_req_object_by_name_well_known() Non fqdn input isn't necessarily an error here. + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit a7b145b99b9f71ad3d02251fff5b587041c9f1ab +Author: Alexey Tikhonov +Date: Mon Nov 30 20:27:44 2020 +0100 + + LDAP: reduced log level in hosts_get_done() + + Absent host in LDAP server isn't SSSD failure. + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 6e3b4d745fc8d2de14d69aa30bc21aa549a435f8 +Author: Alexey Tikhonov +Date: Mon Nov 30 16:45:51 2020 +0100 + + SBUS: reduced log level in case of unexpected signal + + Most probably module is not fully initialized yet. + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 90dae38d7442757b8a51f91a6ba3fb83f99320a1 +Author: Alexey Tikhonov +Date: Mon Nov 30 11:39:56 2020 +0100 + + RESPONDER: reduce log level in sss_parse_inp_done() in case of "Unknown domain" since this might be search by UPN + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 69aa3e8c4b82a06e45ba59eb1c17af252aa971ce +Author: Alexey Tikhonov +Date: Mon Nov 30 01:05:52 2020 +0100 + + DP: do not log failure in case provider doesn't support check_online method + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 1af89925e62cccacb2957f55b16988a5e71fe5e1 +Author: Alexey Tikhonov +Date: Mon Nov 30 00:28:08 2020 +0100 + + IPA: corrected confusing message + + Log message like: + ``` + sysdb_getpwnam() got more users than expected. Expected [1], got [0] + ``` + looks a bit confusing. + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit a419b7e673d2de571d873b79be31b1ae2fa89832 +Author: Alexey Tikhonov +Date: Mon Nov 30 00:13:31 2020 +0100 + + SSS_IFACE: corrected misleading return code + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 99e44d9db41f5bb56281ed65d815c32139195931 +Author: Alexey Tikhonov +Date: Sun Nov 29 22:55:07 2020 +0100 + + LDAP: added missed \n in log message + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 52dc85540e621b00f358fea94e2e390d580948d8 +Author: Alexey Tikhonov +Date: Sun Nov 29 21:42:08 2020 +0100 + + SYSDB: reduce log level in sysdb_update_members_ex() in case failed attempt to DEL unexisting attribute + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit a7b6413d9fb870f51f09955bdceee01952442c63 +Author: Alexey Tikhonov +Date: Sun Nov 29 21:32:46 2020 +0100 + + UTIL: sss_ldb_error_to_errno() improved + + LDB_ERR_NO_SUCH_ATTRIBUTE error code was added to mapping and log level + for unknown error code was reduced. + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit ac22859006b5658017b2720ca3e02d34c5beecdd +Author: Alexey Tikhonov +Date: Sun Nov 29 17:03:58 2020 +0100 + + PAM: reduce log level in may_do_cert_auth() + + Reduce log level in may_do_cert_auth() as this is not a critical failure + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 5068655a67f88cb1730f28689c5effee264321ad +Author: Alexey Tikhonov +Date: Fri Nov 27 21:45:53 2020 +0100 + + UTIL: few debug message corrections + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 3cbd0465b52f9bbb7e20b0b12e154f51bab0866e +Author: Alexey Tikhonov +Date: Fri Nov 27 21:12:16 2020 +0100 + + PAM: few debug message corrections + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit f028253ff87bf11ed034ad5acf1f67e8863bed60 +Author: Alexey Tikhonov +Date: Fri Nov 27 20:59:13 2020 +0100 + + NSS: few debug message corrections + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit f457a1a69240381ad7637a09dc66c1aeb78e1d18 +Author: Alexey Tikhonov +Date: Fri Nov 27 20:33:11 2020 +0100 + + IFP: few debug message corrections + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 058644f2ef6d1958db657d371158d2df7798dd49 +Author: Alexey Tikhonov +Date: Fri Nov 27 20:21:55 2020 +0100 + + RESPONDER: few debug message corrections + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 01ba32f250a0e51771471c52440c11f6f05f2a48 +Author: Alexey Tikhonov +Date: Fri Nov 27 20:15:22 2020 +0100 + + CACHE_REQ: debug message correction + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 018c08acbb3bbb836c9acefaf5c384eb9231a60a +Author: Alexey Tikhonov +Date: Fri Nov 27 20:05:06 2020 +0100 + + AUTOFS: few debug message corrections + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit fb052a4c9843ce518a7202d842c43631f8bbfd2d +Author: Alexey Tikhonov +Date: Fri Nov 27 19:57:00 2020 +0100 + + RESOLV: debug message correction + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit d91409df456f9ad7aad39d0cad0ed053cf1f3653 +Author: Alexey Tikhonov +Date: Fri Nov 27 19:49:14 2020 +0100 + + PROXY: few debug message corrections + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit ff8f44ce2d2eedb098d980793a949f7f7e55576a +Author: Alexey Tikhonov +Date: Fri Nov 20 19:46:28 2020 +0100 + + LDAP: few debug message corrections + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 9244820af59ba6b947cf9aa1269d03bb6f2e4f38 +Author: Alexey Tikhonov +Date: Fri Nov 20 19:22:36 2020 +0100 + + KRB5: few debug message corrections + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 667b983aaee380c50d50ef07542b004e60041581 +Author: Alexey Tikhonov +Date: Thu Nov 19 18:31:28 2020 +0100 + + IPA: few debug message corrections + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 2f70695a874dcb84d4b86773138a5a6b6259958f +Author: Alexey Tikhonov +Date: Wed Nov 18 22:12:21 2020 +0100 + + DP: few debug message corrections + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit d6f6f053d7a97a220b52ce92fd653eef8cec5a74 +Author: Alexey Tikhonov +Date: Wed Nov 18 21:37:38 2020 +0100 + + AD: few debug message corrections + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 85d8adc4d24f09e47f2a9c0fa595d90c61036b18 +Author: Alexey Tikhonov +Date: Wed Nov 18 19:09:33 2020 +0100 + + P11_CHILD: severity level of few debug messages adjusted + + Severity level of few debug messages was adjusted and journal message + in case of disabled certificate verification was added. + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit fe0530ef96baa8fd39ce6b87c0c760e17c5eb6f8 +Author: Alexey Tikhonov +Date: Wed Nov 18 16:28:43 2020 +0100 + + MONITOR: severity level of few debug messages adjusted + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit daa5454f870a5436a554091a1333cc8be0cbc566 +Author: Alexey Tikhonov +Date: Wed Nov 18 16:02:23 2020 +0100 + + SYSDB:views: few debug message corrections + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 82dc14b027f9115cabafce71d2b385d5c7d1dd4f +Author: Alexey Tikhonov +Date: Wed Nov 18 15:56:46 2020 +0100 + + SYSDB:upgrade: debug message corrected + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit e731368ed9cea9b35d0ae654e1534084c6ef4642 +Author: Alexey Tikhonov +Date: Wed Nov 18 15:50:08 2020 +0100 + + SYSDB:service: severity level of few debug messages adjusted + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit f55c9599068c43037a8b666af92ba9b8a044f735 +Author: Alexey Tikhonov +Date: Wed Nov 18 15:32:21 2020 +0100 + + SYSDB:selinux: debug message severity level was adjusted + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 744582419abfd6e5665315748d44e732f1d56f13 +Author: Alexey Tikhonov +Date: Wed Nov 18 15:30:45 2020 +0100 + + SYSDB:search: few debug messages were corrected + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit 033c31a2a4994367edea1ded8303a0d2dbc59b1c +Author: Alexey Tikhonov +Date: Wed Nov 18 15:19:46 2020 +0100 + + SYSDB:ops: few debug messages were corrected + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit a73df70ee0bcc8f1b80a2e20132592724bd5f675 +Author: Alexey Tikhonov +Date: Wed Nov 18 13:19:25 2020 +0100 + + SYSDB:ipnetworks: severity level of few debug messages adjusted + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit b4acf71d0a81aeeb2754645d2798ce1e927121f3 +Author: Alexey Tikhonov +Date: Mon Nov 16 21:18:14 2020 +0100 + + SYSDB:iphosts: severity level of few debug messages adjusted + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit d8af1db84b48193a546bbeec84a7dd7e2b132244 +Author: Alexey Tikhonov +Date: Mon Nov 16 20:05:12 2020 +0100 + + SYSDB:sudo: changed debug message to be consistent + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit df723cb98b406b0262f04d0e43e8e5bf0030074f +Author: Alexey Tikhonov +Date: Mon Nov 16 19:10:41 2020 +0100 + + SYSDB: wrong debug message corrected + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose + +commit e350d917e6d48c1d13502ab2849d3e2a0815215e +Author: Alexey Tikhonov +Date: Mon Nov 16 18:13:26 2020 +0100 + + SYSDB:autofs: cosmetic updates + + Reviewed-by: Pawel Polawski + Reviewed-by: Sumit Bose +--- + src/db/sysdb.c | 2 +- + src/db/sysdb_autofs.c | 4 +- + src/db/sysdb_iphosts.c | 10 ++--- + src/db/sysdb_ipnetworks.c | 6 +-- + src/db/sysdb_ops.c | 37 ++++++++++++------ + src/db/sysdb_search.c | 17 ++++++--- + src/db/sysdb_selinux.c | 2 +- + src/db/sysdb_services.c | 6 +-- + src/db/sysdb_sudo.c | 3 +- + src/db/sysdb_upgrade.c | 2 +- + src/db/sysdb_views.c | 6 +-- + src/lib/certmap/sss_certmap_krb5_match.c | 1 - + src/man/include/debug_levels.xml | 3 +- + src/man/include/debug_levels_tools.xml | 3 +- + src/monitor/monitor.c | 14 +++---- + src/p11_child/p11_child_common.c | 2 +- + src/p11_child/p11_child_common_utils.c | 3 ++ + src/p11_child/p11_child_openssl.c | 4 +- + src/providers/ad/ad_cldap_ping.c | 2 +- + src/providers/ad/ad_common.c | 7 ++-- + src/providers/ad/ad_dyndns.c | 6 +-- + src/providers/ad/ad_gpo.c | 16 +++++--- + src/providers/ad/ad_machine_pw_renewal.c | 7 ++-- + src/providers/ad/ad_pac.c | 6 ++- + src/providers/ad/ad_subdomains.c | 2 +- + src/providers/be_dyndns.c | 3 +- + src/providers/be_ptask.c | 2 +- + src/providers/be_refresh.c | 3 +- + src/providers/data_provider/dp.c | 4 +- + src/providers/data_provider/dp_target_sudo.c | 10 +++-- + src/providers/data_provider_be.c | 5 +-- + src/providers/data_provider_fo.c | 2 +- + src/providers/data_provider_opts.c | 6 +-- + src/providers/data_provider_req.h | 1 + + src/providers/files/files_ops.c | 2 +- + src/providers/ipa/ipa_access.c | 2 +- + src/providers/ipa/ipa_common.c | 5 +-- + src/providers/ipa/ipa_hbac_common.c | 2 +- + src/providers/ipa/ipa_hbac_services.c | 4 +- + src/providers/ipa/ipa_hbac_users.c | 4 +- + src/providers/ipa/ipa_id.c | 2 +- + src/providers/ipa/ipa_init.c | 4 +- + src/providers/ipa/ipa_s2n_exop.c | 3 +- + src/providers/ipa/ipa_selinux.c | 4 +- + src/providers/ipa/ipa_session.c | 4 +- + src/providers/ipa/ipa_subdomains_ext_groups.c | 3 +- + src/providers/ipa/ipa_subdomains_id.c | 38 +++++++++++++------ + src/providers/ipa/ipa_subdomains_server.c | 11 +++--- + src/providers/ipa/ipa_sudo.c | 14 +++---- + src/providers/ipa/ipa_sudo_async.c | 10 ++--- + src/providers/ipa/ipa_sudo_conversion.c | 6 +-- + src/providers/ipa/ipa_views.c | 4 +- + src/providers/krb5/krb5_access.c | 3 +- + src/providers/krb5/krb5_auth.c | 4 +- + src/providers/krb5/krb5_child.c | 25 ++++++------ + src/providers/krb5/krb5_child_handler.c | 4 +- + src/providers/krb5/krb5_common.c | 6 +-- + .../krb5/krb5_delayed_online_authentication.c | 4 +- + src/providers/krb5/krb5_renew_tgt.c | 4 +- + src/providers/krb5/krb5_utils.c | 2 +- + src/providers/ldap/ldap_auth.c | 12 +++--- + src/providers/ldap/ldap_child.c | 2 +- + src/providers/ldap/ldap_init.c | 4 +- + src/providers/ldap/ldap_options.c | 8 ++-- + src/providers/ldap/sdap.c | 28 +++++++++----- + src/providers/ldap/sdap_access.c | 11 +++--- + src/providers/ldap/sdap_async.c | 9 +++-- + src/providers/ldap/sdap_async_autofs.c | 2 +- + src/providers/ldap/sdap_async_connection.c | 6 +-- + src/providers/ldap/sdap_async_groups.c | 27 ++++++++----- + src/providers/ldap/sdap_async_initgroups.c | 6 ++- + src/providers/ldap/sdap_async_initgroups_ad.c | 2 +- + src/providers/ldap/sdap_async_sudo.c | 4 +- + src/providers/ldap/sdap_child_helpers.c | 6 +-- + src/providers/ldap/sdap_hostid.c | 2 +- + src/providers/ldap/sdap_id_op.c | 2 +- + src/providers/proxy/proxy_auth.c | 6 +-- + src/providers/proxy/proxy_child.c | 8 ++-- + src/providers/proxy/proxy_client.c | 2 +- + src/providers/proxy/proxy_id.c | 6 +-- + src/resolv/async_resolv.c | 2 +- + src/responder/autofs/autofssrv.c | 2 +- + src/responder/autofs/autofssrv_cmd.c | 6 +-- + src/responder/common/cache_req/cache_req.c | 2 +- + .../plugins/cache_req_object_by_name.c | 4 +- + src/responder/common/responder_common.c | 4 +- + src/responder/common/responder_get_domains.c | 2 +- + src/responder/common/responder_iface.c | 4 +- + src/responder/ifp/ifp_iface/ifp_iface.c | 2 +- + src/responder/ifp/ifpsrv.c | 8 ++-- + src/responder/ifp/ifpsrv_util.c | 2 +- + src/responder/nss/nss_cmd.c | 20 +++++----- + src/responder/nss/nss_iface.c | 4 +- + src/responder/nss/nss_protocol_netgr.c | 2 +- + src/responder/nss/nsssrv.c | 2 +- + src/responder/pam/pamsrv_cmd.c | 2 +- + src/responder/pam/pamsrv_p11.c | 4 +- + src/sbus/router/sbus_router_handler.c | 3 +- + src/sss_iface/sss_iface.c | 4 +- + src/util/child_common.c | 2 +- + src/util/debug.h | 4 +- + src/util/domain_info_utils.c | 2 +- + src/util/server.c | 15 +++++--- + src/util/sss_sockets.c | 2 +- + src/util/string_utils.c | 2 +- + src/util/util_errors.c | 3 +- + 106 files changed, 364 insertions(+), 279 deletions(-) + +diff --git a/src/db/sysdb.c b/src/db/sysdb.c +index d0052d99b..d78991e36 100644 +--- a/src/db/sysdb.c ++++ b/src/db/sysdb.c +@@ -1489,7 +1489,7 @@ errno_t sysdb_attrs_primary_name(struct sysdb_ctx *sysdb, + * decide which name is correct. + */ + DEBUG(SSSDBG_CRIT_FAILURE, +- "Cannot save entry. Unable to determine groupname\n"); ++ "Can't match the name to the RDN\n"); + ret = EINVAL; + goto done; + } +diff --git a/src/db/sysdb_autofs.c b/src/db/sysdb_autofs.c +index 413b00722..1febdaec5 100644 +--- a/src/db/sysdb_autofs.c ++++ b/src/db/sysdb_autofs.c +@@ -243,14 +243,14 @@ sysdb_get_map_byname(TALLOC_CTX *mem_ctx, + "Error looking up autofs map [%s]\n", safe_map_name); + goto done; + } else if (ret == ENOENT) { +- DEBUG(SSSDBG_TRACE_FUNC, "No such map\n"); ++ DEBUG(SSSDBG_TRACE_FUNC, "No such map [%s]\n", safe_map_name); + *_map = NULL; + goto done; + } + + if (count != 1) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "More than one map named %s\n", safe_map_name); ++ "More than one map named [%s]\n", safe_map_name); + goto done; + } + +diff --git a/src/db/sysdb_iphosts.c b/src/db/sysdb_iphosts.c +index b82279787..d3ee8f1a9 100644 +--- a/src/db/sysdb_iphosts.c ++++ b/src/db/sysdb_iphosts.c +@@ -222,14 +222,14 @@ sysdb_store_host(struct sss_domain_info *domain, + * sort it out. + */ + for (j = 0; j < res->count; j++) { +- DEBUG(SSSDBG_TRACE_FUNC, ++ DEBUG(SSSDBG_CRIT_FAILURE, + "Corrupt cache entry [%s] detected. Deleting\n", + ldb_dn_canonical_string(tmp_ctx, + res->msgs[j]->dn)); + + ret = sysdb_delete_entry(sysdb, res->msgs[j]->dn, true); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, ++ DEBUG(SSSDBG_OP_FAILURE, + "Could not delete corrupt cache entry [%s]\n", + ldb_dn_canonical_string(tmp_ctx, + res->msgs[j]->dn)); +@@ -262,7 +262,7 @@ sysdb_store_host(struct sss_domain_info *domain, + + ret = sysdb_delete_entry(sysdb, res->msgs[0]->dn, true); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, ++ DEBUG(SSSDBG_OP_FAILURE, + "Could not delete cache entry [%s]\n", + ldb_dn_canonical_string(tmp_ctx, + res->msgs[0]->dn)); +@@ -298,7 +298,7 @@ sysdb_store_host(struct sss_domain_info *domain, + + ret = sysdb_delete_entry(sysdb, res->msgs[i]->dn, true); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, ++ DEBUG(SSSDBG_OP_FAILURE, + "Could not delete corrupt cache entry [%s]\n", + ldb_dn_canonical_string(tmp_ctx, + res->msgs[i]->dn)); +@@ -318,7 +318,7 @@ sysdb_store_host(struct sss_domain_info *domain, + /* Delete the entry from the previous pass */ + ret = sysdb_delete_entry(sysdb, update_dn, true); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, ++ DEBUG(SSSDBG_OP_FAILURE, + "Could not delete cache entry [%s]\n", + ldb_dn_canonical_string(tmp_ctx, + update_dn)); +diff --git a/src/db/sysdb_ipnetworks.c b/src/db/sysdb_ipnetworks.c +index 326f984b7..9da4d9b23 100644 +--- a/src/db/sysdb_ipnetworks.c ++++ b/src/db/sysdb_ipnetworks.c +@@ -261,7 +261,7 @@ sysdb_store_ipnetwork(struct sss_domain_info *domain, + + ret = sysdb_delete_entry(sysdb, res->msgs[0]->dn, true); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, ++ DEBUG(SSSDBG_OP_FAILURE, + "Could not delete cache entry [%s]\n", + ldb_dn_canonical_string(tmp_ctx, + res->msgs[0]->dn)); +@@ -296,7 +296,7 @@ sysdb_store_ipnetwork(struct sss_domain_info *domain, + + ret = sysdb_delete_entry(sysdb, res->msgs[i]->dn, true); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, ++ DEBUG(SSSDBG_OP_FAILURE, + "Could not delete corrupt cache entry [%s]\n", + ldb_dn_canonical_string(tmp_ctx, + res->msgs[i]->dn)); +@@ -315,7 +315,7 @@ sysdb_store_ipnetwork(struct sss_domain_info *domain, + /* Delete the entry from the previous pass */ + ret = sysdb_delete_entry(sysdb, update_dn, true); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, ++ DEBUG(SSSDBG_OP_FAILURE, + "Could not delete cache entry [%s]\n", + ldb_dn_canonical_string(tmp_ctx, + update_dn)); +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 3412b9cd1..585708abe 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -157,7 +157,7 @@ static int sysdb_delete_cache_entry(struct ldb_context *ldb, + /* fall through */ + SSS_ATTRIBUTE_FALLTHROUGH; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "LDB Error: %s(%d)\nError Message: [%s]\n", ++ DEBUG(SSSDBG_CRIT_FAILURE, "LDB Error: %s (%d); error message: [%s]\n", + ldb_strerror(ret), ret, ldb_errstring(ldb)); + return sysdb_error_to_errno(ret); + } +@@ -3420,7 +3420,7 @@ int sysdb_search_custom(TALLOC_CTX *mem_ctx, + goto done; + } + if (!ldb_dn_validate(basedn)) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create DN.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Syntactically invalid subtree DN.\n"); + ret = EINVAL; + goto done; + } +@@ -3463,7 +3463,7 @@ int sysdb_search_custom_by_name(TALLOC_CTX *mem_ctx, + goto done; + } + if (!ldb_dn_validate(basedn)) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create DN.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Syntactically invalid DN.\n"); + ret = EINVAL; + goto done; + } +@@ -3545,7 +3545,7 @@ errno_t sysdb_search_by_orig_dn(TALLOC_CTX *mem_ctx, + default: + DEBUG(SSSDBG_CRIT_FAILURE, + "Trying to perform a search by orig_dn using a " +- "non-supported type\n"); ++ "non-supported type %d\n", type); + ret = EINVAL; + goto done; + } +@@ -3690,8 +3690,9 @@ int sysdb_delete_custom(struct sss_domain_info *domain, + break; + + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "LDB Error: %s(%d)\nError Message: [%s]\n", +- ldb_strerror(ret), ret, ldb_errstring(domain->sysdb->ldb)); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "ldb_delete failed: %s (%d); error Message: [%s]\n", ++ ldb_strerror(ret), ret, ldb_errstring(domain->sysdb->ldb)); + ret = sysdb_error_to_errno(ret); + break; + } +@@ -4927,9 +4928,15 @@ static errno_t sysdb_update_members_ex(struct sss_domain_info *domain, + ret = sysdb_add_group_member(domain, add_groups[i], + member, type, is_dn); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Could not add member [%s] to group [%s]. " +- "Skipping.\n", member, add_groups[i]); ++ if (ret != EEXIST) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Could not add member [%s] to group [%s]. " ++ "Skipping.\n", member, add_groups[i]); ++ } else { ++ DEBUG(SSSDBG_FUNC_DATA, ++ "Group [%s] already has member [%s]. Skipping.\n", ++ add_groups[i], member); ++ } + /* Continue on, we should try to finish the rest */ + } + } +@@ -4941,9 +4948,15 @@ static errno_t sysdb_update_members_ex(struct sss_domain_info *domain, + ret = sysdb_remove_group_member(domain, del_groups[i], + member, type, is_dn); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Could not remove member [%s] from group [%s]. " +- "Skipping\n", member, del_groups[i]); ++ if (ret != ENOENT) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Could not remove member [%s] from group [%s]. " ++ "Skipping\n", member, del_groups[i]); ++ } else { ++ DEBUG(SSSDBG_FUNC_DATA, ++ "No member [%s] in group [%s]. " ++ "Skipping\n", member, del_groups[i]); ++ } + /* Continue on, we should try to finish the rest */ + } + } +diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c +index 4ff65c1ae..0cd8321cb 100644 +--- a/src/db/sysdb_search.c ++++ b/src/db/sysdb_search.c +@@ -2393,7 +2393,7 @@ errno_t sysdb_get_direct_parents(TALLOC_CTX *mem_ctx, + } else if (mtype == SYSDB_MEMBER_GROUP) { + dn = sysdb_group_strdn(tmp_ctx, dom->name, name); + } else { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unknown member type\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unknown member type %d\n", mtype); + ret = EINVAL; + goto done; + } +@@ -2453,13 +2453,14 @@ errno_t sysdb_get_direct_parents(TALLOC_CTX *mem_ctx, + tmp_str = ldb_msg_find_attr_as_string(direct_sysdb_groups[i], + SYSDB_NAME, NULL); + if (!tmp_str) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "A group with no name?\n"); + /* This should never happen, but if it does, just continue */ + continue; + } + + direct_parents[pi] = talloc_strdup(direct_parents, tmp_str); + if (!direct_parents[pi]) { +- DEBUG(SSSDBG_CRIT_FAILURE, "A group with no name?\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); + ret = EIO; + goto done; + } +@@ -2522,8 +2523,13 @@ errno_t sysdb_get_real_name(TALLOC_CTX *mem_ctx, + } + if (ret != EOK) { + /* User cannot be found in cache */ +- DEBUG(SSSDBG_OP_FAILURE, "Cannot find user [%s] in cache\n", +- name_or_upn_or_sid); ++ if (ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to find user [%s] in cache: %d\n", ++ name_or_upn_or_sid, ret); ++ } else { ++ DEBUG(SSSDBG_TRACE_FUNC, "User [%s] is missing in cache\n", ++ name_or_upn_or_sid); ++ } + goto done; + } + } else if (res->count == 1) { +@@ -2537,7 +2543,8 @@ errno_t sysdb_get_real_name(TALLOC_CTX *mem_ctx, + + cname = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); + if (!cname) { +- DEBUG(SSSDBG_CRIT_FAILURE, "A user with no name?\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "User '%s' without a name?\n", name_or_upn_or_sid); + ret = ENOENT; + goto done; + } +diff --git a/src/db/sysdb_selinux.c b/src/db/sysdb_selinux.c +index 88ac88786..535411950 100644 +--- a/src/db/sysdb_selinux.c ++++ b/src/db/sysdb_selinux.c +@@ -234,7 +234,7 @@ errno_t sysdb_delete_usermaps(struct sss_domain_info *domain) + ret = sysdb_delete_recursive(sysdb, dn, true); + talloc_free(dn); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_delete_recursive failed.\n"); ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_delete_recursive failed.\n"); + return ret; + } + +diff --git a/src/db/sysdb_services.c b/src/db/sysdb_services.c +index 8118fef00..ac17f4704 100644 +--- a/src/db/sysdb_services.c ++++ b/src/db/sysdb_services.c +@@ -252,7 +252,7 @@ sysdb_store_service(struct sss_domain_info *domain, + + ret = sysdb_delete_entry(sysdb, res->msgs[0]->dn, true); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, ++ DEBUG(SSSDBG_OP_FAILURE, + "Could not delete cache entry [%s]\n", + ldb_dn_canonical_string(tmp_ctx, + res->msgs[0]->dn)); +@@ -290,7 +290,7 @@ sysdb_store_service(struct sss_domain_info *domain, + + ret = sysdb_delete_entry(sysdb, res->msgs[i]->dn, true); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, ++ DEBUG(SSSDBG_OP_FAILURE, + "Could not delete corrupt cache entry [%s]\n", + ldb_dn_canonical_string(tmp_ctx, + res->msgs[i]->dn)); +@@ -310,7 +310,7 @@ sysdb_store_service(struct sss_domain_info *domain, + /* Delete the entry from the previous pass */ + ret = sysdb_delete_entry(sysdb, update_dn, true); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, ++ DEBUG(SSSDBG_OP_FAILURE, + "Could not delete cache entry [%s]\n", + ldb_dn_canonical_string(tmp_ctx, + update_dn)); +diff --git a/src/db/sysdb_sudo.c b/src/db/sysdb_sudo.c +index 03eec9c70..1626b612d 100644 +--- a/src/db/sysdb_sudo.c ++++ b/src/db/sysdb_sudo.c +@@ -480,7 +480,8 @@ sysdb_get_sudo_user_info(TALLOC_CTX *mem_ctx, + sss_get_cased_name(sysdb_groupnames, groupname, + domain->case_sensitive); + if (sysdb_groupnames[num_groups] == NULL) { +- DEBUG(SSSDBG_MINOR_FAILURE, "Cannot strdup %s\n", groupname); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_get_cased_name() failed for '%s'\n", groupname); + continue; + } + num_groups++; +diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c +index 03a0e6173..99213260c 100644 +--- a/src/db/sysdb_upgrade.c ++++ b/src/db/sysdb_upgrade.c +@@ -2455,7 +2455,7 @@ int sysdb_upgrade_19(struct sysdb_ctx *sysdb, const char **ver) + + ret = add_object_category(sysdb->ldb, ctx); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "add_object_category failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "add_object_category failed: %d\n", ret); + goto done; + } + +diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c +index 00da74047..269dab70f 100644 +--- a/src/db/sysdb_views.c ++++ b/src/db/sysdb_views.c +@@ -556,12 +556,12 @@ errno_t sysdb_store_override(struct sss_domain_info *domain, + if (ret == ENOENT) { + DEBUG(SSSDBG_CRIT_FAILURE, "Object to override does not exists.\n"); + } else { +- DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_entry failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_search_entry failed.\n"); + } + goto done; + } + if (count != 1) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Base searched returned more than one object.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Base search returned more than one object.\n"); + ret = EINVAL; + goto done; + } +@@ -660,7 +660,7 @@ errno_t sysdb_store_override(struct sss_domain_info *domain, + SYSDB_OVERRIDE_GROUP_CLASS); + break; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected object type.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected object type %d.\n", type); + ret = EINVAL; + goto done; + } +diff --git a/src/lib/certmap/sss_certmap_krb5_match.c b/src/lib/certmap/sss_certmap_krb5_match.c +index 640930747..ab566ac99 100644 +--- a/src/lib/certmap/sss_certmap_krb5_match.c ++++ b/src/lib/certmap/sss_certmap_krb5_match.c +@@ -220,7 +220,6 @@ static int parse_krb5_get_eku_value(TALLOC_CTX *mem_ctx, + + for (c = 0; eku_list[c] != NULL; c++) { + for (k = 0; sss_ext_key_usage[k].name != NULL; k++) { +-CM_DEBUG(ctx, "[%s][%s].", eku_list[c], sss_ext_key_usage[k].name); + if (strcasecmp(eku_list[c], sss_ext_key_usage[k].name) == 0) { + comp->eku_oid_list[e] = talloc_strdup(comp->eku_oid_list, + sss_ext_key_usage[k].oid); +diff --git a/src/man/include/debug_levels.xml b/src/man/include/debug_levels.xml +index b5e13ba3e..0d9cc17be 100644 +--- a/src/man/include/debug_levels.xml ++++ b/src/man/include/debug_levels.xml +@@ -100,6 +100,7 @@ + introduced in 1.7.0. + + +- Default: 0 ++ Default: 0x0070 (i.e. fatal, critical and serious ++ failures; corresponds to setting 2 in decimal notation) + + +diff --git a/src/man/include/debug_levels_tools.xml b/src/man/include/debug_levels_tools.xml +index b592d50fc..46a3c7d29 100644 +--- a/src/man/include/debug_levels_tools.xml ++++ b/src/man/include/debug_levels_tools.xml +@@ -81,6 +81,7 @@ + introduced in 1.7.0. + + +- Default: 0 ++ Default: 0x0070 (i.e. fatal, critical and serious ++ failures; corresponds to setting 2 in decimal notation) + + +diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c +index d9da05a51..9c2381c81 100644 +--- a/src/monitor/monitor.c ++++ b/src/monitor/monitor.c +@@ -1435,7 +1435,7 @@ static void monitor_quit(struct mt_ctx *mt_ctx, int ret) + DEBUG(SSSDBG_CRIT_FAILURE, + "Child [%s] terminated with a signal\n", svc->name); + } else { +- DEBUG(SSSDBG_FATAL_FAILURE, ++ DEBUG(SSSDBG_CRIT_FAILURE, + "Child [%s] did not exit cleanly\n", svc->name); + /* Forcibly kill this child */ + kill(-svc->pid, SIGKILL); +@@ -2059,7 +2059,7 @@ static void monitor_sbus_connected(struct tevent_req *req) + + ret = sbus_connection_add_path_map(ctx->sbus_conn, paths); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add paths [%d]: %s\n", ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to add paths [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } +@@ -2271,7 +2271,7 @@ static void mt_svc_restart(struct tevent_context *ev, + add_new_provider(svc->mt_ctx, svc->name, svc->restarts + 1); + } else { + /* Invalid type? */ +- DEBUG(SSSDBG_CRIT_FAILURE, ++ DEBUG(SSSDBG_FATAL_FAILURE, + "BUG: Invalid child process type [%d]\n", svc->type); + } + +@@ -2580,14 +2580,14 @@ int main(int argc, const char *argv[]) + switch (ret) { + case EPERM: + case EACCES: +- DEBUG(SSSDBG_CRIT_FAILURE, ++ DEBUG(SSSDBG_FATAL_FAILURE, + CONF_FILE_PERM_ERROR_MSG, config_file); +- sss_log(SSS_LOG_ALERT, CONF_FILE_PERM_ERROR_MSG, config_file); ++ sss_log(SSS_LOG_CRIT, CONF_FILE_PERM_ERROR_MSG, config_file); + break; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, ++ DEBUG(SSSDBG_FATAL_FAILURE, + "SSSD couldn't load the configuration database.\n"); +- sss_log(SSS_LOG_ALERT, ++ sss_log(SSS_LOG_CRIT, + "SSSD couldn't load the configuration database [%d]: %s.\n", + ret, strerror(ret)); + break; +diff --git a/src/p11_child/p11_child_common.c b/src/p11_child/p11_child_common.c +index f17de1a9e..704ced4b6 100644 +--- a/src/p11_child/p11_child_common.c ++++ b/src/p11_child/p11_child_common.c +@@ -125,7 +125,7 @@ static errno_t p11c_recv_data(TALLOC_CTX *mem_ctx, int fd, char **pin) + + str = talloc_strndup(mem_ctx, (char *) buf, len); + if (str == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n"); + return ENOMEM; + } + +diff --git a/src/p11_child/p11_child_common_utils.c b/src/p11_child/p11_child_common_utils.c +index 50cfebb4c..c5f324625 100644 +--- a/src/p11_child/p11_child_common_utils.c ++++ b/src/p11_child/p11_child_common_utils.c +@@ -107,6 +107,9 @@ errno_t parse_cert_verify_opts(TALLOC_CTX *mem_ctx, const char *verify_opts, + "Found 'no_verification' option, " + "disabling verification completely. " + "This should not be used in production.\n"); ++ sss_log(SSS_LOG_CRIT, ++ "Smart card certificate verification disabled completely. " ++ "This should not be used in production."); + cert_verify_opts->do_verification = false; + } else if (strncasecmp(opts[c], OCSP_DEFAUL_RESPONDER, + OCSP_DEFAUL_RESPONDER_LEN) == 0) { +diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c +index d81a1a9ea..879b05b65 100644 +--- a/src/p11_child/p11_child_openssl.c ++++ b/src/p11_child/p11_child_openssl.c +@@ -226,7 +226,7 @@ static char *get_issuer_subject_str(TALLOC_CTX *mem_ctx, X509 *cert) + + bio_mem = BIO_new(BIO_s_mem()); + if (bio_mem == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "BIO_new failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "BIO_new failed.\n"); + return NULL; + } + +@@ -591,7 +591,7 @@ errno_t init_p11_ctx(TALLOC_CTX *mem_ctx, const char *ca_db, + ret = SSL_library_init(); + #endif + if (ret != 1) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize OpenSSL.\n"); ++ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to initialize OpenSSL.\n"); + return EIO; + } + +diff --git a/src/providers/ad/ad_cldap_ping.c b/src/providers/ad/ad_cldap_ping.c +index ab234f4d7..7722af98a 100644 +--- a/src/providers/ad/ad_cldap_ping.c ++++ b/src/providers/ad/ad_cldap_ping.c +@@ -467,7 +467,7 @@ ad_cldap_ping_domain_send(TALLOC_CTX *mem_ctx, + domains[0] = discovery_domain; + domains[1] = NULL; + if (domains[0] == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Bad argument (discovery_domain)"); + ret = ENOMEM; + goto done; + } +diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c +index 624313942..eaa920ca0 100644 +--- a/src/providers/ad/ad_common.c ++++ b/src/providers/ad/ad_common.c +@@ -1072,15 +1072,14 @@ ad_resolve_callback(void *private_data, struct fo_server *server) + } + + if (!service->gc->uri) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to append to URI\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "NULL GC URI\n"); + ret = ENOMEM; + goto done; + } + DEBUG(SSSDBG_CONF_SETTINGS, "Constructed GC uri '%s'\n", service->gc->uri); + + if (service->gc->sockaddr == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "resolv_get_sockaddr_address failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "NULL GC sockaddr\n"); + ret = EIO; + goto done; + } +@@ -1100,7 +1099,7 @@ ad_resolve_callback(void *private_data, struct fo_server *server) + done: + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "Error: [%s]\n", strerror(ret)); ++ "Error: %d [%s]\n", ret, strerror(ret)); + } + talloc_free(tmp_ctx); + return; +diff --git a/src/providers/ad/ad_dyndns.c b/src/providers/ad/ad_dyndns.c +index 71ef16c0b..19fc8acef 100644 +--- a/src/providers/ad/ad_dyndns.c ++++ b/src/providers/ad/ad_dyndns.c +@@ -63,7 +63,7 @@ errno_t ad_dyndns_init(struct be_ctx *be_ctx, + */ + ret = ad_get_dyndns_options(be_ctx, ad_opts); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not set AD options\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not get AD dyndns options\n"); + return ret; + } + +@@ -209,8 +209,8 @@ static void ad_dyndns_update_connect_done(struct tevent_req *subreq) + + ret = ldap_url_parse(ctx->service->sdap->uri, &lud); + if (ret != LDAP_SUCCESS) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to parse ldap URI (%s)!\n", ctx->service->sdap->uri); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse ldap URI '%s': %d\n", ++ ctx->service->sdap->uri, ret); + ret = EINVAL; + goto done; + } +diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c +index 0eb5416ac..b15e0f345 100644 +--- a/src/providers/ad/ad_gpo.c ++++ b/src/providers/ad/ad_gpo.c +@@ -671,7 +671,9 @@ ad_gpo_ace_includes_client_sid(const char *user_sid, + + err = sss_idmap_sid_to_smb_sid(idmap_ctx, user_sid, &user_dom_sid); + if (err != IDMAP_SUCCESS) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize idmap context.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_idmap_sid_to_smb_sid() failed for user_sid '%s': %d\n", ++ user_sid, err); + return EFAULT; + } + +@@ -684,7 +686,9 @@ ad_gpo_ace_includes_client_sid(const char *user_sid, + + err = sss_idmap_sid_to_smb_sid(idmap_ctx, host_sid, &host_dom_sid); + if (err != IDMAP_SUCCESS) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize idmap context.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_idmap_sid_to_smb_sid() failed for host_sid '%s': %d\n", ++ host_sid, err); + return EFAULT; + } + +@@ -698,7 +702,9 @@ ad_gpo_ace_includes_client_sid(const char *user_sid, + for (i = 0; i < group_size; i++) { + err = sss_idmap_sid_to_smb_sid(idmap_ctx, group_sids[i], &group_dom_sid); + if (err != IDMAP_SUCCESS) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize idmap context.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_idmap_sid_to_smb_sid() failed for group_sid '%s': %d\n", ++ group_sids[i], err); + return EFAULT; + } + included = ad_gpo_dom_sid_equal(&ace_dom_sid, group_dom_sid); +@@ -4777,14 +4783,14 @@ gpo_fork_child(struct tevent_req *req) + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, +- "pipe failed [%d][%s].\n", errno, strerror(errno)); ++ "pipe (from) failed [%d][%s].\n", errno, strerror(errno)); + goto fail; + } + ret = pipe(pipefd_to_child); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, +- "pipe failed [%d][%s].\n", errno, strerror(errno)); ++ "pipe (to) failed [%d][%s].\n", errno, strerror(errno)); + goto fail; + } + +diff --git a/src/providers/ad/ad_machine_pw_renewal.c b/src/providers/ad/ad_machine_pw_renewal.c +index ce9bbe6f3..6e7137a86 100644 +--- a/src/providers/ad/ad_machine_pw_renewal.c ++++ b/src/providers/ad/ad_machine_pw_renewal.c +@@ -171,14 +171,14 @@ ad_machine_account_password_renewal_send(TALLOC_CTX *mem_ctx, + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, +- "pipe failed [%d][%s].\n", ret, strerror(ret)); ++ "pipe (from) failed [%d][%s].\n", ret, strerror(ret)); + goto done; + } + ret = pipe(pipefd_to_child); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, +- "pipe failed [%d][%s].\n", ret, strerror(ret)); ++ "pipe (to) failed [%d][%s].\n", ret, strerror(ret)); + goto done; + } + +@@ -354,7 +354,8 @@ errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx, + } + + if (opt_list_size != 2) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Wrong number of renewal options.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Wrong number of renewal options %d\n", ++ opt_list_size); + ret = EINVAL; + goto done; + } +diff --git a/src/providers/ad/ad_pac.c b/src/providers/ad/ad_pac.c +index 80424b44e..aff47304e 100644 +--- a/src/providers/ad/ad_pac.c ++++ b/src/providers/ad/ad_pac.c +@@ -120,7 +120,11 @@ errno_t check_if_pac_is_available(TALLOC_CTX *mem_ctx, + + ret = find_user_entry(mem_ctx, dom, ar, &msg); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "find_user_entry failed.\n"); ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_FUNC_DATA, "find_user_entry didn't find user entry.\n"); ++ } else { ++ DEBUG(SSSDBG_OP_FAILURE, "find_user_entry failed.\n"); ++ } + return ret; + } + +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 4c457b7e5..f5b0be6c2 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -299,7 +299,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, + + subdom_conf_path = subdomain_create_conf_path(id_ctx, subdom); + if (subdom_conf_path == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "subdom_conf_path failed\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "subdomain_create_conf_path failed\n"); + return ENOMEM; + } + +diff --git a/src/providers/be_dyndns.c b/src/providers/be_dyndns.c +index 2de3b11bb..1a304db37 100644 +--- a/src/providers/be_dyndns.c ++++ b/src/providers/be_dyndns.c +@@ -1111,7 +1111,8 @@ be_nsupdate_args(TALLOC_CTX *mem_ctx, + argc++; + break; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "Unknown nsupdate auth type\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unknown nsupdate auth type %d\n", auth_type); + goto fail; + } + +diff --git a/src/providers/be_ptask.c b/src/providers/be_ptask.c +index fb80909a0..fab9e21b8 100644 +--- a/src/providers/be_ptask.c ++++ b/src/providers/be_ptask.c +@@ -251,7 +251,7 @@ static void be_ptask_schedule(struct be_ptask *task, + task->timer = tevent_add_timer(task->ev, task, tv, be_ptask_execute, task); + if (task->timer == NULL) { + /* nothing we can do about it */ +- DEBUG(SSSDBG_CRIT_FAILURE, "FATAL: Unable to schedule task [%s]\n", ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to schedule task [%s]\n", + task->name); + be_ptask_disable(task); + } +diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c +index 01cbf03e2..fdddf8bca 100644 +--- a/src/providers/be_refresh.c ++++ b/src/providers/be_refresh.c +@@ -125,7 +125,8 @@ static errno_t be_refresh_get_values(TALLOC_CTX *mem_ctx, + base_dn = sysdb_netgroup_base_dn(mem_ctx, domain); + break; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "Uknown or unsupported refresh type\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Uknown or unsupported refresh type %d\n", type); + return ERR_INTERNAL; + break; + } +diff --git a/src/providers/data_provider/dp.c b/src/providers/data_provider/dp.c +index 0858c43d2..90324d74d 100644 +--- a/src/providers/data_provider/dp.c ++++ b/src/providers/data_provider/dp.c +@@ -109,7 +109,7 @@ dp_init_interface(struct data_provider *provider) + + ret = sbus_connection_add_path_map(provider->sbus_conn, paths); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add paths [%d]: %s\n", ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to add paths [%d]: %s\n", + ret, sss_strerror(ret)); + } + +@@ -196,7 +196,7 @@ dp_init_send(TALLOC_CTX *mem_ctx, + (sbus_server_on_connection_cb)dp_client_init, + (sbus_server_on_connection_data)state->provider); + if (subreq == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n"); ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to create subrequest!\n"); + ret = ENOMEM; + goto done; + } +diff --git a/src/providers/data_provider/dp_target_sudo.c b/src/providers/data_provider/dp_target_sudo.c +index db14039c4..59e2358cc 100644 +--- a/src/providers/data_provider/dp_target_sudo.c ++++ b/src/providers/data_provider/dp_target_sudo.c +@@ -42,13 +42,13 @@ static errno_t dp_sudo_parse_message(TALLOC_CTX *mem_ctx, + + ret = sbus_iterator_read_u(read_iter, &dp_flags); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse the message (flags)!\n"); + return ret; + } + + ret = sbus_iterator_read_u(read_iter, &sudo_type); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse the message (type)!\n"); + return ret; + } + +@@ -66,13 +66,15 @@ static errno_t dp_sudo_parse_message(TALLOC_CTX *mem_ctx, + /* read rules_num */ + ret = sbus_iterator_read_u(read_iter, &num_rules); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to parse the message (num rules)!\n"); + return ret; + } + + ret = sbus_iterator_read_as(mem_ctx, read_iter, &rules); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to parse the message (rules)!\n"); + return ret; + } + break; +diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c +index 10421c6b4..f059a3f96 100644 +--- a/src/providers/data_provider_be.c ++++ b/src/providers/data_provider_be.c +@@ -407,7 +407,7 @@ static void check_if_online(struct be_ctx *be_ctx, int delay) + check_if_online_delayed, be_ctx); + + if (time_event == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, ++ DEBUG(SSSDBG_CRIT_FAILURE, + "Scheduling check_if_online_delayed failed.\n"); + goto failed; + } +@@ -420,7 +420,6 @@ static void check_if_online(struct be_ctx *be_ctx, int delay) + + failed: + be_ctx->check_online_ref_count--; +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to run a check_online test.\n"); + + if (be_ctx->check_online_ref_count == 0) { + reset_fo(be_ctx); +@@ -629,7 +628,7 @@ static void dp_initialized(struct tevent_req *req) + + ret = be_register_monitor_iface(be_ctx->mon_conn, be_ctx); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to register monitor interface " ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to register monitor interface " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } +diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c +index 8dc09f5b2..0dfbb04b0 100644 +--- a/src/providers/data_provider_fo.c ++++ b/src/providers/data_provider_fo.c +@@ -651,7 +651,7 @@ errno_t be_resolve_server_process(struct tevent_req *subreq, + srvaddr = fo_get_server_hostent(state->srv); + if (!srvaddr) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "FATAL: No hostent available for server (%s)\n", ++ "No hostent available for server (%s)\n", + fo_get_server_str_name(state->srv)); + return EFAULT; + } +diff --git a/src/providers/data_provider_opts.c b/src/providers/data_provider_opts.c +index 9db43fc40..bb543ae4f 100644 +--- a/src/providers/data_provider_opts.c ++++ b/src/providers/data_provider_opts.c +@@ -233,7 +233,7 @@ static int dp_copy_options_ex(TALLOC_CTX *memctx, + } + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to retrieve value for option (%s)\n", ++ "Failed to copy value for option (%s)\n", + opts[i].opt_name); + goto done; + } +@@ -249,7 +249,7 @@ static int dp_copy_options_ex(TALLOC_CTX *memctx, + } + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to retrieve value for option (%s)\n", ++ "Failed to copy value for option (%s)\n", + opts[i].opt_name); + goto done; + } +@@ -265,7 +265,7 @@ static int dp_copy_options_ex(TALLOC_CTX *memctx, + } + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to retrieve value for option (%s)\n", ++ "Failed to copy value for option (%s)\n", + opts[i].opt_name); + goto done; + } +diff --git a/src/providers/data_provider_req.h b/src/providers/data_provider_req.h +index f2e05797f..75f7f9713 100644 +--- a/src/providers/data_provider_req.h ++++ b/src/providers/data_provider_req.h +@@ -39,6 +39,7 @@ + #define BE_REQ_USER_AND_GROUP 0x0012 + #define BE_REQ_BY_UUID 0x0013 + #define BE_REQ_BY_CERT 0x0014 ++#define BE_REQ__LAST BE_REQ_BY_CERT /* must be equal to max REQ number */ + #define BE_REQ_TYPE_MASK 0x00FF + + /** +diff --git a/src/providers/files/files_ops.c b/src/providers/files/files_ops.c +index 59fc20692..54d2b4164 100644 +--- a/src/providers/files/files_ops.c ++++ b/src/providers/files/files_ops.c +@@ -395,7 +395,7 @@ static errno_t refresh_override_attrs(struct files_id_ctx *id_ctx, + override_attrs, &count, &msgs); + if (ret != EOK) { + if (ret == ENOENT) { +- DEBUG(SSSDBG_OP_FAILURE, "No overrides, nothing to do.\n"); ++ DEBUG(SSSDBG_TRACE_FUNC, "No overrides, nothing to do.\n"); + ret = EOK; + } else { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_entry failed.\n"); +diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c +index 375b6f885..4a6727c97 100644 +--- a/src/providers/ipa/ipa_access.c ++++ b/src/providers/ipa/ipa_access.c +@@ -671,7 +671,7 @@ static void ipa_pam_access_handler_done(struct tevent_req *subreq) + talloc_free(subreq); + + if (ret == ENOENT) { +- DEBUG(SSSDBG_CRIT_FAILURE, "No HBAC rules find, denying access\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "No HBAC rules found, denying access\n"); + state->pd->pam_status = PAM_PERM_DENIED; + goto done; + } else if (ret != EOK) { +diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c +index 1211ba4c9..8cadb9249 100644 +--- a/src/providers/ipa/ipa_common.c ++++ b/src/providers/ipa/ipa_common.c +@@ -781,8 +781,7 @@ int ipa_get_auth_options(struct ipa_options *ipa_opts, + dp_opt_get_string(ipa_opts->auth, + KRB5_REALM)); + if (value == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set %s!\n", +- ipa_opts->auth[KRB5_FAST_PRINCIPAL].opt_name); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n"); + ret = ENOMEM; + goto done; + } +@@ -851,7 +850,7 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server) + srvaddr = fo_get_server_hostent(server); + if (!srvaddr) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "FATAL: No hostent available for server (%s)\n", ++ "No hostent available for server (%s)\n", + fo_get_server_str_name(server)); + talloc_free(tmp_ctx); + return; +diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c +index 31e53d24d..1fee41a36 100644 +--- a/src/providers/ipa/ipa_hbac_common.c ++++ b/src/providers/ipa/ipa_hbac_common.c +@@ -423,7 +423,7 @@ hbac_eval_user_element(TALLOC_CTX *mem_ctx, + ret = sysdb_initgroups(tmp_ctx, domain, username, &res); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "sysdb_asq_search failed [%d]: %s\n", ret, sss_strerror(ret)); ++ "sysdb_initgroups() failed [%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + +diff --git a/src/providers/ipa/ipa_hbac_services.c b/src/providers/ipa/ipa_hbac_services.c +index 79088ff66..387e915cd 100644 +--- a/src/providers/ipa/ipa_hbac_services.c ++++ b/src/providers/ipa/ipa_hbac_services.c +@@ -487,7 +487,7 @@ hbac_service_attrs_to_rule(TALLOC_CTX *mem_ctx, + /* Original DN matched a single service. Get the service name */ + name = ldb_msg_find_attr_as_string(msgs[0], IPA_CN, NULL); + if (name == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Attribute is missing!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Attribute IPA_CN is missing!\n"); + ret = EFAULT; + goto done; + } +@@ -523,7 +523,7 @@ hbac_service_attrs_to_rule(TALLOC_CTX *mem_ctx, + /* Original DN matched a single group. Get the groupname */ + name = ldb_msg_find_attr_as_string(msgs[0], IPA_CN, NULL); + if (name == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Attribute is missing!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Attribute IPA_CN is missing!\n"); + ret = EFAULT; + goto done; + } +diff --git a/src/providers/ipa/ipa_hbac_users.c b/src/providers/ipa/ipa_hbac_users.c +index 2801a3162..25850eac0 100644 +--- a/src/providers/ipa/ipa_hbac_users.c ++++ b/src/providers/ipa/ipa_hbac_users.c +@@ -124,7 +124,7 @@ get_ipa_groupname(TALLOC_CTX *mem_ctx, + if (strcasecmp("cn", account_comp_name) != 0) { + /* The third component name is not "cn" */ + DEBUG(SSSDBG_CRIT_FAILURE, +- "Expected cn in second component, got %s\n", account_comp_name); ++ "Expected cn in third component, got %s\n", account_comp_name); + ret = ERR_UNEXPECTED_ENTRY_TYPE; + goto done; + } +@@ -135,7 +135,7 @@ get_ipa_groupname(TALLOC_CTX *mem_ctx, + account_comp_val->length) != 0) { + /* The third component value is not "accounts" */ + DEBUG(SSSDBG_CRIT_FAILURE, +- "Expected cn accounts second component, got %s\n", ++ "Expected accounts third component, got %s\n", + (const char *) account_comp_val->data); + ret = ERR_UNEXPECTED_ENTRY_TYPE; + goto done; +diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c +index 9253514a3..2cbe0c9c7 100644 +--- a/src/providers/ipa/ipa_id.c ++++ b/src/providers/ipa/ipa_id.c +@@ -266,7 +266,7 @@ ipa_initgr_get_overrides_send(TALLOC_CTX *memctx, + } + state->groups_id_attr = talloc_strdup(state, groups_id_attr); + if (state->groups_id_attr == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n"); + ret = ENOMEM; + goto done; + } +diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c +index a4d58e3bd..afdd6fdd0 100644 +--- a/src/providers/ipa/ipa_init.c ++++ b/src/providers/ipa/ipa_init.c +@@ -317,10 +317,10 @@ static errno_t ipa_init_client_mode(struct be_ctx *be_ctx, + ret = sysdb_get_view_name(ipa_id_ctx, be_ctx->domain->sysdb, + &ipa_id_ctx->view_name); + if (ret == ENOENT) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find view name in the cache. " ++ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot find view name in the cache. " + "Will do online lookup later.\n"); + } else if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_view_name() failed [%d]: %s\n", ++ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_get_view_name() failed [%d]: %s\n", + ret, sss_strerror(ret)); + return ret; + } +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index c3e1acb48..fb93c6233 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -2224,7 +2224,8 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + + break; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected request type.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unexpected request type %d.\n", state->request_type); + ret = EINVAL; + goto done; + } +diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c +index 5cb02de86..760349134 100644 +--- a/src/providers/ipa/ipa_selinux.c ++++ b/src/providers/ipa/ipa_selinux.c +@@ -681,7 +681,7 @@ static errno_t selinux_fork_child(struct selinux_child_state *state) + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, +- "pipe failed [%d][%s].\n", errno, sss_strerror(errno)); ++ "pipe (from) failed [%d][%s].\n", errno, sss_strerror(errno)); + return ret; + } + +@@ -689,7 +689,7 @@ static errno_t selinux_fork_child(struct selinux_child_state *state) + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, +- "pipe failed [%d][%s].\n", errno, sss_strerror(errno)); ++ "pipe (to) failed [%d][%s].\n", errno, sss_strerror(errno)); + return ret; + } + +diff --git a/src/providers/ipa/ipa_session.c b/src/providers/ipa/ipa_session.c +index 6672cb349..935393ccd 100644 +--- a/src/providers/ipa/ipa_session.c ++++ b/src/providers/ipa/ipa_session.c +@@ -570,7 +570,7 @@ ipa_pam_session_handler_done(struct tevent_req *subreq) + talloc_free(subreq); + + if (ret == ENOENT) { +- DEBUG(SSSDBG_IMPORTANT_INFO, "No Desktop Profile rules found\n"); ++ DEBUG(SSSDBG_FUNC_DATA, "No Desktop Profile rules found\n"); + if (!state->session_ctx->no_rules_found) { + state->session_ctx->no_rules_found = true; + state->session_ctx->last_request = time(NULL); +@@ -668,7 +668,7 @@ ipa_pam_session_handler_get_deskprofile_user_info(TALLOC_CTX *mem_ctx, + + if (res->count != 1) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "sysdb_getpwnam() got more users than expected. " ++ "sysdb_getpwnam() returned unexpected amount of users. " + "Expected [%d], got [%d]\n", 1, res->count); + ret = EINVAL; + goto done; +diff --git a/src/providers/ipa/ipa_subdomains_ext_groups.c b/src/providers/ipa/ipa_subdomains_ext_groups.c +index c730c3317..790ae9d16 100644 +--- a/src/providers/ipa/ipa_subdomains_ext_groups.c ++++ b/src/providers/ipa/ipa_subdomains_ext_groups.c +@@ -840,7 +840,8 @@ static void ipa_add_ad_memberships_get_next(struct tevent_req *req) + } + + if (missing_groups) { +- DEBUG(SSSDBG_CRIT_FAILURE, "There are unresolved external group " ++ /* this might be HBAC or sudo rule */ ++ DEBUG(SSSDBG_FUNC_DATA, "There are unresolved external group " + "memberships even after all groups " + "have been looked up on the LDAP " + "server.\n"); +diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c +index 36f32fae8..46d496258 100644 +--- a/src/providers/ipa/ipa_subdomains_id.c ++++ b/src/providers/ipa/ipa_subdomains_id.c +@@ -506,7 +506,13 @@ struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx, + break; + default: + ret = EINVAL; +- DEBUG(SSSDBG_OP_FAILURE, "Invalid sub-domain request type.\n"); ++ if (state->entry_type > BE_REQ__LAST) { ++ DEBUG(SSSDBG_OP_FAILURE, "Invalid sub-domain request type %d.\n", ++ state->entry_type); ++ } else { ++ DEBUG(SSSDBG_TRACE_FUNC, "Unhandled sub-domain request type %d.\n", ++ state->entry_type); ++ } + } + if (ret != EOK) goto fail; + +@@ -1027,6 +1033,9 @@ apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, + const char *homedir = NULL; + struct ldb_message_element *msg_el = NULL; + size_t c; ++ const char *category = NULL; ++ size_t length = 0; ++ bool user_class = true; + + msg_el = ldb_msg_find_element(msg, SYSDB_OBJECTCATEGORY); + if (msg_el == NULL) { +@@ -1039,12 +1048,15 @@ apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, + * case of a MPG group lookup if SYSDB_OBJECTCATEGORY is SYSDB_GROUP_CLASS. + */ + for (c = 0; c < msg_el->num_values; c++) { +- if (strncmp(SYSDB_USER_CLASS, (const char *)msg_el->values[c].data, +- msg_el->values[c].length) == 0 +- || (sss_domain_is_mpg(dom) +- && strncmp(SYSDB_GROUP_CLASS, +- (const char *)msg_el->values[c].data, +- msg_el->values[c].length) == 0)) { ++ category = (const char *)msg_el->values[c].data; ++ length = msg_el->values[c].length; ++ if (strncmp(SYSDB_USER_CLASS, category, length) == 0) { ++ user_class = true; ++ break; ++ } ++ if (sss_domain_is_mpg(dom) ++ && strncmp(SYSDB_GROUP_CLASS, category, length) == 0) { ++ user_class = false; + break; + } + } +@@ -1064,8 +1076,12 @@ apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, + + uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0); + if (uid == 0) { +- DEBUG(SSSDBG_OP_FAILURE, "UID for user [%s] is not known.\n", +- fqname); ++ if (user_class) { ++ DEBUG(SSSDBG_OP_FAILURE, "UID for user [%s] is unknown\n", fqname); ++ } else { ++ DEBUG(SSSDBG_TRACE_INTERNAL, ++ "No UID for object [%s], perhaps mpg\n", fqname); ++ } + ret = ENOENT; + goto done; + } +@@ -1309,7 +1325,7 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq) + + state->object_sid = talloc_strdup(state, sid); + if (state->object_sid == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n"); + ret = ENOMEM; + goto fail; + } +@@ -1521,7 +1537,7 @@ static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req) + + state->ar->filter_value = talloc_strdup(state->ar, obj_name); + if (state->ar->filter_value == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n"); + return ENOMEM; + } + state->ar->filter_type = BE_FILTER_NAME; +diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c +index fcdd05322..deb2c2cee 100644 +--- a/src/providers/ipa/ipa_subdomains_server.c ++++ b/src/providers/ipa/ipa_subdomains_server.c +@@ -513,7 +513,7 @@ static void ipa_getkeytab_exec(const char *ccache, + + gkt_env[0] = talloc_asprintf(NULL, "KRB5CCNAME=%s", ccache); + if (gkt_env[0] == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to format KRB5CCNAME\n"); ++ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to format KRB5CCNAME\n"); + exit(1); + } + +@@ -522,7 +522,7 @@ static void ipa_getkeytab_exec(const char *ccache, + ret = unlink(keytab_path); + if (ret == -1) { + ret = errno; +- DEBUG(SSSDBG_CRIT_FAILURE, ++ DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to unlink the temporary ccname [%d][%s]\n", + ret, sss_strerror(ret)); + exit(1); +@@ -533,12 +533,12 @@ static void ipa_getkeytab_exec(const char *ccache, + "-r", "-s", server, "-p", principal, "-k", keytab_path, NULL, + gkt_env); + +- DEBUG(SSSDBG_CRIT_FAILURE, ++ DEBUG(SSSDBG_FATAL_FAILURE, + "execle returned %d, this shouldn't happen!\n", ret); + + /* The child should never end up here */ + ret = errno; +- DEBUG(SSSDBG_CRIT_FAILURE, ++ DEBUG(SSSDBG_FATAL_FAILURE, + "execle failed [%d][%s].\n", ret, sss_strerror(ret)); + exit(1); + } +@@ -748,7 +748,8 @@ static errno_t ipa_server_trusted_dom_setup_1way(struct tevent_req *req) + + state->new_keytab = talloc_asprintf(state, "%sXXXXXX", state->keytab); + if (state->new_keytab == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set up ipa_get_keytab\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot set up ipa_get_keytab. talloc_asprintf() failed\n"); + return ENOMEM; + } + +diff --git a/src/providers/ipa/ipa_sudo.c b/src/providers/ipa/ipa_sudo.c +index 931770922..1b881d085 100644 +--- a/src/providers/ipa/ipa_sudo.c ++++ b/src/providers/ipa/ipa_sudo.c +@@ -223,7 +223,7 @@ ipa_sudo_init_ipa_schema(TALLOC_CTX *mem_ctx, + ipa_sudorule_map, IPA_OPTS_SUDORULE, + &sudo_ctx->sudorule_map); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse attribute map " ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse attribute map (rule) " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } +@@ -232,7 +232,7 @@ ipa_sudo_init_ipa_schema(TALLOC_CTX *mem_ctx, + ipa_sudocmdgroup_map, IPA_OPTS_SUDOCMDGROUP, + &sudo_ctx->sudocmdgroup_map); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse attribute map " ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse attribute map (cmdgroup) " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } +@@ -241,7 +241,7 @@ ipa_sudo_init_ipa_schema(TALLOC_CTX *mem_ctx, + ipa_sudocmd_map, IPA_OPTS_SUDOCMD, + &sudo_ctx->sudocmd_map); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse attribute map " ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse attribute map (cmd) " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } +@@ -250,16 +250,16 @@ ipa_sudo_init_ipa_schema(TALLOC_CTX *mem_ctx, + CONFDB_SUDO_THRESHOLD, CONFDB_DEFAULT_SUDO_THRESHOLD, + &sudo_ctx->sudocmd_threshold); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Could not parse sudo search base\n"); +- return ret; ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not get sudo threshold\n"); ++ goto done; + } + + ret = sdap_parse_search_base(sudo_ctx, sudo_ctx->sdap_opts->basic, + SDAP_SUDO_SEARCH_BASE, + &sudo_ctx->sudo_sb); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Could not parse sudo search base\n"); +- return ret; ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not parse sudo search base\n"); ++ goto done; + } + + ret = ipa_sudo_ptask_setup(be_ctx, sudo_ctx); +diff --git a/src/providers/ipa/ipa_sudo_async.c b/src/providers/ipa/ipa_sudo_async.c +index 1d7a69814..c531ecbf9 100644 +--- a/src/providers/ipa/ipa_sudo_async.c ++++ b/src/providers/ipa/ipa_sudo_async.c +@@ -520,7 +520,7 @@ ipa_sudo_fetch_addtl_cmdgroups_done(struct tevent_req *subreq) + goto done; + } + +- DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu additional command groups\n", ++ DEBUG(SSSDBG_FUNC_DATA, "Received %zu additional command groups\n", + num_attrs); + + ret = ipa_sudo_filter_rules_bycmdgroups(state, state->domain, attrs, +@@ -609,7 +609,7 @@ ipa_sudo_fetch_rules_done(struct tevent_req *subreq) + goto done; + } + +- DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo rules\n", num_attrs); ++ DEBUG(SSSDBG_FUNC_DATA, "Received %zu sudo rules\n", num_attrs); + + ret = ipa_sudo_conv_rules(state->conv, attrs, num_attrs); + if (ret != EOK) { +@@ -689,7 +689,7 @@ ipa_sudo_fetch_cmdgroups_done(struct tevent_req *subreq) + goto done; + } + +- DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo command groups\n", ++ DEBUG(SSSDBG_FUNC_DATA, "Received %zu sudo command groups\n", + num_attrs); + + ret = ipa_sudo_conv_cmdgroups(state->conv, attrs, num_attrs); +@@ -769,7 +769,7 @@ ipa_sudo_fetch_cmds_done(struct tevent_req *subreq) + goto done; + } + +- DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo commands\n", num_attrs); ++ DEBUG(SSSDBG_FUNC_DATA, "Received %zu sudo commands\n", num_attrs); + + ret = ipa_sudo_conv_cmds(state->conv, attrs, num_attrs); + if (ret != EOK) { +@@ -1109,7 +1109,7 @@ done: + if (in_transaction) { + sret = sysdb_transaction_cancel(state->sysdb); + if (sret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n"); + } + } + +diff --git a/src/providers/ipa/ipa_sudo_conversion.c b/src/providers/ipa/ipa_sudo_conversion.c +index b5fc49379..bd1ec72b3 100644 +--- a/src/providers/ipa/ipa_sudo_conversion.c ++++ b/src/providers/ipa/ipa_sudo_conversion.c +@@ -801,7 +801,7 @@ convert_host(TALLOC_CTX *mem_ctx, + *skip_entry = true; + return NULL; + } else if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n", ++ DEBUG(SSSDBG_CRIT_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n", + value, ret, sss_strerror(ret)); + return NULL; + } +@@ -841,7 +841,7 @@ convert_user(TALLOC_CTX *mem_ctx, + *skip_entry = true; + return NULL; + } else if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n", ++ DEBUG(SSSDBG_CRIT_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n", + value, ret, sss_strerror(ret)); + return NULL; + } +@@ -904,7 +904,7 @@ convert_group(TALLOC_CTX *mem_ctx, + *skip_entry = true; + return NULL; + } else if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n", ++ DEBUG(SSSDBG_CRIT_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n", + value, ret, sss_strerror(ret)); + return NULL; + } +diff --git a/src/providers/ipa/ipa_views.c b/src/providers/ipa/ipa_views.c +index 2a918bdc8..e1090d03b 100644 +--- a/src/providers/ipa/ipa_views.c ++++ b/src/providers/ipa/ipa_views.c +@@ -232,7 +232,7 @@ static errno_t get_dp_id_data_for_xyz(TALLOC_CTX *mem_ctx, const char *val, + ar->filter_value = talloc_strdup(ar, val); + ar->domain = talloc_strdup(ar, domain_name); + if (ar->filter_value == NULL || ar->domain == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed.\n"); + talloc_free(ar); + return ENOMEM; + } +@@ -471,7 +471,7 @@ static void ipa_get_ad_override_done(struct tevent_req *subreq) + + ret = ipa_get_ad_override_qualify_name(state); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Cannot qualify object name\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot qualify object name\n"); + goto fail; + } + +diff --git a/src/providers/krb5/krb5_access.c b/src/providers/krb5/krb5_access.c +index be9068c0f..2ae5abe14 100644 +--- a/src/providers/krb5/krb5_access.c ++++ b/src/providers/krb5/krb5_access.c +@@ -78,7 +78,8 @@ struct tevent_req *krb5_access_send(TALLOC_CTX *mem_ctx, + } + + if (pd->cmd != SSS_PAM_ACCT_MGMT) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected pam task.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unexpected pam task %d.\n", pd->cmd); + ret = EINVAL; + goto done; + } +diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c +index a1c0b3640..699c2467b 100644 +--- a/src/providers/krb5/krb5_auth.c ++++ b/src/providers/krb5/krb5_auth.c +@@ -499,7 +499,7 @@ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx, + /* handle empty password gracefully */ + if (authtok_type == SSS_AUTHTOK_TYPE_EMPTY) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "Illegal zero-length authtok for user [%s]\n", ++ "Illegal empty authtok for user [%s]\n", + pd->user); + state->pam_status = PAM_AUTH_ERR; + state->dp_err = DP_ERR_OK; +@@ -854,7 +854,7 @@ static void krb5_auth_done(struct tevent_req *subreq) + ret = EOK; + goto done; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected PAM task\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected PAM task %d\n", pd->cmd); + ret = EINVAL; + goto done; + } +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index cab7b27a2..06fdf7156 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -258,7 +258,7 @@ static void sss_krb5_expire_callback_func(krb5_context context, void *data, + + blob = talloc_array(kr->pd, uint32_t, 2); + if (blob == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_array failed.\n"); + return; + } + +@@ -525,7 +525,8 @@ static krb5_error_code tokeninfo_matches(TALLOC_CTX *mem_ctx, + out_token, out_pin); + break; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported authtok type.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unsupported authtok type %d\n", sss_authtok_get_type(auth_tok)); + } + + return EINVAL; +@@ -1087,7 +1088,7 @@ static errno_t pack_response_packet(TALLOC_CTX *mem_ctx, errno_t error, + + buf = talloc_array(mem_ctx, uint8_t, size); + if (!buf) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Insufficient memory to create message.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_array failed\n"); + return ENOMEM; + } + +@@ -1958,13 +1959,12 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) + &msg_len, &msg); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "pack_user_info_chpass_error failed.\n"); ++ "pack_user_info_chpass_error failed [%d]\n", ret); + } else { + ret = pam_add_response(kr->pd, SSS_PAM_USER_INFO, msg_len, + msg); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "pam_add_response failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); + } + } + return kerr; +@@ -2036,13 +2036,12 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) + &user_resp_len, &user_resp); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "pack_user_info_chpass_error failed.\n"); ++ "pack_user_info_chpass_error failed [%d]\n", ret); + } else { + ret = pam_add_response(kr->pd, SSS_PAM_USER_INFO, user_resp_len, + user_resp); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "pam_add_response failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); + } + } + } +@@ -2448,7 +2447,7 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, + + pd = create_pam_data(kr); + if (pd == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "create_pam_data failed.\n"); + return ENOMEM; + } + kr->pd = pd; +@@ -3110,7 +3109,7 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline) + + kr->creds = calloc(1, sizeof(krb5_creds)); + if (kr->creds == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "calloc failed.\n"); + return ENOMEM; + } + +@@ -3345,7 +3344,7 @@ int main(int argc, const char *argv[]) + + kr = talloc_zero(NULL, struct krb5_req); + if (kr == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n"); + ret = ENOMEM; + goto done; + } +@@ -3403,7 +3402,7 @@ int main(int argc, const char *argv[]) + + ret = k5c_setup(kr, offline); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "krb5_child_setup failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "k5c_setup failed.\n"); + goto done; + } + +diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c +index 37f4304e8..01777e22b 100644 +--- a/src/providers/krb5/krb5_child_handler.c ++++ b/src/providers/krb5/krb5_child_handler.c +@@ -449,14 +449,14 @@ static errno_t fork_child(struct tevent_req *req) + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, +- "pipe failed [%d][%s].\n", errno, strerror(errno)); ++ "pipe (from) failed [%d][%s].\n", errno, strerror(errno)); + goto fail; + } + ret = pipe(pipefd_to_child); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, +- "pipe failed [%d][%s].\n", errno, strerror(errno)); ++ "pipe (to) failed [%d][%s].\n", errno, strerror(errno)); + goto fail; + } + +diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c +index 5c11c347b..316603946 100644 +--- a/src/providers/krb5/krb5_common.c ++++ b/src/providers/krb5/krb5_common.c +@@ -793,7 +793,7 @@ static void krb5_resolve_callback(void *private_data, struct fo_server *server) + + krb5_service = talloc_get_type(private_data, struct krb5_service); + if (!krb5_service) { +- DEBUG(SSSDBG_CRIT_FAILURE, "FATAL: Bad private_data\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Bad private_data\n"); + return; + } + +@@ -1110,7 +1110,7 @@ void remove_krb5_info_files_callback(void *pvt) + ctx->kdc_service_name); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "be_fo_run_callbacks_at_next_request failed, " ++ "be_fo_run_callbacks_at_next_request(kdc_service_name) failed, " + "krb5 info files will not be removed, because " + "it is unclear if they will be recreated properly.\n"); + return; +@@ -1120,7 +1120,7 @@ void remove_krb5_info_files_callback(void *pvt) + ctx->kpasswd_service_name); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "be_fo_run_callbacks_at_next_request failed, " ++ "be_fo_run_callbacks_at_next_request(kpasswd_service_name) failed, " + "krb5 info files will not be removed, because " + "it is unclear if they will be recreated properly.\n"); + return; +diff --git a/src/providers/krb5/krb5_delayed_online_authentication.c b/src/providers/krb5/krb5_delayed_online_authentication.c +index 8572d1249..07d375b9d 100644 +--- a/src/providers/krb5/krb5_delayed_online_authentication.c ++++ b/src/providers/krb5/krb5_delayed_online_authentication.c +@@ -173,7 +173,7 @@ static errno_t authenticate_stored_users( + ret = hash_lookup(uid_table, &key, &value); + + if (ret == HASH_SUCCESS) { +- DEBUG(SSSDBG_CRIT_FAILURE, "User [%s] is still logged in, " ++ DEBUG(SSSDBG_FUNC_DATA, "User [%s] is still logged in, " + "trying online authentication.\n", pd->user); + + auth_data = talloc_zero(deferred_auth_ctx->be_ctx, +@@ -193,7 +193,7 @@ static errno_t authenticate_stored_users( + } + } + } else { +- DEBUG(SSSDBG_CRIT_FAILURE, "User [%s] is not logged in anymore, " ++ DEBUG(SSSDBG_FUNC_DATA, "User [%s] is not logged in anymore, " + "discarding online authentication.\n", pd->user); + talloc_free(pd); + } +diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c +index 8b2159e92..d79e7c367 100644 +--- a/src/providers/krb5/krb5_renew_tgt.c ++++ b/src/providers/krb5/krb5_renew_tgt.c +@@ -405,7 +405,7 @@ static errno_t check_ccache_files(struct renew_tgt_ctx *renew_tgt_ctx) + + base_dn = sysdb_user_base_dn(tmp_ctx, renew_tgt_ctx->be_ctx->domain); + if (base_dn == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "sysdb_base_dn failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_base_dn failed.\n"); + ret = ENOMEM; + goto done; + } +@@ -440,7 +440,7 @@ static errno_t check_ccache_files(struct renew_tgt_ctx *renew_tgt_ctx) + + ret = sss_parse_internal_fqname(tmp_ctx, user_name, NULL, &user_dom); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, ++ DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot parse internal fqname [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; +diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c +index e3f8f2140..43056ba28 100644 +--- a/src/providers/krb5/krb5_utils.c ++++ b/src/providers/krb5/krb5_utils.c +@@ -287,7 +287,7 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, + name = sss_output_name(tmp_ctx, kr->pd->user, case_sensitive, 0); + if (name == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "sss_get_cased_name failed\n"); ++ "sss_output_name failed\n"); + goto done; + } + +diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c +index 89ff4ece0..42ef962b4 100644 +--- a/src/providers/ldap/ldap_auth.c ++++ b/src/providers/ldap/ldap_auth.c +@@ -64,7 +64,7 @@ static errno_t add_expired_warning(struct pam_data *pd, long exp_time) + + data = talloc_array(pd, uint32_t, 2); + if (data == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_array failed.\n"); + return ENOMEM; + } + +@@ -249,7 +249,8 @@ errno_t check_pwexpire_policy(enum pwexpire pw_expire_type, + ret = EOK; + break; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "Unknown password expiration type.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unknown password expiration type %d.\n", pw_expire_type); + ret = EINVAL; + } + +@@ -1355,9 +1356,10 @@ static void sdap_pam_chpass_handler_auth_done(struct tevent_req *subreq) + case PWEXPIRE_NONE: + break; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "Unknown password expiration type.\n"); +- state->pd->pam_status = PAM_SYSTEM_ERR; +- goto done; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unknown password expiration type %d.\n", pw_expire_type); ++ state->pd->pam_status = PAM_SYSTEM_ERR; ++ goto done; + } + } + +diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c +index 84941c6e4..8580e2785 100644 +--- a/src/providers/ldap/ldap_child.c ++++ b/src/providers/ldap/ldap_child.c +@@ -223,7 +223,7 @@ static int lc_verify_keytab_ex(const char *principal, + /* This should never happen. The API docs for this function + * specify only success for this function + */ +- DEBUG(SSSDBG_CRIT_FAILURE,"Could not free keytab entry contents\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not free keytab entry contents\n"); + /* This is non-fatal, so we'll continue here */ + } + +diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c +index cd589a7c0..2ad8680a1 100644 +--- a/src/providers/ldap/ldap_init.c ++++ b/src/providers/ldap/ldap_init.c +@@ -43,8 +43,8 @@ struct ldap_init_ctx { + }; + + /* Please use this only for short lists */ +-errno_t check_order_list_for_duplicates(char **list, +- bool case_sensitive) ++static errno_t check_order_list_for_duplicates(char **list, ++ bool case_sensitive) + { + size_t c; + size_t d; +diff --git a/src/providers/ldap/ldap_options.c b/src/providers/ldap/ldap_options.c +index d06d3980e..bb51785fb 100644 +--- a/src/providers/ldap/ldap_options.c ++++ b/src/providers/ldap/ldap_options.c +@@ -408,14 +408,15 @@ int ldap_get_options(TALLOC_CTX *memctx, + sss_erase_talloc_mem_securely(cleartext); + talloc_free(cleartext); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "dp_opt_set_string failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "dp_opt_set_blob(authtok) failed.\n"); + goto done; + } + + ret = dp_opt_set_string(opts->basic, SDAP_DEFAULT_AUTHTOK_TYPE, + "password"); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "dp_opt_set_string failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "dp_opt_set_string(authtok_type) failed.\n"); + goto done; + } + } +@@ -629,7 +630,8 @@ int ldap_get_autofs_options(TALLOC_CTX *memctx, + default_entry_map = rfc2307bis_autofs_entry_map; + break; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "Unknown LDAP schema!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unknown LDAP schema %d!\n", opts->schema_type); + return EINVAL; + } + +diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c +index 7cb00480d..32c0144b9 100644 +--- a/src/providers/ldap/sdap.c ++++ b/src/providers/ldap/sdap.c +@@ -371,7 +371,7 @@ int sdap_get_map(TALLOC_CTX *memctx, + + if (map[i].def_name && !map[i].name) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "Failed to retrieve value for %s\n", map[i].opt_name); ++ "Failed to process value for %s\n", map[i].opt_name); + talloc_zfree(map); + return EINVAL; + } +@@ -532,7 +532,8 @@ int sdap_parse_entry(TALLOC_CTX *memctx, + if (!vals) { + ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + if (lerrno != LDAP_SUCCESS) { +- DEBUG(SSSDBG_CRIT_FAILURE, "LDAP Library error: %d(%s)\n", ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "ldap_get_values_len() failed: %d(%s)\n", + lerrno, sss_ldap_err2string(lerrno)); + ret = EIO; + goto done; +@@ -613,7 +614,7 @@ int sdap_parse_entry(TALLOC_CTX *memctx, + + ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); + if (lerrno) { +- DEBUG(SSSDBG_CRIT_FAILURE, "LDAP Library error: %d(%s)\n", ++ DEBUG(SSSDBG_CRIT_FAILURE, "ldap_get_option() failed: %d(%s)\n", + lerrno, sss_ldap_err2string(lerrno)); + ret = EIO; + goto done; +@@ -884,7 +885,8 @@ errno_t setup_tls_config(struct dp_option *basic_opts) + ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_HARD; + } + else { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unknown value for tls_reqcert.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unknown value for tls_reqcert '%s'.\n", tls_opt); + return EINVAL; + } + /* LDAP_OPT_X_TLS_REQUIRE_CERT has to be set as a global option, +@@ -893,7 +895,8 @@ errno_t setup_tls_config(struct dp_option *basic_opts) + &ldap_opt_x_tls_require_cert); + if (ret != LDAP_OPT_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "ldap_set_option failed: %s\n", sss_ldap_err2string(ret)); ++ "ldap_set_option(req_cert) failed: %s\n", ++ sss_ldap_err2string(ret)); + return EIO; + } + } +@@ -903,7 +906,8 @@ errno_t setup_tls_config(struct dp_option *basic_opts) + ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, tls_opt); + if (ret != LDAP_OPT_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "ldap_set_option failed: %s\n", sss_ldap_err2string(ret)); ++ "ldap_set_option(cacertfile) failed: %s\n", ++ sss_ldap_err2string(ret)); + return EIO; + } + } +@@ -913,7 +917,8 @@ errno_t setup_tls_config(struct dp_option *basic_opts) + ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTDIR, tls_opt); + if (ret != LDAP_OPT_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "ldap_set_option failed: %s\n", sss_ldap_err2string(ret)); ++ "ldap_set_option(cacertdir) failed: %s\n", ++ sss_ldap_err2string(ret)); + return EIO; + } + } +@@ -923,7 +928,8 @@ errno_t setup_tls_config(struct dp_option *basic_opts) + ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE, tls_opt); + if (ret != LDAP_OPT_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "ldap_set_option failed: %s\n", sss_ldap_err2string(ret)); ++ "ldap_set_option(certfile) failed: %s\n", ++ sss_ldap_err2string(ret)); + return EIO; + } + } +@@ -933,7 +939,8 @@ errno_t setup_tls_config(struct dp_option *basic_opts) + ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_KEYFILE, tls_opt); + if (ret != LDAP_OPT_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "ldap_set_option failed: %s\n", sss_ldap_err2string(ret)); ++ "ldap_set_option(keyfile) failed: %s\n", ++ sss_ldap_err2string(ret)); + return EIO; + } + } +@@ -943,7 +950,8 @@ errno_t setup_tls_config(struct dp_option *basic_opts) + ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE, tls_opt); + if (ret != LDAP_OPT_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "ldap_set_option failed: %s\n", sss_ldap_err2string(ret)); ++ "ldap_set_option(cipher) failed: %s\n", ++ sss_ldap_err2string(ret)); + return EIO; + } + } +diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c +index dd04ec512..8add97ba8 100644 +--- a/src/providers/ldap/sdap_access.c ++++ b/src/providers/ldap/sdap_access.c +@@ -317,7 +317,8 @@ static errno_t sdap_access_check_next_rule(struct sdap_access_req_ctx *state, + + default: + DEBUG(SSSDBG_CRIT_FAILURE, +- "Unexpected access rule type. Access denied.\n"); ++ "Unexpected access rule type %d. Access denied.\n", ++ state->access_ctx->access_rule[state->current_rule]); + ret = ERR_ACCESS_DENIED; + } + +@@ -1220,13 +1221,13 @@ static errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain, + attrs = sysdb_new_attrs(NULL); + if (attrs == NULL) { + ret = ENOMEM; +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not create attrs\n"); + goto done; + } + + ret = sysdb_attrs_add_bool(attrs, attr_name, value); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attr value\n"); + goto done; + } + +@@ -1787,7 +1788,7 @@ errno_t sdap_access_ppolicy_step(struct tevent_req *req) + false); + + if (subreq == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "sdap_access_ppolicy_send failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "sdap_get_generic_send failed.\n"); + ret = ENOMEM; + goto done; + } +@@ -1913,7 +1914,7 @@ static void sdap_access_ppolicy_step_done(struct tevent_req *subreq) + ret = sdap_access_decide_offline(state->cached_access); + } else { + DEBUG(SSSDBG_CRIT_FAILURE, +- "sdap_get_generic_send() returned error [%d][%s]\n", ++ "sdap_id_op_done() returned error [%d][%s]\n", + ret, sss_strerror(ret)); + } + +diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c +index 68d5d44f8..cc77fb249 100644 +--- a/src/providers/ldap/sdap_async.c ++++ b/src/providers/ldap/sdap_async.c +@@ -749,7 +749,7 @@ sdap_modify_send(TALLOC_CTX *mem_ctx, + + ret = ldap_modify_ext(state->sh->ldap, dn, mods, NULL, NULL, &msgid); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to send operation!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "ldap_modify_ext() failed [%d]\n", ret); + goto done; + } + +@@ -2120,7 +2120,7 @@ static int sdap_x_deref_create_control(struct sdap_handle *sh, + + ret = ldap_create_deref_control_value(sh->ldap, ds, &derefval); + if (ret != LDAP_SUCCESS) { +- DEBUG(SSSDBG_CRIT_FAILURE, "sss_ldap_control_create failed: %s\n", ++ DEBUG(SSSDBG_CRIT_FAILURE, "ldap_create_deref_control_value failed: %s\n", + ldap_err2string(ret)); + return ret; + } +@@ -2129,7 +2129,7 @@ static int sdap_x_deref_create_control(struct sdap_handle *sh, + 1, &derefval, 1, ctrl); + ldap_memfree(derefval.bv_val); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "sss_ldap_control_create failed\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "sdap_control_create failed %d\n", ret); + return ret; + } + +@@ -2875,7 +2875,8 @@ static void sdap_deref_search_done(struct tevent_req *subreq) + &state->reply_count, &state->reply); + break; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "Unknown deref method\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unknown deref method %d\n", state->deref_type); + tevent_req_error(req, EINVAL); + return; + } +diff --git a/src/providers/ldap/sdap_async_autofs.c b/src/providers/ldap/sdap_async_autofs.c +index eaca0324e..ae2fa33e1 100644 +--- a/src/providers/ldap/sdap_async_autofs.c ++++ b/src/providers/ldap/sdap_async_autofs.c +@@ -720,7 +720,7 @@ sdap_autofs_setautomntent_send(TALLOC_CTX *memctx, + dp_opt_get_int(state->opts->basic, + SDAP_SEARCH_TIMEOUT)); + if (!subreq) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "sdap_get_automntmap_send failed\n"); + ret = ENOMEM; + goto fail; + } +diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c +index 5f69cedcc..eead3f119 100644 +--- a/src/providers/ldap/sdap_async_connection.c ++++ b/src/providers/ldap/sdap_async_connection.c +@@ -694,10 +694,10 @@ static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, + LDAP_OPT_RESULT_CODE, &ldap_err); + if (ret != LDAP_OPT_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "ldap_bind failed (couldn't get ldap error)\n"); ++ "ldap_sasl_bind failed (couldn't get ldap error)\n"); + ret = LDAP_LOCAL_ERROR; + } else { +- DEBUG(SSSDBG_CRIT_FAILURE, "ldap_bind failed (%d)[%s]\n", ++ DEBUG(SSSDBG_CRIT_FAILURE, "ldap_sasl_bind failed (%d)[%s]\n", + ldap_err, sss_ldap_err2string(ldap_err)); + ret = ldap_err; + } +@@ -988,7 +988,7 @@ static struct tevent_req *sasl_bind_send(TALLOC_CTX *memctx, + (*sdap_sasl_interact), state); + if (ret != LDAP_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "ldap_sasl_bind failed (%d)[%s]\n", ++ "ldap_sasl_interactive_bind_s failed (%d)[%s]\n", + ret, sss_ldap_err2string(ret)); + + optret = sss_ldap_get_diagnostic_msg(state, state->sh->ldap, +diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c +index 5dbfd73c4..16c4a5f37 100644 +--- a/src/providers/ldap/sdap_async_groups.c ++++ b/src/providers/ldap/sdap_async_groups.c +@@ -883,10 +883,7 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx, + const char *check_name; + + if (dom->ignore_group_members) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Group members are ignored, nothing to do. If you see this " \ +- "message it might indicate an error in the group processing " \ +- "logic.\n"); ++ DEBUG(SSSDBG_TRACE_FUNC, "Group members are ignored, nothing to do.\n"); + return EOK; + } + +@@ -978,7 +975,12 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx, + ret = sysdb_remove_attrs(group_dom, group_name, SYSDB_MEMBER_GROUP, + discard_const(remove_attrs)); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "sysdb_remove_attrs failed.\n"); ++ if (ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_remove_attrs failed.\n"); ++ } else { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "sysdb_remove_attrs failed for missing entry\n"); ++ } + goto fail; + } + } else { +@@ -1014,7 +1016,7 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx, + return EOK; + + fail: +- DEBUG(SSSDBG_OP_FAILURE, ++ DEBUG(SSSDBG_MINOR_FAILURE, + "Failed to save members of group %s\n", group_name); + return ret; + } +@@ -1130,8 +1132,13 @@ static int sdap_save_groups(TALLOC_CTX *memctx, + /* Do not fail completely on errors. + * Just report the failure to save and go on */ + if (ret) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to store group %d members.\n", i); ++ if (ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to store group %d members: %d\n", i, ret); ++ } else { ++ DEBUG(SSSDBG_FUNC_DATA, ++ "Can't save members of missing group %d\n", i); ++ } + } else { + DEBUG(SSSDBG_TRACE_ALL, "Group %d members processed!\n", i); + } +@@ -1270,7 +1277,7 @@ sdap_process_group_send(TALLOC_CTX *memctx, + + /* Group without members */ + if (el->num_values == 0) { +- DEBUG(SSSDBG_OP_FAILURE, "No Members. Done!\n"); ++ DEBUG(SSSDBG_FUNC_DATA, "No Members. Done!\n"); + ret = EOK; + goto done; + } +@@ -2249,7 +2256,7 @@ static void sdap_nested_done(struct tevent_req *subreq) + + if (hash_count(state->missing_external) == 0) { + /* No external members. Processing complete */ +- DEBUG(SSSDBG_TRACE_INTERNAL, "No external members, done"); ++ DEBUG(SSSDBG_TRACE_INTERNAL, "No external members, done\n"); + tevent_req_done(req); + return; + } +diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c +index 4b5b36403..bf8f9482b 100644 +--- a/src/providers/ldap/sdap_async_initgroups.c ++++ b/src/providers/ldap/sdap_async_initgroups.c +@@ -345,7 +345,7 @@ int sdap_initgr_common_store(struct sysdb_ctx *sysdb, + add_groups, ldap_groups, + ldap_groups_count); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Adding incomplete users failed\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Adding incomplete groups failed\n"); + goto done; + } + } +@@ -1043,6 +1043,10 @@ static void sdap_initgr_nested_search(struct tevent_req *subreq) + state->groups[state->groups_cur] = talloc_steal(state->groups, + groups[0]); + state->groups_cur++; ++ } else if (count == 0) { ++ /* this might be HBAC or sudo rule */ ++ DEBUG(SSSDBG_FUNC_DATA, "Object %s not found. Skipping\n", ++ state->group_dns[state->cur]); + } else { + DEBUG(SSSDBG_OP_FAILURE, + "Search for group %s, returned %zu results. Skipping\n", +diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c +index eb3e779ed..80ac4c1f4 100644 +--- a/src/providers/ldap/sdap_async_initgroups_ad.c ++++ b/src/providers/ldap/sdap_async_initgroups_ad.c +@@ -378,7 +378,7 @@ static void sdap_ad_resolve_sids_done(struct tevent_req *subreq) + /* Group was not found, we will ignore the error and continue with + * next group. This may happen for example if the group is built-in, + * but a custom search base is provided. */ +- DEBUG(SSSDBG_CRIT_FAILURE, ++ DEBUG(SSSDBG_MINOR_FAILURE, + "Unable to resolve SID %s - will try next sid.\n", + state->current_sid); + } else if (ret != EOK || sdap_error != EOK || dp_error != DP_ERR_OK) { +diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c +index 5473e1df8..28b65b639 100644 +--- a/src/providers/ldap/sdap_async_sudo.c ++++ b/src/providers/ldap/sdap_async_sudo.c +@@ -111,7 +111,7 @@ static void sdap_sudo_load_sudoers_done(struct tevent_req *subreq) + return; + } + +- DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo rules\n", ++ DEBUG(SSSDBG_FUNC_DATA, "Received %zu sudo rules\n", + state->num_rules); + + tevent_req_done(req); +@@ -665,7 +665,7 @@ done: + if (in_transaction) { + sret = sysdb_transaction_cancel(state->sysdb); + if (sret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n"); + } + } + +diff --git a/src/providers/ldap/sdap_child_helpers.c b/src/providers/ldap/sdap_child_helpers.c +index 9d25aea8b..480efc41b 100644 +--- a/src/providers/ldap/sdap_child_helpers.c ++++ b/src/providers/ldap/sdap_child_helpers.c +@@ -95,14 +95,14 @@ static errno_t sdap_fork_child(struct tevent_context *ev, + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, +- "pipe failed [%d][%s].\n", ret, strerror(ret)); ++ "pipe(from) failed [%d][%s].\n", ret, strerror(ret)); + goto fail; + } + ret = pipe(pipefd_to_child); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, +- "pipe failed [%d][%s].\n", ret, strerror(ret)); ++ "pipe(to) failed [%d][%s].\n", ret, strerror(ret)); + goto fail; + } + +@@ -332,7 +332,7 @@ struct tevent_req *sdap_get_tgt_send(TALLOC_CTX *mem_ctx, + + ret = set_tgt_child_timeout(req, ev, timeout); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "activate_child_timeout_handler failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "set_tgt_child_timeout failed.\n"); + goto fail; + } + +diff --git a/src/providers/ldap/sdap_hostid.c b/src/providers/ldap/sdap_hostid.c +index d90a83854..ae8caaddb 100644 +--- a/src/providers/ldap/sdap_hostid.c ++++ b/src/providers/ldap/sdap_hostid.c +@@ -166,7 +166,7 @@ hosts_get_done(struct tevent_req *subreq) + } + + if (state->count == 0) { +- DEBUG(SSSDBG_OP_FAILURE, ++ DEBUG(SSSDBG_FUNC_DATA, + "No host with name [%s] found.\n", state->name); + + ret = sysdb_delete_ssh_host(state->domain, state->name); +diff --git a/src/providers/ldap/sdap_id_op.c b/src/providers/ldap/sdap_id_op.c +index 6c803f31d..b8d76f8a5 100644 +--- a/src/providers/ldap/sdap_id_op.c ++++ b/src/providers/ldap/sdap_id_op.c +@@ -563,7 +563,7 @@ static void sdap_id_op_connect_done(struct tevent_req *subreq) + "is enabled.\n"); + } else { + /* be is going offline as there is no more servers to try */ +- DEBUG(SSSDBG_CRIT_FAILURE, ++ DEBUG(SSSDBG_OP_FAILURE, + "Failed to connect, going offline (%d [%s])\n", + ret, strerror(ret)); + is_offline = true; +diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c +index 926ce98f4..0e6fc8ea8 100644 +--- a/src/providers/proxy/proxy_auth.c ++++ b/src/providers/proxy/proxy_auth.c +@@ -68,7 +68,7 @@ static struct tevent_req *proxy_child_send(TALLOC_CTX *mem_ctx, + + req = tevent_req_create(mem_ctx, &state, struct proxy_child_ctx); + if (req == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not send PAM request to child\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; + } + +@@ -391,7 +391,7 @@ static void proxy_child_init_done(struct tevent_req *subreq) { + */ + sig_ctx = talloc_zero(child_ctx->auth_ctx, struct proxy_child_sig_ctx); + if(sig_ctx == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_signal failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n"); + tevent_req_error(req, ENOMEM); + return; + } +@@ -753,7 +753,7 @@ proxy_pam_handler_send(TALLOC_CTX *mem_ctx, + pd->pam_status = PAM_SUCCESS; + goto immediately; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported PAM task.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported PAM task %d\n", pd->cmd); + pd->pam_status = PAM_MODULE_UNKNOWN; + goto immediately; + } +diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c +index dc06f4669..bb96ec0f4 100644 +--- a/src/providers/proxy/proxy_child.c ++++ b/src/providers/proxy/proxy_child.c +@@ -270,7 +270,7 @@ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd) + } + break; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "unknown PAM call\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "unknown PAM call %d\n", pd->cmd); + pam_status=PAM_ABORT; + } + +@@ -383,13 +383,13 @@ proxy_cli_init(struct pc_ctx *ctx) + ret = sss_iface_connect_address(ctx, ctx->ev, sbus_cliname, sbus_address, + NULL, &ctx->conn); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to connect to %s\n", sbus_address); ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to connect to %s\n", sbus_address); + goto done; + } + + ret = sbus_connection_add_path_map(ctx->conn, paths); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add paths [%d]: %s\n", ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to add paths [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } +@@ -580,7 +580,7 @@ int main(int argc, const char *argv[]) + return 3; + } + +- DEBUG(SSSDBG_CRIT_FAILURE, ++ DEBUG(SSSDBG_IMPORTANT_INFO, + "Proxy child for domain [%s] started!\n", domain); + + /* loop on main */ +diff --git a/src/providers/proxy/proxy_client.c b/src/providers/proxy/proxy_client.c +index 09ebf3bda..5a4fbcde1 100644 +--- a/src/providers/proxy/proxy_client.c ++++ b/src/providers/proxy/proxy_client.c +@@ -116,7 +116,7 @@ proxy_client_init(struct sbus_connection *conn, + + ret = sbus_connection_add_path_map(conn, paths); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add paths [%d]: %s\n", ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to add paths [%d]: %s\n", + ret, sss_strerror(ret)); + } + +diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c +index 82394862c..f36386089 100644 +--- a/src/providers/proxy/proxy_id.c ++++ b/src/providers/proxy/proxy_id.c +@@ -170,7 +170,7 @@ handle_getpw_result(enum nss_status status, struct passwd *pwd, + switch (status) { + case NSS_STATUS_NOTFOUND: + +- DEBUG(SSSDBG_MINOR_FAILURE, "User not found.\n"); ++ DEBUG(SSSDBG_TRACE_FUNC, "User not found.\n"); + *del_user = true; + break; + +@@ -979,9 +979,7 @@ static int get_gr_name(struct proxy_id_ctx *ctx, + grp = talloc(tmpctx, struct group); + if (!grp) { + ret = ENOMEM; +- DEBUG(SSSDBG_CRIT_FAILURE, +- "proxy -> getgrnam_r failed for '%s': [%d] %s\n", +- i_name, ret, strerror(ret)); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc() failed\n"); + goto done; + } + +diff --git a/src/resolv/async_resolv.c b/src/resolv/async_resolv.c +index 07f05ff17..294a4b882 100644 +--- a/src/resolv/async_resolv.c ++++ b/src/resolv/async_resolv.c +@@ -177,7 +177,7 @@ add_timeout_timer(struct tevent_context *ev, struct resolv_ctx *ctx) + ctx->timeout_watcher = tevent_add_timer(ev, ctx, tv, check_fd_timeouts, + ctx); + if (ctx->timeout_watcher == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer() failed\n"); + } + } + +diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c +index a802ed5d0..27de1b44a 100644 +--- a/src/responder/autofs/autofssrv.c ++++ b/src/responder/autofs/autofssrv.c +@@ -85,7 +85,7 @@ autofs_register_service_iface(struct autofs_ctx *autofs_ctx, + + ret = sbus_connection_add_path(rctx->mon_conn, SSS_BUS_PATH, &iface_svc); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to register service interface" ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to register service interface" + "[%d]: %s\n", ret, sss_strerror(ret)); + } + +diff --git a/src/responder/autofs/autofssrv_cmd.c b/src/responder/autofs/autofssrv_cmd.c +index 6d51e75ac..7c8090993 100644 +--- a/src/responder/autofs/autofssrv_cmd.c ++++ b/src/responder/autofs/autofssrv_cmd.c +@@ -477,7 +477,7 @@ sss_autofs_cmd_setautomntent(struct cli_ctx *cli_ctx) + autofs_ctx->rctx->ncache, 0, NULL, + cmd_ctx->mapname); + if (req == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_autofs_map_by_name_send failed\n"); + ret = ENOMEM; + goto done; + } +@@ -685,7 +685,7 @@ sss_autofs_cmd_getautomntent(struct cli_ctx *cli_ctx) + + req = autofs_setent_send(cli_ctx, cli_ctx->ev, autofs_ctx, cmd_ctx->mapname); + if (req == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "autofs_setent_send failed\n"); + ret = ENOMEM; + goto done; + } +@@ -886,7 +886,7 @@ sss_autofs_cmd_getautomntbyname(struct cli_ctx *cli_ctx) + cmd_ctx->mapname, + cmd_ctx->keyname); + if (req == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_autofs_entry_by_name_send failed\n"); + ret = ENOMEM; + goto done; + } +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index 0c8538414..c6902f842 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -1187,7 +1187,7 @@ static errno_t cache_req_process_input(TALLOC_CTX *mem_ctx, + subreq = sss_parse_inp_send(mem_ctx, cr->rctx, default_domain, + cr->data->name.input); + if (subreq == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "sss_parse_inp_send() failed\n"); + return ENOMEM; + } + +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 a740fbb8d..83d00f775 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 +@@ -47,8 +47,8 @@ cache_req_object_by_name_well_known(TALLOC_CTX *mem_ctx, + } + + if (domname == NULL || name == NULL) { +- CACHE_REQ_DEBUG(SSSDBG_OP_FAILURE, cr, "Unable to split [%s] in " +- "name and odmain part. Skipping detection of " ++ CACHE_REQ_DEBUG(SSSDBG_FUNC_DATA, cr, "Unable to split [%s] in " ++ "name and domain part. Skipping detection of " + "well-known name.\n", data->name.input); + return ENOENT; + } +diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c +index e8d298546..7061d018a 100644 +--- a/src/responder/common/responder_common.c ++++ b/src/responder/common/responder_common.c +@@ -116,7 +116,7 @@ static errno_t get_client_cred(struct cli_ctx *cctx) + if (ret != EOK) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, +- "getsock failed [%d][%s].\n", ret, strerror(ret)); ++ "getsockopt failed [%d][%s].\n", ret, strerror(ret)); + return ret; + } + if (client_cred_len != sizeof(struct ucred)) { +@@ -805,7 +805,7 @@ sss_dp_on_reconnect(struct sbus_connection *conn, + SSS_BUS_PATH, + be_conn->cli_name); + if (req == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "sbus_call_dp_client_Register_send() failed\n"); + return; + } + +diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c +index 10939600d..e551b0fff 100644 +--- a/src/responder/common/responder_get_domains.c ++++ b/src/responder/common/responder_get_domains.c +@@ -630,7 +630,7 @@ static void sss_parse_inp_done(struct tevent_req *subreq) + state->rawinp, + &state->domname, &state->name); + if (ret == EAGAIN && state->domname != NULL && state->name == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, ++ DEBUG(SSSDBG_FUNC_DATA, + "Unknown domain in [%s]\n", state->rawinp); + state->error = ERR_DOMAIN_NOT_FOUND; + } else if (ret != EOK) { +diff --git a/src/responder/common/responder_iface.c b/src/responder/common/responder_iface.c +index 911cd6cc0..aaa765950 100644 +--- a/src/responder/common/responder_iface.c ++++ b/src/responder/common/responder_iface.c +@@ -127,7 +127,7 @@ sss_resp_register_sbus_iface(struct sbus_connection *conn, + + ret = sbus_connection_add_path_map(conn, paths); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add paths [%d]: %s\n", ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to add paths [%d]: %s\n", + ret, sss_strerror(ret)); + } + +@@ -151,7 +151,7 @@ sss_resp_register_service_iface(struct resp_ctx *rctx) + + ret = sbus_connection_add_path(rctx->mon_conn, SSS_BUS_PATH, &iface_svc); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to register service interface" ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to register service interface" + "[%d]: %s\n", ret, sss_strerror(ret)); + } + +diff --git a/src/responder/ifp/ifp_iface/ifp_iface.c b/src/responder/ifp/ifp_iface/ifp_iface.c +index a3385091b..833cf6843 100644 +--- a/src/responder/ifp/ifp_iface/ifp_iface.c ++++ b/src/responder/ifp/ifp_iface/ifp_iface.c +@@ -264,7 +264,7 @@ ifp_register_sbus_interface(struct sbus_connection *conn, + + ret = sbus_connection_add_path_map(conn, paths); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add paths [%d]: %s\n", ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to add paths [%d]: %s\n", + ret, sss_strerror(ret)); + } + +diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c +index 17d7692d3..7407ee07b 100644 +--- a/src/responder/ifp/ifpsrv.c ++++ b/src/responder/ifp/ifpsrv.c +@@ -67,7 +67,7 @@ sysbus_init(TALLOC_CTX *mem_ctx, + sysbus = sbus_connect_system(mem_ctx, ev, dbus_name, + &ifp_ctx->rctx->last_request_time); + if (sysbus == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to connect to system bus!\n"); ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to connect to system bus!\n"); + return ERR_NO_SYSBUS; + } + +@@ -75,13 +75,13 @@ sysbus_init(TALLOC_CTX *mem_ctx, + + ret = ifp_register_sbus_interface(sysbus, ifp_ctx); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not register interfaces\n"); ++ DEBUG(SSSDBG_FATAL_FAILURE, "Could not register interfaces\n"); + goto done; + } + + ret = ifp_register_nodes(ifp_ctx, sysbus); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not register nodes factories\n"); ++ DEBUG(SSSDBG_FATAL_FAILURE, "Could not register nodes factories\n"); + goto done; + } + +@@ -148,7 +148,7 @@ ifp_register_service_iface(struct ifp_ctx *ifp_ctx, + + ret = sbus_connection_add_path(rctx->mon_conn, SSS_BUS_PATH, &iface_svc); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to register service interface" ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to register service interface" + "[%d]: %s\n", ret, sss_strerror(ret)); + } + +diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c +index ebc4c2118..3b3df7bc0 100644 +--- a/src/responder/ifp/ifpsrv_util.c ++++ b/src/responder/ifp/ifpsrv_util.c +@@ -341,7 +341,7 @@ immediately: + list_ctx->paths = talloc_realloc(list_ctx, list_ctx->paths, const char *, + list_ctx->paths_max + 1); + if (list_ctx->paths == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_realloc() failed\n"); + ret = ENOMEM; + goto done; + } +diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c +index eac955b4a..844776c5f 100644 +--- a/src/responder/nss/nss_cmd.c ++++ b/src/responder/nss/nss_cmd.c +@@ -121,7 +121,7 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx, + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, + data, memcache, rawname, 0); + if (subreq == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "nss_get_object_send() failed\n"); + ret = ENOMEM; + goto done; + } +@@ -187,7 +187,7 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx, + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, + data, memcache, NULL, id); + if (subreq == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "nss_get_object_send() failed\n"); + ret = ENOMEM; + goto done; + } +@@ -240,7 +240,7 @@ static errno_t nss_getby_svc(struct cli_ctx *cli_ctx, + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, + data, SSS_MC_NONE, NULL, 0); + if (subreq == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "nss_get_object_send() failed\n"); + return ENOMEM; + } + +@@ -376,7 +376,7 @@ static errno_t nss_getby_cert(struct cli_ctx *cli_ctx, + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, + data, SSS_MC_NONE, NULL, 0); + if (subreq == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "nss_get_object_send() failed\n"); + ret = ENOMEM; + goto done; + } +@@ -433,7 +433,7 @@ static errno_t nss_getby_sid(struct cli_ctx *cli_ctx, + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, + data, SSS_MC_NONE, NULL, 0); + if (subreq == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "nss_get_object_send() failed\n"); + ret = ENOMEM; + goto done; + } +@@ -488,7 +488,7 @@ static errno_t nss_getby_addr(struct cli_ctx *cli_ctx, + subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx, + data, memcache, NULL, 0); + if (subreq == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "nss_get_object_send() failed\n"); + ret = ENOMEM; + goto done; + } +@@ -640,7 +640,7 @@ static errno_t nss_setent(struct cli_ctx *cli_ctx, + + subreq = nss_setent_send(cli_ctx, cli_ctx->ev, cli_ctx, type, enum_ctx); + if (subreq == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "nss_setent_send() failed\n"); + return ENOMEM; + } + +@@ -697,7 +697,7 @@ static errno_t nss_getent(struct cli_ctx *cli_ctx, + + subreq = nss_setent_send(cli_ctx, cli_ctx->ev, cli_ctx, type, enum_ctx); + if (subreq == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create setent request!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "nss_setent_send() failed\n"); + ret = ENOMEM; + goto done; + } +@@ -829,7 +829,7 @@ static errno_t sss_nss_setnetgrent(struct cli_ctx *cli_ctx, + subreq = nss_setnetgrent_send(cli_ctx, cli_ctx->ev, cli_ctx, type, + nss_ctx->netgrent, state_ctx->netgroup); + if (subreq == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "nss_setnetgrent_send() failed\n"); + ret = ENOMEM; + goto done; + } +@@ -904,7 +904,7 @@ static errno_t nss_getnetgrent(struct cli_ctx *cli_ctx, + cmd_ctx->nss_ctx->netgrent, + cmd_ctx->state_ctx->netgroup); + if (subreq == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "nss_setnetgrent_send() failed\n"); + return ENOMEM; + } + +diff --git a/src/responder/nss/nss_iface.c b/src/responder/nss/nss_iface.c +index a47b35fca..ab2ba926d 100644 +--- a/src/responder/nss/nss_iface.c ++++ b/src/responder/nss/nss_iface.c +@@ -67,7 +67,7 @@ nss_update_initgr_memcache(struct nss_ctx *nctx, + 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", ++ "sysdb_initgroups() failed [%d][%s]\n", + ret, strerror(ret)); + goto done; + } +@@ -234,7 +234,7 @@ nss_register_backend_iface(struct sbus_connection *conn, + + ret = sbus_connection_add_path(conn, SSS_BUS_PATH, &iface); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to register service interface" ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to register service interface" + "[%d]: %s\n", ret, sss_strerror(ret)); + } + +diff --git a/src/responder/nss/nss_protocol_netgr.c b/src/responder/nss/nss_protocol_netgr.c +index 1e9959c72..274d43007 100644 +--- a/src/responder/nss/nss_protocol_netgr.c ++++ b/src/responder/nss/nss_protocol_netgr.c +@@ -159,7 +159,7 @@ nss_protocol_fill_netgrent(struct nss_ctx *nss_ctx, + ret = nss_protocol_fill_netgr_member(packet, entry, &rp); + break; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected value type!\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected value type %d!\n", entry->type); + ret = ERR_INTERNAL; + break; + } +diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c +index 31a2750b1..e80104e3d 100644 +--- a/src/responder/nss/nsssrv.c ++++ b/src/responder/nss/nsssrv.c +@@ -347,7 +347,7 @@ nss_register_service_iface(struct nss_ctx *nss_ctx, + + ret = sbus_connection_add_path(rctx->mon_conn, SSS_BUS_PATH, &iface_svc); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to register service interface" ++ DEBUG(SSSDBG_FATAL_FAILURE, "Unable to register service interface" + "[%d]: %s\n", ret, sss_strerror(ret)); + } + +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index d3f092b2b..c526f665b 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -138,7 +138,7 @@ static void inform_user(struct pam_data* pd, const char *pam_message) + ret = pack_user_info_msg(pd, pam_message, &msg_len, &msg); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "pack_user_info_account_expired failed.\n"); ++ "pack_user_info_msg failed.\n"); + } else { + ret = pam_add_response(pd, SSS_PAM_USER_INFO, msg_len, msg); + if (ret != EOK) { +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index e1fd72e64..bf285c264 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -425,7 +425,7 @@ bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd) + } + } + if (pctx->smartcard_services[c] == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, ++ DEBUG(SSSDBG_CONF_SETTINGS, + "Smartcard authentication for service [%s] not supported.\n", + pd->service); + return false; +@@ -810,7 +810,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + } else if (pd->cmd == SSS_PAM_PREAUTH) { + extra_args[arg_c++] = "--pre"; + } else { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected PAM command [%d}.\n", pd->cmd); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected PAM command [%d].\n", pd->cmd); + ret = EINVAL; + goto done; + } +diff --git a/src/sbus/router/sbus_router_handler.c b/src/sbus/router/sbus_router_handler.c +index 91a84c51b..a92cf524b 100644 +--- a/src/sbus/router/sbus_router_handler.c ++++ b/src/sbus/router/sbus_router_handler.c +@@ -239,7 +239,8 @@ sbus_signal_handler(struct sbus_connection *conn, + list = sbus_router_listeners_lookup(router->listeners, meta->interface, + meta->member); + if (list == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "We do not listen to this signal!\n"); ++ /* Most probably not fully initialized yet */ ++ DEBUG(SSSDBG_FUNC_DATA, "We do not listen to this signal!\n"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + +diff --git a/src/sss_iface/sss_iface.c b/src/sss_iface/sss_iface.c +index e20c14fea..ed70e30eb 100644 +--- a/src/sss_iface/sss_iface.c ++++ b/src/sss_iface/sss_iface.c +@@ -116,8 +116,8 @@ sss_iface_connect_address(TALLOC_CTX *mem_ctx, + + conn = sbus_connect_private(mem_ctx, ev, address, + conn_name, last_request_time); +- if (conn == NULL) { +- return ENOMEM; ++ if (conn == NULL) { /* most probably sbus_dbus_connect_address() failed */ ++ return EFAULT; + } + + *_conn = conn; +diff --git a/src/util/child_common.c b/src/util/child_common.c +index 5cac725ca..7e8c30552 100644 +--- a/src/util/child_common.c ++++ b/src/util/child_common.c +@@ -768,7 +768,7 @@ void exec_child_ex(TALLOC_CTX *mem_ctx, + binary, extra_argv, extra_args_only, + &argv); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "prepare_child_argv.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "prepare_child_argv() failed.\n"); + exit(EXIT_FAILURE); + } + +diff --git a/src/util/debug.h b/src/util/debug.h +index 20db0f5e4..43d36720f 100644 +--- a/src/util/debug.h ++++ b/src/util/debug.h +@@ -91,8 +91,8 @@ int get_fd_from_debug_file(void); + /* enables all debug levels; + 0x0800 isn't used for historical reasons: 0x1FFF0 - 0x0800 = 0x1F7F0 + */ +-#define SSSDBG_MASK_ALL 0x1F7F0 +-#define SSSDBG_DEFAULT SSSDBG_FATAL_FAILURE ++#define SSSDBG_MASK_ALL 0x1F7F0 ++#define SSSDBG_DEFAULT (SSSDBG_FATAL_FAILURE|SSSDBG_CRIT_FAILURE|SSSDBG_OP_FAILURE) + + #define SSSDBG_TIMESTAMP_UNRESOLVED -1 + #define SSSDBG_TIMESTAMP_DEFAULT 1 +diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c +index 4d4726daa..57157861e 100644 +--- a/src/util/domain_info_utils.c ++++ b/src/util/domain_info_utils.c +@@ -207,7 +207,7 @@ find_domain_by_object_name_ex(struct sss_domain_info *domain, + ret = sss_parse_internal_fqname(tmp_ctx, object_name, + NULL, &domainname); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse name '%s' [%d]: %s\n", ++ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to parse name '%s' [%d]: %s\n", + object_name, ret, sss_strerror(ret)); + goto done; + } +diff --git a/src/util/server.c b/src/util/server.c +index b27cbc155..869ed62a6 100644 +--- a/src/util/server.c ++++ b/src/util/server.c +@@ -374,7 +374,7 @@ static void te_server_hup(struct tevent_context *ev, + struct logrotate_ctx *lctx = + talloc_get_type(private_data, struct logrotate_ctx); + +- DEBUG(SSSDBG_CRIT_FAILURE, "Received SIGHUP. Rotating logfiles.\n"); ++ DEBUG(SSSDBG_IMPORTANT_INFO, "Received SIGHUP. Rotating logfiles.\n"); + + ret = server_common_rotate_logs(lctx->confdb, lctx->confdb_path); + if (ret != EOK) { +@@ -462,6 +462,7 @@ int server_setup(const char *name, int flags, + int watchdog_interval; + pid_t my_pid; + char *pidfile_name; ++ int cfg_debug_level = SSSDBG_INVALID; + + my_pid = getpid(); + ret = setpgid(my_pid, my_pid); +@@ -588,20 +589,20 @@ int server_setup(const char *name, int flags, + /* set debug level if any in conf_entry */ + ret = confdb_get_int(ctx->confdb_ctx, conf_entry, + CONFDB_SERVICE_DEBUG_LEVEL, +- SSSDBG_UNRESOLVED, +- &debug_level); ++ SSSDBG_INVALID, ++ &cfg_debug_level); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) " + "[%s]\n", ret, strerror(ret)); + return ret; + } + +- if (debug_level == SSSDBG_UNRESOLVED) { ++ if (cfg_debug_level == SSSDBG_INVALID) { + /* Check for the `debug` alias */ + ret = confdb_get_int(ctx->confdb_ctx, conf_entry, + CONFDB_SERVICE_DEBUG_LEVEL_ALIAS, + SSSDBG_DEFAULT, +- &debug_level); ++ &cfg_debug_level); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) " + "[%s]\n", ret, strerror(ret)); +@@ -609,7 +610,7 @@ int server_setup(const char *name, int flags, + } + } + +- debug_level = debug_convert_old_level(debug_level); ++ debug_level = debug_convert_old_level(cfg_debug_level); + } + + /* same for debug timestamps */ +@@ -678,6 +679,8 @@ int server_setup(const char *name, int flags, + return ret; + } + } ++ DEBUG(SSSDBG_IMPORTANT_INFO, ++ "Starting with debug level = %#.4x\n", debug_level); + + /* Setup the internal watchdog */ + ret = confdb_get_int(ctx->confdb_ctx, conf_entry, +diff --git a/src/util/sss_sockets.c b/src/util/sss_sockets.c +index c6504ae13..8944e2c4e 100644 +--- a/src/util/sss_sockets.c ++++ b/src/util/sss_sockets.c +@@ -322,7 +322,7 @@ struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx, + + ret = set_fcntl_flags(state->sd, FD_CLOEXEC, O_NONBLOCK); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "settting fd flags failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "setting fd flags failed.\n"); + goto fail; + } + +diff --git a/src/util/string_utils.c b/src/util/string_utils.c +index 1215ec96a..f54395a59 100644 +--- a/src/util/string_utils.c ++++ b/src/util/string_utils.c +@@ -90,7 +90,7 @@ errno_t guid_blob_to_string_buf(const uint8_t *blob, char *str_buf, + int ret; + + if (blob == NULL || str_buf == NULL || buf_size < GUID_STR_BUF_SIZE) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Buffer too small.\n"); ++ DEBUG(SSSDBG_OP_FAILURE, "Buffer too small.\n"); + return EINVAL; + } + +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index 05a66d293..b5c7419a9 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -165,6 +165,7 @@ errno_t sss_ldb_error_to_errno(int ldberr) + case LDB_ERR_OPERATIONS_ERROR: + return EIO; + case LDB_ERR_NO_SUCH_OBJECT: ++ case LDB_ERR_NO_SUCH_ATTRIBUTE: + return ENOENT; + case LDB_ERR_BUSY: + return EBUSY; +@@ -174,7 +175,7 @@ errno_t sss_ldb_error_to_errno(int ldberr) + case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX: + return EINVAL; + default: +- DEBUG(SSSDBG_CRIT_FAILURE, ++ DEBUG(SSSDBG_MINOR_FAILURE, + "LDB returned unexpected error: [%i]\n", + ldberr); + return EFAULT; +-- +2.21.3 + diff --git a/SOURCES/0020-sss_format.h-include-config.h.patch b/SOURCES/0020-sss_format.h-include-config.h.patch new file mode 100644 index 0000000..e237096 --- /dev/null +++ b/SOURCES/0020-sss_format.h-include-config.h.patch @@ -0,0 +1,31 @@ +From 45f2eb57dc9068cba13099cab90f1be3f3455442 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 2 Oct 2020 14:04:24 +0200 +Subject: [PATCH 20/27] sss_format.h: include config.h + +config.h is required for the definitions to work correctly. Compilation +will fail if sss_format.h is included in a file that does not include +directly or indirectly config.h + +Reviewed-by: Robbie Harwood +Reviewed-by: Sumit Bose +--- + src/util/sss_format.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/util/sss_format.h b/src/util/sss_format.h +index 5cf080842..9a3041704 100644 +--- a/src/util/sss_format.h ++++ b/src/util/sss_format.h +@@ -27,6 +27,8 @@ + #ifndef __SSS_FORMAT_H__ + #define __SSS_FORMAT_H__ + ++#include "config.h" ++ + #include + + /* key_serial_t is defined in keyutils.h as typedef int32_t */ +-- +2.21.3 + diff --git a/SOURCES/0021-packet-add-sss_packet_set_body.patch b/SOURCES/0021-packet-add-sss_packet_set_body.patch new file mode 100644 index 0000000..5311316 --- /dev/null +++ b/SOURCES/0021-packet-add-sss_packet_set_body.patch @@ -0,0 +1,59 @@ +From 3b0e48c33c6b43688ff46fed576266cfe6362595 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 8 Oct 2020 13:25:17 +0200 +Subject: [PATCH 21/27] packet: add sss_packet_set_body + +Reviewed-by: Robbie Harwood +Reviewed-by: Sumit Bose +--- + src/responder/common/responder_packet.c | 19 +++++++++++++++++++ + src/responder/common/responder_packet.h | 5 +++++ + 2 files changed, 24 insertions(+) + +diff --git a/src/responder/common/responder_packet.c b/src/responder/common/responder_packet.c +index ab15b1dac..f56d92276 100644 +--- a/src/responder/common/responder_packet.c ++++ b/src/responder/common/responder_packet.c +@@ -302,6 +302,25 @@ void sss_packet_get_body(struct sss_packet *packet, uint8_t **body, size_t *blen + *blen = sss_packet_get_len(packet) - SSS_NSS_HEADER_SIZE; + } + ++errno_t sss_packet_set_body(struct sss_packet *packet, ++ uint8_t *body, ++ size_t blen) ++{ ++ uint8_t *pbody; ++ size_t plen; ++ errno_t ret; ++ ++ ret = sss_packet_grow(packet, blen); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ sss_packet_get_body(packet, &pbody, &plen); ++ memcpy(pbody, body, blen); ++ ++ return EOK; ++} ++ + void sss_packet_set_error(struct sss_packet *packet, int error) + { + SAFEALIGN_SETMEM_UINT32(packet->buffer + SSS_PACKET_ERR_OFFSET, error, +diff --git a/src/responder/common/responder_packet.h b/src/responder/common/responder_packet.h +index afceb4aae..509a22a9a 100644 +--- a/src/responder/common/responder_packet.h ++++ b/src/responder/common/responder_packet.h +@@ -42,4 +42,9 @@ uint32_t sss_packet_get_status(struct sss_packet *packet); + void sss_packet_get_body(struct sss_packet *packet, uint8_t **body, size_t *blen); + void sss_packet_set_error(struct sss_packet *packet, int error); + ++/* Grow packet and set its body. */ ++errno_t sss_packet_set_body(struct sss_packet *packet, ++ uint8_t *body, ++ size_t blen); ++ + #endif /* __SSSSRV_PACKET_H__ */ +-- +2.21.3 + diff --git a/SOURCES/0022-domain-store-hostname-and-keytab-path.patch b/SOURCES/0022-domain-store-hostname-and-keytab-path.patch new file mode 100644 index 0000000..27628e6 --- /dev/null +++ b/SOURCES/0022-domain-store-hostname-and-keytab-path.patch @@ -0,0 +1,119 @@ +From 6715b31f2e12c7f76cfb477551cee46e697c7d51 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 8 Oct 2020 13:25:58 +0200 +Subject: [PATCH 22/27] domain: store hostname and keytab path + +Reviewed-by: Robbie Harwood +Reviewed-by: Sumit Bose +--- + src/confdb/confdb.c | 45 +++++++++++++++++++++++++++++++++++++++ + src/confdb/confdb.h | 6 ++++++ + src/db/sysdb_subdomains.c | 12 +++++++++++ + 3 files changed, 63 insertions(+) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index d2fc018fd..f981ddf1e 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -871,6 +871,35 @@ done: + return ret; + } + ++static char *confdb_get_domain_hostname(TALLOC_CTX *mem_ctx, ++ struct ldb_result *res, ++ const char *provider) ++{ ++ char sys[HOST_NAME_MAX + 1] = {'\0'}; ++ const char *opt = NULL; ++ int ret; ++ ++ if (strcasecmp(provider, "ad") == 0) { ++ opt = ldb_msg_find_attr_as_string(res->msgs[0], "ad_hostname", NULL); ++ } else if (strcasecmp(provider, "ipa") == 0) { ++ opt = ldb_msg_find_attr_as_string(res->msgs[0], "ipa_hostname", NULL); ++ } ++ ++ if (opt != NULL) { ++ return talloc_strdup(mem_ctx, opt); ++ } ++ ++ ret = gethostname(sys, sizeof(sys)); ++ if (ret != 0) { ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get hostname [%d]: %s\n", ret, ++ sss_strerror(ret)); ++ return NULL; ++ } ++ ++ return talloc_strdup(mem_ctx, sys); ++} ++ + static int confdb_get_domain_internal(struct confdb_ctx *cdb, + TALLOC_CTX *mem_ctx, + const char *name, +@@ -1536,6 +1565,22 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, + goto done; + } + ++ domain->hostname = confdb_get_domain_hostname(domain, res, domain->provider); ++ if (domain->hostname == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get domain hostname\n"); ++ goto done; ++ } ++ ++ domain->krb5_keytab = NULL; ++ tmp = ldb_msg_find_attr_as_string(res->msgs[0], "krb5_keytab", NULL); ++ if (tmp != NULL) { ++ domain->krb5_keytab = talloc_strdup(domain, tmp); ++ if (domain->krb5_keytab == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get domain keytab!\n"); ++ goto done; ++ } ++ } ++ + domain->has_views = false; + domain->view_name = NULL; + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index fd6d76cde..54e3f7380 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -425,6 +425,12 @@ struct sss_domain_info { + /* Do not use the _output_fqnames property directly in new code, but rather + * use sss_domain_info_{get,set}_output_fqnames(). */ + bool output_fqnames; ++ ++ /* Hostname associated with this domain. */ ++ const char *hostname; ++ ++ /* Keytab used by this domain. */ ++ const char *krb5_keytab; + }; + + /** +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index d256817a6..5b42f9bdc 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -125,6 +125,18 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, + } + } + ++ dom->hostname = talloc_strdup(dom, parent->hostname); ++ if (dom->hostname == NULL && parent->hostname != NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to copy hostname.\n"); ++ goto fail; ++ } ++ ++ dom->krb5_keytab = talloc_strdup(dom, parent->krb5_keytab); ++ if (dom->krb5_keytab == NULL && parent->krb5_keytab != NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to copy krb5_keytab.\n"); ++ goto fail; ++ } ++ + dom->enumerate = enumerate; + dom->fqnames = true; + dom->mpg_mode = mpg_mode; +-- +2.21.3 + diff --git a/SOURCES/0023-cache_req-add-helper-to-call-user-by-upn-search.patch b/SOURCES/0023-cache_req-add-helper-to-call-user-by-upn-search.patch new file mode 100644 index 0000000..168f8b6 --- /dev/null +++ b/SOURCES/0023-cache_req-add-helper-to-call-user-by-upn-search.patch @@ -0,0 +1,70 @@ +From a3e2677f919c6b1b1649ad80cc3435b4bb2efc0d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 10 Dec 2020 19:28:58 +0100 +Subject: [PATCH 23/27] cache_req: add helper to call user by upn search + +Reviewed-by: Robbie Harwood +Reviewed-by: Sumit Bose +--- + src/responder/common/cache_req/cache_req.h | 13 +++++++++++ + .../cache_req/plugins/cache_req_user_by_upn.c | 23 +++++++++++++++++++ + 2 files changed, 36 insertions(+) + +diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h +index d36cb2d3b..d301a076e 100644 +--- a/src/responder/common/cache_req/cache_req.h ++++ b/src/responder/common/cache_req/cache_req.h +@@ -277,6 +277,19 @@ cache_req_user_by_name_attrs_send(TALLOC_CTX *mem_ctx, + #define cache_req_user_by_name_attrs_recv(mem_ctx, req, _result) \ + cache_req_single_domain_recv(mem_ctx, req, _result) + ++struct tevent_req * ++cache_req_user_by_upn_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ 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 *upn); ++ ++#define cache_req_user_by_upn_recv(mem_ctx, req, _result) \ ++ cache_req_single_domain_recv(mem_ctx, req, _result); ++ + struct tevent_req * + cache_req_user_by_id_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +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 e08ab70ae..037994c8c 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 +@@ -133,3 +133,26 @@ const struct cache_req_plugin cache_req_user_by_upn = { + .dp_get_domain_send_fn = NULL, + .dp_get_domain_recv_fn = NULL, + }; ++ ++struct tevent_req * ++cache_req_user_by_upn_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ 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 *upn) ++{ ++ struct cache_req_data *data; ++ ++ data = cache_req_data_name(mem_ctx, CACHE_REQ_USER_BY_UPN, upn); ++ if (data == NULL) { ++ return NULL; ++ } ++ ++ return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, ++ cache_refresh_percent, ++ req_dom_type, domain, ++ data); ++} +-- +2.21.3 + diff --git a/SOURCES/0024-pam-fix-typo-in-debug-message.patch b/SOURCES/0024-pam-fix-typo-in-debug-message.patch new file mode 100644 index 0000000..25167e1 --- /dev/null +++ b/SOURCES/0024-pam-fix-typo-in-debug-message.patch @@ -0,0 +1,27 @@ +From dcc42015f7ada1c4e4daed17e2c8087e29cb7616 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 1 Oct 2020 14:02:44 +0200 +Subject: [PATCH 24/27] pam: fix typo in debug message + +Reviewed-by: Robbie Harwood +Reviewed-by: Sumit Bose +--- + src/responder/pam/pamsrv_cmd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index 1d0251497..acbfc0c39 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1941,7 +1941,7 @@ static void pam_check_user_search_next(struct tevent_req *req) + talloc_zfree(req); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, "Cache lookup failed, trying to get fresh " +- "data from the backened.\n"); ++ "data from the backend.\n"); + } + + DEBUG(SSSDBG_TRACE_ALL, "PAM initgroups scheme [%s].\n", +-- +2.21.3 + diff --git a/SOURCES/0025-pam-add-pam_gssapi_services-option.patch b/SOURCES/0025-pam-add-pam_gssapi_services-option.patch new file mode 100644 index 0000000..7c90067 --- /dev/null +++ b/SOURCES/0025-pam-add-pam_gssapi_services-option.patch @@ -0,0 +1,280 @@ +From d63172f1277c5ed166a22f04d144bf85ded4757c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 9 Oct 2020 13:03:54 +0200 +Subject: [PATCH 25/27] pam: add pam_gssapi_services option + +:config: Added `pam_gssapi_services` to list PAM services + that can authenticate using GSSAPI + +Reviewed-by: Robbie Harwood +Reviewed-by: Sumit Bose +--- + src/confdb/confdb.c | 12 +++++++++++ + src/confdb/confdb.h | 4 ++++ + src/config/SSSDConfig/sssdoptions.py | 1 + + src/config/SSSDConfigTest.py | 6 ++++-- + src/config/cfg_rules.ini | 3 +++ + src/config/etc/sssd.api.conf | 2 ++ + src/db/sysdb_subdomains.c | 13 ++++++++++++ + src/man/sssd.conf.5.xml | 30 ++++++++++++++++++++++++++++ + src/responder/pam/pamsrv.c | 21 +++++++++++++++++++ + src/responder/pam/pamsrv.h | 3 +++ + 10 files changed, 93 insertions(+), 2 deletions(-) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index f981ddf1e..7f1956d6d 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -1581,6 +1581,18 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, + } + } + ++ tmp = ldb_msg_find_attr_as_string(res->msgs[0], CONFDB_PAM_GSSAPI_SERVICES, ++ "-"); ++ if (tmp != NULL) { ++ ret = split_on_separator(domain, tmp, ',', true, true, ++ &domain->gssapi_services, NULL); ++ if (ret != 0) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Cannot parse %s\n", CONFDB_PAM_GSSAPI_SERVICES); ++ goto done; ++ } ++ } ++ + domain->has_views = false; + domain->view_name = NULL; + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 54e3f7380..7a3bc8bb5 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -144,6 +144,7 @@ + #define CONFDB_PAM_P11_ALLOWED_SERVICES "pam_p11_allowed_services" + #define CONFDB_PAM_P11_URI "p11_uri" + #define CONFDB_PAM_INITGROUPS_SCHEME "pam_initgroups_scheme" ++#define CONFDB_PAM_GSSAPI_SERVICES "pam_gssapi_services" + + /* SUDO */ + #define CONFDB_SUDO_CONF_ENTRY "config/sudo" +@@ -431,6 +432,9 @@ struct sss_domain_info { + + /* Keytab used by this domain. */ + const char *krb5_keytab; ++ ++ /* List of PAM services that are allowed to authenticate with GSSAPI. */ ++ char **gssapi_services; + }; + + /** +diff --git a/src/config/SSSDConfig/sssdoptions.py b/src/config/SSSDConfig/sssdoptions.py +index de96db6f4..f59fe8d9f 100644 +--- a/src/config/SSSDConfig/sssdoptions.py ++++ b/src/config/SSSDConfig/sssdoptions.py +@@ -104,6 +104,7 @@ class SSSDOptions(object): + 'p11_wait_for_card_timeout': _('Additional timeout to wait for a card if requested'), + 'p11_uri': _('PKCS#11 URI to restrict the selection of devices for Smartcard authentication'), + 'pam_initgroups_scheme' : _('When shall the PAM responder force an initgroups request'), ++ 'pam_gssapi_services' : _('List of PAM services that are allowed to authenticate with GSSAPI.'), + + # [sudo] + 'sudo_timed': _('Whether to evaluate the time-based attributes in sudo rules'), +diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py +index 323be5ed3..21fffe1b6 100755 +--- a/src/config/SSSDConfigTest.py ++++ b/src/config/SSSDConfigTest.py +@@ -653,7 +653,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 'full_name_format', + 're_expression', + 'cached_auth_timeout', +- 'auto_private_groups'] ++ 'auto_private_groups', ++ 'pam_gssapi_services'] + + self.assertTrue(type(options) == dict, + "Options should be a dictionary") +@@ -1030,7 +1031,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 'full_name_format', + 're_expression', + 'cached_auth_timeout', +- 'auto_private_groups'] ++ 'auto_private_groups', ++ 'pam_gssapi_services'] + + 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 773afd8bb..c6dfd5648 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -139,6 +139,7 @@ option = pam_p11_allowed_services + option = p11_wait_for_card_timeout + option = p11_uri + option = pam_initgroups_scheme ++option = pam_gssapi_services + + [rule/allowed_sudo_options] + validator = ini_allowed_options +@@ -437,6 +438,7 @@ option = wildcard_limit + option = full_name_format + option = re_expression + option = auto_private_groups ++option = pam_gssapi_services + + #Entry cache timeouts + option = entry_cache_user_timeout +@@ -831,6 +833,7 @@ option = ad_backup_server + option = ad_site + option = use_fully_qualified_names + option = auto_private_groups ++option = pam_gssapi_services + + [rule/sssd_checks] + validator = sssd_checks +diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf +index 623160ffd..f46f3c46d 100644 +--- a/src/config/etc/sssd.api.conf ++++ b/src/config/etc/sssd.api.conf +@@ -80,6 +80,7 @@ pam_p11_allowed_services = str, None, false + p11_wait_for_card_timeout = int, None, false + p11_uri = str, None, false + pam_initgroups_scheme = str, None, false ++pam_gssapi_services = str, None, false + + [sudo] + # sudo service +@@ -199,6 +200,7 @@ cached_auth_timeout = int, None, false + full_name_format = str, None, false + re_expression = str, None, false + auto_private_groups = str, None, false ++pam_gssapi_services = str, None, false + + #Entry cache timeouts + entry_cache_user_timeout = int, None, false +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index 5b42f9bdc..bfc6df0f5 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -184,6 +184,8 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, + dom->homedir_substr = parent->homedir_substr; + dom->override_gid = parent->override_gid; + ++ dom->gssapi_services = parent->gssapi_services; ++ + if (parent->sysdb == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Missing sysdb context in parent domain.\n"); + goto fail; +@@ -241,6 +243,17 @@ check_subdom_config_file(struct confdb_ctx *confdb, + sd_conf_path, CONFDB_DOMAIN_FQ, + subdomain->fqnames ? "TRUE" : "FALSE"); + ++ /* allow to set pam_gssapi_services */ ++ ret = confdb_get_string_as_list(confdb, subdomain, sd_conf_path, ++ CONFDB_PAM_GSSAPI_SERVICES, ++ &subdomain->gssapi_services); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to get %s option for the subdomain: %s\n", ++ CONFDB_PAM_GSSAPI_SERVICES, subdomain->name); ++ goto done; ++ } ++ + ret = EOK; + done: + talloc_free(tmp_ctx); +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index d247400bf..db9dd4677 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -1706,6 +1706,35 @@ p11_uri = library-description=OpenSC%20smartcard%20framework;slot-id=2 + + + ++ ++ pam_gssapi_services ++ ++ ++ Comma separated list of PAM services that are ++ allowed to try GSSAPI authentication using ++ pam_sss_gss.so module. ++ ++ ++ To disable GSSAPI authentication, set this option ++ to - (dash). ++ ++ ++ Note: This option can also be set per-domain which ++ overwrites the value in [pam] section. It can also ++ be set for trusted domain which overwrites the value ++ in the domain section. ++ ++ ++ Example: ++ ++pam_gssapi_services = sudo, sudo-i ++ ++ ++ ++ Default: - (GSSAPI authentication is disabled) ++ ++ ++ + + + +@@ -3780,6 +3809,7 @@ ldap_user_extra_attrs = phone:telephoneNumber + ad_backup_server, + ad_site, + use_fully_qualified_names ++ pam_gssapi_services + + For more details about these options see their individual description + in the manual page. +diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c +index 1f1ee608b..0492569c7 100644 +--- a/src/responder/pam/pamsrv.c ++++ b/src/responder/pam/pamsrv.c +@@ -327,6 +327,27 @@ static int pam_process_init(TALLOC_CTX *mem_ctx, + } + } + ++ ret = confdb_get_string(pctx->rctx->cdb, pctx, CONFDB_PAM_CONF_ENTRY, ++ CONFDB_PAM_GSSAPI_SERVICES, "-", &tmpstr); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to determine gssapi services.\n"); ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Found value [%s] for option [%s].\n", tmpstr, ++ CONFDB_PAM_GSSAPI_SERVICES); ++ ++ if (tmpstr != NULL) { ++ ret = split_on_separator(pctx, tmpstr, ',', true, true, ++ &pctx->gssapi_services, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "split_on_separator() failed [%d]: [%s].\n", ret, ++ sss_strerror(ret)); ++ goto done; ++ } ++ } ++ + /* The responder is initialized. Now tell it to the monitor. */ + ret = sss_monitor_service_init(rctx, rctx->ev, SSS_BUS_PAM, + SSS_PAM_SBUS_SERVICE_NAME, +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index 24d307a14..730dee288 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -62,6 +62,9 @@ struct pam_ctx { + int num_prompting_config_sections; + + enum pam_initgroups_scheme initgroups_scheme; ++ ++ /* List of PAM services that are allowed to authenticate with GSSAPI. */ ++ char **gssapi_services; + }; + + struct pam_auth_req { +-- +2.21.3 + diff --git a/SOURCES/0026-pam-add-pam_gssapi_check_upn-option.patch b/SOURCES/0026-pam-add-pam_gssapi_check_upn-option.patch new file mode 100644 index 0000000..6e59705 --- /dev/null +++ b/SOURCES/0026-pam-add-pam_gssapi_check_upn-option.patch @@ -0,0 +1,250 @@ +From fffe3169bb490c4b010b168c639aa6f9b2ec0c52 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 10 Dec 2020 22:05:30 +0100 +Subject: [PATCH 26/27] pam: add pam_gssapi_check_upn option + +:config: Added `pam_gssapi_check_upn` to enforce authentication + only with principal that can be associated with target user. + +Reviewed-by: Robbie Harwood +Reviewed-by: Sumit Bose +--- + src/confdb/confdb.c | 10 ++++++++++ + src/confdb/confdb.h | 2 ++ + src/config/SSSDConfig/sssdoptions.py | 1 + + src/config/SSSDConfigTest.py | 6 ++++-- + src/config/cfg_rules.ini | 3 +++ + src/config/etc/sssd.api.conf | 2 ++ + src/db/sysdb_subdomains.c | 12 ++++++++++++ + src/man/sssd.conf.5.xml | 26 ++++++++++++++++++++++++++ + src/responder/pam/pamsrv.c | 9 +++++++++ + src/responder/pam/pamsrv.h | 1 + + 10 files changed, 70 insertions(+), 2 deletions(-) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index 7f1956d6d..2881ce5da 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -1593,6 +1593,16 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, + } + } + ++ tmp = ldb_msg_find_attr_as_string(res->msgs[0], CONFDB_PAM_GSSAPI_CHECK_UPN, ++ NULL); ++ if (tmp != NULL) { ++ domain->gssapi_check_upn = talloc_strdup(domain, tmp); ++ if (domain->gssapi_check_upn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ + domain->has_views = false; + domain->view_name = NULL; + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 7a3bc8bb5..036f9ecad 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -145,6 +145,7 @@ + #define CONFDB_PAM_P11_URI "p11_uri" + #define CONFDB_PAM_INITGROUPS_SCHEME "pam_initgroups_scheme" + #define CONFDB_PAM_GSSAPI_SERVICES "pam_gssapi_services" ++#define CONFDB_PAM_GSSAPI_CHECK_UPN "pam_gssapi_check_upn" + + /* SUDO */ + #define CONFDB_SUDO_CONF_ENTRY "config/sudo" +@@ -435,6 +436,7 @@ struct sss_domain_info { + + /* List of PAM services that are allowed to authenticate with GSSAPI. */ + char **gssapi_services; ++ char *gssapi_check_upn; /* true | false | NULL */ + }; + + /** +diff --git a/src/config/SSSDConfig/sssdoptions.py b/src/config/SSSDConfig/sssdoptions.py +index f59fe8d9f..5da52a937 100644 +--- a/src/config/SSSDConfig/sssdoptions.py ++++ b/src/config/SSSDConfig/sssdoptions.py +@@ -105,6 +105,7 @@ class SSSDOptions(object): + 'p11_uri': _('PKCS#11 URI to restrict the selection of devices for Smartcard authentication'), + 'pam_initgroups_scheme' : _('When shall the PAM responder force an initgroups request'), + 'pam_gssapi_services' : _('List of PAM services that are allowed to authenticate with GSSAPI.'), ++ 'pam_gssapi_check_upn' : _('Whether to match authenticated UPN with target user'), + + # [sudo] + 'sudo_timed': _('Whether to evaluate the time-based attributes in sudo rules'), +diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py +index 21fffe1b6..ea4e4f6c9 100755 +--- a/src/config/SSSDConfigTest.py ++++ b/src/config/SSSDConfigTest.py +@@ -654,7 +654,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 're_expression', + 'cached_auth_timeout', + 'auto_private_groups', +- 'pam_gssapi_services'] ++ 'pam_gssapi_services', ++ 'pam_gssapi_check_upn'] + + self.assertTrue(type(options) == dict, + "Options should be a dictionary") +@@ -1032,7 +1033,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 're_expression', + 'cached_auth_timeout', + 'auto_private_groups', +- 'pam_gssapi_services'] ++ 'pam_gssapi_services', ++ 'pam_gssapi_check_upn'] + + 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 c6dfd5648..6642c6321 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -140,6 +140,7 @@ option = p11_wait_for_card_timeout + option = p11_uri + option = pam_initgroups_scheme + option = pam_gssapi_services ++option = pam_gssapi_check_upn + + [rule/allowed_sudo_options] + validator = ini_allowed_options +@@ -439,6 +440,7 @@ option = full_name_format + option = re_expression + option = auto_private_groups + option = pam_gssapi_services ++option = pam_gssapi_check_upn + + #Entry cache timeouts + option = entry_cache_user_timeout +@@ -834,6 +836,7 @@ option = ad_site + option = use_fully_qualified_names + option = auto_private_groups + option = pam_gssapi_services ++option = pam_gssapi_check_upn + + [rule/sssd_checks] + validator = sssd_checks +diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf +index f46f3c46d..d3cad7380 100644 +--- a/src/config/etc/sssd.api.conf ++++ b/src/config/etc/sssd.api.conf +@@ -81,6 +81,7 @@ p11_wait_for_card_timeout = int, None, false + p11_uri = str, None, false + pam_initgroups_scheme = str, None, false + pam_gssapi_services = str, None, false ++pam_gssapi_check_upn = bool, None, false + + [sudo] + # sudo service +@@ -201,6 +202,7 @@ full_name_format = str, None, false + re_expression = str, None, false + auto_private_groups = str, None, false + pam_gssapi_services = str, None, false ++pam_gssapi_check_upn = bool, None, false + + #Entry cache timeouts + entry_cache_user_timeout = int, None, false +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index bfc6df0f5..03ba12164 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -254,6 +254,18 @@ check_subdom_config_file(struct confdb_ctx *confdb, + goto done; + } + ++ /* allow to set pam_gssapi_check_upn */ ++ ret = confdb_get_string(confdb, subdomain, sd_conf_path, ++ CONFDB_PAM_GSSAPI_CHECK_UPN, ++ subdomain->parent->gssapi_check_upn, ++ &subdomain->gssapi_check_upn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to get %s option for the subdomain: %s\n", ++ CONFDB_PAM_GSSAPI_CHECK_UPN, subdomain->name); ++ goto done; ++ } ++ + ret = EOK; + done: + talloc_free(tmp_ctx); +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index db9dd4677..d637e2eaa 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -1735,6 +1735,31 @@ pam_gssapi_services = sudo, sudo-i + + + ++ ++ pam_gssapi_check_upn ++ ++ ++ If True, SSSD will require that the Kerberos user ++ principal that successfully authenticated through ++ GSSAPI can be associated with the user who is being ++ authenticated. Authentication will fail if the check ++ fails. ++ ++ ++ If False, every user that is able to obtained ++ required service ticket will be authenticated. ++ ++ ++ Note: This option can also be set per-domain which ++ overwrites the value in [pam] section. It can also ++ be set for trusted domain which overwrites the value ++ in the domain section. ++ ++ ++ Default: True ++ ++ ++ + + + +@@ -3810,6 +3835,7 @@ ldap_user_extra_attrs = phone:telephoneNumber + ad_site, + use_fully_qualified_names + pam_gssapi_services ++ pam_gssapi_check_upn + + For more details about these options see their individual description + in the manual page. +diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c +index 0492569c7..0db2824ff 100644 +--- a/src/responder/pam/pamsrv.c ++++ b/src/responder/pam/pamsrv.c +@@ -348,6 +348,15 @@ static int pam_process_init(TALLOC_CTX *mem_ctx, + } + } + ++ ret = confdb_get_bool(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY, ++ CONFDB_PAM_GSSAPI_CHECK_UPN, true, ++ &pctx->gssapi_check_upn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to read %s [%d]: %s\n", ++ CONFDB_PAM_GSSAPI_CHECK_UPN, ret, sss_strerror(ret)); ++ goto done; ++ } ++ + /* The responder is initialized. Now tell it to the monitor. */ + ret = sss_monitor_service_init(rctx, rctx->ev, SSS_BUS_PAM, + SSS_PAM_SBUS_SERVICE_NAME, +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index 730dee288..bf4dd75b0 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -65,6 +65,7 @@ struct pam_ctx { + + /* List of PAM services that are allowed to authenticate with GSSAPI. */ + char **gssapi_services; ++ bool gssapi_check_upn; + }; + + struct pam_auth_req { +-- +2.21.3 + diff --git a/SOURCES/0027-pam-add-pam_sss_gss-module-for-gssapi-authentication.patch b/SOURCES/0027-pam-add-pam_sss_gss-module-for-gssapi-authentication.patch new file mode 100644 index 0000000..baa7927 --- /dev/null +++ b/SOURCES/0027-pam-add-pam_sss_gss-module-for-gssapi-authentication.patch @@ -0,0 +1,1866 @@ +From d09aa174b04a825979f31c61b05239de088a732f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 7 Jul 2020 11:05:37 +0200 +Subject: [PATCH 27/27] pam: add pam_sss_gss module for gssapi authentication + +:feature: New PAM module `pam_sss_gss` for authentication using GSSAPI +:packaging: Added `pam_sss_gss.so` PAM module and `pam_sss_gss.8` manual page + +Reviewed-by: Robbie Harwood +Reviewed-by: Sumit Bose +--- + Makefile.am | 33 +- + configure.ac | 1 + + contrib/sssd.spec.in | 2 + + src/external/libgssapi_krb5.m4 | 8 + + src/man/Makefile.am | 4 +- + src/man/pam_sss_gss.8.xml | 209 ++++++++ + src/responder/pam/pamsrv.h | 4 + + src/responder/pam/pamsrv_cmd.c | 2 + + src/responder/pam/pamsrv_gssapi.c | 792 +++++++++++++++++++++++++++++ + src/sss_client/pam_sss_gss.c | 588 +++++++++++++++++++++ + src/sss_client/pam_sss_gss.exports | 4 + + src/sss_client/sss_cli.h | 8 + + src/tests/dlopen-tests.c | 1 + + 13 files changed, 1653 insertions(+), 3 deletions(-) + create mode 100644 src/external/libgssapi_krb5.m4 + create mode 100644 src/man/pam_sss_gss.8.xml + create mode 100644 src/responder/pam/pamsrv_gssapi.c + create mode 100644 src/sss_client/pam_sss_gss.c + create mode 100644 src/sss_client/pam_sss_gss.exports + +diff --git a/Makefile.am b/Makefile.am +index 430b4e842..1c82776ab 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1585,12 +1585,14 @@ sssd_pam_SOURCES = \ + src/responder/pam/pamsrv_cmd.c \ + src/responder/pam/pamsrv_p11.c \ + src/responder/pam/pamsrv_dp.c \ ++ src/responder/pam/pamsrv_gssapi.c \ + src/responder/pam/pam_prompting_config.c \ + src/sss_client/pam_sss_prompt_config.c \ + src/responder/pam/pam_helpers.c \ + $(SSSD_RESPONDER_OBJ) + sssd_pam_CFLAGS = \ + $(AM_CFLAGS) \ ++ $(GSSAPI_KRB5_CFLAGS) \ + $(NULL) + sssd_pam_LDADD = \ + $(LIBADD_DL) \ +@@ -1599,6 +1601,7 @@ sssd_pam_LDADD = \ + $(SELINUX_LIBS) \ + $(PAM_LIBS) \ + $(SYSTEMD_DAEMON_LIBS) \ ++ $(GSSAPI_KRB5_LIBS) \ + libsss_certmap.la \ + $(SSSD_INTERNAL_LTLIBS) \ + libsss_iface.la \ +@@ -2710,6 +2713,7 @@ pam_srv_tests_SOURCES = \ + src/sss_client/pam_message.c \ + src/responder/pam/pamsrv_cmd.c \ + src/responder/pam/pamsrv_p11.c \ ++ src/responder/pam/pamsrv_gssapi.c \ + src/responder/pam/pam_helpers.c \ + src/responder/pam/pamsrv_dp.c \ + src/responder/pam/pam_LOCAL_domain.c \ +@@ -2721,6 +2725,7 @@ pam_srv_tests_CFLAGS = \ + -I$(abs_builddir)/src \ + $(AM_CFLAGS) \ + $(CMOCKA_CFLAGS) \ ++ $(GSSAPI_KRB5_CFLAGS) \ + $(NULL) + pam_srv_tests_LDFLAGS = \ + -Wl,-wrap,sss_packet_get_body \ +@@ -2736,6 +2741,7 @@ pam_srv_tests_LDADD = \ + $(SSSD_LIBS) \ + $(SSSD_INTERNAL_LTLIBS) \ + $(SYSTEMD_DAEMON_LIBS) \ ++ $(GSSAPI_KRB5_LIBS) \ + libsss_test_common.la \ + libsss_idmap.la \ + libsss_certmap.la \ +@@ -4149,6 +4155,28 @@ pam_sss_la_LDFLAGS = \ + -avoid-version \ + -Wl,--version-script,$(srcdir)/src/sss_client/sss_pam.exports + ++pamlib_LTLIBRARIES += pam_sss_gss.la ++pam_sss_gss_la_SOURCES = \ ++ src/sss_client/pam_sss_gss.c \ ++ src/sss_client/common.c \ ++ $(NULL) ++ ++pam_sss_gss_la_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(GSSAPI_KRB5_CFLAGS) \ ++ $(NULL) ++ ++pam_sss_gss_la_LIBADD = \ ++ $(CLIENT_LIBS) \ ++ $(PAM_LIBS) \ ++ $(GSSAPI_KRB5_LIBS) \ ++ $(NULL) ++ ++pam_sss_gss_la_LDFLAGS = \ ++ -module \ ++ -avoid-version \ ++ -Wl,--version-script,$(srcdir)/src/sss_client/pam_sss_gss.exports ++ + if BUILD_SUDO + + libsss_sudo_la_SOURCES = \ +@@ -4187,7 +4215,10 @@ endif + + dist_noinst_DATA += \ + src/sss_client/sss_nss.exports \ +- src/sss_client/sss_pam.exports ++ src/sss_client/sss_pam.exports \ ++ src/sss_client/pam_sss_gss.exports \ ++ $(NULL) ++ + if BUILD_SUDO + dist_noinst_DATA += src/sss_client/sss_sudo.exports + endif +diff --git a/configure.ac b/configure.ac +index 0d24c4b35..75dc81d53 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -182,6 +182,7 @@ m4_include([src/external/libldb.m4]) + m4_include([src/external/libdhash.m4]) + m4_include([src/external/libcollection.m4]) + m4_include([src/external/libini_config.m4]) ++m4_include([src/external/libgssapi_krb5.m4]) + m4_include([src/external/pam.m4]) + m4_include([src/external/ldap.m4]) + m4_include([src/external/libpcre.m4]) +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index ed81da535..f7e5ce133 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -1166,6 +1166,7 @@ done + %license src/sss_client/COPYING src/sss_client/COPYING.LESSER + /%{_lib}/libnss_sss.so.2 + /%{_lib}/security/pam_sss.so ++/%{_lib}/security/pam_sss_gss.so + %{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so + %{_libdir}/krb5/plugins/authdata/sssd_pac_plugin.so + %if (0%{?with_cifs_utils_plugin} == 1) +@@ -1178,6 +1179,7 @@ done + %dir %{_libdir}/%{name}/modules + %{_libdir}/%{name}/modules/sssd_krb5_localauth_plugin.so + %{_mandir}/man8/pam_sss.8* ++%{_mandir}/man8/pam_sss_gss.8* + %{_mandir}/man8/sssd_krb5_locator_plugin.8* + + %files -n libsss_sudo +diff --git a/src/external/libgssapi_krb5.m4 b/src/external/libgssapi_krb5.m4 +new file mode 100644 +index 000000000..67f3c464d +--- /dev/null ++++ b/src/external/libgssapi_krb5.m4 +@@ -0,0 +1,8 @@ ++AC_SUBST(GSSAPI_KRB5_CFLAGS) ++AC_SUBST(GSSAPI_KRB5_LIBS) ++ ++PKG_CHECK_MODULES(GSSAPI_KRB5, ++ krb5-gssapi, ++ , ++ AC_MSG_ERROR("Please install krb5-devel") ++ ) +diff --git a/src/man/Makefile.am b/src/man/Makefile.am +index 351ab8015..c6890a792 100644 +--- a/src/man/Makefile.am ++++ b/src/man/Makefile.am +@@ -69,8 +69,8 @@ man_MANS = \ + sssd.8 sssd.conf.5 sssd-ldap.5 sssd-ldap-attributes.5 \ + sssd-krb5.5 sssd-simple.5 sss-certmap.5 \ + sssd_krb5_locator_plugin.8 \ +- pam_sss.8 sss_obfuscate.8 sss_cache.8 sss_debuglevel.8 sss_seed.8 \ +- sss_override.8 idmap_sss.8 sssctl.8 sssd-session-recording.5 \ ++ pam_sss.8 pam_sss_gss.8 sss_obfuscate.8 sss_cache.8 sss_debuglevel.8 \ ++ sss_seed.8 sss_override.8 idmap_sss.8 sssctl.8 sssd-session-recording.5 \ + $(NULL) + + if BUILD_LOCAL_PROVIDER +diff --git a/src/man/pam_sss_gss.8.xml b/src/man/pam_sss_gss.8.xml +new file mode 100644 +index 000000000..ce5b11bff +--- /dev/null ++++ b/src/man/pam_sss_gss.8.xml +@@ -0,0 +1,209 @@ ++ ++ ++ ++SSSD Manual pages ++ ++ ++ ++ ++ pam_sss_gss ++ 8 ++ ++ ++ ++ pam_sss_gss ++ PAM module for SSSD GSSAPI authentication ++ ++ ++ ++ ++ pam_sss_gss.so ++ ++ debug ++ ++ ++ ++ ++ ++ DESCRIPTION ++ ++ pam_sss_gss.so authenticates user ++ over GSSAPI in cooperation with SSSD. ++ ++ ++ This module will try to authenticate the user using the GSSAPI ++ hostbased service name host@hostname which translates to ++ host/hostname@REALM Kerberos principal. The ++ REALM part of the Kerberos principal name is ++ derived by Kerberos internal mechanisms and it can be set explicitly ++ in configuration of [domain_realm] section in /etc/krb5.conf. ++ ++ ++ SSSD is used to provide desired service name and to validate the ++ user's credentials using GSSAPI calls. If the service ticket is ++ already present in the Kerberos credentials cache or if user's ++ ticket granting ticket can be used to get the correct service ticket ++ then the user will be authenticated. ++ ++ ++ If is True (default) then SSSD ++ requires that the credentials used to obtain the service tickets can ++ be associated with the user. This means that the principal that owns ++ the Kerberos credentials must match with the user principal name as ++ defined in LDAP. ++ ++ ++ To enable GSSAPI authentication in SSSD, set ++ option in [pam] or domain ++ section of sssd.conf. The service credentials need to be stored ++ in SSSD's keytab (it is already present if you use ipa or ad ++ provider). The keytab location can be set with ++ option. See ++ ++ sssd.conf ++ 5 ++ and ++ ++ sssd-krb5 ++ 5 ++ for more details on these options. ++ ++ ++ ++ ++ OPTIONS ++ ++ ++ ++ ++ ++ ++ Print debugging information. ++ ++ ++ ++ ++ ++ ++ MODULE TYPES PROVIDED ++ Only the module type is provided. ++ ++ ++ ++ RETURN VALUES ++ ++ ++ PAM_SUCCESS ++ ++ ++ The PAM operation finished successfully. ++ ++ ++ ++ ++ PAM_USER_UNKNOWN ++ ++ ++ The user is not known to the authentication service or ++ the GSSAPI authentication is not supported. ++ ++ ++ ++ ++ PAM_AUTH_ERR ++ ++ ++ Authentication failure. ++ ++ ++ ++ ++ PAM_AUTHINFO_UNAVAIL ++ ++ ++ Unable to access the authentication information. ++ This might be due to a network or hardware failure. ++ ++ ++ ++ ++ PAM_SYSTEM_ERR ++ ++ ++ A system error occurred. The SSSD log files may contain ++ additional information about the error. ++ ++ ++ ++ ++ ++ ++ ++ EXAMPLES ++ ++ The main use case is to provide password-less authentication in ++ sudo but without the need to disable authentication completely. ++ To achieve this, first enable GSSAPI authentication for sudo in ++ sssd.conf: ++ ++ ++[domain/MYDOMAIN] ++pam_gssapi_services = sudo, sudo-i ++ ++ ++ And then enable the module in desired PAM stack ++ (e.g. /etc/pam.d/sudo and /etc/pam.d/sudo-i). ++ ++ ++... ++auth sufficient pam_sss_gss.so ++... ++ ++ ++ ++ ++ TROUBLESHOOTING ++ ++ SSSD logs, pam_sss_gss debug output and syslog may contain helpful ++ information about the error. Here are some common issues: ++ ++ ++ 1. I have KRB5CCNAME environment variable set and the authentication ++ does not work: Depending on your sudo version, it is possible that ++ sudo does not pass this variable to the PAM environment. Try adding ++ KRB5CCNAME to in /etc/sudoers or in your ++ LDAP sudo rules default options. ++ ++ ++ 2. Authentication does not work and syslog contains "Server not ++ found in Kerberos database": Kerberos is probably not able to ++ resolve correct realm for the service ticket based on the hostname. ++ Try adding the hostname directly to ++ in /etc/krb5.conf like so: ++ ++ ++ 3. Authentication does not work and syslog contains "No Kerberos ++ credentials available": You don't have any credentials that can be ++ used to obtain the required service ticket. Use kinit or autheticate ++ over SSSD to acquire those credentials. ++ ++ ++ 4. Authentication does not work and SSSD sssd-pam log contains "User ++ with UPN [$UPN] was not found." or "UPN [$UPN] does not match target ++ user [$username].": You are using credentials that can not be mapped ++ to the user that is being authenticated. Try to use kswitch to ++ select different principal, make sure you authenticated with SSSD or ++ consider disabling . ++ ++ ++[domain_realm] ++.myhostname = MYREALM ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index bf4dd75b0..355329691 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -145,4 +145,8 @@ errno_t pam_eval_prompting_config(struct pam_ctx *pctx, struct pam_data *pd); + + enum pam_initgroups_scheme pam_initgroups_string_to_enum(const char *str); + const char *pam_initgroup_enum_to_string(enum pam_initgroups_scheme scheme); ++ ++int pam_cmd_gssapi_init(struct cli_ctx *cli_ctx); ++int pam_cmd_gssapi_sec_ctx(struct cli_ctx *cctx); ++ + #endif /* __PAMSRV_H__ */ +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index acbfc0c39..9ea488be4 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -2401,6 +2401,8 @@ struct sss_cmd_table *get_pam_cmds(void) + {SSS_PAM_CHAUTHTOK, pam_cmd_chauthtok}, + {SSS_PAM_CHAUTHTOK_PRELIM, pam_cmd_chauthtok_prelim}, + {SSS_PAM_PREAUTH, pam_cmd_preauth}, ++ {SSS_GSSAPI_INIT, pam_cmd_gssapi_init}, ++ {SSS_GSSAPI_SEC_CTX, pam_cmd_gssapi_sec_ctx}, + {SSS_CLI_NULL, NULL} + }; + +diff --git a/src/responder/pam/pamsrv_gssapi.c b/src/responder/pam/pamsrv_gssapi.c +new file mode 100644 +index 000000000..099675e1c +--- /dev/null ++++ b/src/responder/pam/pamsrv_gssapi.c +@@ -0,0 +1,792 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2020 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 ++#include ++#include ++ ++#include "confdb/confdb.h" ++#include "db/sysdb.h" ++#include "responder/common/responder_packet.h" ++#include "responder/common/responder.h" ++#include "responder/common/cache_req/cache_req.h" ++#include "responder/pam/pamsrv.h" ++#include "sss_client/sss_cli.h" ++#include "util/util.h" ++#include "util/sss_utf8.h" ++ ++static errno_t read_str(size_t body_len, ++ uint8_t *body, ++ size_t *pctr, ++ const char **_str) ++{ ++ size_t i; ++ ++ for (i = *pctr; i < body_len && body[i] != 0; i++) { ++ /* counting */ ++ } ++ ++ if (i >= body_len) { ++ return EINVAL; ++ } ++ ++ if (!sss_utf8_check(&body[*pctr], i - *pctr)) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Body is not UTF-8 string!\n"); ++ return EINVAL; ++ } ++ ++ *_str = (const char *)&body[*pctr]; ++ *pctr = i + 1; ++ ++ return EOK; ++} ++ ++static bool pam_gssapi_should_check_upn(struct pam_ctx *pam_ctx, ++ struct sss_domain_info *domain) ++{ ++ if (domain->gssapi_check_upn != NULL) { ++ if (strcasecmp(domain->gssapi_check_upn, "true") == 0) { ++ return true; ++ } ++ ++ if (strcasecmp(domain->gssapi_check_upn, "false") == 0) { ++ return false; ++ } ++ ++ DEBUG(SSSDBG_MINOR_FAILURE, "Invalid value for %s: %s\n", ++ CONFDB_PAM_GSSAPI_CHECK_UPN, domain->gssapi_check_upn); ++ return false; ++ } ++ ++ return pam_ctx->gssapi_check_upn; ++} ++ ++static bool pam_gssapi_allowed(struct pam_ctx *pam_ctx, ++ struct sss_domain_info *domain, ++ const char *service) ++{ ++ char **list = pam_ctx->gssapi_services; ++ ++ if (domain->gssapi_services != NULL) { ++ list = domain->gssapi_services; ++ } ++ ++ if (strcmp(service, "-") == 0) { ++ /* Dash is used as a "not set" value to allow to explicitly disable ++ * gssapi auth for specific domain. Disallow this service to be safe. ++ */ ++ DEBUG(SSSDBG_TRACE_FUNC, "Dash - was used as a PAM service name. " ++ "GSSAPI authentication is not allowed.\n"); ++ return false; ++ } ++ ++ return string_in_list(service, list, true); ++} ++ ++static char *pam_gssapi_target(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain) ++{ ++ return talloc_asprintf(mem_ctx, "host@%s", domain->hostname); ++} ++ ++static const char *pam_gssapi_get_upn(struct cache_req_result *result) ++{ ++ if (result->count == 0) { ++ return NULL; ++ } ++ ++ /* Canonical UPN should be available if the user has kinited through SSSD. ++ * Use it as a hint for GSSAPI. Default to empty string so it may be ++ * more easily transffered over the wire. */ ++ return ldb_msg_find_attr_as_string(result->msgs[0], SYSDB_CANONICAL_UPN, ""); ++} ++ ++static const char *pam_gssapi_get_name(struct cache_req_result *result) ++{ ++ if (result->count == 0) { ++ return NULL; ++ } ++ ++ /* Return username known to SSSD to make sure we authenticated as the same ++ * user after GSSAPI handshake. */ ++ return ldb_msg_find_attr_as_string(result->msgs[0], SYSDB_NAME, NULL); ++} ++ ++static errno_t pam_gssapi_init_parse(struct cli_protocol *pctx, ++ const char **_service, ++ const char **_username) ++{ ++ size_t body_len; ++ size_t pctr = 0; ++ uint8_t *body; ++ errno_t ret; ++ ++ sss_packet_get_body(pctx->creq->in, &body, &body_len); ++ if (body == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid input\n"); ++ return EINVAL; ++ } ++ ++ ret = read_str(body_len, body, &pctr, _service); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = read_str(body_len, body, &pctr, _username); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ return EOK; ++} ++ ++static errno_t pam_gssapi_init_reply(struct cli_protocol *pctx, ++ const char *domain, ++ const char *target, ++ const char *upn, ++ const char *username) ++{ ++ size_t reply_len; ++ size_t body_len; ++ size_t pctr; ++ uint8_t *body; ++ errno_t ret; ++ ++ ret = sss_packet_new(pctx->creq, 0, sss_packet_get_cmd(pctx->creq->in), ++ &pctx->creq->out); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create a new packet [%d]; %s\n", ++ ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ reply_len = strlen(username) + 1; ++ reply_len += strlen(domain) + 1; ++ reply_len += strlen(target) + 1; ++ reply_len += strlen(upn) + 1; ++ ++ ret = sss_packet_grow(pctx->creq->out, reply_len); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create response: %s\n", ++ sss_strerror(ret)); ++ return ret; ++ } ++ ++ sss_packet_get_body(pctx->creq->out, &body, &body_len); ++ ++ pctr = 0; ++ SAFEALIGN_SETMEM_STRING(&body[pctr], username, strlen(username) + 1, &pctr); ++ SAFEALIGN_SETMEM_STRING(&body[pctr], domain, strlen(domain) + 1, &pctr); ++ SAFEALIGN_SETMEM_STRING(&body[pctr], target, strlen(target) + 1, &pctr); ++ SAFEALIGN_SETMEM_STRING(&body[pctr], upn, strlen(upn) + 1, &pctr); ++ ++ return EOK; ++} ++ ++struct gssapi_init_state { ++ struct cli_ctx *cli_ctx; ++ const char *username; ++ const char *service; ++}; ++ ++static void pam_cmd_gssapi_init_done(struct tevent_req *req); ++ ++int pam_cmd_gssapi_init(struct cli_ctx *cli_ctx) ++{ ++ struct gssapi_init_state *state; ++ struct cli_protocol *pctx; ++ struct tevent_req *req; ++ const char *username; ++ const char *service; ++ const char *attrs[] = { SYSDB_NAME, SYSDB_CANONICAL_UPN, NULL }; ++ errno_t ret; ++ ++ state = talloc_zero(cli_ctx, struct gssapi_init_state); ++ if (state == NULL) { ++ return ENOMEM; ++ } ++ ++ pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol); ++ ++ ret = pam_gssapi_init_parse(pctx, &service, &username); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse input [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ state->cli_ctx = cli_ctx; ++ state->service = service; ++ state->username = username; ++ ++ DEBUG(SSSDBG_TRACE_ALL, ++ "Requesting GSSAPI authentication of [%s] in service [%s]\n", ++ username, service); ++ ++ req = cache_req_user_by_name_attrs_send(cli_ctx, cli_ctx->ev, cli_ctx->rctx, ++ cli_ctx->rctx->ncache, 0, ++ NULL, username, attrs); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tevent_req_set_callback(req, pam_cmd_gssapi_init_done, state); ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ sss_cmd_send_error(cli_ctx, ret); ++ sss_cmd_done(cli_ctx, NULL); ++ } ++ ++ return EOK; ++} ++ ++static void pam_cmd_gssapi_init_done(struct tevent_req *req) ++{ ++ struct gssapi_init_state *state; ++ struct cache_req_result *result; ++ struct cli_protocol *pctx; ++ struct pam_ctx *pam_ctx; ++ const char *username; ++ const char *upn; ++ char *target; ++ errno_t ret; ++ ++ state = tevent_req_callback_data(req, struct gssapi_init_state); ++ pctx = talloc_get_type(state->cli_ctx->protocol_ctx, struct cli_protocol); ++ pam_ctx = talloc_get_type(state->cli_ctx->rctx->pvt_ctx, struct pam_ctx); ++ ++ ret = cache_req_user_by_name_attrs_recv(state, req, &result); ++ talloc_zfree(req); ++ if (ret == ENOENT || ret == ERR_DOMAIN_NOT_FOUND) { ++ ret = ENOENT; ++ goto done; ++ } else if (ret != EOK) { ++ goto done; ++ } ++ ++ if (!pam_gssapi_allowed(pam_ctx, result->domain, state->service)) { ++ ret = ENOTSUP; ++ goto done; ++ } ++ ++ username = pam_gssapi_get_name(result); ++ if (username == NULL) { ++ /* User with no name? */ ++ ret = ERR_INTERNAL; ++ goto done; ++ } ++ ++ upn = pam_gssapi_get_upn(result); ++ if (upn == NULL) { ++ /* UPN hint may be an empty string, but not NULL. */ ++ ret = ERR_INTERNAL; ++ goto done; ++ } ++ ++ target = pam_gssapi_target(state, result->domain); ++ if (target == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Trying GSSAPI auth: User[%s], Domain[%s], UPN[%s], Target[%s]\n", ++ username, result->domain->name, upn, target); ++ ++ ret = pam_gssapi_init_reply(pctx, result->domain->name, target, upn, ++ username); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to construct reply [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++done: ++ DEBUG(SSSDBG_TRACE_FUNC, "Returning [%d]: %s\n", ret, sss_strerror(ret)); ++ ++ if (ret == EOK) { ++ sss_packet_set_error(pctx->creq->out, EOK); ++ } else { ++ sss_cmd_send_error(state->cli_ctx, ret); ++ } ++ ++ sss_cmd_done(state->cli_ctx, state); ++} ++ ++static void gssapi_log_status(int type, OM_uint32 status_code) ++{ ++ OM_uint32 message_context = 0; ++ gss_buffer_desc buf; ++ OM_uint32 minor; ++ ++ do { ++ gss_display_status(&minor, status_code, type, GSS_C_NO_OID, ++ &message_context, &buf); ++ DEBUG(SSSDBG_OP_FAILURE, "GSSAPI: %.*s\n", (int)buf.length, ++ (char *)buf.value); ++ gss_release_buffer(&minor, &buf); ++ } while (message_context != 0); ++} ++ ++static void gssapi_log_error(OM_uint32 major, OM_uint32 minor) ++{ ++ gssapi_log_status(GSS_C_GSS_CODE, major); ++ gssapi_log_status(GSS_C_MECH_CODE, minor); ++} ++ ++static char *gssapi_get_name(TALLOC_CTX *mem_ctx, gss_name_t gss_name) ++{ ++ gss_buffer_desc buf; ++ OM_uint32 major; ++ OM_uint32 minor; ++ char *exported; ++ ++ major = gss_display_name(&minor, gss_name, &buf, NULL); ++ if (major != GSS_S_COMPLETE) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to export name\n"); ++ return NULL; ++ } ++ ++ exported = talloc_strndup(mem_ctx, buf.value, buf.length); ++ gss_release_buffer(&minor, &buf); ++ ++ if (exported == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); ++ return NULL; ++ } ++ ++ return exported; ++} ++ ++struct gssapi_state { ++ struct cli_ctx *cli_ctx; ++ struct sss_domain_info *domain; ++ const char *username; ++ ++ char *authenticated_upn; ++ bool established; ++ gss_ctx_id_t ctx; ++}; ++ ++int gssapi_state_destructor(struct gssapi_state *state) ++{ ++ OM_uint32 minor; ++ ++ gss_delete_sec_context(&minor, &state->ctx, NULL); ++ ++ return 0; ++} ++ ++static struct gssapi_state *gssapi_get_state(struct cli_ctx *cli_ctx, ++ const char *username, ++ struct sss_domain_info *domain) ++{ ++ struct gssapi_state *state; ++ ++ state = talloc_get_type(cli_ctx->state_ctx, struct gssapi_state); ++ if (state != NULL) { ++ return state; ++ } ++ ++ state = talloc_zero(cli_ctx, struct gssapi_state); ++ if (state == NULL) { ++ return NULL; ++ } ++ ++ state->username = talloc_strdup(state, username); ++ if (state == NULL) { ++ talloc_free(state); ++ return NULL; ++ } ++ ++ state->domain = domain; ++ state->cli_ctx = cli_ctx; ++ state->ctx = GSS_C_NO_CONTEXT; ++ talloc_set_destructor(state, gssapi_state_destructor); ++ ++ cli_ctx->state_ctx = state; ++ ++ return state; ++} ++ ++static errno_t gssapi_get_creds(const char *keytab, ++ const char *target, ++ gss_cred_id_t *_creds) ++{ ++ gss_key_value_set_desc cstore = {0, NULL}; ++ gss_key_value_element_desc el; ++ gss_buffer_desc name_buf; ++ gss_name_t name = GSS_C_NO_NAME; ++ OM_uint32 major; ++ OM_uint32 minor; ++ errno_t ret; ++ ++ if (keytab != NULL) { ++ el.key = "keytab"; ++ el.value = keytab; ++ cstore.count = 1; ++ cstore.elements = ⪙ ++ } ++ ++ if (target != NULL) { ++ name_buf.value = discard_const(target); ++ name_buf.length = strlen(target); ++ ++ major = gss_import_name(&minor, &name_buf, GSS_C_NT_HOSTBASED_SERVICE, ++ &name); ++ if (GSS_ERROR(major)) { ++ DEBUG(SSSDBG_OP_FAILURE, "Could not import name [%s] " ++ "[maj:0x%x, min:0x%x]\n", target, major, minor); ++ ++ gssapi_log_error(major, minor); ++ ++ ret = EIO; ++ goto done; ++ } ++ } ++ ++ major = gss_acquire_cred_from(&minor, name, GSS_C_INDEFINITE, ++ GSS_C_NO_OID_SET, GSS_C_ACCEPT, &cstore, ++ _creds, NULL, NULL); ++ if (GSS_ERROR(major)) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to read credentials from [%s] " ++ "[maj:0x%x, min:0x%x]\n", keytab ? keytab : "default", ++ major, minor); ++ ++ gssapi_log_error(major, minor); ++ ++ ret = EIO; ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ gss_release_name(&minor, &name); ++ ++ return ret; ++} ++ ++static errno_t ++gssapi_handshake(struct gssapi_state *state, ++ struct cli_protocol *pctx, ++ const char *keytab, ++ const char *target, ++ uint8_t *gss_data, ++ size_t gss_data_len) ++{ ++ OM_uint32 flags = GSS_C_MUTUAL_FLAG; ++ gss_buffer_desc output = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc input; ++ gss_name_t client_name; ++ gss_cred_id_t creds; ++ OM_uint32 ret_flags; ++ gss_OID mech_type; ++ OM_uint32 major; ++ OM_uint32 minor; ++ errno_t ret; ++ ++ input.value = gss_data; ++ input.length = gss_data_len; ++ ++ ret = gssapi_get_creds(keytab, target, &creds); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ major = gss_accept_sec_context(&minor, &state->ctx, creds, ++ &input, NULL, &client_name, &mech_type, ++ &output, &ret_flags, NULL, NULL); ++ if (major == GSS_S_CONTINUE_NEEDED || output.length > 0) { ++ ret = sss_packet_set_body(pctx->creq->out, output.value, output.length); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ ++ if (GSS_ERROR(major)) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to establish GSS context " ++ "[maj:0x%x, min:0x%x]\n", major, minor); ++ ++ gssapi_log_error(major, minor); ++ ret = EIO; ++ goto done; ++ } ++ ++ if (major == GSS_S_CONTINUE_NEEDED) { ++ ret = EOK; ++ goto done; ++ } else if (major != GSS_S_COMPLETE) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to establish GSS context, unexpected " ++ "value: 0x%x\n", major); ++ ret = EIO; ++ goto done; ++ } ++ ++ if ((ret_flags & flags) != flags) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Negotiated context does not support requested flags\n"); ++ state->established = false; ++ ret = EIO; ++ goto done; ++ } ++ ++ state->authenticated_upn = gssapi_get_name(state, client_name); ++ if (state->authenticated_upn == NULL) { ++ state->established = false; ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Security context established with [%s]\n", ++ state->authenticated_upn); ++ ++ state->established = true; ++ ret = EOK; ++ ++done: ++ gss_release_cred(&minor, &creds); ++ gss_release_buffer(&minor, &output); ++ ++ return ret; ++} ++ ++static errno_t pam_cmd_gssapi_sec_ctx_parse(struct cli_protocol *pctx, ++ const char **_pam_service, ++ const char **_username, ++ const char **_domain, ++ uint8_t **_gss_data, ++ size_t *_gss_data_len) ++{ ++ size_t body_len; ++ uint8_t *body; ++ size_t pctr; ++ errno_t ret; ++ ++ sss_packet_get_body(pctx->creq->in, &body, &body_len); ++ if (body == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid input\n"); ++ return EINVAL; ++ } ++ ++ pctr = 0; ++ ret = read_str(body_len, body, &pctr, _pam_service); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = read_str(body_len, body, &pctr, _username); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = read_str(body_len, body, &pctr, _domain); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ *_gss_data = (pctr == body_len) ? NULL : body + pctr; ++ *_gss_data_len = body_len - pctr; ++ ++ return EOK; ++} ++ ++static void pam_cmd_gssapi_sec_ctx_done(struct tevent_req *req); ++ ++int ++pam_cmd_gssapi_sec_ctx(struct cli_ctx *cli_ctx) ++{ ++ struct sss_domain_info *domain; ++ struct gssapi_state *state; ++ struct cli_protocol *pctx; ++ struct pam_ctx *pam_ctx; ++ struct tevent_req *req; ++ const char *pam_service; ++ const char *domain_name; ++ const char *username; ++ char *target; ++ size_t gss_data_len; ++ uint8_t *gss_data; ++ errno_t ret; ++ ++ pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol); ++ pam_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct pam_ctx); ++ ++ ret = sss_packet_new(pctx->creq, 0, sss_packet_get_cmd(pctx->creq->in), ++ &pctx->creq->out); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create a new packet [%d]; %s\n", ++ ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ ret = pam_cmd_gssapi_sec_ctx_parse(pctx, &pam_service, &username, ++ &domain_name, &gss_data, &gss_data_len); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to parse input data [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ domain = find_domain_by_name(cli_ctx->rctx->domains, domain_name, false); ++ if (domain == NULL) { ++ ret = EINVAL; ++ goto done; ++ } ++ ++ if (!pam_gssapi_allowed(pam_ctx, domain, pam_service)) { ++ ret = ENOTSUP; ++ goto done; ++ } ++ ++ target = pam_gssapi_target(cli_ctx, domain); ++ if (target == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ state = gssapi_get_state(cli_ctx, username, domain); ++ if (state == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ if (strcmp(username, state->username) != 0 || state->domain != domain) { ++ /* This should not happen, but be paranoid. */ ++ DEBUG(SSSDBG_CRIT_FAILURE, "Different input user then who initiated " ++ "the request!\n"); ++ ret = EPERM; ++ goto done; ++ } ++ ++ if (state->established) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Security context is already established\n"); ++ ret = EPERM; ++ goto done; ++ } ++ ++ ret = gssapi_handshake(state, pctx, domain->krb5_keytab, target, gss_data, ++ gss_data_len); ++ if (ret != EOK || !state->established) { ++ goto done; ++ } ++ ++ if (!pam_gssapi_should_check_upn(pam_ctx, domain)) { ++ /* We are done. */ ++ goto done; ++ } ++ ++ /* We have established the security context. Now check the the principal ++ * used for authorization can be associated with the user. We have ++ * already done initgroups before so we could just search the sysdb ++ * directly, but use cache req to avoid looking up a possible expired ++ * object if the handshake took longer. */ ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Checking that target user matches UPN\n"); ++ ++ req = cache_req_user_by_upn_send(cli_ctx, cli_ctx->ev, cli_ctx->rctx, ++ cli_ctx->rctx->ncache, 0, DOM_TYPE_POSIX, ++ domain->name, state->authenticated_upn); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tevent_req_set_callback(req, pam_cmd_gssapi_sec_ctx_done, state); ++ ++ return EOK; ++ ++done: ++ DEBUG(SSSDBG_TRACE_FUNC, "Returning [%d]: %s\n", ret, sss_strerror(ret)); ++ ++ if (ret == EOK) { ++ sss_packet_set_error(pctx->creq->out, EOK); ++ } else { ++ sss_cmd_send_error(cli_ctx, ret); ++ } ++ ++ sss_cmd_done(cli_ctx, NULL); ++ return EOK; ++} ++ ++static void pam_cmd_gssapi_sec_ctx_done(struct tevent_req *req) ++{ ++ struct gssapi_state *state; ++ struct cache_req_result *result; ++ struct cli_protocol *pctx; ++ const char *name; ++ errno_t ret; ++ ++ state = tevent_req_callback_data(req, struct gssapi_state); ++ pctx = talloc_get_type(state->cli_ctx->protocol_ctx, struct cli_protocol); ++ ++ ret = cache_req_user_by_upn_recv(state, req, &result); ++ talloc_zfree(req); ++ if (ret == ENOENT || ret == ERR_DOMAIN_NOT_FOUND) { ++ /* We have no match. Return failure. */ ++ DEBUG(SSSDBG_TRACE_FUNC, "User with UPN [%s] was not found. " ++ "Authentication failed.\n", state->authenticated_upn); ++ ret = EACCES; ++ goto done; ++ } else if (ret != EOK) { ++ /* Generic error. Return failure. */ ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user by UPN [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ /* Check that username match. */ ++ name = ldb_msg_find_attr_as_string(result->msgs[0], SYSDB_NAME, NULL); ++ if (name == NULL || strcmp(name, state->username) != 0) { ++ DEBUG(SSSDBG_TRACE_FUNC, "UPN [%s] does not match target user [%s]. " ++ "Authentication failed.\n", state->authenticated_upn, ++ state->username); ++ ret = EACCES; ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "User [%s] match UPN [%s]. Authentication was " ++ "successful.\n", state->username, state->authenticated_upn); ++ ++ ret = EOK; ++ ++done: ++ DEBUG(SSSDBG_TRACE_FUNC, "Returning [%d]: %s\n", ret, sss_strerror(ret)); ++ ++ if (ret == EOK) { ++ sss_packet_set_error(pctx->creq->out, EOK); ++ } else { ++ sss_cmd_send_error(state->cli_ctx, ret); ++ } ++ ++ sss_cmd_done(state->cli_ctx, state); ++} +diff --git a/src/sss_client/pam_sss_gss.c b/src/sss_client/pam_sss_gss.c +new file mode 100644 +index 000000000..cd38db7da +--- /dev/null ++++ b/src/sss_client/pam_sss_gss.c +@@ -0,0 +1,588 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2020 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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "util/sss_format.h" ++#include "sss_client/sss_cli.h" ++ ++bool debug_enabled; ++ ++#define TRACE(pamh, fmt, ...) do { \ ++ if (debug_enabled) { \ ++ pam_info(pamh, "pam_sss_gss: " fmt, ## __VA_ARGS__); \ ++ } \ ++} while (0) ++ ++#define ERROR(pamh, fmt, ...) do { \ ++ if (debug_enabled) { \ ++ pam_error(pamh, "pam_sss_gss: " fmt, ## __VA_ARGS__); \ ++ pam_syslog(pamh, LOG_ERR, fmt, ## __VA_ARGS__); \ ++ } \ ++} while (0) ++ ++static bool switch_euid(pam_handle_t *pamh, uid_t current, uid_t desired) ++{ ++ int ret; ++ ++ TRACE(pamh, "Switching euid from %" SPRIuid " to %" SPRIuid, current, ++ desired); ++ ++ if (current == desired) { ++ return true; ++ } ++ ++ ret = seteuid(desired); ++ if (ret != 0) { ++ ERROR(pamh, "Unable to set euid to %" SPRIuid, desired); ++ return false; ++ } ++ ++ return true; ++} ++ ++static const char *get_item_as_string(pam_handle_t *pamh, int item) ++{ ++ const char *str; ++ int ret; ++ ++ ret = pam_get_item(pamh, item, (void *)&str); ++ if (ret != PAM_SUCCESS || str == NULL || str[0] == '\0') { ++ return NULL; ++ } ++ ++ return str; ++} ++ ++static errno_t string_to_gss_name(pam_handle_t *pamh, ++ const char *target, ++ gss_OID type, ++ gss_name_t *_name) ++{ ++ gss_buffer_desc name_buf; ++ OM_uint32 major; ++ OM_uint32 minor; ++ ++ name_buf.value = (void *)(uintptr_t)target; ++ name_buf.length = strlen(target); ++ major = gss_import_name(&minor, &name_buf, type, _name); ++ if (GSS_ERROR(major)) { ++ ERROR(pamh, "Could not convert target to GSS name"); ++ return EIO; ++ } ++ ++ return EOK; ++} ++ ++static void gssapi_log_status(pam_handle_t *pamh, ++ int type, ++ OM_uint32 status_code) ++{ ++ gss_buffer_desc buf; ++ OM_uint32 message_context; ++ OM_uint32 minor; ++ ++ message_context = 0; ++ do { ++ gss_display_status(&minor, status_code, type, GSS_C_NO_OID, ++ &message_context, &buf); ++ ERROR(pamh, "GSSAPI: %.*s", (int)buf.length, (char *)buf.value); ++ gss_release_buffer(&minor, &buf); ++ } while (message_context != 0); ++} ++ ++static void gssapi_log_error(pam_handle_t *pamh, ++ OM_uint32 major, ++ OM_uint32 minor) ++{ ++ gssapi_log_status(pamh, GSS_C_GSS_CODE, major); ++ gssapi_log_status(pamh, GSS_C_MECH_CODE, minor); ++} ++ ++static errno_t gssapi_get_creds(pam_handle_t *pamh, ++ const char *ccache, ++ const char *target, ++ const char *upn, ++ gss_cred_id_t *_creds) ++{ ++ gss_key_value_set_desc cstore = {0, NULL}; ++ gss_key_value_element_desc el; ++ gss_name_t name = GSS_C_NO_NAME; ++ OM_uint32 major; ++ OM_uint32 minor; ++ errno_t ret; ++ ++ if (upn != NULL && upn[0] != '\0') { ++ TRACE(pamh, "Acquiring credentials for principal [%s]", upn); ++ ret = string_to_gss_name(pamh, upn, GSS_C_NT_USER_NAME, &name); ++ if (ret != EOK) { ++ goto done; ++ } ++ } else { ++ TRACE(pamh, "Acquiring credentials, principal name will be derived"); ++ } ++ ++ if (ccache != NULL) { ++ el.key = "ccache"; ++ el.value = ccache; ++ cstore.count = 1; ++ cstore.elements = ⪙ ++ } ++ ++ major = gss_acquire_cred_from(&minor, name, GSS_C_INDEFINITE, ++ GSS_C_NO_OID_SET, GSS_C_INITIATE, ++ &cstore, _creds, NULL, NULL); ++ if (GSS_ERROR(major)) { ++ /* TODO: Do not hardcode the error code. */ ++ if (minor == 2529639053 && name != GSS_C_NO_NAME) { ++ /* Hint principal was not found. Try again and let GSSAPI choose. */ ++ TRACE(pamh, "Principal [%s] was not found in ccache", upn); ++ ret = gssapi_get_creds(pamh, ccache, target, NULL, _creds); ++ goto done; ++ } else { ++ ERROR(pamh, "Unable to read credentials from [%s] " ++ "[maj:0x%x, min:0x%x]", ccache == NULL ? "default" : ccache, ++ major, minor); ++ ++ gssapi_log_error(pamh, major, minor); ++ ret = EIO; ++ goto done; ++ } ++ } ++ ++ ret = EOK; ++ ++done: ++ gss_release_name(&minor, &name); ++ ++ return ret; ++} ++ ++static errno_t sssd_gssapi_init_send(pam_handle_t *pamh, ++ const char *pam_service, ++ const char *pam_user, ++ uint8_t **_reply, ++ size_t *_reply_len) ++{ ++ struct sss_cli_req_data req_data; ++ size_t service_len; ++ size_t user_len; ++ uint8_t *data; ++ errno_t ret; ++ int ret_errno; ++ ++ if (pam_service == NULL || pam_user == NULL) { ++ return EINVAL; ++ } ++ ++ service_len = strlen(pam_service) + 1; ++ user_len = strlen(pam_user) + 1; ++ ++ req_data.len = (service_len + user_len) * sizeof(char); ++ data = (uint8_t*)malloc(req_data.len); ++ if (data == NULL) { ++ return ENOMEM; ++ } ++ ++ memcpy(data, pam_service, service_len); ++ memcpy(data + service_len, pam_user, user_len); ++ ++ req_data.data = data; ++ ++ ret = sss_pam_make_request(SSS_GSSAPI_INIT, &req_data, _reply, _reply_len, ++ &ret_errno); ++ free(data); ++ if (ret != PAM_SUCCESS) { ++ if (ret_errno == ENOTSUP) { ++ TRACE(pamh, "GSSAPI authentication is not supported for user %s " ++ "and service %s", pam_user, pam_service); ++ return ret_errno; ++ } ++ ++ ERROR(pamh, "Communication error [%d, %d]: %s; %s", ret, ret_errno, ++ pam_strerror(pamh, ret), strerror(ret_errno)); ++ ++ return (ret_errno != EOK) ? ret_errno : EIO; ++ } ++ ++ return ret_errno; ++} ++ ++static errno_t sssd_gssapi_init_recv(uint8_t *reply, ++ size_t reply_len, ++ char **_username, ++ char **_domain, ++ char **_target, ++ char **_upn) ++{ ++ char *username = NULL; ++ char *domain = NULL; ++ char *target = NULL; ++ char *upn = NULL; ++ const char *buf; ++ size_t pctr = 0; ++ size_t dlen; ++ errno_t ret; ++ ++ username = malloc(reply_len * sizeof(char)); ++ domain = malloc(reply_len * sizeof(char)); ++ target = malloc(reply_len * sizeof(char)); ++ upn = malloc(reply_len * sizeof(char)); ++ if (username == NULL || domain == NULL || target == NULL || upn == NULL) { ++ return ENOMEM; ++ } ++ ++ buf = (const char*)reply; ++ ++ dlen = reply_len; ++ ret = sss_readrep_copy_string(buf, &pctr, &reply_len, &dlen, &username, ++ NULL); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ dlen = reply_len; ++ ret = sss_readrep_copy_string(buf, &pctr, &reply_len, &dlen, &domain, NULL); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ dlen = reply_len; ++ ret = sss_readrep_copy_string(buf, &pctr, &reply_len, &dlen, &target, NULL); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ dlen = reply_len; ++ ret = sss_readrep_copy_string(buf, &pctr, &reply_len, &dlen, &upn, NULL); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ *_username = username; ++ *_domain = domain; ++ *_target = target; ++ *_upn = upn; ++ ++done: ++ if (ret != EOK) { ++ free(username); ++ free(domain); ++ free(target); ++ free(upn); ++ } ++ ++ return ret; ++} ++ ++static errno_t sssd_gssapi_init(pam_handle_t *pamh, ++ const char *pam_service, ++ const char *pam_user, ++ char **_username, ++ char **_domain, ++ char **_target, ++ char **_upn) ++{ ++ size_t reply_len; ++ uint8_t *reply; ++ errno_t ret; ++ ++ ret = sssd_gssapi_init_send(pamh, pam_service, pam_user, &reply, ++ &reply_len); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = sssd_gssapi_init_recv(reply, reply_len, _username, _domain, _target, ++ _upn); ++ free(reply); ++ ++ return ret; ++} ++ ++static errno_t sssd_establish_sec_ctx_send(pam_handle_t *pamh, ++ const char *pam_service, ++ const char *username, ++ const char *domain, ++ const void *gss_data, ++ size_t gss_data_len, ++ void **_reply, ++ size_t *_reply_len) ++{ ++ struct sss_cli_req_data req_data; ++ size_t username_len; ++ size_t service_len; ++ size_t domain_len; ++ uint8_t *data; ++ int ret_errno; ++ int ret; ++ ++ service_len = strlen(pam_service) + 1; ++ username_len = strlen(username) + 1; ++ domain_len = strlen(domain) + 1; ++ ++ req_data.len = (service_len + username_len + domain_len) * sizeof(char) ++ + gss_data_len; ++ data = malloc(req_data.len); ++ if (data == NULL) { ++ return ENOMEM; ++ } ++ ++ memcpy(data, pam_service, service_len); ++ memcpy(data + service_len, username, username_len); ++ memcpy(data + service_len + username_len, domain, domain_len); ++ memcpy(data + service_len + username_len + domain_len, gss_data, ++ gss_data_len); ++ ++ req_data.data = data; ++ ret = sss_pam_make_request(SSS_GSSAPI_SEC_CTX, &req_data, (uint8_t**)_reply, ++ _reply_len, &ret_errno); ++ free(data); ++ if (ret != PAM_SUCCESS) { ++ /* ENOTSUP should not happend here so let's keep it as generic error. */ ++ ERROR(pamh, "Communication error [%d, %d]: %s; %s", ret, ret_errno, ++ pam_strerror(pamh, ret), strerror(ret_errno)); ++ ++ return (ret_errno != EOK) ? ret_errno : EIO; ++ } ++ ++ return ret_errno; ++} ++ ++static int sssd_establish_sec_ctx(pam_handle_t *pamh, ++ const char *ccache, ++ const char *pam_service, ++ const char *username, ++ const char *domain, ++ const char *target, ++ const char *upn) ++{ ++ gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; ++ gss_buffer_desc input = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc output = GSS_C_EMPTY_BUFFER; ++ OM_uint32 flags = GSS_C_MUTUAL_FLAG; ++ gss_name_t gss_name; ++ gss_cred_id_t creds; ++ OM_uint32 ret_flags; ++ OM_uint32 major; ++ OM_uint32 minor; ++ int ret; ++ ++ ret = gssapi_get_creds(pamh, ccache, target, upn, &creds); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = string_to_gss_name(pamh, target, GSS_C_NT_HOSTBASED_SERVICE, &gss_name); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ do { ++ major = gss_init_sec_context(&minor, creds, &ctx, ++ gss_name, GSS_C_NO_OID, flags, 0, NULL, ++ &input, NULL, &output, ++ &ret_flags, NULL); ++ ++ free(input.value); ++ memset(&input, 0, sizeof(gss_buffer_desc)); ++ ++ if (GSS_ERROR(major)) { ++ ERROR(pamh, "Unable to establish GSS context [maj:0x%x, min:0x%x]", ++ major, minor); ++ gssapi_log_error(pamh, major, minor); ++ ret = EIO; ++ goto done; ++ } else if (major == GSS_S_CONTINUE_NEEDED || output.length > 0) { ++ ret = sssd_establish_sec_ctx_send(pamh, pam_service, ++ username, domain, ++ output.value, output.length, ++ &input.value, &input.length); ++ gss_release_buffer(NULL, &output); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ } while (major != GSS_S_COMPLETE); ++ ++ if ((ret_flags & flags) != flags) { ++ ERROR(pamh, "Negotiated context does not support requested flags\n"); ++ ret = EIO; ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ gss_delete_sec_context(&minor, &ctx, NULL); ++ gss_release_name(&minor, &gss_name); ++ ++ return ret; ++} ++ ++static int errno_to_pam(pam_handle_t *pamh, errno_t ret) ++{ ++ switch (ret) { ++ case EOK: ++ TRACE(pamh, "Authentication successful"); ++ return PAM_SUCCESS; ++ case ENOENT: ++ TRACE(pamh, "User not found"); ++ return PAM_USER_UNKNOWN; ++ case ENOTSUP: ++ TRACE(pamh, "GSSAPI authentication is not enabled " ++ "for given user and service"); ++ return PAM_USER_UNKNOWN; ++ case ESSS_NO_SOCKET: ++ TRACE(pamh, "SSSD socket does not exist"); ++ return PAM_AUTHINFO_UNAVAIL; ++ case EPERM: ++ TRACE(pamh, "Authentication failed"); ++ return PAM_AUTH_ERR; ++ default: ++ TRACE(pamh, "System error [%d]: %s", ++ ret, strerror(ret)); ++ return PAM_SYSTEM_ERR; ++ } ++} ++ ++int pam_sm_authenticate(pam_handle_t *pamh, ++ int flags, ++ int argc, ++ const char **argv) ++{ ++ const char *pam_service; ++ const char *pam_user; ++ const char *ccache; ++ char *username = NULL; ++ char *domain = NULL; ++ char *target = NULL; ++ char *upn = NULL; ++ uid_t uid; ++ uid_t euid; ++ errno_t ret; ++ ++ debug_enabled = false; ++ for (int i = 0; i < argc; i++) { ++ if (strcmp(argv[i], "debug") == 0) { ++ debug_enabled = true; ++ break; ++ } ++ } ++ ++ ++ /* Get non-default ccache if specified, may be NULL. */ ++ ccache = getenv("KRB5CCNAME"); ++ ++ uid = getuid(); ++ euid = geteuid(); ++ ++ /* Read PAM data. */ ++ pam_service = get_item_as_string(pamh, PAM_SERVICE); ++ pam_user = get_item_as_string(pamh, PAM_USER); ++ if (pam_service == NULL || pam_user == NULL) { ++ ERROR(pamh, "Unable to get PAM data!"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ /* Initialize GSSAPI authentication with SSSD. Get user domain ++ * and target GSS service name. */ ++ TRACE(pamh, "Initializing GSSAPI authentication with SSSD"); ++ ret = sssd_gssapi_init(pamh, pam_service, pam_user, &username, &domain, ++ &target, &upn); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ /* PAM is often called from set-user-id applications (sudo, su). we want to ++ * make sure that we access credentials of the caller (real uid). */ ++ if (!switch_euid(pamh, euid, uid)) { ++ ret = EFAULT; ++ goto done; ++ } ++ ++ /* Authenticate the user by estabilishing security context. Authorization is ++ * expected to be done by other modules through pam_access. */ ++ TRACE(pamh, "Trying to establish security context"); ++ TRACE(pamh, "SSSD User name: %s", username); ++ TRACE(pamh, "User domain: %s", domain); ++ TRACE(pamh, "User principal: %s", upn); ++ TRACE(pamh, "Target name: %s", target); ++ TRACE(pamh, "Using ccache: %s", ccache == NULL ? "default" : ccache); ++ ret = sssd_establish_sec_ctx(pamh, ccache, pam_service, ++ username, domain, target, upn); ++ ++ /* Restore original euid. */ ++ if (!switch_euid(pamh, uid, euid)) { ++ ret = EFAULT; ++ goto done; ++ } ++ ++done: ++ sss_pam_close_fd(); ++ free(domain); ++ free(target); ++ free(upn); ++ ++ return errno_to_pam(pamh, ret); ++} ++ ++int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) ++{ ++ return PAM_IGNORE; ++} ++ ++int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) ++{ ++ return PAM_IGNORE; ++} ++ ++int pam_sm_open_session(pam_handle_t *pamh, ++ int flags, ++ int argc, ++ const char **argv) ++{ ++ return PAM_IGNORE; ++} ++ ++int pam_sm_close_session(pam_handle_t *pamh, ++ int flags, ++ int argc, ++ const char **argv) ++{ ++ return PAM_IGNORE; ++} ++ ++int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) ++{ ++ return PAM_IGNORE; ++} +diff --git a/src/sss_client/pam_sss_gss.exports b/src/sss_client/pam_sss_gss.exports +new file mode 100644 +index 000000000..9afa106be +--- /dev/null ++++ b/src/sss_client/pam_sss_gss.exports +@@ -0,0 +1,4 @@ ++{ ++ global: ++ *; ++}; +diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h +index d897f43b7..2c3c71bc4 100644 +--- a/src/sss_client/sss_cli.h ++++ b/src/sss_client/sss_cli.h +@@ -233,6 +233,8 @@ enum sss_cli_command { + * an authentication request to find + * out which authentication methods + * are available for the given user. */ ++ SSS_GSSAPI_INIT = 0x00FA, /**< Initialize GSSAPI authentication. */ ++ SSS_GSSAPI_SEC_CTX = 0x00FB, /**< Establish GSSAPI security ctx. */ + + /* PAC responder calls */ + SSS_PAC_ADD_PAC_USER = 0x0101, +@@ -721,4 +723,10 @@ errno_t sss_readrep_copy_string(const char *in, + char **out, + size_t *size); + ++enum pam_gssapi_cmd { ++ PAM_GSSAPI_GET_NAME, ++ PAM_GSSAPI_INIT, ++ PAM_GSSAPI_SENTINEL ++}; ++ + #endif /* _SSSCLI_H */ +diff --git a/src/tests/dlopen-tests.c b/src/tests/dlopen-tests.c +index ccf52abe9..bffa02188 100644 +--- a/src/tests/dlopen-tests.c ++++ b/src/tests/dlopen-tests.c +@@ -47,6 +47,7 @@ struct so { + { "libnss_sss.so", { LIBPFX"libnss_sss.so", NULL } }, + { "libsss_certmap.so", { LIBPFX"libsss_certmap.so", NULL } }, + { "pam_sss.so", { LIBPFX"pam_sss.so", NULL } }, ++ { "pam_sss_gss.so", { LIBPFX"pam_sss_gss.so", NULL } }, + #ifdef BUILD_WITH_LIBSECRET + { "libsss_secrets.so", { LIBPFX"libsss_secrets.so", NULL } }, + #endif /* BUILD_WITH_LIBSECRET */ +-- +2.21.3 + diff --git a/SOURCES/0028-cache_req-allow-cache_req-to-return-ERR_OFFLINE-if-a.patch b/SOURCES/0028-cache_req-allow-cache_req-to-return-ERR_OFFLINE-if-a.patch new file mode 100644 index 0000000..dae8746 --- /dev/null +++ b/SOURCES/0028-cache_req-allow-cache_req-to-return-ERR_OFFLINE-if-a.patch @@ -0,0 +1,100 @@ +From 3f0ba4c2dcf9126b0f94bca4a056b516759d25c1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 6 Mar 2020 12:49:04 +0100 +Subject: [PATCH 13/18] cache_req: allow cache_req to return ERR_OFFLINE if all + dp request failed + +Reviewed-by: Alexey Tikhonov +--- + src/responder/common/cache_req/cache_req.c | 13 +++++++++++++ + src/responder/common/cache_req/cache_req.h | 4 ++++ + src/responder/common/cache_req/cache_req_data.c | 12 ++++++++++++ + src/responder/common/cache_req/cache_req_private.h | 3 +++ + 4 files changed, 32 insertions(+) + +diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c +index afb0e7cda..0c8538414 100644 +--- a/src/responder/common/cache_req/cache_req.c ++++ b/src/responder/common/cache_req/cache_req.c +@@ -974,6 +974,13 @@ static void cache_req_search_domains_done(struct tevent_req *subreq) + case ERR_ID_OUTSIDE_RANGE: + case ENOENT: + if (state->check_next == false) { ++ if (state->cr->data->propogate_offline_status && !state->dp_success) { ++ /* Not found and data provider request failed so we were ++ * unable to fetch the data. */ ++ ret = ERR_OFFLINE; ++ goto done; ++ } ++ + /* Not found. */ + ret = ENOENT; + goto done; +@@ -1002,6 +1009,12 @@ done: + case EAGAIN: + break; + default: ++ if (ret == ENOENT && state->cr->data->propogate_offline_status ++ && !state->dp_success) { ++ /* Not found and data provider request failed so we were ++ * unable to fetch the data. */ ++ ret = ERR_OFFLINE; ++ } + tevent_req_error(req, ret); + break; + } +diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h +index 72d4abe5e..d36cb2d3b 100644 +--- a/src/responder/common/cache_req/cache_req.h ++++ b/src/responder/common/cache_req/cache_req.h +@@ -171,6 +171,10 @@ void + cache_req_data_set_requested_domains(struct cache_req_data *data, + char **requested_domains); + ++void ++cache_req_data_set_propogate_offline_status(struct cache_req_data *data, ++ bool propogate_offline_status); ++ + enum cache_req_type + cache_req_data_get_type(struct cache_req_data *data); + +diff --git a/src/responder/common/cache_req/cache_req_data.c b/src/responder/common/cache_req/cache_req_data.c +index 14c4ad14f..fe9f3db29 100644 +--- a/src/responder/common/cache_req/cache_req_data.c ++++ b/src/responder/common/cache_req/cache_req_data.c +@@ -455,6 +455,18 @@ cache_req_data_set_requested_domains(struct cache_req_data *data, + data->requested_domains = requested_domains; + } + ++void ++cache_req_data_set_propogate_offline_status(struct cache_req_data *data, ++ bool propogate_offline_status) ++{ ++ if (data == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_data should never be NULL\n"); ++ return; ++ } ++ ++ data->propogate_offline_status = propogate_offline_status; ++} ++ + enum cache_req_type + cache_req_data_get_type(struct cache_req_data *data) + { +diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h +index bfca688b9..2d52e7600 100644 +--- a/src/responder/common/cache_req/cache_req_private.h ++++ b/src/responder/common/cache_req/cache_req_private.h +@@ -103,6 +103,9 @@ struct cache_req_data { + + /* if set, only search in the listed domains */ + char **requested_domains; ++ ++ /* if set, ERR_OFFLINE is returned if data provider is offline */ ++ bool propogate_offline_status; + }; + + struct tevent_req * +-- +2.21.3 + diff --git a/SOURCES/0029-autofs-return-ERR_OFFLINE-if-we-fail-to-get-informat.patch b/SOURCES/0029-autofs-return-ERR_OFFLINE-if-we-fail-to-get-informat.patch new file mode 100644 index 0000000..f29ff36 --- /dev/null +++ b/SOURCES/0029-autofs-return-ERR_OFFLINE-if-we-fail-to-get-informat.patch @@ -0,0 +1,58 @@ +From e50258da70b67ff1b0f928e2e7875bc2fa32dfde Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 6 Mar 2020 13:12:46 +0100 +Subject: [PATCH 14/18] autofs: return ERR_OFFLINE if we fail to get + information from backend and cache is empty + +Resolves: +https://github.com/SSSD/sssd/issues/3413 + +Reviewed-by: Alexey Tikhonov +--- + .../common/cache_req/plugins/cache_req_autofs_entry_by_name.c | 2 ++ + .../common/cache_req/plugins/cache_req_autofs_map_by_name.c | 2 ++ + .../common/cache_req/plugins/cache_req_autofs_map_entries.c | 2 ++ + 3 files changed, 6 insertions(+) + +diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c +index cb674add6..55c9fc8b0 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c +@@ -142,6 +142,8 @@ cache_req_autofs_entry_by_name_send(TALLOC_CTX *mem_ctx, + return NULL; + } + ++ cache_req_data_set_propogate_offline_status(data, true); ++ + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, + cache_refresh_percent, + CACHE_REQ_POSIX_DOM, domain, +diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c +index 3c08eaf4f..823eb3595 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c +@@ -136,6 +136,8 @@ cache_req_autofs_map_by_name_send(TALLOC_CTX *mem_ctx, + return NULL; + } + ++ cache_req_data_set_propogate_offline_status(data, true); ++ + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, + cache_refresh_percent, + CACHE_REQ_POSIX_DOM, domain, +diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c +index 1b5645fa0..3e47b1321 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c ++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c +@@ -168,6 +168,8 @@ cache_req_autofs_map_entries_send(TALLOC_CTX *mem_ctx, + return NULL; + } + ++ cache_req_data_set_propogate_offline_status(data, true); ++ + return cache_req_steal_data_and_send(mem_ctx, ev, rctx, ncache, + cache_refresh_percent, + CACHE_REQ_POSIX_DOM, domain, +-- +2.21.3 + diff --git a/SOURCES/0030-autofs-translate-ERR_OFFLINE-to-EHOSTDOWN.patch b/SOURCES/0030-autofs-translate-ERR_OFFLINE-to-EHOSTDOWN.patch new file mode 100644 index 0000000..c605483 --- /dev/null +++ b/SOURCES/0030-autofs-translate-ERR_OFFLINE-to-EHOSTDOWN.patch @@ -0,0 +1,51 @@ +From 9098108a7142513fa04afdf92a2c1b3ac002c56e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 6 Mar 2020 13:44:56 +0100 +Subject: [PATCH 15/18] autofs: translate ERR_OFFLINE to EHOSTDOWN + +So we do not publish internal error code. + +Resolves: +https://github.com/SSSD/sssd/issues/3413 + +Reviewed-by: Alexey Tikhonov +--- + src/sss_client/common.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/src/sss_client/common.c b/src/sss_client/common.c +index 902438c86..d29332939 100644 +--- a/src/sss_client/common.c ++++ b/src/sss_client/common.c +@@ -44,6 +44,7 @@ + #define _(STRING) dgettext (PACKAGE, STRING) + #include "sss_cli.h" + #include "common_private.h" ++#include "util/util_errors.h" + + #if HAVE_PTHREAD + #include +@@ -1054,9 +1055,17 @@ int sss_autofs_make_request(enum sss_cli_command cmd, + uint8_t **repbuf, size_t *replen, + int *errnop) + { +- return sss_cli_make_request_with_checks(cmd, rd, SSS_CLI_SOCKET_TIMEOUT, +- repbuf, replen, errnop, +- SSS_AUTOFS_SOCKET_NAME); ++ enum sss_status status; ++ ++ status = sss_cli_make_request_with_checks(cmd, rd, SSS_CLI_SOCKET_TIMEOUT, ++ repbuf, replen, errnop, ++ SSS_AUTOFS_SOCKET_NAME); ++ ++ if (*errnop == ERR_OFFLINE) { ++ *errnop = EHOSTDOWN; ++ } ++ ++ return status; + } + + int sss_ssh_make_request(enum sss_cli_command cmd, +-- +2.21.3 + diff --git a/SOURCES/0031-autofs-disable-fast-reply.patch b/SOURCES/0031-autofs-disable-fast-reply.patch new file mode 100644 index 0000000..8706aec --- /dev/null +++ b/SOURCES/0031-autofs-disable-fast-reply.patch @@ -0,0 +1,61 @@ +From 34c519a4851194164befc150df8e768431e66405 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 22 Sep 2020 11:04:25 +0200 +Subject: [PATCH 16/18] autofs: disable fast reply + +If the backend is offline when autofs starts and reads auto.master map +we don't want to wait 60 seconds before the offline flag is reset. We +need to allow autofs to retry the call much sooner. + +Resolves: +https://github.com/SSSD/sssd/issues/3413 + +Reviewed-by: Alexey Tikhonov +--- + .../common/cache_req/plugins/cache_req_autofs_entry_by_name.c | 2 +- + .../common/cache_req/plugins/cache_req_autofs_map_by_name.c | 2 +- + .../common/cache_req/plugins/cache_req_autofs_map_entries.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c +index 55c9fc8b0..cd2085187 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c +@@ -84,7 +84,7 @@ cache_req_autofs_entry_by_name_dp_send(TALLOC_CTX *mem_ctx, + + return sbus_call_dp_autofs_GetEntry_send(mem_ctx, be_conn->conn, + be_conn->bus_name, SSS_BUS_PATH, +- DP_FAST_REPLY, data->name.name, ++ 0, data->name.name, + data->autofs_entry_name); + } + +diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c +index 823eb3595..9d9bc3a97 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c +@@ -81,7 +81,7 @@ cache_req_autofs_map_by_name_dp_send(TALLOC_CTX *mem_ctx, + + return sbus_call_dp_autofs_GetMap_send(mem_ctx, be_conn->conn, + be_conn->bus_name, SSS_BUS_PATH, +- DP_FAST_REPLY, data->name.name); ++ 0, data->name.name); + } + + bool +diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c +index 3e47b1321..ee0156b6a 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c ++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c +@@ -113,7 +113,7 @@ cache_req_autofs_map_entries_dp_send(TALLOC_CTX *mem_ctx, + + return sbus_call_dp_autofs_Enumerate_send(mem_ctx, be_conn->conn, + be_conn->bus_name, SSS_BUS_PATH, +- DP_FAST_REPLY, data->name.name); ++ 0, data->name.name); + } + + bool +-- +2.21.3 + diff --git a/SOURCES/0032-autofs-correlate-errors-for-different-protocol-versi.patch b/SOURCES/0032-autofs-correlate-errors-for-different-protocol-versi.patch new file mode 100644 index 0000000..9188a5e --- /dev/null +++ b/SOURCES/0032-autofs-correlate-errors-for-different-protocol-versi.patch @@ -0,0 +1,168 @@ +From 8a22d4ad45f5fc8e888be693539495093c2b3c35 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 4 Nov 2020 14:20:10 +0100 +Subject: [PATCH 17/18] autofs: correlate errors for different protocol + versions + +Reviewed-by: Alexey Tikhonov +--- + src/sss_client/autofs/autofs_test_client.c | 12 ++++++++ + src/sss_client/autofs/sss_autofs.c | 35 +++++++++++++++++++--- + src/sss_client/autofs/sss_autofs.exports | 9 +++--- + src/sss_client/autofs/sss_autofs_private.h | 5 ++++ + 4 files changed, 53 insertions(+), 8 deletions(-) + +diff --git a/src/sss_client/autofs/autofs_test_client.c b/src/sss_client/autofs/autofs_test_client.c +index c5358233f..4b285151e 100644 +--- a/src/sss_client/autofs/autofs_test_client.c ++++ b/src/sss_client/autofs/autofs_test_client.c +@@ -45,10 +45,14 @@ int main(int argc, const char *argv[]) + char *value = NULL; + char *pc_key = NULL; + int pc_setent = 0; ++ int pc_protocol = 1; ++ unsigned int protocol; ++ unsigned int requested_protocol = 1; + struct poptOption long_options[] = { + POPT_AUTOHELP + { "by-name", 'n', POPT_ARG_STRING, &pc_key, 0, "Request map by name", NULL }, + { "only-setent", 's', POPT_ARG_VAL, &pc_setent, 1, "Run only setent, do not enumerate", NULL }, ++ { "protocol", 'p', POPT_ARG_INT, &pc_protocol, 0, "Protocol version", NULL }, + POPT_TABLEEND + }; + poptContext pc = NULL; +@@ -69,6 +73,14 @@ int main(int argc, const char *argv[]) + + poptFreeContext(pc); + ++ requested_protocol = pc_protocol; ++ protocol = _sss_auto_protocol_version(requested_protocol); ++ if (protocol != requested_protocol) { ++ fprintf(stderr, "Unsupported protocol version: %d -> %d\n", ++ requested_protocol, protocol); ++ exit(EXIT_FAILURE); ++ } ++ + ret = _sss_setautomntent(mapname, &ctx); + if (ret) { + fprintf(stderr, "setautomntent failed [%d]: %s\n", +diff --git a/src/sss_client/autofs/sss_autofs.c b/src/sss_client/autofs/sss_autofs.c +index 482ff2c40..ef27cf895 100644 +--- a/src/sss_client/autofs/sss_autofs.c ++++ b/src/sss_client/autofs/sss_autofs.c +@@ -20,6 +20,7 @@ + + #include + #include ++#include + + #include "sss_client/autofs/sss_autofs_private.h" + #include "sss_client/sss_cli.h" +@@ -33,6 +34,32 @@ + /* How many entries shall _sss_getautomntent_r retrieve at once */ + #define GETAUTOMNTENT_MAX_ENTRIES 512 + ++static atomic_uint _protocol = 0; ++ ++unsigned int _sss_auto_protocol_version(unsigned int requested) ++{ ++ switch (requested) { ++ case 0: ++ /* EHOSTDOWN will be translated to ENOENT */ ++ _protocol = 0; ++ return 0; ++ default: ++ /* There is no other protocol version at this point. */ ++ _protocol = 1; ++ return 1; ++ } ++} ++ ++/* Returns correct errno based on autofs version expectations. */ ++static errno_t errnop_to_errno(int errnop) ++{ ++ if (errnop == EHOSTDOWN && _protocol == 0) { ++ return ENOENT; ++ } ++ ++ return errnop; ++} ++ + struct automtent { + char *mapname; + size_t cursor; +@@ -93,7 +120,7 @@ _sss_setautomntent(const char *mapname, void **context) + &repbuf, &replen, &errnop); + if (ret != SSS_STATUS_SUCCESS) { + free(name); +- ret = errnop; ++ ret = errnop_to_errno(errnop); + goto out; + } + +@@ -310,7 +337,7 @@ _sss_getautomntent_r(char **key, char **value, void *context) + &repbuf, &replen, &errnop); + free(data); + if (ret != SSS_STATUS_SUCCESS) { +- ret = errnop; ++ ret = errnop_to_errno(errnop); + goto out; + } + +@@ -408,7 +435,7 @@ _sss_getautomntbyname_r(const char *key, char **value, void *context) + &repbuf, &replen, &errnop); + free(data); + if (ret != SSS_STATUS_SUCCESS) { +- ret = errnop; ++ ret = errnop_to_errno(errnop); + goto out; + } + +@@ -467,7 +494,7 @@ _sss_endautomntent(void **context) + ret = sss_autofs_make_request(SSS_AUTOFS_ENDAUTOMNTENT, + NULL, NULL, NULL, &errnop); + if (ret != SSS_STATUS_SUCCESS) { +- ret = errnop; ++ ret = errnop_to_errno(errnop); + goto out; + } + +diff --git a/src/sss_client/autofs/sss_autofs.exports b/src/sss_client/autofs/sss_autofs.exports +index f9ce8f5b2..ec61f715e 100644 +--- a/src/sss_client/autofs/sss_autofs.exports ++++ b/src/sss_client/autofs/sss_autofs.exports +@@ -2,10 +2,11 @@ EXPORTED { + + # public functions + global: +- _sss_setautomntent; +- _sss_getautomntent_r; +- _sss_getautomntbyname_r; +- _sss_endautomntent; ++ _sss_auto_protocol_version; ++ _sss_setautomntent; ++ _sss_getautomntent_r; ++ _sss_getautomntbyname_r; ++ _sss_endautomntent; + + # everything else is local + local: +diff --git a/src/sss_client/autofs/sss_autofs_private.h b/src/sss_client/autofs/sss_autofs_private.h +index 6459c1cc7..7fd49db1d 100644 +--- a/src/sss_client/autofs/sss_autofs_private.h ++++ b/src/sss_client/autofs/sss_autofs_private.h +@@ -21,6 +21,11 @@ + #include + #include "util/util.h" + ++/** ++ * Choose an autofs protocol version to be used between autofs and sss_autofs. ++ */ ++unsigned int _sss_auto_protocol_version(unsigned int requested); ++ + /** + * Selects a map for processing. + */ +-- +2.21.3 + diff --git a/SOURCES/0033-configure-check-for-stdatomic.h.patch b/SOURCES/0033-configure-check-for-stdatomic.h.patch new file mode 100644 index 0000000..699c3f6 --- /dev/null +++ b/SOURCES/0033-configure-check-for-stdatomic.h.patch @@ -0,0 +1,28 @@ +From 075519bceca7a8f4fa28a0b7c538f2f50d552d13 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 26 Nov 2020 14:56:08 +0100 +Subject: [PATCH 18/18] configure: check for stdatomic.h + +Recent autofs patches adds dependency on automic_uint/_Atomic type from C11 +standard. This is supported in both gcc and clang for a long time now. + +Reviewed-by: Alexey Tikhonov +--- + configure.ac | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/configure.ac b/configure.ac +index 1af1d1785..0d24c4b35 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -42,6 +42,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) + AM_CONDITIONAL([HAVE_GCC], [test "$ac_cv_prog_gcc" = yes]) + + AC_CHECK_HEADERS(stdint.h dlfcn.h) ++AC_CHECK_HEADERS([stdatomic.h],,AC_MSG_ERROR([C11 atomic types are not supported])) + AC_CONFIG_HEADER(config.h) + + AC_CHECK_TYPES([errno_t], [], [], [[#include ]]) +-- +2.21.3 + diff --git a/SOURCES/0034-cache_req-ignore-autofs-not-configured-error.patch b/SOURCES/0034-cache_req-ignore-autofs-not-configured-error.patch new file mode 100644 index 0000000..5181137 --- /dev/null +++ b/SOURCES/0034-cache_req-ignore-autofs-not-configured-error.patch @@ -0,0 +1,131 @@ +From 2499bd145f566bfd73b8c7e284b910dd2b36c6d1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 15 Jan 2021 12:04:38 +0100 +Subject: [PATCH] cache_req: ignore autofs not configured error + +Otherwise we return ERR_OFFLINE for domains where autofs provider is not +set (such as implicit files domain) which is undesirable. + +Steps to reproduce: +1. Enable implicit files domains and LDAP domain with autofs configured +2. Setup NFS server to export `/exports` with `/exports/home/test` +3. Add autofs mount points: +``` +dn: ou=mount,dc=ldap,dc=vm +ou: mount +objectClass: organizationalUnit +objectClass: top + +dn: nisMapName=auto.master,ou=mount,dc=ldap,dc=vm +objectClass: nisMap +objectClass: top +nisMapName: auto.master + +dn: cn=/export/home,nisMapName=auto.master,ou=mount,dc=ldap,dc=vm +objectClass: nisObject +objectClass: top +cn: /export/home +nisMapEntry: auto.home +nisMapName: auto.master + +dn: nisMapName=auto.home,ou=mount,dc=ldap,dc=vm +objectClass: nisMap +objectClass: top +nisMapName: auto.home + +dn: cn=/,nisMapName=auto.home,ou=mount,dc=ldap,dc=vm +objectClass: nisObject +objectClass: top +cn: / +nisMapEntry: -fstype=nfs,rw master.ldap.vm:/export/home/& +nisMapName: auto.home +``` +4. Run SSSD and autofs +5. cd to /exports/home/test + +The directory will not be mounted with the new autofs protocol. It +will succeed with the old protocol. In both versions, you'll see +that SSSD returned ERR_OFFLINE: + +``` +(2021-01-15 11:44:48): [be[implicit_files]] [sbus_issue_request_done] (0x0040): sssd.DataProvider.Autofs.GetEntry: Error [1432158215]: DP target is not configured +... +(2021-01-15 11:44:49): [autofs] [cache_req_search_cache] (0x0400): CR #3: Looking up [auto.home:test] in cache +(2021-01-15 11:44:49): [autofs] [cache_req_search_cache] (0x0400): CR #3: Object [auto.home:test] was not found in cache +(2021-01-15 11:44:49): [autofs] [cache_req_search_ncache_add_to_domain] (0x2000): CR #3: This request type does not support negative cache +(2021-01-15 11:44:49): [autofs] [cache_req_process_result] (0x0400): CR #3: Finished: Error 1432158212: SSSD is offline +``` + +Reviewed-by: Alexey Tikhonov +--- + .../cache_req/plugins/cache_req_autofs_entry_by_name.c | 10 +++++++++- + .../cache_req/plugins/cache_req_autofs_map_by_name.c | 10 +++++++++- + .../cache_req/plugins/cache_req_autofs_map_entries.c | 10 +++++++++- + 3 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c +index cd2085187..f411fd351 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_entry_by_name.c +@@ -92,7 +92,15 @@ bool + cache_req_autofs_entry_by_name_dp_recv(struct tevent_req *subreq, + struct cache_req *cr) + { +- return sbus_call_dp_autofs_GetEntry_recv(subreq) == EOK; ++ errno_t ret; ++ ++ ret = sbus_call_dp_autofs_GetEntry_recv(subreq); ++ ++ if (ret == ERR_MISSING_DP_TARGET) { ++ ret = EOK; ++ } ++ ++ return ret == EOK; + } + + const struct cache_req_plugin cache_req_autofs_entry_by_name = { +diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c +index 9d9bc3a97..c22cf0c8e 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c ++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_by_name.c +@@ -88,7 +88,15 @@ bool + cache_req_autofs_map_by_name_dp_recv(struct tevent_req *subreq, + struct cache_req *cr) + { +- return sbus_call_dp_autofs_GetMap_recv(subreq) == EOK; ++ errno_t ret; ++ ++ ret = sbus_call_dp_autofs_GetMap_recv(subreq); ++ ++ if (ret == ERR_MISSING_DP_TARGET) { ++ ret = EOK; ++ } ++ ++ return ret == EOK; + } + + const struct cache_req_plugin cache_req_autofs_map_by_name = { +diff --git a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c +index ee0156b6a..4d9db6595 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c ++++ b/src/responder/common/cache_req/plugins/cache_req_autofs_map_entries.c +@@ -120,7 +120,15 @@ bool + cache_req_autofs_map_entries_dp_recv(struct tevent_req *subreq, + struct cache_req *cr) + { +- return sbus_call_dp_autofs_Enumerate_recv(subreq) == EOK; ++ errno_t ret; ++ ++ ret = sbus_call_dp_autofs_Enumerate_recv(subreq); ++ ++ if (ret == ERR_MISSING_DP_TARGET) { ++ ret = EOK; ++ } ++ ++ return ret == EOK; + } + + const struct cache_req_plugin cache_req_autofs_map_entries = { +-- +2.21.3 + diff --git a/SOURCES/0035-simple-fix-memory-leak-while-reloading-lists.patch b/SOURCES/0035-simple-fix-memory-leak-while-reloading-lists.patch new file mode 100644 index 0000000..5cd16fa --- /dev/null +++ b/SOURCES/0035-simple-fix-memory-leak-while-reloading-lists.patch @@ -0,0 +1,100 @@ +From 19c2c641e669ee1c08d6706c132625dc30e64609 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 12 Jan 2021 16:40:56 +0100 +Subject: [PATCH] simple: fix memory leak while reloading lists + +The simple access provider will reload the access and deny lists at +runtime to make sure that users and groups from domains which are +discovered at runtime are properly processed. + +While reloading the lists the original lists are not freed and an +intermediate list wasn't removed as well. + +Resolves: https://github.com/SSSD/sssd/issues/5456 + +:fixes: Memory leak in the simple access provider + +Reviewed-by: Alexey Tikhonov +--- + src/providers/simple/simple_access.c | 28 +++++++++++++++++++++------- + 1 file changed, 21 insertions(+), 7 deletions(-) + +diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c +index 1868569b1..49226adf2 100644 +--- a/src/providers/simple/simple_access.c ++++ b/src/providers/simple/simple_access.c +@@ -117,17 +117,13 @@ int simple_access_obtain_filter_lists(struct simple_ctx *ctx) + const char *name; + const char *option; + char **orig_list; +- char ***ctx_list; ++ char **ctx_list; + } lists[] = {{"Allow users", CONFDB_SIMPLE_ALLOW_USERS, NULL, NULL}, + {"Deny users", CONFDB_SIMPLE_DENY_USERS, NULL, NULL}, + {"Allow groups", CONFDB_SIMPLE_ALLOW_GROUPS, NULL, NULL}, + {"Deny groups", CONFDB_SIMPLE_DENY_GROUPS, NULL, NULL}, + {NULL, NULL, NULL, NULL}}; + +- lists[0].ctx_list = &ctx->allow_users; +- lists[1].ctx_list = &ctx->deny_users; +- lists[2].ctx_list = &ctx->allow_groups; +- lists[3].ctx_list = &ctx->deny_groups; + + ret = sysdb_master_domain_update(bectx->domain); + if (ret != EOK) { +@@ -141,7 +137,6 @@ int simple_access_obtain_filter_lists(struct simple_ctx *ctx) + lists[i].option, &lists[i].orig_list); + if (ret == ENOENT) { + DEBUG(SSSDBG_FUNC_DATA, "%s list is empty.\n", lists[i].name); +- *lists[i].ctx_list = NULL; + continue; + } else if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "confdb_get_string_as_list failed.\n"); +@@ -149,7 +144,8 @@ int simple_access_obtain_filter_lists(struct simple_ctx *ctx) + } + + ret = simple_access_parse_names(ctx, bectx, lists[i].orig_list, +- lists[i].ctx_list); ++ &lists[i].ctx_list); ++ talloc_free(lists[i].orig_list); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse %s list [%d]: %s\n", + lists[i].name, ret, sss_strerror(ret)); +@@ -157,6 +153,18 @@ int simple_access_obtain_filter_lists(struct simple_ctx *ctx) + } + } + ++ talloc_free(ctx->allow_users); ++ ctx->allow_users = talloc_steal(ctx, lists[0].ctx_list); ++ ++ talloc_free(ctx->deny_users); ++ ctx->deny_users = talloc_steal(ctx, lists[1].ctx_list); ++ ++ talloc_free(ctx->allow_groups); ++ ctx->allow_groups = talloc_steal(ctx, lists[2].ctx_list); ++ ++ talloc_free(ctx->deny_groups); ++ ctx->deny_groups = talloc_steal(ctx, lists[3].ctx_list); ++ + if (!ctx->allow_users && + !ctx->allow_groups && + !ctx->deny_users && +@@ -165,9 +173,15 @@ int simple_access_obtain_filter_lists(struct simple_ctx *ctx) + "No rules supplied for simple access provider. " + "Access will be granted for all users.\n"); + } ++ ++ + return EOK; + + failed: ++ for (i = 0; lists[i].name != NULL; i++) { ++ talloc_free(lists[i].ctx_list); ++ } ++ + return ret; + } + +-- +2.21.3 + diff --git a/SOURCES/0036-SBUS-do-not-try-to-del-non-existing-sender.patch b/SOURCES/0036-SBUS-do-not-try-to-del-non-existing-sender.patch new file mode 100644 index 0000000..d432682 --- /dev/null +++ b/SOURCES/0036-SBUS-do-not-try-to-del-non-existing-sender.patch @@ -0,0 +1,38 @@ +From bdf461c7577c458d7b2a785b2007c0ccae73e3f7 Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Mon, 11 Jan 2021 18:28:02 +0100 +Subject: [PATCH] SBUS: do not try to del non existing sender +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves: https://github.com/SSSD/sssd/issues/5425 + +Reviewed-by: Pavel Březina +--- + src/sbus/request/sbus_request_sender.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/sbus/request/sbus_request_sender.c b/src/sbus/request/sbus_request_sender.c +index cecb188b0..39cdec064 100644 +--- a/src/sbus/request/sbus_request_sender.c ++++ b/src/sbus/request/sbus_request_sender.c +@@ -101,10 +101,11 @@ void + sbus_senders_delete(hash_table_t *table, + const char *name) + { +- DEBUG(SSSDBG_TRACE_INTERNAL, "Removing identity of sender [%s]\n", +- name); +- +- sss_ptr_hash_delete(table, name, true); ++ if (sss_ptr_hash_has_key(table, name)) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Removing identity of sender [%s]\n", ++ name); ++ sss_ptr_hash_delete(table, name, true); ++ } + } + + errno_t +-- +2.21.3 + diff --git a/SOURCES/0037-pamsrv_gssapi-fix-implicit-conversion-warning.patch b/SOURCES/0037-pamsrv_gssapi-fix-implicit-conversion-warning.patch new file mode 100644 index 0000000..cb06e15 --- /dev/null +++ b/SOURCES/0037-pamsrv_gssapi-fix-implicit-conversion-warning.patch @@ -0,0 +1,34 @@ +From c0ae6d34ff7c170ca0e6d0faa8a2daf9a77becb7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 8 Jan 2021 14:00:47 +0100 +Subject: [PATCH] pamsrv_gssapi: fix implicit conversion warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +src/responder/pam/pamsrv_gssapi.c: In function ‘pam_cmd_gssapi_sec_ctx’: +src/responder/pam/pamsrv_gssapi.c:716:64: error: implicit conversion from ‘enum sss_domain_type’ to ‘enum cache_req_dom_type’ [-Werror=enum-conversion] + 716 | cli_ctx->rctx->ncache, 0, DOM_TYPE_POSIX, + +Reviewed-by: Alexey Tikhonov +--- + src/responder/pam/pamsrv_gssapi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/responder/pam/pamsrv_gssapi.c b/src/responder/pam/pamsrv_gssapi.c +index 099675e1c..2d05c7888 100644 +--- a/src/responder/pam/pamsrv_gssapi.c ++++ b/src/responder/pam/pamsrv_gssapi.c +@@ -713,7 +713,8 @@ pam_cmd_gssapi_sec_ctx(struct cli_ctx *cli_ctx) + DEBUG(SSSDBG_TRACE_FUNC, "Checking that target user matches UPN\n"); + + req = cache_req_user_by_upn_send(cli_ctx, cli_ctx->ev, cli_ctx->rctx, +- cli_ctx->rctx->ncache, 0, DOM_TYPE_POSIX, ++ cli_ctx->rctx->ncache, 0, ++ CACHE_REQ_POSIX_DOM, + domain->name, state->authenticated_upn); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); +-- +2.21.3 + diff --git a/SOURCES/0038-gssapi-default-pam_gssapi_services-to-NULL-in-domain.patch b/SOURCES/0038-gssapi-default-pam_gssapi_services-to-NULL-in-domain.patch new file mode 100644 index 0000000..d4ea08c --- /dev/null +++ b/SOURCES/0038-gssapi-default-pam_gssapi_services-to-NULL-in-domain.patch @@ -0,0 +1,34 @@ +From cc173629f30fbc885ee90e52a205554b118e0ee6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Mon, 11 Jan 2021 13:11:39 +0100 +Subject: [PATCH 38/39] gssapi: default pam_gssapi_services to NULL in domain + section + +We need to distinguish when the option is not set in domain section and when +it is is explicitly disabled. Now if it is not set, domain->gssapi_services +is NULL and we'll use value from the pam section. + +Without this change, the value in the pam section is ignored. + +Reviewed-by: Alexey Tikhonov +Reviewed-by: Sumit Bose +--- + src/confdb/confdb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index 2881ce5da..befcfff2d 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -1582,7 +1582,7 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, + } + + tmp = ldb_msg_find_attr_as_string(res->msgs[0], CONFDB_PAM_GSSAPI_SERVICES, +- "-"); ++ NULL); + if (tmp != NULL) { + ret = split_on_separator(domain, tmp, ',', true, true, + &domain->gssapi_services, NULL); +-- +2.21.3 + diff --git a/SOURCES/0039-pam_sss_gssapi-fix-coverity-issues.patch b/SOURCES/0039-pam_sss_gssapi-fix-coverity-issues.patch new file mode 100644 index 0000000..cd37baf --- /dev/null +++ b/SOURCES/0039-pam_sss_gssapi-fix-coverity-issues.patch @@ -0,0 +1,133 @@ +From 111b8b4d62a4fe192c075e6f6bfacb408e6074b3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 12 Jan 2021 13:50:11 +0100 +Subject: [PATCH 39/39] pam_sss_gssapi: fix coverity issues +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +``` +1. Defect type: RESOURCE_LEAK +7. sssd-2.4.0/src/sss_client/pam_sss_gss.c:556: leaked_storage: Variable "username" going out of scope leaks the storage it points to. +Expand +2. Defect type: RESOURCE_LEAK +3. sssd-2.4.0/src/sss_client/pam_sss_gss.c:321: leaked_storage: Variable "reply" going out of scope leaks the storage it points to. +Expand +3. Defect type: RESOURCE_LEAK +7. sssd-2.4.0/src/sss_client/pam_sss_gss.c:260: leaked_storage: Variable "username" going out of scope leaks the storage it points to. +Expand +4. Defect type: RESOURCE_LEAK +6. sssd-2.4.0/src/sss_client/pam_sss_gss.c:260: leaked_storage: Variable "upn" going out of scope leaks the storage it points to. +Expand +5. Defect type: RESOURCE_LEAK +7. sssd-2.4.0/src/sss_client/pam_sss_gss.c:260: leaked_storage: Variable "target" going out of scope leaks the storage it points to. +Expand +6. Defect type: RESOURCE_LEAK +7. sssd-2.4.0/src/sss_client/pam_sss_gss.c:260: leaked_storage: Variable "domain" going out of scope leaks the storage it points to. + +1. Defect type: CLANG_WARNING +1. sssd-2.4.0/src/sss_client/pam_sss_gss.c:260:16: warning[unix.Malloc]: Potential leak of memory pointed to by 'username' +Expand +2. Defect type: CLANG_WARNING +1. sssd-2.4.0/src/sss_client/pam_sss_gss.c:260:16: warning[unix.Malloc]: Potential leak of memory pointed to by 'upn' +Expand +3. Defect type: CLANG_WARNING +1. sssd-2.4.0/src/sss_client/pam_sss_gss.c:260:16: warning[unix.Malloc]: Potential leak of memory pointed to by 'target' +Expand +4. Defect type: CLANG_WARNING +1. sssd-2.4.0/src/sss_client/pam_sss_gss.c:260:16: warning[unix.Malloc]: Potential leak of memory pointed to by 'domain' +``` + +Also fix compilation warning +``` +../src/sss_client/pam_sss_gss.c:339:5: warning: ‘reply’ may be used uninitialized in this function [-Wmaybe-uninitialized] + 339 | free(reply); + | ^~~~~~~~~~~ +../src/sss_client/pam_sss_gss.c:328:14: note: ‘reply’ was declared here + 328 | uint8_t *reply; + | ^~~~~ +../src/sss_client/pam_sss_gss.c:270:11: warning: ‘reply_len’ may be used uninitialized in this function [-Wmaybe-uninitialized] + 270 | upn = malloc(reply_len * sizeof(char)); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +../src/sss_client/pam_sss_gss.c:327:12: note: ‘reply_len’ was declared here + 327 | size_t reply_len; + | ^~~~~~~~~ +``` + +Reviewed-by: Alexey Tikhonov +Reviewed-by: Sumit Bose +--- + src/sss_client/pam_sss_gss.c | 22 ++++++++++++++++++---- + 1 file changed, 18 insertions(+), 4 deletions(-) + +diff --git a/src/sss_client/pam_sss_gss.c b/src/sss_client/pam_sss_gss.c +index cd38db7da..51be36ece 100644 +--- a/src/sss_client/pam_sss_gss.c ++++ b/src/sss_client/pam_sss_gss.c +@@ -195,6 +195,8 @@ static errno_t sssd_gssapi_init_send(pam_handle_t *pamh, + struct sss_cli_req_data req_data; + size_t service_len; + size_t user_len; ++ size_t reply_len; ++ uint8_t *reply = NULL; + uint8_t *data; + errno_t ret; + int ret_errno; +@@ -217,7 +219,7 @@ static errno_t sssd_gssapi_init_send(pam_handle_t *pamh, + + req_data.data = data; + +- ret = sss_pam_make_request(SSS_GSSAPI_INIT, &req_data, _reply, _reply_len, ++ ret = sss_pam_make_request(SSS_GSSAPI_INIT, &req_data, &reply, &reply_len, + &ret_errno); + free(data); + if (ret != PAM_SUCCESS) { +@@ -233,6 +235,16 @@ static errno_t sssd_gssapi_init_send(pam_handle_t *pamh, + return (ret_errno != EOK) ? ret_errno : EIO; + } + ++ if (ret_errno == EOK) { ++ *_reply = reply; ++ *_reply_len = reply_len; ++ } else { ++ /* We got PAM_SUCCESS therefore the communication with SSSD was ++ * successful and we have received a reply buffer. We just don't care ++ * about it, we are only interested in the error code. */ ++ free(reply); ++ } ++ + return ret_errno; + } + +@@ -257,7 +269,8 @@ static errno_t sssd_gssapi_init_recv(uint8_t *reply, + target = malloc(reply_len * sizeof(char)); + upn = malloc(reply_len * sizeof(char)); + if (username == NULL || domain == NULL || target == NULL || upn == NULL) { +- return ENOMEM; ++ ret = ENOMEM; ++ goto done; + } + + buf = (const char*)reply; +@@ -311,8 +324,8 @@ static errno_t sssd_gssapi_init(pam_handle_t *pamh, + char **_target, + char **_upn) + { +- size_t reply_len; +- uint8_t *reply; ++ size_t reply_len = 0; ++ uint8_t *reply = NULL; + errno_t ret; + + ret = sssd_gssapi_init_send(pamh, pam_service, pam_user, &reply, +@@ -549,6 +562,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, + + done: + sss_pam_close_fd(); ++ free(username); + free(domain); + free(target); + free(upn); +-- +2.21.3 + diff --git a/SOURCES/0040-sudo-runas-do-not-add-to-external-groups-in-IPA.patch b/SOURCES/0040-sudo-runas-do-not-add-to-external-groups-in-IPA.patch new file mode 100644 index 0000000..ca3d905 --- /dev/null +++ b/SOURCES/0040-sudo-runas-do-not-add-to-external-groups-in-IPA.patch @@ -0,0 +1,40 @@ +From cd48ef5071741443e3b84e100a4d4d28e3578e4f Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Mon, 25 Jan 2021 15:14:05 +0200 +Subject: [PATCH] sudo runas: do not add '%' to external groups in IPA +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When IPA allows to add AD users and groups directly to sudo rules +(FreeIPA 4.9.1 or later), external groups will already have '%' prefix. +Thus, we don't need to add additional '%'. + +Resolves: https://github.com/SSSD/sssd/issues/5475 +Signed-off-by: Alexander Bokovoy + +Reviewed-by: Pavel Březina +--- + src/providers/ipa/ipa_sudo_conversion.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/providers/ipa/ipa_sudo_conversion.c b/src/providers/ipa/ipa_sudo_conversion.c +index cfb41d8b0..1bfee096d 100644 +--- a/src/providers/ipa/ipa_sudo_conversion.c ++++ b/src/providers/ipa/ipa_sudo_conversion.c +@@ -939,6 +939,12 @@ convert_runasextusergroup(TALLOC_CTX *mem_ctx, + const char *value, + bool *skip_entry) + { ++ if (value == NULL) ++ return NULL; ++ ++ if (value[0] == '%') ++ return talloc_strdup(mem_ctx, value); ++ + return talloc_asprintf(mem_ctx, "%%%s", value); + } + +-- +2.21.3 + diff --git a/SOURCES/0041-responders-add-callback-to-schedule_get_domains_task.patch b/SOURCES/0041-responders-add-callback-to-schedule_get_domains_task.patch new file mode 100644 index 0000000..e61ec25 --- /dev/null +++ b/SOURCES/0041-responders-add-callback-to-schedule_get_domains_task.patch @@ -0,0 +1,199 @@ +From e07eeea7df55ede36ac0978ac904c1bb11188265 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 20 Jan 2021 17:48:44 +0100 +Subject: [PATCH 41/42] responders: add callback to schedule_get_domains_task() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To allow responders to run dedicated code at the end of the initial +getDomains request a callback is added. + +Resolves: https://github.com/SSSD/sssd/issues/5469 + +Reviewed-by: Tomáš Halman +--- + src/responder/autofs/autofssrv.c | 2 +- + src/responder/common/responder.h | 5 ++++- + src/responder/common/responder_get_domains.c | 12 +++++++++++- + src/responder/ifp/ifpsrv.c | 2 +- + src/responder/nss/nsssrv.c | 3 ++- + src/responder/pac/pacsrv.c | 2 +- + src/responder/pam/pamsrv.c | 3 ++- + src/responder/ssh/sshsrv.c | 2 +- + src/responder/sudo/sudosrv.c | 2 +- + src/tests/cmocka/test_responder_common.c | 2 +- + 10 files changed, 25 insertions(+), 10 deletions(-) + +diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c +index 27de1b44a..130eaf775 100644 +--- a/src/responder/autofs/autofssrv.c ++++ b/src/responder/autofs/autofssrv.c +@@ -142,7 +142,7 @@ autofs_process_init(TALLOC_CTX *mem_ctx, + goto fail; + } + +- ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL); ++ ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL, NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n"); + goto fail; +diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h +index f83ba1bc0..ff0559c08 100644 +--- a/src/responder/common/responder.h ++++ b/src/responder/common/responder.h +@@ -366,10 +366,13 @@ errno_t sss_dp_get_account_domain_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + char **_domain); + ++typedef void (get_domains_callback_fn_t)(void *); + errno_t schedule_get_domains_task(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct resp_ctx *rctx, +- struct sss_nc_ctx *optional_ncache); ++ struct sss_nc_ctx *optional_ncache, ++ get_domains_callback_fn_t *callback, ++ void *callback_pvt); + + errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *csv_string, + bool allow_sss_loop, +diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c +index e551b0fff..12b6e9028 100644 +--- a/src/responder/common/responder_get_domains.c ++++ b/src/responder/common/responder_get_domains.c +@@ -430,6 +430,8 @@ static errno_t check_last_request(struct resp_ctx *rctx, const char *hint) + struct get_domains_state { + struct resp_ctx *rctx; + struct sss_nc_ctx *optional_ncache; ++ get_domains_callback_fn_t *callback; ++ void *callback_pvt; + }; + + static void get_domains_at_startup_done(struct tevent_req *req) +@@ -462,6 +464,10 @@ static void get_domains_at_startup_done(struct tevent_req *req) + } + } + ++ if (state->callback != NULL) { ++ state->callback(state->callback_pvt); ++ } ++ + talloc_free(state); + return; + } +@@ -489,7 +495,9 @@ static void get_domains_at_startup(struct tevent_context *ev, + errno_t schedule_get_domains_task(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct resp_ctx *rctx, +- struct sss_nc_ctx *optional_ncache) ++ struct sss_nc_ctx *optional_ncache, ++ get_domains_callback_fn_t *callback, ++ void *callback_pvt) + { + struct tevent_immediate *imm; + struct get_domains_state *state; +@@ -500,6 +508,8 @@ errno_t schedule_get_domains_task(TALLOC_CTX *mem_ctx, + } + state->rctx = rctx; + state->optional_ncache = optional_ncache; ++ state->callback = callback; ++ state->callback_pvt = callback_pvt; + + imm = tevent_create_immediate(mem_ctx); + if (imm == NULL) { +diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c +index 7407ee07b..ee1452728 100644 +--- a/src/responder/ifp/ifpsrv.c ++++ b/src/responder/ifp/ifpsrv.c +@@ -266,7 +266,7 @@ int ifp_process_init(TALLOC_CTX *mem_ctx, + return EIO; + } + +- ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL); ++ ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL, NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "schedule_get_domains_tasks failed.\n"); +diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c +index e80104e3d..2b7958e80 100644 +--- a/src/responder/nss/nsssrv.c ++++ b/src/responder/nss/nsssrv.c +@@ -557,7 +557,8 @@ int nss_process_init(TALLOC_CTX *mem_ctx, + } + responder_set_fd_limit(fd_limit); + +- ret = schedule_get_domains_task(rctx, rctx->ev, rctx, nctx->rctx->ncache); ++ ret = schedule_get_domains_task(rctx, rctx->ev, rctx, nctx->rctx->ncache, ++ NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n"); + goto fail; +diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c +index 217f83c26..96935150b 100644 +--- a/src/responder/pac/pacsrv.c ++++ b/src/responder/pac/pacsrv.c +@@ -129,7 +129,7 @@ int pac_process_init(TALLOC_CTX *mem_ctx, + goto fail; + } + +- ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL); ++ ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL, NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n"); + goto fail; +diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c +index de1620e82..8b1ce2e92 100644 +--- a/src/responder/pam/pamsrv.c ++++ b/src/responder/pam/pamsrv.c +@@ -246,7 +246,8 @@ static int pam_process_init(TALLOC_CTX *mem_ctx, + } + responder_set_fd_limit(fd_limit); + +- ret = schedule_get_domains_task(rctx, rctx->ev, rctx, pctx->rctx->ncache); ++ ret = schedule_get_domains_task(rctx, rctx->ev, rctx, pctx->rctx->ncache, ++ NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n"); + goto done; +diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c +index 6072a702c..e79a0438c 100644 +--- a/src/responder/ssh/sshsrv.c ++++ b/src/responder/ssh/sshsrv.c +@@ -126,7 +126,7 @@ int ssh_process_init(TALLOC_CTX *mem_ctx, + goto fail; + } + +- ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL); ++ ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL, NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n"); + goto fail; +diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c +index 5951b17b1..dc4a44b2f 100644 +--- a/src/responder/sudo/sudosrv.c ++++ b/src/responder/sudo/sudosrv.c +@@ -102,7 +102,7 @@ int sudo_process_init(TALLOC_CTX *mem_ctx, + goto fail; + } + +- ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL); ++ ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL, NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n"); + goto fail; +diff --git a/src/tests/cmocka/test_responder_common.c b/src/tests/cmocka/test_responder_common.c +index 5fc0d712d..29356253b 100644 +--- a/src/tests/cmocka/test_responder_common.c ++++ b/src/tests/cmocka/test_responder_common.c +@@ -265,7 +265,7 @@ void test_schedule_get_domains_task(void **state) + ret = schedule_get_domains_task(dummy_ncache_ptr, + parse_inp_ctx->rctx->ev, + parse_inp_ctx->rctx, +- dummy_ncache_ptr); ++ dummy_ncache_ptr, NULL, NULL); + assert_int_equal(ret, EOK); + + ret = test_ev_loop(parse_inp_ctx->tctx); +-- +2.21.3 + diff --git a/SOURCES/0042-pam-refresh-certificate-maps-at-the-end-of-initial-d.patch b/SOURCES/0042-pam-refresh-certificate-maps-at-the-end-of-initial-d.patch new file mode 100644 index 0000000..882f567 --- /dev/null +++ b/SOURCES/0042-pam-refresh-certificate-maps-at-the-end-of-initial-d.patch @@ -0,0 +1,64 @@ +From cb936e92041d63f79a74c30bae8140c74a18dbc0 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 20 Jan 2021 18:25:04 +0100 +Subject: [PATCH 42/42] pam: refresh certificate maps at the end of initial + domains lookup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +During startup SSSD's responders send a getDomains request to all +backends to refresh some domain related needed by the responders. + +The PAM responder specifically needs the certificate mapping and +matching rules when Smartcard authentication is enable. Currently the +rules are not refreshed at the end of the initial request but the code +assumed that the related structures are initialized after the request +finished. + +To avoid a race condition this patch adds a callback to the end of the +request to make sure the rules are properly refreshed even if they are +already initialized before. + +Resolves: https://github.com/SSSD/sssd/issues/5469 + +Reviewed-by: Tomáš Halman +--- + src/responder/pam/pamsrv.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c +index 8b1ce2e92..65370662d 100644 +--- a/src/responder/pam/pamsrv.c ++++ b/src/responder/pam/pamsrv.c +@@ -154,6 +154,18 @@ static errno_t get_app_services(struct pam_ctx *pctx) + return EOK; + } + ++static void pam_get_domains_callback(void *pvt) ++{ ++ struct pam_ctx *pctx; ++ int ret; ++ ++ pctx = talloc_get_type(pvt, struct pam_ctx); ++ ret = p11_refresh_certmap_ctx(pctx, pctx->rctx->domains); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "p11_refresh_certmap_ctx failed.\n"); ++ } ++} ++ + static int pam_process_init(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct confdb_ctx *cdb, +@@ -247,7 +259,7 @@ static int pam_process_init(TALLOC_CTX *mem_ctx, + responder_set_fd_limit(fd_limit); + + ret = schedule_get_domains_task(rctx, rctx->ev, rctx, pctx->rctx->ncache, +- NULL, NULL); ++ pam_get_domains_callback, pctx); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n"); + goto done; +-- +2.21.3 + diff --git a/SOURCES/0043-SBUS-set-sbus_name-before-dp_init_send.patch b/SOURCES/0043-SBUS-set-sbus_name-before-dp_init_send.patch new file mode 100644 index 0000000..eb99c88 --- /dev/null +++ b/SOURCES/0043-SBUS-set-sbus_name-before-dp_init_send.patch @@ -0,0 +1,134 @@ +From 0c6924b8d474daf35ee30d74e5496957e503b206 Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Wed, 20 Jan 2021 15:40:34 +0100 +Subject: [PATCH] SBUS: set sbus_name before dp_init_send() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some async task might access sbus_name before dp_initialized() was executed + +Resolves: https://github.com/SSSD/sssd/issues/5466 + +Reviewed-by: Pavel Březina +--- + src/providers/data_provider/dp.c | 21 ++++----------------- + src/providers/data_provider/dp.h | 6 +++--- + src/providers/data_provider_be.c | 12 ++++++++++-- + 3 files changed, 17 insertions(+), 22 deletions(-) + +diff --git a/src/providers/data_provider/dp.c b/src/providers/data_provider/dp.c +index 90324d74d..64fe847b2 100644 +--- a/src/providers/data_provider/dp.c ++++ b/src/providers/data_provider/dp.c +@@ -134,7 +134,6 @@ static int dp_destructor(struct data_provider *provider) + struct dp_init_state { + struct be_ctx *be_ctx; + struct data_provider *provider; +- char *sbus_name; + }; + + static void dp_init_done(struct tevent_req *subreq); +@@ -144,7 +143,8 @@ dp_init_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_ctx *be_ctx, + uid_t uid, +- gid_t gid) ++ gid_t gid, ++ const char *sbus_name) + { + struct dp_init_state *state; + struct tevent_req *subreq; +@@ -177,13 +177,6 @@ dp_init_send(TALLOC_CTX *mem_ctx, + state->provider->gid = gid; + state->provider->be_ctx = be_ctx; + +- state->sbus_name = sss_iface_domain_bus(state, be_ctx->domain); +- if (state->sbus_name == NULL) { +- DEBUG(SSSDBG_FATAL_FAILURE, "Could not get sbus backend name.\n"); +- ret = ENOMEM; +- 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 +@@ -192,7 +185,7 @@ dp_init_send(TALLOC_CTX *mem_ctx, + talloc_set_destructor(state->provider, dp_destructor); + + subreq = sbus_server_create_and_connect_send(state->provider, ev, +- state->sbus_name, NULL, sbus_address, true, 1000, uid, gid, ++ sbus_name, NULL, sbus_address, true, 1000, uid, gid, + (sbus_server_on_connection_cb)dp_client_init, + (sbus_server_on_connection_data)state->provider); + if (subreq == NULL) { +@@ -270,16 +263,10 @@ done: + } + + errno_t dp_init_recv(TALLOC_CTX *mem_ctx, +- struct tevent_req *req, +- const char **_sbus_name) ++ struct tevent_req *req) + { +- struct dp_init_state *state; +- state = tevent_req_data(req, struct dp_init_state); +- + TEVENT_REQ_RETURN_ON_ERROR(req); + +- *_sbus_name = talloc_steal(mem_ctx, state->sbus_name); +- + return EOK; + } + +diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h +index a8b6e9f3a..95c6588ad 100644 +--- a/src/providers/data_provider/dp.h ++++ b/src/providers/data_provider/dp.h +@@ -122,11 +122,11 @@ dp_init_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_ctx *be_ctx, + uid_t uid, +- gid_t gid); ++ gid_t gid, ++ const char *sbus_name); + + errno_t dp_init_recv(TALLOC_CTX *mem_ctx, +- struct tevent_req *req, +- const char **_sbus_name); ++ struct tevent_req *req); + + bool _dp_target_enabled(struct data_provider *provider, + const char *module_name, +diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c +index f059a3f96..8458146ea 100644 +--- a/src/providers/data_provider_be.c ++++ b/src/providers/data_provider_be.c +@@ -565,7 +565,15 @@ errno_t be_process_init(TALLOC_CTX *mem_ctx, + goto done; + } + +- req = dp_init_send(be_ctx, be_ctx->ev, be_ctx, be_ctx->uid, be_ctx->gid); ++ be_ctx->sbus_name = sss_iface_domain_bus(be_ctx, be_ctx->domain); ++ if (be_ctx->sbus_name == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "Could not get sbus backend name.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ req = dp_init_send(be_ctx, be_ctx->ev, be_ctx, be_ctx->uid, be_ctx->gid, ++ be_ctx->sbus_name); + if (req == NULL) { + ret = ENOMEM; + goto done; +@@ -612,7 +620,7 @@ static void dp_initialized(struct tevent_req *req) + + be_ctx = tevent_req_callback_data(req, struct be_ctx); + +- ret = dp_init_recv(be_ctx, req, &be_ctx->sbus_name); ++ ret = dp_init_recv(be_ctx, req); + talloc_zfree(req); + if (ret != EOK) { + goto done; +-- +2.21.3 + diff --git a/SOURCES/0044-pam_sss_gss-support-authentication-indicators.patch b/SOURCES/0044-pam_sss_gss-support-authentication-indicators.patch new file mode 100644 index 0000000..91d15c4 --- /dev/null +++ b/SOURCES/0044-pam_sss_gss-support-authentication-indicators.patch @@ -0,0 +1,655 @@ +From c2e8879189ecbbdfdd4b42395319a4cd91cb569f Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Fri, 12 Feb 2021 20:02:52 +0100 +Subject: [PATCH] pam_sss_gss: support authentication indicators (upstream +patch 5ce7ced269c7b3dd8f75122a50f539083b5697ae by Alexander Bokovoy) + +MIT Kerberos allows to associate authentication indicators with the +issued ticket based on the way how the TGT was obtained. The indicators +present in the TGT then copied to service tickets. There are two ways to +check the authentication indicators: + + - when KDC issues a service ticket, a policy at KDC side can reject the + ticket issuance based on a lack of certain indicator + + - when a server application presented with a service ticket from a + client, it can verify that this ticket contains intended + authentication indicators before authorizing access from the client. + +Add support to validate presence of a specific (set of) authentication +indicator(s) in pam_sss_gss when validating a user's TGT. + +This concept can be used to only allow access to a PAM service when user +is in possession of a ticket obtained using some of pre-authentication +mechanisms that require multiple factors: smart-cards (PKINIT), 2FA +tokens (otp/radius), etc. + +Patch by: Alexander Bokovoy + +Reviewed by: Sumit Bose + +Adapted to 8.4 branch by: Alexey Tikhonov +--- + src/confdb/confdb.c | 13 ++ + src/confdb/confdb.h | 3 + + src/config/SSSDConfig/sssdoptions.py | 2 + + src/config/SSSDConfigTest.py | 6 +- + src/config/cfg_rules.ini | 3 + + src/config/etc/sssd.api.conf | 2 + + src/db/sysdb_subdomains.c | 12 ++ + src/man/pam_sss_gss.8.xml | 13 ++ + src/man/sssd.conf.5.xml | 64 +++++++ + src/responder/pam/pamsrv.c | 21 +++ + src/responder/pam/pamsrv.h | 2 + + src/responder/pam/pamsrv_gssapi.c | 250 +++++++++++++++++++++++++++ + 12 files changed, 389 insertions(+), 2 deletions(-) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index befcfff..cca7615 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -1603,6 +1603,19 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, + } + } + ++ tmp = ldb_msg_find_attr_as_string(res->msgs[0], ++ CONFDB_PAM_GSSAPI_INDICATORS_MAP, ++ NULL); ++ if (tmp != NULL && tmp[0] != '\0') { ++ ret = split_on_separator(domain, tmp, ',', true, true, ++ &domain->gssapi_indicators_map, NULL); ++ if (ret != 0) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Cannot parse %s\n", CONFDB_PAM_GSSAPI_INDICATORS_MAP); ++ goto done; ++ } ++ } ++ + domain->has_views = false; + domain->view_name = NULL; + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 036f9ec..a2be227 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -146,6 +146,7 @@ + #define CONFDB_PAM_INITGROUPS_SCHEME "pam_initgroups_scheme" + #define CONFDB_PAM_GSSAPI_SERVICES "pam_gssapi_services" + #define CONFDB_PAM_GSSAPI_CHECK_UPN "pam_gssapi_check_upn" ++#define CONFDB_PAM_GSSAPI_INDICATORS_MAP "pam_gssapi_indicators_map" + + /* SUDO */ + #define CONFDB_SUDO_CONF_ENTRY "config/sudo" +@@ -437,6 +438,8 @@ struct sss_domain_info { + /* List of PAM services that are allowed to authenticate with GSSAPI. */ + char **gssapi_services; + char *gssapi_check_upn; /* true | false | NULL */ ++ /* List of indicators associated with the specific PAM service */ ++ char **gssapi_indicators_map; + }; + + /** +diff --git a/src/config/SSSDConfig/sssdoptions.py b/src/config/SSSDConfig/sssdoptions.py +index 5da52a9..0d849bc 100644 +--- a/src/config/SSSDConfig/sssdoptions.py ++++ b/src/config/SSSDConfig/sssdoptions.py +@@ -106,6 +106,8 @@ class SSSDOptions(object): + 'pam_initgroups_scheme' : _('When shall the PAM responder force an initgroups request'), + 'pam_gssapi_services' : _('List of PAM services that are allowed to authenticate with GSSAPI.'), + 'pam_gssapi_check_upn' : _('Whether to match authenticated UPN with target user'), ++ 'pam_gssapi_indicators_map' : _('List of pairs : that ' ++ 'must be enforced for PAM access with GSSAPI authentication'), + + # [sudo] + 'sudo_timed': _('Whether to evaluate the time-based attributes in sudo rules'), +diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py +index ea4e4f6..d0422df 100755 +--- a/src/config/SSSDConfigTest.py ++++ b/src/config/SSSDConfigTest.py +@@ -655,7 +655,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 'cached_auth_timeout', + 'auto_private_groups', + 'pam_gssapi_services', +- 'pam_gssapi_check_upn'] ++ 'pam_gssapi_check_upn', ++ 'pam_gssapi_indicators_map'] + + self.assertTrue(type(options) == dict, + "Options should be a dictionary") +@@ -1034,7 +1035,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 'cached_auth_timeout', + 'auto_private_groups', + 'pam_gssapi_services', +- 'pam_gssapi_check_upn'] ++ 'pam_gssapi_check_upn', ++ 'pam_gssapi_indicators_map'] + + 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 6642c63..872ceba 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -141,6 +141,7 @@ option = p11_uri + option = pam_initgroups_scheme + option = pam_gssapi_services + option = pam_gssapi_check_upn ++option = pam_gssapi_indicators_map + + [rule/allowed_sudo_options] + validator = ini_allowed_options +@@ -441,6 +442,7 @@ option = re_expression + option = auto_private_groups + option = pam_gssapi_services + option = pam_gssapi_check_upn ++option = pam_gssapi_indicators_map + + #Entry cache timeouts + option = entry_cache_user_timeout +@@ -837,6 +839,7 @@ option = use_fully_qualified_names + option = auto_private_groups + option = pam_gssapi_services + option = pam_gssapi_check_upn ++option = pam_gssapi_indicators_map + + [rule/sssd_checks] + validator = sssd_checks +diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf +index d3cad73..49ced63 100644 +--- a/src/config/etc/sssd.api.conf ++++ b/src/config/etc/sssd.api.conf +@@ -82,6 +82,7 @@ p11_uri = str, None, false + pam_initgroups_scheme = str, None, false + pam_gssapi_services = str, None, false + pam_gssapi_check_upn = bool, None, false ++pam_gssapi_indicators_map = str, None, false + + [sudo] + # sudo service +@@ -203,6 +204,7 @@ re_expression = str, None, false + auto_private_groups = str, None, false + pam_gssapi_services = str, None, false + pam_gssapi_check_upn = bool, None, false ++pam_gssapi_indicators_map = str, None, false + + #Entry cache timeouts + entry_cache_user_timeout = int, None, false +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index 03ba121..2243872 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -185,6 +185,7 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, + dom->override_gid = parent->override_gid; + + dom->gssapi_services = parent->gssapi_services; ++ dom->gssapi_indicators_map = parent->gssapi_indicators_map; + + if (parent->sysdb == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Missing sysdb context in parent domain.\n"); +@@ -266,6 +267,17 @@ check_subdom_config_file(struct confdb_ctx *confdb, + goto done; + } + ++ /* allow to set pam_gssapi_indicators_map */ ++ ret = confdb_get_string_as_list(confdb, subdomain, sd_conf_path, ++ CONFDB_PAM_GSSAPI_INDICATORS_MAP, ++ &subdomain->gssapi_indicators_map); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to get %s option for the subdomain: %s\n", ++ CONFDB_PAM_GSSAPI_INDICATORS_MAP, subdomain->name); ++ goto done; ++ } ++ + ret = EOK; + done: + talloc_free(tmp_ctx); +diff --git a/src/man/pam_sss_gss.8.xml b/src/man/pam_sss_gss.8.xml +index ce5b11b..a83369d 100644 +--- a/src/man/pam_sss_gss.8.xml ++++ b/src/man/pam_sss_gss.8.xml +@@ -70,6 +70,19 @@ + 5 + for more details on these options. + ++ ++ Some Kerberos deployments allow to assocate authentication ++ indicators with a particular pre-authentication method used to ++ obtain the ticket granting ticket by the user. ++ pam_sss_gss.so allows to enforce presence of ++ authentication indicators in the service tickets before a particular ++ PAM service can be accessed. ++ ++ ++ If is set in the [pam] or ++ domain section of sssd.conf, then SSSD will perform a check of the ++ presence of any configured indicators in the service ticket. ++ + + + +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 8b330de..3a9955b 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -1770,6 +1770,70 @@ pam_gssapi_services = sudo, sudo-i + + + ++ ++ pam_gssapi_indicators_map ++ ++ ++ Comma separated list of authentication indicators required ++ to be present in a Kerberos ticket to access a PAM service ++ that is allowed to try GSSAPI authentication using ++ pam_sss_gss.so module. ++ ++ ++ Each element of the list can be either an authentication indicator ++ name or a pair service:indicator. Indicators not ++ prefixed with the PAM service name will be required to access any ++ PAM service configured to be used with ++ . A resulting list of indicators ++ per PAM service is then checked against indicators in the Kerberos ++ ticket during authentication by pam_sss_gss.so. Any indicator from the ++ ticket that matches the resulting list of indicators for the PAM service ++ would grant access. If none of the indicators in the list match, access ++ will be denied. If the resulting list of indicators for the PAM service ++ is empty, the check will not prevent the access. ++ ++ ++ To disable GSSAPI authentication indicator check, set this option ++ to - (dash). To disable the check for a specific PAM ++ service, add service:-. ++ ++ ++ Note: This option can also be set per-domain which ++ overwrites the value in [pam] section. It can also ++ be set for trusted domain which overwrites the value ++ in the domain section. ++ ++ ++ Following authentication indicators are supported by IPA Kerberos deployments: ++ ++ ++ pkinit -- pre-authentication using X.509 certificates -- whether stored in files or on smart cards. ++ ++ ++ hardened -- SPAKE pre-authentication or any pre-authentication wrapped in a FAST channel. ++ ++ ++ radius -- pre-authentication with the help of a RADIUS server. ++ ++ ++ otp -- pre-authentication using integrated two-factor authentication (2FA or one-time password, OTP) in IPA. ++ ++ ++ ++ ++ Example: to require access to SUDO services only ++ for users which obtained their Kerberos tickets ++ with a X.509 certificate pre-authentication ++ (PKINIT), set ++ ++pam_gssapi_indicators_map = sudo:pkinit, sudo-i:pkinit ++ ++ ++ ++ Default: not set (use of authentication indicators is not required) ++ ++ ++ + + + +diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c +index 3904c09..9b4d6c1 100644 +--- a/src/responder/pam/pamsrv.c ++++ b/src/responder/pam/pamsrv.c +@@ -370,6 +370,27 @@ static int pam_process_init(TALLOC_CTX *mem_ctx, + goto done; + } + ++ ret = confdb_get_string(pctx->rctx->cdb, pctx, CONFDB_PAM_CONF_ENTRY, ++ CONFDB_PAM_GSSAPI_INDICATORS_MAP, "-", &tmpstr); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to determine gssapi services.\n"); ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Found value [%s] for option [%s].\n", tmpstr, ++ CONFDB_PAM_GSSAPI_INDICATORS_MAP); ++ ++ if (tmpstr != NULL) { ++ ret = split_on_separator(pctx, tmpstr, ',', true, true, ++ &pctx->gssapi_indicators_map, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "split_on_separator() failed [%d]: [%s].\n", ret, ++ sss_strerror(ret)); ++ goto done; ++ } ++ } ++ + /* The responder is initialized. Now tell it to the monitor. */ + ret = sss_monitor_service_init(rctx, rctx->ev, SSS_BUS_PAM, + SSS_PAM_SBUS_SERVICE_NAME, +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index 3553296..383c7be 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -65,6 +65,8 @@ struct pam_ctx { + + /* List of PAM services that are allowed to authenticate with GSSAPI. */ + char **gssapi_services; ++ /* List of authentication indicators associated with a PAM service */ ++ char **gssapi_indicators_map; + bool gssapi_check_upn; + }; + +diff --git a/src/responder/pam/pamsrv_gssapi.c b/src/responder/pam/pamsrv_gssapi.c +index 2d05c78..e4da4c4 100644 +--- a/src/responder/pam/pamsrv_gssapi.c ++++ b/src/responder/pam/pamsrv_gssapi.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -83,6 +84,117 @@ static bool pam_gssapi_should_check_upn(struct pam_ctx *pam_ctx, + return pam_ctx->gssapi_check_upn; + } + ++static int pam_gssapi_check_indicators(TALLOC_CTX *mem_ctx, ++ const char *pam_service, ++ char **gssapi_indicators_map, ++ char **indicators) ++{ ++ char *authind = NULL; ++ size_t pam_len = strlen(pam_service); ++ char **map = gssapi_indicators_map; ++ char **result = NULL; ++ int res; ++ ++ authind = talloc_strdup(mem_ctx, ""); ++ if (authind == NULL) { ++ return ENOMEM; ++ } ++ ++ for (int i = 0; map[i]; i++) { ++ if (map[i][0] == '-') { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Indicators aren't used for [%s]\n", ++ pam_service); ++ talloc_free(authind); ++ return EOK; ++ } ++ if (!strchr(map[i], ':')) { ++ authind = talloc_asprintf_append(authind, "%s ", map[i]); ++ if (authind == NULL) { ++ /* Since we allocate on pam_ctx, caller will free it */ ++ return ENOMEM; ++ } ++ continue; ++ } ++ ++ res = strncmp(map[i], pam_service, pam_len); ++ if (res == 0) { ++ if (strlen(map[i]) > pam_len) { ++ if (map[i][pam_len] != ':') { ++ /* different PAM service, skip it */ ++ continue; ++ } ++ ++ if (map[i][pam_len + 1] == '-') { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Indicators aren't used for [%s]\n", ++ pam_service); ++ talloc_free(authind); ++ return EOK; ++ } ++ ++ authind = talloc_asprintf_append(authind, "%s ", ++ map[i] + (pam_len + 1)); ++ if (authind == NULL) { ++ /* Since we allocate on pam_ctx, caller will free it */ ++ return ENOMEM; ++ } ++ } else { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Invalid value for %s: [%s]\n", ++ CONFDB_PAM_GSSAPI_INDICATORS_MAP, map[i]); ++ talloc_free(authind); ++ return EINVAL; ++ } ++ } ++ } ++ ++ res = ENOENT; ++ map = NULL; ++ ++ if (authind[0] == '\0') { ++ /* empty list of per-service indicators -> skip */ ++ goto done; ++ } ++ ++ /* trim a space after the final indicator ++ * to prevent split_on_separator() to fail */ ++ authind[strlen(authind) - 1] = '\0'; ++ ++ res = split_on_separator(mem_ctx, authind, ' ', true, true, ++ &map, NULL); ++ if (res != 0) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Cannot parse list of indicators: [%s]\n", authind); ++ res = EINVAL; ++ goto done; ++ } ++ ++ res = diff_string_lists(mem_ctx, indicators, map, NULL, NULL, &result); ++ if (res != 0) { ++ DEBUG(SSSDBG_FATAL_FAILURE,"Cannot diff lists of indicators\n"); ++ res = EINVAL; ++ goto done; ++ } ++ ++ if (result && result[0] != NULL) { ++ for (int i = 0; result[i]; i++) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "indicator [%s] is allowed for PAM service [%s]\n", ++ result[i], pam_service); ++ } ++ res = EOK; ++ goto done; ++ } ++ ++ res = EPERM; ++ ++done: ++ talloc_free(result); ++ talloc_free(authind); ++ talloc_free(map); ++ return res; ++} ++ + static bool pam_gssapi_allowed(struct pam_ctx *pam_ctx, + struct sss_domain_info *domain, + const char *service) +@@ -385,12 +497,126 @@ static char *gssapi_get_name(TALLOC_CTX *mem_ctx, gss_name_t gss_name) + return exported; + } + ++#define AUTH_INDICATORS_TAG "auth-indicators" ++ ++static char **gssapi_get_indicators(TALLOC_CTX *mem_ctx, gss_name_t gss_name) ++{ ++ gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; ++ int is_mechname; ++ OM_uint32 major; ++ OM_uint32 minor; ++ gss_buffer_desc value = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc display_value = GSS_C_EMPTY_BUFFER; ++ char *exported = NULL; ++ char **map = NULL; ++ int res; ++ ++ major = gss_inquire_name(&minor, gss_name, &is_mechname, NULL, &attrs); ++ if (major != GSS_S_COMPLETE) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to inquire name\n"); ++ return NULL; ++ } ++ ++ if (attrs == GSS_C_NO_BUFFER_SET) { ++ DEBUG(SSSDBG_TRACE_FUNC, "No krb5 attributes in the ticket\n"); ++ return NULL; ++ } ++ ++ exported = talloc_strdup(mem_ctx, ""); ++ if (exported == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unable to pre-allocate indicators\n"); ++ goto done; ++ } ++ ++ for (int i = 0; i < attrs->count; i++) { ++ int authenticated = 0; ++ int complete = 0; ++ int more = -1; ++ ++ /* skip anything but auth-indicators */ ++ if (strncmp(AUTH_INDICATORS_TAG, attrs->elements[i].value, ++ sizeof(AUTH_INDICATORS_TAG) - 1) != 0) ++ continue; ++ ++ /* retrieve all indicators */ ++ while (more != 0) { ++ value.value = NULL; ++ display_value.value = NULL; ++ ++ major = gss_get_name_attribute(&minor, gss_name, ++ &attrs->elements[i], ++ &authenticated, ++ &complete, &value, ++ &display_value, ++ &more); ++ if (major != GSS_S_COMPLETE) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unable to retrieve an attribute\n"); ++ goto done; ++ } ++ ++ if ((value.value != NULL) && authenticated) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "attribute's [%.*s] value [%.*s] authenticated\n", ++ (int) attrs->elements[i].length, ++ (char*) attrs->elements[i].value, ++ (int) value.length, ++ (char*) value.value); ++ exported = talloc_asprintf_append(exported, "%.*s ", ++ (int) value.length, ++ (char*) value.value); ++ } ++ ++ if (exported == NULL) { ++ /* Since we allocate on mem_ctx, caller will free ++ * the previous version of 'exported' */ ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Unable to collect an attribute value\n"); ++ goto done; ++ } ++ (void) gss_release_buffer(&minor, &value); ++ (void) gss_release_buffer(&minor, &display_value); ++ } ++ } ++ ++ if (exported[0] != '\0') { ++ /* trim a space after the final indicator ++ * to prevent split_on_separator() to fail */ ++ exported[strlen(exported) - 1] = '\0'; ++ } else { ++ /* empty list */ ++ goto done; ++ } ++ ++ res = split_on_separator(mem_ctx, exported, ' ', true, true, ++ &map, NULL); ++ if (res != 0) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Cannot parse list of indicators: [%s]\n", exported); ++ goto done; ++ } else { ++ DEBUG(SSSDBG_TRACE_FUNC, "authentication indicators: [%s]\n", ++ exported); ++ } ++ ++done: ++ (void) gss_release_buffer(&minor, &value); ++ (void) gss_release_buffer(&minor, &display_value); ++ (void) gss_release_buffer_set(&minor, &attrs); ++ ++ talloc_free(exported); ++ return map; ++} ++ ++ + struct gssapi_state { + struct cli_ctx *cli_ctx; + struct sss_domain_info *domain; + const char *username; + + char *authenticated_upn; ++ char **auth_indicators; + bool established; + gss_ctx_id_t ctx; + }; +@@ -568,6 +794,8 @@ gssapi_handshake(struct gssapi_state *state, + DEBUG(SSSDBG_TRACE_FUNC, "Security context established with [%s]\n", + state->authenticated_upn); + ++ state->auth_indicators = gssapi_get_indicators(state, client_name); ++ + state->established = true; + ret = EOK; + +@@ -632,6 +860,7 @@ pam_cmd_gssapi_sec_ctx(struct cli_ctx *cli_ctx) + const char *domain_name; + const char *username; + char *target; ++ char **indicators_map = NULL; + size_t gss_data_len; + uint8_t *gss_data; + errno_t ret; +@@ -699,6 +928,27 @@ pam_cmd_gssapi_sec_ctx(struct cli_ctx *cli_ctx) + goto done; + } + ++ /* Use map for auth-indicators from the domain, if defined and ++ * fallback to the [pam] section otherwise */ ++ indicators_map = domain->gssapi_indicators_map ? ++ domain->gssapi_indicators_map : ++ (pam_ctx->gssapi_indicators_map ? ++ pam_ctx->gssapi_indicators_map : NULL); ++ if (indicators_map != NULL) { ++ ret = pam_gssapi_check_indicators(state, ++ pam_service, ++ indicators_map, ++ state->auth_indicators); ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Check if acquired service ticket has req. indicators: %d\n", ++ ret); ++ if ((ret == EPERM) || (ret == ENOMEM) || (ret == EINVAL)) { ++ /* skip further checks if denied or no memory, ++ * ENOENT means the check is not applicable */ ++ goto done; ++ } ++ } ++ + if (!pam_gssapi_should_check_upn(pam_ctx, domain)) { + /* We are done. */ + goto done; +-- +2.21.3 + diff --git a/SOURCES/0045-sudo-do-not-search-by-low-usn-value-to-improve-perfo.patch b/SOURCES/0045-sudo-do-not-search-by-low-usn-value-to-improve-perfo.patch new file mode 100644 index 0000000..af99e4f --- /dev/null +++ b/SOURCES/0045-sudo-do-not-search-by-low-usn-value-to-improve-perfo.patch @@ -0,0 +1,121 @@ +From b100efbfabd96dcfb2825777b75b9a9dfaacb937 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 29 Jan 2021 12:41:28 +0100 +Subject: [PATCH] sudo: do not search by low usn value to improve performance + +This is a follow up on these two commits. + +- 819d70ef6e6fa0e736ebd60a7f8a26f672927d57 +- 6815844daa7701c76e31addbbdff74656cd30bea + +The first one improved the search filter little bit to achieve better +performance, however it also changed the behavior: we started to search +for `usn >= 1` in the filter if no usn number was known. + +This caused issues on OpenLDAP server which was fixed by the second patch. +However, the fix was wrong and searching by this meaningfully low number +can cause performance issues depending on how the filter is optimized and +evaluated on the server. + +Now we omit the usn attribute from the filter if there is no meaningful value. + +How to test: +1. Setup LDAP with no sudo rules defined +2. Make sure that the LDAP server does not support USN or use the following diff + to enforce modifyTimestamp (last USN is always available from rootDSE) +```diff + +Reviewed-by: Alexey Tikhonov +--- + src/providers/ldap/sdap.c | 4 ++-- + src/providers/ldap/sdap_sudo_refresh.c | 6 ++++-- + src/providers/ldap/sdap_sudo_shared.c | 21 ++++++--------------- + 3 files changed, 12 insertions(+), 19 deletions(-) + +diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c +index 32c0144b9..c853e4dc1 100644 +--- a/src/providers/ldap/sdap.c ++++ b/src/providers/ldap/sdap.c +@@ -1391,7 +1391,7 @@ int sdap_get_server_opts_from_rootdse(TALLOC_CTX *memctx, + last_usn_name = opts->gen_map[SDAP_AT_LAST_USN].name; + entry_usn_name = opts->gen_map[SDAP_AT_ENTRY_USN].name; + if (rootdse) { +- if (last_usn_name) { ++ if (false) { + ret = sysdb_attrs_get_string(rootdse, + last_usn_name, &last_usn_value); + if (ret != EOK) { +@@ -1500,7 +1500,7 @@ int sdap_get_server_opts_from_rootdse(TALLOC_CTX *memctx, + } + } + +- if (!last_usn_name) { ++ if (true) { + DEBUG(SSSDBG_FUNC_DATA, + "No known USN scheme is supported by this server!\n"); + if (!entry_usn_name) { +diff --git a/src/providers/ldap/sdap_sudo_refresh.c b/src/providers/ldap/sdap_sudo_refresh.c +index ddcb23781..83f944ccf 100644 +--- a/src/providers/ldap/sdap_sudo_refresh.c ++++ b/src/providers/ldap/sdap_sudo_refresh.c +@@ -181,8 +181,10 @@ struct tevent_req *sdap_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + state->sysdb = id_ctx->be->domain->sysdb; + + /* Download all rules from LDAP that are newer than usn */ +- if (srv_opts == NULL || srv_opts->max_sudo_value == 0) { +- DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, assuming zero.\n"); ++ if (srv_opts == NULL || srv_opts->max_sudo_value == NULL ++ || strcmp(srv_opts->max_sudo_value, "0") == 0) { ++ DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, assuming zero and " ++ "omitting it from the filter.\n"); + usn = "0"; + search_filter = talloc_asprintf(state, "(%s=%s)", + map[SDAP_AT_SUDO_OC].name, +diff --git a/src/providers/ldap/sdap_sudo_shared.c b/src/providers/ldap/sdap_sudo_shared.c +index 4f09957ea..75d1bc3d8 100644 +--- a/src/providers/ldap/sdap_sudo_shared.c ++++ b/src/providers/ldap/sdap_sudo_shared.c +@@ -129,25 +129,17 @@ sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx, + static char * + sdap_sudo_new_usn(TALLOC_CTX *mem_ctx, + unsigned long usn, +- const char *leftover, +- bool supports_usn) ++ const char *leftover) + { + const char *str = leftover == NULL ? "" : leftover; + char *newusn; + +- /* This is a fresh start and server uses modifyTimestamp. We need to +- * provide proper datetime value. */ +- if (!supports_usn && usn == 0) { +- newusn = talloc_strdup(mem_ctx, "00000101000000Z"); +- if (newusn == NULL) { +- DEBUG(SSSDBG_MINOR_FAILURE, "Unable to change USN value (OOM)!\n"); +- return NULL; +- } +- +- return newusn; ++ /* Current largest USN is unknown so we keep "0" to indicate it. */ ++ if (usn == 0) { ++ return talloc_strdup(mem_ctx, "0"); + } + +- /* We increment USN number so that we can later use simplify filter ++ /* We increment USN number so that we can later use simplified filter + * (just usn >= last+1 instead of usn >= last && usn != last). + */ + usn++; +@@ -219,8 +211,7 @@ sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, + srv_opts->last_usn = usn_number; + } + +- newusn = sdap_sudo_new_usn(srv_opts, srv_opts->last_usn, timezone, +- srv_opts->supports_usn); ++ newusn = sdap_sudo_new_usn(srv_opts, srv_opts->last_usn, timezone); + if (newusn == NULL) { + return; + } +-- +2.21.3 + diff --git a/SOURCES/0046-ldap-fix-modifytimestamp-debugging-leftovers.patch b/SOURCES/0046-ldap-fix-modifytimestamp-debugging-leftovers.patch new file mode 100644 index 0000000..ae6dfb7 --- /dev/null +++ b/SOURCES/0046-ldap-fix-modifytimestamp-debugging-leftovers.patch @@ -0,0 +1,34 @@ +From fff02bbf7967d291ccb019fae741e6591ed8fd41 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 12 Feb 2021 15:30:59 +0100 +Subject: [PATCH] ldap: fix modifytimestamp debugging leftovers + +--- + src/providers/ldap/sdap.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c +index c853e4dc1..32c0144b9 100644 +--- a/src/providers/ldap/sdap.c ++++ b/src/providers/ldap/sdap.c +@@ -1391,7 +1391,7 @@ int sdap_get_server_opts_from_rootdse(TALLOC_CTX *memctx, + last_usn_name = opts->gen_map[SDAP_AT_LAST_USN].name; + entry_usn_name = opts->gen_map[SDAP_AT_ENTRY_USN].name; + if (rootdse) { +- if (false) { ++ if (last_usn_name) { + ret = sysdb_attrs_get_string(rootdse, + last_usn_name, &last_usn_value); + if (ret != EOK) { +@@ -1500,7 +1500,7 @@ int sdap_get_server_opts_from_rootdse(TALLOC_CTX *memctx, + } + } + +- if (true) { ++ if (!last_usn_name) { + DEBUG(SSSDBG_FUNC_DATA, + "No known USN scheme is supported by this server!\n"); + if (!entry_usn_name) { +-- +2.21.3 + diff --git a/SOURCES/0047-ssh-restore-default-debug-level.patch b/SOURCES/0047-ssh-restore-default-debug-level.patch new file mode 100644 index 0000000..7b29783 --- /dev/null +++ b/SOURCES/0047-ssh-restore-default-debug-level.patch @@ -0,0 +1,49 @@ +From 2d26c95d78cf43798b54ac8c478b8a9ee41cab39 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 3 Feb 2021 18:28:29 +0100 +Subject: [PATCH] ssh: restore default debug level + +The recent change of the default debug level for the main SSSD +components affected the ssh helpers sss_ssh_authorizedkeys and +sss_ssh_knownhostsproxy as well. + +To avoid any confusion about unexpected debug messages this patch +restores to original value for the two helpers. + +Resolves: https://github.com/SSSD/sssd/issues/5488 + +Reviewed-by: Alexey Tikhonov +--- + src/sss_client/ssh/sss_ssh_authorizedkeys.c | 2 +- + src/sss_client/ssh/sss_ssh_knownhostsproxy.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/sss_client/ssh/sss_ssh_authorizedkeys.c b/src/sss_client/ssh/sss_ssh_authorizedkeys.c +index 8e80f9663..877c00299 100644 +--- a/src/sss_client/ssh/sss_ssh_authorizedkeys.c ++++ b/src/sss_client/ssh/sss_ssh_authorizedkeys.c +@@ -32,7 +32,7 @@ + int main(int argc, const char **argv) + { + TALLOC_CTX *mem_ctx = NULL; +- int pc_debug = SSSDBG_DEFAULT; ++ int pc_debug = SSSDBG_FATAL_FAILURE; + const char *pc_domain = NULL; + const char *pc_user = NULL; + struct poptOption long_options[] = { +diff --git a/src/sss_client/ssh/sss_ssh_knownhostsproxy.c b/src/sss_client/ssh/sss_ssh_knownhostsproxy.c +index ad6af81d8..1102fd4ab 100644 +--- a/src/sss_client/ssh/sss_ssh_knownhostsproxy.c ++++ b/src/sss_client/ssh/sss_ssh_knownhostsproxy.c +@@ -174,7 +174,7 @@ connect_proxy_command(char **args) + int main(int argc, const char **argv) + { + TALLOC_CTX *mem_ctx = NULL; +- int pc_debug = SSSDBG_DEFAULT; ++ int pc_debug = SSSDBG_FATAL_FAILURE; + int pc_port = 22; + const char *pc_domain = NULL; + const char *pc_host = NULL; +-- +2.21.3 + diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec index fa7ea36..07ea246 100644 --- a/SPECS/sssd.spec +++ b/SPECS/sssd.spec @@ -25,8 +25,8 @@ %endif Name: sssd -Version: 2.3.0 -Release: 2%{?dist} +Version: 2.4.0 +Release: 8%{?dist} Group: Applications/System Summary: System Security Services Daemon License: GPLv3+ @@ -34,9 +34,53 @@ URL: https://pagure.io/SSSD/sssd/ Source0: https://releases.pagure.org/SSSD/sssd/%{name}-%{version}.tar.gz ### Patches ### -Patch0001: 0001-ad_gpo_ndr.c-more-ndr-updates.patch -Patch0002: 0002-test-avoid-endian-issues-in-network-tests.patch -Patch0003: 0003-sssctl-sssctl-config-check-alternative-config-file.patch +Patch0001: 0001-SYSDB-merge_res_sysdb_attrs-fixed-to-avoid-NULL-ptr-.patch +Patch0002: 0002-KCM-perf-improvements.patch +Patch0003: 0003-DEBUG-journal_send-was-made-static.patch +Patch0004: 0004-DEBUG-fixes-program-identifier-as-seen-in-syslog.patch +Patch0005: 0005-negcache-make-sure-domain-config-does-not-leak-into-.patch +Patch0006: 0006-utils-add-SSS_GND_SUBDOMAINS-flag-for-get_next_domai.patch +Patch0007: 0007-negcache-make-sure-short-names-are-added-to-sub-doma.patch +Patch0008: 0008-negcache-do-not-use-default_domain_suffix.patch +Patch0009: 0009-kcm-decode-base64-encoded-secret-on-upgrade-path.patch +Patch0010: 0010-nss-check-if-groups-are-filtered-during-initgroups.patch +Patch0011: 0011-ifp-fix-use-after-free.patch +Patch0012: 0012-ifp-fix-original-fix-use-after-free.patch +Patch0013: 0013-pam_sss-use-unique-id-for-gdm-choice-list.patch +Patch0014: 0014-authtok-add-label-to-Smartcard-token.patch +Patch0015: 0015-pam_sss-add-certificate-label-to-reply-to-pam_sss.patch +Patch0016: 0016-add-tests-multiple-certs-same-id.patch +Patch0017: 0017-data_provider_be-Add-random-offset-default.patch +Patch0018: 0018-data_provider_be-MAN-page-update.patch +Patch0019: 0019-logs-review.patch +Patch0020: 0020-sss_format.h-include-config.h.patch +Patch0021: 0021-packet-add-sss_packet_set_body.patch +Patch0022: 0022-domain-store-hostname-and-keytab-path.patch +Patch0023: 0023-cache_req-add-helper-to-call-user-by-upn-search.patch +Patch0024: 0024-pam-fix-typo-in-debug-message.patch +Patch0025: 0025-pam-add-pam_gssapi_services-option.patch +Patch0026: 0026-pam-add-pam_gssapi_check_upn-option.patch +Patch0027: 0027-pam-add-pam_sss_gss-module-for-gssapi-authentication.patch +Patch0028: 0028-cache_req-allow-cache_req-to-return-ERR_OFFLINE-if-a.patch +Patch0029: 0029-autofs-return-ERR_OFFLINE-if-we-fail-to-get-informat.patch +Patch0030: 0030-autofs-translate-ERR_OFFLINE-to-EHOSTDOWN.patch +Patch0031: 0031-autofs-disable-fast-reply.patch +Patch0032: 0032-autofs-correlate-errors-for-different-protocol-versi.patch +Patch0033: 0033-configure-check-for-stdatomic.h.patch +Patch0034: 0034-cache_req-ignore-autofs-not-configured-error.patch +Patch0035: 0035-simple-fix-memory-leak-while-reloading-lists.patch +Patch0036: 0036-SBUS-do-not-try-to-del-non-existing-sender.patch +Patch0037: 0037-pamsrv_gssapi-fix-implicit-conversion-warning.patch +Patch0038: 0038-gssapi-default-pam_gssapi_services-to-NULL-in-domain.patch +Patch0039: 0039-pam_sss_gssapi-fix-coverity-issues.patch +Patch0040: 0040-sudo-runas-do-not-add-to-external-groups-in-IPA.patch +Patch0041: 0041-responders-add-callback-to-schedule_get_domains_task.patch +Patch0042: 0042-pam-refresh-certificate-maps-at-the-end-of-initial-d.patch +Patch0043: 0043-SBUS-set-sbus_name-before-dp_init_send.patch +Patch0044: 0044-pam_sss_gss-support-authentication-indicators.patch +Patch0045: 0045-sudo-do-not-search-by-low-usn-value-to-improve-perfo.patch +Patch0046: 0046-ldap-fix-modifytimestamp-debugging-leftovers.patch +Patch0047: 0047-ssh-restore-default-debug-level.patch ### Downstream Patches ### @@ -161,6 +205,7 @@ Recommends: libsss_sudo = %{version}-%{release} Recommends: libsss_autofs%{?_isa} = %{version}-%{release} Recommends: sssd-nfs-idmap = %{version}-%{release} Requires: libsss_idmap = %{version}-%{release} +Requires: libsss_certmap = %{version}-%{release} Requires(pre): shadow-utils %{?systemd_requires} @@ -177,6 +222,8 @@ sub-packages such as sssd-ldap. Summary: SSSD Client libraries for NSS and PAM Group: Applications/System License: LGPLv3+ +Requires: libsss_nss_idmap = %{version}-%{release} +Requires: libsss_idmap = %{version}-%{release} Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig Requires(post): /usr/sbin/alternatives @@ -211,9 +258,11 @@ Summary: Userspace tools for use with the SSSD Group: Applications/System License: GPLv3+ Requires: sssd-common = %{version}-%{release} +Requires: libsss_simpleifp = %{version}-%{release} # required by sss_obfuscate Requires: python3-sss = %{version}-%{release} Requires: python3-sssdconfig = %{version}-%{release} +Requires: libsss_certmap = %{version}-%{release} Recommends: sssd-dbus %description tools @@ -267,6 +316,8 @@ License: GPLv3+ Conflicts: sssd < 1.10.0-8.beta2 Requires: sssd-common = %{version}-%{release} Requires: sssd-krb5-common = %{version}-%{release} +Requires: libsss_idmap = %{version}-%{release} +Requires: libsss_certmap = %{version}-%{release} %description ldap Provides the LDAP back end that the SSSD can utilize to fetch identity data @@ -302,6 +353,7 @@ Summary: Common files needed for supporting PAC processing Group: Applications/System License: GPLv3+ Requires: sssd-common = %{version}-%{release} +Requires: libsss_idmap = %{version}-%{release} %description common-pac Provides common files needed by SSSD providers such as IPA and Active Directory @@ -316,8 +368,10 @@ Requires: samba-client-libs >= %{samba_package_version} Requires: sssd-common = %{version}-%{release} Requires: sssd-krb5-common = %{version}-%{release} Requires: libipa_hbac%{?_isa} = %{version}-%{release} +Requires: libsss_certmap = %{version}-%{release} Recommends: bind-utils Requires: sssd-common-pac = %{version}-%{release} +Requires: libsss_idmap = %{version}-%{release} Requires(pre): shadow-utils %description ipa @@ -333,6 +387,8 @@ Requires: samba-client-libs >= %{samba_package_version} Requires: sssd-common = %{version}-%{release} Requires: sssd-krb5-common = %{version}-%{release} Requires: sssd-common-pac = %{version}-%{release} +Requires: libsss_idmap = %{version}-%{release} +Requires: libsss_certmap = %{version}-%{release} Recommends: bind-utils Recommends: adcli Suggests: sssd-libwbclient = %{version}-%{release} @@ -482,6 +538,7 @@ Provides library that simplifies D-Bus API for the SSSD InfoPipe responder. Summary: The SSSD libwbclient implementation Group: Applications/System License: GPLv3+ and LGPLv3+ +Requires: libsss_nss_idmap = %{version}-%{release} Conflicts: libwbclient < 4.2.0-0.2.rc2 Conflicts: sssd-common < %{version}-%{release} @@ -503,6 +560,8 @@ Summary: SSSD's idmap_sss Backend for Winbind Group: Applications/System License: GPLv3+ and LGPLv3+ Conflicts: sssd-common < %{version}-%{release} +Requires: libsss_nss_idmap = %{version}-%{release} +Requires: libsss_idmap = %{version}-%{release} %description winbind-idmap The idmap_sss module provides a way for Winbind to call SSSD to map UIDs/GIDs @@ -590,6 +649,7 @@ autoreconf -ivf --enable-nfsidmaplibdir=%{_libdir}/libnfsidmap \ --disable-static \ --with-crypto=libcrypto \ + --with-libwbclient \ --disable-rpath \ --with-initscript=systemd \ --with-syslog=journald \ @@ -604,6 +664,7 @@ autoreconf -ivf make %{?_smp_mflags} all docs make -C po ja.gmo make -C po fr.gmo +make -C po zh_CN.po %check export CK_TIMEOUT_MULTIPLIER=10 @@ -825,8 +886,6 @@ done %{_libdir}/%{name}/conf/sssd.conf %{_datadir}/sssd/cfg_rules.ini -%{_datadir}/sssd/sssd.api.conf -%{_datadir}/sssd/sssd.api.d %{_mandir}/man1/sss_ssh_authorizedkeys.1* %{_mandir}/man1/sss_ssh_knownhostsproxy.1* %{_mandir}/man5/sssd.conf.5* @@ -925,6 +984,7 @@ done %license src/sss_client/COPYING src/sss_client/COPYING.LESSER %{_libdir}/libnss_sss.so.2 %{_libdir}/security/pam_sss.so +%{_libdir}/security/pam_sss_gss.so %{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so %{_libdir}/krb5/plugins/authdata/sssd_pac_plugin.so %dir %{_libdir}/cifs-utils @@ -935,6 +995,7 @@ done %dir %{_libdir}/%{name}/modules %{_libdir}/%{name}/modules/sssd_krb5_localauth_plugin.so %{_mandir}/man8/pam_sss.8* +%{_mandir}/man8/pam_sss_gss.8* %{_mandir}/man8/sssd_krb5_locator_plugin.8* %files -n libsss_sudo @@ -968,6 +1029,9 @@ done %{python3_sitelib}/SSSDConfig/*.py* %dir %{python3_sitelib}/SSSDConfig/__pycache__ %{python3_sitelib}/SSSDConfig/__pycache__/*.py* +%dir %{_datadir}/sssd +%{_datadir}/sssd/sssd.api.conf +%{_datadir}/sssd/sssd.api.d %files -n python3-sss %defattr(-,root,root,-) @@ -1197,6 +1261,106 @@ fi %{_libdir}/%{name}/modules/libwbclient.so %changelog +* Fri Feb 12 2021 Alexey Tikhonov - 2.4.0-8 +- Resolves: rhbz#1926622 - Add support to verify authentication indicators in pam_sss_gss +- Resolves: rhbz#1926454 - First smart refresh query contains modifyTimestamp even if the modifyTimestamp is 0. +- Resolves: rhbz#1893159 - Default debug level should report all errors / failures (additional patch) + +* Tue Jan 26 2021 Alexey Tikhonov - 2.4.0-7 +- Resolves: rhbz#1920001 - Do not add '%' to group names already prefixed with '%' in IPA sudo rules +- Resolves: rhbz#1918433 - sssd unable to lookup certmap rules +- Resolves: rhbz#1917382 - [abrt] [faf] sssd: dp_client_handshake_timeout(): /usr/libexec/sssd/sssd_be killed by 11 + +* Mon Jan 18 2021 Alexey Tikhonov - 2.4.0-6 +- Resolves: rhbz#1113639 - autofs: return a connection failure until maps have been fetched +- Resolves: rhbz#1915395 - Memory leak in the simple access provider +- Resolves: rhbz#1915319 - SSSD: SBUS: failures during servers startup +- Resolves: rhbz#1893698 - [RFE] sudo kerberos authentication (additional patches) + +* Mon Dec 28 2020 Alexey Tikhonov - 2.4.0-5 +- Resolves: rhbz#1631410 - Can't login with smartcard with multiple certs having same ID value +- Resolves: rhbz#1884213 - [RFE] add offline_timeout_max config option to control offline interval backoff (additional patches) +- Resolves: rhbz#1893159 - Default debug level should report all errors / failures +- Resolves: rhbz#1893698 - [RFE] sudo kerberos authentication + +* Mon Dec 21 2020 Alexey Tikhonov - 2.4.0-4 +- Resolves: rhbz#1876514 - High CPU utilization by the sssd_kcm process +- Resolves: rhbz#1876658 - filter_groups option partially filters the group from 'id' output of the user because gidNumber still appears in 'id' output [RHEL 8] +- Resolves: rhbz#1895001 - User lookups over the InfoPipe responder fail intermittently + +* Mon Dec 07 2020 Alexey Tikhonov - 2.4.0-3 +- Resolves: rhbz#1900733 - sssd_be segfaults at be_refresh_get_values_ex() due to NULL ptrs in results of sysdb_search_with_ts_attr() +- Resolves: rhbz#1876514 - High CPU utilization by the sssd_kcm process +- Resolves: rhbz#1894540 - sssd component logging is now too generic in syslog/journal +- Resolves: rhbz#1828483 - filtered ID is appearing due to strange negative cache behavior + +* Thu Nov 12 2020 Alexey Tikhonov - 2.4.0-2 +- This is to bump version to allow rebuild against rebased libldb. + +* Fri Oct 23 2020 Alexey Tikhonov - 2.4.0-1 +- Resolves: rhbz#1881992 - Rebase SSSD for RHEL 8.4 +- Resolves: rhbz#1722842 - sssd-kcm does not store TGT with ssh login using GSSAPI +- Resolves: rhbz#1734040 - sssd crash in ad_get_account_domain_search() +- Resolves: rhbz#1784459 - [RFE] tlog does not allow to exclude some users from session recording +- Resolves: rhbz#1791300 - sporadic sssd_be crash on s390x +- Resolves: rhbz#1817122 - 'getent group ldapgroupname' doesn't show any LDAP users or some LDAP users when 'rfc2307bis' schema is used with SSSD. +- Resolves: rhbz#1819012 - [RFE] Improve AD site discovery process +- Resolves: rhbz#1846778 - [RfE] `/usr/libexec/sssd/p11_child` cmdline argument '--nssdb' might be confusing when SSSD was built against OpenSSL +- Resolves: rhbz#1873715 - automount sssd issue when 2 automount maps have the same key (one un uppercase, one in lowercase) +- Resolves: rhbz#1879860 - correction in sssd.conf:pam_response_filter man page +- Resolves: rhbz#1881336 - [RFE] sssd-ldap man page modification for parameter "ldap_referrals" +- Resolves: rhbz#1883488 - [RfE] Implement a new sssd.conf option to disable the filter for AD domain local groups from trusted domains +- Resolves: rhbz#1884196 - [RFE] Add "enabled" option to domain section in config file +- Resolves: rhbz#1884205 - KCM: Increase client idle timeout to 5 minutes +- Resolves: rhbz#1884207 - [RFE] ldap: add new option ldap_library_debug_level +- Resolves: rhbz#1884213 - [RFE] add offline_timeout_max config option to control offline interval backoff +- Resolves: rhbz#1884281 - Secondary LDAP group go missing from 'id' command +- Resolves: rhbz#1884301 - [RFE] dyndns: suport asymmetric auth for nsupdate + +* Mon Sep 14 2020 Alexey Tikhonov - 2.3.0-9 +- Resolves: rhbz#1855323 - When ad_gpo_implicit_deny is True, it is permitting users to login when no gpo is applied + +* Fri Aug 21 2020 Alexey Tikhonov - 2.3.0-8 +- Resolves: rhbz#1868387 - system not enforcing GPO rule restriction. ad_gpo_implicit_deny = True is not working +- Resolves: rhbz#1854951 - sss-certmap man page change to add clarification for userPrincipalName attribute from AD schema +- Resolves: rhbz#1856861 - False errors/warnings are logged in sssd.log file after enabling 2FA prompting settings in sssd.conf +- Resolves: rhbz#1869683 - p11_child: default value of ocsp_dgst == sha256 doesn't conform RFC5019 and has to be changed to sha1 + +* Fri Aug 07 2020 Alexey Tikhonov - 2.3.0-7 +- Resolves: rhbz#1723273 - RFE: Add option to specify alternate sssd config file location with "sssctl config-check" command. +- Resolves: rhbz#1780404 - smartcards: special characters must be escaped when building search filter + +* Fri Jul 24 2020 Alexey Tikhonov - 2.3.0-6 +- Resolves: rhbz#1820574 - [sssd] RHEL 8.3 Tier 0 Localization + +* Mon Jul 20 2020 Alexey Tikhonov - 2.3.0-5 +- Resolves: rhbz#1821719 - sssd (sssd_be) is consuming 100% CPU, partially due to failing mem-cache +- Fixed "requires/provides" rpmdiff warning + +* Thu Jul 02 2020 Alexey Tikhonov - 2.3.0-4 +- Resolves: rhbz#1815584 - id_provider = proxy proxy_lib_name = files returns * in password field, breaking PAM authentication +- Resolves: rhbz#1794607 - SSSD must be able to resolve membership involving root with files provider +- Resolves: rhbz#1803134 - Improve "unlock" time when user session already active + +* Fri Jun 26 2020 Alexey Tikhonov - 2.3.0-3 +- Resolves: rhbz#1829470 - `sssd.api.conf` and `sssd.api.d` should belong to `python-sssdconfig` package +- Resolves: rhbz#1544457 - sssd fails to release file descriptor on child logs after receiving HUP +- Resolves: rhbz#1824323 - SSSD user filtering is failing on RHEL 8 after "files" provider rebuilds cache +- Resolves: rhbz#1827432 - When the passwd or group files are replaced, sssd stops monitoring the file for + inotify events, and no updates are triggered +- Resolves: rhbz#1835710 - Change the message "Please enter smart card" to "Please insert smart card" + on GDM login with smart-card +- Resolves: rhbz#1838037 - Oddjob-mkhomedir fails when using NSS compat +- Resolves: rhbz#1845904 - gdm smart card authentication does not work shortly after disconnecting from network. +- Resolves: rhbz#1845975 - sssd doesn't follow the link order of AD Group Policy Management +- Resolves: rhbz#1845980 - sssd is failing to discover other subdomains in the forest + if LDAP entries do not contain AD forest root information +- Resolves: rhbz#1845987 - Document how to prevent invalid selinux context for default home directories + in SSSD-AD direct integration. +- Resolves: rhbz#1845994 - GDM failure loop when no user mapped for smart card +- Resolves: rhbz#1846003 - GDM password prompt when cert mapped to multiple users and promptusername is False +- Resolves: rhbz#1850961 - /usr/share/systemtap/tapset/sssd_functions.stp missing a comma + * Thu Jun 11 2020 Alexey Tikhonov - 2.3.0-2 - Resolves: rhbz#Bug 1723273 - RFE: Add option to specify alternate sssd config file location with "sssctl config-check" command.