Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP3:Update
sssd
0056-certmap-sanitize-LDAP-search-filter.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0056-certmap-sanitize-LDAP-search-filter.patch of Package sssd
From 43aea6fe1cb9f94f25fdbd1bca1708766938a2e1 Mon Sep 17 00:00:00 2001 From: Sumit Bose <sbose@redhat.com> Date: Thu, 14 Feb 2019 18:35:49 +0100 Subject: [PATCH 1/8] TESTS: replace hardcoded certificates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the hardcoded certificates have a limited lifetime they are replaces by certificates from the test CA. Related to https://pagure.io/SSSD/sssd/issue/3436 Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com> --- src/tests/cmocka/test_cert_utils.c | 41 ++++-------- src/tests/cmocka/test_pam_srv.c | 104 +++++++++++------------------ 2 files changed, 50 insertions(+), 95 deletions(-) diff --git a/src/tests/cmocka/test_cert_utils.c b/src/tests/cmocka/test_cert_utils.c index f50030e49..dd58b73a7 100644 --- a/src/tests/cmocka/test_cert_utils.c +++ b/src/tests/cmocka/test_cert_utils.c @@ -34,6 +34,13 @@ #include "util/crypto/nss/nss_util.h" #include "util/crypto/sss_crypto.h" +#ifdef HAVE_TEST_CA +#include "tests/test_CA/SSSD_test_cert_pubsshkey_0001.h" +#include "tests/test_CA/SSSD_test_cert_x509_0001.h" +#else +#define SSSD_TEST_CERT_0001 "" +#define SSSD_TEST_CERT_SSH_KEY_0001 "" +#endif /* TODO: create a certificate for this test */ const uint8_t test_cert_der[] = { @@ -325,32 +332,6 @@ void test_sss_cert_derb64_to_ldap_filter(void **state) talloc_free(filter); } -#define SSH_TEST_CERT \ -"MIIECTCCAvGgAwIBAgIBCDANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ -"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ -"NDEzNDlaFw0xODA1MjQxNDEzNDlaMDIxEjAQBgNVBAoMCUlQQS5ERVZFTDEcMBoG" \ -"A1UEAwwTaXBhLWRldmVsLmlwYS5kZXZlbDCCASIwDQYJKoZIhvcNAQEBBQADggEP" \ -"ADCCAQoCggEBALfEAE0IUlOAgDTdZQGcYA03IPooixNnkUQruh0eU3uw+KYGQoS1" \ -"YCdCHJzRc+IfuqdNntgtGDIpWADRwB4h963pBImpMSU5L1T4uiHNCpvl9eMt4ynk" \ -"xduOa+JmJUvqvwe7Gj9iDql4lWmJcXvq74/yOc3MBSPQCdg/pHZU65+NjSZmZzlN" \ -"eNV3tQKrhMe6tM00pai2igXilfUpzOU2v+AX69oOesrqTUl9i2eCUirGanR9l95d" \ -"yVCcmIDJd2P2NLIkhbHGRitfTC/tQZ4G+Edg9STw8Y+4ljp2rTHs59dWRBe2Gn8Z" \ -"Zt8zZ5WuNxARVF1THI9X6ydX/uoaz8R7pfkCAwEAAaOCASYwggEiMB8GA1UdIwQY" \ -"MBaAFPci/0Km5D/L5z7YqwEc7E1/GwgcMDsGCCsGAQUFBwEBBC8wLTArBggrBgEF" \ -"BQcwAYYfaHR0cDovL2lwYS1jYS5pcGEuZGV2ZWwvY2Evb2NzcDAOBgNVHQ8BAf8E" \ -"BAMCBPAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHQGA1UdHwRtMGsw" \ -"aaAxoC+GLWh0dHA6Ly9pcGEtY2EuaXBhLmRldmVsL2lwYS9jcmwvTWFzdGVyQ1JM" \ -"LmJpbqI0pDIwMDEOMAwGA1UECgwFaXBhY2ExHjAcBgNVBAMMFUNlcnRpZmljYXRl" \ -"IEF1dGhvcml0eTAdBgNVHQ4EFgQUMydoshxYXhDXOMo/EETvrZaQuBwwDQYJKoZI" \ -"hvcNAQELBQADggEBADIrTFNvEdZGna7jD1xpiLGGUwCi11GQT+Txg5B7dydUn5U5" \ -"32zSBBZV6bsy0E+PiiAgehJObv9hBaOWnhp7ltNyQod1OLdI1t988ow2wxHvUEEi" \ -"MhRF0h2RJwdYIUIIF7XC01mKBOFj/84vvMOgLToZnGqVzArkzpr1aCaHI7EoTkpb" \ -"V16v+drZkXc47JuHg5CRjTHV/kFPm63gQ8Fstmw/dQZBzbCiVzmcG0Xm9r4jMOOf" \ -"YjVueMt/jk1LP4KoSCBY6kLMcpL5rQm53hO82rPAgV695rjdPlIUm09dvkCl28ZD" \ -"109Ju18eAaaVFewK82NDg9rsNraBKxMCBSgg0es=" - -#define SSH_PUB_KEY "AAAAB3NzaC1yc2EAAAADAQABAAABAQC3xABNCFJTgIA03WUBnGANNyD6KIsTZ5FEK7odHlN7sPimBkKEtWAnQhyc0XPiH7qnTZ7YLRgyKVgA0cAeIfet6QSJqTElOS9U+LohzQqb5fXjLeMp5MXbjmviZiVL6r8Huxo/Yg6peJVpiXF76u+P8jnNzAUj0AnYP6R2VOufjY0mZmc5TXjVd7UCq4THurTNNKWotooF4pX1KczlNr/gF+vaDnrK6k1JfYtnglIqxmp0fZfeXclQnJiAyXdj9jSyJIWxxkYrX0wv7UGeBvhHYPUk8PGPuJY6dq0x7OfXVkQXthp/GWbfM2eVrjcQEVRdUxyPV+snV/7qGs/Ee6X5" - void test_cert_to_ssh_key(void **state) { int ret; @@ -366,13 +347,13 @@ void test_cert_to_ssh_key(void **state) struct test_state *ts = talloc_get_type_abort(*state, struct test_state); assert_non_null(ts); - der = sss_base64_decode(ts, SSH_TEST_CERT, &der_size); + der = sss_base64_decode(ts, SSSD_TEST_CERT_0001, &der_size); assert_non_null(der); - exp_key = sss_base64_decode(ts, SSH_PUB_KEY, &exp_key_size); + exp_key = sss_base64_decode(ts, SSSD_TEST_CERT_SSH_KEY_0001, &exp_key_size); assert_non_null(exp_key); - ret = cert_to_ssh_key(ts, "sql:" ABS_SRC_DIR "/src/tests/cmocka/p11_nssdb", + ret = cert_to_ssh_key(ts, "sql:" ABS_BUILD_DIR "/src/tests/test_CA/p11_nssdb", der, der_size, &cert_verify_opts, &key, &key_size); assert_int_equal(ret, EOK); assert_int_equal(key_size, exp_key_size); @@ -407,8 +388,10 @@ int main(int argc, const char *argv[]) setup, teardown), cmocka_unit_test_setup_teardown(test_sss_cert_derb64_to_ldap_filter, setup, teardown), +#ifdef HAVE_TEST_CA cmocka_unit_test_setup_teardown(test_cert_to_ssh_key, setup, teardown), +#endif }; /* Set debug level to invalid value so we can decide if -d 0 was used. */ diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c index c510c2d3b..e68e81f97 100644 --- a/src/tests/cmocka/test_pam_srv.c +++ b/src/tests/cmocka/test_pam_srv.c @@ -38,6 +38,14 @@ #include "util/crypto/nss/nss_util.h" #endif +#ifdef HAVE_TEST_CA +#include "tests/test_CA/SSSD_test_cert_x509_0001.h" +#include "tests/test_CA/SSSD_test_cert_x509_0002.h" +#else +#define SSSD_TEST_CERT_0001 "" +#define SSSD_TEST_CERT_0002 "" +#endif + #define TESTS_PATH "tp_" BASE_FILE_STEM #define TEST_CONF_DB "test_pam_conf.ldb" #define TEST_DOM_NAME "pam_test" @@ -52,55 +60,11 @@ #define TEST_TOKEN_NAME "SSSD Test Token" #define TEST_MODULE_NAME "NSS-Internal" -#define TEST_KEY_ID "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7" -#define TEST_PROMPT "Server-Cert\nCN=ipa-devel.ipa.devel,O=IPA.DEVEL" -#define TEST_TOKEN_CERT \ -"MIIECTCCAvGgAwIBAgIBCTANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ -"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ -"NDE0MTVaFw0xODA1MjQxNDE0MTVaMDIxEjAQBgNVBAoMCUlQQS5ERVZFTDEcMBoG" \ -"A1UEAwwTaXBhLWRldmVsLmlwYS5kZXZlbDCCASIwDQYJKoZIhvcNAQEBBQADggEP" \ -"ADCCAQoCggEBALHvOzZy/3llvoAYxrtOpux0gDVvSuSRpTGOW/bjpgdTowvXoOb5" \ -"G9Cy/9S6be7ZJ9D95lc/J9W8tX+ShKN8Q4b74l4WjmILQJ4dUsJ/BXfvoMPR8tw/" \ -"G47dGbLZanMXdWGBSTuXhoiogZWib2DhSwrX2DbEH5L3OWooeAVU5ZWOw55/HD7O" \ -"Q/7Of7H3tf4bvxNTFkxh39KQMG28wjPZSv+SZWNHMB+rj2yZgyeHBMkoPOPesAEi" \ -"7KKHxw1MHSv2xBI1AiV+aMdKfYUMy0Rq3PrRU4274i3eaBX4Q9GnDi36K/7bHjbt" \ -"LW0YTIW/L5/cH/BO88BREjxS3bEXAQqlKOcCAwEAAaOCASYwggEiMB8GA1UdIwQY" \ -"MBaAFPci/0Km5D/L5z7YqwEc7E1/GwgcMDsGCCsGAQUFBwEBBC8wLTArBggrBgEF" \ -"BQcwAYYfaHR0cDovL2lwYS1jYS5pcGEuZGV2ZWwvY2Evb2NzcDAOBgNVHQ8BAf8E" \ -"BAMCBPAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHQGA1UdHwRtMGsw" \ -"aaAxoC+GLWh0dHA6Ly9pcGEtY2EuaXBhLmRldmVsL2lwYS9jcmwvTWFzdGVyQ1JM" \ -"LmJpbqI0pDIwMDEOMAwGA1UECgwFaXBhY2ExHjAcBgNVBAMMFUNlcnRpZmljYXRl" \ -"IEF1dGhvcml0eTAdBgNVHQ4EFgQUIJuWIts3m3uEYqJ9pUL0y7utTiEwDQYJKoZI" \ -"hvcNAQELBQADggEBAB0GyqGxtZ99fsXA1+fHfAwKOwznT7Hh8hN9efEMBJICVud+" \ -"ivUBOH6JpSTWgNLuBhrpebV/b/DSjhn+ayuvoPWng3hjwMbSEIe0euzCEdwVcokt" \ -"bwNMMSeTxSg6wbJnEyZqQEIr2h/TR9dRNxE+RbQXyamW0fUxSVT16iueL0hMwszT" \ -"jCfI/UZv3tDMHbh6D4811A0HO8daW7ufMGb/M+kDxYigJiL2gllMZ+6xba1RRgzF" \ -"8Z+9gqZhCa7FEKJOPNR9RVtJs0qUUutMZrp1zpyx0GTmXQBA7LbgPxy8L68uymEQ" \ -"XyQBwOYRORlnfGyu+Yc9c3E0Wx8Tlznz0lqPR9g=" - -#define TEST2_KEY_ID "C8D60E009EB195D01A7083EE1D5419251AA87C2C" -#define TEST2_PROMPT "ipaCert\nCN=IPA RA,O=IPA.DEVEL" -#define TEST_TOKEN_2ND_CERT \ -"MIIDazCCAlOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ -"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ -"NDEzMDFaFw0xODA1MTMxNDEzMDFaMCUxEjAQBgNVBAoMCUlQQS5ERVZFTDEPMA0G" \ -"A1UEAwwGSVBBIFJBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3abE" \ -"8LmIc6QN16VVxsMlN/rrCOoZKyyJolSzpP4+K66t+KZUiW/1j1MZogjyYyD39U1F" \ -"zpa2H+pID74XYrdiqP7sp+uE9/k2XOv/nN3FobXDt+fSINLDriCmxNhUZqpgo2uq" \ -"Mmka+yx2iJZwkntEoJTcd3aynoa2Sa2ZZbkMBy5p6/pUQKwnD6scOwe6mUDppIBK" \ -"+ZZRm+u/NDdIRFI5wfKLRR1r/ONaJA9nz1TxSEsgLsjG/1m+Zbb6lGG4pePIFkQ9" \ -"Iotpi64obBh93oIxzQR29lBG/FMjQVHlPIbx+xuGx11Vtp5pAomgFz0HRrj0leI7" \ -"bROE+jnC/VGPLQD2aQIDAQABo4GWMIGTMB8GA1UdIwQYMBaAFPci/0Km5D/L5z7Y" \ -"qwEc7E1/GwgcMEEGCCsGAQUFBwEBBDUwMzAxBggrBgEFBQcwAYYlaHR0cDovL2lw" \ -"YS1kZXZlbC5pcGEuZGV2ZWw6ODAvY2Evb2NzcDAOBgNVHQ8BAf8EBAMCBPAwHQYD" \ -"VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBg" \ -"4Sppx2C3eXPJ4Pd9XElkQPOaBReXf1vV0uk/GlK+rG+aAqAkA2Lryx5PK/iAuzAU" \ -"M6JUpELuQYgqugoCgBXMgsMlpAO/0C3CFq4ZH3KgIsRlRngKPrt6RG0UPMRD1CE2" \ -"tSVkwUWvyK83lDiu2BbWDXyMyz5eZOlp7uHusf5BKvob8jEndHj1YzaNTmVSsDM5" \ -"kiIwf8qgFhsO1HCq08PtAnbVHhqkcvnmIJN98eNWNfTKodDmFVbN8gB0wK+WB5ii" \ -"WVOw7+3/zF1QgqnYX3t+kPLRryip/wvTZkzXWwMNj/W6UHgjNF/4gWGoBgCHu+u3" \ -"EvjMmbVSrEkesibpGQS5" +#define TEST_KEY_ID "C554C9F82C2A9D58B70921C143304153A8A42F17" +#define TEST_PROMPT "SSSD test cert 0001 - SSSD\nCN=SSSD test cert 0001,OU=SSSD test,O=SSSD" +#define TEST2_KEY_ID "5405842D56CF31F0BB025A695C5F3E907051C5B9" +#define TEST2_PROMPT "SSSD test cert 0002 - SSSD\nCN=SSSD test cert 0002,OU=SSSD test,O=SSSD" static char CACHED_AUTH_TIMEOUT_STR[] = "4"; static const int CACHED_AUTH_TIMEOUT = 4; @@ -187,7 +151,7 @@ static errno_t setup_nss_db(void) DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n"); return ret; } - ret = fprintf(fp, "parameters=configdir='sql:%s/src/tests/cmocka/p11_nssdb' dbSlotDescription='SSSD Test Slot' dbTokenDescription='SSSD Test Token' secmod='secmod.db' flags=readOnly \n\n", ABS_SRC_DIR); + ret = fprintf(fp, "parameters=configdir='sql:%s/src/tests/test_CA/p11_nssdb' dbSlotDescription='SSSD Test Slot' dbTokenDescription='SSSD Test Token' secmod='secmod.db' flags=readOnly \n\n", ABS_BUILD_DIR); if (ret < 0) { DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n"); return ret; @@ -208,7 +172,7 @@ static errno_t setup_nss_db(void) DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n"); return ret; } - ret = fprintf(fp, "parameters=configdir='sql:%s/src/tests/cmocka/p11_nssdb_2certs' dbSlotDescription='SSSD Test Slot' dbTokenDescription='SSSD Test Token' secmod='secmod.db' flags=readOnly \n\n", ABS_SRC_DIR); + ret = fprintf(fp, "parameters=configdir='sql:%s/src/tests/test_CA/p11_nssdb_2certs' dbSlotDescription='SSSD Test Slot' dbTokenDescription='SSSD Test Token' secmod='secmod.db' flags=readOnly \n\n", ABS_BUILD_DIR); if (ret < 0) { DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n"); return ret; @@ -451,6 +415,7 @@ static int pam_test_setup(void **state) return 0; } +#ifdef HAVE_TEST_CA #ifdef HAVE_NSS static int pam_test_setup_no_verification(void **state) { @@ -476,6 +441,7 @@ static int pam_test_setup_no_verification(void **state) return 0; } #endif /* HAVE_NSS */ +#endif /* HAVE_TEST_CA */ static int pam_cached_test_setup(void **state) { @@ -1915,6 +1881,7 @@ static int test_lookup_by_cert_cb(void *pvt) return EOK; } + static int test_lookup_by_cert_cb_2nd_cert_same_user(void *pvt) { int ret; @@ -1927,7 +1894,7 @@ static int test_lookup_by_cert_cb_2nd_cert_same_user(void *pvt) attrs = sysdb_new_attrs(pam_test_ctx); assert_non_null(attrs); - der = sss_base64_decode(pam_test_ctx, TEST_TOKEN_2ND_CERT, &der_size); + der = sss_base64_decode(pam_test_ctx, SSSD_TEST_CERT_0002, &der_size); assert_non_null(der); ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); @@ -2033,7 +2000,7 @@ void test_pam_preauth_cert_match(void **state) set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, - test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); + test_lookup_by_cert_cb, SSSD_TEST_CERT_0001, false); will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); @@ -2057,7 +2024,7 @@ void test_pam_preauth_cert_match_gdm_smartcard(void **state) mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, "gdm-smartcard", test_lookup_by_cert_cb, - TEST_TOKEN_CERT, false); + SSSD_TEST_CERT_0001, false); will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); @@ -2080,7 +2047,7 @@ void test_pam_preauth_cert_match_wrong_user(void **state) mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, test_lookup_by_cert_wrong_user_cb, - TEST_TOKEN_CERT, false); + SSSD_TEST_CERT_0001, false); will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); @@ -2111,7 +2078,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, TEST_TOKEN_CERT, false); + test_lookup_by_cert_cb, SSSD_TEST_CERT_0001, false); mock_account_recv_simple(); mock_parse_inp("pamuser", NULL, EOK); @@ -2140,7 +2107,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, TEST_TOKEN_CERT, false); + test_lookup_by_cert_cb, SSSD_TEST_CERT_0001, false); will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); @@ -2162,7 +2129,8 @@ void test_pam_preauth_cert_no_logon_name_double_cert(void **state) set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, - test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, false); + test_lookup_by_cert_double_cb, SSSD_TEST_CERT_0001, + false); will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); @@ -2185,7 +2153,8 @@ void test_pam_preauth_cert_no_logon_name_double_cert_with_hint(void **state) pam_test_ctx->rctx->domains->user_name_hint = true; mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, - test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, false); + test_lookup_by_cert_double_cb, SSSD_TEST_CERT_0001, + false); will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); @@ -2258,8 +2227,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", "NSS-Internal", - "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7", NULL, - test_lookup_by_cert_cb, TEST_TOKEN_CERT, true); + "C554C9F82C2A9D58B70921C143304153A8A42F17", NULL, + test_lookup_by_cert_cb, SSSD_TEST_CERT_0001, true); will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); @@ -2292,8 +2261,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", "NSS-Internal", - "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7", NULL, - test_lookup_by_cert_cb, TEST_TOKEN_CERT, true); + "C554C9F82C2A9D58B70921C143304153A8A42F17", NULL, + test_lookup_by_cert_cb, SSSD_TEST_CERT_0001, true); mock_account_recv_simple(); mock_parse_inp("pamuser", NULL, EOK); @@ -2354,8 +2323,9 @@ void test_pam_cert_auth_double_cert(void **state) mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token", "NSS-Internal", - "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7", NULL, - test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, true); + "C554C9F82C2A9D58B70921C143304153A8A42F17", NULL, + test_lookup_by_cert_double_cb, SSSD_TEST_CERT_0001, + true); will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); @@ -2380,7 +2350,7 @@ void test_pam_cert_preauth_2certs_one_mapping(void **state) set_cert_auth_param(pam_test_ctx->pctx, NSS_DB_2CERTS); mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, - test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); + test_lookup_by_cert_cb, SSSD_TEST_CERT_0001, false); will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); @@ -2403,7 +2373,7 @@ void test_pam_cert_preauth_2certs_two_mappings(void **state) mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, test_lookup_by_cert_cb_2nd_cert_same_user, - TEST_TOKEN_CERT, false); + SSSD_TEST_CERT_0001, false); will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); @@ -2812,6 +2782,7 @@ int main(int argc, const char *argv[]) cmocka_unit_test_setup_teardown(test_pam_cached_auth_failed_combined_pw_with_cached_2fa, pam_cached_test_setup, pam_test_teardown), +#ifdef HAVE_TEST_CA /* p11_child is not built without NSS */ #ifdef HAVE_NSS cmocka_unit_test_setup_teardown(test_pam_preauth_cert_nocert, @@ -2856,6 +2827,7 @@ int main(int argc, const char *argv[]) cmocka_unit_test_setup_teardown(test_pam_cert_auth_no_logon_name_no_key_id, pam_test_setup, pam_test_teardown), #endif /* HAVE_NSS */ +#endif /* HAVE_TEST_CA */ cmocka_unit_test_setup_teardown(test_filter_response, pam_test_setup, pam_test_teardown), -- 2.39.1 From 50b0dd3c23f252ecad49792f147d776247f0b9d3 Mon Sep 17 00:00:00 2001 From: Tomas Halman <thalman@redhat.com> Date: Fri, 31 Jul 2020 11:12:02 +0200 Subject: [PATCH 2/8] UTIL: DN sanitization Some of the ldap servers returns DN in attributes such as isMemberOf with spaces like dc=example, dc=com. That should be fine and we should ignore them (cut them out) instead of escaping. Resolves: https://github.com/SSSD/sssd/issues/5261 Reviewed-by: Alexey Tikhonov <atikhono@redhat.com> (cherry picked from commit 093061f553ab0a2c316794221e79779fb1bd40d2) Reviewed-by: Alexey Tikhonov <atikhono@redhat.com> --- src/tests/cmocka/test_utils.c | 69 +++++++++++++++++++ src/util/util.c | 126 ++++++++++++++++++++++++++++++++++ src/util/util.h | 20 ++++++ 3 files changed, 215 insertions(+) diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c index 1a8699a2a..998f50d8a 100644 --- a/src/tests/cmocka/test_utils.c +++ b/src/tests/cmocka/test_utils.c @@ -1849,6 +1849,72 @@ static void test_sss_get_domain_mappings_content(void **state) * capaths might not be as expected. */ } +static void test_sss_filter_sanitize_dn(void **state) +{ + TALLOC_CTX *tmp_ctx; + char *trimmed; + int ret; + const char *DN = "cn=user,ou=people,dc=example,dc=com"; + + tmp_ctx = talloc_new(NULL); + assert_non_null(tmp_ctx); + + /* test that we remove spaces around '=' and ','*/ + ret = sss_filter_sanitize_dn(tmp_ctx, DN, &trimmed); + assert_int_equal(ret, EOK); + assert_string_equal(DN, trimmed); + talloc_free(trimmed); + + ret = sss_filter_sanitize_dn(tmp_ctx, "cn=user,ou=people,dc=example,dc=com", &trimmed); + assert_int_equal(ret, EOK); + assert_string_equal(DN, trimmed); + talloc_free(trimmed); + + ret = sss_filter_sanitize_dn(tmp_ctx, "cn= user,ou =people,dc = example,dc = com", &trimmed); + assert_int_equal(ret, EOK); + assert_string_equal(DN, trimmed); + talloc_free(trimmed); + + ret = sss_filter_sanitize_dn(tmp_ctx, "cn=user, ou=people ,dc=example , dc=com", &trimmed); + assert_int_equal(ret, EOK); + assert_string_equal(DN, trimmed); + talloc_free(trimmed); + + ret = sss_filter_sanitize_dn(tmp_ctx, "cn=user, ou=people ,dc=example , dc=com", &trimmed); + assert_int_equal(ret, EOK); + assert_string_equal(DN, trimmed); + talloc_free(trimmed); + + ret = sss_filter_sanitize_dn(tmp_ctx, "cn= user, ou =people ,dc = example , dc = com", &trimmed); + assert_int_equal(ret, EOK); + assert_string_equal(DN, trimmed); + talloc_free(trimmed); + + ret = sss_filter_sanitize_dn(tmp_ctx, " cn=user,ou=people,dc=example,dc=com ", &trimmed); + assert_int_equal(ret, EOK); + assert_string_equal(DN, trimmed); + talloc_free(trimmed); + + ret = sss_filter_sanitize_dn(tmp_ctx, " cn=user, ou=people, dc=example, dc=com ", &trimmed); + assert_int_equal(ret, EOK); + assert_string_equal(DN, trimmed); + talloc_free(trimmed); + + /* test that we keep spaces inside a value */ + ret = sss_filter_sanitize_dn(tmp_ctx, "cn = user one, ou=people branch, dc=example, dc=com", &trimmed); + assert_int_equal(ret, EOK); + assert_string_equal("cn=user\\20one,ou=people\\20\\20branch,dc=example,dc=com", trimmed); + talloc_free(trimmed); + + /* test that we keep escape special chars like () */ + ret = sss_filter_sanitize_dn(tmp_ctx, "cn = user one, ou=p(e)ople, dc=example, dc=com", &trimmed); + assert_int_equal(ret, EOK); + assert_string_equal("cn=user\\20one,ou=p\\28e\\29ople,dc=example,dc=com", trimmed); + talloc_free(trimmed); + + talloc_free(tmp_ctx); +} + int main(int argc, const char *argv[]) { poptContext pc; @@ -1945,6 +2011,9 @@ int main(int argc, const char *argv[]) cmocka_unit_test_setup_teardown(test_sss_get_domain_mappings_content, setup_dom_list_with_subdomains, teardown_dom_list), + cmocka_unit_test_setup_teardown(test_sss_filter_sanitize_dn, + setup_leak_tests, + teardown_leak_tests), }; /* Set debug level to invalid value so we can decide if -d 0 was used. */ diff --git a/src/util/util.c b/src/util/util.c index e3efa7fef..aaf3609c3 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -530,6 +530,132 @@ errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx, return sss_filter_sanitize_ex(mem_ctx, input, sanitized, NULL); } +/* There is similar function ldap_dn_normalize in openldap. + * To avoid dependecies across project we have this own func. + * Also ldb can do this but doesn't handle all the cases + */ +static errno_t sss_trim_dn(TALLOC_CTX *mem_ctx, + const char *input, + char **trimmed) +{ + int i = 0; + int o = 0; + int s; + char *output; + enum sss_trim_dn_state { + SSS_TRIM_DN_STATE_READING_NAME, + SSS_TRIM_DN_STATE_READING_VALUE + } state = SSS_TRIM_DN_STATE_READING_NAME; + + *trimmed = NULL; + + output = talloc_array(mem_ctx, char, strlen(input) + 1); + if (!output) { + return ENOMEM; + } + + /* skip leading spaces */ + while(isspace(input[i])) { + ++i; + } + + while(input[i] != '\0') { + if (!isspace(input[i])) { + switch (input[i]) { + case '=': + output[o++] = input[i++]; + if (state == SSS_TRIM_DN_STATE_READING_NAME) { + while (isspace(input[i])) { + ++i; + } + state = SSS_TRIM_DN_STATE_READING_VALUE; + } + break; + case ',': + output[o++] = input[i++]; + if (state == SSS_TRIM_DN_STATE_READING_VALUE) { + while (isspace(input[i])) { + ++i; + } + state = SSS_TRIM_DN_STATE_READING_NAME; + } + break; + case '\\': + output[o++] = input[i++]; + if (input[i] != '\0') { + output[o++] = input[i++]; + } + break; + default: + if (input[i] != '\0') { + output[o++] = input[i++]; + } + break; + } + + continue; + } + + /* non escaped space found */ + s = 1; + while (isspace(input[i + s])) { + ++s; + } + + switch (state) { + case SSS_TRIM_DN_STATE_READING_NAME: + if (input[i + s] != '=') { + /* this is not trailing space - should not be removed */ + while (isspace(input[i])) { + output[o++] = input[i++]; + } + } else { + i += s; + } + break; + case SSS_TRIM_DN_STATE_READING_VALUE: + if (input[i + s] != ',') { + /* this is not trailing space - should not be removed */ + while (isspace(input[i])) { + output[o++] = input[i++]; + } + } else { + i += s; + } + break; + } + } + + output[o--] = '\0'; + + /* trim trailing space */ + while (o >= 0 && isspace(output[o])) { + output[o--] = '\0'; + } + + *trimmed = output; + return EOK; +} + +errno_t sss_filter_sanitize_dn(TALLOC_CTX *mem_ctx, + const char *input, + char **sanitized) +{ + errno_t ret; + char *trimmed_dn = NULL; + + ret = sss_trim_dn(mem_ctx, input, &trimmed_dn); + if (ret != EOK) { + goto done; + } + + ret = sss_filter_sanitize_ex(mem_ctx, trimmed_dn, sanitized, NULL); + + done: + talloc_free(trimmed_dn); + return ret; +} + char * sss_escape_ip_address(TALLOC_CTX *mem_ctx, int family, const char *addr) { diff --git a/src/util/util.h b/src/util/util.h index 0b52bc121..80368b152 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -470,6 +470,26 @@ errno_t sss_filter_sanitize_for_dom(TALLOC_CTX *mem_ctx, char **sanitized, char **lc_sanitized); +/* Sanitize an input string (e.g. a DN) for use in + * an LDAP/LDB filter + * + * It is basically the same as sss_filter_sanitize(_ex), + * just extra spaces inside DN around '=' and ',' are removed + * before sanitizing other characters . According the documentation + * spaces in DN are allowed and some ldap servers can return them + * in isMemberOf or member attributes. + * + * (dc = my example, dc = com => dc=my\20example,dc=com) + * + * Returns a newly-constructed string attached to mem_ctx + * It will fail only on an out of memory condition, where it + * will return ENOMEM. + * + */ +errno_t sss_filter_sanitize_dn(TALLOC_CTX *mem_ctx, + const char *input, + char **sanitized); + char * sss_escape_ip_address(TALLOC_CTX *mem_ctx, int family, const char *addr); -- 2.39.1 From f6ee62fd13bc671642f1857773849b514e89b3c9 Mon Sep 17 00:00:00 2001 From: Tomas Halman <thalman@redhat.com> Date: Fri, 31 Jul 2020 11:21:44 +0200 Subject: [PATCH 3/8] UTIL: Use sss_sanitize_dn where we deal with DN Resolves: https://github.com/SSSD/sssd/issues/5261 Reviewed-by: Alexey Tikhonov <atikhono@redhat.com> (cherry picked from commit 21b9417e14ce35a2548c309642325ac43103d51e) Reviewed-by: Alexey Tikhonov <atikhono@redhat.com> --- src/db/sysdb_ops.c | 2 +- src/providers/ipa/ipa_deskprofile_rules.c | 2 +- src/providers/ipa/ipa_hbac_rules.c | 2 +- src/providers/ipa/ipa_netgroups.c | 2 +- src/providers/ldap/sdap_async_groups.c | 2 +- src/providers/ldap/sdap_async_groups_ad.c | 2 +- src/providers/ldap/sdap_async_initgroups.c | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 7427c8b2e..f7c899080 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -3329,7 +3329,7 @@ errno_t sysdb_search_by_orig_dn(TALLOC_CTX *mem_ctx, return ENOMEM; } - ret = sss_filter_sanitize(tmp_ctx, member_dn, &sanitized_dn); + ret = sss_filter_sanitize_dn(tmp_ctx, member_dn, &sanitized_dn); if (ret != EOK) { goto done; } diff --git a/src/providers/ipa/ipa_deskprofile_rules.c b/src/providers/ipa/ipa_deskprofile_rules.c index 65994356e..cce6184db 100644 --- a/src/providers/ipa/ipa_deskprofile_rules.c +++ b/src/providers/ipa/ipa_deskprofile_rules.c @@ -91,7 +91,7 @@ ipa_deskprofile_rule_info_send(TALLOC_CTX *mem_ctx, goto immediate; } - ret = sss_filter_sanitize(state, host_dn, &host_dn_clean); + ret = sss_filter_sanitize_dn(state, host_dn, &host_dn_clean); if (ret != EOK) { goto immediate; } diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c index 0634a277e..e2c97ae3d 100644 --- a/src/providers/ipa/ipa_hbac_rules.c +++ b/src/providers/ipa/ipa_hbac_rules.c @@ -84,7 +84,7 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, goto immediate; } - ret = sss_filter_sanitize(state, host_dn, &host_dn_clean); + ret = sss_filter_sanitize_dn(state, host_dn, &host_dn_clean); if (ret != EOK) goto immediate; state->ev = ev; diff --git a/src/providers/ipa/ipa_netgroups.c b/src/providers/ipa/ipa_netgroups.c index 5c929a485..66342edd7 100644 --- a/src/providers/ipa/ipa_netgroups.c +++ b/src/providers/ipa/ipa_netgroups.c @@ -376,7 +376,7 @@ static void ipa_get_netgroups_process(struct tevent_req *subreq) continue; } - ret = sss_filter_sanitize(state, orig_dn, &dn); + ret = sss_filter_sanitize_dn(state, orig_dn, &dn); if (ret != EOK) { goto done; } diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c index 77acded7a..0a55795f0 100644 --- a/src/providers/ldap/sdap_async_groups.c +++ b/src/providers/ldap/sdap_async_groups.c @@ -53,7 +53,7 @@ static int sdap_find_entry_by_origDN(TALLOC_CTX *memctx, return ENOMEM; } - ret = sss_filter_sanitize(tmpctx, orig_dn, &sanitized_dn); + ret = sss_filter_sanitize_dn(tmpctx, orig_dn, &sanitized_dn); if (ret != EOK) { ret = ENOMEM; goto done; diff --git a/src/providers/ldap/sdap_async_groups_ad.c b/src/providers/ldap/sdap_async_groups_ad.c index 3f842b26d..c954398bb 100644 --- a/src/providers/ldap/sdap_async_groups_ad.c +++ b/src/providers/ldap/sdap_async_groups_ad.c @@ -91,7 +91,7 @@ sdap_get_ad_match_rule_members_send(TALLOC_CTX *mem_ctx, } /* Sanitize it in case we have special characters in DN */ - ret = sss_filter_sanitize(state, group_dn, &sanitized_group_dn); + ret = sss_filter_sanitize_dn(state, group_dn, &sanitized_group_dn); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Could not sanitize group DN: %s\n", diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c index 326294a1c..6e0f42277 100644 --- a/src/providers/ldap/sdap_async_initgroups.c +++ b/src/providers/ldap/sdap_async_initgroups.c @@ -1634,7 +1634,7 @@ static struct tevent_req *sdap_initgr_rfc2307bis_send( attr_filter, &state->attrs, NULL); if (ret != EOK) goto done; - ret = sss_filter_sanitize(state, orig_dn, &clean_orig_dn); + ret = sss_filter_sanitize_dn(state, orig_dn, &clean_orig_dn); if (ret != EOK) goto done; use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( @@ -2416,7 +2416,7 @@ static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req) goto done; } - ret = sss_filter_sanitize(tmp_ctx, state->orig_dn, &clean_orig_dn); + ret = sss_filter_sanitize_dn(tmp_ctx, state->orig_dn, &clean_orig_dn); if (ret != EOK) { goto done; } -- 2.39.1 From c8dda38da5fd4223df942a455c88d86d129d51d5 Mon Sep 17 00:00:00 2001 From: Tomas Halman <thalman@redhat.com> Date: Wed, 19 Aug 2020 15:17:44 +0200 Subject: [PATCH 4/8] UTIL: Use sss_sanitize_dn where we deal with DN 2 Tests show that also ldb_dn_get_linearized can return DN with extra spaces. We have to trim that too. Resolves: https://github.com/SSSD/sssd/issues/5261 Reviewed-by: Alexey Tikhonov <atikhono@redhat.com> (cherry picked from commit fe0f1e64e8a77dadde699495c7eb368ce61ac992) Reviewed-by: Alexey Tikhonov <atikhono@redhat.com> --- src/ldb_modules/memberof.c | 6 +++--- src/providers/ldap/ldap_id_cleanup.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ldb_modules/memberof.c b/src/ldb_modules/memberof.c index 5e1ff95a8..7651fe09f 100644 --- a/src/ldb_modules/memberof.c +++ b/src/ldb_modules/memberof.c @@ -1364,7 +1364,7 @@ static int memberof_del(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - sret = sss_filter_sanitize(del_ctx, dn, &clean_dn); + sret = sss_filter_sanitize_dn(del_ctx, dn, &clean_dn); if (sret != 0) { talloc_free(ctx); return LDB_ERR_OPERATIONS_ERROR; @@ -1781,7 +1781,7 @@ static int mbof_del_execute_op(struct mbof_del_operation *delop) return LDB_ERR_OPERATIONS_ERROR; } - ret = sss_filter_sanitize(del_ctx, dn, &clean_dn); + ret = sss_filter_sanitize_dn(del_ctx, dn, &clean_dn); if (ret != 0) { return LDB_ERR_OPERATIONS_ERROR; } @@ -3058,7 +3058,7 @@ static int mbof_get_ghost_from_parent(struct mbof_mod_del_op *igh) return LDB_ERR_OPERATIONS_ERROR; } - ret = sss_filter_sanitize(igh, dn, &clean_dn); + ret = sss_filter_sanitize_dn(igh, dn, &clean_dn); if (ret != 0) { return LDB_ERR_OPERATIONS_ERROR; } diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c index 8c0f0c18b..cd10126f4 100644 --- a/src/providers/ldap/ldap_id_cleanup.c +++ b/src/providers/ldap/ldap_id_cleanup.c @@ -422,7 +422,7 @@ static int cleanup_groups(TALLOC_CTX *memctx, } /* sanitize dn */ - ret = sss_filter_sanitize(tmpctx, dn, &sanitized_dn); + ret = sss_filter_sanitize_dn(tmpctx, dn, &sanitized_dn); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "sss_filter_sanitize failed: %s:[%d]\n", -- 2.39.1 From ec86e5187bc5ff1fc993fd8813b3e93f90f0d5f7 Mon Sep 17 00:00:00 2001 From: Sumit Bose <sbose@redhat.com> Date: Wed, 26 Aug 2020 15:40:53 +0200 Subject: [PATCH 5/8] ldap: use member DN to create ghost user hash table Reviewed-by: Alexey Tikhonov <atikhono@redhat.com> (cherry picked from commit 50d0d154cedb6915ab321b47c40851c40e91cf41) Reviewed-by: Alexey Tikhonov <atikhono@redhat.com> --- src/db/sysdb.h | 1 + src/providers/ldap/sdap.c | 10 ++++++++++ src/providers/ldap/sdap_async_groups.c | 17 +++++++++++++++- src/providers/ldap/sdap_async_nested_groups.c | 20 +++++++++++++++++-- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 2660314a7..fcfb81dfe 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -128,6 +128,7 @@ #define SYSDB_UPN "userPrincipalName" #define SYSDB_CANONICAL_UPN "canonicalUserPrincipalName" #define SYSDB_CCACHE_FILE "ccacheFile" +#define SYSDB_DN_FOR_MEMBER_HASH_TABLE "dnForMemberHashTable" #define SYSDB_ORIG_DN "originalDN" #define SYSDB_ORIG_MODSTAMP "originalModifyTimestamp" diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c index cb55de7f6..632df1134 100644 --- a/src/providers/ldap/sdap.c +++ b/src/providers/ldap/sdap.c @@ -771,6 +771,16 @@ errno_t sdap_parse_deref(TALLOC_CTX *mem_ctx, goto done; } + /* The dereference control seems to return the DN from the dereference + * attribute (e.g. member) so we can use it as key for the hash table + * later. */ + ret = sysdb_attrs_add_string(res[mi]->attrs, + SYSDB_DN_FOR_MEMBER_HASH_TABLE, orig_dn); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n"); + goto done; + } + for (dval = dref->attrVals; dval != NULL; dval = dval->next) { DEBUG(SSSDBG_TRACE_INTERNAL, "Dereferenced attribute: %s\n", dval->type); diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c index 0a55795f0..4fbd8cf7b 100644 --- a/src/providers/ldap/sdap_async_groups.c +++ b/src/providers/ldap/sdap_async_groups.c @@ -2510,6 +2510,7 @@ static errno_t sdap_nested_group_populate_users(TALLOC_CTX *mem_ctx, struct ldb_message_element *el; const char *username; const char *original_dn; + const char *hash_key_dn; struct sss_domain_info *user_dom; struct sdap_domain *sdap_dom; @@ -2608,8 +2609,22 @@ static errno_t sdap_nested_group_populate_users(TALLOC_CTX *mem_ctx, SYSDB_MOD_REP); if (ret != EOK) goto done; } else { + /* The DN of the user object and the DN in the member attribute + * might differ, e.g. in case. Since we later search the hash with + * DNs from the member attribute we should try to use DN from the + * member attribute here as well. This should be added earlier in + * the SYSDB_DN_FOR_MEMBER_HASH_TABLE attribute. If this does not + * exists we fall-back to original_dn which should work in the + * most cases as well. */ + ret = sysdb_attrs_get_string(users[i], + SYSDB_DN_FOR_MEMBER_HASH_TABLE, + &hash_key_dn); + if (ret != EOK) { + hash_key_dn = original_dn; + } + key.type = HASH_KEY_STRING; - key.str = talloc_steal(ghosts, discard_const(original_dn)); + key.str = talloc_steal(ghosts, discard_const(hash_key_dn)); value.type = HASH_VALUE_PTR; /* Already qualified from sdap_get_user_primary_name() */ value.ptr = talloc_steal(ghosts, discard_const(username)); diff --git a/src/providers/ldap/sdap_async_nested_groups.c b/src/providers/ldap/sdap_async_nested_groups.c index 0a69e96f4..056ee2da0 100644 --- a/src/providers/ldap/sdap_async_nested_groups.c +++ b/src/providers/ldap/sdap_async_nested_groups.c @@ -241,9 +241,12 @@ static errno_t sdap_nested_group_hash_entry(hash_table_t *table, const char *name = NULL; errno_t ret; - ret = sysdb_attrs_get_string(entry, SYSDB_ORIG_DN, &name); + ret = sysdb_attrs_get_string(entry, SYSDB_DN_FOR_MEMBER_HASH_TABLE, &name); if (ret != EOK) { - return ret; + ret = sysdb_attrs_get_string(entry, SYSDB_ORIG_DN, &name); + if (ret != EOK) { + return ret; + } } return sdap_nested_group_hash_insert(table, name, entry, false, table_name); @@ -1498,6 +1501,19 @@ sdap_nested_group_single_step_process(struct tevent_req *subreq) } } + /* The original DN of the user object itself might differ from the one + * used in the member attribute, e.g. different case. To make sure if + * can be found in a hash table when iterating over group members the + * DN from the member attribute used for the search as saved as well. + */ + ret = sysdb_attrs_add_string(entry, + SYSDB_DN_FOR_MEMBER_HASH_TABLE, + state->current_member->dn); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n"); + goto done; + } + /* save user in hash table */ ret = sdap_nested_group_hash_user(state->group_ctx, entry); if (ret == EEXIST) { -- 2.39.1 From 6aa38a9e4a27245b2b7a42bffa338eec7de1132e Mon Sep 17 00:00:00 2001 From: Sumit Bose <sbose@redhat.com> Date: Wed, 2 Sep 2020 12:37:27 +0200 Subject: [PATCH 6/8] intg: allow member DN to have a different case Make sure that group members are added properly to the group even if the user DN in the RFC2307bis member attribute differs in case from the original DN of the user object. Reviewed-by: Alexey Tikhonov <atikhono@redhat.com> (cherry picked from commit 88631392e9172ae4fa3e411398516a2f39f0060e) Reviewed-by: Alexey Tikhonov <atikhono@redhat.com> --- src/tests/intg/test_ldap.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/tests/intg/test_ldap.py b/src/tests/intg/test_ldap.py index a6659b1b7..352875291 100644 --- a/src/tests/intg/test_ldap.py +++ b/src/tests/intg/test_ldap.py @@ -299,6 +299,25 @@ def sanity_rfc2307_bis(request, ldap_conn): return None +@pytest.fixture +def member_with_different_cases_rfc2307_bis(request, ldap_conn): + """ + Create a group where the user DN values of the RFC2307bis member attribute + differ in case from the original DN of the user object. + """ + ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) + ent_list.add_user("user1", 1001, 2001) + ent_list.add_user("user2", 1002, 2002) + + ent_list.add_group_bis("two_user_group", 2012, ["USER1", "uSeR2"]) + + create_ldap_fixture(request, ldap_conn, ent_list) + conf = format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + create_conf_fixture(request, conf) + create_sssd_fixture(request) + return None + + def expected_list_to_name_dict(entries): return dict((u["name"], u) for u in entries) @@ -390,6 +409,22 @@ def test_sanity_rfc2307_bis(ldap_conn, sanity_rfc2307_bis): grp.getgrgid(1) +def test_member_with_different_cases_rfc2307_bis( + ldap_conn, + member_with_different_cases_rfc2307_bis): + """ + Regression test for https://bugzilla.redhat.com/show_bug.cgi?id=1817122 + Make sure that group members are added properly to the group even if the + user DN in the RFC2307bis member attribute differs in case from the + original DN of the user object. + """ + group_pattern = expected_list_to_name_dict([ + dict(name='two_user_group', passwd='*', gid=2012, + mem=ent.contains_only("user1", "user2")), + ]) + ent.assert_each_group_by_name(group_pattern) + + @pytest.fixture def refresh_after_cleanup_task(request, ldap_conn): ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) -- 2.39.1 From 87305fec9d628b32873fea6b56b8c3b572d927ef Mon Sep 17 00:00:00 2001 From: Sumit Bose <sbose@redhat.com> Date: Tue, 27 Nov 2018 16:40:01 +0100 Subject: [PATCH 7/8] certmap: add sss_certmap_display_cert_content() To make debugging and writing certificate mapping and matching rules more easy a new function is added to libsss_certmap to display the certificate content as seen by libsss_certmap. Please note that the actual output might change in future. Reviewed-by: Jakub Hrozek <jhrozek@redhat.com> (cherry picked from commit 1c40208aa1e0f9a17cc4f336c99bcaa6977592d3) Reviewed-by: Alexey Tikhonov <atikhono@redhat.com> Reviewed-by: Justin Stephenson <jstephen@redhat.com> --- Makefile.am | 2 +- src/lib/certmap/sss_certmap.c | 142 ++++++++++++++++++++++ src/lib/certmap/sss_certmap.exports | 5 + src/lib/certmap/sss_certmap.h | 18 +++ src/lib/certmap/sss_certmap_int.h | 31 ++++- src/lib/certmap/sss_certmap_krb5_match.c | 145 +++++++++++------------ 6 files changed, 261 insertions(+), 82 deletions(-) diff --git a/Makefile.am b/Makefile.am index 03729da38..70aee984c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1836,7 +1836,7 @@ libsss_certmap_la_LIBADD = \ $(NULL) libsss_certmap_la_LDFLAGS = \ -Wl,--version-script,$(srcdir)/src/lib/certmap/sss_certmap.exports \ - -version-info 0:0:0 + -version-info 1:0:1 if HAVE_NSS libsss_certmap_la_SOURCES += \ diff --git a/src/lib/certmap/sss_certmap.c b/src/lib/certmap/sss_certmap.c index f6f6f9804..c60ac24c6 100644 --- a/src/lib/certmap/sss_certmap.c +++ b/src/lib/certmap/sss_certmap.c @@ -914,3 +914,145 @@ void sss_certmap_free_filter_and_domains(char *filter, char **domains) talloc_free(filter); talloc_free(domains); } + +static const char *sss_eku_oid2name(const char *oid) +{ + size_t c; + + for (c = 0; sss_ext_key_usage[c].name != NULL; c++) { + if (strcmp(sss_ext_key_usage[c].oid, oid) == 0) { + return sss_ext_key_usage[c].name; + } + } + + return NULL; +} + +struct parsed_template san_parsed_template[] = { + { NULL, NULL, NULL }, /* SAN_OTHER_NAME handled separately */ + { "subject_rfc822_name", NULL, NULL}, + { "subject_dns_name", NULL, NULL}, + { "subject_x400_address", NULL, NULL}, + { "subject_directory_name", NULL, NULL}, + { "subject_ediparty_name", NULL, NULL}, + { "subject_uri", NULL, NULL}, + { "subject_ip_address", NULL, NULL}, + { "subject_registered_id", NULL, NULL}, + { "subject_pkinit_principal", NULL, NULL}, + { "subject_nt_principal", NULL, NULL}, + { "subject_principal", NULL, NULL}, + { NULL, NULL, NULL }, /* SAN_STRING_OTHER_NAME handled separately */ + { NULL, NULL, NULL } /* SAN_END */ +}; + +int sss_cert_dump_content(TALLOC_CTX *mem_ctx, struct sss_cert_content *c, + char **content_str) +{ + char *out = NULL; + size_t o; + struct san_list *s; + struct sss_certmap_ctx *ctx = NULL; + char *expanded = NULL; + int ret; + char *b64 = NULL; + const char *eku_str = NULL; + + ret = sss_certmap_init(mem_ctx, NULL, NULL, &ctx); + if (ret != EOK) { + return ret; + } + + out = talloc_strdup(mem_ctx, "sss cert content (format might change):\n"); + if (out == NULL) return ENOMEM; + + out = talloc_asprintf_append(out, "Issuer: %s\n", c->issuer_str != NULL + ? c->issuer_str + : "- not available -"); + if (out == NULL) return ENOMEM; + out = talloc_asprintf_append(out, "Subject: %s\n", c->subject_str != NULL + ? c->subject_str + : "- not available -"); + if (out == NULL) return ENOMEM; + + out = talloc_asprintf_append(out, "Key Usage: %u(0x%04x)", c->key_usage, + c->key_usage); + if (out == NULL) return ENOMEM; + + if (c->key_usage != 0) { + out = talloc_asprintf_append(out, " ("); + if (out == NULL) return ENOMEM; + for (o = 0; sss_key_usage[o].name != NULL; o++) { + if ((c->key_usage & sss_key_usage[o].flag) != 0) { + out = talloc_asprintf_append(out, "%s%s", + o == 0 ? "" : ",", + sss_key_usage[o].name); + if (out == NULL) return ENOMEM; + } + } + out = talloc_asprintf_append(out, ")"); + if (out == NULL) return ENOMEM; + } + out = talloc_asprintf_append(out, "\n"); + if (out == NULL) return ENOMEM; + + for (o = 0; c->extended_key_usage_oids[o] != NULL; o++) { + eku_str = sss_eku_oid2name(c->extended_key_usage_oids[o]); + out = talloc_asprintf_append(out, "Extended Key Usage #%zu: %s%s%s%s\n", + o, c->extended_key_usage_oids[o], + eku_str == NULL ? "" : " (", + eku_str == NULL ? "" : eku_str, + eku_str == NULL ? "" : ")"); + if (out == NULL) return ENOMEM; + } + + DLIST_FOR_EACH(s, c->san_list) { + out = talloc_asprintf_append(out, "SAN type: %s\n", + s->san_opt < SAN_END + ? sss_san_names[s->san_opt].name + : "- unsupported -"); + if (out == NULL) return ENOMEM; + + if (san_parsed_template[s->san_opt].name != NULL) { + ret = expand_san(ctx, &san_parsed_template[s->san_opt], c->san_list, + &expanded); + if (ret != EOK) { + return ret; + } + out = talloc_asprintf_append(out, " %s=%s\n\n", + san_parsed_template[s->san_opt].name, + expanded); + talloc_free(expanded); + if (out == NULL) return ENOMEM; + } else if (s->san_opt == SAN_STRING_OTHER_NAME) { + b64 = sss_base64_encode(mem_ctx, s->bin_val, s->bin_val_len); + out = talloc_asprintf_append(out, " %s=%s\n\n", s->other_name_oid, + b64 != NULL ? b64 + : "- cannot encode -"); + talloc_free(b64); + } + } + + *content_str = out; + + return EOK; +} + +int sss_certmap_display_cert_content(TALLOC_CTX *mem_cxt, + const uint8_t *der_cert, size_t der_size, + char **desc) +{ + int ret; + struct sss_cert_content *content; + + ret = sss_cert_get_content(mem_cxt, der_cert, der_size, &content); + if (ret != EOK) { + return ret; + } + + ret = sss_cert_dump_content(mem_cxt, content, desc); + if (ret != EOK) { + return ret; + } + + return 0; +} diff --git a/src/lib/certmap/sss_certmap.exports b/src/lib/certmap/sss_certmap.exports index 8b5d53666..a9e48d6d0 100644 --- a/src/lib/certmap/sss_certmap.exports +++ b/src/lib/certmap/sss_certmap.exports @@ -11,3 +11,8 @@ SSS_CERTMAP_0.0 { local: *; }; + +SSS_CERTMAP_0.1 { + global: + sss_certmap_display_cert_content; +} SSS_CERTMAP_0.0; diff --git a/src/lib/certmap/sss_certmap.h b/src/lib/certmap/sss_certmap.h index 646e0f393..7da2d1c58 100644 --- a/src/lib/certmap/sss_certmap.h +++ b/src/lib/certmap/sss_certmap.h @@ -146,6 +146,24 @@ int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx, */ void sss_certmap_free_filter_and_domains(char *filter, char **domains); +/** + * @brief Get a string with the content of the certificate used by the library + * + * @param[in] mem_ctx Talloc memory context, may be NULL + * @param[in] der_cert binary blog with the DER encoded certificate + * @param[in] der_size size of the certificate blob + * @param[out] desc Multiline string showing the certificate content + * which is used by libsss_certmap + * + * @return + * - 0: success + * - EINVAL: certificate cannot be parsed + * - ENOMEM: memory allocation failure + */ +int sss_certmap_display_cert_content(TALLOC_CTX *mem_cxt, + const uint8_t *der_cert, size_t der_size, + char **desc); + /** * @} */ diff --git a/src/lib/certmap/sss_certmap_int.h b/src/lib/certmap/sss_certmap_int.h index 479cc1606..b1155e220 100644 --- a/src/lib/certmap/sss_certmap_int.h +++ b/src/lib/certmap/sss_certmap_int.h @@ -101,9 +101,9 @@ enum comp_type { }; struct parsed_template { - char *name; - char *attr_name; - char *conversion; + const char *name; + const char *attr_name; + const char *conversion; }; struct ldap_mapping_rule_comp { @@ -166,6 +166,28 @@ struct san_list { #define SSS_KU_ENCIPHER_ONLY 0x0001 #define SSS_KU_DECIPHER_ONLY 0x8000 +struct sss_key_usage { + const char *name; + uint32_t flag; +}; + +extern const struct sss_key_usage sss_key_usage[]; + +struct sss_ext_key_usage { + const char *name; + const char *oid; +}; + +extern const struct sss_ext_key_usage sss_ext_key_usage[]; + +struct sss_san_name { + const char *name; + enum san_opt san_opt; + bool is_string; +}; + +extern const struct sss_san_name sss_san_names[]; + struct sss_cert_content { char *issuer_str; const char **issuer_rdn_list; @@ -183,6 +205,9 @@ int sss_cert_get_content(TALLOC_CTX *mem_ctx, const uint8_t *der_blob, size_t der_size, struct sss_cert_content **content); +int sss_cert_dump_content(TALLOC_CTX *mem_ctx, struct sss_cert_content *c, + char **content_str); + char *check_ad_attr_name(TALLOC_CTX *mem_ctx, const char *rdn); char *openssl_2_nss_attr_name(const char *attr); diff --git a/src/lib/certmap/sss_certmap_krb5_match.c b/src/lib/certmap/sss_certmap_krb5_match.c index 125e925d9..398d3d283 100644 --- a/src/lib/certmap/sss_certmap_krb5_match.c +++ b/src/lib/certmap/sss_certmap_krb5_match.c @@ -29,6 +29,59 @@ #include "lib/certmap/sss_certmap.h" #include "lib/certmap/sss_certmap_int.h" +const struct sss_key_usage sss_key_usage[] = { + {"digitalSignature" , SSS_KU_DIGITAL_SIGNATURE}, + {"nonRepudiation" , SSS_KU_NON_REPUDIATION}, + {"keyEncipherment" , SSS_KU_KEY_ENCIPHERMENT}, + {"dataEncipherment" , SSS_KU_DATA_ENCIPHERMENT}, + {"keyAgreement" , SSS_KU_KEY_AGREEMENT}, + {"keyCertSign" , SSS_KU_KEY_CERT_SIGN}, + {"cRLSign" , SSS_KU_CRL_SIGN}, + {"encipherOnly" , SSS_KU_ENCIPHER_ONLY}, + {"decipherOnly" , SSS_KU_DECIPHER_ONLY}, + {NULL ,0} +}; + +const struct sss_ext_key_usage sss_ext_key_usage[] = { + /* RFC 3280 section 4.2.1.13 */ + {"serverAuth", "1.3.6.1.5.5.7.3.1"}, + {"clientAuth", "1.3.6.1.5.5.7.3.2"}, + {"codeSigning", "1.3.6.1.5.5.7.3.3"}, + {"emailProtection", "1.3.6.1.5.5.7.3.4"}, + {"timeStamping", "1.3.6.1.5.5.7.3.8"}, + {"OCSPSigning", "1.3.6.1.5.5.7.3.9"}, + + /* RFC 4556 section 3.2.2 */ + {"KPClientAuth", "1.3.6.1.5.2.3.4"}, + {"pkinit", "1.3.6.1.5.2.3.4"}, + + /* https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography*/ + {"msScLogin", "1.3.6.1.4.1.311.20.2.2"}, + + {NULL ,0} +}; + +const struct sss_san_name sss_san_names[] = { + /* https://www.ietf.org/rfc/rfc3280.txt section 4.2.1.7 */ + {"otherName", SAN_OTHER_NAME, false}, + {"rfc822Name", SAN_RFC822_NAME, true}, + {"dNSName", SAN_DNS_NAME, true}, + {"x400Address", SAN_X400_ADDRESS, false}, + {"directoryName", SAN_DIRECTORY_NAME, true}, + {"ediPartyName", SAN_EDIPART_NAME, false}, + {"uniformResourceIdentifier", SAN_URI, true}, + {"iPAddress", SAN_IP_ADDRESS, true}, + {"registeredID", SAN_REGISTERED_ID, true}, + /* https://www.ietf.org/rfc/rfc4556.txt section 3.2.2 */ + {"pkinitSAN", SAN_PKINIT, true}, + /* https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography */ + {"ntPrincipalName", SAN_NT, true}, + /* both previous principal types */ + {"Principal", SAN_PRINCIPAL, true}, + {"stringOtherName", SAN_STRING_OTHER_NAME, true}, + {NULL, SAN_END, false} +}; + static bool is_dotted_decimal(const char *s, size_t len) { size_t c = 0; @@ -145,28 +198,6 @@ static int parse_krb5_get_eku_value(TALLOC_CTX *mem_ctx, size_t e = 0; int eku_list_size; - struct ext_key_usage { - const char *name; - const char *oid; - } ext_key_usage[] = { - /* RFC 3280 section 4.2.1.13 */ - {"serverAuth", "1.3.6.1.5.5.7.3.1"}, - {"clientAuth", "1.3.6.1.5.5.7.3.2"}, - {"codeSigning", "1.3.6.1.5.5.7.3.3"}, - {"emailProtection", "1.3.6.1.5.5.7.3.4"}, - {"timeStamping", "1.3.6.1.5.5.7.3.8"}, - {"OCSPSigning", "1.3.6.1.5.5.7.3.9"}, - - /* RFC 4556 section 3.2.2 */ - {"KPClientAuth", "1.3.6.1.5.2.3.4"}, - {"pkinit", "1.3.6.1.5.2.3.4"}, - - /* https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography*/ - {"msScLogin", "1.3.6.1.4.1.311.20.2.2"}, - - {NULL ,0} - }; - ret = get_comp_value(mem_ctx, ctx, cur, &comp); if (ret != 0) { CM_DEBUG(ctx, "Failed to parse regexp."); @@ -188,11 +219,11 @@ static int parse_krb5_get_eku_value(TALLOC_CTX *mem_ctx, } for (c = 0; eku_list[c] != NULL; c++) { - for (k = 0; ext_key_usage[k].name != NULL; k++) { -CM_DEBUG(ctx, "[%s][%s].", eku_list[c], ext_key_usage[k].name); - if (strcasecmp(eku_list[c], ext_key_usage[k].name) == 0) { + 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, - ext_key_usage[k].oid); + sss_ext_key_usage[k].oid); if (comp->eku_oid_list[e] == NULL) { ret = ENOMEM; goto done; @@ -202,7 +233,7 @@ CM_DEBUG(ctx, "[%s][%s].", eku_list[c], ext_key_usage[k].name); } } - if (ext_key_usage[k].name == NULL) { + if (sss_ext_key_usage[k].name == NULL) { /* check for an dotted-decimal OID */ if (*(eku_list[c]) != '.') { o = eku_list[c]; @@ -252,23 +283,6 @@ static int parse_krb5_get_ku_value(TALLOC_CTX *mem_ctx, size_t c; size_t k; - struct key_usage { - const char *name; - uint32_t flag; - } key_usage[] = { - {"digitalSignature" , SSS_KU_DIGITAL_SIGNATURE}, - {"nonRepudiation" , SSS_KU_NON_REPUDIATION}, - {"keyEncipherment" , SSS_KU_KEY_ENCIPHERMENT}, - {"dataEncipherment" , SSS_KU_DATA_ENCIPHERMENT}, - {"keyAgreement" , SSS_KU_KEY_AGREEMENT}, - {"keyCertSign" , SSS_KU_KEY_CERT_SIGN}, - {"cRLSign" , SSS_KU_CRL_SIGN}, - {"encipherOnly" , SSS_KU_ENCIPHER_ONLY}, - {"decipherOnly" , SSS_KU_DECIPHER_ONLY}, - {NULL ,0} - }; - - ret = get_comp_value(mem_ctx, ctx, cur, &comp); if (ret != 0) { CM_DEBUG(ctx, "Failed to get value."); @@ -283,14 +297,14 @@ static int parse_krb5_get_ku_value(TALLOC_CTX *mem_ctx, } for (c = 0; ku_list[c] != NULL; c++) { - for (k = 0; key_usage[k].name != NULL; k++) { - if (strcasecmp(ku_list[c], key_usage[k].name) == 0) { - comp->ku |= key_usage[k].flag; + for (k = 0; sss_key_usage[k].name != NULL; k++) { + if (strcasecmp(ku_list[c], sss_key_usage[k].name) == 0) { + comp->ku |= sss_key_usage[k].flag; break; } } - if (key_usage[k].name == NULL) { + if (sss_key_usage[k].name == NULL) { /* FIXME: add check for numerical ku */ CM_DEBUG(ctx, "No matching key usage found."); ret = EINVAL; @@ -342,31 +356,6 @@ done: return ret; } -struct san_name { - const char *name; - enum san_opt san_opt; - bool is_string; -} san_names[] = { - /* https://www.ietf.org/rfc/rfc3280.txt section 4.2.1.7 */ - {"otherName", SAN_OTHER_NAME, false}, - {"rfc822Name", SAN_RFC822_NAME,true}, - {"dNSName", SAN_DNS_NAME, true}, - {"x400Address", SAN_X400_ADDRESS, false}, - {"directoryName", SAN_DIRECTORY_NAME, true}, - {"ediPartyName", SAN_EDIPART_NAME, false}, - {"uniformResourceIdentifier", SAN_URI, true}, - {"iPAddress", SAN_IP_ADDRESS, true}, - {"registeredID", SAN_REGISTERED_ID, true}, - /* https://www.ietf.org/rfc/rfc4556.txt section 3.2.2 */ - {"pkinitSAN", SAN_PKINIT, true}, - /* https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography */ - {"ntPrincipalName", SAN_NT, true}, - /* both previous principal types */ - {"Principal", SAN_PRINCIPAL, true}, - {"stringOtherName", SAN_STRING_OTHER_NAME, true}, - {NULL, SAN_END, false} -}; - static int parse_krb5_get_san_option(TALLOC_CTX *mem_ctx, struct sss_certmap_ctx *ctx, const char **cur, @@ -388,12 +377,12 @@ static int parse_krb5_get_san_option(TALLOC_CTX *mem_ctx, if (len == 0) { c= SAN_PRINCIPAL; } else { - for (c = 0; san_names[c].name != NULL; c++) { - if (strncasecmp(*cur, san_names[c].name, len) == 0) { + for (c = 0; sss_san_names[c].name != NULL; c++) { + if (strncasecmp(*cur, sss_san_names[c].name, len) == 0) { break; } } - if (san_names[c].name == NULL) { + if (sss_san_names[c].name == NULL) { if (is_dotted_decimal(*cur, len)) { c = SAN_STRING_OTHER_NAME; *str_other_name_oid = talloc_strndup(mem_ctx, *cur, len); @@ -408,7 +397,7 @@ static int parse_krb5_get_san_option(TALLOC_CTX *mem_ctx, } } - *option = san_names[c].san_opt; + *option = sss_san_names[c].san_opt; *cur = end + 1; return 0; @@ -432,7 +421,7 @@ static int parse_krb5_get_san_value(TALLOC_CTX *mem_ctx, } } - if (san_names[san_opt].is_string) { + if (sss_san_names[san_opt].is_string) { ret = parse_krb5_get_component_value(mem_ctx, ctx, cur, &comp); if (ret != 0) { goto done; -- 2.39.1 From 4f80a8eca9fa3d7f9207f31fd9463f7db629cc4d Mon Sep 17 00:00:00 2001 From: Sumit Bose <sbose@redhat.com> Date: Mon, 9 Dec 2019 11:31:14 +0100 Subject: [PATCH 8/8] certmap: sanitize LDAP search filter The sss_certmap_get_search_filter() will now sanitize the values read from the certificates before adding them to a search filter. To be able to get the plain values as well sss_certmap_expand_mapping_rule() is added. Resolves: https://github.com/SSSD/sssd/issues/5135 Reviewed-by: Alexey Tikhonov <atikhono@redhat.com> (cherry picked from commit a2b9a84460429181f2a4fa7e2bb5ab49fd561274) Reviewed-by: Alexey Tikhonov <atikhono@redhat.com> Reviewed-by: Justin Stephenson <jstephen@redhat.com> --- Makefile.am | 2 +- src/lib/certmap/sss_certmap.c | 42 ++++++++++-- src/lib/certmap/sss_certmap.exports | 5 ++ src/lib/certmap/sss_certmap.h | 35 ++++++++-- src/responder/pam/pamsrv_p11.c | 5 +- src/tests/cmocka/test_certmap.c | 98 +++++++++++++++++++++++++++- src/util/util.c | 94 --------------------------- src/util/util_ext.c | 99 +++++++++++++++++++++++++++++ 8 files changed, 272 insertions(+), 108 deletions(-) diff --git a/Makefile.am b/Makefile.am index 70aee984c..b82129eae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1836,7 +1836,7 @@ libsss_certmap_la_LIBADD = \ $(NULL) libsss_certmap_la_LDFLAGS = \ -Wl,--version-script,$(srcdir)/src/lib/certmap/sss_certmap.exports \ - -version-info 1:0:1 + -version-info 2:0:2 if HAVE_NSS libsss_certmap_la_SOURCES += \ diff --git a/src/lib/certmap/sss_certmap.c b/src/lib/certmap/sss_certmap.c index c60ac24c6..d7bc99286 100644 --- a/src/lib/certmap/sss_certmap.c +++ b/src/lib/certmap/sss_certmap.c @@ -441,10 +441,12 @@ static int expand_san(struct sss_certmap_ctx *ctx, static int expand_template(struct sss_certmap_ctx *ctx, struct parsed_template *parsed_template, struct sss_cert_content *cert_content, + bool sanitize, char **expanded) { int ret; char *exp = NULL; + char *exp_sanitized = NULL; if (strcmp("issuer_dn", parsed_template->name) == 0) { ret = rdn_list_2_dn_str(ctx, parsed_template->conversion, @@ -455,6 +457,8 @@ static int expand_template(struct sss_certmap_ctx *ctx, } else if (strncmp("subject_", parsed_template->name, 8) == 0) { ret = expand_san(ctx, parsed_template, cert_content->san_list, &exp); } else if (strcmp("cert", parsed_template->name) == 0) { + /* cert blob is already sanitized */ + sanitize = false; ret = expand_cert(ctx, parsed_template, cert_content, &exp); } else { CM_DEBUG(ctx, "Unsupported template name."); @@ -471,6 +475,16 @@ static int expand_template(struct sss_certmap_ctx *ctx, goto done; } + if (sanitize) { + ret = sss_filter_sanitize(ctx, exp, &exp_sanitized); + if (ret != EOK) { + CM_DEBUG(ctx, "Failed to sanitize expanded template."); + goto done; + } + talloc_free(exp); + exp = exp_sanitized; + } + ret = 0; done: @@ -485,7 +499,7 @@ done: static int get_filter(struct sss_certmap_ctx *ctx, struct ldap_mapping_rule *parsed_mapping_rule, - struct sss_cert_content *cert_content, + struct sss_cert_content *cert_content, bool sanitize, char **filter) { struct ldap_mapping_rule_comp *comp; @@ -503,7 +517,7 @@ static int get_filter(struct sss_certmap_ctx *ctx, result = talloc_strdup_append(result, comp->val); } else if (comp->type == comp_template) { ret = expand_template(ctx, comp->parsed_template, cert_content, - &expanded); + sanitize, &expanded); if (ret != 0) { CM_DEBUG(ctx, "Failed to expanded template."); goto done; @@ -791,8 +805,9 @@ done: return ret; } -int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx, +static int expand_mapping_rule_ex(struct sss_certmap_ctx *ctx, const uint8_t *der_cert, size_t der_size, + bool sanitize, char **_filter, char ***_domains) { int ret; @@ -819,7 +834,8 @@ int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx, return EINVAL; } - ret = get_filter(ctx, ctx->default_mapping_rule, cert_content, &filter); + ret = get_filter(ctx, ctx->default_mapping_rule, cert_content, sanitize, + &filter); goto done; } @@ -829,7 +845,7 @@ int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx, if (ret == 0) { /* match */ ret = get_filter(ctx, r->parsed_mapping_rule, cert_content, - &filter); + sanitize, &filter); if (ret != 0) { CM_DEBUG(ctx, "Failed to get filter"); goto done; @@ -873,6 +889,22 @@ done: return ret; } +int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx, + const uint8_t *der_cert, size_t der_size, + char **_filter, char ***_domains) +{ + return expand_mapping_rule_ex(ctx, der_cert, der_size, true, + _filter, _domains); +} + +int sss_certmap_expand_mapping_rule(struct sss_certmap_ctx *ctx, + const uint8_t *der_cert, size_t der_size, + char **_expanded, char ***_domains) +{ + return expand_mapping_rule_ex(ctx, der_cert, der_size, false, + _expanded, _domains); +} + int sss_certmap_init(TALLOC_CTX *mem_ctx, sss_certmap_ext_debug *debug, void *debug_priv, struct sss_certmap_ctx **ctx) diff --git a/src/lib/certmap/sss_certmap.exports b/src/lib/certmap/sss_certmap.exports index a9e48d6d0..7d7667738 100644 --- a/src/lib/certmap/sss_certmap.exports +++ b/src/lib/certmap/sss_certmap.exports @@ -16,3 +16,8 @@ SSS_CERTMAP_0.1 { global: sss_certmap_display_cert_content; } SSS_CERTMAP_0.0; + +SSS_CERTMAP_0.2 { + global: + sss_certmap_expand_mapping_rule; +} SSS_CERTMAP_0.1; diff --git a/src/lib/certmap/sss_certmap.h b/src/lib/certmap/sss_certmap.h index 7da2d1c58..058d4f9e4 100644 --- a/src/lib/certmap/sss_certmap.h +++ b/src/lib/certmap/sss_certmap.h @@ -103,7 +103,7 @@ int sss_certmap_add_rule(struct sss_certmap_ctx *ctx, * * @param[in] ctx certmap context previously initialized with * @ref sss_certmap_init - * @param[in] der_cert binary blog with the DER encoded certificate + * @param[in] der_cert binary blob with the DER encoded certificate * @param[in] der_size size of the certificate blob * * @return @@ -119,10 +119,11 @@ int sss_certmap_match_cert(struct sss_certmap_ctx *ctx, * * @param[in] ctx certmap context previously initialized with * @ref sss_certmap_init - * @param[in] der_cert binary blog with the DER encoded certificate + * @param[in] der_cert binary blob with the DER encoded certificate * @param[in] der_size size of the certificate blob - * @param[out] filter LDAP filter string, caller should free the data by - * calling sss_certmap_free_filter_and_domains + * @param[out] filter LDAP filter string, expanded templates are sanitized, + * caller should free the data by calling + * sss_certmap_free_filter_and_domains * @param[out] domains NULL-terminated array of strings with the domains the * rule applies, caller should free the data by calling * sss_certmap_free_filter_and_domains @@ -136,8 +137,32 @@ int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx, const uint8_t *der_cert, size_t der_size, char **filter, char ***domains); +/** + * @brief Expand the mapping rule by replacing the templates + * + * @param[in] ctx certmap context previously initialized with + * @ref sss_certmap_init + * @param[in] der_cert binary blob with the DER encoded certificate + * @param[in] der_size size of the certificate blob + * @param[out] expanded expanded mapping rule, templates are filled in + * verbatim in contrast to sss_certmap_get_search_filter, + * caller should free the data by + * calling sss_certmap_free_filter_and_domains + * @param[out] domains NULL-terminated array of strings with the domains the + * rule applies, caller should free the data by calling + * sss_certmap_free_filter_and_domains + * + * @return + * - 0: certificate matches a rule + * - ENOENT: certificate does not match + * - EINVAL: internal error + */ +int sss_certmap_expand_mapping_rule(struct sss_certmap_ctx *ctx, + const uint8_t *der_cert, size_t der_size, + char **_expanded, char ***_domains); /** * @brief Free data returned by @ref sss_certmap_get_search_filter + * and @ref sss_certmap_expand_mapping_rule * * @param[in] filter LDAP filter strings returned by * sss_certmap_get_search_filter @@ -150,7 +175,7 @@ void sss_certmap_free_filter_and_domains(char *filter, char **domains); * @brief Get a string with the content of the certificate used by the library * * @param[in] mem_ctx Talloc memory context, may be NULL - * @param[in] der_cert binary blog with the DER encoded certificate + * @param[in] der_cert binary blob with the DER encoded certificate * @param[in] der_size size of the certificate blob * @param[out] desc Multiline string showing the certificate content * which is used by libsss_certmap diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c index b6f4ba4ad..2a7cab28e 100644 --- a/src/responder/pam/pamsrv_p11.c +++ b/src/responder/pam/pamsrv_p11.c @@ -879,9 +879,10 @@ static char *get_cert_prompt(TALLOC_CTX *mem_ctx, goto done; } - ret = sss_certmap_get_search_filter(ctx, der, der_size, &filter, &domains); + ret = sss_certmap_expand_mapping_rule(ctx, der, der_size, + &filter, &domains); if (ret != 0) { - DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_get_search_filter failed.\n"); + DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_expand_mapping_rule failed.\n"); goto done; } diff --git a/src/tests/cmocka/test_certmap.c b/src/tests/cmocka/test_certmap.c index 6b5a31c3d..13e39dbc8 100644 --- a/src/tests/cmocka/test_certmap.c +++ b/src/tests/cmocka/test_certmap.c @@ -1336,6 +1336,15 @@ static void test_sss_certmap_get_search_filter(void **state) &filter, &domains); assert_int_equal(ret, 0); assert_non_null(filter); + assert_string_equal(filter, "rule100=<I>CN=Certificate\\20Authority,O=IPA.DEVEL" + "<S>CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); + assert_null(domains); + + ret = sss_certmap_expand_mapping_rule(ctx, discard_const(test_cert_der), + sizeof(test_cert_der), + &filter, &domains); + assert_int_equal(ret, 0); + assert_non_null(filter); assert_string_equal(filter, "rule100=<I>CN=Certificate Authority,O=IPA.DEVEL" "<S>CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); assert_null(domains); @@ -1350,6 +1359,17 @@ static void test_sss_certmap_get_search_filter(void **state) &filter, &domains); assert_int_equal(ret, 0); assert_non_null(filter); + assert_string_equal(filter, "rule99=<I>CN=Certificate\\20Authority,O=IPA.DEVEL" + "<S>CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); + assert_non_null(domains); + assert_string_equal(domains[0], "test.dom"); + assert_null(domains[1]); + + ret = sss_certmap_expand_mapping_rule(ctx, discard_const(test_cert_der), + sizeof(test_cert_der), + &filter, &domains); + assert_int_equal(ret, 0); + assert_non_null(filter); assert_string_equal(filter, "rule99=<I>CN=Certificate Authority,O=IPA.DEVEL" "<S>CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); assert_non_null(domains); @@ -1371,6 +1391,16 @@ static void test_sss_certmap_get_search_filter(void **state) assert_string_equal(domains[0], "test.dom"); assert_null(domains[1]); + ret = sss_certmap_expand_mapping_rule(ctx, discard_const(test_cert_der), + sizeof(test_cert_der), + &filter, &domains); + assert_int_equal(ret, 0); + assert_non_null(filter); + assert_string_equal(filter, "rule98=userCertificate;binary=" TEST_CERT_BIN); + assert_non_null(domains); + assert_string_equal(domains[0], "test.dom"); + assert_null(domains[1]); + ret = sss_certmap_add_rule(ctx, 97, "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL", "LDAP:rule97=<I>{issuer_dn!nss_x500}<S>{subject_dn}", @@ -1381,6 +1411,17 @@ static void test_sss_certmap_get_search_filter(void **state) &filter, &domains); assert_int_equal(ret, 0); assert_non_null(filter); + assert_string_equal(filter, "rule97=<I>O=IPA.DEVEL,CN=Certificate\\20Authority" + "<S>CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); + assert_non_null(domains); + assert_string_equal(domains[0], "test.dom"); + assert_null(domains[1]); + + ret = sss_certmap_expand_mapping_rule(ctx, discard_const(test_cert_der), + sizeof(test_cert_der), + &filter, &domains); + assert_int_equal(ret, 0); + assert_non_null(filter); assert_string_equal(filter, "rule97=<I>O=IPA.DEVEL,CN=Certificate Authority" "<S>CN=ipa-devel.ipa.devel,O=IPA.DEVEL"); assert_non_null(domains); @@ -1397,6 +1438,17 @@ static void test_sss_certmap_get_search_filter(void **state) &filter, &domains); assert_int_equal(ret, 0); assert_non_null(filter); + assert_string_equal(filter, "rule96=<I>O=IPA.DEVEL,CN=Certificate\\20Authority" + "<S>O=IPA.DEVEL,CN=ipa-devel.ipa.devel"); + assert_non_null(domains); + assert_string_equal(domains[0], "test.dom"); + assert_null(domains[1]); + + ret = sss_certmap_expand_mapping_rule(ctx, discard_const(test_cert_der), + sizeof(test_cert_der), + &filter, &domains); + assert_int_equal(ret, 0); + assert_non_null(filter); assert_string_equal(filter, "rule96=<I>O=IPA.DEVEL,CN=Certificate Authority" "<S>O=IPA.DEVEL,CN=ipa-devel.ipa.devel"); assert_non_null(domains); @@ -1415,6 +1467,14 @@ static void test_sss_certmap_get_search_filter(void **state) assert_string_equal(filter, "(userCertificate;binary=" TEST_CERT_BIN ")"); assert_null(domains); + ret = sss_certmap_expand_mapping_rule(ctx, discard_const(test_cert_der), + sizeof(test_cert_der), + &filter, &domains); + assert_int_equal(ret, 0); + assert_non_null(filter); + assert_string_equal(filter, "(userCertificate;binary=" TEST_CERT_BIN ")"); + assert_null(domains); + ret = sss_certmap_add_rule(ctx, 94, "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL", "LDAP:rule94=<I>{issuer_dn!ad_x500}<S>{subject_dn!ad_x500}", @@ -1425,12 +1485,22 @@ static void test_sss_certmap_get_search_filter(void **state) &filter, &domains); assert_int_equal(ret, 0); assert_non_null(filter); - assert_string_equal(filter, "rule94=<I>O=IPA.DEVEL,CN=Certificate Authority" + assert_string_equal(filter, "rule94=<I>O=IPA.DEVEL,CN=Certificate\\20Authority" "<S>O=IPA.DEVEL,CN=ipa-devel.ipa.devel"); assert_non_null(domains); assert_string_equal(domains[0], "test.dom"); assert_null(domains[1]); + ret = sss_certmap_expand_mapping_rule(ctx, discard_const(test_cert_der), + sizeof(test_cert_der), + &filter, &domains); + assert_int_equal(ret, 0); + assert_non_null(filter); + assert_string_equal(filter, "rule94=<I>O=IPA.DEVEL,CN=Certificate Authority" + "<S>O=IPA.DEVEL,CN=ipa-devel.ipa.devel"); + assert_non_null(domains); + assert_string_equal(domains[0], "test.dom"); + assert_null(domains[1]); ret = sss_certmap_add_rule(ctx, 89, NULL, "(rule89={subject_nt_principal})", @@ -1444,6 +1514,14 @@ static void test_sss_certmap_get_search_filter(void **state) assert_string_equal(filter, "(rule89=tu1@ad.devel)"); assert_null(domains); + ret = sss_certmap_expand_mapping_rule(ctx, discard_const(test_cert2_der), + sizeof(test_cert2_der), + &filter, &domains); + assert_int_equal(ret, 0); + assert_non_null(filter); + assert_string_equal(filter, "(rule89=tu1@ad.devel)"); + assert_null(domains); + ret = sss_certmap_add_rule(ctx, 88, NULL, "(rule88={subject_nt_principal.short_name})", NULL); @@ -1465,6 +1543,15 @@ static void test_sss_certmap_get_search_filter(void **state) &filter, &domains); assert_int_equal(ret, 0); assert_non_null(filter); + assert_string_equal(filter, "rule87=<I>DC=devel,DC=ad,CN=ad-AD-SERVER-CA" + "<S>DC=devel,DC=ad,CN=Users,CN=t\\20u,E=test.user@email.domain"); + assert_null(domains); + + ret = sss_certmap_expand_mapping_rule(ctx, discard_const(test_cert2_der), + sizeof(test_cert2_der), + &filter, &domains); + assert_int_equal(ret, 0); + assert_non_null(filter); assert_string_equal(filter, "rule87=<I>DC=devel,DC=ad,CN=ad-AD-SERVER-CA" "<S>DC=devel,DC=ad,CN=Users,CN=t u,E=test.user@email.domain"); assert_null(domains); @@ -1478,6 +1565,15 @@ static void test_sss_certmap_get_search_filter(void **state) &filter, &domains); assert_int_equal(ret, 0); assert_non_null(filter); + assert_string_equal(filter, "rule86=<I>DC=devel,DC=ad,CN=ad-AD-SERVER-CA" + "<S>DC=devel,DC=ad,CN=Users,CN=t\\20u,E=test.user@email.domain"); + assert_null(domains); + + ret = sss_certmap_expand_mapping_rule(ctx, discard_const(test_cert2_der), + sizeof(test_cert2_der), + &filter, &domains); + assert_int_equal(ret, 0); + assert_non_null(filter); assert_string_equal(filter, "rule86=<I>DC=devel,DC=ad,CN=ad-AD-SERVER-CA" "<S>DC=devel,DC=ad,CN=Users,CN=t u,E=test.user@email.domain"); assert_null(domains); diff --git a/src/util/util.c b/src/util/util.c index aaf3609c3..9327f971c 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -436,100 +436,6 @@ errno_t sss_hash_create(TALLOC_CTX *mem_ctx, unsigned long count, return sss_hash_create_ex(mem_ctx, count, tbl, 0, 0, 0, 0, NULL, NULL); } -errno_t sss_filter_sanitize_ex(TALLOC_CTX *mem_ctx, - const char *input, - char **sanitized, - const char *ignore) -{ - char *output; - size_t i = 0; - size_t j = 0; - char *allowed; - - /* Assume the worst-case. We'll resize it later, once */ - output = talloc_array(mem_ctx, char, strlen(input) * 3 + 1); - if (!output) { - return ENOMEM; - } - - while (input[i]) { - /* Even though this character might have a special meaning, if it's - * expliticly allowed, just copy it and move on - */ - if (ignore == NULL) { - allowed = NULL; - } else { - allowed = strchr(ignore, input[i]); - } - if (allowed) { - output[j++] = input[i++]; - continue; - } - - switch(input[i]) { - case '\t': - output[j++] = '\\'; - output[j++] = '0'; - output[j++] = '9'; - break; - case ' ': - output[j++] = '\\'; - output[j++] = '2'; - output[j++] = '0'; - break; - case '*': - output[j++] = '\\'; - output[j++] = '2'; - output[j++] = 'a'; - break; - case '(': - output[j++] = '\\'; - output[j++] = '2'; - output[j++] = '8'; - break; - case ')': - output[j++] = '\\'; - output[j++] = '2'; - output[j++] = '9'; - break; - case '\\': - output[j++] = '\\'; - output[j++] = '5'; - output[j++] = 'c'; - break; - case '\r': - output[j++] = '\\'; - output[j++] = '0'; - output[j++] = 'd'; - break; - case '\n': - output[j++] = '\\'; - output[j++] = '0'; - output[j++] = 'a'; - break; - default: - output[j++] = input[i]; - } - - i++; - } - output[j] = '\0'; - *sanitized = talloc_realloc(mem_ctx, output, char, j+1); - if (!*sanitized) { - talloc_free(output); - return ENOMEM; - } - - return EOK; -} - -errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx, - const char *input, - char **sanitized) -{ - return sss_filter_sanitize_ex(mem_ctx, input, sanitized, NULL); -} - /* There is similar function ldap_dn_normalize in openldap. * To avoid dependecies across project we have this own func. * Also ldb can do this but doesn't handle all the cases diff --git a/src/util/util_ext.c b/src/util/util_ext.c index 04dc02a8a..a89b60f76 100644 --- a/src/util/util_ext.c +++ b/src/util/util_ext.c @@ -29,6 +29,11 @@ #define EOK 0 +#ifndef HAVE_ERRNO_T +#define HAVE_ERRNO_T +typedef int errno_t; +#endif + int split_on_separator(TALLOC_CTX *mem_ctx, const char *str, const char sep, bool trim, bool skip_empty, char ***_list, int *size) @@ -141,3 +146,97 @@ bool string_in_list(const char *string, char **list, bool case_sensitive) return false; } + +errno_t sss_filter_sanitize_ex(TALLOC_CTX *mem_ctx, + const char *input, + char **sanitized, + const char *ignore) +{ + char *output; + size_t i = 0; + size_t j = 0; + char *allowed; + + /* Assume the worst-case. We'll resize it later, once */ + output = talloc_array(mem_ctx, char, strlen(input) * 3 + 1); + if (!output) { + return ENOMEM; + } + + while (input[i]) { + /* Even though this character might have a special meaning, if it's + * explicitly allowed, just copy it and move on + */ + if (ignore == NULL) { + allowed = NULL; + } else { + allowed = strchr(ignore, input[i]); + } + if (allowed) { + output[j++] = input[i++]; + continue; + } + + switch(input[i]) { + case '\t': + output[j++] = '\\'; + output[j++] = '0'; + output[j++] = '9'; + break; + case ' ': + output[j++] = '\\'; + output[j++] = '2'; + output[j++] = '0'; + break; + case '*': + output[j++] = '\\'; + output[j++] = '2'; + output[j++] = 'a'; + break; + case '(': + output[j++] = '\\'; + output[j++] = '2'; + output[j++] = '8'; + break; + case ')': + output[j++] = '\\'; + output[j++] = '2'; + output[j++] = '9'; + break; + case '\\': + output[j++] = '\\'; + output[j++] = '5'; + output[j++] = 'c'; + break; + case '\r': + output[j++] = '\\'; + output[j++] = '0'; + output[j++] = 'd'; + break; + case '\n': + output[j++] = '\\'; + output[j++] = '0'; + output[j++] = 'a'; + break; + default: + output[j++] = input[i]; + } + + i++; + } + output[j] = '\0'; + *sanitized = talloc_realloc(mem_ctx, output, char, j+1); + if (!*sanitized) { + talloc_free(output); + return ENOMEM; + } + + return EOK; +} + +errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx, + const char *input, + char **sanitized) +{ + return sss_filter_sanitize_ex(mem_ctx, input, sanitized, NULL); +} -- 2.39.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor