[SSSD] [PATCH] Handle Krb5 password expiration warning
Sumit Bose
sbose at redhat.com
Thu Apr 29 11:27:57 UTC 2010
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
> From cbf80a5f3aa12917c6c05dc264916564caf40068 Mon Sep 17 00:00:00 2001
> From: Sumit Bose <sbose at 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 | 91 -----------------------------
> src/providers/dp_pam_data_util.c | 116 ++++++++++++++++++++++++++++++++++++++
> 3 files changed, 118 insertions(+), 91 deletions(-)
> create mode 100644 src/providers/dp_pam_data_util.c
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index ead53f9..637a4f3 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 \
> @@ -824,6 +825,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 d0ce190..e09a692 100644
> --- a/src/providers/dp_auth_util.c
> +++ b/src/providers/dp_auth_util.c
> @@ -21,97 +21,6 @@
>
> #include "data_provider.h"
>
> -#define PD_STR_COPY(el) do { \
> - if (old_pd->el != NULL) { \
> - pd->el = talloc_strdup(pd, old_pd->el); \
> - if (pd->el == NULL) { \
> - DEBUG(1, ("talloc_strdup failed.\n")); \
> - goto failed; \
> - } \
> - } \
> -} while(0);
> -
> -#define PD_MEM_COPY(el, size) do { \
> - if (old_pd->el != NULL) { \
> - pd->el = talloc_memdup(pd, old_pd->el, (size)); \
> - if (pd->el == NULL) { \
> - DEBUG(1, ("talloc_memdup failed.\n")); \
> - goto failed; \
> - } \
> - } \
> -} while(0);
> -
> -errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *old_pd,
> - struct pam_data **new_pd)
> -{
> - struct pam_data *pd = NULL;
> -
> - pd = talloc_zero(mem_ctx, struct pam_data);
> - if (pd == NULL) {
> - DEBUG(1, ("talloc_zero failed.\n"));
> - return ENOMEM;
> - }
> -
> - pd->cmd = old_pd->cmd;
> - pd->authtok_type = old_pd->authtok_type;
> - pd->authtok_size = old_pd->authtok_size;
> - pd->newauthtok_type = old_pd->newauthtok_type;
> - pd->newauthtok_size = old_pd->newauthtok_size;
> -
> - PD_STR_COPY(domain);
> - PD_STR_COPY(user);
> - PD_STR_COPY(service);
> - PD_STR_COPY(tty);
> - PD_STR_COPY(ruser);
> - PD_STR_COPY(rhost);
> - PD_MEM_COPY(authtok, old_pd->authtok_size);
> - PD_MEM_COPY(newauthtok, old_pd->newauthtok_size);
> - pd->cli_pid = old_pd->cli_pid;
> -
> - *new_pd = pd;
> -
> - return EOK;
> -
> -failed:
> - talloc_free(pd);
> - return ENOMEM;
> -}
> -
> -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..f551a48
> --- /dev/null
> +++ b/src/providers/dp_pam_data_util.c
> @@ -0,0 +1,116 @@
> +/*
> + SSSD
> +
> + Utilities to for tha pam_data structure
> +
> + Authors:
> + Sumit Bose <sbose at 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"
> +
> +#define PD_STR_COPY(el) do { \
> + if (old_pd->el != NULL) { \
> + pd->el = talloc_strdup(pd, old_pd->el); \
> + if (pd->el == NULL) { \
> + DEBUG(1, ("talloc_strdup failed.\n")); \
> + goto failed; \
> + } \
> + } \
> +} while(0);
> +
> +#define PD_MEM_COPY(el, size) do { \
> + if (old_pd->el != NULL) { \
> + pd->el = talloc_memdup(pd, old_pd->el, (size)); \
> + if (pd->el == NULL) { \
> + DEBUG(1, ("talloc_memdup failed.\n")); \
> + goto failed; \
> + } \
> + } \
> +} while(0);
> +
> +errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *old_pd,
> + struct pam_data **new_pd)
> +{
> + struct pam_data *pd = NULL;
> +
> + pd = talloc_zero(mem_ctx, struct pam_data);
> + if (pd == NULL) {
> + DEBUG(1, ("talloc_zero failed.\n"));
> + return ENOMEM;
> + }
> +
> + pd->cmd = old_pd->cmd;
> + pd->authtok_type = old_pd->authtok_type;
> + pd->authtok_size = old_pd->authtok_size;
> + pd->newauthtok_type = old_pd->newauthtok_type;
> + pd->newauthtok_size = old_pd->newauthtok_size;
> +
> + PD_STR_COPY(domain);
> + PD_STR_COPY(user);
> + PD_STR_COPY(service);
> + PD_STR_COPY(tty);
> + PD_STR_COPY(ruser);
> + PD_STR_COPY(rhost);
> + PD_MEM_COPY(authtok, old_pd->authtok_size);
> + PD_MEM_COPY(newauthtok, old_pd->newauthtok_size);
> + pd->cli_pid = old_pd->cli_pid;
> +
> + *new_pd = pd;
> +
> + return EOK;
> +
> +failed:
> + talloc_free(pd);
> + return ENOMEM;
> +}
> +
> +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 37faca0409579e20f0744730d1be8f1a105b523d Mon Sep 17 00:00:00 2001
> From: Sumit Bose <sbose at 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 | 163 +++++++++++---------------------------
> src/providers/krb5/krb5_child.c | 167 ++++++++++++++++++++++++++-------------
> src/sss_client/pam_sss.c | 14 +++-
> src/sss_client/sss_cli.h | 6 +-
> 4 files changed, 176 insertions(+), 174 deletions(-)
>
> diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
> index 3b36b93..cca0132 100644
> --- a/src/providers/krb5/krb5_auth.c
> +++ b/src/providers/krb5/krb5_auth.c
> @@ -6,7 +6,7 @@
> Authors:
> Sumit Bose <sbose at 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)
> {
> @@ -1116,11 +1048,11 @@ static void krb5_child_done(struct tevent_req *subreq)
> int ret;
> 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;
> + ssize_t pref_len = sizeof(CCACHE_ENV_NAME);
> + 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);
> @@ -1137,71 +1069,76 @@ static void krb5_child_done(struct tevent_req *subreq)
> return;
> }
>
> - if ((size_t) len < 3*sizeof(int32_t)) {
> + 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);
> + SAFEALIGN_COPY_INT32(&msg_status, buf+p, &p);
>
> - msg_type = ((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);
>
> - msg_len = ((int32_t *)(buf+p));
> - p += sizeof(int32_t);
> + DEBUG(9, ("child response [%d][%d][%d].\n", msg_status, msg_type,
> + msg_len));
>
> - DEBUG(4, ("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;
> + 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 (msg_status != PAM_SUCCESS && msg_status != PAM_AUTHINFO_UNAVAIL) {
> + 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 (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]));
> + if (kr->ccname == NULL) {
> + DEBUG(1, ("Missing ccache name in child response.\n"));
> ret = EINVAL;
> goto done;
> }
>
> - if (*msg_status == PAM_AUTHINFO_UNAVAIL) {
> + if (msg_status == PAM_AUTHINFO_UNAVAIL) {
> if (kr->srv != NULL) {
> fo_set_port_status(kr->srv, PORT_NOT_WORKING);
> }
> @@ -1212,7 +1149,7 @@ static void krb5_child_done(struct tevent_req *subreq)
> }
>
> if (kr->kpasswd_srv != NULL) {
> - if (*msg_status == PAM_AUTHTOK_LOCK_BUSY) {
> + 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);
> @@ -1255,14 +1192,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..ac5fd75 100644
> --- a/src/providers/krb5/krb5_child.c
> +++ b/src/providers/krb5/krb5_child.c
> @@ -6,7 +6,7 @@
> Authors:
> Sumit Bose <sbose at 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,39 @@ 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;
> +
> + size = sizeof(int32_t);
>
> - resp->buf = talloc_array(resp, uint8_t,
> - 3*sizeof(int32_t) + len);
> + 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 +318,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 +333,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 +347,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 +377,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 +507,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 +559,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 +571,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 +646,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 +679,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 +710,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 +741,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 +760,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 +926,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 31a3de8..8d6953b 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 at lists.fedorahosted.org
> https://fedorahosted.org/mailman/listinfo/sssd-devel
-------------- next part --------------
From a19ac991d1dd2622058fddcf8923083d6a341aa1 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at 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 92244f4..a991a35 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 \
@@ -822,6 +823,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 <sbose at 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
-------------- next part --------------
From b2f3017a6d69496e023f06500544380c454f42d4 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at 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 | 163 +++++++++++---------------------------
src/providers/krb5/krb5_child.c | 167 ++++++++++++++++++++++++++-------------
src/sss_client/pam_sss.c | 14 +++-
src/sss_client/sss_cli.h | 6 +-
4 files changed, 176 insertions(+), 174 deletions(-)
diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c
index 0c08fe1..6bf50a7 100644
--- a/src/providers/krb5/krb5_auth.c
+++ b/src/providers/krb5/krb5_auth.c
@@ -6,7 +6,7 @@
Authors:
Sumit Bose <sbose at 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)
{
@@ -1103,11 +1035,11 @@ static void krb5_child_done(struct tevent_req *subreq)
int ret;
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;
+ ssize_t pref_len = sizeof(CCACHE_ENV_NAME);
+ 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,76 @@ static void krb5_child_done(struct tevent_req *subreq)
return;
}
- if ((size_t) len < 3*sizeof(int32_t)) {
+ 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);
+ SAFEALIGN_COPY_INT32(&msg_status, buf+p, &p);
- msg_type = ((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);
- msg_len = ((int32_t *)(buf+p));
- p += sizeof(int32_t);
+ DEBUG(9, ("child response [%d][%d][%d].\n", msg_status, msg_type,
+ msg_len));
- DEBUG(4, ("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;
+ 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 (msg_status != PAM_SUCCESS && msg_status != PAM_AUTHINFO_UNAVAIL) {
+ 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 (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]));
+ if (kr->ccname == NULL) {
+ DEBUG(1, ("Missing ccache name in child response.\n"));
ret = EINVAL;
goto done;
}
- if (*msg_status == PAM_AUTHINFO_UNAVAIL) {
+ if (msg_status == PAM_AUTHINFO_UNAVAIL) {
if (kr->srv != NULL) {
fo_set_port_status(kr->srv, PORT_NOT_WORKING);
}
@@ -1199,7 +1136,7 @@ static void krb5_child_done(struct tevent_req *subreq)
}
if (kr->kpasswd_srv != NULL) {
- if (*msg_status == PAM_AUTHTOK_LOCK_BUSY) {
+ 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 +1179,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..ac5fd75 100644
--- a/src/providers/krb5/krb5_child.c
+++ b/src/providers/krb5/krb5_child.c
@@ -6,7 +6,7 @@
Authors:
Sumit Bose <sbose at 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,39 @@ 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;
+
+ size = sizeof(int32_t);
- resp->buf = talloc_array(resp, uint8_t,
- 3*sizeof(int32_t) + len);
+ 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 +318,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 +333,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 +347,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 +377,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 +507,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 +559,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 +571,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 +646,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 +679,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 +710,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 +741,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 +760,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 +926,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
More information about the sssd-devel
mailing list