diff options
-rw-r--r-- | server/Makefile.am | 4 | ||||
-rw-r--r-- | server/providers/krb5/krb5_child.c | 78 | ||||
-rw-r--r-- | server/providers/ldap/ldap_auth.c | 19 | ||||
-rw-r--r-- | server/providers/ldap/sdap_async.c | 17 | ||||
-rw-r--r-- | server/providers/ldap/sdap_async.h | 5 | ||||
-rw-r--r-- | server/util/user_info_msg.c | 51 | ||||
-rw-r--r-- | server/util/user_info_msg.h | 33 | ||||
-rw-r--r-- | sss_client/pam_sss.c | 42 | ||||
-rw-r--r-- | sss_client/sss_cli.h | 3 |
9 files changed, 228 insertions, 24 deletions
diff --git a/server/Makefile.am b/server/Makefile.am index 7f8c24b47..5cab21fb5 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -306,6 +306,7 @@ dist_noinst_HEADERS = \ util/sss_krb5.h \ util/refcount.h \ util/find_uid.h \ + util/user_info_msg.h \ config.h \ monitor/monitor.h \ monitor/monitor_interfaces.h \ @@ -632,6 +633,7 @@ libsss_ldap_la_SOURCES = \ providers/ldap/sdap_async_connection.c \ providers/ldap/sdap_child_helpers.c \ providers/ldap/sdap.c \ + util/user_info_msg.c \ util/sss_ldap.c \ util/sss_krb5.c libsss_ldap_la_CFLAGS = \ @@ -691,6 +693,7 @@ libsss_ipa_la_SOURCES = \ providers/ldap/sdap_async_connection.c \ providers/ldap/sdap_child_helpers.c \ providers/ldap/sdap.c \ + util/user_info_msg.c \ util/sss_ldap.c \ util/sss_krb5.c \ util/find_uid.c \ @@ -716,6 +719,7 @@ krb5_child_SOURCES = \ providers/krb5/krb5_become_user.c \ providers/krb5/krb5_child.c \ providers/child_common.c \ + util/user_info_msg.c \ util/sss_krb5.c krb5_child_CFLAGS = \ $(AM_CFLAGS) \ diff --git a/server/providers/krb5/krb5_child.c b/server/providers/krb5/krb5_child.c index d8f733b70..645274b36 100644 --- a/server/providers/krb5/krb5_child.c +++ b/server/providers/krb5/krb5_child.c @@ -30,6 +30,7 @@ #include <security/pam_modules.h> #include "util/util.h" +#include "util/user_info_msg.h" #include "providers/child_common.h" #include "providers/dp_backend.h" #include "providers/krb5/krb5_auth.h" @@ -256,13 +257,12 @@ static struct response *init_response(TALLOC_CTX *mem_ctx) { return r; } -static errno_t pack_response_packet(struct response *resp, int status, int type, const char *data) +static errno_t pack_response_packet(struct response *resp, int status, int type, + size_t len, const uint8_t *data) { - int len; int p=0; int32_t c; - len = strlen(data)+1; if ((3*sizeof(int32_t) + len +1) > resp->max_size) { DEBUG(1, ("response message too big.\n")); return ENOMEM; @@ -289,12 +289,16 @@ static errno_t pack_response_packet(struct response *resp, int status, int type, } static struct response *prepare_response_message(struct krb5_req *kr, - krb5_error_code kerr, int pam_status) + krb5_error_code kerr, + char *user_error_message, + int pam_status) { char *msg = NULL; const char *krb5_msg = NULL; int ret; struct response *resp; + size_t user_resp_len; + uint8_t *user_resp; resp = init_response(kr); if (resp == NULL) { @@ -305,7 +309,8 @@ static struct response *prepare_response_message(struct krb5_req *kr, if (kerr == 0) { if(kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { ret = pack_response_packet(resp, PAM_SUCCESS, SSS_PAM_SYSTEM_INFO, - "success"); + strlen("success") + 1, + (const uint8_t *) "success"); } else { if (kr->ccname == NULL) { DEBUG(1, ("Error obtaining ccname.\n")); @@ -318,19 +323,43 @@ static struct response *prepare_response_message(struct krb5_req *kr, return NULL; } - ret = pack_response_packet(resp, PAM_SUCCESS, SSS_PAM_ENV_ITEM, msg); + ret = pack_response_packet(resp, PAM_SUCCESS, SSS_PAM_ENV_ITEM, + strlen(msg) + 1, (uint8_t *) msg); talloc_zfree(msg); } } else { - krb5_msg = sss_krb5_get_error_message(krb5_error_ctx, kerr); - if (krb5_msg == NULL) { - DEBUG(1, ("sss_krb5_get_error_message failed.\n")); - return NULL; + + if (user_error_message != NULL) { + ret = pack_user_info_chpass_error(kr, user_error_message, + &user_resp_len, &user_resp); + if (ret != EOK) { + DEBUG(1, ("pack_user_info_chpass_error failed.\n")); + talloc_zfree(user_error_message); + } else { + ret = pack_response_packet(resp, pam_status, SSS_PAM_USER_INFO, + user_resp_len, user_resp); + if (ret != EOK) { + DEBUG(1, ("pack_response_packet failed.\n")); + talloc_zfree(user_error_message); + } + } + } + + if (user_error_message == NULL) { + krb5_msg = sss_krb5_get_error_message(krb5_error_ctx, kerr); + if (krb5_msg == NULL) { + DEBUG(1, ("sss_krb5_get_error_message failed.\n")); + return NULL; + } + + ret = pack_response_packet(resp, pam_status, SSS_PAM_SYSTEM_INFO, + strlen(krb5_msg) + 1, + (const uint8_t *) krb5_msg); + sss_krb5_free_error_message(krb5_error_ctx, krb5_msg); + } else { + } - ret = pack_response_packet(resp, pam_status, SSS_PAM_SYSTEM_INFO, - krb5_msg); - sss_krb5_free_error_message(krb5_error_ctx, krb5_msg); } if (ret != EOK) { @@ -341,14 +370,15 @@ static struct response *prepare_response_message(struct krb5_req *kr, return resp; } -static errno_t sendresponse(int fd, krb5_error_code kerr, int pam_status, +static errno_t sendresponse(int fd, krb5_error_code kerr, + char *user_error_message, int pam_status, struct krb5_req *kr) { struct response *resp; size_t written; int ret; - resp = prepare_response_message(kr, kerr, pam_status); + resp = prepare_response_message(kr, kerr, user_error_message, pam_status); if (resp == NULL) { DEBUG(1, ("prepare_response_message failed.\n")); return ENOMEM; @@ -522,6 +552,7 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) int result_code = -1; krb5_data result_code_string; krb5_data result_string; + char *user_error_message = NULL; pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, kr->pd->authtok_size); @@ -576,11 +607,22 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) if (result_code_string.length > 0) { DEBUG(1, ("krb5_change_password failed [%d][%.*s].\n", result_code, result_code_string.length, result_code_string.data)); + user_error_message = talloc_strndup(kr->pd, result_code_string.data, + result_code_string.length); + if (user_error_message == NULL) { + DEBUG(1, ("talloc_strndup failed.\n")); + } } if (result_string.length > 0) { DEBUG(1, ("krb5_change_password failed [%d][%.*s].\n", result_code, result_string.length, result_string.data)); + talloc_free(user_error_message); + user_error_message = talloc_strndup(kr->pd, result_string.data, + result_string.length); + if (user_error_message == NULL) { + DEBUG(1, ("talloc_strndup failed.\n")); + } } pam_status = PAM_AUTHTOK_ERR; @@ -602,7 +644,7 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) } sendresponse: - ret = sendresponse(fd, kerr, pam_status, kr); + ret = sendresponse(fd, kerr, user_error_message, pam_status, kr); if (ret != EOK) { DEBUG(1, ("sendresponse failed.\n")); } @@ -664,7 +706,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) } sendresponse: - ret = sendresponse(fd, kerr, pam_status, kr); + ret = sendresponse(fd, kerr, NULL, pam_status, kr); if (ret != EOK) { DEBUG(1, ("sendresponse failed.\n")); } @@ -683,7 +725,7 @@ static errno_t create_empty_ccache(int fd, struct krb5_req *kr) pam_status = PAM_SYSTEM_ERR; } - ret = sendresponse(fd, ret, pam_status, kr); + ret = sendresponse(fd, ret, NULL, pam_status, kr); if (ret != EOK) { DEBUG(1, ("sendresponse failed.\n")); } diff --git a/server/providers/ldap/ldap_auth.c b/server/providers/ldap/ldap_auth.c index 1d1346c07..cfe8adb97 100644 --- a/server/providers/ldap/ldap_auth.c +++ b/server/providers/ldap/ldap_auth.c @@ -40,6 +40,7 @@ #include <security/pam_modules.h> #include "util/util.h" +#include "util/user_info_msg.h" #include "db/sysdb.h" #include "providers/ldap/ldap_common.h" #include "providers/ldap/sdap_async.h" @@ -809,8 +810,11 @@ static void sdap_pam_chpass_done(struct tevent_req *req) enum sdap_result result; int dp_err = DP_ERR_FATAL; int ret; + char *user_error_message = NULL; + size_t msg_len; + uint8_t *msg; - ret = sdap_exop_modify_passwd_recv(req, &result); + ret = sdap_exop_modify_passwd_recv(req, state, &result, &user_error_message); talloc_zfree(req); if (ret) { state->pd->pam_status = PAM_SYSTEM_ERR; @@ -824,6 +828,19 @@ static void sdap_pam_chpass_done(struct tevent_req *req) break; default: state->pd->pam_status = PAM_AUTHTOK_ERR; + if (user_error_message != NULL) { + ret = pack_user_info_chpass_error(state->pd, user_error_message, + &msg_len, &msg); + if (ret != EOK) { + DEBUG(1, ("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(1, ("pam_add_response failed.\n")); + } + } + } } done: diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c index 88f1c4be6..959c08a65 100644 --- a/server/providers/ldap/sdap_async.c +++ b/server/providers/ldap/sdap_async.c @@ -530,6 +530,7 @@ struct sdap_exop_modify_passwd_state { struct sdap_op *op; int result; + char *user_error_message; }; static void sdap_exop_modify_passwd_done(struct sdap_op *op, @@ -556,6 +557,7 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, if (!req) return NULL; state->sh = sh; + state->user_error_message = NULL; ber = ber_alloc_t( LBER_USE_DER ); if (ber == NULL) { @@ -626,7 +628,7 @@ static void sdap_exop_modify_passwd_done(struct sdap_op *op, struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); struct sdap_exop_modify_passwd_state *state = tevent_req_data(req, struct sdap_exop_modify_passwd_state); - char *errmsg; + char *errmsg = NULL; int ret; LDAPControl **response_controls = NULL; int c; @@ -673,12 +675,20 @@ static void sdap_exop_modify_passwd_done(struct sdap_op *op, } } + if (state->result != LDAP_SUCCESS) { + state->user_error_message = talloc_strdup(state, errmsg); + if (state->user_error_message == NULL) { + DEBUG(1, ("talloc_strdup failed.\n")); + } + } + DEBUG(3, ("ldap_extended_operation result: %s(%d), %s\n", ldap_err2string(state->result), state->result, errmsg)); ret = LDAP_SUCCESS; done: ldap_controls_free(response_controls); + ldap_memfree(errmsg); if (ret == LDAP_SUCCESS) { tevent_req_done(req); @@ -688,12 +698,15 @@ done: } int sdap_exop_modify_passwd_recv(struct tevent_req *req, - enum sdap_result *result) + TALLOC_CTX * mem_ctx, + enum sdap_result *result, + char **user_error_message) { struct sdap_exop_modify_passwd_state *state = tevent_req_data(req, struct sdap_exop_modify_passwd_state); *result = SDAP_ERROR; + *user_error_message = talloc_steal(mem_ctx, state->user_error_message); TEVENT_REQ_RETURN_ON_ERROR(req); diff --git a/server/providers/ldap/sdap_async.h b/server/providers/ldap/sdap_async.h index e18fb69a2..3c52d236b 100644 --- a/server/providers/ldap/sdap_async.h +++ b/server/providers/ldap/sdap_async.h @@ -94,8 +94,9 @@ struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, char *user_dn, char *password, char *new_password); -int sdap_exop_modify_passwd_recv(struct tevent_req *req, - enum sdap_result *result); +int sdap_exop_modify_passwd_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + enum sdap_result *result, + char **user_error_msg); struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx, struct tevent_context *ev, diff --git a/server/util/user_info_msg.c b/server/util/user_info_msg.c new file mode 100644 index 000000000..1886537a4 --- /dev/null +++ b/server/util/user_info_msg.c @@ -0,0 +1,51 @@ +/* + SSSD + + Pack user info messages + + Authors: + Sumit Bose <sbose@redhat.com> + + Copyright (C) 2009 Red Hat + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "util/util.h" +#include "../sss_client/sss_cli.h" + +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; + + 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(1, ("talloc_size failed.\n")); + return ENOMEM; + } + + memcpy(resp, &resp_type, sizeof(uint32_t)); + memcpy(resp + sizeof(uint32_t), &err_len, sizeof(uint32_t)); + memcpy(resp + 2 * sizeof(uint32_t), user_error_message, err_len); + + *_resp = resp; + return EOK; +} diff --git a/server/util/user_info_msg.h b/server/util/user_info_msg.h new file mode 100644 index 000000000..c68d538c2 --- /dev/null +++ b/server/util/user_info_msg.h @@ -0,0 +1,33 @@ +/* + SSSD + + Pack user info messages + + Authors: + Sumit Bose <sbose@redhat.com> + + Copyright (C) 2009 Red Hat + + 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 <http://www.gnu.org/licenses/>. +*/ +#ifndef __USER_INFO_MSG_H__ +#define __USER_INFO_MSG_H__ + + +errno_t pack_user_info_chpass_error(TALLOC_CTX *mem_ctx, + const char *user_error_message, + size_t *len, + uint8_t **_resp); + +#endif /* __USER_INFO_MSG_H__ */ diff --git a/sss_client/pam_sss.c b/sss_client/pam_sss.c index 8c970e489..8a1e3129a 100644 --- a/sss_client/pam_sss.c +++ b/sss_client/pam_sss.c @@ -496,6 +496,45 @@ static int user_info_offline_chpass(pam_handle_t *pamh, size_t buflen, return PAM_SUCCESS; } +static int user_info_chpass_error(pam_handle_t *pamh, size_t buflen, + uint8_t *buf) +{ + int ret; + uint32_t msg_len; + char user_msg[256]; + + if (buflen < 2* sizeof(uint32_t)) { + D(("User info response data is too short")); + return PAM_BUF_ERR; + } + + 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; + } + + ret = snprintf(user_msg, sizeof(user_msg), "%s%s%.*s", + _("Password change failed. "), + msg_len > 0 ? _("Server message: ") : "", + msg_len, + msg_len > 0 ? (char *)(buf + 2 * sizeof(uint32_t)) : "" ); + if (ret < 0 || ret >= sizeof(user_msg)) { + D(("snprintf failed.")); + return PAM_SYSTEM_ERR; + } + + ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL); + if (ret != PAM_SUCCESS) { + D(("do_pam_conversation failed.")); + return PAM_SYSTEM_ERR; + } + + return PAM_SUCCESS; +} + + static int eval_user_info_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf) { @@ -519,6 +558,9 @@ static int eval_user_info_response(pam_handle_t *pamh, size_t buflen, case SSS_PAM_USER_INFO_OFFLINE_CHPASS: ret = user_info_offline_chpass(pamh, buflen, buf); break; + case SSS_PAM_USER_INFO_CHPASS_ERROR: + ret = user_info_chpass_error(pamh, buflen, buf); + break; default: D(("Unknown user info type [%d]", type)); ret = PAM_SYSTEM_ERR; diff --git a/sss_client/sss_cli.h b/sss_client/sss_cli.h index 55d5a2825..7e9a81ff3 100644 --- a/sss_client/sss_cli.h +++ b/sss_client/sss_cli.h @@ -180,7 +180,8 @@ enum response_type { enum user_info_type { SSS_PAM_USER_INFO_OFFLINE_AUTH = 0x01, SSS_PAM_USER_INFO_OFFLINE_AUTH_DELAYED, - SSS_PAM_USER_INFO_OFFLINE_CHPASS + SSS_PAM_USER_INFO_OFFLINE_CHPASS, + SSS_PAM_USER_INFO_CHPASS_ERROR }; enum nss_status sss_nss_make_request(enum sss_cli_command cmd, |