From 97dff3cb6a7a2f9a456ac6d77851da532b63bb33 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Tue, 10 Nov 2015 17:45:04 +0100 Subject: [PATCH 07/12] PAM: Consolidate PAM responses In order to produce different kind of PAM responses normally emitted in providers or responders, move them into a common module that could be used by pam_sss tests. --- src/providers/data_provider.h | 12 ++++ src/providers/dp_pam_data_util.c | 136 +++++++++++++++++++++++++++++++++++++++ src/providers/krb5/krb5_child.c | 82 ++--------------------- src/providers/ldap/ldap_auth.c | 62 ++---------------- src/responder/pam/pamsrv.h | 5 ++ src/responder/pam/pamsrv_cmd.c | 55 ++-------------- src/responder/pam/pamsrv_reply.c | 72 +++++++++++++++++++++ 7 files changed, 240 insertions(+), 184 deletions(-) diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index 14a0902c265850d91fa7d29cc2708e70b060ec18..761558faccdd81e5376a95bda38ae71e0f58014d 100644 --- a/src/providers/data_provider.h +++ b/src/providers/data_provider.h @@ -218,6 +218,18 @@ int pam_add_response(struct pam_data *pd, enum response_type type, int len, const uint8_t *data); +void pam_resp_grace_login(struct pam_data *pd, uint32_t grace); +void pam_resp_expired_login(struct pam_data *pd, uint32_t expire); +void pam_resp_srv_msg(struct pam_data *pd, const char *str_msg); + +/* Unlike other pam_resp* function, failure of this one must + * be fatal + */ +errno_t pam_resp_otp_info(struct pam_data *pd, + const char *otp_vendor, + const char *otp_token_id, + const char *otp_challenge); + bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd); bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx, struct pam_data **new_pd, DBusError *dbus_error); diff --git a/src/providers/dp_pam_data_util.c b/src/providers/dp_pam_data_util.c index bed5db872d18e0c3ab13d7b7fd061749253cc72a..9ad75f6f128e80e4b90c59b65c4f0febb9547481 100644 --- a/src/providers/dp_pam_data_util.c +++ b/src/providers/dp_pam_data_util.c @@ -196,3 +196,139 @@ int pam_add_response(struct pam_data *pd, enum response_type type, return EOK; } + +static void pam_resp_add_pwexpire(struct pam_data *pd, + uint32_t key, + uint32_t value) +{ + uint32_t *data; + errno_t ret; + + data = talloc_size(pd, 2 * sizeof(uint32_t)); + if (data == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n"); + return; + } + + data[0] = key; + data[1] = value; + + ret = pam_add_response(pd, SSS_PAM_USER_INFO, 2 * sizeof(uint32_t), + (uint8_t*)data); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); + } +} + +void pam_resp_grace_login(struct pam_data *pd, uint32_t grace) +{ + pam_resp_add_pwexpire(pd, SSS_PAM_USER_INFO_GRACE_LOGIN, grace); +} + +void pam_resp_expired_login(struct pam_data *pd, uint32_t expire) +{ + pam_resp_add_pwexpire(pd, SSS_PAM_USER_INFO_EXPIRE_WARN, expire); +} + +static errno_t pack_user_info_chpass_error(TALLOC_CTX *mem_ctx, + const char *user_error_message, + size_t *resp_len, + uint8_t **_resp) +{ + uint32_t resp_type = SSS_PAM_USER_INFO_CHPASS_ERROR; + 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; +} + +void pam_resp_srv_msg(struct pam_data *pd, const char *str_msg) +{ + int ret; + size_t msg_len; + uint8_t *msg; + + ret = pack_user_info_chpass_error(pd, str_msg, &msg_len, &msg); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "pack_user_info_chpass_error 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"); + } + } +} + +errno_t pam_resp_otp_info(struct pam_data *pd, + const char *otp_vendor, + const char *otp_token_id, + const char *otp_challenge) +{ + uint8_t *msg = NULL; + size_t msg_len; + int ret; + size_t vendor_len = 0; + size_t token_id_len = 0; + size_t challenge_len = 0; + size_t idx = 0; + + msg_len = 3; /* Length of the components */ + + if (otp_vendor != NULL) { + vendor_len = strlen(otp_vendor); + msg_len += vendor_len; + } + + if (otp_token_id != NULL) { + token_id_len = strlen(otp_token_id); + msg_len += token_id_len; + } + + if (otp_challenge != NULL) { + challenge_len = strlen(otp_challenge); + msg_len += challenge_len; + } + + msg = talloc_zero_size(pd, msg_len); + if (msg == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n"); + return ENOMEM; + } + + if (otp_vendor != NULL) { + memcpy(msg, otp_vendor, vendor_len); + } + idx += vendor_len +1; + + if (otp_token_id != NULL) { + memcpy(msg + idx, otp_token_id, token_id_len); + } + idx += token_id_len +1; + + if (otp_challenge != NULL) { + memcpy(msg + idx, otp_challenge, challenge_len); + } + + ret = pam_add_response(pd, SSS_PAM_OTP_INFO, msg_len, msg); + talloc_zfree(msg); + + return ret; +} diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index df94bc4c481b090d50f9b0119ccde5a373d9e20b..7d3f9a051b502e33c5a0f931526bbeec41ae3df7 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -922,54 +922,8 @@ static errno_t pack_response_packet(TALLOC_CTX *mem_ctx, errno_t error, static errno_t k5c_attach_otp_info_msg(struct krb5_req *kr) { - uint8_t *msg = NULL; - size_t msg_len; - int ret; - size_t vendor_len = 0; - size_t token_id_len = 0; - size_t challenge_len = 0; - size_t idx = 0; - - msg_len = 3; - if (kr->otp_vendor != NULL) { - vendor_len = strlen(kr->otp_vendor); - msg_len += vendor_len; - } - - if (kr->otp_token_id != NULL) { - token_id_len = strlen(kr->otp_token_id); - msg_len += token_id_len; - } - - if (kr->otp_challenge != NULL) { - challenge_len = strlen(kr->otp_challenge); - msg_len += challenge_len; - } - - msg = talloc_zero_size(kr, msg_len); - if (msg == NULL) { - DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n"); - return ENOMEM; - } - - if (kr->otp_vendor != NULL) { - memcpy(msg, kr->otp_vendor, vendor_len); - } - idx += vendor_len +1; - - if (kr->otp_token_id != NULL) { - memcpy(msg + idx, kr->otp_token_id, token_id_len); - } - idx += token_id_len +1; - - if (kr->otp_challenge != NULL) { - memcpy(msg + idx, kr->otp_challenge, challenge_len); - } - - ret = pam_add_response(kr->pd, SSS_PAM_OTP_INFO, msg_len, msg); - talloc_zfree(msg); - - return ret; + return pam_resp_otp_info(kr->pd, kr->otp_vendor, + kr->otp_token_id, kr->otp_challenge); } static errno_t k5c_attach_ccname_msg(struct krb5_req *kr) @@ -1428,13 +1382,9 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) krb5_data result_code_string; krb5_data result_string; char *user_error_message = NULL; - size_t user_resp_len; - uint8_t *user_resp; krb5_prompter_fct prompter = NULL; const char *realm_name; int realm_length; - size_t msg_len; - uint8_t *msg; uint32_t user_info_type; DEBUG(SSSDBG_TRACE_LIBS, "Password change operation\n"); @@ -1469,19 +1419,7 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) DEBUG(SSSDBG_TRACE_INTERNAL, "chpass is%s using OTP\n", kr->otp ? "" : " not"); if (kerr != 0) { - ret = pack_user_info_chpass_error(kr->pd, "Old password not accepted.", - &msg_len, &msg); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "pack_user_info_chpass_error failed.\n"); - } else { - ret = pam_add_response(kr->pd, SSS_PAM_USER_INFO, msg_len, - msg); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "pam_add_response failed.\n"); - } - } + pam_resp_srv_msg(kr->pd, "Old password not accepted."); return kerr; } @@ -1547,19 +1485,7 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) } if (user_error_message != NULL) { - ret = pack_user_info_chpass_error(kr->pd, user_error_message, - &user_resp_len, &user_resp); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "pack_user_info_chpass_error failed.\n"); - } else { - ret = pam_add_response(kr->pd, SSS_PAM_USER_INFO, user_resp_len, - user_resp); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "pack_response_packet failed.\n"); - } - } + pam_resp_srv_msg(kr->pd, user_error_message); } return ERR_CHPASS_FAILED; diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c index 00d38284e428eea42254820fd08ee4fb125235a6..876cc3473e1ca4ca7b18a26357ce306f11fc70ac 100644 --- a/src/providers/ldap/ldap_auth.c +++ b/src/providers/ldap/ldap_auth.c @@ -182,48 +182,24 @@ static errno_t check_pwexpire_ldap(struct pam_data *pd, struct sdap_ppolicy_data *ppolicy, int pwd_exp_warning) { - int ret = EOK; - if (ppolicy->grace >= 0 || ppolicy->expire > 0) { - uint32_t *data; - uint32_t *ptr; - if (pwd_exp_warning < 0) { pwd_exp_warning = 0; } - data = talloc_size(pd, 2* sizeof(uint32_t)); - if (data == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n"); - return ENOMEM; - } - - ptr = data; if (ppolicy->grace >= 0) { - *ptr = SSS_PAM_USER_INFO_GRACE_LOGIN; - ptr++; - *ptr = ppolicy->grace; + pam_resp_grace_login(pd, ppolicy->grace); } else if (ppolicy->expire > 0) { if (pwd_exp_warning != 0 && ppolicy->expire > pwd_exp_warning) { /* do not warn */ - goto done; + return EOK; } - /* send warning */ - *ptr = SSS_PAM_USER_INFO_EXPIRE_WARN; - ptr++; - *ptr = ppolicy->expire; - } - - ret = pam_add_response(pd, SSS_PAM_USER_INFO, 2* sizeof(uint32_t), - (uint8_t*)data); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); + pam_resp_grace_login(pd, ppolicy->expire); } } -done: - return ret; + return EOK; } errno_t check_pwexpire_policy(enum pwexpire pw_expire_type, @@ -1155,9 +1131,7 @@ static void sdap_pam_chpass_handler_auth_done(struct tevent_req *subreq) struct tevent_req *req; enum pwexpire pw_expire_type; void *pw_expire_data; - size_t msg_len; - uint8_t *msg; - errno_t ret; + int ret; req = tevent_req_callback_data(subreq, struct tevent_req); state = tevent_req_data(req, struct sdap_pam_chpass_handler_state); @@ -1252,18 +1226,7 @@ static void sdap_pam_chpass_handler_auth_done(struct tevent_req *subreq) case ERR_AUTH_DENIED: case ERR_AUTH_FAILED: state->pd->pam_status = PAM_AUTH_ERR; - ret = pack_user_info_chpass_error(state->pd, "Old password not " - "accepted.", &msg_len, &msg); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "pack_user_info_chpass_error failed.\n"); - } else { - ret = pam_add_response(state->pd, SSS_PAM_USER_INFO, - msg_len, msg); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); - } - } + pam_resp_srv_msg(state->pd, "Old password not accepted"); break; case ETIMEDOUT: case ERR_NETWORK_IO: @@ -1286,8 +1249,6 @@ static void sdap_pam_chpass_handler_chpass_done(struct tevent_req *subreq) struct tevent_req *req; char *user_error_message = NULL; char *lastchanged_name; - size_t msg_len; - uint8_t *msg; errno_t ret; req = tevent_req_callback_data(subreq, struct tevent_req); @@ -1312,16 +1273,7 @@ static void sdap_pam_chpass_handler_chpass_done(struct tevent_req *subreq) } if (state->pd->pam_status != PAM_SUCCESS && user_error_message != NULL) { - ret = pack_user_info_chpass_error(state->pd, user_error_message, - &msg_len, &msg); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "pack_user_info_chpass_error failed.\n"); - } else { - ret = pam_add_response(state->pd, SSS_PAM_USER_INFO, msg_len, msg); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); - } - } + pam_resp_srv_msg(state->pd, user_error_message); } if (state->pd->pam_status == PAM_SUCCESS && diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h index 9502e9958c468dffeca5d8a3d9c53e0208d50493..00dcec1f16947405a5cb9eb44ebf91dd503076d3 100644 --- a/src/responder/pam/pamsrv.h +++ b/src/responder/pam/pamsrv.h @@ -128,6 +128,11 @@ void pamsrv_exp_warn(struct pam_data *pd, void pamsrv_lock_warn(struct pam_data *pd, const char *pam_account_locked_message); +void pamsrv_resp_offline_auth(struct pam_data *pd, time_t expire_date); +void pamsrv_resp_offline_delayed_auth(struct pam_data *pd, + time_t delayed_until); +void pamsrv_resp_offline_chpass(struct pam_data *pd); + errno_t pamsrv_reply_packet(TALLOC_CTX *mem_ctx, struct pam_data *pd, enum sss_cli_command cmd, diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index 57040f34d63fde995769621f806411a60b0488bd..d416eb406d68408f25f1895c65bad3e1b27507c6 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -244,7 +244,6 @@ static void pam_reply(struct pam_auth_req *preq) struct tevent_timer *te; struct pam_data *pd; struct pam_ctx *pctx; - uint32_t user_info_type; time_t exp_date = -1; time_t delay_until = -1; @@ -301,16 +300,8 @@ static void pam_reply(struct pam_auth_req *preq) break; case SSS_PAM_CHAUTHTOK_PRELIM: case SSS_PAM_CHAUTHTOK: - DEBUG(SSSDBG_FUNC_DATA, - "Password change not possible while offline.\n"); - pd->pam_status = PAM_AUTHTOK_ERR; - user_info_type = SSS_PAM_USER_INFO_OFFLINE_CHPASS; - ret = pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t), - (const uint8_t *) &user_info_type); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); - goto done; - } + preq->pd->pam_status = PAM_AUTHTOK_ERR; + pamsrv_resp_offline_chpass(preq->pd); break; /* TODO: we need the pam session cookie here to make sure that cached * authentication was successful */ @@ -416,52 +407,14 @@ static void pam_handle_cached_login(struct pam_auth_req *preq, int ret, time_t expire_date, time_t delayed_until, bool use_cached_auth) { - uint32_t resp_type; - size_t resp_len; - uint8_t *resp; - int64_t dummy; - preq->pd->pam_status = cached_login_pam_status(ret); switch (preq->pd->pam_status) { case PAM_SUCCESS: - resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH; - resp_len = sizeof(uint32_t) + sizeof(int64_t); - resp = talloc_size(preq->pd, resp_len); - if (resp == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, - "talloc_size failed, cannot prepare user info.\n"); - } else { - memcpy(resp, &resp_type, sizeof(uint32_t)); - dummy = (int64_t) expire_date; - memcpy(resp+sizeof(uint32_t), &dummy, sizeof(int64_t)); - ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len, - (const uint8_t *) resp); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); - } - } + pamsrv_resp_offline_auth(preq->pd, expire_date); break; case PAM_PERM_DENIED: - if (delayed_until >= 0) { - resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH_DELAYED; - resp_len = sizeof(uint32_t) + sizeof(int64_t); - resp = talloc_size(preq->pd, resp_len); - if (resp == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, - "talloc_size failed, cannot prepare user info.\n"); - } else { - memcpy(resp, &resp_type, sizeof(uint32_t)); - dummy = (int64_t) delayed_until; - memcpy(resp+sizeof(uint32_t), &dummy, sizeof(int64_t)); - ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len, - (const uint8_t *) resp); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - "pam_add_response failed.\n"); - } - } - } + pamsrv_resp_offline_delayed_auth(preq->pd, delayed_until); break; case PAM_AUTH_ERR: /* Was this attempt to authenticate from cache? */ diff --git a/src/responder/pam/pamsrv_reply.c b/src/responder/pam/pamsrv_reply.c index 73fe66a936af395e27af2feaf82607755c79ba22..c3010335361a208bcc3846b032f31ea44cc5e677 100644 --- a/src/responder/pam/pamsrv_reply.c +++ b/src/responder/pam/pamsrv_reply.c @@ -24,6 +24,78 @@ #include "responder/pam/pamsrv.h" #include "responder/common/responder_packet.h" +void pamsrv_resp_offline_auth(struct pam_data *pd, time_t expire_date) +{ + int ret; + uint32_t resp_type; + size_t resp_len; + uint8_t *resp; + int64_t dummy; + + resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH; + resp_len = sizeof(uint32_t) + sizeof(int64_t); + resp = talloc_size(pd, resp_len); + if (resp == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "talloc_size failed, cannot prepare user info.\n"); + } else { + memcpy(resp, &resp_type, sizeof(uint32_t)); + dummy = (int64_t) expire_date; + memcpy(resp+sizeof(uint32_t), &dummy, sizeof(int64_t)); + ret = pam_add_response(pd, SSS_PAM_USER_INFO, resp_len, + (const uint8_t *) resp); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); + } + } +} + +void pamsrv_resp_offline_delayed_auth(struct pam_data *pd, + time_t delayed_until) +{ + int ret; + uint32_t resp_type; + size_t resp_len; + uint8_t *resp; + int64_t dummy; + + if (delayed_until >= 0) { + resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH_DELAYED; + resp_len = sizeof(uint32_t) + sizeof(int64_t); + resp = talloc_size(pd, resp_len); + if (resp == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "talloc_size failed, cannot prepare user info.\n"); + } else { + memcpy(resp, &resp_type, sizeof(uint32_t)); + dummy = (int64_t) delayed_until; + memcpy(resp+sizeof(uint32_t), &dummy, sizeof(int64_t)); + ret = pam_add_response(pd, SSS_PAM_USER_INFO, resp_len, + (const uint8_t *) resp); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); + } + } + } +} + +void pamsrv_resp_offline_chpass(struct pam_data *pd) +{ + int ret; + uint32_t user_info_type; + + DEBUG(SSSDBG_FUNC_DATA, + "Password change not possible while offline.\n"); + + user_info_type = SSS_PAM_USER_INFO_OFFLINE_CHPASS; + + ret = pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t), + (const uint8_t *) &user_info_type); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n"); + } +} + static errno_t pack_user_info_msg(TALLOC_CTX *mem_ctx, const char *user_error_message, size_t *resp_len, -- 2.7.4