From 325a3a1015a8ce239efa07b2371f2f8db8bf395e Mon Sep 17 00:00:00 2001 From: Pavel Reichl Date: Wed, 11 Feb 2015 19:38:16 -0500 Subject: [PATCH 01/99] PAM: do not reject abruptly If account has expired then pass message. Resolves: https://fedorahosted.org/sssd/ticket/2050 Reviewed-by: Sumit Bose (cherry picked from commit a61d6d01a4e89ec14175af135e84f1cac55af748) --- src/responder/pam/pamsrv_cmd.c | 53 ++++++++++++++++++++++++++++++++++ src/sss_client/pam_sss.c | 64 +++++++++++++++++++++++++++++++++++++++++- src/sss_client/sss_cli.h | 18 +++++++++--- 3 files changed, 130 insertions(+), 5 deletions(-) diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 90cdbec519587a0d5dd680bfe3a991d896d6c008..c874cae61960ffa17dbe8aab7b96b792d65ac618 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -44,6 +44,54 @@ enum pam_verbosity { static void pam_reply(struct pam_auth_req *preq); +static errno_t pack_user_info_account_expired(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_account_expired(struct pam_data* pd) +{ + size_t msg_len; + uint8_t *msg; + errno_t ret; + + ret = pack_user_info_account_expired(pd, "", &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; @@ -609,6 +657,11 @@ static void pam_reply(struct pam_auth_req *preq) goto done; } + if (pd->pam_status == PAM_ACCT_EXPIRED && pd->service != NULL && + strcasecmp(pd->service, "sshd") == 0) { + inform_account_expired(pd); + } + ret = filter_responses(pctx->rctx->cdb, pd->resp_list); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "filter_responses failed, not fatal.\n"); diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c index fdf6c9e6da75c9f7eaa7c00d9a5792fbdd97eabc..59529796c682416d49c7f92f5feea3b0ace8d2d4 100644 --- a/src/sss_client/pam_sss.c +++ b/src/sss_client/pam_sss.c @@ -60,6 +60,9 @@ #define OPT_RETRY_KEY "retry=" #define OPT_DOMAINS_KEY "domains=" +#define EXP_ACC_MSG _("Your account has expired. ") +#define SRV_MSG _("Server message: ") + struct pam_items { const char* pam_service; const char* pam_user; @@ -797,6 +800,63 @@ static int user_info_otp_chpass(pam_handle_t *pamh) return PAM_SUCCESS; } +static int user_info_account_expired(pam_handle_t *pamh, size_t buflen, + uint8_t *buf) +{ + int ret; + uint32_t msg_len; + char *user_msg; + size_t bufsize = 0; + + /* resp_type and length of message are expected to be in buf */ + if (buflen < 2* sizeof(uint32_t)) { + D(("User info response data is too short")); + return PAM_BUF_ERR; + } + + /* msg_len = legth of message */ + memcpy(&msg_len, buf + sizeof(uint32_t), sizeof(uint32_t)); + + if (buflen != 2* sizeof(uint32_t) + msg_len) { + D(("User info response data has the wrong size")); + return PAM_BUF_ERR; + } + + bufsize = strlen(EXP_ACC_MSG) + 1; + + if (msg_len > 0) { + bufsize += strlen(SRV_MSG) + msg_len; + } + + user_msg = (char *)malloc(sizeof(char) * bufsize); + if (!user_msg) { + D(("Out of memory.")); + return PAM_SYSTEM_ERR; + } + + ret = snprintf(user_msg, bufsize, "%s%s%.*s", + EXP_ACC_MSG, + msg_len > 0 ? SRV_MSG : "", + msg_len, + msg_len > 0 ? (char *)(buf + 2 * sizeof(uint32_t)) : "" ); + if (ret < 0 || ret > bufsize) { + D(("snprintf failed.")); + + free(user_msg); + return PAM_SYSTEM_ERR; + } + + ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL); + free(user_msg); + if (ret != PAM_SUCCESS) { + D(("do_pam_conversation failed.")); + + return PAM_SYSTEM_ERR; + } + + return PAM_SUCCESS; +} + static int user_info_chpass_error(pam_handle_t *pamh, size_t buflen, uint8_t *buf) { @@ -852,7 +912,6 @@ static int user_info_chpass_error(pam_handle_t *pamh, size_t buflen, return PAM_SUCCESS; } - static int eval_user_info_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf) { @@ -888,6 +947,9 @@ static int eval_user_info_response(pam_handle_t *pamh, size_t buflen, case SSS_PAM_USER_INFO_CHPASS_ERROR: ret = user_info_chpass_error(pamh, buflen, buf); break; + case SSS_PAM_USER_INFO_ACCOUNT_EXPIRED: + ret = user_info_account_expired(pamh, buflen, buf); + break; default: D(("Unknown user info type [%d]", type)); ret = PAM_SYSTEM_ERR; diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h index 6286077fcf25aead1dfcba5c6483e4ff8ae63b9f..d508a0671cd1b3ee087e0967f7015628ceabe20f 100644 --- a/src/sss_client/sss_cli.h +++ b/src/sss_client/sss_cli.h @@ -461,15 +461,25 @@ enum user_info_type { * indicates that no message is following. * @param String with the specified * length. */ + SSS_PAM_USER_INFO_GRACE_LOGIN, /**< Warn the user that the password is * expired and inform about the remaining * number of grace logins. * @param The number of remaining grace * logins as uint32_t */ - SSS_PAM_USER_INFO_EXPIRE_WARN /**< Warn the user that the password will - * expire soon. - * @param Number of seconds before the user's - * password will expire. */ + SSS_PAM_USER_INFO_EXPIRE_WARN, /**< Warn the user that the password will + * expire soon. + * @param Number of seconds before the + * user's password will expire. */ + + SSS_PAM_USER_INFO_ACCOUNT_EXPIRED, /**< Tell the user that the account + * has expired and optionally give + * a reason. + * @param Size of the message as + * unsigned 32-bit integer value. A + * value of 0 indicates that no message + * is following. @param String with the + * specified length. */ }; /** * @} -- 2.4.0