diff options
author | Sumit Bose <sbose@redhat.com> | 2009-08-24 13:52:23 +0200 |
---|---|---|
committer | Simo Sorce <ssorce@redhat.com> | 2009-09-11 17:56:45 -0400 |
commit | a49645cbdd00abcc1170d5a60fed98c66c7d810b (patch) | |
tree | 7c28c7ca2e033e9e1eb7f88cee206d1238158a7d | |
parent | e4f831c3a990717babb7d31c2b6190bb7e2bf555 (diff) | |
download | sssd-a49645cbdd00abcc1170d5a60fed98c66c7d810b.tar.gz sssd-a49645cbdd00abcc1170d5a60fed98c66c7d810b.tar.bz2 sssd-a49645cbdd00abcc1170d5a60fed98c66c7d810b.zip |
add change password target to krb5 backend
-rw-r--r-- | server/Makefile.am | 2 | ||||
-rw-r--r-- | server/man/sssd-krb5.5.xml | 17 | ||||
-rw-r--r-- | server/providers/krb5/krb5_auth.c | 105 | ||||
-rw-r--r-- | server/providers/krb5/krb5_auth.h | 3 | ||||
-rw-r--r-- | server/providers/krb5/krb5_child.c | 363 | ||||
-rw-r--r-- | server/providers/krb5/tgt_req_child.c | 183 |
6 files changed, 464 insertions, 209 deletions
diff --git a/server/Makefile.am b/server/Makefile.am index 20df79e4..e475e255 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -404,7 +404,7 @@ libsss_proxy_la_LDFLAGS = \ libsss_krb5_la_SOURCES = \ providers/krb5/krb5_auth.c \ - providers/krb5/tgt_req_child.c + providers/krb5/krb5_child.c libsss_krb5_la_CFLAGS = \ $(AM_CFLAGS) \ $(KRB5_CFLAGS) diff --git a/server/man/sssd-krb5.5.xml b/server/man/sssd-krb5.5.xml index 3a22afcd..188cc913 100644 --- a/server/man/sssd-krb5.5.xml +++ b/server/man/sssd-krb5.5.xml @@ -37,7 +37,7 @@ <refsect1 id='file-format'> <title>CONFIGURATION OPTIONS</title> <para> - If the auth-module krb5 is used in a SSSD domain, the following + If the auth-module krb5 is used in a SSSD domain, the following options must be used. See the <citerefentry> <refentrytitle>sssd.conf</refentrytitle> @@ -76,6 +76,21 @@ </para> </listitem> </varlistentry> + + <varlistentry> + <term>krb5changepw_principle (string)</term> + <listitem> + <para> + The priciple of the change password service. + If only the 'identifier/instance' part of the + principle are given the realm part is added + automatically. + </para> + <para> + Default: kadmin/changepw + </para> + </listitem> + </varlistentry> </variablelist> </para> </refsect1> diff --git a/server/providers/krb5/krb5_auth.c b/server/providers/krb5/krb5_auth.c index b1fe47a1..b9574660 100644 --- a/server/providers/krb5/krb5_auth.c +++ b/server/providers/krb5/krb5_auth.c @@ -102,6 +102,19 @@ static int krb5_setup(struct be_req *req, const char *user_princ_str, kr->req = req; kr->krb5_ctx = krb5_ctx; + switch(pd->cmd) { + case SSS_PAM_AUTHENTICATE: + kr->client = tgt_req_child; + break; + case SSS_PAM_CHAUTHTOK: + kr->client = changepw_child; + break; + default: + DEBUG(1, ("PAM command [%d] not supported.\n", pd->cmd)); + kerr = EINVAL; + goto failed; + } + kerr = krb5_init_context(&kr->ctx); if (kerr != 0) { KRB5_DEBUG(1, kerr); @@ -185,7 +198,7 @@ static void wait_for_child_handler(struct tevent_context *ev, return; } -static int fork_tgt_req_child(struct krb5_req *kr) +static int fork_child(struct krb5_req *kr) { int pipefd[2]; pid_t pid; @@ -200,7 +213,7 @@ static int fork_tgt_req_child(struct krb5_req *kr) if (pid == 0) { /* child */ close(pipefd[0]); - tgt_req_child(pipefd[1], kr); + kr->client(pipefd[1], kr); } else if (pid > 0) { /* parent */ kr->child_pid = pid; kr->fd = pipefd[0]; @@ -296,29 +309,29 @@ static ssize_t read_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, return state->len; } -struct tgt_req_state { +struct handle_child_state { struct krb5_req *kr; ssize_t len; uint8_t *buf; }; -static void tgt_req_done(struct tevent_req *subreq); +static void handle_child_done(struct tevent_req *subreq); -static struct tevent_req *tgt_req_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, +static struct tevent_req *handle_child_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct krb5_req *kr) { int ret; struct tevent_req *req; struct tevent_req *subreq; - struct tgt_req_state *state; + struct handle_child_state *state; - ret = fork_tgt_req_child(kr); + ret = fork_child(kr); if (ret != EOK) { - DEBUG(1, ("fork_tgt_req_child failed.\n")); + DEBUG(1, ("fork_child failed.\n")); return NULL; } - req = tevent_req_create(mem_ctx, &state, struct tgt_req_state); + req = tevent_req_create(mem_ctx, &state, struct handle_child_state); if (req == NULL) { return NULL; } @@ -329,15 +342,16 @@ static struct tevent_req *tgt_req_send(TALLOC_CTX *mem_ctx, struct tevent_contex if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } - tevent_req_set_callback(subreq, tgt_req_done, req); + tevent_req_set_callback(subreq, handle_child_done, req); return req; } -static void tgt_req_done(struct tevent_req *subreq) +static void handle_child_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); - struct tgt_req_state *state = tevent_req_data(req, struct tgt_req_state); + struct handle_child_state *state = tevent_req_data(req, + struct handle_child_state); uint64_t error; state->len = read_pipe_recv(subreq, state, &state->buf, &error); @@ -352,9 +366,10 @@ static void tgt_req_done(struct tevent_req *subreq) return; } -static ssize_t tgt_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, +static ssize_t handle_child_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, uint8_t **buf, uint64_t *error) { - struct tgt_req_state *state = tevent_req_data(req, struct tgt_req_state); + struct handle_child_state *state = tevent_req_data(req, + struct handle_child_state); enum tevent_req_state tstate; if (tevent_req_is_error(req, &tstate, error)) { @@ -378,7 +393,7 @@ static void krb5_pam_handler(struct be_req *be_req) pd = talloc_get_type(be_req->req_data, struct pam_data); - if (pd->cmd != SSS_PAM_AUTHENTICATE) { + if (pd->cmd != SSS_PAM_AUTHENTICATE && pd->cmd != SSS_PAM_CHAUTHTOK) { DEBUG(4, ("krb5 does not handles pam task %d.\n", pd->cmd)); pam_status = PAM_SUCCESS; goto done; @@ -465,9 +480,9 @@ static void get_user_upn_done(void *pvt, int err, struct ldb_result *res) goto failed; } - req = tgt_req_send(be_req, be_req->be_ctx->ev, kr); + req = handle_child_send(be_req, be_req->be_ctx->ev, kr); if (req == NULL) { - DEBUG(1, ("tgt_req_send failed.\n")); + DEBUG(1, ("handle_child_send failed.\n")); goto failed; } @@ -488,7 +503,6 @@ static void krb5_pam_handler_done(struct tevent_req *req) struct pam_data *pd = kr->pd; struct be_req *be_req = kr->req; struct krb5_ctx *krb5_ctx = kr->krb5_ctx; - struct tgt_req_state *state = tevent_req_data(req, struct tgt_req_state); int ret; uint8_t *buf; ssize_t len; @@ -504,10 +518,10 @@ static void krb5_pam_handler_done(struct tevent_req *req) pd->pam_status = PAM_SYSTEM_ERR; krb5_cleanup(kr); - len = tgt_req_recv(req, state, &buf, &error); + len = handle_child_recv(req, pd, &buf, &error); talloc_zfree(req); if (len == -1) { - DEBUG(1, ("tgt_req request failed\n")); + DEBUG(1, ("child failed\n")); goto done; } @@ -568,13 +582,31 @@ static void krb5_pam_handler_done(struct tevent_req *req) if (pd->pam_status == PAM_SUCCESS && be_req->be_ctx->domain->cache_credentials == TRUE) { - password = talloc_size(be_req, pd->authtok_size + 1); + + switch(pd->cmd) { + case SSS_PAM_AUTHENTICATE: + password = talloc_size(be_req, pd->authtok_size + 1); + if (password != NULL) { + memcpy(password, pd->authtok, pd->authtok_size); + password[pd->authtok_size] = '\0'; + } + break; + case SSS_PAM_CHAUTHTOK: + password = talloc_size(be_req, pd->newauthtok_size + 1); + if (password != NULL) { + memcpy(password, pd->newauthtok, pd->newauthtok_size); + password[pd->newauthtok_size] = '\0'; + } + break; + default: + DEBUG(0, ("unsupported PAM command [%d].\n", pd->cmd)); + } + if (password == NULL) { - DEBUG(0, ("talloc_size failed, offline auth may not work.\n")); + DEBUG(0, ("password not available, offline auth may not work.\n")); goto done; } - memcpy(password, pd->authtok, pd->authtok_size); - password[pd->authtok_size] = '\0'; + talloc_set_destructor((TALLOC_CTX *)password, password_destructor); subreq = sysdb_cache_password_send(be_req, be_req->be_ctx->ev, @@ -617,6 +649,12 @@ struct bet_ops krb5_auth_ops = { .finalize = NULL, }; +struct bet_ops krb5_chpass_ops = { + .check_online = NULL, + .handler = krb5_pam_handler, + .finalize = NULL, +}; + int sssm_krb5_auth_init(struct be_ctx *bectx, struct bet_ops **ops, void **pvt_auth_data) @@ -668,6 +706,19 @@ int sssm_krb5_auth_init(struct be_ctx *bectx, struct bet_ops **ops, if (ret != EOK) goto fail; ctx->try_simple_upn = bool_value; + ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path, + "krb5changepw_principle", "kadmin/changepw", + &value); + if (ret != EOK) goto fail; + if (strchr(value, '@') == NULL) { + value = talloc_asprintf_append(value, "@%s", ctx->realm); + if (value == NULL) { + DEBUG(7, ("talloc_asprintf_append failed.\n")); + goto fail; + } + } + ctx->changepw_principle = value; + /* TODO: set options */ sige = tevent_add_signal(bectx->ev, ctx, SIGCHLD, SA_SIGINFO, @@ -687,3 +738,9 @@ fail: talloc_free(ctx); return ret; } + +int sssm_krb5_chpass_init(struct be_ctx *bectx, struct bet_ops **ops, + void **pvt_auth_data) +{ + return sssm_krb5_auth_init(bectx, ops, pvt_auth_data); +} diff --git a/server/providers/krb5/krb5_auth.h b/server/providers/krb5/krb5_auth.h index 540f65fa..0db3ef05 100644 --- a/server/providers/krb5/krb5_auth.h +++ b/server/providers/krb5/krb5_auth.h @@ -62,6 +62,7 @@ struct krb5_ctx { char *kdcip; char *realm; bool try_simple_upn; + char *changepw_principle; }; struct krb5_req { @@ -77,6 +78,7 @@ struct krb5_req { struct be_req *req; struct pam_data *pd; struct krb5_ctx *krb5_ctx; + void (*client)(int fd, struct krb5_req *kr); }; static krb5_context krb5_error_ctx; @@ -88,5 +90,6 @@ static const char *__krb5_error_msg; } while(0); void tgt_req_child(int fd, struct krb5_req *kr); +void changepw_child(int fd, struct krb5_req *kr); #endif /* __KRB5_AUTH_H__ */ diff --git a/server/providers/krb5/krb5_child.c b/server/providers/krb5/krb5_child.c new file mode 100644 index 00000000..daa2f71e --- /dev/null +++ b/server/providers/krb5/krb5_child.c @@ -0,0 +1,363 @@ +/* + SSSD + + Kerberos 5 Backend Module -- tgt_req and changepw child + + 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 <krb5/krb5.h> +#include <sys/types.h> + +#include <security/pam_modules.h> + +#include "util/util.h" +#include "providers/dp_backend.h" +#include "providers/krb5/krb5_auth.h" + +struct response { + size_t max_size; + size_t size; + uint8_t *buf; +}; + +static struct response *init_response(TALLOC_CTX *mem_ctx) { + struct response *r; + r = talloc(mem_ctx, struct response); + r->buf = talloc_size(mem_ctx, MAX_CHILD_MSG_SIZE); + if (r->buf == NULL) { + DEBUG(1, ("talloc_size failed.\n")); + return NULL; + } + r->max_size = MAX_CHILD_MSG_SIZE; + r->size = 0; + + return r; +} + +static errno_t pack_response_packet(struct response *resp, int status, int type, const char *data) +{ + int len; + int p=0; + + len = strlen(data)+1; + if ((3*sizeof(int32_t) + len +1) > resp->max_size) { + DEBUG(1, ("response message too big.\n")); + return ENOMEM; + } + + ((int32_t *)(&resp->buf[p]))[0] = status; + p += sizeof(int32_t); + + ((int32_t *)(&resp->buf[p]))[0] = type; + p += sizeof(int32_t); + + ((int32_t *)(&resp->buf[p]))[0] = len; + p += sizeof(int32_t); + + memcpy(&resp->buf[p], data, len); + p += len; + + resp->size = p; + + return EOK; +} + +static struct response * prepare_response_message(struct krb5_req *kr, + krb5_error_code kerr, int pam_status) +{ + const char *cc_name = NULL; + char *msg = NULL; + const char *krb5_msg = NULL; + int ret; + struct response *resp; + + resp = init_response(kr); + if (resp == NULL) { + DEBUG(1, ("init_response failed.\n")); + return NULL; + } + + if (kerr == 0) { + cc_name = krb5_cc_get_name(kr->ctx, kr->cc); + if (cc_name == NULL) { + DEBUG(1, ("krb5_cc_get_name failed.\n")); + return NULL; + } + + msg = talloc_asprintf(kr, "%s=%s",CCACHE_ENV_NAME, cc_name); + if (msg == NULL) { + DEBUG(1, ("talloc_asprintf failed.\n")); + return NULL; + } + + ret = pack_response_packet(resp, PAM_SUCCESS, PAM_ENV_ITEM, msg); + talloc_zfree(msg); + } else { + krb5_msg = krb5_get_error_message(krb5_error_ctx, kerr); + if (krb5_msg == NULL) { + DEBUG(1, ("krb5_get_error_message failed.\n")); + return NULL; + } + + ret = pack_response_packet(resp, pam_status, PAM_USER_INFO, krb5_msg); + krb5_free_error_message(krb5_error_ctx, krb5_msg); + } + + if (ret != EOK) { + DEBUG(1, ("pack_response_packet failed.\n")); + return NULL; + } + + return resp; +} + +static errno_t become_user(uid_t uid, gid_t gid) +{ + int ret; + ret = setgid(gid); + if (ret == -1) { + DEBUG(1, ("setgid failed [%d][%s].\n", errno, strerror(errno))); + return errno; + } + + ret = setuid(uid); + if (ret == -1) { + DEBUG(1, ("setuid failed [%d][%s].\n", errno, strerror(errno))); + return errno; + } + + ret = setegid(gid); + if (ret == -1) { + DEBUG(1, ("setegid failed [%d][%s].\n", errno, strerror(errno))); + return errno; + } + + ret = seteuid(uid); + if (ret == -1) { + DEBUG(1, ("seteuid failed [%d][%s].\n", errno, strerror(errno))); + return errno; + } + + return EOK; +} + +static krb5_error_code get_and_save_tgt(struct krb5_req *kr, + char *password) +{ + krb5_error_code kerr = 0; + + kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, + password, NULL, NULL, 0, NULL, + kr->options); + if (kerr != 0) { + KRB5_DEBUG(1, kerr); + return kerr; + } + + kerr = krb5_cc_default(kr->ctx, &kr->cc); + if (kerr != 0) { + KRB5_DEBUG(1, kerr); + return kerr; + } + + kerr = krb5_cc_initialize(kr->ctx, kr->cc, kr->princ); + if (kerr != 0) { + KRB5_DEBUG(1, kerr); + return kerr; + } + + kerr = krb5_cc_store_cred(kr->ctx, kr->cc, kr->creds); + if (kerr != 0) { + KRB5_DEBUG(1, kerr); + krb5_cc_destroy(kr->ctx, kr->cc); + return kerr; + } + + return 0; + +} + +void changepw_child(int fd, struct krb5_req *kr) +{ + int ret; + krb5_error_code kerr = 0; + char *pass_str = NULL; + char *newpass_str = NULL; + struct response *resp = NULL; + int pam_status = PAM_SYSTEM_ERR; + int result_code = -1; + krb5_data result_code_string; + krb5_data result_string; + + if (kr->pd->priv != 1) { + ret = become_user(kr->pd->pw_uid, kr->pd->gr_gid); + if (ret != EOK) { + DEBUG(1, ("become_user failed.\n")); + kerr = KRB5KRB_ERR_GENERIC; + goto sendresponse; + } + } else { +/* TODO: implement password reset by root */ + DEBUG(1, ("Password reset not implemented.\n")); + kerr = KRB5KRB_ERR_GENERIC; + goto sendresponse; + } + + pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, + kr->pd->authtok_size); + if (pass_str == NULL) { + DEBUG(1, ("talloc_strndup failed.\n")); + kerr = KRB5KRB_ERR_GENERIC; + goto sendresponse; + } + + kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, + pass_str, NULL, NULL, 0, + kr->krb5_ctx->changepw_principle, + kr->options); + if (kerr != 0) { + KRB5_DEBUG(1, kerr); + if (kerr == KRB5_KDC_UNREACH) { + pam_status = PAM_AUTHINFO_UNAVAIL; + } + goto sendresponse; + } + + memset(pass_str, 0, kr->pd->authtok_size); + talloc_zfree(pass_str); + memset(kr->pd->authtok, 0, kr->pd->authtok_size); + + newpass_str = talloc_strndup(kr, (const char *) kr->pd->newauthtok, + kr->pd->newauthtok_size); + if (newpass_str == NULL) { + DEBUG(1, ("talloc_strndup failed.\n")); + kerr = KRB5KRB_ERR_GENERIC; + goto sendresponse; + } + + kerr = krb5_change_password(kr->ctx, kr->creds, newpass_str, &result_code, + &result_code_string, &result_string); + + if (kerr != 0 || result_code != 0) { + if (kerr != 0) { + KRB5_DEBUG(1, kerr); + } + + 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)); + } + + if (result_string.length > 0) { + DEBUG(1, ("krb5_change_password failed [%d][%.*s].\n", result_code, + result_string.length, result_string.data)); + } + + goto sendresponse; + } + + + kerr = get_and_save_tgt(kr, newpass_str); + memset(newpass_str, 0, kr->pd->newauthtok_size); + talloc_zfree(newpass_str); + memset(kr->pd->newauthtok, 0, kr->pd->newauthtok_size); + + if (kerr != 0) { + KRB5_DEBUG(1, kerr); + if (kerr == KRB5_KDC_UNREACH) { + pam_status = PAM_AUTHINFO_UNAVAIL; + } + } + +sendresponse: + resp = prepare_response_message(kr, kerr, pam_status); + if (resp == NULL) { + DEBUG(1, ("prepare_response_message failed.\n")); + krb5_cc_destroy(kr->ctx, kr->cc); + _exit(-1); + } + + ret = write(fd, resp->buf, resp->size); + if (ret == -1) { + DEBUG(1, ("write failed [%d][%s].\n", errno, strerror(errno))); + krb5_cc_destroy(kr->ctx, kr->cc); + _exit(ret); + } + + krb5_cc_close(kr->ctx, kr->cc); + + + _exit(0); +} + +void tgt_req_child(int fd, struct krb5_req *kr) +{ + int ret; + krb5_error_code kerr = 0; + char *pass_str = NULL; + int pam_status = PAM_SYSTEM_ERR; + struct response *resp = NULL; + + ret = become_user(kr->pd->pw_uid, kr->pd->gr_gid); + if (ret != EOK) { + DEBUG(1, ("become_user failed.\n")); + kerr = KRB5KRB_ERR_GENERIC; + goto sendresponse; + } + + pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, + kr->pd->authtok_size); + if (pass_str == NULL) { + DEBUG(1, ("talloc_strndup failed.\n")); + kerr = KRB5KRB_ERR_GENERIC; + goto sendresponse; + } + + kerr = get_and_save_tgt(kr, pass_str); + memset(pass_str, 0, kr->pd->authtok_size); + talloc_zfree(pass_str); + memset(kr->pd->authtok, 0, kr->pd->authtok_size); + + if (kerr != 0) { + KRB5_DEBUG(1, kerr); + if (kerr == KRB5_KDC_UNREACH) { + pam_status = PAM_AUTHINFO_UNAVAIL; + } + } + +sendresponse: + resp = prepare_response_message(kr, kerr, pam_status); + if (resp == NULL) { + DEBUG(1, ("prepare_response_message failed.\n")); + krb5_cc_destroy(kr->ctx, kr->cc); + _exit(-1); + } + + ret = write(fd, resp->buf, resp->size); + if (ret == -1) { + DEBUG(1, ("write failed [%d][%s].\n", errno, strerror(errno))); + krb5_cc_destroy(kr->ctx, kr->cc); + _exit(ret); + } + + krb5_cc_close(kr->ctx, kr->cc); + + + _exit(0); +} diff --git a/server/providers/krb5/tgt_req_child.c b/server/providers/krb5/tgt_req_child.c deleted file mode 100644 index af9f52ff..00000000 --- a/server/providers/krb5/tgt_req_child.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - SSSD - - Kerberos 5 Backend Module -- tgt_req child - - 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 <krb5/krb5.h> -#include <sys/types.h> - -#include <security/pam_modules.h> - -#include "util/util.h" -#include "providers/dp_backend.h" -#include "providers/krb5/krb5_auth.h" - -static int pack_response_packet(uint8_t *buf, int status, int type, - const char *data) -{ - int len; - int p=0; - - if ((3*sizeof(int32_t) + strlen(data)+1) > MAX_CHILD_MSG_SIZE) { - return -1; - } - - ((int32_t *)(&buf[p]))[0] = status; - p += sizeof(int32_t); - - ((int32_t *)(&buf[p]))[0] = type; - p += sizeof(int32_t); - - len = strlen(data)+1; - ((int32_t *)(&buf[p]))[0] = len; - p += sizeof(int32_t); - - memcpy(&buf[p], data, len); - p += len; - - return p; -} - -void tgt_req_child(int fd, struct krb5_req *kr) -{ - int ret; - krb5_error_code kerr = 0; - char *pass_str = NULL; - uint8_t buf[MAX_CHILD_MSG_SIZE]; - int size = 0; - const char *cc_name; - char *env; - const char *krb5_error_msg; - int pam_status = PAM_SYSTEM_ERR; - - ret = setgid(kr->pd->gr_gid); - if (ret == -1) { - DEBUG(1, ("setgid failed [%d][%s].\n", errno, strerror(errno))); - _exit(-1); - } - - ret = setuid(kr->pd->pw_uid); - if (ret == -1) { - DEBUG(1, ("setuid failed [%d][%s].\n", errno, strerror(errno))); - _exit(-1); - } - - ret = setegid(kr->pd->gr_gid); - if (ret == -1) { - DEBUG(1, ("setegid failed [%d][%s].\n", errno, strerror(errno))); - _exit(-1); - } - - ret = seteuid(kr->pd->pw_uid); - if (ret == -1) { - DEBUG(1, ("seteuid failed [%d][%s].\n", errno, strerror(errno))); - _exit(-1); - } - - pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - if (pass_str == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - _exit(-1); - } - - kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, - pass_str, NULL, NULL, 0, NULL, - kr->options); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - if (kerr == KRB5_KDC_UNREACH) { - pam_status = PAM_AUTHINFO_UNAVAIL; - } - goto childfailed; - } - - memset(pass_str, 0, kr->pd->authtok_size); - talloc_free(pass_str); - memset(kr->pd->authtok, 0, kr->pd->authtok_size); - - kerr = krb5_cc_default(kr->ctx, &kr->cc); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto childfailed; - } - - kerr = krb5_cc_initialize(kr->ctx, kr->cc, kr->princ); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto childfailed; - } - - kerr = krb5_cc_store_cred(kr->ctx, kr->cc, kr->creds); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - krb5_cc_destroy(kr->ctx, kr->cc); - goto childfailed; - } - - cc_name = krb5_cc_get_name(kr->ctx, kr->cc); - if (cc_name == NULL) { - DEBUG(1, ("krb5_cc_get_name failed.\n")); - krb5_cc_destroy(kr->ctx, kr->cc); - _exit(-1); - } - - env = talloc_asprintf(kr, "%s=%s",CCACHE_ENV_NAME, cc_name); - if (env == NULL) { - DEBUG(1, ("talloc_asprintf failed.\n")); - krb5_cc_destroy(kr->ctx, kr->cc); - _exit(-1); - } - - size = pack_response_packet(buf, PAM_SUCCESS, PAM_ENV_ITEM, env); - if (size < 0) { - DEBUG(1, ("failed to create response message.\n")); - krb5_cc_destroy(kr->ctx, kr->cc); - _exit(-1); - } - - kerr = 0; - -childfailed: - if (kerr != 0 ) { - krb5_error_msg = krb5_get_error_message(krb5_error_ctx, kerr); - size = pack_response_packet(buf, pam_status, PAM_USER_INFO, - krb5_error_msg); - if (size < 0) { - DEBUG(1, ("failed to create response message.\n")); - krb5_cc_destroy(kr->ctx, kr->cc); - _exit(-1); - } - krb5_free_error_message(krb5_error_ctx, krb5_error_msg); - } - - ret = write(fd, buf, size); - if (ret == -1) { - DEBUG(1, ("write failed [%d][%s].\n", errno, strerror(errno))); - krb5_cc_destroy(kr->ctx, kr->cc); - _exit(ret); - } - - krb5_cc_close(kr->ctx, kr->cc); - - - _exit(0); -} |