diff options
author | Sumit Bose <sbose@redhat.com> | 2015-10-08 16:42:39 +0200 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2017-02-23 10:15:08 +0100 |
commit | 82c5971fafe6063a90289ebba08035fc49ae8590 (patch) | |
tree | 7cc048fa7e5fae8db2a08a2f2359c4cac9de9849 | |
parent | dd17a3aaddab6f122dff3bd15b7005464c07c0ea (diff) | |
download | sssd-82c5971fafe6063a90289ebba08035fc49ae8590.tar.gz sssd-82c5971fafe6063a90289ebba08035fc49ae8590.tar.xz sssd-82c5971fafe6063a90289ebba08035fc49ae8590.zip |
PAM: forward Smartcard credentials to backends
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-rw-r--r-- | src/responder/pam/pamsrv.h | 3 | ||||
-rw-r--r-- | src/responder/pam/pamsrv_cmd.c | 102 | ||||
-rw-r--r-- | src/tests/cmocka/test_pam_srv.c | 16 |
3 files changed, 97 insertions, 24 deletions
diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h index e3568123a..389888eca 100644 --- a/src/responder/pam/pamsrv.h +++ b/src/responder/pam/pamsrv.h @@ -71,6 +71,9 @@ struct pam_auth_req { struct ldb_message *user_obj; struct ldb_message *cert_user_obj; char *token_name; + char *module_name; + char *key_id; + bool cert_auth_local; }; struct sss_cmd_table *get_pam_cmds(void); diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index e74dd1684..529c74f70 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -53,6 +53,14 @@ pam_get_last_online_auth_with_curr_token(struct sss_domain_info *domain, static void pam_reply(struct pam_auth_req *preq); +static errno_t check_cert(TALLOC_CTX *mctx, + struct tevent_context *ev, + struct pam_ctx *pctx, + struct pam_auth_req *preq, + struct pam_data *pd); + +static int pam_check_user_done(struct pam_auth_req *preq, int ret); + static errno_t pack_user_info_msg(TALLOC_CTX *mem_ctx, const char *user_error_message, size_t *resp_len, @@ -718,6 +726,28 @@ static void pam_reply(struct pam_auth_req *preq) DEBUG(SSSDBG_FUNC_DATA, "pam_reply called with result [%d]: %s.\n", pd->pam_status, pam_strerror(NULL, pd->pam_status)); + + if (pd->cmd == SSS_PAM_AUTHENTICATE + && (pd->pam_status == PAM_AUTHINFO_UNAVAIL + || pd->pam_status == PAM_NO_MODULE_DATA + || pd->pam_status == PAM_BAD_ITEM) + && may_do_cert_auth(pctx, pd)) { + /* We have Smartcard credentials and the backend indicates that it is + * offline (PAM_AUTHINFO_UNAVAIL) or cannot handle the credentials + * (PAM_BAD_ITEM), so let's try authentication against the Smartcard + * PAM_NO_MODULE_DATA is returned by the krb5 backend if no + * authentication method was found at all, this might happen if the + * user has a Smartcard assigned but the pkint plugin is not available + * on the client. */ + DEBUG(SSSDBG_IMPORTANT_INFO, + "Backend cannot handle Smartcard authentication, " + "trying local Smartcard authentication.\n"); + preq->cert_auth_local = true; + ret = check_cert(cctx, cctx->ev, pctx, preq, pd); + pam_check_user_done(preq, ret); + return; + } + if (pd->pam_status == PAM_AUTHINFO_UNAVAIL || preq->use_cached_auth) { switch(pd->cmd) { @@ -1019,7 +1049,6 @@ static void pam_forwarder_cert_cb(struct tevent_req *req); static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min, const char *err_msg, void *ptr); static int pam_check_user_search(struct pam_auth_req *preq); -static int pam_check_user_done(struct pam_auth_req *preq, int ret); static errno_t pam_cmd_assume_upn(struct pam_auth_req *preq) { @@ -1234,6 +1263,7 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) } talloc_set_destructor(preq, pam_auth_req_destructor); preq->cctx = cctx; + preq->cert_auth_local = false; preq->pd = create_pam_data(preq); if (!preq->pd) { @@ -1330,8 +1360,9 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) } } - - if (may_do_cert_auth(pctx, pd)) { + /* try backend first for authentication before doing local Smartcard + * authentication */ + if (pd->cmd != SSS_PAM_AUTHENTICATE && may_do_cert_auth(pctx, pd)) { ret = check_cert(cctx, cctx->ev, pctx, preq, pd); /* Finish here */ goto done; @@ -1439,6 +1470,12 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) preq->cert_user_obj = talloc_steal(preq, result->msgs[0]); if (preq->pd->logon_name == NULL) { + if (preq->pd->cmd != SSS_PAM_PREAUTH) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Missing logon name only allowed during pre-auth.\n"); + ret = ENOENT; + goto done; + } cert_user = ldb_msg_find_attr_as_string(preq->cert_user_obj, SYSDB_NAME, NULL); if (cert_user == NULL) { @@ -1451,20 +1488,17 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) DEBUG(SSSDBG_FUNC_DATA, "Found certificate user [%s].\n", cert_user); - ret = add_pam_cert_response(preq->pd, cert_user, preq->token_name); + ret = sss_parse_name_for_domains(preq->pd, + preq->cctx->rctx->domains, + preq->cctx->rctx->default_domain, + cert_user, + &preq->pd->domain, + &preq->pd->user); if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n"); - } - - preq->pd->domain = talloc_strdup(preq->pd, result->domain->name); - if (preq->pd->domain == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); - ret = ENOMEM; + DEBUG(SSSDBG_OP_FAILURE, + "sss_parse_name_for_domains failed.\n"); goto done; } - preq->pd->pam_status = PAM_SUCCESS; - pam_reply(preq); - return; } } else { if (preq->pd->logon_name == NULL) { @@ -1475,7 +1509,12 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) } } - ret = pam_check_user_search(preq); + if (preq->user_obj == NULL) { + ret = pam_check_user_search(preq); + } else { + ret = EOK; + } + if (ret == EOK) { pam_dom_forwarder(preq); } @@ -1531,7 +1570,9 @@ static void pam_forwarder_cb(struct tevent_req *req) } } - if (may_do_cert_auth(pctx, pd)) { + /* try backend first for authentication before doing local Smartcard + * authentication */ + if (pd->cmd != SSS_PAM_AUTHENTICATE && may_do_cert_auth(pctx, pd)) { ret = check_cert(cctx, cctx->ev, pctx, preq, pd); /* Finish here */ goto done; @@ -1985,7 +2026,7 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) NULL); if (cert_user == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, - "Certificate user object has not name.\n"); + "Certificate user object has no name.\n"); preq->pd->pam_status = PAM_USER_UNKNOWN; pam_reply(preq); return; @@ -1994,11 +2035,21 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) /* pam_check_user_search() calls pd_set_primary_name() is the search * was successful, so pd->user contains the canonical sysdb name * as well */ - if (strcmp(cert_user, preq->pd->user) == 0) { - - preq->pd->pam_status = PAM_SUCCESS; + if (ldb_dn_compare(preq->cert_user_obj->dn, preq->user_obj->dn) == 0) { if (preq->pd->cmd == SSS_PAM_PREAUTH) { + ret = sss_authtok_set_sc(preq->pd->authtok, + SSS_AUTHTOK_TYPE_SC_PIN, NULL, 0, + preq->token_name, 0, + preq->module_name, 0, + preq->key_id, 0); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_set_sc failed, " + "Smartcard authentication " + "detection might fail in the " + "backend.\n"); + } + ret = add_pam_cert_response(preq->pd, cert_user, preq->token_name); if (ret != EOK) { @@ -2007,9 +2058,14 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) } } - preq->callback = pam_reply; - pam_reply(preq); - return; + /* We are done if we do not have to call the backend */ + if (preq->pd->cmd == SSS_PAM_AUTHENTICATE + && preq->cert_auth_local) { + preq->pd->pam_status = PAM_SUCCESS; + preq->callback = pam_reply; + pam_reply(preq); + return; + } } else { if (preq->pd->cmd == SSS_PAM_PREAUTH) { DEBUG(SSSDBG_TRACE_FUNC, diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c index e6ed8f509..6b91f49c6 100644 --- a/src/tests/cmocka/test_pam_srv.c +++ b/src/tests/cmocka/test_pam_srv.c @@ -285,6 +285,9 @@ static void pam_test_setup_common(void) pam_test_ctx->tctx->dom->name); assert_non_null(pam_test_ctx->wrong_user_fqdn); + /* integer values cannot be set by pam_params */ + pam_test_ctx->pctx->id_timeout = 5; + /* Prime the cache with a valid user */ ret = sysdb_add_user(pam_test_ctx->tctx->dom, pam_test_ctx->pam_user_fqdn, @@ -783,6 +786,13 @@ static int test_pam_wrong_pw_offline_auth_check(uint32_t status, return test_pam_simple_check(status, body, blen); } +static int test_pam_simple_check_success(uint32_t status, + uint8_t *body, size_t blen) +{ + pam_test_ctx->exp_pam_status = PAM_SUCCESS; + return test_pam_simple_check(status, body, blen); +} + static int test_pam_creds_insufficient_check(uint32_t status, uint8_t *body, size_t blen) { @@ -1752,7 +1762,11 @@ void test_pam_cert_auth(void **state) mock_account_recv(0, 0, NULL, test_lookup_by_cert_cb, discard_const(TEST_TOKEN_CERT)); - set_cmd_cb(test_pam_simple_check); + /* Assume backend cannot handle Smartcard credentials */ + pam_test_ctx->exp_pam_status = PAM_BAD_ITEM; + + + set_cmd_cb(test_pam_simple_check_success); ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, pam_test_ctx->pam_cmds); assert_int_equal(ret, EOK); |