URL: https://github.com/SSSD/sssd/pull/871 Author: sumit-bose Title: #871: pam: set PAM_USER properly with allow_missing_name Action: synchronized
To pull the PR as Git branch: git remote add ghsssd https://github.com/SSSD/sssd git fetch ghsssd pull/871/head:pr871 git checkout pr871
From 53047f6f9f931f5d11ee65fa934622a1ab306625 Mon Sep 17 00:00:00 2001 From: Sumit Bose <sb...@redhat.com> Date: Thu, 15 Aug 2019 15:01:28 +0200 Subject: [PATCH 1/2] pam: set PAM_USER properly with allow_missing_name Currently if the allow_missing_name pam_sss option is used PAM_USER is set to the fully-qualified name only for the files provider it is set to the short name. This might cause issue with other components expecting that the value of PAM_USER corresponds to the name returned by the nss calls getpwnam() and getpwuid(). With this patch PAM_USER is set to the same user name as returned by the NSS responder. For the communication between pam_sss and SSSD's PAM responder the fully-qualified name is kept. Related to https://pagure.io/SSSD/sssd/issue/4069 --- src/responder/pam/pamsrv_p11.c | 35 ++++++++-- src/sss_client/pam_sss.c | 42 +++++++---- src/tests/cmocka/test_pam_srv.c | 39 ++++++++--- src/tests/intg/Makefile.am | 9 ++- src/tests/intg/test_pam_responder.py | 101 ++++++++++++++++++++++++++- 5 files changed, 193 insertions(+), 33 deletions(-) diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c index 67fbd89efb..f46e6bff87 100644 --- a/src/responder/pam/pamsrv_p11.c +++ b/src/responder/pam/pamsrv_p11.c @@ -1077,6 +1077,7 @@ static char *get_cert_prompt(TALLOC_CTX *mem_ctx, static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, struct cert_auth_info *cert_info, + const char *nss_name, uint8_t **_msg, size_t *_msg_len) { uint8_t *msg = NULL; @@ -1090,12 +1091,18 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, size_t module_len; size_t key_id_len; size_t prompt_len; + size_t nss_name_len; const char *username = ""; + const char *nss_username = ""; if (sysdb_username != NULL) { username = sysdb_username; } + if (nss_name != NULL) { + nss_username = nss_name; + } + prompt = get_cert_prompt(mem_ctx, cert_info); if (prompt == NULL) { DEBUG(SSSDBG_OP_FAILURE, "get_cert_prompt failed.\n"); @@ -1111,7 +1118,10 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, module_len = strlen(module_name) + 1; key_id_len = strlen(key_id) + 1; prompt_len = strlen(prompt) + 1; - msg_len = user_len + token_len + module_len + key_id_len + prompt_len; + nss_name_len = strlen(nss_username) +1; + + msg_len = user_len + token_len + module_len + key_id_len + prompt_len + + nss_name_len; msg = talloc_zero_size(mem_ctx, msg_len); if (msg == NULL) { @@ -1126,6 +1136,8 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, memcpy(msg + user_len + token_len + module_len, key_id, key_id_len); memcpy(msg + user_len + token_len + module_len + key_id_len, prompt, prompt_len); + memcpy(msg + user_len + token_len + module_len + key_id_len + prompt_len, + nss_username, nss_name_len); talloc_free(prompt); if (_msg != NULL) { @@ -1159,6 +1171,8 @@ errno_t add_pam_cert_response(struct pam_data *pd, struct sss_domain_info *dom, char *short_name = NULL; char *domain_name = NULL; const char *cert_info_name = sysdb_username; + struct sss_domain_info *user_dom; + char *nss_name = NULL; if (type != SSS_PAM_CERT_INFO && type != SSS_PAM_CERT_INFO_WITH_HINT) { @@ -1194,15 +1208,24 @@ errno_t add_pam_cert_response(struct pam_data *pd, struct sss_domain_info *dom, "using full name.\n", sysdb_username, ret, sss_strerror(ret)); } else { - if (domain_name != NULL - && is_files_provider(find_domain_by_name(dom, domain_name, - false))) { - cert_info_name = short_name; + if (domain_name != NULL) { + user_dom = find_domain_by_name(dom, domain_name, false); + + if (user_dom != NULL) { + ret = sss_output_fqname(short_name, user_dom, + sysdb_username, false, &nss_name); + if (ret != EOK) { + nss_name = NULL; + } + } } + } } - ret = pack_cert_data(pd, cert_info_name, cert_info, &msg, &msg_len); + ret = pack_cert_data(pd, cert_info_name, cert_info, + nss_name != NULL ? nss_name : sysdb_username, + &msg, &msg_len); talloc_free(short_name); talloc_free(domain_name); if (ret != EOK) { diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c index cfd3e3731d..21a5813486 100644 --- a/src/sss_client/pam_sss.c +++ b/src/sss_client/pam_sss.c @@ -124,6 +124,7 @@ struct cert_auth_info { char *module_name; char *key_id; char *prompt_str; + char *pam_cert_user; struct cert_auth_info *prev; struct cert_auth_info *next; }; @@ -853,7 +854,8 @@ static int eval_user_info_response(pam_handle_t *pamh, size_t buflen, } static int parse_cert_info(struct pam_items *pi, uint8_t *buf, size_t len, - size_t *p, const char **cert_user) + size_t *p, const char **cert_user, + const char **pam_cert_user) { struct cert_auth_info *cai = NULL; size_t offset; @@ -935,11 +937,27 @@ static int parse_cert_info(struct pam_items *pi, uint8_t *buf, size_t len, goto done; } + offset += strlen(cai->prompt_str) + 1; + if (offset >= len) { + D(("Cert message size mismatch")); + ret = EINVAL; + goto done; + } + + cai->pam_cert_user = strdup((char *) &buf[*p + offset]); + if (cai->pam_cert_user == NULL) { + D(("strdup failed")); + ret = ENOMEM; + goto done; + } + if (pam_cert_user != NULL) { + *pam_cert_user = cai->pam_cert_user; + } D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s] " - "prompt: [%s]", + "prompt: [%s] pam cert user: [%s]", cai->cert_user, cai->token_name, cai->module_name, - cai->key_id, cai->prompt_str)); + cai->key_id, cai->prompt_str, cai->pam_cert_user)); DLIST_ADD(pi->cert_list, cai); ret = 0; @@ -964,6 +982,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, int32_t pam_status; size_t offset; const char *cert_user; + const char *pam_cert_user; if (buflen < (2*sizeof(int32_t))) { D(("response buffer is too small")); @@ -1126,15 +1145,16 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, pi->user_name_hint = false; } - ret = parse_cert_info(pi, buf, len, &p, &cert_user); + ret = parse_cert_info(pi, buf, len, &p, &cert_user, + &pam_cert_user); if (ret != 0) { D(("Failed to parse cert info")); break; } if ((pi->pam_user == NULL || *(pi->pam_user) == '\0') - && *cert_user != '\0') { - ret = pam_set_item(pamh, PAM_USER, cert_user); + && *cert_user != '\0' && *pam_cert_user != '\0') { + ret = pam_set_item(pamh, PAM_USER, pam_cert_user); if (ret != PAM_SUCCESS) { D(("Failed to set PAM_USER during " "Smartcard authentication [%s]", @@ -1142,15 +1162,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, break; } - ret = pam_get_item(pamh, PAM_USER, - (const void **)&(pi->pam_user)); - if (ret != PAM_SUCCESS) { - D(("Failed to get PAM_USER during " - "Smartcard authentication [%s]", - pam_strerror(pamh, ret))); - break; - } - + pi->pam_user = cert_user; pi->pam_user_size = strlen(pi->pam_user) + 1; } break; diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c index f55e6222ea..af4ce7166d 100644 --- a/src/tests/cmocka/test_pam_srv.c +++ b/src/tests/cmocka/test_pam_srv.c @@ -381,6 +381,8 @@ void test_pam_setup(struct sss_test_conf_param dom_params[], struct cli_protocol *prctx; errno_t ret; + test_dom_suite_setup(TESTS_PATH); + pam_test_ctx = talloc_zero(NULL, struct pam_test_ctx); assert_non_null(pam_test_ctx); @@ -570,6 +572,8 @@ static int pam_test_teardown(void **state) assert_int_equal(ret, EOK); talloc_free(pam_test_ctx); + cleanup_nss_db(); + test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME); return 0; } @@ -892,7 +896,8 @@ 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_PROMPT))); + + sizeof(TEST_PROMPT) + + sizeof("pamuser"))); assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0); assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME); @@ -914,6 +919,10 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, assert_string_equal(body + rp, TEST_PROMPT); rp += sizeof(TEST_PROMPT); + assert_int_equal(*(body + rp + sizeof("pamuser") - 1), 0); + assert_string_equal(body + rp, "pamuser"); + rp += sizeof("pamuser"); + assert_int_equal(rp, blen); return EOK; } @@ -943,7 +952,7 @@ static size_t check_string_array_len(const char **strs) static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, enum response_type type, const char *name, - const char *name2) + const char *name2, const char *nss_name) { size_t rp = 0; uint32_t val; @@ -955,6 +964,7 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, TEST_MODULE_NAME, TEST_KEY_ID, TEST_PROMPT, + NULL, NULL }; size_t check2_len = 0; @@ -963,15 +973,19 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, TEST_MODULE_NAME, TEST2_KEY_ID, TEST2_PROMPT, + NULL, NULL }; assert_int_equal(status, 0); check_strings[0] = name; + check_strings[5] = nss_name; check_len = check_string_array_len(check_strings); check2_strings[0] = name; + check2_strings[5] = nss_name; check2_len = check_string_array_len(check2_strings); + SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); assert_int_equal(val, pam_test_ctx->exp_pam_status); @@ -1042,7 +1056,8 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, static int test_pam_cert2_token2_check_ex(uint32_t status, uint8_t *body, size_t blen, enum response_type type, - const char *name) + const char *name, + const char *nss_name) { size_t rp = 0; uint32_t val; @@ -1052,11 +1067,13 @@ static int test_pam_cert2_token2_check_ex(uint32_t status, uint8_t *body, TEST_MODULE_NAME, TEST2_KEY_ID, TEST2_PROMPT, + NULL, NULL }; assert_int_equal(status, 0); check2_strings[0] = name; + check2_strings[5] = nss_name; check2_len = check_string_array_len(check2_strings); SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); @@ -1092,13 +1109,13 @@ static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen) { return test_pam_cert_check_ex(status, body, blen, SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME, - NULL); + NULL, "pamuser"); } static int test_pam_cert2_check(uint32_t status, uint8_t *body, size_t blen) { return test_pam_cert2_token2_check_ex(status, body, blen, SSS_PAM_CERT_INFO, - "pamuser@"TEST_DOM_NAME); + "pamuser@"TEST_DOM_NAME, "pamuser"); } static int test_pam_cert_check_auth_success(uint32_t status, uint8_t *body, @@ -1108,7 +1125,7 @@ static int test_pam_cert_check_auth_success(uint32_t status, uint8_t *body, pam_test_ctx->exp_pam_status = PAM_SUCCESS; return test_pam_cert_check_ex(status, body, blen, SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME, - NULL); + NULL, "pamuser"); } static int test_pam_cert_check_with_hint(uint32_t status, uint8_t *body, @@ -1116,14 +1133,15 @@ static int test_pam_cert_check_with_hint(uint32_t status, uint8_t *body, { return test_pam_cert_check_ex(status, body, blen, SSS_PAM_CERT_INFO_WITH_HINT, - "pamuser@"TEST_DOM_NAME, NULL); + "pamuser@"TEST_DOM_NAME, NULL, + "pamuser"); } static int test_pam_cert_check_with_hint_no_user(uint32_t status, uint8_t *body, size_t blen) { return test_pam_cert_check_ex(status, body, blen, - SSS_PAM_CERT_INFO_WITH_HINT, "", NULL); + SSS_PAM_CERT_INFO_WITH_HINT, "", NULL, ""); } static int test_pam_cert_check_2certs(uint32_t status, uint8_t *body, @@ -1131,7 +1149,8 @@ static int test_pam_cert_check_2certs(uint32_t status, uint8_t *body, { return test_pam_cert_check_ex(status, body, blen, SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME, - "pamuser@"TEST_DOM_NAME); + "pamuser@"TEST_DOM_NAME, + "pamuser"); } static int test_pam_offline_chauthtok_check(uint32_t status, @@ -3168,7 +3187,7 @@ int main(int argc, const char *argv[]) pam_test_setup_appsvc_app_dom, pam_test_teardown), cmocka_unit_test_setup_teardown(test_not_appsvc_app_dom, - pam_test_setup_appsvc_posix_dom, + pam_test_setup_appsvc_app_dom, pam_test_teardown), }; diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am index 2aa1566e35..820c9ed3cc 100644 --- a/src/tests/intg/Makefile.am +++ b/src/tests/intg/Makefile.am @@ -134,6 +134,13 @@ pam_sss_try_sc: echo "password required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@ echo "session required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@ +pam_sss_allow_missing_name: + $(MKDIR_P) $(PAM_SERVICE_DIR) + echo "auth required $(DESTDIR)$(pammoddir)/pam_sss.so allow_missing_name" > $(PAM_SERVICE_DIR)/$@ + echo "account required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@ + echo "password required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@ + echo "session required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@ + CLEANFILES=config.py config.pyc passwd group clean-local: @@ -148,7 +155,7 @@ PAM_CERT_DB_PATH="$(abs_builddir)/../test_CA/SSSD_test_CA.pem" SOFTHSM2_CONF="$(abs_builddir)/../test_CA/softhsm2_one.conf" endif -intgcheck-installed: config.py passwd group pam_sss_service pam_sss_alt_service pam_sss_sc_required pam_sss_try_sc +intgcheck-installed: config.py passwd group pam_sss_service pam_sss_alt_service pam_sss_sc_required pam_sss_try_sc pam_sss_allow_missing_name pipepath="$(DESTDIR)$(pipepath)"; \ if test $${#pipepath} -gt 80; then \ echo "error: Pipe directory path too long," \ diff --git a/src/tests/intg/test_pam_responder.py b/src/tests/intg/test_pam_responder.py index 8e1fcf126e..58969012f2 100644 --- a/src/tests/intg/test_pam_responder.py +++ b/src/tests/intg/test_pam_responder.py @@ -131,7 +131,7 @@ def format_pam_cert_auth_conf(config): [pam] pam_cert_auth = True pam_p11_allowed_services = +pam_sss_service, +pam_sss_sc_required, \ - +pam_sss_try_sc + +pam_sss_try_sc, +pam_sss_allow_missing_name pam_cert_db_path = {config.PAM_CERT_DB_PATH} p11_child_timeout = 5 p11_wait_for_card_timeout = 5 @@ -146,6 +146,37 @@ def format_pam_cert_auth_conf(config): """).format(**locals()) +def format_pam_cert_auth_conf_name_format(config): + """Format SSSD configuration with full_name_format""" + return unindent("""\ + [sssd] + debug_level = 10 + domains = auth_only + services = pam, nss + + [nss] + debug_level = 10 + + [pam] + pam_cert_auth = True + pam_p11_allowed_services = +pam_sss_service, +pam_sss_sc_required, \ + +pam_sss_try_sc, +pam_sss_allow_missing_name + pam_cert_db_path = {config.PAM_CERT_DB_PATH} + p11_child_timeout = 5 + p11_wait_for_card_timeout = 5 + debug_level = 10 + + [domain/auth_only] + use_fully_qualified_names = True + full_name_format = %2$s\%1$s + debug_level = 10 + id_provider = files + + [certmap/auth_only/user1] + matchrule = <SUBJECT>.*CN=SSSD test cert 0001.* + """).format(**locals()) + + def create_conf_file(contents): """Create sssd.conf with specified contents""" conf = open(config.CONF_PATH, "w") @@ -284,6 +315,19 @@ def simple_pam_cert_auth_no_cert(request, passwd_ops_setup): return None +@pytest.fixture +def simple_pam_cert_auth_name_format(request, passwd_ops_setup): + """Setup SSSD with pam_cert_auth=True and full_name_format""" + config.PAM_CERT_DB_PATH = os.environ['PAM_CERT_DB_PATH'] + conf = format_pam_cert_auth_conf_name_format(config) + create_conf_fixture(request, conf) + create_sssd_fixture(request) + create_nssdb_fixture(request) + passwd_ops_setup.useradd(**USER1) + passwd_ops_setup.useradd(**USER2) + return None + + def test_preauth_indicator(simple_pam_cert_auth): """Check if preauth indicator file is created""" statinfo = os.stat(config.PUBCONF_PATH + "/pam_preauth_available") @@ -546,3 +590,58 @@ def test_try_sc_auth_root(simple_pam_cert_auth, env_for_sssctl): assert err.find("pam_authenticate for user [root]: Authentication " + "service cannot retrieve authentication info") != -1 + + +def test_sc_auth_missing_name(simple_pam_cert_auth, env_for_sssctl): + """ + Test pam_sss allow_missing_name feature. + """ + + sssctl = subprocess.Popen(["sssctl", "user-checks", "", + "--action=auth", + "--service=pam_sss_allow_missing_name"], + universal_newlines=True, + env=env_for_sssctl, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + try: + out, err = sssctl.communicate(input="123456") + except: + sssctl.kill() + out, err = sssctl.communicate() + + sssctl.stdin.close() + sssctl.stdout.close() + + if sssctl.wait() != 0: + raise Exception("sssctl failed") + + assert err.find("pam_authenticate for user [user1]: Success") != -1 + + +def test_sc_auth_name_format(simple_pam_cert_auth_name_format, env_for_sssctl): + """ + Test that full_name_format is respected with pam_sss allow_missing_name + option. + """ + + sssctl = subprocess.Popen(["sssctl", "user-checks", "", + "--action=auth", + "--service=pam_sss_allow_missing_name"], + universal_newlines=True, + env=env_for_sssctl, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + try: + out, err = sssctl.communicate(input="123456") + except: + sssctl.kill() + out, err = sssctl.communicate() + + sssctl.stdin.close() + sssctl.stdout.close() + + if sssctl.wait() != 0: + raise Exception("sssctl failed") + + assert err.find("pam_authenticate for user [auth_only\user1]: Success") != -1 From ca2a40ed29bd563ada1966ff834def596b8965a4 Mon Sep 17 00:00:00 2001 From: Sumit Bose <sb...@redhat.com> Date: Thu, 22 Aug 2019 12:58:39 +0200 Subject: [PATCH 2/2] f --- src/tests/intg/test_pam_responder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tests/intg/test_pam_responder.py b/src/tests/intg/test_pam_responder.py index 58969012f2..74d12d8f99 100644 --- a/src/tests/intg/test_pam_responder.py +++ b/src/tests/intg/test_pam_responder.py @@ -644,4 +644,5 @@ def test_sc_auth_name_format(simple_pam_cert_auth_name_format, env_for_sssctl): if sssctl.wait() != 0: raise Exception("sssctl failed") - assert err.find("pam_authenticate for user [auth_only\user1]: Success") != -1 + assert err.find("pam_authenticate for user [auth_only\user1]: " + + "Success") != -1
_______________________________________________ sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedorahosted.org/archives/list/sssd-devel@lists.fedorahosted.org