On Fri, Apr 30, 2010 at 10:18:39AM -0400, Stephen Gallagher wrote: > On 04/29/2010 07:27 AM, Sumit Bose wrote: > > Sorry, the first patch had dependencies to another patch, new version > > attached. > > > > bye, > > Sumit > > On Tue, Apr 27, 2010 at 02:08:02PM +0200, Sumit Bose wrote: > >> Hi, > >> > >> this two patches add the support to display a warning to the user that > >> the Kerberos password is about to expire. The first patch just moves > >> some utility functions to a separate file to avoid linking the > >> krb5_child against libdbus. > >> > >> I the second patch a prompter function is introduced to catch the > >> warning message which is generated by libkrb5. With the current API of > >> MIT Kerberos we have to rely on this message, because the the underlying > >> AS_REPLY data is not exposed by the library. As a consequece this message > >> cannot be translated, but this is true for messages which are generated > >> to indicate why a password change failed, too. The rest of the patch > >> changes the way the response from the child is packed and unpacked to > >> allow more than one response message. > >> > >> bye, > >> Sumit > > > > > Patch 0001: Ack > > Patch 0002: The krb5_child_done() function is in desperate need of > comments. At minimum, there needs to be a comment describing the format > of the received buffer. Same for the pack_response_packet().
comments added > > This is wrong: > if (msg_len > pref_len && > strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", > pref_len) == 0) { > > pref_len needs to be another byte longer to account for the '='. Also, a > comment here would be fantastic. pref_len is already a bye longer, because I used sizeof instead of strlen. I added a comment about this, too. New version attached. bye, Sumit > > Otherwise this looks fine. > > > -- > Stephen Gallagher > RHCE 804006346421761 > > Delivering value year after year. > Red Hat ranks #1 in value among software vendors. > http://www.redhat.com/promo/vendor/ > _______________________________________________ > sssd-devel mailing list > sssd-devel@lists.fedorahosted.org > https://fedorahosted.org/mailman/listinfo/sssd-devel
From 7a1ecb87fe5b65bfbce19afcce2f8e1551f4b0a1 Mon Sep 17 00:00:00 2001 From: Sumit Bose <sb...@redhat.com> Date: Fri, 23 Apr 2010 15:21:38 +0200 Subject: [PATCH 1/2] Split pam_data utilities into a separate file --- src/Makefile.am | 2 + src/providers/dp_auth_util.c | 35 ---------------------- src/providers/dp_pam_data_util.c | 60 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 35 deletions(-) create mode 100644 src/providers/dp_pam_data_util.c diff --git a/src/Makefile.am b/src/Makefile.am index 22ac358..5fb4062 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -221,6 +221,7 @@ SSSD_UTIL_OBJ = \ db/sysdb_search.c \ monitor/monitor_sbus.c \ providers/dp_auth_util.c \ + providers/dp_pam_data_util.c \ providers/dp_sbus.c \ sbus/sbus_client.c \ sbus/sssd_dbus_common.c \ @@ -825,6 +826,7 @@ krb5_child_SOURCES = \ providers/krb5/krb5_become_user.c \ providers/krb5/krb5_child.c \ providers/child_common.c \ + providers/dp_pam_data_util.c \ util/user_info_msg.c \ util/sss_krb5.c krb5_child_CFLAGS = \ diff --git a/src/providers/dp_auth_util.c b/src/providers/dp_auth_util.c index fb10ced..e09a692 100644 --- a/src/providers/dp_auth_util.c +++ b/src/providers/dp_auth_util.c @@ -21,41 +21,6 @@ #include "data_provider.h" -void pam_print_data(int l, struct pam_data *pd) -{ - DEBUG(l, ("command: %d\n", pd->cmd)); - DEBUG(l, ("domain: %s\n", pd->domain)); - DEBUG(l, ("user: %s\n", pd->user)); - DEBUG(l, ("service: %s\n", pd->service)); - DEBUG(l, ("tty: %s\n", pd->tty)); - DEBUG(l, ("ruser: %s\n", pd->ruser)); - DEBUG(l, ("rhost: %s\n", pd->rhost)); - DEBUG(l, ("authtok type: %d\n", pd->authtok_type)); - DEBUG(l, ("authtok size: %d\n", pd->authtok_size)); - DEBUG(l, ("newauthtok type: %d\n", pd->newauthtok_type)); - DEBUG(l, ("newauthtok size: %d\n", pd->newauthtok_size)); - DEBUG(l, ("priv: %d\n", pd->priv)); - DEBUG(l, ("cli_pid: %d\n", pd->cli_pid)); -} - -int pam_add_response(struct pam_data *pd, enum response_type type, - int len, const uint8_t *data) -{ - struct response_data *new; - - new = talloc(pd, struct response_data); - if (new == NULL) return ENOMEM; - - new->type = type; - new->len = len; - new->data = talloc_memdup(pd, data, len); - if (new->data == NULL) return ENOMEM; - new->next = pd->resp_list; - pd->resp_list = new; - - return EOK; -} - bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd) { int ret; diff --git a/src/providers/dp_pam_data_util.c b/src/providers/dp_pam_data_util.c new file mode 100644 index 0000000..308bd7c --- /dev/null +++ b/src/providers/dp_pam_data_util.c @@ -0,0 +1,60 @@ +/* + SSSD + + Utilities to for tha pam_data structure + + Authors: + Sumit Bose <sb...@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 "providers/data_provider.h" + +void pam_print_data(int l, struct pam_data *pd) +{ + DEBUG(l, ("command: %d\n", pd->cmd)); + DEBUG(l, ("domain: %s\n", pd->domain)); + DEBUG(l, ("user: %s\n", pd->user)); + DEBUG(l, ("service: %s\n", pd->service)); + DEBUG(l, ("tty: %s\n", pd->tty)); + DEBUG(l, ("ruser: %s\n", pd->ruser)); + DEBUG(l, ("rhost: %s\n", pd->rhost)); + DEBUG(l, ("authtok type: %d\n", pd->authtok_type)); + DEBUG(l, ("authtok size: %d\n", pd->authtok_size)); + DEBUG(l, ("newauthtok type: %d\n", pd->newauthtok_type)); + DEBUG(l, ("newauthtok size: %d\n", pd->newauthtok_size)); + DEBUG(l, ("priv: %d\n", pd->priv)); + DEBUG(l, ("cli_pid: %d\n", pd->cli_pid)); +} + +int pam_add_response(struct pam_data *pd, enum response_type type, + int len, const uint8_t *data) +{ + struct response_data *new; + + new = talloc(pd, struct response_data); + if (new == NULL) return ENOMEM; + + new->type = type; + new->len = len; + new->data = talloc_memdup(pd, data, len); + if (new->data == NULL) return ENOMEM; + new->next = pd->resp_list; + pd->resp_list = new; + + return EOK; +} -- 1.6.6.1
From 422d4c28318ae3896bbcc729a75d7652d86a44a5 Mon Sep 17 00:00:00 2001 From: Sumit Bose <sb...@redhat.com> Date: Fri, 23 Apr 2010 13:37:22 +0200 Subject: [PATCH 2/2] Handle Krb5 password expiration warning --- src/providers/krb5/krb5_auth.c | 190 +++++++++++++++------------------------ src/providers/krb5/krb5_child.c | 177 +++++++++++++++++++++++++----------- src/sss_client/pam_sss.c | 14 +++- src/sss_client/sss_cli.h | 6 +- 4 files changed, 214 insertions(+), 173 deletions(-) diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index 0c08fe1..9e9eb13 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -6,7 +6,7 @@ Authors: Sumit Bose <sb...@redhat.com> - Copyright (C) 2009 Red Hat + Copyright (C) 2009-2010 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 @@ -45,74 +45,6 @@ #define KRB5_CHILD SSSD_LIBEXEC_PATH"/krb5_child" #endif -static errno_t add_krb5_env(struct dp_option *opts, const char *ccname, - struct pam_data *pd) -{ - int ret; - const char *dummy; - char *env; - TALLOC_CTX *tmp_ctx = NULL; - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(1, ("talloc_new failed.\n")); - return ENOMEM; - } - - if (ccname != NULL) { - env = talloc_asprintf(tmp_ctx, "%s=%s",CCACHE_ENV_NAME, ccname); - if (env == NULL) { - DEBUG(1, ("talloc_asprintf failed.\n")); - ret = ENOMEM; - goto done; - } - ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(env)+1, - (uint8_t *) env); - if (ret != EOK) { - DEBUG(1, ("pam_add_response failed.\n")); - goto done; - } - } - - dummy = dp_opt_get_cstring(opts, KRB5_REALM); - if (dummy != NULL) { - env = talloc_asprintf(tmp_ctx, "%s=%s", SSSD_KRB5_REALM, dummy); - if (env == NULL) { - DEBUG(1, ("talloc_asprintf failed.\n")); - ret = ENOMEM; - goto done; - } - ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(env)+1, - (uint8_t *) env); - if (ret != EOK) { - DEBUG(1, ("pam_add_response failed.\n")); - goto done; - } - } - - dummy = dp_opt_get_cstring(opts, KRB5_KDC); - if (dummy != NULL) { - env = talloc_asprintf(tmp_ctx, "%s=%s", SSSD_KRB5_KDC, dummy); - if (env == NULL) { - DEBUG(1, ("talloc_asprintf failed.\n")); - ret = ENOMEM; - goto done; - } - ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(env)+1, - (uint8_t *) env); - if (ret != EOK) { - DEBUG(1, ("pam_add_response failed.\n")); - goto done; - } - } - - ret = EOK; - -done: - talloc_free(tmp_ctx); - return ret; -} - static errno_t check_if_ccache_file_is_used(uid_t uid, const char *ccname, bool *result) { @@ -1104,10 +1036,10 @@ static void krb5_child_done(struct tevent_req *subreq) uint8_t *buf = NULL; ssize_t len = -1; ssize_t pref_len; - int p; - int32_t *msg_status; - int32_t *msg_type; - int32_t *msg_len; + size_t p; + int32_t msg_status; + int32_t msg_type; + int32_t msg_len; ret = handle_child_recv(subreq, pd, &buf, &len); talloc_zfree(kr->timeout_handler); @@ -1124,71 +1056,104 @@ static void krb5_child_done(struct tevent_req *subreq) return; } - if ((size_t) len < 3*sizeof(int32_t)) { + /* A buffer with the following structure is expected. + * int32_t status of the request (required) + * message (zero or more) + * + * A message consists of: + * int32_t type of the message + * int32_t length of the following data + * uint8_t[len] data + */ + + if ((size_t) len < sizeof(int32_t)) { DEBUG(1, ("message too short.\n")); ret = EINVAL; goto done; } p=0; - msg_status = ((int32_t *)(buf+p)); - p += sizeof(int32_t); - - msg_type = ((int32_t *)(buf+p)); - p += sizeof(int32_t); + SAFEALIGN_COPY_INT32(&msg_status, buf+p, &p); - msg_len = ((int32_t *)(buf+p)); - p += sizeof(int32_t); + while (p < len) { + SAFEALIGN_COPY_INT32(&msg_type, buf+p, &p); + SAFEALIGN_COPY_INT32(&msg_len, buf+p, &p); - DEBUG(4, ("child response [%d][%d][%d].\n", *msg_status, *msg_type, - *msg_len)); + DEBUG(9, ("child response [%d][%d][%d].\n", msg_status, msg_type, + msg_len)); - if ((p + *msg_len) != len) { - DEBUG(1, ("message format error [%d] != [%d].\n", p+*msg_len, len)); - goto done; - } + if ((p + msg_len) > len) { + DEBUG(1, ("message format error [%d] > [%d].\n", p+msg_len, len)); + ret = EINVAL; + goto done; + } - if (*msg_status != PAM_SUCCESS && *msg_status != PAM_AUTHINFO_UNAVAIL) { - state->pam_status = *msg_status; - state->dp_err = DP_ERR_OK; + /* We need to save the name of the credential cache file. To find it + * we check if the data part of a message starts with + * CCACHE_ENV_NAME"=". pref_len also counts the trailing '=' because + * sizeof() counts the trailing '\0' of a string. */ + pref_len = sizeof(CCACHE_ENV_NAME); + if (msg_len > pref_len && + strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", pref_len) == 0) { + kr->ccname = talloc_strndup(kr, (char *) &buf[p+pref_len], + msg_len-pref_len); + if (kr->ccname == NULL) { + DEBUG(1, ("talloc_strndup failed.\n")); + ret = ENOMEM; + goto done; + } + } - ret = pam_add_response(pd, *msg_type, *msg_len, &buf[p]); + ret = pam_add_response(pd, msg_type, msg_len, &buf[p]); if (ret != EOK) { /* This is not a fatal error */ DEBUG(1, ("pam_add_response failed.\n")); } + p += msg_len; + + if ((p < len) && (p + 2*sizeof(int32_t) >= len)) { + DEBUG(1, ("The remainder of the message is too short.\n")); + ret = EINVAL; + goto done; + } + } + /* If the child request failed, but did not return an offline error code, + * return with the status */ + if (msg_status != PAM_SUCCESS && msg_status != PAM_AUTHINFO_UNAVAIL && + msg_status != PAM_AUTHTOK_LOCK_BUSY) { + state->pam_status = msg_status; + state->dp_err = DP_ERR_OK; ret = EOK; goto done; } else { - state->pam_status = *msg_status; + state->pam_status = msg_status; } - if (*msg_status == PAM_SUCCESS && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { + /* If the child request was successful and we run the first pass of the + * change password request just return success. */ + if (msg_status == PAM_SUCCESS && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { state->pam_status = PAM_SUCCESS; state->dp_err = DP_ERR_OK; ret = EOK; goto done; } - pref_len = strlen(CCACHE_ENV_NAME)+1; - if (*msg_len > pref_len && - strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", pref_len) == 0) { - kr->ccname = talloc_strndup(kr, (char *) &buf[p+pref_len], - *msg_len-pref_len); - if (kr->ccname == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - ret = ENOMEM; - goto done; - } - } else { - DEBUG(1, ("Missing ccache name in child response [%.*s].\n", *msg_len, - &buf[p])); + /* The following cases are left now: + * - offline (msg_status == PAM_AUTHINFO_UNAVAIL or + * msg_status == PAM_AUTHTOK_LOCK_BUSY) + * - successful authentication or password change + * + * For all these cases we expect that one of the messages for the + * received buffer contains the name of the credential cache file. */ + if (kr->ccname == NULL) { + DEBUG(1, ("Missing ccache name in child response.\n")); ret = EINVAL; goto done; } - if (*msg_status == PAM_AUTHINFO_UNAVAIL) { + /* KDC is not reachable */ + if (msg_status == PAM_AUTHINFO_UNAVAIL) { if (kr->srv != NULL) { fo_set_port_status(kr->srv, PORT_NOT_WORKING); } @@ -1199,7 +1164,8 @@ static void krb5_child_done(struct tevent_req *subreq) } if (kr->kpasswd_srv != NULL) { - if (*msg_status == PAM_AUTHTOK_LOCK_BUSY) { + /* kpasswd is not reachable */ + if (msg_status == PAM_AUTHTOK_LOCK_BUSY) { fo_set_port_status(kr->kpasswd_srv, PORT_NOT_WORKING); } else { fo_set_port_status(kr->kpasswd_srv, PORT_WORKING); @@ -1242,14 +1208,6 @@ static void krb5_save_ccname_done(struct tevent_req *subreq) int ret; char *password = NULL; - if (pd->cmd == SSS_PAM_AUTHENTICATE || pd->cmd == SSS_PAM_CHAUTHTOK) { - ret = add_krb5_env(krb5_ctx->opts, kr->ccname, pd); - if (ret != EOK) { - DEBUG(1, ("add_krb5_env failed.\n")); - goto done; - } - } - ret = sysdb_set_user_attr_recv(subreq); talloc_zfree(subreq); if (ret != EOK) { diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index 620e4d1..7249aeb 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -6,7 +6,7 @@ Authors: Sumit Bose <sb...@redhat.com> - Copyright (C) 2009 Red Hat + Copyright (C) 2009-2010 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 @@ -103,6 +103,36 @@ static const char *__krb5_error_msg; sss_krb5_free_error_message(krb5_error_ctx, __krb5_error_msg); \ } while(0); + +static krb5_error_code sss_krb5_prompter(krb5_context context, void *data, + const char *name, const char *banner, + int num_prompts, krb5_prompt prompts[]) +{ + int ret; + struct krb5_req *kr = talloc_get_type(data, struct krb5_req); + + if (num_prompts != 0) { + DEBUG(1, ("Cannot handle password prompts.\n")); + return KRB5_LIBOS_CANTREADPWD; + } + + if (banner == NULL || *banner == '\0') { + DEBUG(5, ("Prompter called with empty banner, nothing to do.\n")); + return EOK; + } + + DEBUG(9, ("Prompter called with [%s].\n", banner)); + + ret = pam_add_response(kr->pd, SSS_PAM_TEXT_MSG, strlen(banner)+1, + (const uint8_t *) banner); + if (ret != EOK) { + DEBUG(1, ("pam_add_response failed.\n")); + } + + return EOK; +} + + static krb5_error_code create_empty_cred(struct krb5_req *kr, krb5_creds **_cred) { krb5_error_code kerr; @@ -247,22 +277,49 @@ done: return kerr; } -static errno_t pack_response_packet(struct response *resp, int status, int type, - size_t len, const uint8_t *data) +static errno_t pack_response_packet(struct response *resp, int status, + struct pam_data *pd) { + size_t size = 0; size_t p = 0; + struct response_data *pdr; + + /* A buffer with the following structure must be created: + * int32_t status of the request (required) + * message (zero or more) + * + * A message consists of: + * int32_t type of the message + * int32_t length of the following data + * uint8_t[len] data + */ - resp->buf = talloc_array(resp, uint8_t, - 3*sizeof(int32_t) + len); + size = sizeof(int32_t); + + pdr = pd->resp_list; + while (pdr != NULL) { + size += 2*sizeof(int32_t) + pdr->len; + pdr = pdr->next; + } + + + resp->buf = talloc_array(resp, uint8_t, size); if (!resp->buf) { DEBUG(1, ("Insufficient memory to create message.\n")); return ENOMEM; } SAFEALIGN_SET_INT32(&resp->buf[p], status, &p); - SAFEALIGN_SET_INT32(&resp->buf[p], type, &p); - SAFEALIGN_SET_INT32(&resp->buf[p], len, &p); - safealign_memcpy(&resp->buf[p], data, len, &p); + + pdr = pd->resp_list; + while(pdr != NULL) { + SAFEALIGN_SET_INT32(&resp->buf[p], pdr->type, &p); + SAFEALIGN_SET_INT32(&resp->buf[p], pdr->len, &p); + safealign_memcpy(&resp->buf[p], pdr->data, pdr->len, &p); + + pdr = pdr->next; + } + resp->size = p; @@ -271,15 +328,12 @@ 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, - 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 = talloc_zero(kr, struct response); if (resp == NULL) { @@ -289,9 +343,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, - strlen("success") + 1, - (const uint8_t *) "success"); + pam_status = PAM_SUCCESS; + ret = EOK; } else { if (kr->ccname == NULL) { DEBUG(1, ("Error obtaining ccname.\n")); @@ -304,44 +357,28 @@ static struct response *prepare_response_message(struct krb5_req *kr, return NULL; } - ret = pack_response_packet(resp, PAM_SUCCESS, SSS_PAM_ENV_ITEM, - strlen(msg) + 1, (uint8_t *) msg); + pam_status = PAM_SUCCESS; + ret = pam_add_response(kr->pd, SSS_PAM_ENV_ITEM, strlen(msg) + 1, + (uint8_t *) msg); talloc_zfree(msg); } } else { - 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 { - + 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 = pam_add_response(kr->pd, SSS_PAM_SYSTEM_INFO, + strlen(krb5_msg) + 1, + (const uint8_t *) krb5_msg); + sss_krb5_free_error_message(krb5_error_ctx, krb5_msg); + } + if (ret != EOK) { + DEBUG(1, ("pam_add_response failed.\n")); } + ret = pack_response_packet(resp, pam_status, kr->pd); if (ret != EOK) { DEBUG(1, ("pack_response_packet failed.\n")); return NULL; @@ -350,15 +387,14 @@ static struct response *prepare_response_message(struct krb5_req *kr, return resp; } -static errno_t sendresponse(int fd, krb5_error_code kerr, - char *user_error_message, int pam_status, +static errno_t sendresponse(int fd, krb5_error_code kerr, int pam_status, struct krb5_req *kr) { struct response *resp; size_t written; int ret; - resp = prepare_response_message(kr, kerr, user_error_message, pam_status); + resp = prepare_response_message(kr, kerr, pam_status); if (resp == NULL) { DEBUG(1, ("prepare_response_message failed.\n")); return ENOMEM; @@ -481,8 +517,8 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, int ret; kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - password, NULL, NULL, 0, NULL, - kr->options); + password, sss_krb5_prompter, kr, 0, + NULL, kr->options); if (kerr != 0) { KRB5_DEBUG(1, kerr); return kerr; @@ -533,6 +569,9 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) 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 = sss_krb5_prompter; pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, kr->pd->authtok_size); @@ -542,8 +581,13 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) goto sendresponse; } + if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { + /* We do not need a password expiration warning here. */ + prompter = NULL; + } + kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, NULL, NULL, 0, + pass_str, prompter, kr, 0, kr->krb5_ctx->changepw_principle, kr->options); if (kerr != 0) { @@ -612,6 +656,20 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) } } + 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(1, ("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(1, ("pack_response_packet failed.\n")); + } + } + } + pam_status = PAM_AUTHTOK_ERR; goto sendresponse; } @@ -631,7 +689,7 @@ static errno_t changepw_child(int fd, struct krb5_req *kr) } sendresponse: - ret = sendresponse(fd, kerr, user_error_message, pam_status, kr); + ret = sendresponse(fd, kerr, pam_status, kr); if (ret != EOK) { DEBUG(1, ("sendresponse failed.\n")); } @@ -662,7 +720,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) So we validate the password by trying to get a changepw ticket. */ if (kerr == KRB5KDC_ERR_KEY_EXP) { kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, NULL, NULL, 0, + pass_str, sss_krb5_prompter, kr, 0, kr->krb5_ctx->changepw_principle, kr->options); krb5_free_cred_contents(kr->ctx, kr->creds); @@ -693,7 +751,7 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) } sendresponse: - ret = sendresponse(fd, kerr, NULL, pam_status, kr); + ret = sendresponse(fd, kerr, pam_status, kr); if (ret != EOK) { DEBUG(1, ("sendresponse failed.\n")); } @@ -712,7 +770,7 @@ static errno_t create_empty_ccache(int fd, struct krb5_req *kr) pam_status = PAM_SYSTEM_ERR; } - ret = sendresponse(fd, ret, NULL, pam_status, kr); + ret = sendresponse(fd, ret, pam_status, kr); if (ret != EOK) { DEBUG(1, ("sendresponse failed.\n")); } @@ -878,6 +936,15 @@ static int krb5_setup(struct krb5_req *kr, uint32_t offline) goto failed; } + /* A prompter is used to catch messages about when a password will + * expired. The library shall not use the prompter to ask for a new password + * but shall return KRB5KDC_ERR_KEY_EXP. */ + krb5_get_init_creds_opt_set_change_password_prompt(kr->options, 0); + if (kerr != 0) { + KRB5_DEBUG(1, kerr); + goto failed; + } + /* TODO: set options, e.g. * krb5_get_init_creds_opt_set_tkt_life * krb5_get_init_creds_opt_set_renew_life diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c index 8bd3c9e..d4e09da 100644 --- a/src/sss_client/pam_sss.c +++ b/src/sss_client/pam_sss.c @@ -888,7 +888,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, switch(type) { case SSS_PAM_SYSTEM_INFO: if (buf[p + (len -1)] != '\0') { - D(("user info does not end with \\0.")); + D(("system info does not end with \\0.")); break; } logger(pamh, LOG_INFO, "system info: [%s]", &buf[p]); @@ -940,6 +940,18 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf, D(("eval_user_info_response failed")); } break; + case SSS_PAM_TEXT_MSG: + if (buf[p + (len -1)] != '\0') { + D(("system info does not end with \\0.")); + break; + } + + ret = do_pam_conversation(pamh, PAM_TEXT_INFO, (char *) &buf[p], + NULL, NULL); + if (ret != PAM_SUCCESS) { + D(("do_pam_conversation failed.")); + } + break; default: D(("Unknown response type [%d]", type)); } diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h index f7e58fe..8712a6f 100644 --- a/src/sss_client/sss_cli.h +++ b/src/sss_client/sss_cli.h @@ -316,9 +316,13 @@ enum response_type { * @param String, zero terminated, of the form * name=value. See putenv(3) and pam_putenv(3) for * details. */ - SSS_PAM_USER_INFO /**< A message which should be displayed to the user. + SSS_PAM_USER_INFO, /**< A message which should be displayed to the user. * @param User info message, see #user_info_type * for details. */ + SSS_PAM_TEXT_MSG, /**< A plain text message which should be displayed to + * the user.This should only be used in the case where + * it is not possile to use SSS_PAM_USER_INFO. + * @param A zero terminated string. */ }; /** -- 1.6.6.1
_______________________________________________ sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://fedorahosted.org/mailman/listinfo/sssd-devel