From 04bddc96b93dc86fa8e33b8f0bccda4b2f1c40b7 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Thu, 15 Oct 2015 23:41:46 +0200 Subject: [PATCH 03/11] PAM: Move lockout and info messages to pamsrv_reply.c The pam_sss tests need a mocked pam responder that simulates the responses normally coming from sssd_pam. The functions to display lockout and expiration messages naturally belong there. --- Makefile.am | 2 + src/responder/pam/pamsrv.c | 43 ++++++++++++ src/responder/pam/pamsrv.h | 26 +++++++ src/responder/pam/pamsrv_cmd.c | 144 +++------------------------------------ src/responder/pam/pamsrv_reply.c | 93 +++++++++++++++++++++++++ src/tests/cmocka/test_pam_srv.c | 2 + 6 files changed, 176 insertions(+), 134 deletions(-) create mode 100644 src/responder/pam/pamsrv_reply.c diff --git a/Makefile.am b/Makefile.am index e6bb69f3a30fda3e47d5eb8493763e8e3d6dbb67..9636e133b58ce2633cfd03e3861d88032a84f9e3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1132,6 +1132,7 @@ sssd_pam_SOURCES = \ src/responder/pam/pamsrv.c \ src/responder/pam/pamsrv_cmd.c \ src/responder/pam/pamsrv_extract.c \ + src/responder/pam/pamsrv_reply.c \ src/responder/pam/pamsrv_p11.c \ src/responder/pam/pamsrv_dp.c \ src/responder/pam/pam_helpers.c \ @@ -1939,6 +1940,7 @@ pam_srv_tests_SOURCES = \ src/sss_client/pam_message.c \ src/responder/pam/pamsrv_cmd.c \ src/responder/pam/pamsrv_extract.c \ + src/responder/pam/pamsrv_reply.c \ src/responder/pam/pamsrv_p11.c \ src/responder/pam/pam_helpers.c \ src/responder/pam/pamsrv_dp.c \ diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c index a63b52ec173342b6089adb5d7131cdc2d8a526d2..d07e6c6dc37bbf9f50b6a787249fef62906bc13a 100644 --- a/src/responder/pam/pamsrv.c +++ b/src/responder/pam/pamsrv.c @@ -181,6 +181,42 @@ done: return ret; } +static errno_t get_warn_msgs(struct pam_ctx *pctx) +{ + errno_t ret; + + ret = confdb_get_int(pctx->rctx->cdb, CONFDB_PAM_CONF_ENTRY, + CONFDB_PAM_VERBOSITY, DEFAULT_PAM_VERBOSITY, + &pctx->warn_msgs.pam_verbosity); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to read PAM verbosity, not fatal.\n"); + pctx->warn_msgs.pam_verbosity = DEFAULT_PAM_VERBOSITY; + } + + ret = confdb_get_string(pctx->rctx->cdb, pctx, CONFDB_PAM_CONF_ENTRY, + CONFDB_PAM_ACCOUNT_EXPIRED_MESSAGE, "", + &pctx->warn_msgs.pam_account_expired_message); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Failed to get expiration message: %d:[%s].\n", + ret, sss_strerror(ret)); + return ret; + } + + ret = confdb_get_string(pctx->rctx->cdb, pctx, CONFDB_PAM_CONF_ENTRY, + CONFDB_PAM_ACCOUNT_LOCKED_MESSAGE, "", + &pctx->warn_msgs.pam_account_locked_message); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Failed to get expiration message: %d:[%s].\n", + ret, sss_strerror(ret)); + return ret; + } + + return EOK; +} + static int pam_process_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct confdb_ctx *cdb, @@ -233,6 +269,13 @@ static int pam_process_init(TALLOC_CTX *mem_ctx, goto done; } + ret = get_warn_msgs(pctx); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "get_warn_msgs failed: %d:[%s].\n", + ret, sss_strerror(ret)); + goto done; + } + /* Enable automatic reconnection to the Data Provider */ /* FIXME: "retries" is too generic, either get it from a global config diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h index 324291ab38c82cca8845e8eeab37b4146bb8bf40..753b30a0112a8ab3adccf7ede6fc857b95cc5ccd 100644 --- a/src/responder/pam/pamsrv.h +++ b/src/responder/pam/pamsrv.h @@ -31,6 +31,13 @@ struct pam_auth_req; typedef void (pam_dp_callback_t)(struct pam_auth_req *preq); +struct pam_warn_msgs { + char *pam_account_expired_message; + char *pam_account_locked_message; + + int pam_verbosity; +}; + struct pam_ctx { struct resp_ctx *rctx; struct sss_nc_ctx *ncache; @@ -47,6 +54,8 @@ struct pam_ctx { bool cert_auth; int p11_child_debug_fd; char *nss_db; + + struct pam_warn_msgs warn_msgs; }; struct pam_auth_dp_req { @@ -102,6 +111,23 @@ pam_set_last_online_auth_with_curr_token(struct sss_domain_info *domain, const char *username, uint64_t value); +enum pam_verbosity { + PAM_VERBOSITY_NO_MESSAGES = 0, + PAM_VERBOSITY_IMPORTANT, + PAM_VERBOSITY_INFO, + PAM_VERBOSITY_DEBUG +}; + errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *pd); +/* PAM responder output API */ +#define DEFAULT_PAM_VERBOSITY PAM_VERBOSITY_IMPORTANT + +void pamsrv_exp_warn(struct pam_data *pd, + int pam_verbosity, + const char *pam_account_expired_message); + +void pamsrv_lock_warn(struct pam_data *pd, + const char *pam_account_locked_message); + #endif /* __PAMSRV_H__ */ diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index b1454af0224b816df3d7c751b10ed18b2cd6b403..a125d6ef92d988df742a7eea56903803930e5119 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -34,15 +34,6 @@ #include "responder/common/responder_cache_req.h" #include "db/sysdb.h" -enum pam_verbosity { - PAM_VERBOSITY_NO_MESSAGES = 0, - PAM_VERBOSITY_IMPORTANT, - PAM_VERBOSITY_INFO, - PAM_VERBOSITY_DEBUG -}; - -#define DEFAULT_PAM_VERBOSITY PAM_VERBOSITY_IMPORTANT - static errno_t pam_null_last_online_auth_with_curr_token(struct sss_domain_info *domain, const char *username); @@ -53,54 +44,6 @@ 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 pack_user_info_msg(TALLOC_CTX *mem_ctx, - const char *user_error_message, - size_t *resp_len, - uint8_t **_resp) -{ - uint32_t resp_type = SSS_PAM_USER_INFO_ACCOUNT_EXPIRED; - size_t err_len; - uint8_t *resp; - size_t p; - - err_len = strlen(user_error_message); - *resp_len = 2 * sizeof(uint32_t) + err_len; - resp = talloc_size(mem_ctx, *resp_len); - if (resp == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n"); - return ENOMEM; - } - - p = 0; - SAFEALIGN_SET_UINT32(&resp[p], resp_type, &p); - SAFEALIGN_SET_UINT32(&resp[p], err_len, &p); - safealign_memcpy(&resp[p], user_error_message, err_len, &p); - if (p != *resp_len) { - DEBUG(SSSDBG_FATAL_FAILURE, "Size mismatch\n"); - } - - *_resp = resp; - return EOK; -} - -static void inform_user(struct pam_data* pd, const char *pam_message) -{ - size_t msg_len; - uint8_t *msg; - errno_t ret; - - ret = pack_user_info_msg(pd, pam_message, &msg_len, &msg); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "pack_user_info_account_expired failed.\n"); - } else { - ret = pam_add_response(pd, SSS_PAM_USER_INFO, msg_len, msg); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); - } - } -} - static bool is_domain_requested(struct pam_data *pd, const char *domain_name) { int i; @@ -191,23 +134,12 @@ fail: return ret; } -static errno_t filter_responses(struct confdb_ctx *cdb, +static errno_t filter_responses(int pam_verbosity, struct response_data *resp_list) { - int ret; struct response_data *resp; uint32_t user_info_type; int64_t expire_date; - int pam_verbosity; - - ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY, - CONFDB_PAM_VERBOSITY, DEFAULT_PAM_VERBOSITY, - &pam_verbosity); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Failed to read PAM verbosity, not fatal.\n"); - pam_verbosity = DEFAULT_PAM_VERBOSITY; - } resp = resp_list; while(resp != NULL) { @@ -299,49 +231,6 @@ static errno_t get_password_for_cache_auth(struct sss_auth_token *authtok, return EOK; } -static errno_t add_warning_about_expiration(struct pam_data *pd, - struct confdb_ctx *cdb) -{ - char* pam_account_expired_message; - int pam_verbosity; - errno_t ret; - - ret = confdb_get_int(cdb, CONFDB_PAM_CONF_ENTRY, - CONFDB_PAM_VERBOSITY, DEFAULT_PAM_VERBOSITY, - &pam_verbosity); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Failed to read PAM verbosity, not fatal.\n"); - pam_verbosity = DEFAULT_PAM_VERBOSITY; - } - - /* Account expiration warning is printed for sshd. If pam_verbosity - * is equal or above PAM_VERBOSITY_INFO then all services are informed - * about account expiration. - */ - if (pd->pam_status == PAM_ACCT_EXPIRED && - ((pd->service != NULL && strcasecmp(pd->service, "sshd") == 0) || - pam_verbosity >= PAM_VERBOSITY_INFO)) { - - ret = confdb_get_string(cdb, pd, CONFDB_PAM_CONF_ENTRY, - CONFDB_PAM_ACCOUNT_EXPIRED_MESSAGE, "", - &pam_account_expired_message); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, - "Failed to get expiration message: %d:[%s].\n", - ret, sss_strerror(ret)); - goto done; - } - - inform_user(pd, pam_account_expired_message); - } - - ret = EOK; - -done: - return ret; -} - static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd); static void pam_handle_cached_login(struct pam_auth_req *preq, int ret, time_t expire_date, time_t delayed_until, bool cached_auth); @@ -363,7 +252,6 @@ static void pam_reply(struct pam_auth_req *preq) uint32_t user_info_type; time_t exp_date = -1; time_t delay_until = -1; - char* pam_account_locked_message; pd = preq->pd; cctx = preq->cctx; @@ -491,27 +379,15 @@ static void pam_reply(struct pam_auth_req *preq) return; } - ret = add_warning_about_expiration(pd, pctx->rctx->cdb); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, "warn_about_expiration failed: %d:[%s]\n", - ret, sss_strerror(ret)); - goto done; - } + /* Add informational messages to PAM reply for cases where the user + * is expired or locked out + */ + pamsrv_exp_warn(pd, + pctx->warn_msgs.pam_verbosity, + pctx->warn_msgs.pam_account_locked_message); - if (pd->account_locked) { - - ret = confdb_get_string(pctx->rctx->cdb, pd, CONFDB_PAM_CONF_ENTRY, - CONFDB_PAM_ACCOUNT_LOCKED_MESSAGE, "", - &pam_account_locked_message); - if (ret != EOK) { - DEBUG(SSSDBG_MINOR_FAILURE, - "Failed to get expiration message: %d:[%s].\n", - ret, sss_strerror(ret)); - goto done; - } - - inform_user(pd, pam_account_locked_message); - } + pamsrv_lock_warn(pd, + pctx->warn_msgs.pam_account_locked_message); ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in), &cctx->creq->out); @@ -519,7 +395,7 @@ static void pam_reply(struct pam_auth_req *preq) goto done; } - ret = filter_responses(pctx->rctx->cdb, pd->resp_list); + ret = filter_responses(pctx->warn_msgs.pam_verbosity, pd->resp_list); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "filter_responses failed, not fatal.\n"); } diff --git a/src/responder/pam/pamsrv_reply.c b/src/responder/pam/pamsrv_reply.c new file mode 100644 index 0000000000000000000000000000000000000000..829b1b35aa7e095e727d20e961a541d1f215f477 --- /dev/null +++ b/src/responder/pam/pamsrv_reply.c @@ -0,0 +1,93 @@ +/* + SSSD + + PAM Responder + + Copyright (C) Red Hat 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "util/util.h" +#include "providers/data_provider.h" +#include "responder/pam/pamsrv.h" +#include "responder/common/responder_packet.h" + +static errno_t pack_user_info_msg(TALLOC_CTX *mem_ctx, + const char *user_error_message, + size_t *resp_len, + uint8_t **_resp) +{ + uint32_t resp_type = SSS_PAM_USER_INFO_ACCOUNT_EXPIRED; + size_t err_len; + uint8_t *resp; + size_t p; + + err_len = strlen(user_error_message); + *resp_len = 2 * sizeof(uint32_t) + err_len; + resp = talloc_size(mem_ctx, *resp_len); + if (resp == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n"); + return ENOMEM; + } + + p = 0; + SAFEALIGN_SET_UINT32(&resp[p], resp_type, &p); + SAFEALIGN_SET_UINT32(&resp[p], err_len, &p); + safealign_memcpy(&resp[p], user_error_message, err_len, &p); + if (p != *resp_len) { + DEBUG(SSSDBG_FATAL_FAILURE, "Size mismatch\n"); + } + + *_resp = resp; + return EOK; +} + +static void inform_user(struct pam_data* pd, const char *pam_message) +{ + size_t msg_len; + uint8_t *msg; + errno_t ret; + + ret = pack_user_info_msg(pd, pam_message, &msg_len, &msg); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "pack_user_info_account_expired failed.\n"); + } else { + ret = pam_add_response(pd, SSS_PAM_USER_INFO, msg_len, msg); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); + } + } +} + +void pamsrv_exp_warn(struct pam_data *pd, + int pam_verbosity, + const char *pam_account_expired_message) +{ + if (pd->pam_status == PAM_ACCT_EXPIRED && + ((pd->service != NULL && strcasecmp(pd->service, "sshd") == 0) || + pam_verbosity >= PAM_VERBOSITY_INFO)) { + inform_user(pd, pam_account_expired_message); + } +} + + +void pamsrv_lock_warn(struct pam_data *pd, + const char *pam_account_locked_message) +{ + if (pd->account_locked) { + inform_user(pd, pam_account_locked_message); + } +} diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c index 202e970a658c3a6d1daa0e87d1fc42ada541ad23..147c004d18cecdc8e7a974293a1d9ac429e76e8b 100644 --- a/src/tests/cmocka/test_pam_srv.c +++ b/src/tests/cmocka/test_pam_srv.c @@ -1311,6 +1311,7 @@ void test_pam_offline_chauthtok_prelim(void **state) will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); pam_test_ctx->exp_pam_status = PAM_AUTHINFO_UNAVAIL; + pam_test_ctx->pctx->warn_msgs.pam_verbosity = PAM_VERBOSITY_INFO; set_cmd_cb(test_pam_offline_chauthtok_check); ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_CHAUTHTOK_PRELIM, @@ -1332,6 +1333,7 @@ void test_pam_offline_chauthtok(void **state) will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); pam_test_ctx->exp_pam_status = PAM_AUTHINFO_UNAVAIL; + pam_test_ctx->pctx->warn_msgs.pam_verbosity = PAM_VERBOSITY_INFO; set_cmd_cb(test_pam_offline_chauthtok_check); ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_CHAUTHTOK, -- 2.4.11