From 923d9224e2c41b22135fab6514d38df16085102f Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Tue, 10 Nov 2015 17:45:04 +0100 Subject: [PATCH 07/11] 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, 239 insertions(+), 185 deletions(-) diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h index 7332b677d19f70f4736e4d0b68d55cdd3c67a4af..6fd8cdb7dbac2419a49b4ad6f76a27fcf0309486 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 fff6a0a0cb186ef72350b5906b85455db561e4b8..47872aee0e04e37f9048f3e78fae9c8109544eec 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -858,54 +858,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) @@ -1362,13 +1316,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"); @@ -1403,19 +1353,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; } @@ -1481,19 +1419,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 8d6a37b2ceb3347cb8092858889d07e5615e5c77..12a554efac050550ff49727c1f09aea6a4cbeffb 100644 --- a/src/providers/ldap/ldap_auth.c +++ b/src/providers/ldap/ldap_auth.c @@ -181,48 +181,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, @@ -983,8 +959,6 @@ static void sdap_auth4chpass_done(struct tevent_req *req) void *pw_expire_data; int dp_err = DP_ERR_FATAL; int ret; - size_t msg_len; - uint8_t *msg; ret = auth_recv(req, state, &state->sh, &state->dn, &pw_expire_type, &pw_expire_data); @@ -1073,19 +1047,7 @@ static void sdap_auth4chpass_done(struct tevent_req *req) 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: @@ -1111,8 +1073,6 @@ static void sdap_pam_chpass_done(struct tevent_req *req) char *user_error_message = NULL; char *lastchanged_name; struct tevent_req *subreq; - size_t msg_len; - uint8_t *msg; ret = sdap_exop_modify_passwd_recv(req, state, &user_error_message); talloc_zfree(req); @@ -1134,17 +1094,7 @@ static void sdap_pam_chpass_done(struct tevent_req *req) } 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 2f47e8dfe797104d9d453eea9b9db26176af01b9..66f64c243e9ec198d7a05cb249cdfd91ee14ec21 100644 --- a/src/responder/pam/pamsrv.h +++ b/src/responder/pam/pamsrv.h @@ -130,6 +130,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 311dfe1e0d91008c4667233e2baf5d6f68ab15f3..ba55204ade037699816d823530e752c7c2452c91 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -243,7 +243,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; @@ -299,16 +298,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 */ @@ -413,52 +404,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.4.11