From 1c48b5a62f73234ed26bb20f0ab345ab61cda0ab Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Thu, 18 Feb 2010 07:49:04 -0500 Subject: Rename server/ directory to src/ Also update BUILD.txt --- server/providers/krb5/krb5_auth.c | 1193 ------------------------------ server/providers/krb5/krb5_auth.h | 91 --- server/providers/krb5/krb5_become_user.c | 61 -- server/providers/krb5/krb5_child.c | 1030 -------------------------- server/providers/krb5/krb5_common.c | 356 --------- server/providers/krb5/krb5_common.h | 72 -- server/providers/krb5/krb5_init.c | 152 ---- server/providers/krb5/krb5_utils.c | 145 ---- server/providers/krb5/krb5_utils.h | 39 - 9 files changed, 3139 deletions(-) delete mode 100644 server/providers/krb5/krb5_auth.c delete mode 100644 server/providers/krb5/krb5_auth.h delete mode 100644 server/providers/krb5/krb5_become_user.c delete mode 100644 server/providers/krb5/krb5_child.c delete mode 100644 server/providers/krb5/krb5_common.c delete mode 100644 server/providers/krb5/krb5_common.h delete mode 100644 server/providers/krb5/krb5_init.c delete mode 100644 server/providers/krb5/krb5_utils.c delete mode 100644 server/providers/krb5/krb5_utils.h (limited to 'server/providers/krb5') diff --git a/server/providers/krb5/krb5_auth.c b/server/providers/krb5/krb5_auth.c deleted file mode 100644 index a2dadc80..00000000 --- a/server/providers/krb5/krb5_auth.c +++ /dev/null @@ -1,1193 +0,0 @@ -/* - SSSD - - Kerberos 5 Backend Module - - Authors: - Sumit Bose - - 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 . -*/ - -#include -#include - -#include -#include -#include -#include - -#include - -#include "util/util.h" -#include "util/find_uid.h" -#include "db/sysdb.h" -#include "providers/child_common.h" -#include "providers/krb5/krb5_auth.h" -#include "providers/krb5/krb5_utils.h" - -#ifndef SSSD_LIBEXEC_PATH -#error "SSSD_LIBEXEC_PATH not defined" -#else -#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) -{ - int ret; - size_t offset = 0; - struct stat stat_buf; - const char *filename; - bool active; - - *result = false; - - if (ccname == NULL || *ccname == '\0') { - return EINVAL; - } - - if (strncmp(ccname, "FILE:", 5) == 0) { - offset = 5; - } - - filename = ccname + offset; - - if (filename[0] != '/') { - DEBUG(1, ("Only absolute path names are allowed")); - return EINVAL; - } - - ret = lstat(filename, &stat_buf); - - if (ret == -1 && errno != ENOENT) { - DEBUG(1, ("stat failed [%d][%s].\n", errno, strerror(errno))); - return errno; - } else if (ret == EOK) { - if (stat_buf.st_uid != uid) { - DEBUG(1, ("Cache file [%s] exists, but is owned by [%d] instead of " - "[%d].\n", filename, stat_buf.st_uid, uid)); - return EINVAL; - } - - if (!S_ISREG(stat_buf.st_mode)) { - DEBUG(1, ("Cache file [%s] exists, but is not a regular file.\n", - filename)); - return EINVAL; - } - } - - ret = check_if_uid_is_active(uid, &active); - if (ret != EOK) { - DEBUG(1, ("check_if_uid_is_active failed.\n")); - return ret; - } - - if (!active) { - DEBUG(5, ("User [%d] is not active\n", uid)); - } else { - DEBUG(9, ("User [%d] is still active, reusing ccache file [%s].\n", - uid, filename)); - *result = true; - } - return EOK; -} - -struct krb5_save_ccname_state { - struct tevent_context *ev; - struct sysdb_ctx *sysdb; - struct sysdb_handle *handle; - struct sss_domain_info *domain; - const char *name; - struct sysdb_attrs *attrs; -}; - -static void krb5_save_ccname_trans(struct tevent_req *subreq); -static void krb5_set_user_attr_done(struct tevent_req *subreq); - -static struct tevent_req *krb5_save_ccname_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - const char *name, - const char *ccname) -{ - struct tevent_req *req; - struct tevent_req *subreq; - struct krb5_save_ccname_state *state; - int ret; - - if (name == NULL || ccname == NULL) { - DEBUG(1, ("Missing user or ccache name.\n")); - return NULL; - } - - req = tevent_req_create(mem_ctx, &state, struct krb5_save_ccname_state); - if (req == NULL) { - DEBUG(1, ("tevent_req_create failed.\n")); - return NULL; - } - - state->ev = ev; - state->sysdb = sysdb; - state->handle = NULL; - state->domain = domain; - state->name = name; - - state->attrs = sysdb_new_attrs(state); - ret = sysdb_attrs_add_string(state->attrs, SYSDB_CCACHE_FILE, ccname); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_add_string failed.\n")); - goto failed; - } - - subreq = sysdb_transaction_send(state, ev, sysdb); - if (subreq == NULL) { - goto failed; - } - tevent_req_set_callback(subreq, krb5_save_ccname_trans, req); - - return req; - -failed: - talloc_free(req); - return NULL; -} - -static void krb5_save_ccname_trans(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct krb5_save_ccname_state *state = tevent_req_data(req, - struct krb5_save_ccname_state); - int ret; - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - talloc_zfree(subreq); - if (ret != EOK) { - DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret))); - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_set_user_attr_send(state, state->ev, state->handle, - state->domain, state->name, - state->attrs, SYSDB_MOD_REP); - if (subreq == NULL) { - DEBUG(6, ("Error: Out of memory\n")); - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, krb5_set_user_attr_done, req); -} - -static void krb5_set_user_attr_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct krb5_save_ccname_state *state = tevent_req_data(req, - struct krb5_save_ccname_state); - int ret; - - ret = sysdb_set_user_attr_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret))); - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (subreq == NULL) { - DEBUG(6, ("Error: Out of memory\n")); - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sysdb_transaction_complete, req); - return; -} - -int krb5_save_ccname_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - -errno_t create_send_buffer(struct krb5child_req *kr, struct io_buffer **io_buf) -{ - struct io_buffer *buf; - size_t rp; - const char *keytab; - uint32_t validate; - - keytab = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_KEYTAB); - if (keytab == NULL) { - DEBUG(1, ("Missing keytab option.\n")); - return EINVAL; - } - - validate = dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) ? 1 : 0; - - buf = talloc(kr, struct io_buffer); - if (buf == NULL) { - DEBUG(1, ("talloc failed.\n")); - return ENOMEM; - } - - buf->size = 9*sizeof(uint32_t) + strlen(kr->pd->upn) + strlen(kr->ccname) + - strlen(keytab) + - kr->pd->authtok_size; - if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - buf->size += sizeof(uint32_t) + kr->pd->newauthtok_size; - } - - buf->data = talloc_size(kr, buf->size); - if (buf->data == NULL) { - DEBUG(1, ("talloc_size failed.\n")); - talloc_free(buf); - return ENOMEM; - } - - rp = 0; - COPY_UINT32(&buf->data[rp], &kr->pd->cmd, rp); - COPY_UINT32(&buf->data[rp], &kr->pd->pw_uid, rp); - COPY_UINT32(&buf->data[rp], &kr->pd->gr_gid, rp); - COPY_UINT32(&buf->data[rp], &validate, rp); - COPY_UINT32(&buf->data[rp], &kr->is_offline, rp); - - COPY_UINT32_VALUE(&buf->data[rp], strlen(kr->pd->upn), rp); - COPY_MEM(&buf->data[rp], kr->pd->upn, rp, strlen(kr->pd->upn)); - - COPY_UINT32_VALUE(&buf->data[rp], strlen(kr->ccname), rp); - COPY_MEM(&buf->data[rp], kr->ccname, rp, strlen(kr->ccname)); - - COPY_UINT32_VALUE(&buf->data[rp], strlen(keytab), rp); - COPY_MEM(&buf->data[rp], keytab, rp, strlen(keytab)); - - COPY_UINT32(&buf->data[rp], &kr->pd->authtok_size, rp); - COPY_MEM(&buf->data[rp], kr->pd->authtok, rp, kr->pd->authtok_size); - - if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) { - COPY_UINT32(&buf->data[rp], &kr->pd->newauthtok_size, rp); - COPY_MEM(&buf->data[rp], kr->pd->newauthtok, - rp, kr->pd->newauthtok_size); - } - - *io_buf = buf; - - return EOK; -} - -static struct krb5_ctx *get_krb5_ctx(struct be_req *be_req) -{ - struct pam_data *pd; - - pd = talloc_get_type(be_req->req_data, struct pam_data); - - switch (pd->cmd) { - case SSS_PAM_AUTHENTICATE: - return talloc_get_type(be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data, - struct krb5_ctx); - break; - case SSS_PAM_CHAUTHTOK: - case SSS_PAM_CHAUTHTOK_PRELIM: - return talloc_get_type(be_req->be_ctx->bet_info[BET_CHPASS].pvt_bet_data, - struct krb5_ctx); - break; - default: - DEBUG(1, ("Unsupported PAM task.\n")); - return NULL; - } -} - -static void krb_reply(struct be_req *req, int dp_err, int result); - -static void krb5_child_timeout(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt) -{ - struct krb5child_req *kr = talloc_get_type(pvt, struct krb5child_req); - struct be_req *be_req = kr->req; - struct pam_data *pd = kr->pd; - int ret; - - if (kr->timeout_handler == NULL) { - return; - } - - DEBUG(9, ("timeout for child [%d] reached.\n", kr->child_pid)); - - ret = kill(kr->child_pid, SIGKILL); - if (ret == -1) { - DEBUG(1, ("kill failed [%d][%s].\n", errno, strerror(errno))); - } - - talloc_zfree(kr); - - pd->pam_status = PAM_AUTHINFO_UNAVAIL; - be_mark_offline(be_req->be_ctx); - - krb_reply(be_req, DP_ERR_OFFLINE, pd->pam_status); -} - -static errno_t activate_child_timeout_handler(struct krb5child_req *kr) -{ - struct timeval tv; - - tv = tevent_timeval_current(); - tv = tevent_timeval_add(&tv, - dp_opt_get_int(kr->krb5_ctx->opts, - KRB5_AUTH_TIMEOUT), - 0); - kr->timeout_handler = tevent_add_timer(kr->req->be_ctx->ev, kr, tv, - krb5_child_timeout, kr); - if (kr->timeout_handler == NULL) { - DEBUG(1, ("tevent_add_timer failed.\n")); - return ENOMEM; - } - - return EOK; -} - -static int krb5_cleanup(void *ptr) -{ - struct krb5child_req *kr = talloc_get_type(ptr, struct krb5child_req); - - if (kr == NULL) return EOK; - - child_cleanup(kr->read_from_child_fd, kr->write_to_child_fd); - memset(kr, 0, sizeof(struct krb5child_req)); - - return EOK; -} - -static errno_t krb5_setup(struct be_req *req, struct krb5child_req **krb5_req) -{ - struct krb5child_req *kr = NULL; - struct krb5_ctx *krb5_ctx; - struct pam_data *pd; - errno_t err; - - pd = talloc_get_type(req->req_data, struct pam_data); - - krb5_ctx = get_krb5_ctx(req); - if (krb5_ctx == NULL) { - DEBUG(1, ("Kerberos context not available.\n")); - err = EINVAL; - goto failed; - } - - kr = talloc_zero(req, struct krb5child_req); - if (kr == NULL) { - DEBUG(1, ("talloc failed.\n")); - err = ENOMEM; - goto failed; - } - kr->read_from_child_fd = -1; - kr->write_to_child_fd = -1; - kr->is_offline = false; - kr->active_ccache_present = true; - talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup); - - kr->pd = pd; - kr->req = req; - kr->krb5_ctx = krb5_ctx; - - *krb5_req = kr; - - return EOK; - -failed: - talloc_zfree(kr); - - return err; -} - -static errno_t fork_child(struct krb5child_req *kr) -{ - int pipefd_to_child[2]; - int pipefd_from_child[2]; - pid_t pid; - int ret; - errno_t err; - - ret = pipe(pipefd_from_child); - if (ret == -1) { - err = errno; - DEBUG(1, ("pipe failed [%d][%s].\n", errno, strerror(errno))); - return err; - } - ret = pipe(pipefd_to_child); - if (ret == -1) { - err = errno; - DEBUG(1, ("pipe failed [%d][%s].\n", errno, strerror(errno))); - return err; - } - - pid = fork(); - - if (pid == 0) { /* child */ - /* We need to keep the root privileges to read the keytab file if - * validation is enabled, otherwise we can drop them here and run - * krb5_child with user privileges. - * If authtok_size is zero we are offline and want to create an empty - * ccache file. In this case we can drop the privileges, too. */ - if (!dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) || - kr->pd->authtok_size == 0) { - ret = become_user(kr->pd->pw_uid, kr->pd->gr_gid); - if (ret != EOK) { - DEBUG(1, ("become_user failed.\n")); - return ret; - } - } - - err = exec_child(kr, - pipefd_to_child, pipefd_from_child, - KRB5_CHILD, kr->krb5_ctx->child_debug_fd); - if (err != EOK) { - DEBUG(1, ("Could not exec LDAP child: [%d][%s].\n", - err, strerror(err))); - return err; - } - } else if (pid > 0) { /* parent */ - kr->child_pid = pid; - kr->read_from_child_fd = pipefd_from_child[0]; - close(pipefd_from_child[1]); - kr->write_to_child_fd = pipefd_to_child[1]; - close(pipefd_to_child[0]); - fd_nonblocking(kr->read_from_child_fd); - fd_nonblocking(kr->write_to_child_fd); - - err = activate_child_timeout_handler(kr); - if (err != EOK) { - DEBUG(1, ("activate_child_timeout_handler failed.\n")); - } - - } else { /* error */ - err = errno; - DEBUG(1, ("fork failed [%d][%s].\n", errno, strerror(errno))); - return err; - } - - return EOK; -} - -struct handle_child_state { - struct tevent_context *ev; - struct krb5child_req *kr; - uint8_t *buf; - ssize_t len; -}; - -static void handle_child_step(struct tevent_req *subreq); -static void handle_child_done(struct tevent_req *subreq); - -static struct tevent_req *handle_child_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct krb5child_req *kr) -{ - struct tevent_req *req, *subreq; - struct handle_child_state *state; - struct io_buffer *buf; - int ret; - - req = tevent_req_create(mem_ctx, &state, struct handle_child_state); - if (req == NULL) { - return NULL; - } - - state->ev = ev; - state->kr = kr; - state->buf = NULL; - state->len = 0; - - ret = create_send_buffer(kr, &buf); - if (ret != EOK) { - DEBUG(1, ("create_send_buffer failed.\n")); - goto fail; - } - - ret = fork_child(kr); - if (ret != EOK) { - DEBUG(1, ("fork_child failed.\n")); - goto fail; - } - - subreq = write_pipe_send(state, ev, buf->data, buf->size, - kr->write_to_child_fd); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, handle_child_step, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void handle_child_step(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct handle_child_state *state = tevent_req_data(req, - struct handle_child_state); - int ret; - - ret = write_pipe_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - close(state->kr->write_to_child_fd); - state->kr->write_to_child_fd = -1; - - subreq = read_pipe_send(state, state->ev, state->kr->read_from_child_fd); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, handle_child_done, req); -} - -static void handle_child_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct handle_child_state *state = tevent_req_data(req, - struct handle_child_state); - int ret; - - ret = read_pipe_recv(subreq, state, &state->buf, &state->len); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - close(state->kr->read_from_child_fd); - state->kr->read_from_child_fd = -1; - - tevent_req_done(req); - return; -} - -static int handle_child_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - uint8_t **buf, ssize_t *len) -{ - struct handle_child_state *state = tevent_req_data(req, - struct handle_child_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *buf = talloc_move(mem_ctx, &state->buf); - *len = state->len; - - return EOK; -} - -static void get_user_attr_done(void *pvt, int err, struct ldb_result *res); -static void krb5_resolve_done(struct tevent_req *req); -static void krb5_save_ccname_done(struct tevent_req *req); -static void krb5_child_done(struct tevent_req *req); -static void krb5_pam_handler_cache_done(struct tevent_req *treq); - -void krb5_pam_handler(struct be_req *be_req) -{ - struct pam_data *pd; - const char **attrs; - int pam_status = PAM_SYSTEM_ERR; - int dp_err = DP_ERR_FATAL; - int ret; - - pd = talloc_get_type(be_req->req_data, struct pam_data); - - switch (pd->cmd) { - case SSS_PAM_AUTHENTICATE: - case SSS_PAM_CHAUTHTOK: - case SSS_PAM_CHAUTHTOK_PRELIM: - break; - case SSS_PAM_ACCT_MGMT: - case SSS_PAM_SETCRED: - case SSS_PAM_OPEN_SESSION: - case SSS_PAM_CLOSE_SESSION: - pam_status = PAM_SUCCESS; - dp_err = DP_ERR_OK; - goto done; - break; - default: - DEBUG(4, ("krb5 does not handles pam task %d.\n", pd->cmd)); - pam_status = PAM_MODULE_UNKNOWN; - dp_err = DP_ERR_OK; - goto done; - } - - if (be_is_offline(be_req->be_ctx) && - (pd->cmd == SSS_PAM_CHAUTHTOK || pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM)) { - DEBUG(9, ("Password changes are not possible while offline.\n")); - pam_status = PAM_AUTHINFO_UNAVAIL; - dp_err = DP_ERR_OFFLINE; - goto done; - } - - attrs = talloc_array(be_req, const char *, 4); - if (attrs == NULL) { - goto done; - } - - attrs[0] = SYSDB_UPN; - attrs[1] = SYSDB_HOMEDIR; - attrs[2] = SYSDB_CCACHE_FILE; - attrs[3] = NULL; - - ret = sysdb_get_user_attr(be_req, be_req->be_ctx->sysdb, - be_req->be_ctx->domain, pd->user, attrs, - get_user_attr_done, be_req); - - if (ret) { - goto done; - } - - return; - -done: - pd->pam_status = pam_status; - - krb_reply(be_req, dp_err, pd->pam_status); -} - -static void get_user_attr_done(void *pvt, int err, struct ldb_result *res) -{ - struct be_req *be_req = talloc_get_type(pvt, struct be_req); - struct krb5_ctx *krb5_ctx; - struct krb5child_req *kr = NULL; - struct tevent_req *req; - krb5_error_code kerr; - int ret; - struct pam_data *pd = talloc_get_type(be_req->req_data, struct pam_data); - int pam_status=PAM_SYSTEM_ERR; - int dp_err = DP_ERR_FATAL; - const char *ccache_file = NULL; - const char *realm; - - ret = krb5_setup(be_req, &kr); - if (ret != EOK) { - DEBUG(1, ("krb5_setup failed.\n")); - goto failed; - } - - krb5_ctx = kr->krb5_ctx; - - if (err != LDB_SUCCESS) { - DEBUG(5, ("sysdb search for upn of user [%s] failed.\n", pd->user)); - goto failed; - } - - realm = dp_opt_get_cstring(krb5_ctx->opts, KRB5_REALM); - if (realm == NULL) { - DEBUG(1, ("Missing Kerberos realm.\n")); - goto failed; - } - - switch (res->count) { - case 0: - DEBUG(5, ("No attributes for user [%s] found.\n", pd->user)); - goto failed; - break; - - case 1: - pd->upn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_UPN, NULL); - if (pd->upn == NULL) { - /* NOTE: this is a hack, works only in some environments */ - pd->upn = talloc_asprintf(be_req, "%s@%s", pd->user, realm); - if (pd->upn == NULL) { - DEBUG(1, ("failed to build simple upn.\n")); - goto failed; - } - DEBUG(9, ("Using simple UPN [%s].\n", pd->upn)); - } - - kr->homedir = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_HOMEDIR, - NULL); - if (kr->homedir == NULL) { - DEBUG(4, ("Home directory for user [%s] not known.\n", pd->user)); - } - - ccache_file = ldb_msg_find_attr_as_string(res->msgs[0], - SYSDB_CCACHE_FILE, - NULL); - if (ccache_file != NULL) { - ret = check_if_ccache_file_is_used(pd->pw_uid, ccache_file, - &kr->active_ccache_present); - if (ret != EOK) { - DEBUG(1, ("check_if_ccache_file_is_used failed.\n")); - goto failed; - } - - kerr = check_for_valid_tgt(ccache_file, realm, pd->upn, - &kr->valid_tgt_present); - if (kerr != 0) { - DEBUG(1, ("check_for_valid_tgt failed.\n")); - goto failed; - } - } else { - kr->active_ccache_present = false; - kr->valid_tgt_present = false; - DEBUG(4, ("No ccache file for user [%s] found.\n", pd->user)); - } - DEBUG(9, ("Ccache_file is [%s] and is %s active and TGT is %s valid.\n", - ccache_file ? ccache_file : "not set", - kr->active_ccache_present ? "" : "not", - kr->valid_tgt_present ? "" : "not")); - kr->ccname = ccache_file; - break; - - default: - DEBUG(1, ("A user search by name (%s) returned > 1 results!\n", - pd->user)); - goto failed; - break; - } - - req = be_resolve_server_send(kr, be_req->be_ctx->ev, be_req->be_ctx, - krb5_ctx->service->name); - if (req == NULL) { - DEBUG(1, ("handle_child_send failed.\n")); - goto failed; - } - - tevent_req_set_callback(req, krb5_resolve_done, kr); - - return; - -failed: - talloc_free(kr); - - pd->pam_status = pam_status; - krb_reply(be_req, dp_err, pd->pam_status); -} - -static void krb5_resolve_done(struct tevent_req *req) -{ - struct krb5child_req *kr = tevent_req_callback_data(req, - struct krb5child_req); - int ret; - int pam_status = PAM_SYSTEM_ERR; - int dp_err = DP_ERR_FATAL; - struct pam_data *pd = kr->pd; - struct be_req *be_req = kr->req; - char *msg; - size_t offset = 0; - - ret = be_resolve_server_recv(req, &kr->srv); - talloc_zfree(req); - if (ret) { - /* all servers have been tried and none - * was found good, setting offline, - * but we still have to call the child to setup - * the ccache file. */ - be_mark_offline(be_req->be_ctx); - kr->is_offline = true; - } - - if (kr->ccname == NULL || - (be_is_offline(be_req->be_ctx) && !kr->active_ccache_present && - !kr->valid_tgt_present) || - (!be_is_offline(be_req->be_ctx) && !kr->active_ccache_present)) { - DEBUG(9, ("Recreating ccache file.\n")); - if (kr->ccname != NULL) { - if (strncmp(kr->ccname, "FILE:", 5) == 0) { - offset = 5; - } - if (kr->ccname[offset] != '/') { - DEBUG(1, ("Ccache file name [%s] is not an absolute path.\n", - kr->ccname + offset)); - goto done; - } - ret = unlink(kr->ccname + offset); - if (ret == -1 && errno != ENOENT) { - DEBUG(1, ("unlink [%s] failed [%d][%s].\n", kr->ccname, - errno, strerror(errno))); - goto done; - } - } - kr->ccname = expand_ccname_template(kr, kr, - dp_opt_get_cstring(kr->krb5_ctx->opts, - KRB5_CCNAME_TMPL) - ); - if (kr->ccname == NULL) { - DEBUG(1, ("expand_ccname_template failed.\n")); - goto done; - } - } - - if (be_is_offline(be_req->be_ctx)) { - DEBUG(9, ("Preparing for offline operation.\n")); - kr->is_offline = true; - - if (kr->valid_tgt_present) { - DEBUG(9, ("Valid TGT available, nothing to do.\n")); - msg = talloc_asprintf(pd, "%s=%s", CCACHE_ENV_NAME, kr->ccname); - if (msg == NULL) { - DEBUG(1, ("talloc_asprintf failed.\n")); - goto done; - } - - ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(msg) + 1, - (uint8_t *) msg); - if (ret != EOK) { - DEBUG(1, ("pam_add_response failed.\n")); - } - - pam_status = PAM_AUTHINFO_UNAVAIL; - dp_err = DP_ERR_OFFLINE; - goto done; - } - memset(pd->authtok, 0, pd->authtok_size); - pd->authtok_size = 0; - - if (kr->active_ccache_present) { - req = krb5_save_ccname_send(kr, be_req->be_ctx->ev, - be_req->be_ctx->sysdb, - be_req->be_ctx->domain, pd->user, - kr->ccname); - if (req == NULL) { - DEBUG(1, ("krb5_save_ccname_send failed.\n")); - goto done; - } - - tevent_req_set_callback(req, krb5_save_ccname_done, kr); - return; - } - } - - req = handle_child_send(kr, be_req->be_ctx->ev, kr); - if (req == NULL) { - DEBUG(1, ("handle_child_send failed.\n")); - goto done; - } - - tevent_req_set_callback(req, krb5_child_done, kr); - return; - -done: - talloc_free(kr); - pd->pam_status = pam_status; - krb_reply(be_req, dp_err, pd->pam_status); -} - -static void krb5_child_done(struct tevent_req *req) -{ - struct krb5child_req *kr = tevent_req_callback_data(req, - struct krb5child_req); - struct pam_data *pd = kr->pd; - struct be_req *be_req = kr->req; - 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; - int pam_status = PAM_SYSTEM_ERR; - int dp_err = DP_ERR_FATAL; - - ret = handle_child_recv(req, pd, &buf, &len); - talloc_zfree(kr->timeout_handler); - talloc_zfree(req); - if (ret != EOK) { - DEBUG(1, ("child failed (%d [%s])\n", ret, strerror(ret))); - goto done; - } - - if ((size_t) len < 3*sizeof(int32_t)) { - DEBUG(1, ("message too short.\n")); - goto done; - } - - p=0; - msg_status = ((int32_t *)(buf+p)); - p += sizeof(int32_t); - - msg_type = ((int32_t *)(buf+p)); - p += sizeof(int32_t); - - msg_len = ((int32_t *)(buf+p)); - p += sizeof(int32_t); - - DEBUG(4, ("child response [%d][%d][%d].\n", *msg_status, *msg_type, - *msg_len)); - - if ((p + *msg_len) != len) { - DEBUG(1, ("message format error.\n")); - goto done; - } - - if (*msg_status != PAM_SUCCESS && *msg_status != PAM_AUTHINFO_UNAVAIL) { - pam_status = *msg_status; - dp_err = DP_ERR_OK; - - ret = pam_add_response(pd, *msg_type, *msg_len, &buf[p]); - if (ret != EOK) { - DEBUG(1, ("pam_add_response failed.\n")); - } - - goto done; - } else { - pd->pam_status = *msg_status; - } - - if (*msg_status == PAM_SUCCESS && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { - pam_status = PAM_SUCCESS; - dp_err = DP_ERR_OK; - 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")); - goto done; - } - } else { - DEBUG(1, ("Missing ccache name in child response [%.*s].\n", *msg_len, - &buf[p])); - goto done; - } - - if (*msg_status == PAM_AUTHINFO_UNAVAIL) { - if (kr->srv != NULL) { - fo_set_port_status(kr->srv, PORT_NOT_WORKING); - } - be_mark_offline(be_req->be_ctx); - kr->is_offline = true; - } else if (kr->srv != NULL) { - fo_set_port_status(kr->srv, PORT_WORKING); - } - - struct sysdb_attrs *attrs; - attrs = sysdb_new_attrs(kr); - ret = sysdb_attrs_add_string(attrs, SYSDB_CCACHE_FILE, kr->ccname); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_add_string failed.\n")); - goto done; - } - - req = krb5_save_ccname_send(kr, be_req->be_ctx->ev, be_req->be_ctx->sysdb, - be_req->be_ctx->domain, pd->user, kr->ccname); - if (req == NULL) { - DEBUG(1, ("krb5_save_ccname_send failed.\n")); - goto done; - } - - tevent_req_set_callback(req, krb5_save_ccname_done, kr); - return; -done: - talloc_free(kr); - pd->pam_status = pam_status; - krb_reply(be_req, dp_err, pd->pam_status); -} - -static void krb5_save_ccname_done(struct tevent_req *req) -{ - struct krb5child_req *kr = tevent_req_callback_data(req, - struct krb5child_req); - struct pam_data *pd = kr->pd; - struct be_req *be_req = kr->req; - struct krb5_ctx *krb5_ctx = kr->krb5_ctx; - int pam_status = PAM_SYSTEM_ERR; - int dp_err = DP_ERR_FATAL; - int ret; - char *password = NULL; - - if (pd->cmd == SSS_PAM_AUTHENTICATE) { - ret = add_krb5_env(krb5_ctx->opts, kr->ccname, pd); - if (ret != EOK) { - DEBUG(1, ("add_krb5_env failed.\n")); - goto failed; - } - } - - ret = sysdb_set_user_attr_recv(req); - talloc_zfree(req); - if (ret != EOK) { - DEBUG(1, ("Saving ccache name failed.\n")); - goto failed; - } - - if (kr->is_offline) { - DEBUG(4, ("Backend is marked offline, retry later!\n")); - pam_status = PAM_AUTHINFO_UNAVAIL; - dp_err = DP_ERR_OFFLINE; - goto failed; - } - - if (be_req->be_ctx->domain->cache_credentials == TRUE) { - - /* password caching failures are not fatal errors */ - pd->pam_status = PAM_SUCCESS; - - switch(pd->cmd) { - case SSS_PAM_AUTHENTICATE: - case SSS_PAM_CHAUTHTOK_PRELIM: - 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, ("password not available, offline auth may not work.\n")); - goto failed; - } - - talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - - req = sysdb_cache_password_send(be_req, be_req->be_ctx->ev, - be_req->be_ctx->sysdb, NULL, - be_req->be_ctx->domain, pd->user, - password); - if (req == NULL) { - DEBUG(2, ("cache_password_send failed, offline auth may not work.\n")); - goto failed; - } - tevent_req_set_callback(req, krb5_pam_handler_cache_done, be_req); - return; - } - - pam_status = PAM_SUCCESS; - dp_err = DP_ERR_OK; - -failed: - talloc_free(kr); - - pd->pam_status = pam_status; - krb_reply(be_req, dp_err, pd->pam_status); -} - -static void krb5_pam_handler_cache_done(struct tevent_req *subreq) -{ - struct be_req *be_req = tevent_req_callback_data(subreq, struct be_req); - int ret; - - /* password caching failures are not fatal errors */ - ret = sysdb_cache_password_recv(subreq); - talloc_zfree(subreq); - - /* so we just log it any return */ - if (ret) { - DEBUG(2, ("Failed to cache password (%d)[%s]!?\n", - ret, strerror(ret))); - } - - krb_reply(be_req, DP_ERR_OK, PAM_SUCCESS); -} - -static void krb_reply(struct be_req *req, int dp_err, int result) -{ - req->fn(req, dp_err, result, NULL); -} - diff --git a/server/providers/krb5/krb5_auth.h b/server/providers/krb5/krb5_auth.h deleted file mode 100644 index a011af89..00000000 --- a/server/providers/krb5/krb5_auth.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - SSSD - - Kerberos Backend, private header file - - Authors: - Sumit Bose - - 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 . -*/ - -#ifndef __KRB5_AUTH_H__ -#define __KRB5_AUTH_H__ - -#include "util/sss_krb5.h" -#include "providers/dp_backend.h" -#include "providers/krb5/krb5_common.h" - -#define CCACHE_ENV_NAME "KRB5CCNAME" -#define SSSD_KRB5_CHANGEPW_PRINCIPLE "SSSD_KRB5_CHANGEPW_PRINCIPLE" - -typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type; - -struct krb5child_req { - pid_t child_pid; - int read_from_child_fd; - int write_to_child_fd; - - struct be_req *req; - struct pam_data *pd; - struct krb5_ctx *krb5_ctx; - - struct tevent_timer *timeout_handler; - - const char *ccname; - const char *homedir; - bool is_offline; - struct fo_server *srv; - bool active_ccache_present; - bool valid_tgt_present; -}; - -struct fo_service; - -struct krb5_ctx { - /* opts taken from kinit */ - /* in seconds */ - krb5_deltat starttime; - krb5_deltat lifetime; - krb5_deltat rlife; - - int forwardable; - int proxiable; - int addresses; - - int not_forwardable; - int not_proxiable; - int no_addresses; - - int verbose; - - char* principal_name; - char* service_name; - char* keytab_name; - char* k5_cache_name; - char* k4_cache_name; - - action_type action; - - struct dp_option *opts; - struct krb5_service *service; - int child_debug_fd; -}; - -void krb5_pam_handler(struct be_req *be_req); - -#endif /* __KRB5_AUTH_H__ */ diff --git a/server/providers/krb5/krb5_become_user.c b/server/providers/krb5/krb5_become_user.c deleted file mode 100644 index 351f539a..00000000 --- a/server/providers/krb5/krb5_become_user.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - SSSD - - Kerberos 5 Backend Module -- Utilities - - Authors: - Sumit Bose - - 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 . -*/ - -#include -#include - -#include "util/util.h" - -errno_t become_user(uid_t uid, gid_t gid) -{ - int ret; - - DEBUG(9, ("Trying to become user [%d][%d].\n", uid, gid)); - 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; -} - diff --git a/server/providers/krb5/krb5_child.c b/server/providers/krb5/krb5_child.c deleted file mode 100644 index 5e185940..00000000 --- a/server/providers/krb5/krb5_child.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* - SSSD - - Kerberos 5 Backend Module -- tgt_req and changepw child - - Authors: - Sumit Bose - - 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 . -*/ - -#include -#include -#include -#include - -#include - -#include "util/util.h" -#include "util/user_info_msg.h" -#include "providers/child_common.h" -#include "providers/dp_backend.h" -#include "providers/krb5/krb5_auth.h" -#include "providers/krb5/krb5_utils.h" - -struct krb5_child_ctx { - /* opts taken from kinit */ - /* in seconds */ - krb5_deltat starttime; - krb5_deltat lifetime; - krb5_deltat rlife; - - int forwardable; - int proxiable; - int addresses; - - int not_forwardable; - int not_proxiable; - int no_addresses; - - int verbose; - - char* principal_name; - char* service_name; - char* keytab_name; - char* k5_cache_name; - char* k4_cache_name; - - action_type action; - - char *kdcip; - char *realm; - char *changepw_principle; - char *ccache_dir; - char *ccname_template; - int auth_timeout; - - int child_debug_fd; -}; - -struct krb5_req { - krb5_context ctx; - krb5_principal princ; - char* name; - krb5_creds *creds; - krb5_get_init_creds_opt *options; - pid_t child_pid; - int read_from_child_fd; - int write_to_child_fd; - - struct be_req *req; - struct pam_data *pd; - struct krb5_child_ctx *krb5_ctx; - errno_t (*child_req)(int fd, struct krb5_req *kr); - - char *ccname; - char *keytab; - bool validate; -}; - -static krb5_context krb5_error_ctx; -static const char *__krb5_error_msg; -#define KRB5_DEBUG(level, krb5_error) do { \ - __krb5_error_msg = sss_krb5_get_error_message(krb5_error_ctx, krb5_error); \ - DEBUG(level, ("%d: [%d][%s]\n", __LINE__, krb5_error, __krb5_error_msg)); \ - sss_krb5_free_error_message(krb5_error_ctx, __krb5_error_msg); \ -} while(0); - -static krb5_error_code create_empty_cred(struct krb5_req *kr, krb5_creds **_cred) -{ - krb5_error_code kerr; - krb5_creds *cred = NULL; - krb5_data *krb5_realm; - - cred = calloc(sizeof(krb5_creds), 1); - if (cred == NULL) { - DEBUG(1, ("calloc failed.\n")); - return ENOMEM; - } - - kerr = krb5_copy_principal(kr->ctx, kr->princ, &cred->client); - if (kerr != 0) { - DEBUG(1, ("krb5_copy_principal failed.\n")); - goto done; - } - - krb5_realm = krb5_princ_realm(kr->ctx, kr->princ); - - kerr = krb5_build_principal_ext(kr->ctx, &cred->server, - krb5_realm->length, krb5_realm->data, - KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, - krb5_realm->length, krb5_realm->data, 0); - if (kerr != 0) { - DEBUG(1, ("krb5_build_principal_ext failed.\n")); - goto done; - } - -done: - if (kerr != 0) { - if (cred != NULL && cred->client != NULL) { - krb5_free_principal(kr->ctx, cred->client); - } - - free(cred); - } else { - *_cred = cred; - } - - return kerr; -} - -static krb5_error_code create_ccache_file(struct krb5_req *kr, krb5_creds *creds) -{ - krb5_error_code kerr; - krb5_ccache tmp_cc = NULL; - char *cc_file_name; - int fd = -1; - size_t ccname_len; - char *dummy; - char *tmp_ccname; - krb5_creds *l_cred; - - if (strncmp(kr->ccname, "FILE:", 5) == 0) { - cc_file_name = kr->ccname + 5; - } else { - cc_file_name = kr->ccname; - } - - if (cc_file_name[0] != '/') { - DEBUG(1, ("Ccache filename is not an absolute path.\n")); - return EINVAL; - } - - dummy = strrchr(cc_file_name, '/'); - tmp_ccname = talloc_strndup(kr, cc_file_name, (size_t) (dummy-cc_file_name)); - if (tmp_ccname == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - return ENOMEM; - } - tmp_ccname = talloc_asprintf_append(tmp_ccname, "/.krb5cc_dummy_XXXXXX"); - - fd = mkstemp(tmp_ccname); - if (fd == -1) { - DEBUG(1, ("mkstemp failed [%d][%s].\n", errno, strerror(errno))); - return errno; - } - - kerr = krb5_cc_resolve(kr->ctx, tmp_ccname, &tmp_cc); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto done; - } - - kerr = krb5_cc_initialize(kr->ctx, tmp_cc, kr->princ); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto done; - } - if (fd != -1) { - close(fd); - fd = -1; - } - - if (creds == NULL) { - kerr = create_empty_cred(kr, &l_cred); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto done; - } - } else { - l_cred = creds; - } - - kerr = krb5_cc_store_cred(kr->ctx, tmp_cc, l_cred); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto done; - } - - kerr = krb5_cc_close(kr->ctx, tmp_cc); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto done; - } - tmp_cc = NULL; - - ccname_len = strlen(cc_file_name); - if (ccname_len >= 6 && strcmp(cc_file_name + (ccname_len-6), "XXXXXX")==0 ) { - fd = mkstemp(cc_file_name); - if (fd == -1) { - DEBUG(1, ("mkstemp failed [%d][%s].\n", errno, strerror(errno))); - kerr = errno; - goto done; - } - } - - kerr = rename(tmp_ccname, cc_file_name); - if (kerr == -1) { - DEBUG(1, ("rename failed [%d][%s].\n", errno, strerror(errno))); - } - -done: - if (fd != -1) { - close(fd); - fd = -1; - } - if (kerr != 0 && tmp_cc != NULL) { - krb5_cc_destroy(kr->ctx, tmp_cc); - } - return kerr; -} - -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, - size_t len, const uint8_t *data) -{ - int p=0; - - if ((3*sizeof(int32_t) + len +1) > resp->max_size) { - DEBUG(1, ("response message too big.\n")); - return ENOMEM; - } - - COPY_INT32_VALUE(&resp->buf[p], status, p); - COPY_INT32_VALUE(&resp->buf[p], type, p); - COPY_INT32_VALUE(&resp->buf[p], len, p); - COPY_MEM(&resp->buf[p], data, p, len); - - resp->size = p; - - return EOK; -} - -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 = init_response(kr); - if (resp == NULL) { - DEBUG(1, ("init_response failed.\n")); - return NULL; - } - - 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"); - } else { - if (kr->ccname == NULL) { - DEBUG(1, ("Error obtaining ccname.\n")); - return NULL; - } - - msg = talloc_asprintf(kr, "%s=%s",CCACHE_ENV_NAME, kr->ccname); - if (msg == NULL) { - DEBUG(1, ("talloc_asprintf failed.\n")); - return NULL; - } - - ret = pack_response_packet(resp, PAM_SUCCESS, 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 { - - } - - } - - if (ret != EOK) { - DEBUG(1, ("pack_response_packet failed.\n")); - return NULL; - } - - return resp; -} - -static errno_t sendresponse(int fd, krb5_error_code kerr, - char *user_error_message, int pam_status, - struct krb5_req *kr) -{ - struct response *resp; - size_t written; - int ret; - - resp = prepare_response_message(kr, kerr, user_error_message, pam_status); - if (resp == NULL) { - DEBUG(1, ("prepare_response_message failed.\n")); - return ENOMEM; - } - - written = 0; - while (written < resp->size) { - ret = write(fd, resp->buf + written, resp->size - written); - if (ret == -1) { - if (errno == EAGAIN || errno == EINTR) { - continue; - } - ret = errno; - DEBUG(1, ("write failed [%d][%s].\n", ret, strerror(ret))); - return ret; - } - written += ret; - } - - return EOK; -} - -static krb5_error_code validate_tgt(struct krb5_req *kr) -{ - krb5_error_code kerr; - krb5_error_code kt_err; - char *principal; - krb5_keytab keytab; - krb5_kt_cursor cursor; - krb5_keytab_entry entry; - krb5_verify_init_creds_opt opt; - - memset(&keytab, 0, sizeof(keytab)); - kerr = krb5_kt_resolve(kr->ctx, kr->keytab, &keytab); - if (kerr != 0) { - DEBUG(1, ("error resolving keytab [%s], not verifying TGT.\n", - kr->keytab)); - return kerr; - } - - memset(&cursor, 0, sizeof(cursor)); - kerr = krb5_kt_start_seq_get(kr->ctx, keytab, &cursor); - if (kerr != 0) { - DEBUG(1, ("error reading keytab [%s], not verifying TGT.\n", - kr->keytab)); - return kerr; - } - - /* We look for the first entry from our realm or take the last one */ - memset(&entry, 0, sizeof(entry)); - while ((kt_err = krb5_kt_next_entry(kr->ctx, keytab, &entry, &cursor)) == 0) { - if (krb5_realm_compare(kr->ctx, entry.principal, kr->princ)) { - DEBUG(9, ("Found keytab entry with the realm of the credential.\n")); - break; - } - - kerr = krb5_free_keytab_entry_contents(kr->ctx, &entry); - if (kerr != 0) { - DEBUG(1, ("Failed to free keytab entry.\n")); - } - memset(&entry, 0, sizeof(entry)); - } - - /* Close the keytab here. Even though we're using cursors, the file - * handle is stored in the krb5_keytab structure, and it gets - * overwritten when the verify_init_creds() call below creates its own - * cursor, creating a leak. */ - kerr = krb5_kt_end_seq_get(kr->ctx, keytab, &cursor); - if (kerr != 0) { - DEBUG(1, ("krb5_kt_end_seq_get failed, not verifying TGT.\n")); - goto done; - } - - /* check if we got any errors from krb5_kt_next_entry */ - if (kt_err != 0 && kt_err != KRB5_KT_END) { - DEBUG(1, ("error reading keytab [%s], not verifying TGT.\n", - kr->keytab)); - goto done; - } - - /* Get the principal to which the key belongs, for logging purposes. */ - principal = NULL; - kerr = krb5_unparse_name(kr->ctx, entry.principal, &principal); - if (kerr != 0) { - DEBUG(1, ("internal error parsing principal name, " - "not verifying TGT.\n")); - goto done; - } - - - krb5_verify_init_creds_opt_init(&opt); - kerr = krb5_verify_init_creds(kr->ctx, kr->creds, entry.principal, keytab, - NULL, &opt); - - if (kerr == 0) { - DEBUG(5, ("TGT verified using key for [%s].\n", principal)); - } else { - DEBUG(1 ,("TGT failed verification using key for [%s].\n", principal)); - } - -done: - if (krb5_kt_close(kr->ctx, keytab) != 0) { - DEBUG(1, ("krb5_kt_close failed")); - } - if (krb5_free_keytab_entry_contents(kr->ctx, &entry) != 0) { - DEBUG(1, ("Failed to free keytab entry.\n")); - } - if (principal != NULL) { - sss_krb5_free_unparsed_name(kr->ctx, principal); - } - - return kerr; - -} - -static krb5_error_code get_and_save_tgt(struct krb5_req *kr, - char *password) -{ - krb5_error_code kerr = 0; - int ret; - - 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; - } - - if (kr->validate) { - kerr = validate_tgt(kr); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - return kerr; - } - - /* We drop root privileges which were needed to read the keytab file - * for the validation validation of the credentials here to run the - * ccache I/O operations with user privileges. */ - ret = become_user(kr->pd->pw_uid, kr->pd->gr_gid); - if (ret != EOK) { - DEBUG(1, ("become_user failed.\n")); - return ret; - } - } else { - DEBUG(9, ("TGT validation is disabled.\n")); - } - - kerr = create_ccache_file(kr, kr->creds); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto done; - } - - kerr = 0; - -done: - krb5_free_cred_contents(kr->ctx, kr->creds); - - return kerr; - -} - -static errno_t changepw_child(int fd, struct krb5_req *kr) -{ - int ret; - krb5_error_code kerr = 0; - char *pass_str = NULL; - char *newpass_str = NULL; - int pam_status = PAM_SYSTEM_ERR; - int result_code = -1; - krb5_data result_code_string; - krb5_data result_string; - char *user_error_message = NULL; - - pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok, - kr->pd->authtok_size); - 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); - - if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { - DEBUG(9, ("Initial authentication for change password operation " - "successfull.\n")); - krb5_free_cred_contents(kr->ctx, kr->creds); - pam_status = PAM_SUCCESS; - goto sendresponse; - } - - 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); - } else { - kerr = KRB5KRB_ERR_GENERIC; - } - - if (result_code_string.length > 0) { - DEBUG(1, ("krb5_change_password failed [%d][%.*s].\n", result_code, - result_code_string.length, result_code_string.data)); - user_error_message = talloc_strndup(kr->pd, result_code_string.data, - result_code_string.length); - if (user_error_message == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - } - } - - if (result_string.length > 0) { - DEBUG(1, ("krb5_change_password failed [%d][%.*s].\n", result_code, - result_string.length, result_string.data)); - talloc_free(user_error_message); - user_error_message = talloc_strndup(kr->pd, result_string.data, - result_string.length); - if (user_error_message == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - } - } - - pam_status = PAM_AUTHTOK_ERR; - goto sendresponse; - } - - krb5_free_cred_contents(kr->ctx, kr->creds); - - 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: - ret = sendresponse(fd, kerr, user_error_message, pam_status, kr); - if (ret != EOK) { - DEBUG(1, ("sendresponse failed.\n")); - } - - return ret; -} - -static errno_t 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; - - 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); - - /* If the password is expired the KDC will always return - KRB5KDC_ERR_KEY_EXP regardless if the supplied password is correct or - not. In general the password can still be used to get a changepw ticket. - 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, - kr->krb5_ctx->changepw_principle, - kr->options); - krb5_free_cred_contents(kr->ctx, kr->creds); - if (kerr == 0) { - kerr = KRB5KDC_ERR_KEY_EXP; - } - } - - 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); - switch (kerr) { - case KRB5_KDC_UNREACH: - pam_status = PAM_AUTHINFO_UNAVAIL; - break; - case KRB5KDC_ERR_KEY_EXP: - pam_status = PAM_AUTHTOK_EXPIRED; - break; - case KRB5KDC_ERR_PREAUTH_FAILED: - pam_status = PAM_CRED_ERR; - break; - default: - pam_status = PAM_SYSTEM_ERR; - } - } - -sendresponse: - ret = sendresponse(fd, kerr, NULL, pam_status, kr); - if (ret != EOK) { - DEBUG(1, ("sendresponse failed.\n")); - } - - return ret; -} - -static errno_t create_empty_ccache(int fd, struct krb5_req *kr) -{ - int ret; - int pam_status = PAM_SUCCESS; - - ret = create_ccache_file(kr, NULL); - if (ret != 0) { - KRB5_DEBUG(1, ret); - pam_status = PAM_SYSTEM_ERR; - } - - ret = sendresponse(fd, ret, NULL, pam_status, kr); - if (ret != EOK) { - DEBUG(1, ("sendresponse failed.\n")); - } - - return ret; -} - -static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd, - char **ccname, char **keytab, uint32_t *validate, - uint32_t *offline) -{ - size_t p = 0; - uint32_t len; - - COPY_UINT32_CHECK(&pd->cmd, buf + p, p, size); - COPY_UINT32_CHECK(&pd->pw_uid, buf + p, p, size); - COPY_UINT32_CHECK(&pd->gr_gid, buf + p, p, size); - COPY_UINT32_CHECK(validate, buf + p, p, size); - COPY_UINT32_CHECK(offline, buf + p, p, size); - - COPY_UINT32_CHECK(&len, buf + p, p, size); - if ((p + len ) > size) return EINVAL; - pd->upn = talloc_strndup(pd, (char *)(buf + p), len); - if (pd->upn == NULL) return ENOMEM; - p += len; - - COPY_UINT32_CHECK(&len, buf + p, p, size); - if ((p + len ) > size) return EINVAL; - *ccname = talloc_strndup(pd, (char *)(buf + p), len); - if (*ccname == NULL) return ENOMEM; - p += len; - - COPY_UINT32_CHECK(&len, buf + p, p, size); - if ((p + len ) > size) return EINVAL; - *keytab = talloc_strndup(pd, (char *)(buf + p), len); - if (*keytab == NULL) return ENOMEM; - p += len; - - COPY_UINT32_CHECK(&len, buf + p, p, size); - if ((p + len) > size) return EINVAL; - pd->authtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->authtok == NULL) return ENOMEM; - pd->authtok_size = len + 1; - p += len; - - if (pd->cmd == SSS_PAM_CHAUTHTOK) { - COPY_UINT32_CHECK(&len, buf + p, p, size); - - if ((p + len) > size) return EINVAL; - pd->newauthtok = (uint8_t *)talloc_strndup(pd, (char *)(buf + p), len); - if (pd->newauthtok == NULL) return ENOMEM; - pd->newauthtok_size = len + 1; - p += len; - } else { - pd->newauthtok = NULL; - pd->newauthtok_size = 0; - } - - return EOK; -} - -static int krb5_cleanup(void *ptr) -{ - struct krb5_req *kr = talloc_get_type(ptr, struct krb5_req); - if (kr == NULL) return EOK; - - if (kr->options != NULL) { - sss_krb5_get_init_creds_opt_free(kr->ctx, kr->options); - } - - if (kr->creds != NULL) { - krb5_free_cred_contents(kr->ctx, kr->creds); - krb5_free_creds(kr->ctx, kr->creds); - } - if (kr->name != NULL) - sss_krb5_free_unparsed_name(kr->ctx, kr->name); - if (kr->princ != NULL) - krb5_free_principal(kr->ctx, kr->princ); - if (kr->ctx != NULL) - krb5_free_context(kr->ctx); - - if (kr->krb5_ctx != NULL) { - memset(kr->krb5_ctx, 0, sizeof(struct krb5_child_ctx)); - } - memset(kr, 0, sizeof(struct krb5_req)); - - return EOK; -} - -static int krb5_setup(struct pam_data *pd, const char *user_princ_str, - uint32_t offline, struct krb5_req **krb5_req) -{ - struct krb5_req *kr = NULL; - krb5_error_code kerr = 0; - - kr = talloc_zero(pd, struct krb5_req); - if (kr == NULL) { - DEBUG(1, ("talloc failed.\n")); - kerr = ENOMEM; - goto failed; - } - talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup); - - kr->krb5_ctx = talloc_zero(kr, struct krb5_child_ctx); - if (kr->krb5_ctx == NULL) { - DEBUG(1, ("talloc failed.\n")); - kerr = ENOMEM; - goto failed; - } - - kr->krb5_ctx->changepw_principle = getenv(SSSD_KRB5_CHANGEPW_PRINCIPLE); - if (kr->krb5_ctx->changepw_principle == NULL) { - DEBUG(1, ("Cannot read [%s] from environment.\n", - SSSD_KRB5_CHANGEPW_PRINCIPLE)); - if (pd->cmd == SSS_PAM_CHAUTHTOK) { - goto failed; - } - } - - kr->krb5_ctx->realm = getenv(SSSD_KRB5_REALM); - if (kr->krb5_ctx->realm == NULL) { - DEBUG(2, ("Cannot read [%s] from environment.\n", SSSD_KRB5_REALM)); - } - - kr->pd = pd; - - switch(pd->cmd) { - case SSS_PAM_AUTHENTICATE: - /* If we are offline, we need to create an empty ccache file */ - if (offline) { - kr->child_req = create_empty_ccache; - } else { - kr->child_req = tgt_req_child; - } - break; - case SSS_PAM_CHAUTHTOK: - case SSS_PAM_CHAUTHTOK_PRELIM: - kr->child_req = 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); - goto failed; - } - - kerr = krb5_parse_name(kr->ctx, user_princ_str, &kr->princ); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto failed; - } - - kerr = krb5_unparse_name(kr->ctx, kr->princ, &kr->name); - if (kerr != 0) { - KRB5_DEBUG(1, kerr); - goto failed; - } - - kr->creds = calloc(1, sizeof(krb5_creds)); - if (kr->creds == NULL) { - DEBUG(1, ("talloc_zero failed.\n")); - kerr = ENOMEM; - goto failed; - } - - kerr = sss_krb5_get_init_creds_opt_alloc(kr->ctx, &kr->options); - 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 - * krb5_get_init_creds_opt_set_forwardable - * krb5_get_init_creds_opt_set_proxiable - * krb5_get_init_creds_opt_set_etype_list - * krb5_get_init_creds_opt_set_address_list - * krb5_get_init_creds_opt_set_preauth_list - * krb5_get_init_creds_opt_set_salt - * krb5_get_init_creds_opt_set_change_password_prompt - * krb5_get_init_creds_opt_set_pa - */ - - *krb5_req = kr; - return EOK; - -failed: - talloc_free(kr); - - return kerr; -} - -int main(int argc, const char *argv[]) -{ - uint8_t *buf = NULL; - int ret; - ssize_t len = 0; - struct pam_data *pd = NULL; - struct krb5_req *kr = NULL; - char *ccname; - char *keytab; - uint32_t validate; - uint32_t offline; - int opt; - poptContext pc; - int debug_fd = -1; - - struct poptOption long_options[] = { - POPT_AUTOHELP - {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0, - _("Debug level"), NULL}, - {"debug-timestamps", 0, POPT_ARG_INT, &debug_timestamps, 0, - _("Add debug timestamps"), NULL}, - {"debug-fd", 0, POPT_ARG_INT, &debug_fd, 0, - _("An open file descriptor for the debug logs"), NULL}, - POPT_TABLEEND - }; - - - pc = poptGetContext(argv[0], argc, argv, long_options, 0); - while((opt = poptGetNextOpt(pc)) != -1) { - switch(opt) { - default: - fprintf(stderr, "\nInvalid option %s: %s\n\n", - poptBadOption(pc, 0), poptStrerror(opt)); - poptPrintUsage(pc, stderr, 0); - _exit(-1); - } - } - - poptFreeContext(pc); - - DEBUG(7, ("krb5_child started.\n")); - - pd = talloc(NULL, struct pam_data); - if (pd == NULL) { - DEBUG(1, ("malloc failed.\n")); - _exit(-1); - } - - debug_prg_name = talloc_asprintf(pd, "[sssd[krb5_child[%d]]]", getpid()); - - if (debug_fd != -1) { - ret = set_debug_file_from_fd(debug_fd); - if (ret != EOK) { - DEBUG(1, ("set_debug_file_from_fd failed.\n")); - } - } - - buf = talloc_size(pd, sizeof(uint8_t)*IN_BUF_SIZE); - if (buf == NULL) { - DEBUG(1, ("malloc failed.\n")); - _exit(-1); - } - - while ((ret = read(STDIN_FILENO, buf + len, IN_BUF_SIZE - len)) != 0) { - if (ret == -1) { - if (errno == EINTR || errno == EAGAIN) { - continue; - } - DEBUG(1, ("read failed [%d][%s].\n", errno, strerror(errno))); - goto fail; - } else if (ret > 0) { - len += ret; - if (len > IN_BUF_SIZE) { - DEBUG(1, ("read too much, this should never happen.\n")); - goto fail; - } - continue; - } else { - DEBUG(1, ("unexpected return code of read [%d].\n", ret)); - goto fail; - } - } - close(STDIN_FILENO); - - ret = unpack_buffer(buf, len, pd, &ccname, &keytab, &validate, &offline); - if (ret != EOK) { - DEBUG(1, ("unpack_buffer failed.\n")); - goto fail; - } - - ret = krb5_setup(pd, pd->upn, offline, &kr); - if (ret != EOK) { - DEBUG(1, ("krb5_setup failed.\n")); - goto fail; - } - kr->ccname = ccname; - kr->keytab = keytab; - kr->validate = (validate == 0) ? false : true; - - ret = kr->child_req(STDOUT_FILENO, kr); - if (ret != EOK) { - DEBUG(1, ("Child request failed.\n")); - goto fail; - } - - close(STDOUT_FILENO); - talloc_free(pd); - - return 0; - -fail: - close(STDOUT_FILENO); - talloc_free(pd); - exit(-1); -} diff --git a/server/providers/krb5/krb5_common.c b/server/providers/krb5/krb5_common.c deleted file mode 100644 index 86676f44..00000000 --- a/server/providers/krb5/krb5_common.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - SSSD - - Kerberos Provider Common Functions - - Authors: - Sumit Bose - - Copyright (C) 2008-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 . -*/ -#include -#include -#include -#include - -#include "providers/dp_backend.h" -#include "providers/krb5/krb5_common.h" - -struct dp_option default_krb5_opts[] = { - { "krb5_kdcip", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "krb5_ccachedir", DP_OPT_STRING, { "/tmp" }, NULL_STRING }, - { "krb5_ccname_template", DP_OPT_STRING, { "FILE:%d/krb5cc_%U_XXXXXX" }, NULL_STRING}, - { "krb5_changepw_principal", DP_OPT_STRING, { "kadmin/changepw" }, NULL_STRING }, - { "krb5_auth_timeout", DP_OPT_NUMBER, { .number = 15 }, NULL_NUMBER }, - { "krb5_keytab", DP_OPT_STRING, { "/etc/krb5.keytab" }, NULL_STRING }, - { "krb5_validate", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE } -}; - -errno_t check_and_export_options(struct dp_option *opts, - struct sss_domain_info *dom) -{ - int ret; - char *value; - const char *realm; - const char *dummy; - struct stat stat_buf; - char **list; - - realm = dp_opt_get_cstring(opts, KRB5_REALM); - if (realm == NULL) { - ret = dp_opt_set_string(opts, KRB5_REALM, dom->name); - if (ret != EOK) { - DEBUG(1, ("dp_opt_set_string failed.\n")); - return ret; - } - realm = dom->name; - } - - ret = setenv(SSSD_KRB5_REALM, realm, 1); - if (ret != EOK) { - DEBUG(2, ("setenv %s failed, authentication might fail.\n", - SSSD_KRB5_REALM)); - } - - dummy = dp_opt_get_cstring(opts, KRB5_KDC); - if (dummy == NULL) { - DEBUG(1, ("No KDC expicitly configured, using defaults")); - } else { - ret = split_on_separator(opts, dummy, ',', true, &list, NULL); - if (ret != EOK) { - DEBUG(1, ("Failed to parse server list!\n")); - return ret; - } - ret = write_kdcinfo_file(realm, list[0]); - if (ret != EOK) { - DEBUG(1, ("write_kdcinfo_file failed, " - "using kerberos defaults from /etc/krb5.conf")); - } - talloc_free(list); - } - - dummy = dp_opt_get_cstring(opts, KRB5_CCACHEDIR); - ret = lstat(dummy, &stat_buf); - if (ret != EOK) { - DEBUG(1, ("lstat for [%s] failed: [%d][%s].\n", dummy, errno, - strerror(errno))); - return ret; - } - if ( !S_ISDIR(stat_buf.st_mode) ) { - DEBUG(1, ("Value of krb5ccache_dir [%s] is not a directory.\n", dummy)); - return EINVAL; - } - - dummy = dp_opt_get_cstring(opts, KRB5_CCNAME_TMPL); - if (dummy == NULL) { - DEBUG(1, ("Missing credential cache name template.\n")); - return EINVAL; - } - if (dummy[0] != '/' && strncmp(dummy, "FILE:", 5) != 0) { - DEBUG(1, ("Currently only file based credential caches are supported " - "and krb5ccname_template must start with '/' or 'FILE:'\n")); - return EINVAL; - } - - dummy = dp_opt_get_cstring(opts, KRB5_CHANGEPW_PRINC); - if (dummy == NULL) { - DEBUG(1, ("Missing change password principle.\n")); - return EINVAL; - } - if (strchr(dummy, '@') == NULL) { - value = talloc_asprintf(opts, "%s@%s", dummy, realm); - if (value == NULL) { - DEBUG(7, ("talloc_asprintf failed.\n")); - return ENOMEM; - } - ret = dp_opt_set_string(opts, KRB5_CHANGEPW_PRINC, value); - if (ret != EOK) { - DEBUG(1, ("dp_opt_set_string failed.\n")); - return ret; - } - dummy = value; - } - - ret = setenv(SSSD_KRB5_CHANGEPW_PRINCIPLE, dummy, 1); - if (ret != EOK) { - DEBUG(2, ("setenv %s failed, password change might fail.\n", - SSSD_KRB5_CHANGEPW_PRINCIPLE)); - } - - return EOK; -} - -errno_t krb5_get_options(TALLOC_CTX *memctx, struct confdb_ctx *cdb, - const char *conf_path, struct dp_option **_opts) -{ - int ret; - struct dp_option *opts; - - opts = talloc_zero(memctx, struct dp_option); - if (opts == NULL) { - DEBUG(1, ("talloc_zero failed.\n")); - return ENOMEM; - } - - ret = dp_get_options(opts, cdb, conf_path, default_krb5_opts, - KRB5_OPTS, &opts); - if (ret != EOK) { - DEBUG(1, ("dp_get_options failed.\n")); - goto done; - } - - *_opts = opts; - ret = EOK; - -done: - if (ret != EOK) { - talloc_zfree(opts); - } - - return ret; -} - -errno_t write_kdcinfo_file(const char *realm, const char *kdc) -{ - int ret; - int fd = -1; - char *tmp_name = NULL; - char *kdcinfo_name = NULL; - TALLOC_CTX *tmp_ctx = NULL; - int kdc_len; - - if (realm == NULL || *realm == '\0' || kdc == NULL || *kdc == '\0') { - DEBUG(1, ("Missing or empty realm or kdc.\n")); - return EINVAL; - } - - kdc_len = strlen(kdc); - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(1, ("talloc_new failed.\n")); - return ENOMEM; - } - - tmp_name = talloc_asprintf(tmp_ctx, PUBCONF_PATH"/.kdcinfo_dummy_XXXXXX"); - if (tmp_name == NULL) { - DEBUG(1, ("talloc_asprintf failed.\n")); - ret = ENOMEM; - goto done; - } - - kdcinfo_name = talloc_asprintf(tmp_ctx, KDCINFO_TMPL, realm); - if (kdcinfo_name == NULL) { - DEBUG(1, ("talloc_asprintf failed.\n")); - ret = ENOMEM; - goto done; - } - - fd = mkstemp(tmp_name); - if (fd == -1) { - DEBUG(1, ("mkstemp failed [%d][%s].\n", errno, strerror(errno))); - ret = errno; - goto done; - } - - ret = write(fd, kdc, kdc_len); - if (ret == -1) { - DEBUG(1, ("write failed [%d][%s].\n", errno, strerror(errno))); - goto done; - } - if (ret != kdc_len) { - DEBUG(1, ("Partial write occured, this should never happen.\n")); - ret = EINTR; - goto done; - } - - ret = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); - if (ret == -1) { - DEBUG(1, ("fchmod failed [%d][%s].\n", errno, strerror(errno))); - goto done; - } - - ret = close(fd); - if (ret == -1) { - DEBUG(1, ("close failed [%d][%s].\n", errno, strerror(errno))); - goto done; - } - - ret = rename(tmp_name, kdcinfo_name); - if (ret == -1) { - DEBUG(1, ("rename failed [%d][%s].\n", errno, strerror(errno))); - goto done; - } - -done: - talloc_free(tmp_ctx); - return ret; -} - -static void krb5_resolve_callback(void *private_data, struct fo_server *server) -{ - struct krb5_service *krb5_service; - struct hostent *srvaddr; - char *address; - int ret; - - krb5_service = talloc_get_type(private_data, struct krb5_service); - if (!krb5_service) { - DEBUG(1, ("FATAL: Bad private_data\n")); - return; - } - - srvaddr = fo_get_server_hostent(server); - if (!srvaddr) { - DEBUG(1, ("FATAL: No hostent available for server (%s)\n", - fo_get_server_name(server))); - return; - } - - address = talloc_asprintf(krb5_service, "%s", srvaddr->h_name); - if (!address) { - DEBUG(1, ("Failed to copy address ...\n")); - return; - } - - talloc_zfree(krb5_service->address); - krb5_service->address = address; - - ret = write_kdcinfo_file(krb5_service->realm, address); - if (ret != EOK) { - DEBUG(2, ("write_kdcinfo_file failed, authentication might fail.\n")); - } - - return; -} - - -int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, - const char *service_name, const char *servers, - const char *realm, struct krb5_service **_service) -{ - TALLOC_CTX *tmp_ctx; - struct krb5_service *service; - char **list = NULL; - int ret; - int i; - - tmp_ctx = talloc_new(memctx); - if (!tmp_ctx) { - return ENOMEM; - } - - service = talloc_zero(tmp_ctx, struct krb5_service); - if (!service) { - ret = ENOMEM; - goto done; - } - - ret = be_fo_add_service(ctx, service_name); - if (ret != EOK) { - DEBUG(1, ("Failed to create failover service!\n")); - goto done; - } - - service->name = talloc_strdup(service, service_name); - if (!service->name) { - ret = ENOMEM; - goto done; - } - - service->realm = talloc_strdup(service, realm); - if (!service->realm) { - ret = ENOMEM; - goto done; - } - - ret = split_on_separator(tmp_ctx, servers, ',', true, &list, NULL); - if (ret != EOK) { - DEBUG(1, ("Failed to parse server list!\n")); - goto done; - } - - for (i = 0; list[i]; i++) { - - talloc_steal(service, list[i]); - - ret = be_fo_add_server(ctx, service_name, list[i], 0, NULL); - if (ret && ret != EEXIST) { - DEBUG(0, ("Failed to add server\n")); - goto done; - } - - DEBUG(6, ("Added Server %s\n", list[i])); - } - - ret = be_fo_service_add_callback(memctx, ctx, service_name, - krb5_resolve_callback, service); - if (ret != EOK) { - DEBUG(1, ("Failed to add failover callback!\n")); - goto done; - } - - ret = EOK; - -done: - if (ret == EOK) { - *_service = talloc_steal(memctx, service); - } - talloc_zfree(tmp_ctx); - return ret; -} - diff --git a/server/providers/krb5/krb5_common.h b/server/providers/krb5/krb5_common.h deleted file mode 100644 index 832ffcdd..00000000 --- a/server/providers/krb5/krb5_common.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - SSSD - - Kerberos Backend, common header file - - Authors: - Sumit Bose - - 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 . -*/ - -#ifndef __KRB5_COMMON_H__ -#define __KRB5_COMMON_H__ - -#include "config.h" -#include - -#include "providers/dp_backend.h" -#include "util/util.h" -#include "util/sss_krb5.h" - -#define SSSD_KRB5_KDC "SSSD_KRB5_KDC" -#define SSSD_KRB5_REALM "SSSD_KRB5_REALM" -#define SSSD_KRB5_CHANGEPW_PRINCIPLE "SSSD_KRB5_CHANGEPW_PRINCIPLE" - -#define KDCINFO_TMPL PUBCONF_PATH"/kdcinfo.%s" - -enum krb5_opts { - KRB5_KDC = 0, - KRB5_REALM, - KRB5_CCACHEDIR, - KRB5_CCNAME_TMPL, - KRB5_CHANGEPW_PRINC, - KRB5_AUTH_TIMEOUT, - KRB5_KEYTAB, - KRB5_VALIDATE, - - KRB5_OPTS -}; - -struct krb5_service { - char *name; - char *address; - char *realm; -}; - -errno_t check_and_export_options(struct dp_option *opts, - struct sss_domain_info *dom); - -errno_t krb5_get_options(TALLOC_CTX *memctx, struct confdb_ctx *cdb, - const char *conf_path, struct dp_option **_opts); - -errno_t write_kdcinfo_file(const char *realm, const char *kdc); - -int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, - const char *service_name, const char *servers, - const char *realm, struct krb5_service **_service); -#endif /* __KRB5_COMMON_H__ */ diff --git a/server/providers/krb5/krb5_init.c b/server/providers/krb5/krb5_init.c deleted file mode 100644 index 43cbc1bc..00000000 --- a/server/providers/krb5/krb5_init.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - SSSD - - Kerberos 5 Backend Module - - Authors: - Sumit Bose - - 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 . -*/ - -#include -#include -#include -#include -#include "providers/child_common.h" -#include "providers/krb5/krb5_auth.h" -#include "providers/krb5/krb5_common.h" - -struct krb5_options { - struct dp_option *opts; - struct krb5_ctx *auth_ctx; -}; - -struct krb5_options *krb5_options = NULL; - -struct bet_ops krb5_auth_ops = { - .handler = krb5_pam_handler, - .finalize = NULL, -}; - -int sssm_krb5_auth_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_auth_data) -{ - struct krb5_ctx *ctx = NULL; - int ret; - struct tevent_signal *sige; - unsigned v; - FILE *debug_filep; - const char *krb5_servers; - const char *krb5_realm; - - if (krb5_options == NULL) { - krb5_options = talloc_zero(bectx, struct krb5_options); - if (krb5_options == NULL) { - DEBUG(1, ("talloc_zero failed.\n")); - return ENOMEM; - } - ret = krb5_get_options(krb5_options, bectx->cdb, bectx->conf_path, - &krb5_options->opts); - if (ret != EOK) { - DEBUG(1, ("krb5_get_options failed.\n")); - return ret; - } - } - - if (krb5_options->auth_ctx != NULL) { - *ops = &krb5_auth_ops; - *pvt_auth_data = krb5_options->auth_ctx; - return EOK; - } - - ctx = talloc_zero(bectx, struct krb5_ctx); - if (!ctx) { - DEBUG(1, ("talloc failed.\n")); - return ENOMEM; - } - - ctx->action = INIT_PW; - ctx->opts = krb5_options->opts; - - krb5_servers = dp_opt_get_string(ctx->opts, KRB5_KDC); - if (krb5_servers == NULL) { - DEBUG(0, ("Missing krb5_kdcip option!\n")); - return EINVAL; - } - - krb5_realm = dp_opt_get_string(ctx->opts, KRB5_REALM); - if (krb5_realm == NULL) { - DEBUG(0, ("Missing krb5_realm option!\n")); - return EINVAL; - } - - ret = krb5_service_init(ctx, bectx, "KRB5", krb5_servers, krb5_realm, - &ctx->service); - if (ret != EOK) { - DEBUG(0, ("Failed to init IPA failover service!\n")); - return ret; - } - - ret = check_and_export_options(ctx->opts, bectx->domain); - if (ret != EOK) { - DEBUG(1, ("check_and_export_options failed.\n")); - goto fail; - } - - sige = tevent_add_signal(bectx->ev, ctx, SIGCHLD, SA_SIGINFO, - child_sig_handler, NULL); - if (sige == NULL) { - DEBUG(1, ("tevent_add_signal failed.\n")); - ret = ENOMEM; - goto fail; - } - - if (debug_to_file != 0) { - ret = open_debug_file_ex("krb5_child", &debug_filep); - if (ret != EOK) { - DEBUG(0, ("Error setting up logging (%d) [%s]\n", - ret, strerror(ret))); - goto fail; - } - - ctx->child_debug_fd = fileno(debug_filep); - if (ctx->child_debug_fd == -1) { - DEBUG(0, ("fileno failed [%d][%s]\n", errno, strerror(errno))); - ret = errno; - goto fail; - } - - v = fcntl(ctx->child_debug_fd, F_GETFD, 0); - fcntl(ctx->child_debug_fd, F_SETFD, v & ~FD_CLOEXEC); - } - - *ops = &krb5_auth_ops; - *pvt_auth_data = ctx; - return EOK; - -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_utils.c b/server/providers/krb5/krb5_utils.c deleted file mode 100644 index 489030af..00000000 --- a/server/providers/krb5/krb5_utils.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - SSSD - - Kerberos 5 Backend Module -- Utilities - - Authors: - Sumit Bose - - 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 . -*/ -#include -#include - -#include "providers/krb5/krb5_utils.h" -#include "providers/krb5/krb5_auth.h" -#include "util/util.h" - -char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, - const char *template) -{ - char *copy; - char *p; - char *n; - char *result = NULL; - const char *dummy; - - if (template == NULL) { - DEBUG(1, ("Missing template.\n")); - return NULL; - } - - copy = talloc_strdup(mem_ctx, template); - if (copy == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - return NULL; - } - - result = talloc_strdup(mem_ctx, ""); - if (result == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - return NULL; - } - - p = copy; - while ( (n = strchr(p, '%')) != NULL) { - *n = '\0'; - n++; - if ( *n == '\0' ) { - DEBUG(1, ("format error, single %% at the end of the template.\n")); - return NULL; - } - - switch( *n ) { - case 'u': - if (kr->pd->user == NULL) { - DEBUG(1, ("Cannot expand user name template " - "because user name is empty.\n")); - return NULL; - } - result = talloc_asprintf_append(result, "%s%s", p, - kr->pd->user); - break; - case 'U': - if (kr->pd->pw_uid <= 0) { - DEBUG(1, ("Cannot expand uid template " - "because uid is invalid.\n")); - return NULL; - } - result = talloc_asprintf_append(result, "%s%d", p, - kr->pd->pw_uid); - break; - case 'p': - if (kr->pd->upn == NULL) { - DEBUG(1, ("Cannot expand user principle name template " - "because upn is empty.\n")); - return NULL; - } - result = talloc_asprintf_append(result, "%s%s", p, kr->pd->upn); - break; - case '%': - result = talloc_asprintf_append(result, "%s%%", p); - break; - case 'r': - dummy = dp_opt_get_string(kr->krb5_ctx->opts, KRB5_REALM); - if (dummy == NULL) { - DEBUG(1, ("Missing kerberos realm.\n")); - return NULL; - } - result = talloc_asprintf_append(result, "%s%s", p, dummy); - break; - case 'h': - if (kr->homedir == NULL) { - DEBUG(1, ("Cannot expand home directory template " - "because the path is not available.\n")); - return NULL; - } - result = talloc_asprintf_append(result, "%s%s", p, kr->homedir); - break; - case 'd': - dummy = dp_opt_get_string(kr->krb5_ctx->opts, KRB5_CCACHEDIR); - if (dummy == NULL) { - DEBUG(1, ("Missing credential cache directory.\n")); - return NULL; - } - result = talloc_asprintf_append(result, "%s%s", p, dummy); - break; - case 'P': - if (kr->pd->cli_pid == 0) { - DEBUG(1, ("Cannot expand PID template " - "because PID is not available.\n")); - return NULL; - } - result = talloc_asprintf_append(result, "%s%d", p, - kr->pd->cli_pid); - break; - default: - DEBUG(1, ("format error, unknown template [%%%c].\n", *n)); - return NULL; - } - - if (result == NULL) { - DEBUG(1, ("talloc_asprintf_append failed.\n")); - return NULL; - } - - p = n + 1; - } - - result = talloc_asprintf_append(result, "%s", p); - - return result; -} diff --git a/server/providers/krb5/krb5_utils.h b/server/providers/krb5/krb5_utils.h deleted file mode 100644 index 7637041a..00000000 --- a/server/providers/krb5/krb5_utils.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - SSSD - - Kerberos Backend, header file for utilities - - Authors: - Sumit Bose - - 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 . -*/ - -#ifndef __KRB5_UTILS_H__ -#define __KRB5_UTILS_H__ - -#include - -#include "providers/krb5/krb5_auth.h" -#include "providers/data_provider.h" - -char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, - const char *template); - -errno_t become_user(uid_t uid, gid_t gid); - -#endif /* __KRB5_UTILS_H__ */ -- cgit