summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSumit Bose <sbose@redhat.com>2010-02-11 13:15:52 +0100
committerStephen Gallagher <sgallagh@redhat.com>2010-02-12 08:44:11 -0500
commitfbcab705c90135080e09544616f1526c0e7ef90c (patch)
tree8868be756692302c757dafa08c21154dd873bb2a
parent152f9e939f91d94e6f30391182fd72d9267ec6e1 (diff)
downloadsssd-fbcab705c90135080e09544616f1526c0e7ef90c.tar.gz
sssd-fbcab705c90135080e09544616f1526c0e7ef90c.tar.xz
sssd-fbcab705c90135080e09544616f1526c0e7ef90c.zip
Make change password errors more transparent
-rw-r--r--server/Makefile.am4
-rw-r--r--server/providers/krb5/krb5_child.c78
-rw-r--r--server/providers/ldap/ldap_auth.c19
-rw-r--r--server/providers/ldap/sdap_async.c17
-rw-r--r--server/providers/ldap/sdap_async.h5
-rw-r--r--server/util/user_info_msg.c51
-rw-r--r--server/util/user_info_msg.h33
-rw-r--r--sss_client/pam_sss.c42
-rw-r--r--sss_client/sss_cli.h3
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,