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/child_common.c | 416 ---- server/providers/child_common.h | 73 - server/providers/data_provider.h | 219 --- server/providers/data_provider_be.c | 1235 ------------ server/providers/data_provider_fo.c | 356 ---- server/providers/data_provider_opts.c | 384 ---- server/providers/dp_auth_util.c | 414 ---- server/providers/dp_backend.h | 142 -- server/providers/dp_sbus.c | 45 - server/providers/fail_over.c | 651 ------- server/providers/fail_over.h | 108 -- server/providers/ipa/ipa_access.c | 1823 ------------------ server/providers/ipa/ipa_access.h | 66 - server/providers/ipa/ipa_auth.c | 313 --- server/providers/ipa/ipa_auth.h | 32 - server/providers/ipa/ipa_common.c | 597 ------ server/providers/ipa/ipa_common.h | 83 - server/providers/ipa/ipa_init.c | 293 --- server/providers/ipa/ipa_timerules.c | 1186 ------------ server/providers/ipa/ipa_timerules.h | 56 - 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 - server/providers/ldap/ldap_auth.c | 1055 ----------- server/providers/ldap/ldap_child.c | 429 ----- server/providers/ldap/ldap_common.c | 589 ------ server/providers/ldap/ldap_common.h | 115 -- server/providers/ldap/ldap_id.c | 795 -------- server/providers/ldap/ldap_id_cleanup.c | 555 ------ server/providers/ldap/ldap_id_enum.c | 608 ------ server/providers/ldap/ldap_init.c | 179 -- server/providers/ldap/sdap.c | 388 ---- server/providers/ldap/sdap.h | 258 --- server/providers/ldap/sdap_async.c | 1018 ---------- server/providers/ldap/sdap_async.h | 126 -- server/providers/ldap/sdap_async_accounts.c | 2065 -------------------- server/providers/ldap/sdap_async_connection.c | 1141 ----------- server/providers/ldap/sdap_async_private.h | 68 - server/providers/ldap/sdap_child_helpers.c | 462 ----- server/providers/providers.h | 24 - server/providers/proxy.c | 2521 ------------------------- server/providers/sssd_be.exports | 4 - 48 files changed, 24031 deletions(-) delete mode 100644 server/providers/child_common.c delete mode 100644 server/providers/child_common.h delete mode 100644 server/providers/data_provider.h delete mode 100644 server/providers/data_provider_be.c delete mode 100644 server/providers/data_provider_fo.c delete mode 100644 server/providers/data_provider_opts.c delete mode 100644 server/providers/dp_auth_util.c delete mode 100644 server/providers/dp_backend.h delete mode 100644 server/providers/dp_sbus.c delete mode 100644 server/providers/fail_over.c delete mode 100644 server/providers/fail_over.h delete mode 100644 server/providers/ipa/ipa_access.c delete mode 100644 server/providers/ipa/ipa_access.h delete mode 100644 server/providers/ipa/ipa_auth.c delete mode 100644 server/providers/ipa/ipa_auth.h delete mode 100644 server/providers/ipa/ipa_common.c delete mode 100644 server/providers/ipa/ipa_common.h delete mode 100644 server/providers/ipa/ipa_init.c delete mode 100644 server/providers/ipa/ipa_timerules.c delete mode 100644 server/providers/ipa/ipa_timerules.h 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 delete mode 100644 server/providers/ldap/ldap_auth.c delete mode 100644 server/providers/ldap/ldap_child.c delete mode 100644 server/providers/ldap/ldap_common.c delete mode 100644 server/providers/ldap/ldap_common.h delete mode 100644 server/providers/ldap/ldap_id.c delete mode 100644 server/providers/ldap/ldap_id_cleanup.c delete mode 100644 server/providers/ldap/ldap_id_enum.c delete mode 100644 server/providers/ldap/ldap_init.c delete mode 100644 server/providers/ldap/sdap.c delete mode 100644 server/providers/ldap/sdap.h delete mode 100644 server/providers/ldap/sdap_async.c delete mode 100644 server/providers/ldap/sdap_async.h delete mode 100644 server/providers/ldap/sdap_async_accounts.c delete mode 100644 server/providers/ldap/sdap_async_connection.c delete mode 100644 server/providers/ldap/sdap_async_private.h delete mode 100644 server/providers/ldap/sdap_child_helpers.c delete mode 100644 server/providers/providers.h delete mode 100644 server/providers/proxy.c delete mode 100644 server/providers/sssd_be.exports (limited to 'server/providers') diff --git a/server/providers/child_common.c b/server/providers/child_common.c deleted file mode 100644 index 2ad0f04e3..000000000 --- a/server/providers/child_common.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - SSSD - - Common helper functions to be used in child processes - - 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/find_uid.h" -#include "db/sysdb.h" -#include "providers/child_common.h" - -/* Async communication with the child process via a pipe */ - -struct write_pipe_state { - int fd; - uint8_t *buf; - size_t len; - size_t written; -}; - -static void write_pipe_handler(struct tevent_context *ev, - struct tevent_fd *fde, - uint16_t flags, void *pvt); - -struct tevent_req *write_pipe_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - uint8_t *buf, size_t len, int fd) -{ - struct tevent_req *req; - struct write_pipe_state *state; - struct tevent_fd *fde; - - req = tevent_req_create(mem_ctx, &state, struct write_pipe_state); - if (req == NULL) return NULL; - - state->fd = fd; - state->buf = buf; - state->len = len; - state->written = 0; - - fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, - write_pipe_handler, req); - if (fde == NULL) { - DEBUG(1, ("tevent_add_fd failed.\n")); - goto fail; - } - - return req; - -fail: - talloc_zfree(req); - return NULL; -} - -static void write_pipe_handler(struct tevent_context *ev, - struct tevent_fd *fde, - uint16_t flags, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct write_pipe_state *state = tevent_req_data(req, - struct write_pipe_state); - ssize_t size; - - if (flags & TEVENT_FD_READ) { - DEBUG(1, ("write_pipe_done called with TEVENT_FD_READ," - " this should not happen.\n")); - tevent_req_error(req, EINVAL); - return; - } - - size = write(state->fd, - state->buf + state->written, - state->len - state->written); - if (size == -1) { - if (errno == EAGAIN || errno == EINTR) return; - DEBUG(1, ("write failed [%d][%s].\n", errno, strerror(errno))); - tevent_req_error(req, errno); - return; - - } else if (size >= 0) { - state->written += size; - if (state->written > state->len) { - DEBUG(1, ("write to much, this should never happen.\n")); - tevent_req_error(req, EINVAL); - return; - } - } else { - DEBUG(1, ("unexpected return value of write [%d].\n", size)); - tevent_req_error(req, EINVAL); - return; - } - - if (state->len == state->written) { - DEBUG(6, ("All data has been sent!\n")); - tevent_req_done(req); - return; - } -} - -int write_pipe_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - -struct read_pipe_state { - int fd; - uint8_t *buf; - size_t len; -}; - -static void read_pipe_handler(struct tevent_context *ev, - struct tevent_fd *fde, - uint16_t flags, void *pvt); - -struct tevent_req *read_pipe_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, int fd) -{ - struct tevent_req *req; - struct read_pipe_state *state; - struct tevent_fd *fde; - - req = tevent_req_create(mem_ctx, &state, struct read_pipe_state); - if (req == NULL) return NULL; - - state->fd = fd; - state->buf = talloc_array(state, uint8_t, MAX_CHILD_MSG_SIZE); - state->len = 0; - if (state->buf == NULL) goto fail; - - fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ, - read_pipe_handler, req); - if (fde == NULL) { - DEBUG(1, ("tevent_add_fd failed.\n")); - goto fail; - } - - return req; - -fail: - talloc_zfree(req); - return NULL; -} - -static void read_pipe_handler(struct tevent_context *ev, - struct tevent_fd *fde, - uint16_t flags, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct read_pipe_state *state = tevent_req_data(req, - struct read_pipe_state); - ssize_t size; - errno_t err; - - if (flags & TEVENT_FD_WRITE) { - DEBUG(1, ("read_pipe_done called with TEVENT_FD_WRITE," - " this should not happen.\n")); - tevent_req_error(req, EINVAL); - return; - } - - size = read(state->fd, - state->buf + state->len, - MAX_CHILD_MSG_SIZE - state->len); - if (size == -1) { - err = errno; - if (err == EAGAIN || err == EINTR) { - return; - } - - DEBUG(1, ("read failed [%d][%s].\n", err, strerror(err))); - tevent_req_error(req, err); - return; - - } else if (size > 0) { - state->len += size; - if (state->len > MAX_CHILD_MSG_SIZE) { - DEBUG(1, ("read to much, this should never happen.\n")); - tevent_req_error(req, EINVAL); - return; - } - - } else if (size == 0) { - DEBUG(6, ("EOF received, client finished\n")); - tevent_req_done(req); - return; - - } else { - DEBUG(1, ("unexpected return value of read [%d].\n", size)); - tevent_req_error(req, EINVAL); - return; - } -} - -int read_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - uint8_t **buf, ssize_t *len) -{ - struct read_pipe_state *state; - state = tevent_req_data(req, struct read_pipe_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *buf = talloc_steal(mem_ctx, state->buf); - *len = state->len; - - return EOK; -} - -/* The pipes to communicate with the child must be nonblocking */ -void fd_nonblocking(int fd) -{ - int flags; - int ret; - - flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) { - ret = errno; - DEBUG(1, ("F_GETFL failed [%d][%s].\n", ret, strerror(ret))); - return; - } - - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { - ret = errno; - DEBUG(1, ("F_SETFL failed [%d][%s].\n", ret, strerror(ret))); - } - - return; -} - -void child_sig_handler(struct tevent_context *ev, - struct tevent_signal *sige, int signum, - int count, void *__siginfo, void *pvt) -{ - int ret; - int child_status; - - DEBUG(7, ("Waiting for [%d] childeren.\n", count)); - do { - errno = 0; - ret = waitpid(-1, &child_status, WNOHANG); - - if (ret == -1) { - DEBUG(1, ("waitpid failed [%d][%s].\n", errno, strerror(errno))); - } else if (ret == 0) { - DEBUG(1, ("waitpid did not found a child with changed status.\n")); - } else { - if (WEXITSTATUS(child_status) != 0) { - DEBUG(1, ("child [%d] failed with status [%d].\n", ret, - child_status)); - } else { - DEBUG(4, ("child [%d] finished successful.\n", ret)); - } - } - - --count; - } while (count < 0); - - return; -} - -static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx, - int child_debug_fd, - const char *binary, - char ***_argv) -{ - uint_t argc = 3; /* program name, debug_level and NULL */ - char ** argv; - errno_t ret = EINVAL; - - /* Save the current state in case an interrupt changes it */ - bool child_debug_to_file = debug_to_file; - bool child_debug_timestamps = debug_timestamps; - - if (child_debug_to_file) argc++; - if (!child_debug_timestamps) argc++; - - /* program name, debug_level, - * debug_to_file, debug_timestamps - * and NULL */ - argv = talloc_array(mem_ctx, char *, argc); - if (argv == NULL) { - DEBUG(1, ("talloc_array failed.\n")); - return ENOMEM; - } - - argv[--argc] = NULL; - - argv[--argc] = talloc_asprintf(argv, "--debug-level=%d", - debug_level); - if (argv[argc] == NULL) { - ret = ENOMEM; - goto fail; - } - - if (child_debug_to_file) { - argv[--argc] = talloc_asprintf(argv, "--debug-fd=%d", - child_debug_fd); - if (argv[argc] == NULL) { - ret = ENOMEM; - goto fail; - } - } - - if (!child_debug_timestamps) { - argv[--argc] = talloc_strdup(argv, "--debug-timestamps=0"); - if (argv[argc] == NULL) { - ret = ENOMEM; - goto fail; - } - } - - argv[--argc] = talloc_strdup(argv, binary); - if (argv[argc] == NULL) { - ret = ENOMEM; - goto fail; - } - - if (argc != 0) { - ret = EINVAL; - goto fail; - } - - *_argv = argv; - - return EOK; - -fail: - talloc_free(argv); - return ret; -} - -errno_t exec_child(TALLOC_CTX *mem_ctx, - int *pipefd_to_child, int *pipefd_from_child, - const char *binary, int debug_fd) -{ - int ret; - errno_t err; - char **argv; - - close(pipefd_to_child[1]); - ret = dup2(pipefd_to_child[0], STDIN_FILENO); - if (ret == -1) { - err = errno; - DEBUG(1, ("dup2 failed [%d][%s].\n", err, strerror(err))); - return err; - } - - close(pipefd_from_child[0]); - ret = dup2(pipefd_from_child[1], STDOUT_FILENO); - if (ret == -1) { - err = errno; - DEBUG(1, ("dup2 failed [%d][%s].\n", err, strerror(err))); - return err; - } - - ret = prepare_child_argv(mem_ctx, debug_fd, - binary, &argv); - if (ret != EOK) { - DEBUG(1, ("prepare_child_argv.\n")); - return ret; - } - - ret = execv(binary, argv); - if (ret == -1) { - err = errno; - DEBUG(1, ("execv failed [%d][%s].\n", err, strerror(err))); - return err; - } - - return EOK; -} - -void child_cleanup(int readfd, int writefd) -{ - int ret; - - if (readfd != -1) { - ret = close(readfd); - if (ret != EOK) { - ret = errno; - DEBUG(1, ("close failed [%d][%s].\n", errno, strerror(errno))); - } - } - if (writefd != -1) { - ret = close(writefd); - if (ret != EOK) { - ret = errno; - DEBUG(1, ("close failed [%d][%s].\n", errno, strerror(errno))); - } - } -} diff --git a/server/providers/child_common.h b/server/providers/child_common.h deleted file mode 100644 index a441df3c5..000000000 --- a/server/providers/child_common.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - SSSD - - Common helper functions to be used in child processes - - 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 __CHILD_COMMON_H__ -#define __CHILD_COMMON_H__ - -#include -#include -#include -#include - -#include "util/util.h" - -#define IN_BUF_SIZE 512 -#define MAX_CHILD_MSG_SIZE 255 - -struct response { - size_t max_size; - size_t size; - uint8_t *buf; -}; - -struct io_buffer { - uint8_t *data; - size_t size; -}; - -/* Async communication with the child process via a pipe */ -struct tevent_req *write_pipe_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - uint8_t *buf, size_t len, int fd); -int write_pipe_recv(struct tevent_req *req); - -struct tevent_req *read_pipe_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, int fd); -int read_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - uint8_t **buf, ssize_t *len); - -/* The pipes to communicate with the child must be nonblocking */ -void fd_nonblocking(int fd); - -void child_sig_handler(struct tevent_context *ev, - struct tevent_signal *sige, int signum, - int count, void *__siginfo, void *pvt); - -errno_t exec_child(TALLOC_CTX *mem_ctx, - int *pipefd_to_child, int *pipefd_from_child, - const char *binary, int debug_fd); - -void child_cleanup(int readfd, int writefd); - -#endif /* __CHILD_COMMON_H__ */ diff --git a/server/providers/data_provider.h b/server/providers/data_provider.h deleted file mode 100644 index 76ba4cffb..000000000 --- a/server/providers/data_provider.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - SSSD - - Data Provider, private header file - - Copyright (C) Simo Sorce 2008 - - 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 __DATA_PROVIDER_H__ -#define __DATA_PROVIDER_H__ - -#include -#include -#include -#include -#include "talloc.h" -#include "tevent.h" -#include "ldb.h" -#include "util/util.h" -#include "confdb/confdb.h" -#include "dbus/dbus.h" -#include "sbus/sssd_dbus.h" -#include "sbus/sbus_client.h" -#include "sss_client/sss_cli.h" - -#define DATA_PROVIDER_VERSION 0x0001 -#define DATA_PROVIDER_SERVICE_NAME "dp" -#define DATA_PROVIDER_PIPE "private/sbus-dp" - -#define DATA_PROVIDER_DB_FILE "sssd.ldb" -#define DATA_PROVIDER_DB_CONF_SEC "config/services/nss" - -#define MOD_OFFLINE 0x0000 -#define MOD_ONLINE 0x0001 - -#define DP_INTERFACE "org.freedesktop.sssd.dataprovider" -#define DP_PATH "/org/freedesktop/sssd/dataprovider" - -#define BE_PROVIDE_ACC_INFO (1<<8) -#define BE_PROVIDE_PAM (1<<9) -#define BE_PROVIDE_POLICY (1<<10) - -#define DP_METHOD_REGISTER "RegisterService" -#define DP_METHOD_ONLINE "getOnline" -#define DP_METHOD_GETACCTINFO "getAccountInfo" -#define DP_METHOD_PAMHANDLER "pamHandler" - -#define DP_ERR_OK 0 -#define DP_ERR_OFFLINE 1 -#define DP_ERR_TIMEOUT 2 -#define DP_ERR_FATAL 3 - -#define BE_ATTR_CORE 1 -#define BE_ATTR_MEM 2 -#define BE_ATTR_ALL 3 - -#define BE_FILTER_NAME 1 -#define BE_FILTER_IDNUM 2 - -#define BE_REQ_USER 0x0001 -#define BE_REQ_GROUP 0x0002 -#define BE_REQ_INITGROUPS 0x0003 -#define BE_REQ_FAST 0x1000 - -/* AUTH related common data and functions */ - -#define DEBUG_PAM_DATA(level, pd) do { \ - if (level <= debug_level) pam_print_data(level, pd); \ -} while(0); - - -struct response_data { - int32_t type; - int32_t len; - uint8_t *data; - struct response_data *next; -}; - -struct pam_data { - int cmd; - uint32_t authtok_type; - uint32_t authtok_size; - uint32_t newauthtok_type; - uint32_t newauthtok_size; - char *domain; - char *user; - char *service; - char *tty; - char *ruser; - char *rhost; - uint8_t *authtok; - uint8_t *newauthtok; - uint32_t cli_pid; - - int pam_status; - int response_delay; - struct response_data *resp_list; - - bool offline_auth; - bool last_auth_saved; - int priv; - uid_t pw_uid; - gid_t gr_gid; - - const char *upn; -}; - -/* from dp_auth_util.c */ -void pam_print_data(int l, struct pam_data *pd); -int pam_add_response(struct pam_data *pd, - enum response_type type, - int len, const uint8_t *data); - -bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd); -bool dp_unpack_pam_request(DBusMessage *msg, struct pam_data *pd, - DBusError *dbus_error); - -bool dp_pack_pam_response(DBusMessage *msg, struct pam_data *pd); -bool dp_unpack_pam_response(DBusMessage *msg, struct pam_data *pd, - DBusError *dbus_error); - -int dp_common_send_id(struct sbus_connection *conn, uint16_t version, - const char *name, const char *domain); - -/* from dp_sbus.c */ -int dp_get_sbus_address(TALLOC_CTX *mem_ctx, - char **address, const char *domain_name); - - -/* Helpers */ - -#define NULL_STRING { .string = NULL } -#define NULL_BLOB { .blob = { NULL, 0 } } -#define NULL_NUMBER { .number = 0 } -#define BOOL_FALSE { .boolean = false } -#define BOOL_TRUE { .boolean = true } - -enum dp_opt_type { - DP_OPT_STRING, - DP_OPT_BLOB, - DP_OPT_NUMBER, - DP_OPT_BOOL -}; - -struct dp_opt_blob { - uint8_t *data; - size_t length; -}; - -union dp_opt_value { - const char *cstring; - char *string; - struct dp_opt_blob blob; - int number; - bool boolean; -}; - -struct dp_option { - const char *opt_name; - enum dp_opt_type type; - union dp_opt_value def_val; - union dp_opt_value val; -}; - -int dp_get_options(TALLOC_CTX *memctx, - struct confdb_ctx *cdb, - const char *conf_path, - struct dp_option *def_opts, - int num_opts, - struct dp_option **_opts); - -int dp_copy_options(TALLOC_CTX *memctx, - struct dp_option *src_opts, - int num_opts, - struct dp_option **_opts); - -const char *_dp_opt_get_cstring(struct dp_option *opts, - int id, const char *location); -char *_dp_opt_get_string(struct dp_option *opts, - int id, const char *location); -struct dp_opt_blob _dp_opt_get_blob(struct dp_option *opts, - int id, const char *location); -int _dp_opt_get_int(struct dp_option *opts, - int id, const char *location); -bool _dp_opt_get_bool(struct dp_option *opts, - int id, const char *location); -#define dp_opt_get_cstring(o, i) _dp_opt_get_cstring(o, i, __FUNCTION__) -#define dp_opt_get_string(o, i) _dp_opt_get_string(o, i, __FUNCTION__) -#define dp_opt_get_blob(o, i) _dp_opt_get_blob(o, i, __FUNCTION__) -#define dp_opt_get_int(o, i) _dp_opt_get_int(o, i, __FUNCTION__) -#define dp_opt_get_bool(o, i) _dp_opt_get_bool(o, i, __FUNCTION__) - -int _dp_opt_set_string(struct dp_option *opts, int id, - const char *s, const char *location); -int _dp_opt_set_blob(struct dp_option *opts, int id, - struct dp_opt_blob b, const char *location); -int _dp_opt_set_int(struct dp_option *opts, int id, - int i, const char *location); -int _dp_opt_set_bool(struct dp_option *opts, int id, - bool b, const char *location); -#define dp_opt_set_string(o, i, v) _dp_opt_set_string(o, i, v, __FUNCTION__) -#define dp_opt_set_blob(o, i, v) _dp_opt_set_blob(o, i, v, __FUNCTION__) -#define dp_opt_set_int(o, i, v) _dp_opt_set_int(o, i, v, __FUNCTION__) -#define dp_opt_set_bool(o, i, v) _dp_opt_set_bool(o, i, v, __FUNCTION__) - -#endif /* __DATA_PROVIDER_ */ diff --git a/server/providers/data_provider_be.c b/server/providers/data_provider_be.c deleted file mode 100644 index 93cae0702..000000000 --- a/server/providers/data_provider_be.c +++ /dev/null @@ -1,1235 +0,0 @@ -/* - SSSD - - Data Provider Process - - Copyright (C) Simo Sorce 2008 - - 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 -#include -#include -#include - -#include -#include - -#include "popt.h" -#include "util/util.h" -#include "confdb/confdb.h" -#include "db/sysdb.h" -#include "dbus/dbus.h" -#include "sbus/sssd_dbus.h" -#include "providers/dp_backend.h" -#include "providers/fail_over.h" -#include "resolv/async_resolv.h" -#include "monitor/monitor_interfaces.h" - -#define MSG_TARGET_NO_CONFIGURED "sssd_be: The requested target is not configured" - -#define ACCESS_PERMIT "permit" -#define ACCESS_DENY "deny" -#define NO_PROVIDER "none" - -static int data_provider_res_init(DBusMessage *message, - struct sbus_connection *conn); -static int data_provider_go_offline(DBusMessage *message, - struct sbus_connection *conn); - -struct sbus_method monitor_be_methods[] = { - { MON_CLI_METHOD_PING, monitor_common_pong }, - { MON_CLI_METHOD_RES_INIT, data_provider_res_init }, - { MON_CLI_METHOD_OFFLINE, data_provider_go_offline }, - { NULL, NULL } -}; - -struct sbus_interface monitor_be_interface = { - MONITOR_INTERFACE, - MONITOR_PATH, - SBUS_DEFAULT_VTABLE, - monitor_be_methods, - NULL -}; - -static int client_registration(DBusMessage *message, struct sbus_connection *conn); -static int be_check_online(DBusMessage *message, struct sbus_connection *conn); -static int be_get_account_info(DBusMessage *message, struct sbus_connection *conn); -static int be_pam_handler(DBusMessage *message, struct sbus_connection *conn); - -struct sbus_method be_methods[] = { - { DP_METHOD_REGISTER, client_registration }, - { DP_METHOD_ONLINE, be_check_online }, - { DP_METHOD_GETACCTINFO, be_get_account_info }, - { DP_METHOD_PAMHANDLER, be_pam_handler }, - { NULL, NULL } -}; - -struct sbus_interface be_interface = { - DP_INTERFACE, - DP_PATH, - SBUS_DEFAULT_VTABLE, - be_methods, - NULL -}; - -static struct bet_data bet_data[] = { - {BET_NULL, NULL, NULL}, - {BET_ID, CONFDB_DOMAIN_ID_PROVIDER, "sssm_%s_init"}, - {BET_AUTH, CONFDB_DOMAIN_AUTH_PROVIDER, "sssm_%s_auth_init"}, - {BET_ACCESS, CONFDB_DOMAIN_ACCESS_PROVIDER, "sssm_%s_access_init"}, - {BET_CHPASS, CONFDB_DOMAIN_CHPASS_PROVIDER, "sssm_%s_chpass_init"}, - {BET_MAX, NULL, NULL} -}; - -struct be_async_req { - be_req_fn_t fn; - struct be_req *req; -}; - -static void be_async_req_handler(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt) -{ - struct be_async_req *async_req; - - async_req = talloc_get_type(pvt, struct be_async_req); - - async_req->fn(async_req->req); -} - -static int be_file_request(struct be_ctx *ctx, - be_req_fn_t fn, - struct be_req *req) -{ - struct be_async_req *areq; - struct tevent_timer *te; - struct timeval tv; - - if (!fn || !req) return EINVAL; - - areq = talloc(req, struct be_async_req); - if (!areq) { - return ENOMEM; - } - areq->fn = fn; - areq->req = req; - - /* fire immediately */ - tv.tv_sec = 0; - tv.tv_usec = 0; - - te = tevent_add_timer(ctx->ev, req, tv, be_async_req_handler, areq); - if (te == NULL) { - return EIO; - } - - return EOK; -} - -bool be_is_offline(struct be_ctx *ctx) -{ - time_t now = time(NULL); - - /* check if we are past the offline blackout timeout */ - /* FIXME: get offline_timeout from configuration */ - if (ctx->offstat.went_offline + 60 < now) { - ctx->offstat.offline = false; - } - - return ctx->offstat.offline; -} - -void be_mark_offline(struct be_ctx *ctx) -{ - DEBUG(8, ("Going offline!\n")); - - ctx->offstat.went_offline = time(NULL); - ctx->offstat.offline = true; -} - -static int be_check_online(DBusMessage *message, struct sbus_connection *conn) -{ - struct be_client *becli; - DBusMessage *reply; - DBusConnection *dbus_conn; - dbus_bool_t dbret; - void *user_data; - dbus_uint16_t online; - dbus_uint16_t err_maj = 0; - dbus_uint32_t err_min = 0; - static const char *err_msg = "Success"; - - user_data = sbus_conn_get_private_data(conn); - if (!user_data) return EINVAL; - becli = talloc_get_type(user_data, struct be_client); - if (!becli) return EINVAL; - - reply = dbus_message_new_method_return(message); - if (!reply) return ENOMEM; - - if (be_is_offline(becli->bectx)) { - online = MOD_OFFLINE; - } else { - online = MOD_ONLINE; - } - - dbret = dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &online, - DBUS_TYPE_UINT16, &err_maj, - DBUS_TYPE_UINT32, &err_min, - DBUS_TYPE_STRING, &err_msg, - DBUS_TYPE_INVALID); - if (!dbret) { - DEBUG(1, ("Failed to generate dbus reply\n")); - return EIO; - } - - dbus_conn = sbus_get_connection(becli->conn); - dbus_connection_send(dbus_conn, reply, NULL); - dbus_message_unref(reply); - - DEBUG(4, ("Request processed. Returned %d,%d,%s\n", - err_maj, err_min, err_msg)); - - return EOK; -} - -static char *dp_err_to_string(TALLOC_CTX *memctx, int dp_err_type, int errnum) -{ - switch (dp_err_type) { - case DP_ERR_OK: - return talloc_strdup(memctx, "Success"); - break; - - case DP_ERR_OFFLINE: - return talloc_asprintf(memctx, - "Provider is Offline (%s)", - strerror(errnum)); - break; - - case DP_ERR_TIMEOUT: - return talloc_asprintf(memctx, - "Request timed out (%s)", - strerror(errnum)); - break; - - case DP_ERR_FATAL: - default: - return talloc_asprintf(memctx, - "Internal Error (%s)", - strerror(errnum)); - break; - } - - return NULL; -} - - -static void acctinfo_callback(struct be_req *req, - int dp_err_type, - int errnum, - const char *errstr) -{ - DBusMessage *reply; - DBusConnection *dbus_conn; - dbus_bool_t dbret; - dbus_uint16_t err_maj = 0; - dbus_uint32_t err_min = 0; - const char *err_msg = NULL; - - reply = (DBusMessage *)req->pvt; - - if (reply) { - /* Return a reply if one was requested - * There may not be one if this request began - * while we were offline - */ - - err_maj = dp_err_type; - err_min = errnum; - if (errstr) { - err_msg = errstr; - } else { - err_msg = dp_err_to_string(req, dp_err_type, errnum); - } - if (!err_msg) { - DEBUG(1, ("Failed to set err_msg, Out of memory?\n")); - err_msg = "OOM"; - } - - dbret = dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &err_maj, - DBUS_TYPE_UINT32, &err_min, - DBUS_TYPE_STRING, &err_msg, - DBUS_TYPE_INVALID); - if (!dbret) { - DEBUG(1, ("Failed to generate dbus reply\n")); - return; - } - - dbus_conn = sbus_get_connection(req->becli->conn); - dbus_connection_send(dbus_conn, reply, NULL); - dbus_message_unref(reply); - - DEBUG(4, ("Request processed. Returned %d,%d,%s\n", - err_maj, err_min, err_msg)); - } - - /* finally free the request */ - talloc_free(req); -} - -static int be_get_account_info(DBusMessage *message, struct sbus_connection *conn) -{ - struct be_acct_req *req; - struct be_req *be_req; - struct be_client *becli; - DBusMessage *reply; - DBusError dbus_error; - dbus_bool_t dbret; - void *user_data; - uint32_t type; - char *filter; - int filter_type; - uint32_t attr_type; - char *filter_val; - int ret; - dbus_uint16_t err_maj; - dbus_uint32_t err_min; - const char *err_msg; - - be_req = NULL; - - user_data = sbus_conn_get_private_data(conn); - if (!user_data) return EINVAL; - becli = talloc_get_type(user_data, struct be_client); - if (!becli) return EINVAL; - - dbus_error_init(&dbus_error); - - ret = dbus_message_get_args(message, &dbus_error, - DBUS_TYPE_UINT32, &type, - DBUS_TYPE_UINT32, &attr_type, - DBUS_TYPE_STRING, &filter, - DBUS_TYPE_INVALID); - if (!ret) { - DEBUG(1,("Failed, to parse message!\n")); - if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error); - return EIO; - } - - DEBUG(4, ("Got request for [%u][%d][%s]\n", type, attr_type, filter)); - - reply = dbus_message_new_method_return(message); - if (!reply) return ENOMEM; - - /* If we are offline and fast reply was requested - * return offline immediately - */ - if ((type & BE_REQ_FAST) && becli->bectx->offstat.offline) { - /* Send back an immediate reply */ - err_maj = DP_ERR_OFFLINE; - err_min = EAGAIN; - err_msg = "Fast reply - offline"; - - dbret = dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &err_maj, - DBUS_TYPE_UINT32, &err_min, - DBUS_TYPE_STRING, &err_msg, - DBUS_TYPE_INVALID); - if (!dbret) return EIO; - - DEBUG(4, ("Request processed. Returned %d,%d,%s\n", - err_maj, err_min, err_msg)); - - sbus_conn_send_reply(conn, reply); - dbus_message_unref(reply); - reply = NULL; - /* This reply will be queued and sent - * when we reenter the mainloop. - * - * Continue processing in case we are - * going back online. - */ - } - - if ((attr_type != BE_ATTR_CORE) && - (attr_type != BE_ATTR_MEM) && - (attr_type != BE_ATTR_ALL)) { - /* Unrecognized attr type */ - err_maj = DP_ERR_FATAL; - err_min = EINVAL; - err_msg = "Invalid Attrs Parameter"; - goto done; - } - - if (filter) { - if (strncmp(filter, "name=", 5) == 0) { - filter_type = BE_FILTER_NAME; - filter_val = &filter[5]; - } else if (strncmp(filter, "idnumber=", 9) == 0) { - filter_type = BE_FILTER_IDNUM; - filter_val = &filter[9]; - } else { - err_maj = DP_ERR_FATAL; - err_min = EINVAL; - err_msg = "Invalid Filter"; - goto done; - } - } else { - err_maj = DP_ERR_FATAL; - err_min = EINVAL; - err_msg = "Missing Filter Parameter"; - goto done; - } - - /* process request */ - be_req = talloc(becli, struct be_req); - if (!be_req) { - err_maj = DP_ERR_FATAL; - err_min = ENOMEM; - err_msg = "Out of memory"; - goto done; - } - be_req->becli = becli; - be_req->be_ctx = becli->bectx; - be_req->fn = acctinfo_callback; - be_req->pvt = reply; - - req = talloc(be_req, struct be_acct_req); - if (!req) { - err_maj = DP_ERR_FATAL; - err_min = ENOMEM; - err_msg = "Out of memory"; - goto done; - } - req->entry_type = type; - req->attr_type = (int)attr_type; - req->filter_type = filter_type; - req->filter_value = talloc_strdup(req, filter_val); - - be_req->req_data = req; - - ret = be_file_request(becli->bectx, - becli->bectx->bet_info[BET_ID].bet_ops->handler, - be_req); - if (ret != EOK) { - err_maj = DP_ERR_FATAL; - err_min = ret; - err_msg = "Failed to file request"; - goto done; - } - - return EOK; - -done: - if (be_req) { - talloc_free(be_req); - } - - if (reply) { - dbret = dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &err_maj, - DBUS_TYPE_UINT32, &err_min, - DBUS_TYPE_STRING, &err_msg, - DBUS_TYPE_INVALID); - if (!dbret) return EIO; - - DEBUG(4, ("Request processed. Returned %d,%d,%s\n", - err_maj, err_min, err_msg)); - - /* send reply back */ - sbus_conn_send_reply(conn, reply); - dbus_message_unref(reply); - } - - return EOK; -} - -static void be_pam_handler_callback(struct be_req *req, - int dp_err_type, - int errnum, - const char *errstr) -{ - struct pam_data *pd; - DBusMessage *reply; - DBusConnection *dbus_conn; - dbus_bool_t dbret; - - DEBUG(4, ("Backend returned: (%d, %d, %s) [%s]\n", - dp_err_type, errnum, errstr?errstr:"", - dp_err_to_string(req, dp_err_type, 0))); - - pd = talloc_get_type(req->req_data, struct pam_data); - - DEBUG(4, ("Sending result [%d][%s]\n", pd->pam_status, pd->domain)); - reply = (DBusMessage *)req->pvt; - dbret = dp_pack_pam_response(reply, pd); - if (!dbret) { - DEBUG(1, ("Failed to generate dbus reply\n")); - dbus_message_unref(reply); - return; - } - - dbus_conn = sbus_get_connection(req->becli->conn); - dbus_connection_send(dbus_conn, reply, NULL); - dbus_message_unref(reply); - - DEBUG(4, ("Sent result [%d][%s]\n", pd->pam_status, pd->domain)); - - talloc_free(req); -} - -static int be_pam_handler(DBusMessage *message, struct sbus_connection *conn) -{ - DBusError dbus_error; - DBusMessage *reply; - struct be_client *becli; - dbus_bool_t ret; - void *user_data; - struct pam_data *pd = NULL; - struct be_req *be_req = NULL; - enum bet_type target = BET_NULL; - - user_data = sbus_conn_get_private_data(conn); - if (!user_data) return EINVAL; - becli = talloc_get_type(user_data, struct be_client); - if (!becli) return EINVAL; - - reply = dbus_message_new_method_return(message); - if (!reply) { - DEBUG(1, ("dbus_message_new_method_return failed, cannot send reply.\n")); - return ENOMEM; - } - - be_req = talloc_zero(becli, struct be_req); - if (!be_req) { - DEBUG(7, ("talloc_zero failed.\n")); - goto done; - } - - be_req->becli = becli; - be_req->be_ctx = becli->bectx; - be_req->fn = be_pam_handler_callback; - be_req->pvt = reply; - - pd = talloc_zero(be_req, struct pam_data); - if (!pd) { - talloc_free(be_req); - return ENOMEM; - } - - pd->pam_status = PAM_SYSTEM_ERR; - pd->domain = talloc_strdup(pd, becli->bectx->domain->name); - if (pd->domain == NULL) { - talloc_free(be_req); - return ENOMEM; - } - - dbus_error_init(&dbus_error); - - ret = dp_unpack_pam_request(message, pd, &dbus_error); - if (!ret) { - DEBUG(1,("Failed, to parse message!\n")); - talloc_free(be_req); - return EIO; - } - - DEBUG(4, ("Got request with the following data\n")); - DEBUG_PAM_DATA(4, pd); - - switch (pd->cmd) { - case SSS_PAM_AUTHENTICATE: - target = BET_AUTH; - break; - case SSS_PAM_ACCT_MGMT: - target = BET_ACCESS; - break; - case SSS_PAM_CHAUTHTOK: - case SSS_PAM_CHAUTHTOK_PRELIM: - target = BET_CHPASS; - break; - case SSS_PAM_SETCRED: - case SSS_PAM_OPEN_SESSION: - case SSS_PAM_CLOSE_SESSION: - pd->pam_status = PAM_SUCCESS; - goto done; - break; - default: - DEBUG(7, ("Unsupported PAM command [%d].\n", pd->cmd)); - pd->pam_status = PAM_MODULE_UNKNOWN; - goto done; - } - - /* return an error if corresponding backend target is not configured */ - if (!becli->bectx->bet_info[target].bet_ops) { - DEBUG(7, ("Undefined backend target.\n")); - pd->pam_status = PAM_MODULE_UNKNOWN; - ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO, - sizeof(MSG_TARGET_NO_CONFIGURED), - (const uint8_t *) MSG_TARGET_NO_CONFIGURED); - if (ret != EOK) { - DEBUG(1, ("pam_add_response failed.\n")); - } - goto done; - } - - be_req->req_data = pd; - - ret = be_file_request(becli->bectx, - becli->bectx->bet_info[target].bet_ops->handler, - be_req); - if (ret != EOK) { - DEBUG(7, ("be_file_request failed.\n")); - goto done; - } - - return EOK; - -done: - - DEBUG(4, ("Sending result [%d][%s]\n", - pd->pam_status, pd->domain)); - - ret = dp_pack_pam_response(reply, pd); - if (!ret) { - DEBUG(1, ("Failed to generate dbus reply\n")); - talloc_free(be_req); - dbus_message_unref(reply); - return EIO; - } - - /* send reply back immediately */ - sbus_conn_send_reply(conn, reply); - dbus_message_unref(reply); - - talloc_free(be_req); - - return EOK; -} - -static int be_client_destructor(void *ctx) -{ - struct be_client *becli = talloc_get_type(ctx, struct be_client); - if (becli->bectx) { - if (becli->bectx->nss_cli == becli) { - DEBUG(4, ("Removed NSS client\n")); - becli->bectx->nss_cli = NULL; - } else if (becli->bectx->pam_cli == becli) { - DEBUG(4, ("Removed PAM client\n")); - becli->bectx->pam_cli = NULL; - } else { - DEBUG(2, ("Unknown client removed ...\n")); - } - } - return 0; -} - -static int client_registration(DBusMessage *message, - struct sbus_connection *conn) -{ - dbus_uint16_t version = DATA_PROVIDER_VERSION; - struct be_client *becli; - DBusMessage *reply; - DBusError dbus_error; - dbus_uint16_t cli_ver; - char *cli_name; - char *cli_domain; - dbus_bool_t dbret; - void *data; - - data = sbus_conn_get_private_data(conn); - becli = talloc_get_type(data, struct be_client); - if (!becli) { - DEBUG(0, ("Connection holds no valid init data\n")); - return EINVAL; - } - - /* First thing, cancel the timeout */ - DEBUG(4, ("Cancel DP ID timeout [%p]\n", becli->timeout)); - talloc_zfree(becli->timeout); - - dbus_error_init(&dbus_error); - - dbret = dbus_message_get_args(message, &dbus_error, - DBUS_TYPE_UINT16, &cli_ver, - DBUS_TYPE_STRING, &cli_name, - DBUS_TYPE_STRING, &cli_domain, - DBUS_TYPE_INVALID); - if (!dbret) { - DEBUG(1, ("Failed to parse message, killing connection\n")); - if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error); - sbus_disconnect(conn); - /* FIXME: should we just talloc_zfree(conn) ? */ - return EIO; - } - - if (strcasecmp(cli_name, "NSS") == 0) { - becli->bectx->nss_cli = becli; - } else if (strcasecmp(cli_name, "PAM") == 0) { - becli->bectx->pam_cli = becli; - } else { - DEBUG(1, ("Unknown client! [%s]\n", cli_name)); - } - talloc_set_destructor((TALLOC_CTX *)becli, be_client_destructor); - - DEBUG(4, ("Added Frontend client [%s]\n", cli_name)); - - /* reply that all is ok */ - reply = dbus_message_new_method_return(message); - if (!reply) { - DEBUG(0, ("Dbus Out of memory!\n")); - return ENOMEM; - } - - dbret = dbus_message_append_args(reply, - DBUS_TYPE_UINT16, &version, - DBUS_TYPE_INVALID); - if (!dbret) { - DEBUG(0, ("Failed to build dbus reply\n")); - dbus_message_unref(reply); - sbus_disconnect(conn); - return EIO; - } - - /* send reply back */ - sbus_conn_send_reply(conn, reply); - dbus_message_unref(reply); - - becli->initialized = true; - return EOK; -} - -static void init_timeout(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval t, void *ptr) -{ - struct be_client *becli; - - DEBUG(2, ("Client timed out before Identification [%p]!\n", te)); - - becli = talloc_get_type(ptr, struct be_client); - - sbus_disconnect(becli->conn); - talloc_zfree(becli); -} - -static int be_client_init(struct sbus_connection *conn, void *data) -{ - struct be_ctx *bectx; - struct be_client *becli; - struct timeval tv; - - bectx = talloc_get_type(data, struct be_ctx); - - /* hang off this memory to the connection so that when the connection - * is freed we can potentially call a destructor */ - - becli = talloc(conn, struct be_client); - if (!becli) { - DEBUG(0,("Out of memory?!\n")); - talloc_zfree(conn); - return ENOMEM; - } - becli->bectx = bectx; - becli->conn = conn; - becli->initialized = false; - - /* 5 seconds should be plenty */ - tv = tevent_timeval_current_ofs(5, 0); - - becli->timeout = tevent_add_timer(bectx->ev, becli, - tv, init_timeout, becli); - if (!becli->timeout) { - DEBUG(0,("Out of memory?!\n")); - talloc_zfree(conn); - return ENOMEM; - } - DEBUG(4, ("Set-up Backend ID timeout [%p]\n", becli->timeout)); - - /* Attach the client context to the connection context, so that it is - * always available when we need to manage the connection. */ - sbus_conn_set_private_data(conn, becli); - - return EOK; -} - -/* be_srv_init - * set up per-domain sbus channel */ -static int be_srv_init(struct be_ctx *ctx) -{ - char *sbus_address; - int ret; - - /* Set up SBUS connection to the monitor */ - ret = dp_get_sbus_address(ctx, &sbus_address, ctx->domain->name); - if (ret != EOK) { - DEBUG(0, ("Could not get sbus backend address.\n")); - return ret; - } - - ret = sbus_new_server(ctx, ctx->ev, sbus_address, - &be_interface, &ctx->sbus_srv, - be_client_init, ctx); - if (ret != EOK) { - DEBUG(0, ("Could not set up sbus server.\n")); - return ret; - } - - return EOK; -} - -/* mon_cli_init - * sbus channel to the monitor daemon */ -static int mon_cli_init(struct be_ctx *ctx) -{ - char *sbus_address; - int ret; - - /* Set up SBUS connection to the monitor */ - ret = monitor_get_sbus_address(ctx, &sbus_address); - if (ret != EOK) { - DEBUG(0, ("Could not locate monitor address.\n")); - return ret; - } - - ret = sbus_client_init(ctx, ctx->ev, sbus_address, - &monitor_be_interface, &ctx->mon_conn, - NULL, ctx); - if (ret != EOK) { - DEBUG(0, ("Failed to connect to monitor services.\n")); - return ret; - } - - /* Identify ourselves to the monitor */ - ret = monitor_common_send_id(ctx->mon_conn, - ctx->identity, - DATA_PROVIDER_VERSION); - if (ret != EOK) { - DEBUG(0, ("Failed to identify to the monitor!\n")); - return ret; - } - - return EOK; -} - -static void be_target_access_permit(struct be_req *be_req) -{ - struct pam_data *pd = talloc_get_type(be_req->req_data, struct pam_data); - DEBUG(9, ("be_target_access_permit called, returning PAM_SUCCESS.\n")); - - pd->pam_status = PAM_SUCCESS; - be_req->fn(be_req, DP_ERR_OK, PAM_SUCCESS, NULL); -} - -static struct bet_ops be_target_access_permit_ops = { - .check_online = NULL, - .handler = be_target_access_permit, - .finalize = NULL -}; - -static void be_target_access_deny(struct be_req *be_req) -{ - struct pam_data *pd = talloc_get_type(be_req->req_data, struct pam_data); - DEBUG(9, ("be_target_access_deny called, returning PAM_PERM_DENIED.\n")); - - pd->pam_status = PAM_PERM_DENIED; - be_req->fn(be_req, DP_ERR_OK, PAM_PERM_DENIED, NULL); -} - -static struct bet_ops be_target_access_deny_ops = { - .check_online = NULL, - .handler = be_target_access_deny, - .finalize = NULL -}; - -static int load_backend_module(struct be_ctx *ctx, - enum bet_type bet_type, - struct bet_info *bet_info, - const char *default_mod_name) -{ - TALLOC_CTX *tmp_ctx; - int ret = EINVAL; - bool already_loaded = false; - int lb=0; - char *mod_name = NULL; - char *path = NULL; - void *handle; - char *mod_init_fn_name = NULL; - bet_init_fn_t mod_init_fn = NULL; - - (*bet_info).mod_name = NULL; - (*bet_info).bet_ops = NULL; - (*bet_info).pvt_bet_data = NULL; - - if (bet_type <= BET_NULL || bet_type >= BET_MAX || - bet_type != bet_data[bet_type].bet_type) { - DEBUG(2, ("invalid bet_type or bet_data corrupted.\n")); - return EINVAL; - } - - tmp_ctx = talloc_new(ctx); - if (!tmp_ctx) { - DEBUG(7, ("talloc_new failed.\n")); - return ENOMEM; - } - - ret = confdb_get_string(ctx->cdb, tmp_ctx, ctx->conf_path, - bet_data[bet_type].option_name, NULL, - &mod_name); - if (ret != EOK) { - ret = EFAULT; - goto done; - } - if (!mod_name) { - if (default_mod_name != NULL) { - DEBUG(5, ("no module name found in confdb, using [%s].\n", - default_mod_name)); - mod_name = talloc_strdup(ctx, default_mod_name); - } else { - ret = ENOENT; - goto done; - } - } - - if (strcasecmp(mod_name, NO_PROVIDER) == 0) { - ret = ENOENT; - goto done; - } - - if (bet_type == BET_ACCESS) { - if (strcmp(mod_name, ACCESS_PERMIT) == 0) { - (*bet_info).bet_ops = &be_target_access_permit_ops; - (*bet_info).pvt_bet_data = NULL; - (*bet_info).mod_name = talloc_strdup(ctx, ACCESS_PERMIT); - - ret = EOK; - goto done; - } - if (strcmp(mod_name, ACCESS_DENY) == 0) { - (*bet_info).bet_ops = &be_target_access_deny_ops; - (*bet_info).pvt_bet_data = NULL; - (*bet_info).mod_name = talloc_strdup(ctx, ACCESS_DENY); - - ret = EOK; - goto done; - } - } - - mod_init_fn_name = talloc_asprintf(tmp_ctx, - bet_data[bet_type].mod_init_fn_name_fmt, - mod_name); - if (mod_init_fn_name == NULL) { - DEBUG(7, ("talloc_asprintf failed\n")); - ret = ENOMEM; - goto done; - } - - - lb = 0; - while(ctx->loaded_be[lb].be_name != NULL) { - if (strncmp(ctx->loaded_be[lb].be_name, mod_name, - strlen(mod_name)) == 0) { - DEBUG(7, ("Backend [%s] already loaded.\n", mod_name)); - already_loaded = true; - break; - } - - ++lb; - if (lb >= BET_MAX) { - DEBUG(2, ("Backend context corrupted.\n")); - ret = EINVAL; - goto done; - } - } - - if (!already_loaded) { - path = talloc_asprintf(tmp_ctx, "%s/libsss_%s.so", - DATA_PROVIDER_PLUGINS_PATH, mod_name); - if (!path) { - ret = ENOMEM; - goto done; - } - - DEBUG(7, ("Loading backend [%s] with path [%s].\n", mod_name, path)); - handle = dlopen(path, RTLD_NOW); - if (!handle) { - DEBUG(0, ("Unable to load %s module with path (%s), error: %s\n", - mod_name, path, dlerror())); - ret = ELIBACC; - goto done; - } - - ctx->loaded_be[lb].be_name = talloc_strdup(ctx, mod_name); - ctx->loaded_be[lb].handle = handle; - } - - mod_init_fn = (bet_init_fn_t)dlsym(ctx->loaded_be[lb].handle, - mod_init_fn_name); - if (mod_init_fn == NULL) { - if (default_mod_name != NULL && - strcmp(default_mod_name, mod_name) == 0 ) { - /* If the default is used and fails we indicate this to the caller - * by returning ENOENT. Ths way the caller can decide how to - * handle the different types of error conditions. */ - ret = ENOENT; - } else { - DEBUG(0, ("Unable to load init fn %s from module %s, error: %s\n", - mod_init_fn_name, mod_name, dlerror())); - ret = ELIBBAD; - } - goto done; - } - - ret = mod_init_fn(ctx, &(*bet_info).bet_ops, &(*bet_info).pvt_bet_data); - if (ret != EOK) { - DEBUG(0, ("Error (%d) in module (%s) initialization (%s)!\n", - ret, mod_name, mod_init_fn_name)); - goto done; - } - - (*bet_info).mod_name = talloc_strdup(ctx, mod_name); - - ret = EOK; - -done: - talloc_free(tmp_ctx); - return ret; -} - -static void signal_be_offline(struct tevent_context *ev, - struct tevent_signal *se, - int signum, - int count, - void *siginfo, - void *private_data) -{ - struct be_ctx *ctx = talloc_get_type(private_data, struct be_ctx); - be_mark_offline(ctx); -} - -int be_process_init(TALLOC_CTX *mem_ctx, - const char *be_domain, - struct tevent_context *ev, - struct confdb_ctx *cdb) -{ - struct be_ctx *ctx; - struct tevent_signal *tes; - int ret; - - ctx = talloc_zero(mem_ctx, struct be_ctx); - if (!ctx) { - DEBUG(0, ("fatal error initializing be_ctx\n")); - return ENOMEM; - } - ctx->ev = ev; - ctx->cdb = cdb; - ctx->identity = talloc_asprintf(ctx, "%%BE_%s", be_domain); - ctx->conf_path = talloc_asprintf(ctx, CONFDB_DOMAIN_PATH_TMPL, be_domain); - if (!ctx->identity || !ctx->conf_path) { - DEBUG(0, ("Out of memory!?\n")); - return ENOMEM; - } - - ret = be_init_failover(ctx); - if (ret != EOK) { - DEBUG(0, ("fatal error initializing failover context\n")); - return ret; - } - - ret = confdb_get_domain(cdb, be_domain, &ctx->domain); - if (ret != EOK) { - DEBUG(0, ("fatal error retrieving domain configuration\n")); - return ret; - } - - ret = sysdb_domain_init(ctx, ev, ctx->domain, DB_PATH, &ctx->sysdb); - if (ret != EOK) { - DEBUG(0, ("fatal error opening cache database\n")); - return ret; - } - - ret = mon_cli_init(ctx); - if (ret != EOK) { - DEBUG(0, ("fatal error setting up monitor bus\n")); - return ret; - } - - ret = be_srv_init(ctx); - if (ret != EOK) { - DEBUG(0, ("fatal error setting up server bus\n")); - return ret; - } - - ret = load_backend_module(ctx, BET_ID, - &ctx->bet_info[BET_ID], NULL); - if (ret != EOK) { - DEBUG(0, ("fatal error initializing data providers\n")); - return ret; - } - DEBUG(9, ("ID backend target successfully loaded from provider [%s].\n", - ctx->bet_info[BET_ID].mod_name)); - - ret = load_backend_module(ctx, BET_AUTH, - &ctx->bet_info[BET_AUTH], - ctx->bet_info[BET_ID].mod_name); - if (ret != EOK) { - if (ret != ENOENT) { - DEBUG(0, ("fatal error initializing data providers\n")); - return ret; - } - DEBUG(1, ("No authentication module provided for [%s] !!\n", - be_domain)); - } else { - DEBUG(9, ("AUTH backend target successfully loaded " - "from provider [%s].\n", ctx->bet_info[BET_AUTH].mod_name)); - } - - ret = load_backend_module(ctx, BET_ACCESS, &ctx->bet_info[BET_ACCESS], - ACCESS_PERMIT); - if (ret != EOK) { - DEBUG(0, ("Failed to setup ACCESS backend.\n")); - return ret; - } - DEBUG(9, ("ACCESS backend target successfully loaded " - "from provider [%s].\n", ctx->bet_info[BET_ACCESS].mod_name)); - - ret = load_backend_module(ctx, BET_CHPASS, - &ctx->bet_info[BET_CHPASS], - ctx->bet_info[BET_AUTH].mod_name); - if (ret != EOK) { - if (ret != ENOENT) { - DEBUG(0, ("fatal error initializing data providers\n")); - return ret; - } - DEBUG(1, ("No change password module provided for [%s] !!\n", - be_domain)); - } else { - DEBUG(9, ("CHPASS backend target successfully loaded " - "from provider [%s].\n", ctx->bet_info[BET_CHPASS].mod_name)); - } - - /* Handle SIGUSR1 to force offline behavior */ - BlockSignals(false, SIGUSR1); - tes = tevent_add_signal(ctx->ev, ctx, SIGUSR1, 0, - signal_be_offline, ctx); - if (tes == NULL) { - return EIO; - } - - return EOK; -} - -int main(int argc, const char *argv[]) -{ - int opt; - poptContext pc; - char *be_domain = NULL; - char *srv_name = NULL; - char *conf_entry = NULL; - struct main_context *main_ctx; - int ret; - - struct poptOption long_options[] = { - POPT_AUTOHELP - SSSD_MAIN_OPTS - {"domain", 0, POPT_ARG_STRING, &be_domain, 0, - _("Domain of the information provider (mandatory)"), 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); - return 1; - } - } - - if (be_domain == NULL) { - fprintf(stderr, "\nMissing option, --domain is a mandatory option.\n\n"); - poptPrintUsage(pc, stderr, 0); - return 1; - } - - poptFreeContext(pc); - - - /* set up things like debug , signals, daemonization, etc... */ - debug_log_file = talloc_asprintf(NULL, "sssd_%s", be_domain); - if (!debug_log_file) return 2; - - srv_name = talloc_asprintf(NULL, "sssd[be[%s]]", be_domain); - if (!srv_name) return 2; - - conf_entry = talloc_asprintf(NULL, CONFDB_DOMAIN_PATH_TMPL, be_domain); - if (!conf_entry) return 2; - - ret = server_setup(srv_name, 0, conf_entry, &main_ctx); - if (ret != EOK) { - DEBUG(0, ("Could not set up mainloop [%d]\n", ret)); - return 2; - } - - ret = die_if_parent_died(); - if (ret != EOK) { - /* This is not fatal, don't return */ - DEBUG(2, ("Could not set up to exit when parent process does\n")); - } - - ret = be_process_init(main_ctx, - be_domain, - main_ctx->event_ctx, - main_ctx->confdb_ctx); - if (ret != EOK) { - DEBUG(0, ("Could not initialize backend [%d]\n", ret)); - return 3; - } - - DEBUG(1, ("Backend provider (%s) started!\n", be_domain)); - - /* loop on main */ - server_loop(main_ctx); - - return 0; -} - -static int data_provider_res_init(DBusMessage *message, - struct sbus_connection *conn) -{ - resolv_reread_configuration(); - - return monitor_common_res_init(message, conn); -} - -static int data_provider_go_offline(DBusMessage *message, - struct sbus_connection *conn) -{ - struct be_ctx *be_ctx; - be_ctx = talloc_get_type(sbus_conn_get_private_data(conn), struct be_ctx); - be_mark_offline(be_ctx); - return monitor_common_pong(message, conn); -} diff --git a/server/providers/data_provider_fo.c b/server/providers/data_provider_fo.c deleted file mode 100644 index 7d0240489..000000000 --- a/server/providers/data_provider_fo.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - SSSD - - Data Provider Helpers - - Copyright (C) Simo Sorce 2009 - - 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/dp_backend.h" -#include "resolv/async_resolv.h" - -struct be_svc_callback { - struct be_svc_callback *prev; - struct be_svc_callback *next; - - struct be_svc_data *svc; - - be_svc_callback_fn_t *fn; - void *private_data; -}; - -struct be_svc_data { - struct be_svc_data *prev; - struct be_svc_data *next; - - const char *name; - struct fo_service *fo_service; - - struct fo_server *last_good_srv; - - struct be_svc_callback *callbacks; -}; - -struct be_failover_ctx { - struct fo_ctx *fo_ctx; - struct resolv_ctx *resolv; - - struct be_svc_data *svcs; -}; - -int be_init_failover(struct be_ctx *ctx) -{ - int ret; - - if (ctx->be_fo != NULL) { - return EOK; - } - - ctx->be_fo = talloc_zero(ctx, struct be_failover_ctx); - if (!ctx->be_fo) { - return ENOMEM; - } - - ret = resolv_init(ctx, ctx->ev, 5, &ctx->be_fo->resolv); - if (ret != EOK) { - talloc_zfree(ctx->be_fo); - return ret; - } - - /* todo get timeout from configuration */ - ctx->be_fo->fo_ctx = fo_context_init(ctx->be_fo, 30); - if (!ctx->be_fo->fo_ctx) { - talloc_zfree(ctx->be_fo); - return ENOMEM; - } - - return EOK; -} - -static int be_svc_data_destroy(void *memptr) -{ - struct be_svc_data *svc; - - svc = talloc_get_type(memptr, struct be_svc_data); - - while (svc->callbacks) { - /* callbacks removes themselves from the list, - * so this while will freem them all and then terminate */ - talloc_free(svc->callbacks); - } - - return 0; -} - -int be_fo_add_service(struct be_ctx *ctx, const char *service_name) -{ - struct fo_service *service; - struct be_svc_data *svc; - int ret; - - DLIST_FOR_EACH(svc, ctx->be_fo->svcs) { - if (strcmp(svc->name, service_name) == 0) { - DEBUG(6, ("Failover service already initialized!\n")); - /* we already have a service up and configured, - * can happen when using both id and auth provider - */ - return EOK; - } - } - - /* if not in the be service list, try to create new one */ - - ret = fo_new_service(ctx->be_fo->fo_ctx, service_name, &service); - if (ret != EOK && ret != EEXIST) { - DEBUG(1, ("Failed to create failover service!\n")); - return ret; - } - - svc = talloc_zero(ctx->be_fo, struct be_svc_data); - if (!svc) { - return ENOMEM; - } - talloc_set_destructor((TALLOC_CTX *)svc, be_svc_data_destroy); - - svc->name = talloc_strdup(svc, service_name); - if (!svc->name) { - talloc_zfree(svc); - return ENOMEM; - } - svc->fo_service = service; - - DLIST_ADD(ctx->be_fo->svcs, svc); - - return EOK; -} - -static int be_svc_callback_destroy(void *memptr) -{ - struct be_svc_callback *callback; - - callback = talloc_get_type(memptr, struct be_svc_callback); - - if (callback->svc) { - DLIST_REMOVE(callback->svc->callbacks, callback); - } - - return 0; -} - -int be_fo_service_add_callback(TALLOC_CTX *memctx, - struct be_ctx *ctx, const char *service_name, - be_svc_callback_fn_t *fn, void *private_data) -{ - struct be_svc_callback *callback; - struct be_svc_data *svc; - - DLIST_FOR_EACH(svc, ctx->be_fo->svcs) { - if (strcmp(svc->name, service_name) == 0) { - break; - } - } - if (NULL == svc) { - return ENOENT; - } - - callback = talloc_zero(memctx, struct be_svc_callback); - if (!callback) { - return ENOMEM; - } - talloc_set_destructor((TALLOC_CTX *)callback, be_svc_callback_destroy); - - callback->svc = svc; - callback->fn = fn; - callback->private_data = private_data; - - DLIST_ADD(svc->callbacks, callback); - - return EOK; -} - -int be_fo_add_server(struct be_ctx *ctx, const char *service_name, - const char *server, int port, void *user_data) -{ - struct be_svc_data *svc; - int ret; - - DLIST_FOR_EACH(svc, ctx->be_fo->svcs) { - if (strcmp(svc->name, service_name) == 0) { - break; - } - } - if (NULL == svc) { - return ENOENT; - } - - ret = fo_add_server(svc->fo_service, server, port, user_data); - if (ret && ret != EEXIST) { - DEBUG(1, ("Failed to add server to failover service\n")); - return ret; - } - - return EOK; -} - -struct be_resolve_server_state { - struct tevent_context *ev; - struct be_ctx *ctx; - - struct be_svc_data *svc; - int attempts; - - struct fo_server *srv; -}; - -static void be_resolve_server_done(struct tevent_req *subreq); - -struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct be_ctx *ctx, - const char *service_name) -{ - struct tevent_req *req, *subreq; - struct be_resolve_server_state *state; - struct be_svc_data *svc; - - req = tevent_req_create(memctx, &state, struct be_resolve_server_state); - if (!req) return NULL; - - state->ev = ev; - state->ctx = ctx; - - DLIST_FOR_EACH(svc, ctx->be_fo->svcs) { - if (strcmp(svc->name, service_name) == 0) { - state->svc = svc; - break; - } - } - - if (NULL == svc) { - tevent_req_error(req, EINVAL); - tevent_req_post(req, ev); - return req; - } - - state->attempts = 0; - - subreq = fo_resolve_service_send(state, ev, - ctx->be_fo->resolv, svc->fo_service); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, be_resolve_server_done, req); - - return req; -} - -static void be_resolve_server_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct be_resolve_server_state *state = tevent_req_data(req, - struct be_resolve_server_state); - struct be_svc_callback *callback; - int ret; - - ret = fo_resolve_service_recv(subreq, &state->srv); - talloc_zfree(subreq); - switch (ret) { - case EOK: - if (!state->srv) { - tevent_req_error(req, EFAULT); - return; - } - break; - - case ENOENT: - /* all servers have been tried and none - * was found good, go offline */ - tevent_req_error(req, EIO); - return; - - default: - /* mark server as bad and retry */ - if (!state->srv) { - tevent_req_error(req, EFAULT); - return; - } - DEBUG(6, ("Couldn't resolve server (%s), resolver returned (%d)\n", - fo_get_server_name(state->srv), ret)); - - state->attempts++; - if (state->attempts >= 10) { - DEBUG(2, ("Failed to find a server after 10 attempts\n")); - tevent_req_error(req, EIO); - return; - } - - /* now try next one */ - DEBUG(6, ("Trying with the next one!\n")); - subreq = fo_resolve_service_send(state, state->ev, - state->ctx->be_fo->resolv, - state->svc->fo_service); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, be_resolve_server_done, req); - - return; - } - - /* all fine we got the server */ - - if (debug_level >= 4) { - struct hostent *srvaddr; - char ipaddr[128]; - srvaddr = fo_get_server_hostent(state->srv); - inet_ntop(srvaddr->h_addrtype, srvaddr->h_addr_list[0], - ipaddr, 128); - - DEBUG(4, ("Found address for server %s: [%s]\n", - fo_get_server_name(state->srv), ipaddr)); - } - - /* now call all svc callbacks if server changed */ - if (state->srv != state->svc->last_good_srv) { - state->svc->last_good_srv = state->srv; - - DLIST_FOR_EACH(callback, state->svc->callbacks) { - callback->fn(callback->private_data, state->srv); - } - } - - tevent_req_done(req); -} - -int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv) -{ - struct be_resolve_server_state *state = tevent_req_data(req, - struct be_resolve_server_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - if (srv) { - *srv = state->srv; - } - - return EOK; -} - diff --git a/server/providers/data_provider_opts.c b/server/providers/data_provider_opts.c deleted file mode 100644 index 98283e430..000000000 --- a/server/providers/data_provider_opts.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - SSSD - - Data Provider Helpers - - Copyright (C) Simo Sorce 2009 - - 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 "data_provider.h" - -/* =Retrieve-Options====================================================== */ - -int dp_get_options(TALLOC_CTX *memctx, - struct confdb_ctx *cdb, - const char *conf_path, - struct dp_option *def_opts, - int num_opts, - struct dp_option **_opts) -{ - struct dp_option *opts; - int i, ret; - - opts = talloc_zero_array(memctx, struct dp_option, num_opts); - if (!opts) return ENOMEM; - - for (i = 0; i < num_opts; i++) { - char *tmp; - - opts[i].opt_name = def_opts[i].opt_name; - opts[i].type = def_opts[i].type; - opts[i].def_val = def_opts[i].def_val; - ret = EOK; - - switch (def_opts[i].type) { - case DP_OPT_STRING: - ret = confdb_get_string(cdb, opts, conf_path, - opts[i].opt_name, - opts[i].def_val.cstring, - &opts[i].val.string); - if (ret != EOK || - ((opts[i].def_val.string != NULL) && - (opts[i].val.string == NULL))) { - DEBUG(0, ("Failed to retrieve value for option (%s)\n", - opts[i].opt_name)); - if (ret == EOK) ret = EINVAL; - goto done; - } - DEBUG(6, ("Option %s has value %s\n", - opts[i].opt_name, opts[i].val.cstring)); - break; - - case DP_OPT_BLOB: - ret = confdb_get_string(cdb, opts, conf_path, - opts[i].opt_name, - NULL, &tmp); - if (ret != EOK) { - DEBUG(0, ("Failed to retrieve value for option (%s)\n", - opts[i].opt_name)); - goto done; - } - - if (tmp) { - opts[i].val.blob.data = (uint8_t *)tmp; - opts[i].val.blob.length = strlen(tmp); - } else { - opts[i].val.blob.data = NULL; - opts[i].val.blob.length = 0; - } - - DEBUG(6, ("Option %s has %s binary value.\n", - opts[i].opt_name, - opts[i].val.blob.length?"a":"no")); - break; - - case DP_OPT_NUMBER: - ret = confdb_get_int(cdb, opts, conf_path, - opts[i].opt_name, - opts[i].def_val.number, - &opts[i].val.number); - if (ret != EOK) { - DEBUG(0, ("Failed to retrieve value for option (%s)\n", - opts[i].opt_name)); - goto done; - } - DEBUG(6, ("Option %s has value %d\n", - opts[i].opt_name, opts[i].val.number)); - break; - - case DP_OPT_BOOL: - ret = confdb_get_bool(cdb, opts, conf_path, - opts[i].opt_name, - opts[i].def_val.boolean, - &opts[i].val.boolean); - if (ret != EOK) { - DEBUG(0, ("Failed to retrieve value for option (%s)\n", - opts[i].opt_name)); - goto done; - } - DEBUG(6, ("Option %s is %s\n", - opts[i].opt_name, - opts[i].val.boolean?"TRUE":"FALSE")); - break; - } - } - - ret = EOK; - *_opts = opts; - -done: - if (ret != EOK) talloc_zfree(opts); - return ret; -} - -/* =Basic-Option-Helpers================================================== */ - -int dp_copy_options(TALLOC_CTX *memctx, - struct dp_option *src_opts, - int num_opts, - struct dp_option **_opts) -{ - struct dp_option *opts; - int i, ret; - - opts = talloc_zero_array(memctx, struct dp_option, num_opts); - if (!opts) return ENOMEM; - - for (i = 0; i < num_opts; i++) { - opts[i].opt_name = src_opts[i].opt_name; - opts[i].type = src_opts[i].type; - opts[i].def_val = src_opts[i].def_val; - ret = EOK; - - switch (src_opts[i].type) { - case DP_OPT_STRING: - if (src_opts[i].val.string) { - ret = dp_opt_set_string(opts, i, src_opts[i].val.string); - } else if (src_opts[i].def_val.string) { - ret = dp_opt_set_string(opts, i, src_opts[i].def_val.string); - } - if (ret != EOK) { - DEBUG(0, ("Failed to copy value for option (%s)\n", - opts[i].opt_name)); - goto done; - } - DEBUG(6, ("Option %s has value %s\n", - opts[i].opt_name, opts[i].val.cstring)); - break; - - case DP_OPT_BLOB: - if (src_opts[i].val.blob.data) { - ret = dp_opt_set_blob(opts, i, src_opts[i].val.blob); - } else if (src_opts[i].def_val.blob.data) { - ret = dp_opt_set_blob(opts, i, src_opts[i].def_val.blob); - } - if (ret != EOK) { - DEBUG(0, ("Failed to retrieve value for option (%s)\n", - opts[i].opt_name)); - goto done; - } - DEBUG(6, ("Option %s has %s binary value.\n", - opts[i].opt_name, - opts[i].val.blob.length?"a":"no")); - break; - - case DP_OPT_NUMBER: - if (src_opts[i].val.number) { - ret = dp_opt_set_int(opts, i, src_opts[i].val.number); - } else if (src_opts[i].def_val.number) { - ret = dp_opt_set_int(opts, i, src_opts[i].def_val.number); - } - if (ret != EOK) { - DEBUG(0, ("Failed to retrieve value for option (%s)\n", - opts[i].opt_name)); - goto done; - } - DEBUG(6, ("Option %s has value %d\n", - opts[i].opt_name, opts[i].val.number)); - break; - - case DP_OPT_BOOL: - if (src_opts[i].val.boolean) { - ret = dp_opt_set_bool(opts, i, src_opts[i].val.boolean); - } else if (src_opts[i].def_val.boolean) { - ret = dp_opt_set_int(opts, i, src_opts[i].def_val.boolean); - } - if (ret != EOK) { - DEBUG(0, ("Failed to retrieve value for option (%s)\n", - opts[i].opt_name)); - goto done; - } - DEBUG(6, ("Option %s is %s\n", - opts[i].opt_name, - opts[i].val.boolean?"TRUE":"FALSE")); - break; - } - } - - *_opts = opts; - -done: - if (ret != EOK) talloc_zfree(opts); - return ret; -} - -static const char *dp_opt_type_to_string(enum dp_opt_type type) -{ - switch (type) { - case DP_OPT_STRING: - return "String"; - case DP_OPT_BLOB: - return "Blob"; - case DP_OPT_NUMBER: - return "Number"; - case DP_OPT_BOOL: - return "Boolean"; - } - return NULL; -} - -/* Getters */ -const char *_dp_opt_get_cstring(struct dp_option *opts, - int id, const char *location) -{ - if (opts[id].type != DP_OPT_STRING) { - DEBUG(0, ("[%s] Requested type 'String' for option '%s'" - " but value is of type '%s'!\n", - location, opts[id].opt_name, - dp_opt_type_to_string(opts[id].type))); - return NULL; - } - return opts[id].val.cstring; -} - -char *_dp_opt_get_string(struct dp_option *opts, - int id, const char *location) -{ - if (opts[id].type != DP_OPT_STRING) { - DEBUG(0, ("[%s] Requested type 'String' for option '%s'" - " but value is of type '%s'!\n", - location, opts[id].opt_name, - dp_opt_type_to_string(opts[id].type))); - return NULL; - } - return opts[id].val.string; -} - -struct dp_opt_blob _dp_opt_get_blob(struct dp_option *opts, - int id, const char *location) -{ - struct dp_opt_blob null_blob = { NULL, 0 }; - if (opts[id].type != DP_OPT_BLOB) { - DEBUG(0, ("[%s] Requested type 'Blob' for option '%s'" - " but value is of type '%s'!\n", - location, opts[id].opt_name, - dp_opt_type_to_string(opts[id].type))); - return null_blob; - } - return opts[id].val.blob; -} - -int _dp_opt_get_int(struct dp_option *opts, - int id, const char *location) -{ - if (opts[id].type != DP_OPT_NUMBER) { - DEBUG(0, ("[%s] Requested type 'Number' for option '%s'" - " but value is of type '%s'!\n", - location, opts[id].opt_name, - dp_opt_type_to_string(opts[id].type))); - return 0; - } - return opts[id].val.number; -} - -bool _dp_opt_get_bool(struct dp_option *opts, - int id, const char *location) -{ - if (opts[id].type != DP_OPT_BOOL) { - DEBUG(0, ("[%s] Requested type 'Boolean' for option '%s'" - " but value is of type '%s'!\n", - location, opts[id].opt_name, - dp_opt_type_to_string(opts[id].type))); - return false; - } - return opts[id].val.boolean; -} - -/* Setters */ -int _dp_opt_set_string(struct dp_option *opts, int id, - const char *s, const char *location) -{ - if (opts[id].type != DP_OPT_STRING) { - DEBUG(0, ("[%s] Requested type 'String' for option '%s'" - " but type is '%s'!\n", - location, opts[id].opt_name, - dp_opt_type_to_string(opts[id].type))); - return EINVAL; - } - - if (opts[id].val.string) { - talloc_zfree(opts[id].val.string); - } - if (s) { - opts[id].val.string = talloc_strdup(opts, s); - if (!opts[id].val.string) { - DEBUG(0, ("talloc_strdup() failed!\n")); - return ENOMEM; - } - } - - return EOK; -} - -int _dp_opt_set_blob(struct dp_option *opts, int id, - struct dp_opt_blob b, const char *location) -{ - if (opts[id].type != DP_OPT_BLOB) { - DEBUG(0, ("[%s] Requested type 'Blob' for option '%s'" - " but type is '%s'!\n", - location, opts[id].opt_name, - dp_opt_type_to_string(opts[id].type))); - return EINVAL; - } - - if (opts[id].val.blob.data) { - talloc_zfree(opts[id].val.blob.data); - opts[id].val.blob.length = 0; - } - if (b.data) { - opts[id].val.blob.data = talloc_memdup(opts, b.data, b.length); - if (!opts[id].val.blob.data) { - DEBUG(0, ("talloc_memdup() failed!\n")); - return ENOMEM; - } - } - opts[id].val.blob.length = b.length; - - return EOK; -} - -int _dp_opt_set_int(struct dp_option *opts, int id, - int i, const char *location) -{ - if (opts[id].type != DP_OPT_NUMBER) { - DEBUG(0, ("[%s] Requested type 'Number' for option '%s'" - " but type is '%s'!\n", - location, opts[id].opt_name, - dp_opt_type_to_string(opts[id].type))); - return EINVAL; - } - - opts[id].val.number = i; - - return EOK; -} - -int _dp_opt_set_bool(struct dp_option *opts, int id, - bool b, const char *location) -{ - if (opts[id].type != DP_OPT_BOOL) { - DEBUG(0, ("[%s] Requested type 'Boolean' for option '%s'" - " but type is '%s'!\n", - location, opts[id].opt_name, - dp_opt_type_to_string(opts[id].type))); - return EINVAL; - } - - opts[id].val.boolean = b; - - return EOK; -} - diff --git a/server/providers/dp_auth_util.c b/server/providers/dp_auth_util.c deleted file mode 100644 index 39cc0f60f..000000000 --- a/server/providers/dp_auth_util.c +++ /dev/null @@ -1,414 +0,0 @@ -/* - SSSD - - Data Provider, auth utils - - Copyright (C) Sumit Bose 2009 - - 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 "data_provider.h" - -void pam_print_data(int l, struct pam_data *pd) -{ - DEBUG(l, ("command: %d\n", pd->cmd)); - DEBUG(l, ("domain: %s\n", pd->domain)); - DEBUG(l, ("user: %s\n", pd->user)); - DEBUG(l, ("service: %s\n", pd->service)); - DEBUG(l, ("tty: %s\n", pd->tty)); - DEBUG(l, ("ruser: %s\n", pd->ruser)); - DEBUG(l, ("rhost: %s\n", pd->rhost)); - DEBUG(l, ("authtok type: %d\n", pd->authtok_type)); - DEBUG(l, ("authtok size: %d\n", pd->authtok_size)); - DEBUG(l, ("newauthtok type: %d\n", pd->newauthtok_type)); - DEBUG(l, ("newauthtok size: %d\n", pd->newauthtok_size)); - DEBUG(l, ("priv: %d\n", pd->priv)); - DEBUG(l, ("pw_uid: %d\n", pd->pw_uid)); - DEBUG(l, ("gr_gid: %d\n", pd->gr_gid)); - DEBUG(l, ("cli_pid: %d\n", pd->cli_pid)); -} - -int pam_add_response(struct pam_data *pd, enum response_type type, - int len, const uint8_t *data) -{ - struct response_data *new; - - new = talloc(pd, struct response_data); - if (new == NULL) return ENOMEM; - - new->type = type; - new->len = len; - new->data = talloc_memdup(pd, data, len); - if (new->data == NULL) return ENOMEM; - new->next = pd->resp_list; - pd->resp_list = new; - - return EOK; -} - -bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd) -{ - int ret; - - if (pd->user == NULL || pd->domain == NULL) return false; - if (pd->service == NULL) pd->service = talloc_strdup(pd, ""); - if (pd->tty == NULL) pd->tty = talloc_strdup(pd, ""); - if (pd->ruser == NULL) pd->ruser = talloc_strdup(pd, ""); - if (pd->rhost == NULL) pd->rhost = talloc_strdup(pd, ""); - - - ret = dbus_message_append_args(msg, - DBUS_TYPE_INT32, &(pd->cmd), - DBUS_TYPE_STRING, &(pd->domain), - DBUS_TYPE_STRING, &(pd->user), - DBUS_TYPE_STRING, &(pd->service), - DBUS_TYPE_STRING, &(pd->tty), - DBUS_TYPE_STRING, &(pd->ruser), - DBUS_TYPE_STRING, &(pd->rhost), - DBUS_TYPE_UINT32, &(pd->authtok_type), - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->authtok), - (pd->authtok_size), - DBUS_TYPE_UINT32, &(pd->newauthtok_type), - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->newauthtok), - pd->newauthtok_size, - DBUS_TYPE_INT32, &(pd->priv), - DBUS_TYPE_INT32, &(pd->pw_uid), - DBUS_TYPE_INT32, &(pd->gr_gid), - DBUS_TYPE_UINT32, &(pd->cli_pid), - DBUS_TYPE_INVALID); - - return ret; -} - -bool dp_unpack_pam_request(DBusMessage *msg, struct pam_data *pd, DBusError *dbus_error) -{ - int ret; - - ret = dbus_message_get_args(msg, dbus_error, - DBUS_TYPE_INT32, &(pd->cmd), - DBUS_TYPE_STRING, &(pd->domain), - DBUS_TYPE_STRING, &(pd->user), - DBUS_TYPE_STRING, &(pd->service), - DBUS_TYPE_STRING, &(pd->tty), - DBUS_TYPE_STRING, &(pd->ruser), - DBUS_TYPE_STRING, &(pd->rhost), - DBUS_TYPE_UINT32, &(pd->authtok_type), - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->authtok), - &(pd->authtok_size), - DBUS_TYPE_UINT32, &(pd->newauthtok_type), - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, - &(pd->newauthtok), - &(pd->newauthtok_size), - DBUS_TYPE_INT32, &(pd->priv), - DBUS_TYPE_INT32, &(pd->pw_uid), - DBUS_TYPE_INT32, &(pd->gr_gid), - DBUS_TYPE_UINT32, &(pd->cli_pid), - DBUS_TYPE_INVALID); - - return ret; -} - -bool dp_pack_pam_response(DBusMessage *msg, struct pam_data *pd) -{ - dbus_bool_t dbret; - struct response_data *resp; - DBusMessageIter iter; - DBusMessageIter array_iter; - DBusMessageIter struct_iter; - DBusMessageIter data_iter; - - dbus_message_iter_init_append(msg, &iter); - - /* Append the PAM status */ - dbret = dbus_message_iter_append_basic(&iter, - DBUS_TYPE_UINT32, &(pd->pam_status)); - if (!dbret) { - return false; - } - - /* Append the domain */ - dbret = dbus_message_iter_append_basic(&iter, - DBUS_TYPE_STRING, &(pd->domain)); - if (!dbret) { - return false; - } - - /* Create an array of response structures */ - dbret = dbus_message_iter_open_container(&iter, - DBUS_TYPE_ARRAY, "(uay)", - &array_iter); - if (!dbret) { - return false; - } - - resp = pd->resp_list; - while (resp != NULL) { - /* Create a DBUS struct */ - dbret = dbus_message_iter_open_container(&array_iter, - DBUS_TYPE_STRUCT, NULL, - &struct_iter); - if (!dbret) { - return false; - } - - /* Add the response type */ - dbret = dbus_message_iter_append_basic(&struct_iter, - DBUS_TYPE_UINT32, - &(resp->type)); - if (!dbret) { - return false; - } - - /* Add the response message */ - dbret = dbus_message_iter_open_container(&struct_iter, - DBUS_TYPE_ARRAY, "y", - &data_iter); - if (!dbret) { - return false; - } - dbret = dbus_message_iter_append_fixed_array(&data_iter, - DBUS_TYPE_BYTE, &(resp->data), resp->len); - if (!dbret) { - return false; - } - dbret = dbus_message_iter_close_container(&struct_iter, &data_iter); - if (!dbret) { - return false; - } - - resp = resp->next; - dbret = dbus_message_iter_close_container(&array_iter, &struct_iter); - if (!dbret) { - return false; - } - } - - /* Close the struct array */ - dbret = dbus_message_iter_close_container(&iter, &array_iter); - if (!dbret) { - return false; - } - - return true; -} - -bool dp_unpack_pam_response(DBusMessage *msg, struct pam_data *pd, DBusError *dbus_error) -{ - DBusMessageIter iter; - DBusMessageIter array_iter; - DBusMessageIter struct_iter; - DBusMessageIter sub_iter; - int type; - int len; - const uint8_t *data; - - if (!dbus_message_iter_init(msg, &iter)) { - DEBUG(1, ("pam response has no arguments.\n")); - return false; - } - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) { - DEBUG(1, ("pam response format error.\n")); - return false; - } - dbus_message_iter_get_basic(&iter, &(pd->pam_status)); - - if (!dbus_message_iter_next(&iter)) { - DEBUG(1, ("pam response has too few arguments.\n")); - return false; - } - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) { - DEBUG(1, ("pam response format error.\n")); - return false; - } - dbus_message_iter_get_basic(&iter, &(pd->domain)); - - if (!dbus_message_iter_next(&iter)) { - DEBUG(1, ("pam response has too few arguments.\n")); - return false; - } - - /* After this point will be an array of pam data */ - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { - DEBUG(1, ("pam response format error.\n")); - DEBUG(1, ("Type was %c\n", (char)dbus_message_iter_get_arg_type(&iter))); - return false; - } - - if (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { - DEBUG(1, ("pam response format error.\n")); - return false; - } - - dbus_message_iter_recurse(&iter, &array_iter); - while (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID) { - /* Read in a pam data struct */ - if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) { - DEBUG(1, ("pam response format error.\n")); - return false; - } - - dbus_message_iter_recurse(&array_iter, &struct_iter); - - /* PAM data struct contains a type and a byte-array of data */ - - /* Get the pam data type */ - if (dbus_message_iter_get_arg_type(&struct_iter) != DBUS_TYPE_UINT32) { - DEBUG(1, ("pam response format error.\n")); - return false; - } - dbus_message_iter_get_basic(&struct_iter, &type); - - if (!dbus_message_iter_next(&struct_iter)) { - DEBUG(1, ("pam response format error.\n")); - return false; - } - - /* Get the byte array */ - if (dbus_message_iter_get_arg_type(&struct_iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&struct_iter) != DBUS_TYPE_BYTE) { - DEBUG(1, ("pam response format error.\n")); - return false; - } - - dbus_message_iter_recurse(&struct_iter, &sub_iter); - dbus_message_iter_get_fixed_array(&sub_iter, &data, &len); - - pam_add_response(pd, type, len, data); - dbus_message_iter_next(&array_iter); - } - - return true; -} - -static void id_callback(DBusPendingCall *pending, void *ptr) -{ - DBusMessage *reply; - DBusError dbus_error; - dbus_bool_t ret; - dbus_uint16_t dp_ver; - int type; - - dbus_error_init(&dbus_error); - - reply = dbus_pending_call_steal_reply(pending); - if (!reply) { - /* reply should never be null. This function shouldn't be called - * until reply is valid or timeout has occurred. If reply is NULL - * here, something is seriously wrong and we should bail out. - */ - DEBUG(0, ("Severe error. A reply callback was called but no" - " reply was received and no timeout occurred\n")); - - /* FIXME: Destroy this connection ? */ - goto done; - } - - type = dbus_message_get_type(reply); - switch (type) { - case DBUS_MESSAGE_TYPE_METHOD_RETURN: - ret = dbus_message_get_args(reply, &dbus_error, - DBUS_TYPE_UINT16, &dp_ver, - DBUS_TYPE_INVALID); - if (!ret) { - DEBUG(1, ("Failed to parse message\n")); - if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error); - /* FIXME: Destroy this connection ? */ - goto done; - } - - DEBUG(4, ("Got id ack and version (%d) from DP\n", dp_ver)); - - break; - - case DBUS_MESSAGE_TYPE_ERROR: - DEBUG(0,("The Monitor returned an error [%s]\n", - dbus_message_get_error_name(reply))); - /* Falling through to default intentionally*/ - default: - /* - * Timeout or other error occurred or something - * unexpected happened. - * It doesn't matter which, because either way we - * know that this connection isn't trustworthy. - * We'll destroy it now. - */ - - /* FIXME: Destroy this connection ? */ - break; - } - -done: - dbus_pending_call_unref(pending); - dbus_message_unref(reply); -} - -int dp_common_send_id(struct sbus_connection *conn, uint16_t version, - const char *name, const char *domain) -{ - DBusPendingCall *pending_reply; - DBusConnection *dbus_conn; - DBusMessage *msg; - dbus_bool_t ret; - - dbus_conn = sbus_get_connection(conn); - - /* create the message */ - msg = dbus_message_new_method_call(NULL, - DP_PATH, - DP_INTERFACE, - DP_METHOD_REGISTER); - if (msg == NULL) { - DEBUG(0, ("Out of memory?!\n")); - return ENOMEM; - } - - DEBUG(4, ("Sending ID to DP: (%d,%s,%s)\n", - version, name, domain)); - - ret = dbus_message_append_args(msg, - DBUS_TYPE_UINT16, &version, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &domain, - DBUS_TYPE_INVALID); - if (!ret) { - DEBUG(1, ("Failed to build message\n")); - return EIO; - } - - ret = dbus_connection_send_with_reply(dbus_conn, msg, &pending_reply, - 30000 /* TODO: set timeout */); - if (!ret || !pending_reply) { - /* - * Critical Failure - * We can't communicate on this connection - * We'll drop it using the default destructor. - */ - DEBUG(0, ("D-BUS send failed.\n")); - dbus_message_unref(msg); - return EIO; - } - - /* Set up the reply handler */ - dbus_pending_call_set_notify(pending_reply, id_callback, NULL, NULL); - dbus_message_unref(msg); - - return EOK; -} - diff --git a/server/providers/dp_backend.h b/server/providers/dp_backend.h deleted file mode 100644 index f1069d0db..000000000 --- a/server/providers/dp_backend.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - SSSD - - Data Provider, private header file - - Copyright (C) Simo Sorce 2008 - - 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 __DP_BACKEND_H__ -#define __DP_BACKEND_H__ - -#include "providers/data_provider.h" -#include "providers/fail_over.h" -#include "db/sysdb.h" - -struct be_ctx; -struct bet_ops; -struct be_req; - -typedef int (*bet_init_fn_t)(TALLOC_CTX *, struct bet_ops **, void **); -typedef void (*be_shutdown_fn)(void *); -typedef void (*be_req_fn_t)(struct be_req *); -typedef void (*be_async_callback_t)(struct be_req *, int, int, const char *); - -enum bet_type { - BET_NULL = 0, - BET_ID, - BET_AUTH, - BET_ACCESS, - BET_CHPASS, - BET_MAX -}; - -struct bet_data { - enum bet_type bet_type; - const char *option_name; - const char *mod_init_fn_name_fmt; -}; - -struct loaded_be { - char *be_name; - void *handle; -}; - -struct bet_info { - enum bet_type bet_type; - struct bet_ops *bet_ops; - void *pvt_bet_data; - char *mod_name; -}; - -struct be_offline_status { - time_t went_offline; - bool offline; -}; - -struct be_client { - struct be_ctx *bectx; - struct sbus_connection *conn; - struct tevent_timer *timeout; - bool initialized; -}; - -struct be_failover_ctx; - -struct be_ctx { - struct tevent_context *ev; - struct confdb_ctx *cdb; - struct sysdb_ctx *sysdb; - struct sss_domain_info *domain; - const char *identity; - const char *conf_path; - struct be_failover_ctx *be_fo; - - struct be_offline_status offstat; - - struct sbus_connection *mon_conn; - struct sbus_connection *sbus_srv; - - struct be_client *nss_cli; - struct be_client *pam_cli; - - struct loaded_be loaded_be[BET_MAX]; - struct bet_info bet_info[BET_MAX]; -}; - -struct bet_ops { - be_req_fn_t check_online; - be_req_fn_t handler; - be_req_fn_t finalize; -}; - -struct be_req { - struct be_client *becli; - struct be_ctx *be_ctx; - void *req_data; - - be_async_callback_t fn; - void *pvt; -}; - -struct be_acct_req { - int entry_type; - int attr_type; - int filter_type; - char *filter_value; -}; - -bool be_is_offline(struct be_ctx *ctx); -void be_mark_offline(struct be_ctx *ctx); - -/* from data_provider_fo.c */ -typedef void (be_svc_callback_fn_t)(void *, struct fo_server *); - -int be_init_failover(struct be_ctx *ctx); -int be_fo_add_service(struct be_ctx *ctx, const char *service_name); -int be_fo_service_add_callback(TALLOC_CTX *memctx, - struct be_ctx *ctx, const char *service_name, - be_svc_callback_fn_t *fn, void *private_data); -int be_fo_add_server(struct be_ctx *ctx, const char *service_name, - const char *server, int port, void *user_data); - -struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct be_ctx *ctx, - const char *service_name); -int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv); - -#endif /* __DP_BACKEND_H___ */ diff --git a/server/providers/dp_sbus.c b/server/providers/dp_sbus.c deleted file mode 100644 index f9dd28216..000000000 --- a/server/providers/dp_sbus.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - SSSD - - Data Provider Helpers - - Copyright (C) Stephen Gallagher 2009 - - 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 "config.h" -#include "talloc.h" -#include "tevent.h" -#include "confdb/confdb.h" -#include "sbus/sssd_dbus.h" -#include "providers/data_provider.h" - -int dp_get_sbus_address(TALLOC_CTX *mem_ctx, - char **address, const char *domain_name) -{ - char *default_address; - - *address = NULL; - default_address = talloc_asprintf(mem_ctx, "unix:path=%s/%s_%s", - PIPE_PATH, DATA_PROVIDER_PIPE, - domain_name); - if (default_address == NULL) { - return ENOMEM; - } - - *address = default_address; - return EOK; -} - diff --git a/server/providers/fail_over.c b/server/providers/fail_over.c deleted file mode 100644 index 7560b89ee..000000000 --- a/server/providers/fail_over.c +++ /dev/null @@ -1,651 +0,0 @@ -/* - SSSD - - Fail over helper functions. - - Authors: - Martin Nagy - - Copyright (C) Red Hat, Inc 2009 - - 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/dlinklist.h" -#include "util/refcount.h" -#include "util/util.h" -#include "providers/fail_over.h" -#include "resolv/async_resolv.h" - -#define STATUS_DIFF(p, now) ((now).tv_sec - (p)->last_status_change.tv_sec) -#define SERVER_NAME(s) ((s)->common ? (s)->common->name : "(no name)") - -#define DEFAULT_PORT_STATUS PORT_NEUTRAL -#define DEFAULT_SERVER_STATUS SERVER_NAME_NOT_RESOLVED - -struct fo_ctx { - struct fo_service *service_list; - struct server_common *server_common_list; - - /* Settings. */ - time_t retry_timeout; -}; - -struct fo_service { - struct fo_service *prev; - struct fo_service *next; - - struct fo_ctx *ctx; - char *name; - struct fo_server *active_server; - struct fo_server *last_tried_server; - struct fo_server *server_list; -}; - -struct fo_server { - struct fo_server *prev; - struct fo_server *next; - - void *user_data; - int port; - int port_status; - struct fo_service *service; - struct timeval last_status_change; - struct server_common *common; -}; - -struct server_common { - REFCOUNT_COMMON; - - struct server_common *prev; - struct server_common *next; - - char *name; - struct hostent *hostent; - struct resolve_service_request *request_list; - int server_status; - struct timeval last_status_change; -}; - -struct resolve_service_request { - struct resolve_service_request *prev; - struct resolve_service_request *next; - - struct server_common *server_common; - struct tevent_req *req; -}; - -struct status { - int value; - struct timeval last_change; -}; - -struct fo_ctx * -fo_context_init(TALLOC_CTX *mem_ctx, time_t retry_timeout) -{ - struct fo_ctx *ctx; - - ctx = talloc_zero(mem_ctx, struct fo_ctx); - if (ctx == NULL) { - DEBUG(1, ("No memory\n")); - return NULL; - } - - ctx->retry_timeout = retry_timeout; - - DEBUG(3, ("Created new fail over context, retry timeout is %d\n", - retry_timeout)); - return ctx; -} - -static const char * -str_port_status(enum port_status status) -{ - switch (status) { - case PORT_NEUTRAL: - return "neutral"; - case PORT_WORKING: - return "working"; - case PORT_NOT_WORKING: - return "not working"; - } - - return "unknown port status"; -} - -static const char * -str_server_status(enum server_status status) -{ - switch (status) { - case SERVER_NAME_NOT_RESOLVED: - return "name not resolved"; - case SERVER_RESOLVING_NAME: - return "resolving name"; - case SERVER_NAME_RESOLVED: - return "name resolved"; - case SERVER_WORKING: - return "working"; - case SERVER_NOT_WORKING: - return "not working"; - } - - return "unknown server status"; -} - -/* - * This function will return the status of the server. If the status was - * last updated a long time ago, we will first reset the status. - */ -static enum server_status -get_server_status(struct fo_server *server) -{ - struct timeval tv; - time_t timeout; - - if (server->common == NULL) - return SERVER_NAME_RESOLVED; - - DEBUG(7, ("Status of server '%s' is '%s'\n", SERVER_NAME(server), - str_server_status(server->common->server_status))); - - timeout = server->service->ctx->retry_timeout; - if (timeout != 0 && server->common->server_status == SERVER_NOT_WORKING) { - gettimeofday(&tv, NULL); - if (STATUS_DIFF(server->common, tv) > timeout) { - DEBUG(4, ("Reseting the server status of '%s'\n", - SERVER_NAME(server))); - server->common->server_status = SERVER_NAME_NOT_RESOLVED; - server->last_status_change.tv_sec = 0; - } - } - - return server->common->server_status; -} - -/* - * This function will return the status of the service. If the status was - * last updated a long time ago, we will first reset the status. - */ -static enum port_status -get_port_status(struct fo_server *server) -{ - struct timeval tv; - time_t timeout; - - DEBUG(7, ("Port status of port %d for server '%s' is '%s'\n", server->port, - SERVER_NAME(server), str_port_status(server->port_status))); - - timeout = server->service->ctx->retry_timeout; - if (timeout != 0 && server->port_status == PORT_NOT_WORKING) { - gettimeofday(&tv, NULL); - if (STATUS_DIFF(server, tv) > timeout) { - DEBUG(4, ("Reseting the status of port %d for server '%s'\n", - server->port, SERVER_NAME(server))); - server->port_status = PORT_NEUTRAL; - server->last_status_change.tv_sec = tv.tv_sec; - } - } - - return server->port_status; -} - -static int -server_works(struct fo_server *server) -{ - if (get_server_status(server) == SERVER_NOT_WORKING) - return 0; - - return 1; -} - -static int -service_works(struct fo_server *server) -{ - if (!server_works(server)) - return 0; - if (get_port_status(server) == PORT_NOT_WORKING) - return 0; - - return 1; -} - -static int -service_destructor(struct fo_service *service) -{ - DLIST_REMOVE(service->ctx->service_list, service); - return 0; -} - -int -fo_new_service(struct fo_ctx *ctx, const char *name, - struct fo_service **_service) -{ - struct fo_service *service; - int ret; - - DEBUG(3, ("Creating new service '%s'\n", name)); - ret = fo_get_service(ctx, name, &service); - if (ret == EOK) { - DEBUG(5, ("Service '%s' already exists\n", name)); - if (_service) { - *_service = service; - } - return EEXIST; - } else if (ret != ENOENT) { - return ret; - } - - service = talloc_zero(ctx, struct fo_service); - if (service == NULL) - return ENOMEM; - - service->name = talloc_strdup(service, name); - if (service->name == NULL) { - talloc_free(service); - return ENOMEM; - } - - service->ctx = ctx; - DLIST_ADD(ctx->service_list, service); - - talloc_set_destructor(service, service_destructor); - if (_service) { - *_service = service; - } - - return EOK; -} - -int -fo_get_service(struct fo_ctx *ctx, const char *name, - struct fo_service **_service) -{ - struct fo_service *service; - - DLIST_FOR_EACH(service, ctx->service_list) { - if (!strcmp(name, service->name)) { - *_service = service; - return EOK; - } - } - - return ENOENT; -} - -static int -get_server_common(TALLOC_CTX *mem_ctx, struct fo_ctx *ctx, const char *name, - struct server_common **_common) -{ - struct server_common *common; - - DLIST_FOR_EACH(common, ctx->server_common_list) { - if (!strcmp(name, common->name)) { - *_common = rc_reference(mem_ctx, struct server_common, common); - if (_common == NULL) - return ENOMEM; - return EOK; - } - } - - return ENOENT; -} - -static struct server_common * -create_server_common(TALLOC_CTX *mem_ctx, struct fo_ctx *ctx, const char *name) -{ - struct server_common *common; - - common = rc_alloc(mem_ctx, struct server_common); - if (common == NULL) - return NULL; - - common->name = talloc_strdup(common, name); - if (common->name == NULL) { - talloc_free(common); - return NULL; - } - - common->prev = NULL; - common->next = NULL; - common->hostent = NULL; - common->request_list = NULL; - common->server_status = DEFAULT_SERVER_STATUS; - common->last_status_change.tv_sec = 0; - common->last_status_change.tv_usec = 0; - - DLIST_ADD_END(ctx->server_common_list, common, struct server_common *); - return common; -} - -int -fo_add_server(struct fo_service *service, const char *name, int port, - void *user_data) -{ - struct fo_server *server; - int ret; - - DEBUG(3, ("Adding new server '%s', to service '%s'\n", - name ? name : "(no name)", service->name)); - DLIST_FOR_EACH(server, service->server_list) { - if (server->port != port || server->user_data != user_data) - continue; - if (name == NULL && server->common == NULL) { - return EEXIST; - } else if (name != NULL && server->common != NULL) { - if (!strcmp(name, server->common->name)) - return EEXIST; - } - } - - server = talloc_zero(service, struct fo_server); - if (server == NULL) - return ENOMEM; - - server->port = port; - server->user_data = user_data; - server->service = service; - server->port_status = DEFAULT_PORT_STATUS; - - if (name != NULL) { - ret = get_server_common(server, service->ctx, name, &server->common); - if (ret == ENOENT) { - server->common = create_server_common(server, service->ctx, name); - if (server->common == NULL) { - talloc_free(server); - return ENOMEM; - } - } else if (ret != EOK) { - talloc_free(server); - return ret; - } - } - - DLIST_ADD_END(service->server_list, server, struct fo_server *); - - return EOK; -} - -static int -get_first_server_entity(struct fo_service *service, struct fo_server **_server) -{ - struct fo_server *server; - - /* If we already have a working server, use that one. */ - server = service->active_server; - if (server != NULL) { - if (service_works(server)) { - goto done; - } - service->active_server = NULL; - } - - /* - * Otherwise iterate through the server list. - */ - - /* First, try servers after the last one we tried. */ - if (service->last_tried_server != NULL) { - DLIST_FOR_EACH(server, service->last_tried_server->next) { - if (service_works(server)) { - goto done; - } - } - } - - /* If none were found, try at the start. */ - DLIST_FOR_EACH(server, service->server_list) { - if (service_works(server)) { - goto done; - } - if (server == service->last_tried_server) { - break; - } - } - - service->last_tried_server = NULL; - return ENOENT; - -done: - service->last_tried_server = server; - *_server = server; - return EOK; -} - -static int -resolve_service_request_destructor(struct resolve_service_request *request) -{ - DLIST_REMOVE(request->server_common->request_list, request); - return 0; -} - -static int -set_lookup_hook(struct fo_server *server, struct tevent_req *req) -{ - struct resolve_service_request *request; - - request = talloc(req, struct resolve_service_request); - if (request == NULL) { - DEBUG(1, ("No memory\n")); - talloc_free(request); - return ENOMEM; - } - request->server_common = server->common; - request->req = req; - DLIST_ADD(server->common->request_list, request); - talloc_set_destructor(request, resolve_service_request_destructor); - - return EOK; -} - -/******************************************************************* - * Get server to connect to. * - *******************************************************************/ - -struct resolve_service_state { - struct fo_server *server; -}; - -static void fo_resolve_service_done(struct tevent_req *subreq); - -struct tevent_req * -fo_resolve_service_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, - struct resolv_ctx *resolv, struct fo_service *service) -{ - int ret; - struct fo_server *server; - struct tevent_req *req; - struct tevent_req *subreq; - struct resolve_service_state *state; - - DEBUG(4, ("Trying to resolve service '%s'\n", service->name)); - req = tevent_req_create(mem_ctx, &state, struct resolve_service_state); - if (req == NULL) - return NULL; - - ret = get_first_server_entity(service, &server); - if (ret != EOK) { - DEBUG(1, ("No available servers for service '%s'\n", service->name)); - goto done; - } - - state->server = server; - - if (server->common == NULL) { - /* This server doesn't have a name, we don't do name resolution. */ - tevent_req_done(req); - tevent_req_post(req, ev); - return req; - } - - switch (get_server_status(server)) { - case SERVER_NAME_NOT_RESOLVED: /* Request name resolution. */ - subreq = resolv_gethostbyname_send(server->common, ev, resolv, - server->common->name); - if (subreq == NULL) { - ret = ENOMEM; - goto done; - } - tevent_req_set_callback(subreq, fo_resolve_service_done, server->common); - fo_set_server_status(server, SERVER_RESOLVING_NAME); - /* FALLTHROUGH */ - case SERVER_RESOLVING_NAME: - /* Name resolution is already under way. Just add ourselves into the - * waiting queue so we get notified after the operation is finished. */ - ret = set_lookup_hook(server, req); - if (ret != EOK) - goto done; - break; - default: /* The name is already resolved. Return immediately. */ - tevent_req_done(req); - tevent_req_post(req, ev); - break; - } - -done: - if (ret != EOK) { - tevent_req_error(req, ret); - tevent_req_post(req, ev); - } - return req; -} - -static void set_server_common_status(struct server_common *common, - enum server_status status); - -static void -fo_resolve_service_done(struct tevent_req *subreq) -{ - int resolv_status; - struct resolve_service_request *request; - struct server_common *common; - int ret; - - common = tevent_req_callback_data(subreq, struct server_common); - - if (common->hostent != NULL) { - talloc_zfree(common->hostent); - } - - ret = resolv_gethostbyname_recv(subreq, common, - &resolv_status, NULL, &common->hostent); - talloc_free(subreq); - if (ret != EOK) { - DEBUG(1, ("Failed to resolve server '%s': %s\n", common->name, - resolv_strerror(resolv_status))); - set_server_common_status(common, SERVER_NOT_WORKING); - } else { - set_server_common_status(common, SERVER_NAME_RESOLVED); - } - - /* Take care of all requests for this server. */ - while ((request = common->request_list) != NULL) { - DLIST_REMOVE(common->request_list, request); - if (resolv_status) { - /* FIXME FIXME: resolv_status is an ARES error. - * but any caller will expect classic error codes. - * also the send() function may return ENOENT, so this mix - * IS explosive (ENOENT = 2 = ARES_EFORMER) */ - tevent_req_error(request->req, resolv_status); - } else { - tevent_req_done(request->req); - } - } -} - -int -fo_resolve_service_recv(struct tevent_req *req, struct fo_server **server) -{ - struct resolve_service_state *state; - - state = tevent_req_data(req, struct resolve_service_state); - - /* always return the server if asked for, otherwise the caller - * cannot mark it as faulty in case we return an error */ - if (server) - *server = state->server; - - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - -static void -set_server_common_status(struct server_common *common, - enum server_status status) -{ - DEBUG(4, ("Marking server '%s' as '%s'\n", common->name, - str_server_status(status))); - - common->server_status = status; - gettimeofday(&common->last_status_change, NULL); -} - -void -fo_set_server_status(struct fo_server *server, enum server_status status) -{ - if (server->common == NULL) { - DEBUG(1, ("Bug: Trying to set server status of a name-less server\n")); - return; - } - - set_server_common_status(server->common, status); -} - -void -fo_set_port_status(struct fo_server *server, enum port_status status) -{ - DEBUG(4, ("Marking port %d of server '%s' as '%s'\n", server->port, - SERVER_NAME(server), str_port_status(status))); - - server->port_status = status; - gettimeofday(&server->last_status_change, NULL); - if (status == PORT_WORKING) { - fo_set_server_status(server, SERVER_WORKING); - server->service->active_server = server; - } -} - -void * -fo_get_server_user_data(struct fo_server *server) -{ - return server->user_data; -} - -int -fo_get_server_port(struct fo_server *server) -{ - return server->port; -} - -const char *fo_get_server_name(struct fo_server *server) -{ - return server->common->name; -} - -struct hostent * -fo_get_server_hostent(struct fo_server *server) -{ - if (server->common == NULL) { - DEBUG(1, ("Bug: Trying to get hostent from a name-less server\n")); - return NULL; - } - return server->common->hostent; -} diff --git a/server/providers/fail_over.h b/server/providers/fail_over.h deleted file mode 100644 index e581fbaf5..000000000 --- a/server/providers/fail_over.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef __FAIL_OVER_H__ -#define __FAIL_OVER_H__ - -#include -#include - -/* Some forward declarations that don't have to do anything with fail over. */ -struct hostent; -struct resolv_ctx; -struct tevent_context; -struct tevent_req; - -enum port_status { - PORT_NEUTRAL, /* We didn't try this port yet. */ - PORT_WORKING, /* This port was reported to work. */ - PORT_NOT_WORKING /* This port was reported to not work. */ -}; - -enum server_status { - SERVER_NAME_NOT_RESOLVED, /* We didn't yet resolved the host name. */ - SERVER_RESOLVING_NAME, /* Name resolving is in progress. */ - SERVER_NAME_RESOLVED, /* We resolved the host name but didn't try to connect. */ - SERVER_WORKING, /* We successfully connected to the server. */ - SERVER_NOT_WORKING /* We tried and failed to connect to the server. */ -}; - -struct fo_ctx; -struct fo_service; -struct fo_server; - -/* - * Create a new fail over context. The 'retry_timeout' argument specifies the - * duration in seconds of how long a server or port will be considered - * non-working after being marked as such. - */ -struct fo_ctx *fo_context_init(TALLOC_CTX *mem_ctx, - time_t retry_timeout); - -/* - * Create a new service structure for 'ctx', saving it to the location pointed - * to by '_service'. The needed memory will be allocated from 'ctx'. - * Service name will be set to 'name'. - */ -int fo_new_service(struct fo_ctx *ctx, - const char *name, - struct fo_service **_service); - -/* - * Look up service named 'name' from the 'ctx' service list. Target of - * '_service' will be set to the service if it was found. - */ -int fo_get_service(struct fo_ctx *ctx, - const char *name, - struct fo_service **_service); - -/* - * Adds a server 'name' to the 'service'. Port 'port' will be used for - * connection. If 'name' is NULL, no server resolution will be done. - */ -int fo_add_server(struct fo_service *service, - const char *name, - int port, - void *user_data); - -/* - * Request the first server from the service's list of servers. It is only - * considered if it is not marked as not working (or the retry interval already - * passed). If the server address wasn't resolved yet, it will be done. - */ -struct tevent_req *fo_resolve_service_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct resolv_ctx *resolv, - struct fo_service *service); - -int fo_resolve_service_recv(struct tevent_req *req, - struct fo_server **server); - -/* - * Set feedback about 'server'. Caller should use this to indicate a problem - * with the server itself, not only with the service on that server. This - * should be used, for example, when the IP address of the server can't be - * reached. This setting can affect other services as well, since they can - * share the same server. - */ -void fo_set_server_status(struct fo_server *server, - enum server_status status); - -/* - * Set feedback about the port status. This function should be used when - * the server itself is working but the service is not. When status is set - * to PORT_WORKING, 'server' is also marked as an "active server" for its - * service. When the next fo_resolve_service_send() function is called, this - * server will be preferred. This will hold as long as it is not marked as - * not-working. - */ -void fo_set_port_status(struct fo_server *server, - enum port_status status); - - -void *fo_get_server_user_data(struct fo_server *server); - -int fo_get_server_port(struct fo_server *server); - -const char *fo_get_server_name(struct fo_server *server); - -struct hostent *fo_get_server_hostent(struct fo_server *server); - -#endif /* !__FAIL_OVER_H__ */ diff --git a/server/providers/ipa/ipa_access.c b/server/providers/ipa/ipa_access.c deleted file mode 100644 index 7dfe1fd90..000000000 --- a/server/providers/ipa/ipa_access.c +++ /dev/null @@ -1,1823 +0,0 @@ -/* - SSSD - - IPA Backend Module -- Access control - - 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" -#include "providers/ldap/sdap_async.h" -#include "providers/ipa/ipa_common.h" -#include "providers/ipa/ipa_access.h" -#include "providers/ipa/ipa_timerules.h" - -#define IPA_HOST_MEMBEROF "memberOf" -#define IPA_HOST_SERVERHOSTNAME "serverHostName" -#define IPA_HOST_FQDN "fqdn" -#define IPA_ACCESS_RULE_TYPE "accessRuleType" -#define IPA_MEMBER_USER "memberUser" -#define IPA_USER_CATEGORY "userCategory" -#define IPA_SERVICE_NAME "serviceName" -#define IPA_SOURCE_HOST "sourceHost" -#define IPA_SOURCE_HOST_CATEGORY "sourceHostCategory" -#define IPA_EXTERNAL_HOST "externalHost" -#define IPA_ACCESS_TIME "accessTime" -#define IPA_UNIQUE_ID "ipauniqueid" -#define IPA_ENABLED_FLAG "ipaenabledflag" -#define IPA_MEMBER_HOST "memberHost" -#define IPA_HOST_CATEGORY "hostCategory" -#define IPA_CN "cn" - -#define IPA_HOST_BASE_TMPL "cn=computers,cn=accounts,dc=%s" -#define IPA_HBAC_BASE_TMPL "cn=hbac,dc=%s" - -#define SYSDB_HBAC_BASE_TMPL "cn=hbac,"SYSDB_TMPL_CUSTOM_BASE - -#define HBAC_RULES_SUBDIR "hbac_rules" -#define HBAC_HOSTS_SUBDIR "hbac_hosts" - -static errno_t msgs2attrs_array(TALLOC_CTX *mem_ctx, size_t count, - struct ldb_message **msgs, - struct sysdb_attrs ***attrs) -{ - int i; - struct sysdb_attrs **a; - - a = talloc_array(mem_ctx, struct sysdb_attrs *, count); - if (a == NULL) { - DEBUG(1, ("talloc_array failed.\n")); - return ENOMEM; - } - - for (i = 0; i < count; i++) { - a[i] = talloc(a, struct sysdb_attrs); - if (a[i] == NULL) { - DEBUG(1, ("talloc_array failed.\n")); - talloc_free(a); - return ENOMEM; - } - a[i]->num = msgs[i]->num_elements; - a[i]->a = talloc_steal(a[i], msgs[i]->elements); - } - - *attrs = a; - - return EOK; -} - -static void ipa_access_reply(struct be_req *be_req, int pam_status) -{ - struct pam_data *pd; - pd = talloc_get_type(be_req->req_data, struct pam_data); - pd->pam_status = pam_status; - - if (pam_status == PAM_SUCCESS) { - be_req->fn(be_req, DP_ERR_OK, pam_status, NULL); - } else { - be_req->fn(be_req, DP_ERR_FATAL, pam_status, NULL); - } -} - -struct hbac_get_user_info_state { - struct tevent_context *ev; - struct be_ctx *be_ctx;; - struct sysdb_handle *handle; - - const char *user; - const char *user_orig_dn; - struct ldb_dn *user_dn; - size_t groups_count; - const char **groups; -}; - -static void search_user_done(struct tevent_req *subreq); -static void search_groups_done(struct tevent_req *subreq); - -struct tevent_req *hbac_get_user_info_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct be_ctx *be_ctx, - const char *user) -{ - struct tevent_req *req = NULL; - struct tevent_req *subreq = NULL; - struct hbac_get_user_info_state *state; - int ret; - const char **attrs; - - req = tevent_req_create(memctx, &state, struct hbac_get_user_info_state); - if (req == NULL) { - DEBUG(1, ("tevent_req_create failed.\n")); - return NULL; - } - - state->ev = ev; - state->be_ctx = be_ctx; - state->handle = NULL; - state->user = user; - state->user_orig_dn = NULL; - state->user_dn = NULL; - state->groups_count = 0; - state->groups = NULL; - - attrs = talloc_array(state, const char *, 2); - if (attrs == NULL) { - ret = ENOMEM; - goto fail; - } - - attrs[0] = SYSDB_ORIG_DN; - attrs[1] = NULL; - - subreq = sysdb_search_user_by_name_send(state, ev, be_ctx->sysdb, NULL, - be_ctx->domain, user, attrs); - if (subreq == NULL) { - DEBUG(1, ("sysdb_search_user_by_name_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, search_user_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void search_user_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_user_info_state *state = tevent_req_data(req, - struct hbac_get_user_info_state); - int ret; - const char **attrs; - const char *dummy; - struct ldb_message *user_msg; - - - ret = sysdb_search_user_recv(subreq, state, &user_msg); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - DEBUG(9, ("Found user info for user [%s].\n", state->user)); - state->user_dn = talloc_steal(state, user_msg->dn); - dummy = ldb_msg_find_attr_as_string(user_msg, SYSDB_ORIG_DN, NULL); - if (dummy == NULL) { - DEBUG(1, ("Original DN of user [%s] not available.\n", state->user)); - ret = EINVAL; - goto failed; - } - state->user_orig_dn = talloc_strdup(state, dummy); - if (state->user_dn == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - ret = ENOMEM; - goto failed; - } - DEBUG(9, ("Found original DN [%s] for user [%s].\n", state->user_orig_dn, - state->user)); - - attrs = talloc_array(state, const char *, 2); - if (attrs == NULL) { - DEBUG(1, ("talloc_array failed.\n")); - ret = ENOMEM; - goto failed; - } - attrs[0] = SYSDB_ORIG_DN; - attrs[1] = NULL; - - subreq = sysdb_asq_search_send(state, state->ev, state->be_ctx->sysdb, NULL, - state->be_ctx->domain, state->user_dn, NULL, - SYSDB_MEMBEROF, attrs); - if (subreq == NULL) { - DEBUG(1, ("sysdb_asq_search_send failed.\n")); - ret = ENOMEM; - goto failed; - } - - tevent_req_set_callback(subreq, search_groups_done, req); - return; - -failed: - tevent_req_error(req, ret); - return; -} - -static void search_groups_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_user_info_state *state = tevent_req_data(req, - struct hbac_get_user_info_state); - int ret; - int i; - struct ldb_message **msg; - - ret = sysdb_asq_search_recv(subreq, state, &state->groups_count, &msg); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - if (state->groups_count == 0) { - tevent_req_done(req); - return; - } - - state->groups = talloc_array(state, const char *, state->groups_count); - if (state->groups == NULL) { - DEBUG(1, ("talloc_groups failed.\n")); - ret = ENOMEM; - goto failed; - } - - for(i = 0; i < state->groups_count; i++) { - if (msg[i]->num_elements != 1) { - DEBUG(1, ("Unexpected number of elements.\n")); - ret = EINVAL; - goto failed; - } - - if (msg[i]->elements[0].num_values != 1) { - DEBUG(1, ("Unexpected number of values.\n")); - ret = EINVAL; - goto failed; - } - - state->groups[i] = talloc_strndup(state->groups, - (const char *) msg[i]->elements[0].values[0].data, - msg[i]->elements[0].values[0].length); - if (state->groups[i] == NULL) { - DEBUG(1, ("talloc_strndup failed.\n")); - ret = ENOMEM; - goto failed; - } - - DEBUG(9, ("Found group [%s].\n", state->groups[i])); - } - - tevent_req_done(req); - return; - -failed: - talloc_free(state->groups); - tevent_req_error(req, ret); - return; -} - -static int hbac_get_user_info_recv(struct tevent_req *req, TALLOC_CTX *memctx, - const char **user_dn, size_t *groups_count, - const char ***groups) -{ - struct hbac_get_user_info_state *state = tevent_req_data(req, - struct hbac_get_user_info_state); - int i; - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *user_dn = talloc_steal(memctx, state->user_orig_dn); - *groups_count = state->groups_count; - for (i = 0; i < state->groups_count; i++) { - talloc_steal(memctx, state->groups[i]); - } - *groups = talloc_steal(memctx, state->groups); - - return EOK; -} - - -struct hbac_get_host_info_state { - struct tevent_context *ev; - struct sdap_id_ctx *sdap_ctx; - struct sysdb_ctx *sysdb; - struct sysdb_handle *handle; - bool offline; - - char *host_filter; - char *host_search_base; - const char **host_attrs; - - struct sysdb_attrs **host_reply_list; - size_t host_reply_count; - size_t current_item; - struct hbac_host_info **hbac_host_info; -}; - -static void hbac_get_host_info_connect_done(struct tevent_req *subreq); -static void hbac_get_host_memberof_done(struct tevent_req *subreq); -static void hbac_get_host_info_sysdb_transaction_started(struct tevent_req *subreq); -static void hbac_get_host_info_store_prepare(struct tevent_req *req); -static void hbac_get_host_info_store_done(struct tevent_req *subreq); - -static struct tevent_req *hbac_get_host_info_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - bool offline, - struct sdap_id_ctx *sdap_ctx, - struct sysdb_ctx *sysdb, - const char *ipa_domain, - const char **hostnames) -{ - struct tevent_req *req = NULL; - struct tevent_req *subreq = NULL; - struct hbac_get_host_info_state *state; - int ret; - int i; - - if (hostnames == NULL || ipa_domain == NULL) { - DEBUG(1, ("Missing hostnames or domain.\n")); - return NULL; - } - - req = tevent_req_create(memctx, &state, struct hbac_get_host_info_state); - if (req == NULL) { - DEBUG(1, ("tevent_req_create failed.\n")); - return NULL; - } - - state->ev = ev; - state->sdap_ctx = sdap_ctx; - state->sysdb = sysdb; - state->handle = NULL; - state->offline = offline; - - state->host_reply_list = NULL; - state->host_reply_count = 0; - state->current_item = 0; - state->hbac_host_info = NULL; - - state->host_filter = talloc_asprintf(state, "(|"); - if (state->host_filter == NULL) { - DEBUG(1, ("Failed to create filter.\n")); - ret = ENOMEM; - goto fail; - } - for (i = 0; hostnames[i] != NULL; i++) { - state->host_filter = talloc_asprintf_append(state->host_filter, - "(&(objectclass=ipaHost)" - "(|(fqdn=%s)(serverhostname=%s)))", - hostnames[i], hostnames[i]); - if (state->host_filter == NULL) { - ret = ENOMEM; - goto fail; - } - } - state->host_filter = talloc_asprintf_append(state->host_filter, ")"); - if (state->host_filter == NULL) { - ret = ENOMEM; - goto fail; - } - - state->host_search_base = talloc_asprintf(state, IPA_HOST_BASE_TMPL, - ipa_domain); - if (state->host_search_base == NULL) { - DEBUG(1, ("Failed to create host search base.\n")); - ret = ENOMEM; - goto fail; - } - - state->host_attrs = talloc_array(state, const char *, 7); - if (state->host_attrs == NULL) { - DEBUG(1, ("Failed to allocate host attribute list.\n")); - ret = ENOMEM; - goto fail; - } - state->host_attrs[0] = IPA_HOST_MEMBEROF; - state->host_attrs[1] = IPA_HOST_SERVERHOSTNAME; - state->host_attrs[2] = IPA_HOST_FQDN; - state->host_attrs[3] = "objectClass"; - state->host_attrs[4] = SYSDB_ORIG_DN; - state->host_attrs[5] = SYSDB_ORIG_MEMBEROF; - state->host_attrs[6] = NULL; - - if (offline) { - subreq = sysdb_search_custom_send(state, state->ev, state->sysdb, NULL, - state->sdap_ctx->be->domain, - state->host_filter, HBAC_HOSTS_SUBDIR, - state->host_attrs); - if (subreq == NULL) { - DEBUG(1, ("sysdb_search_custom_send.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_get_host_memberof_done, req); - - return req; - } - - if (sdap_ctx->gsh == NULL || ! sdap_ctx->gsh->connected) { - if (sdap_ctx->gsh != NULL) { - talloc_zfree(sdap_ctx->gsh); - } - - subreq = sdap_cli_connect_send(state, ev, sdap_ctx->opts, - sdap_ctx->be, sdap_ctx->service, NULL); - if (!subreq) { - DEBUG(1, ("sdap_cli_connect_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_get_host_info_connect_done, req); - - return req; - } - - subreq = sdap_get_generic_send(state, state->ev, - state->sdap_ctx->opts, - state->sdap_ctx->gsh, - state->host_search_base, - LDAP_SCOPE_SUB, - state->host_filter, - state->host_attrs, - NULL, 0); - - if (subreq == NULL) { - DEBUG(1, ("sdap_get_generic_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_get_host_memberof_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void hbac_get_host_info_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_host_info_state *state = tevent_req_data(req, - struct hbac_get_host_info_state); - int ret; - - ret = sdap_cli_connect_recv(subreq, state->sdap_ctx, &state->sdap_ctx->gsh, - NULL); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - subreq = sdap_get_generic_send(state, state->ev, - state->sdap_ctx->opts, - state->sdap_ctx->gsh, - state->host_search_base, - LDAP_SCOPE_SUB, - state->host_filter, - state->host_attrs, - NULL, 0); - - if (subreq == NULL) { - DEBUG(1, ("sdap_get_generic_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_get_host_memberof_done, req); - - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_get_host_memberof_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_host_info_state *state = tevent_req_data(req, - struct hbac_get_host_info_state); - int ret; - int i; - int v; - struct ldb_message_element *el; - struct hbac_host_info **hhi; - struct ldb_message **msgs; - - if (state->offline) { - ret = sysdb_search_custom_recv(subreq, state, &state->host_reply_count, - &msgs); - } else { - ret = sdap_get_generic_recv(subreq, state, &state->host_reply_count, - &state->host_reply_list); - } - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - if (state->host_reply_count == 0) { - DEBUG(1, ("No hosts not found in IPA server.\n")); - ret = ENOENT; - goto fail; - } - - if (state->offline) { - ret = msgs2attrs_array(state, state->host_reply_count, msgs, - &state->host_reply_list); - talloc_zfree(msgs); - if (ret != EOK) { - DEBUG(1, ("msgs2attrs_array failed.\n")); - goto fail; - } - } - - hhi = talloc_array(state, struct hbac_host_info *, state->host_reply_count + 1); - if (hhi == NULL) { - DEBUG(1, ("talloc_array failed.\n")); - ret = ENOMEM; - goto fail; - } - memset(hhi, 0, - sizeof(struct hbac_host_info *) * (state->host_reply_count + 1)); - - for (i = 0; i < state->host_reply_count; i++) { - hhi[i] = talloc_zero(hhi, struct hbac_host_info); - if (hhi[i] == NULL) { - ret = ENOMEM; - goto fail; - } - - ret = sysdb_attrs_get_el(state->host_reply_list[i], SYSDB_ORIG_DN, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - if (el->num_values == 0) { - ret = EINVAL; - goto fail; - } - DEBUG(9, ("OriginalDN: [%.*s].\n", el->values[0].length, - (char *)el->values[0].data)); - hhi[i]->dn = talloc_strndup(hhi, (char *)el->values[0].data, - el->values[0].length); - if (hhi[i]->dn == NULL) { - ret = ENOMEM; - goto fail; - } - - ret = sysdb_attrs_get_el(state->host_reply_list[i], - IPA_HOST_SERVERHOSTNAME, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - if (el->num_values == 0) { - ret = EINVAL; - goto fail; - } - DEBUG(9, ("ServerHostName: [%.*s].\n", el->values[0].length, - (char *)el->values[0].data)); - hhi[i]->serverhostname = talloc_strndup(hhi, (char *)el->values[0].data, - el->values[0].length); - if (hhi[i]->serverhostname == NULL) { - ret = ENOMEM; - goto fail; - } - - ret = sysdb_attrs_get_el(state->host_reply_list[i], - IPA_HOST_FQDN, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - if (el->num_values == 0) { - ret = EINVAL; - goto fail; - } - DEBUG(9, ("FQDN: [%.*s].\n", el->values[0].length, - (char *)el->values[0].data)); - hhi[i]->fqdn = talloc_strndup(hhi, (char *)el->values[0].data, - el->values[0].length); - if (hhi[i]->fqdn == NULL) { - ret = ENOMEM; - goto fail; - } - - ret = sysdb_attrs_get_el(state->host_reply_list[i], - state->offline ? SYSDB_ORIG_MEMBEROF : - IPA_HOST_MEMBEROF, - &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - - hhi[i]->memberof = talloc_array(hhi, const char *, el->num_values + 1); - if (hhi[i]->memberof == NULL) { - ret = ENOMEM; - goto fail; - } - memset(hhi[i]->memberof, 0, - sizeof(const char *) * (el->num_values + 1)); - - for(v = 0; v < el->num_values; v++) { - DEBUG(9, ("%s: [%.*s].\n", IPA_HOST_MEMBEROF, el->values[v].length, - (const char *)el->values[v].data)); - hhi[i]->memberof[v] = talloc_strndup(hhi, - (const char *)el->values[v].data, - el->values[v].length); - if (hhi[i]->memberof[v] == NULL) { - ret = ENOMEM; - goto fail; - } - } - } - - state->hbac_host_info = hhi; - - if (state->offline) { - tevent_req_done(req); - return; - } - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (subreq == NULL) { - DEBUG(1, ("sysdb_transaction_send failed.\n")); - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, hbac_get_host_info_sysdb_transaction_started, req); - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_get_host_info_sysdb_transaction_started( - struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_host_info_state *state = tevent_req_data(req, - struct hbac_get_host_info_state); - int ret; - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - state->current_item = 0; - hbac_get_host_info_store_prepare(req); - return; -} - -static void hbac_get_host_info_store_prepare(struct tevent_req *req) -{ - struct hbac_get_host_info_state *state = tevent_req_data(req, - struct hbac_get_host_info_state); - int ret; - char *object_name; - struct ldb_message_element *el; - struct tevent_req *subreq; - - if (state->current_item < state->host_reply_count) { - ret = sysdb_attrs_get_el(state->host_reply_list[state->current_item], - IPA_HOST_FQDN, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - if (el->num_values == 0) { - ret = EINVAL; - goto fail; - } - object_name = talloc_strndup(state, (const char *)el->values[0].data, - el->values[0].length); - if (object_name == NULL) { - ret = ENOMEM; - goto fail; - } - DEBUG(9, ("Fqdn [%s].\n", object_name)); - - - ret = sysdb_attrs_replace_name( - state->host_reply_list[state->current_item], - IPA_HOST_MEMBEROF, SYSDB_ORIG_MEMBEROF); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_replace_name failed.\n")); - goto fail; - } - - subreq = sysdb_store_custom_send(state, state->ev, - state->handle, - state->sdap_ctx->be->domain, - object_name, - HBAC_HOSTS_SUBDIR, - state->host_reply_list[state->current_item]); - - if (subreq == NULL) { - DEBUG(1, ("sysdb_store_custom_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_get_host_info_store_done, req); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (subreq == NULL) { - DEBUG(1, ("sysdb_transaction_commit_send failed.\n")); - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, sysdb_transaction_complete, req); - - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_get_host_info_store_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_host_info_state *state = tevent_req_data(req, - struct hbac_get_host_info_state); - int ret; - - ret = sysdb_store_custom_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - state->current_item++; - hbac_get_host_info_store_prepare(req); -} - -static int hbac_get_host_info_recv(struct tevent_req *req, TALLOC_CTX *memctx, - struct hbac_host_info ***hhi) -{ - struct hbac_get_host_info_state *state = tevent_req_data(req, - struct hbac_get_host_info_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *hhi = talloc_steal(memctx, state->hbac_host_info); - return EOK; -} - - -struct hbac_get_rules_state { - struct tevent_context *ev; - struct sdap_id_ctx *sdap_ctx; - struct sysdb_ctx *sysdb; - struct sysdb_handle *handle; - bool offline; - - const char *host_dn; - const char **memberof; - char *hbac_filter; - char *hbac_search_base; - const char **hbac_attrs; - - struct ldb_message *old_rules; - struct sysdb_attrs **hbac_reply_list; - size_t hbac_reply_count; - int current_item; -}; - -static void hbac_get_rules_connect_done(struct tevent_req *subreq); -static void hbac_rule_get_done(struct tevent_req *subreq); -static void hbac_rule_sysdb_transaction_started(struct tevent_req *subreq); -static void hbac_rule_sysdb_delete_done(struct tevent_req *subreq); -static void hbac_rule_store_prepare(struct tevent_req *req); -static void hbac_rule_store_done(struct tevent_req *subreq); - -static struct tevent_req *hbac_get_rules_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - bool offline, - struct sdap_id_ctx *sdap_ctx, - struct sysdb_ctx *sysdb, - const char *ipa_domain, - const char *host_dn, - const char **memberof) -{ - struct tevent_req *req = NULL; - struct tevent_req *subreq = NULL; - struct hbac_get_rules_state *state; - int ret; - int i; - - if (host_dn == NULL || ipa_domain == NULL) { - DEBUG(1, ("Missing host_dn or domain.\n")); - return NULL; - } - - req = tevent_req_create(memctx, &state, struct hbac_get_rules_state); - if (req == NULL) { - DEBUG(1, ("tevent_req_create failed.\n")); - return NULL; - } - - state->ev = ev; - state->offline = offline; - state->sdap_ctx = sdap_ctx; - state->sysdb = sysdb; - state->handle = NULL; - state->host_dn = host_dn; - state->memberof = memberof; - - state->old_rules = NULL; - state->hbac_reply_list = NULL; - state->hbac_reply_count = 0; - state->current_item = 0; - - state->hbac_search_base = talloc_asprintf(state, IPA_HBAC_BASE_TMPL, - ipa_domain); - if (state->hbac_search_base == NULL) { - DEBUG(1, ("Failed to create HBAC search base.\n")); - ret = ENOMEM; - goto fail; - } - - state->hbac_attrs = talloc_array(state, const char *, 16); - if (state->hbac_attrs == NULL) { - DEBUG(1, ("Failed to allocate HBAC attribute list.\n")); - ret = ENOMEM; - goto fail; - } - state->hbac_attrs[0] = IPA_ACCESS_RULE_TYPE; - state->hbac_attrs[1] = IPA_MEMBER_USER; - state->hbac_attrs[2] = IPA_USER_CATEGORY; - state->hbac_attrs[3] = IPA_SERVICE_NAME; - state->hbac_attrs[4] = IPA_SOURCE_HOST; - state->hbac_attrs[5] = IPA_SOURCE_HOST_CATEGORY; - state->hbac_attrs[6] = IPA_EXTERNAL_HOST; - state->hbac_attrs[7] = IPA_ACCESS_TIME; - state->hbac_attrs[8] = IPA_UNIQUE_ID; - state->hbac_attrs[9] = IPA_ENABLED_FLAG; - state->hbac_attrs[10] = IPA_CN; - state->hbac_attrs[11] = "objectclass"; - state->hbac_attrs[12] = IPA_MEMBER_HOST; - state->hbac_attrs[13] = IPA_HOST_CATEGORY; - state->hbac_attrs[14] = SYSDB_ORIG_DN; - state->hbac_attrs[15] = NULL; - - state->hbac_filter = talloc_asprintf(state, - "(&(objectclass=ipaHBACRule)" - "(|(%s=%s)(%s=%s)", - IPA_HOST_CATEGORY, "all", - IPA_MEMBER_HOST, host_dn); - if (state->hbac_filter == NULL) { - ret = ENOMEM; - goto fail; - } - for (i = 0; memberof[i] != NULL; i++) { - state->hbac_filter = talloc_asprintf_append(state->hbac_filter, - "(%s=%s)", - IPA_MEMBER_HOST, - memberof[i]); - if (state->hbac_filter == NULL) { - ret = ENOMEM; - goto fail; - } - } - state->hbac_filter = talloc_asprintf_append(state->hbac_filter, "))"); - if (state->hbac_filter == NULL) { - ret = ENOMEM; - goto fail; - } - - DEBUG(9, ("HBAC rule filter: [%s].\n", state->hbac_filter)); - - if (offline) { - subreq = sysdb_search_custom_send(state, state->ev, state->sysdb, NULL, - state->sdap_ctx->be->domain, - state->hbac_filter, HBAC_RULES_SUBDIR, - state->hbac_attrs); - if (subreq == NULL) { - DEBUG(1, ("sysdb_search_custom_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_rule_get_done, req); - - return req; - } - - if (sdap_ctx->gsh == NULL || ! sdap_ctx->gsh->connected) { - if (sdap_ctx->gsh != NULL) { - talloc_zfree(sdap_ctx->gsh); - } - - subreq = sdap_cli_connect_send(state, ev, sdap_ctx->opts, - sdap_ctx->be, sdap_ctx->service, NULL); - if (!subreq) { - DEBUG(1, ("sdap_cli_connect_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_get_rules_connect_done, req); - - return req; - } - - subreq = sdap_get_generic_send(state, state->ev, - state->sdap_ctx->opts, - state->sdap_ctx->gsh, - state->hbac_search_base, - LDAP_SCOPE_SUB, - state->hbac_filter, - state->hbac_attrs, - NULL, 0); - - if (subreq == NULL) { - DEBUG(1, ("sdap_get_generic_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_rule_get_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void hbac_get_rules_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int ret; - - ret = sdap_cli_connect_recv(subreq, state->sdap_ctx, &state->sdap_ctx->gsh, - NULL); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - subreq = sdap_get_generic_send(state, state->ev, - state->sdap_ctx->opts, - state->sdap_ctx->gsh, - state->hbac_search_base, - LDAP_SCOPE_SUB, - state->hbac_filter, - state->hbac_attrs, - NULL, 0); - - if (subreq == NULL) { - DEBUG(1, ("sdap_get_generic_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_rule_get_done, req); - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_rule_get_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int ret; - int i; - struct ldb_message_element *el; - struct ldb_message **msgs; - - if (state->offline) { - ret = sysdb_search_custom_recv(subreq, state, &state->hbac_reply_count, - &msgs); - } else { - ret = sdap_get_generic_recv(subreq, state, &state->hbac_reply_count, - &state->hbac_reply_list); - } - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - if (state->offline) { - ret = msgs2attrs_array(state, state->hbac_reply_count, msgs, - &state->hbac_reply_list); - talloc_zfree(msgs); - if (ret != EOK) { - DEBUG(1, ("msgs2attrs_array failed.\n")); - goto fail; - } - } - - for (i = 0; i < state->hbac_reply_count; i++) { - ret = sysdb_attrs_get_el(state->hbac_reply_list[i], SYSDB_ORIG_DN, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - if (el->num_values == 0) { - DEBUG(1, ("Missing original DN.\n")); - ret = EINVAL; - goto fail; - } - DEBUG(9, ("OriginalDN: [%s].\n", (const char *)el->values[0].data)); - } - - if (state->hbac_reply_count == 0 || state->offline) { - tevent_req_done(req); - return; - } - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (subreq == NULL) { - DEBUG(1, ("sysdb_transaction_send failed.\n")); - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, hbac_rule_sysdb_transaction_started, req); - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_rule_sysdb_transaction_started(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int ret; - struct ldb_dn *hbac_base_dn; - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - hbac_base_dn = sysdb_custom_subtree_dn(state->sysdb, state, - state->sdap_ctx->be->domain->name, - HBAC_RULES_SUBDIR); - if (hbac_base_dn == NULL) { - ret = ENOMEM; - goto fail; - } - subreq = sysdb_delete_recursive_send(state, state->ev, state->handle, - hbac_base_dn, true); - if (subreq == NULL) { - DEBUG(1, ("sysdb_delete_recursive_send failed.\n")); - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, hbac_rule_sysdb_delete_done, req); - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_rule_sysdb_delete_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int ret; - - ret = sysdb_delete_recursive_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - state->current_item = 0; - hbac_rule_store_prepare(req); -} - -static void hbac_rule_store_prepare(struct tevent_req *req) -{ - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int ret; - struct ldb_message_element *el; - struct tevent_req *subreq; - char *object_name; - - if (state->current_item < state->hbac_reply_count) { - - ret = sysdb_attrs_get_el(state->hbac_reply_list[state->current_item], - IPA_UNIQUE_ID, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - goto fail; - } - if (el->num_values == 0) { - ret = EINVAL; - goto fail; - } - object_name = talloc_strndup(state, (const char *)el->values[0].data, - el->values[0].length); - if (object_name == NULL) { - ret = ENOMEM; - goto fail; - } - DEBUG(9, ("IPAUniqueId: [%s].\n", object_name)); - - subreq = sysdb_store_custom_send(state, state->ev, - state->handle, - state->sdap_ctx->be->domain, - object_name, - HBAC_RULES_SUBDIR, - state->hbac_reply_list[state->current_item]); - - if (subreq == NULL) { - DEBUG(1, ("sysdb_store_custom_send failed.\n")); - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, hbac_rule_store_done, req); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (subreq == NULL) { - DEBUG(1, ("sysdb_transaction_commit_send failed.\n")); - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, sysdb_transaction_complete, req); - - return; - -fail: - tevent_req_error(req, ret); - return; -} - -static void hbac_rule_store_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int ret; - - ret = sysdb_store_custom_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - state->current_item++; - hbac_rule_store_prepare(req); -} - -static int hbac_get_rules_recv(struct tevent_req *req, TALLOC_CTX *memctx, - size_t *hbac_rule_count, - struct sysdb_attrs ***hbac_rule_list) -{ - struct hbac_get_rules_state *state = tevent_req_data(req, - struct hbac_get_rules_state); - int i; - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *hbac_rule_count = state->hbac_reply_count; - *hbac_rule_list = talloc_steal(memctx, state->hbac_reply_list); - for (i = 0; i < state->hbac_reply_count; i++) { - talloc_steal(memctx, state->hbac_reply_list[i]); - } - return EOK; -} - -enum hbac_result { - HBAC_ALLOW = 1, - HBAC_DENY, - HBAC_NOT_APPLICABLE -}; - -enum check_result { - RULE_APPLICABLE = 0, - RULE_NOT_APPLICABLE, - RULE_ERROR -}; - -enum check_result check_service(struct pam_data *pd, - struct sysdb_attrs *rule_attrs) -{ - int ret; - int i; - struct ldb_message_element *el; - - if (pd->service == NULL) { - DEBUG(1, ("No service in pam data, assuming error.\n")); - return RULE_ERROR; - } - - ret = sysdb_attrs_get_el(rule_attrs, IPA_SERVICE_NAME, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - if (el->num_values == 0) { - DEBUG(9, ("No services in rule specified, assuming rule applies.\n")); - return RULE_APPLICABLE; - } else { - for (i = 0; i < el->num_values; i++) { - if (strncasecmp(pd->service, (const char *) el->values[i].data, - el->values[i].length) == 0) { - DEBUG(9, ("Service [%s] found, rule applies.\n", - pd->service)); - return RULE_APPLICABLE; - } - } - DEBUG(9, ("No matching service found, rule does not apply.\n")); - return RULE_NOT_APPLICABLE; - } - - return RULE_ERROR; -} - -enum check_result check_access_time(struct time_rules_ctx *tr_ctx, - struct sysdb_attrs *rule_attrs) -{ - int ret; - int i; - TALLOC_CTX *tmp_ctx = NULL; - struct ldb_message_element *el; - char *rule; - time_t now; - bool result; - - now = time(NULL); - if (now == (time_t) -1) { - DEBUG(1, ("time failed [%d][%s].\n", errno, strerror(errno))); - return RULE_ERROR; - } - - ret = sysdb_attrs_get_el(rule_attrs, IPA_ACCESS_TIME, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - if (el->num_values == 0) { - DEBUG(9, ("No access time specified, assuming rule applies.\n")); - return RULE_APPLICABLE; - } else { - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(1, ("talloc_new failed.\n")); - return RULE_ERROR; - } - - for (i = 0; i < el->num_values; i++) { - rule = talloc_strndup(tmp_ctx, (const char *) el->values[i].data, - el->values[i].length); - ret = check_time_rule(tmp_ctx, tr_ctx, rule, now, &result); - if (ret != EOK) { - DEBUG(1, ("check_time_rule failed.\n")); - ret = RULE_ERROR; - goto done; - } - - if (result) { - DEBUG(9, ("Current time [%d] matches rule [%s].\n", now, rule)); - ret = RULE_APPLICABLE; - goto done; - } - } - } - - ret = RULE_NOT_APPLICABLE; - -done: - talloc_free(tmp_ctx); - return ret; -} - -enum check_result check_user(struct hbac_ctx *hbac_ctx, - struct sysdb_attrs *rule_attrs) -{ - int ret; - int i; - int g; - struct ldb_message_element *el; - - if (hbac_ctx->user_dn == NULL) { - DEBUG(1, ("No user DN available, this should never happen.\n")); - return RULE_ERROR; - } - - ret = sysdb_attrs_get_el(rule_attrs, IPA_USER_CATEGORY, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - if (el->num_values == 0) { - DEBUG(9, ("USer category is not set.\n")); - } else { - for (i = 0; i < el->num_values; i++) { - if (strncasecmp("all", (const char *) el->values[i].data, - el->values[i].length) == 0) { - DEBUG(9, ("User category is set to 'all', rule applies.\n")); - return RULE_APPLICABLE; - } - DEBUG(9, ("Unsupported user category [%.*s].\n", - el->values[i].length, - (char *) el->values[i].data)); - } - } - - ret = sysdb_attrs_get_el(rule_attrs, IPA_MEMBER_USER, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - if (el->num_values == 0) { - DEBUG(9, ("No user specified, rule does not apply.\n")); - return RULE_APPLICABLE; - } else { - for (i = 0; i < el->num_values; i++) { - DEBUG(9, ("Searching matches for [%.*s].\n", el->values[i].length, - (const char *) el->values[i].data)); - DEBUG(9, ("Checking user [%s].\n", hbac_ctx->user_dn)); - if (strncmp(hbac_ctx->user_dn, (const char *) el->values[i].data, - el->values[i].length) == 0) { - DEBUG(9, ("User [%s] found, rule applies.\n", - hbac_ctx->user_dn)); - return RULE_APPLICABLE; - } - - for (g = 0; g < hbac_ctx->groups_count; g++) { - DEBUG(9, ("Checking group [%s].\n", hbac_ctx->groups[g])); - if (strncmp(hbac_ctx->groups[g], - (const char *) el->values[i].data, - el->values[i].length) == 0) { - DEBUG(9, ("Group [%s] found, rule applies.\n", - hbac_ctx->groups[g])); - return RULE_APPLICABLE; - } - } - } - DEBUG(9, ("No matching user found, rule does not apply.\n")); - return RULE_NOT_APPLICABLE; - } - - return RULE_ERROR; -} - -enum check_result check_remote_hosts(const char *rhost, - struct hbac_host_info *hhi, - struct sysdb_attrs *rule_attrs) -{ - int ret; - int i; - int m; - struct ldb_message_element *cat_el; - struct ldb_message_element *src_el; - struct ldb_message_element *ext_el; - - if (hhi == NULL && (rhost == NULL || *rhost == '\0')) { - DEBUG(1, ("No remote host information specified, assuming error.\n")); - return RULE_ERROR; - } - - ret = sysdb_attrs_get_el(rule_attrs, IPA_SOURCE_HOST_CATEGORY, &cat_el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - if (cat_el->num_values == 0) { - DEBUG(9, ("Source host category not set.\n")); - } else { - for(i = 0; i < cat_el->num_values; i++) { - if (strncasecmp("all", (const char *) cat_el->values[i].data, - cat_el->values[i].length) == 0) { - DEBUG(9, ("Source host category is set to 'all', " - "rule applies.\n")); - return RULE_APPLICABLE; - } - DEBUG(9, ("Unsupported source hosts category [%.*s].\n", - cat_el->values[i].length, - (char *) cat_el->values[i].data)); - } - } - - ret = sysdb_attrs_get_el(rule_attrs, IPA_SOURCE_HOST, &src_el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - ret = sysdb_attrs_get_el(rule_attrs, IPA_EXTERNAL_HOST, &ext_el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return RULE_ERROR; - } - - if (src_el->num_values == 0 && ext_el->num_values == 0) { - DEBUG(9, ("No remote host specified in rule, rule does not apply.\n")); - return RULE_NOT_APPLICABLE; - } else { - if (hhi != NULL) { - for (i = 0; i < src_el->num_values; i++) { - if (strncasecmp(hhi->dn, (const char *) src_el->values[i].data, - src_el->values[i].length) == 0) { - DEBUG(9, ("Source host [%s] found, rule applies.\n", - hhi->dn)); - return RULE_APPLICABLE; - } - for (m = 0; hhi->memberof[m] != NULL; m++) { - if (strncasecmp(hhi->memberof[m], - (const char *) src_el->values[i].data, - src_el->values[i].length) == 0) { - DEBUG(9, ("Source host group [%s] found, rule applies.\n", - hhi->memberof[m])); - return RULE_APPLICABLE; - } - } - } - } - - if (rhost != NULL && *rhost != '\0') { - for (i = 0; i < ext_el->num_values; i++) { - if (strncasecmp(rhost, (const char *) ext_el->values[i].data, - ext_el->values[i].length) == 0) { - DEBUG(9, ("External host [%s] found, rule applies.\n", - rhost)); - return RULE_APPLICABLE; - } - } - } - DEBUG(9, ("No matching remote host found.\n")); - return RULE_NOT_APPLICABLE; - } - - return RULE_ERROR; -} - -static errno_t check_if_rule_applies(enum hbac_result *result, - struct hbac_ctx *hbac_ctx, - struct sysdb_attrs *rule_attrs) { - int ret; - struct ldb_message_element *el; - enum hbac_result rule_type; - char *rule_name; - struct pam_data *pd = hbac_ctx->pd; - - ret = sysdb_attrs_get_el(rule_attrs, IPA_CN, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return ret; - } - if (el->num_values == 0) { - DEBUG(4, ("rule has no name, assuming '(none)'.\n")); - rule_name = talloc_strdup(rule_attrs, "(none)"); - } else { - rule_name = talloc_strndup(rule_attrs, (const char*) el->values[0].data, - el->values[0].length); - } - if (rule_name == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - return ENOMEM; - } - DEBUG(9, ("Processsing rule [%s].\n", rule_name)); - - /* rule type */ - ret = sysdb_attrs_get_el(rule_attrs, IPA_ACCESS_RULE_TYPE, &el); - if (ret != EOK) { - DEBUG(1, ("sysdb_attrs_get_el failed.\n")); - return ret; - } - if (el->num_values == 0) { - DEBUG(4, ("rule has no type, assuming 'deny'.\n")); - rule_type = HBAC_DENY; - } else if (el->num_values == 1) { - if (strncasecmp((const char *) el->values[0].data, "allow", - el->values[0].length) == 0) { - rule_type = HBAC_ALLOW; - } else { - rule_type = HBAC_DENY; - } - } else { - DEBUG(1, ("rule has an unsupported number of values [%d].\n", - el->num_values)); - return EINVAL; - } - - ret = check_service(pd, rule_attrs); - if (ret != RULE_APPLICABLE) { - goto not_applicable; - } - - ret = check_user(hbac_ctx, rule_attrs); - if (ret != RULE_APPLICABLE) { - goto not_applicable; - } - - ret = check_access_time(hbac_ctx->tr_ctx, rule_attrs); - if (ret != RULE_APPLICABLE) { - goto not_applicable; - } - - ret = check_remote_hosts(pd->rhost, hbac_ctx->remote_hhi, rule_attrs); - if (ret != RULE_APPLICABLE) { - goto not_applicable; - } - - *result = rule_type; - - return EOK; - -not_applicable: - if (ret == RULE_NOT_APPLICABLE) { - *result = HBAC_NOT_APPLICABLE; - } else { - *result = HBAC_DENY; - } - return EOK; -} - -static int evaluate_ipa_hbac_rules(struct hbac_ctx *hbac_ctx, - bool *access_allowed) -{ - bool allow_matched = false; - enum hbac_result result; - int ret; - int i; - - *access_allowed = false; - - for (i = 0; i < hbac_ctx->hbac_rule_count ; i++) { - - ret = check_if_rule_applies(&result, hbac_ctx, - hbac_ctx->hbac_rule_list[i]); - if (ret != EOK) { - DEBUG(1, ("check_if_rule_applies failed.\n")); - return ret; - } - - switch (result) { - case HBAC_DENY: - DEBUG(3, ("Access denied by single rule.\n")); - return EOK; - break; - case HBAC_ALLOW: - allow_matched = true; - DEBUG(9, ("Current rule allows access.\n")); - break; - default: - DEBUG(9, ("Current rule does not apply.\n")); - } - - } - - *access_allowed = allow_matched; - - return EOK; -} - -static void hbac_get_host_info_done(struct tevent_req *req); -static void hbac_get_rules_done(struct tevent_req *req); -static void hbac_get_user_info_done(struct tevent_req *req); - -void ipa_access_handler(struct be_req *be_req) -{ - struct tevent_req *req; - struct pam_data *pd; - struct hbac_ctx *hbac_ctx; - int pam_status = PAM_SYSTEM_ERR; - struct ipa_access_ctx *ipa_access_ctx; - const char *hostlist[3]; - - pd = talloc_get_type(be_req->req_data, struct pam_data); - - hbac_ctx = talloc_zero(be_req, struct hbac_ctx); - if (hbac_ctx == NULL) { - DEBUG(1, ("talloc failed.\n")); - goto fail; - } - hbac_ctx->be_req = be_req; - hbac_ctx->pd = pd; - ipa_access_ctx = talloc_get_type( - be_req->be_ctx->bet_info[BET_ACCESS].pvt_bet_data, - struct ipa_access_ctx); - hbac_ctx->sdap_ctx = ipa_access_ctx->sdap_ctx; - hbac_ctx->ipa_options = ipa_access_ctx->ipa_options; - hbac_ctx->tr_ctx = ipa_access_ctx->tr_ctx; - hbac_ctx->offline = be_is_offline(be_req->be_ctx); - - DEBUG(9, ("Connection status is [%s].\n", hbac_ctx->offline ? "offline" : - "online")); - - - hostlist[0] = dp_opt_get_cstring(hbac_ctx->ipa_options, IPA_HOSTNAME); - if (hostlist[0] == NULL) { - DEBUG(1, ("ipa_hostname not available.\n")); - goto fail; - } - if (pd->rhost != NULL && *pd->rhost != '\0') { - hostlist[1] = pd->rhost; - } else { - hostlist[1] = NULL; - pd->rhost = dp_opt_get_string(hbac_ctx->ipa_options, IPA_HOSTNAME); - if (pd->rhost == NULL) { - DEBUG(1, ("ipa_hostname not available.\n")); - goto fail; - } - } - hostlist[2] = NULL; - - req = hbac_get_host_info_send(hbac_ctx, be_req->be_ctx->ev, - hbac_ctx->offline, - hbac_ctx->sdap_ctx, be_req->be_ctx->sysdb, - dp_opt_get_string(hbac_ctx->ipa_options, - IPA_DOMAIN), - hostlist); - if (req == NULL) { - DEBUG(1, ("hbac_get_host_info_send failed.\n")); - goto fail; - } - - tevent_req_set_callback(req, hbac_get_host_info_done, hbac_ctx); - return; - -fail: - ipa_access_reply(be_req, pam_status); -} - -static void hbac_get_host_info_done(struct tevent_req *req) -{ - struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx); - struct be_req *be_req = hbac_ctx->be_req; - int ret; - int pam_status = PAM_SYSTEM_ERR; - const char *ipa_hostname; - struct hbac_host_info *local_hhi = NULL; - int i; - - ret = hbac_get_host_info_recv(req, hbac_ctx, &hbac_ctx->hbac_host_info); - talloc_zfree(req); - if (ret != EOK) { - goto fail; - } - - ipa_hostname = dp_opt_get_cstring(hbac_ctx->ipa_options, IPA_HOSTNAME); - if (ipa_hostname == NULL) { - DEBUG(1, ("Missing ipa_hostname, this should never happen.\n")); - ret = EINVAL; - goto fail; - } - - for (i = 0; hbac_ctx->hbac_host_info[i] != NULL; i++) { - if (strcmp(hbac_ctx->hbac_host_info[i]->fqdn, ipa_hostname) == 0 || - strcmp(hbac_ctx->hbac_host_info[i]->serverhostname, - ipa_hostname) == 0) { - local_hhi = hbac_ctx->hbac_host_info[i]; - } - if (hbac_ctx->pd->rhost != NULL && *hbac_ctx->pd->rhost != '\0') { - if (strcmp(hbac_ctx->hbac_host_info[i]->fqdn, - hbac_ctx->pd->rhost) == 0 || - strcmp(hbac_ctx->hbac_host_info[i]->serverhostname, - hbac_ctx->pd->rhost) == 0) { - hbac_ctx->remote_hhi = hbac_ctx->hbac_host_info[i]; - } - } - } - if (local_hhi == NULL) { - DEBUG(1, ("Missing host info for [%s].\n", ipa_hostname)); - ret = EINVAL; - goto fail; - } - req = hbac_get_rules_send(hbac_ctx, be_req->be_ctx->ev, hbac_ctx->offline, - hbac_ctx->sdap_ctx, be_req->be_ctx->sysdb, - dp_opt_get_string(hbac_ctx->ipa_options, - IPA_DOMAIN), - local_hhi->dn, local_hhi->memberof); - if (req == NULL) { - DEBUG(1, ("hbac_get_rules_send failed.\n")); - goto fail; - } - - tevent_req_set_callback(req, hbac_get_rules_done, hbac_ctx); - return; - -fail: - ipa_access_reply(be_req, pam_status); -} - -static void hbac_get_rules_done(struct tevent_req *req) -{ - struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx); - struct pam_data *pd = hbac_ctx->pd; - struct be_req *be_req = hbac_ctx->be_req; - int ret; - int pam_status = PAM_SYSTEM_ERR; - - ret = hbac_get_rules_recv(req, hbac_ctx, &hbac_ctx->hbac_rule_count, - &hbac_ctx->hbac_rule_list); - talloc_zfree(req); - if (ret != EOK) { - goto fail; - } - - req = hbac_get_user_info_send(hbac_ctx, be_req->be_ctx->ev, be_req->be_ctx, - pd->user); - if (req == NULL) { - DEBUG(1, ("hbac_get_user_info_send failed.\n")); - goto fail; - } - - tevent_req_set_callback(req, hbac_get_user_info_done, hbac_ctx); - return; - -fail: - ipa_access_reply(be_req, pam_status); -} - -static void hbac_get_user_info_done(struct tevent_req *req) -{ - struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx); - struct be_req *be_req = hbac_ctx->be_req; - int ret; - int pam_status = PAM_SYSTEM_ERR; - bool access_allowed = false; - - ret = hbac_get_user_info_recv(req, hbac_ctx, &hbac_ctx->user_dn, - &hbac_ctx->groups_count, - &hbac_ctx->groups); - talloc_zfree(req); - if (ret != EOK) { - goto failed; - } - - ret = evaluate_ipa_hbac_rules(hbac_ctx, &access_allowed); - if (ret != EOK) { - DEBUG(1, ("evaluate_ipa_hbac_rules failed.\n")); - goto failed; - } - - if (access_allowed) { - pam_status = PAM_SUCCESS; - DEBUG(5, ("Access allowed.\n")); - } else { - pam_status = PAM_PERM_DENIED; - DEBUG(3, ("Access denied.\n")); - } - -failed: - ipa_access_reply(be_req, pam_status); -} diff --git a/server/providers/ipa/ipa_access.h b/server/providers/ipa/ipa_access.h deleted file mode 100644 index bd221c574..000000000 --- a/server/providers/ipa/ipa_access.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - SSSD - - IPA Backend Module -- Access control - - 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 _IPA_ACCESS_H_ -#define _IPA_ACCESS_H_ - -#include "providers/ldap/ldap_common.h" - -enum ipa_access_mode { - IPA_ACCESS_DENY = 0, - IPA_ACCESS_ALLOW -}; - -struct hbac_host_info { - const char *fqdn; - const char *serverhostname; - const char *dn; - const char **memberof; -}; - -struct ipa_access_ctx { - struct sdap_id_ctx *sdap_ctx; - struct dp_option *ipa_options; - struct time_rules_ctx *tr_ctx; -}; - -struct hbac_ctx { - struct sdap_id_ctx *sdap_ctx; - struct dp_option *ipa_options; - struct time_rules_ctx *tr_ctx; - struct be_req *be_req; - struct pam_data *pd; - struct hbac_host_info **hbac_host_info; - struct hbac_host_info *remote_hhi; - struct sysdb_attrs **hbac_rule_list; - size_t hbac_rule_count; - const char *user_dn; - size_t groups_count; - const char **groups; - bool offline; -}; - -void ipa_access_handler(struct be_req *be_req); - -#endif /* _IPA_ACCESS_H_ */ diff --git a/server/providers/ipa/ipa_auth.c b/server/providers/ipa/ipa_auth.c deleted file mode 100644 index 86b72e495..000000000 --- a/server/providers/ipa/ipa_auth.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - SSSD - - IPA Backend Module -- Authentication - - 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" -#include "providers/ldap/ldap_common.h" -#include "providers/ldap/sdap_async.h" -#include "providers/krb5/krb5_auth.h" -#include "providers/ipa/ipa_common.h" - -struct ipa_auth_ctx { - struct sdap_auth_ctx *sdap_auth_ctx; - struct krb5_ctx *krb5_ctx; - struct be_req *be_req; - be_async_callback_t callback; - void *pvt; - bool password_migration; - - int dp_err_type; - int errnum; - char *errstr; -}; - -static void ipa_auth_reply(struct ipa_auth_ctx *ipa_auth_ctx) -{ - struct pam_data *pd; - struct be_req *be_req = ipa_auth_ctx->be_req; - be_req->fn = ipa_auth_ctx->callback; - be_req->pvt = ipa_auth_ctx->pvt; - be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data = ipa_auth_ctx->krb5_ctx; - pd = talloc_get_type(be_req->req_data, struct pam_data); - int dp_err_type = ipa_auth_ctx->dp_err_type; - char *errstr = ipa_auth_ctx->errstr; - - talloc_zfree(ipa_auth_ctx); - DEBUG(9, ("sending [%d] [%d] [%s].\n", dp_err_type, pd->pam_status, - errstr)); - - be_req->fn(be_req, dp_err_type, pd->pam_status, errstr); -} - -struct ipa_auth_handler_state { - struct tevent_context *ev; - - int dp_err_type; - int errnum; - char *errstr; -}; - -static void ipa_auth_handler_callback(struct be_req *be_req, - int dp_err_type, - int errnum, - const char *errstr); - -static struct tevent_req *ipa_auth_handler_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct be_req *be_req, - be_req_fn_t auth_handler) -{ - struct ipa_auth_handler_state *state; - struct tevent_req *req; - - req = tevent_req_create(memctx, &state, struct ipa_auth_handler_state); - if (req == NULL) { - DEBUG(1, ("tevent_req_create failed.\n")); - return NULL; - } - - state->ev = ev; - - be_req->fn = ipa_auth_handler_callback; - be_req->pvt = req; - - auth_handler(be_req); - - return req; -} - -static void ipa_auth_handler_callback(struct be_req *be_req, - int dp_err_type, - int errnum, - const char *errstr) -{ - struct tevent_req *req = talloc_get_type(be_req->pvt, struct tevent_req); - struct ipa_auth_handler_state *state = tevent_req_data(req, - struct ipa_auth_handler_state); - - DEBUG(9, ("received from handler [%d] [%d] [%s].\n", dp_err_type, errnum, - errstr)); - state->dp_err_type = dp_err_type; - state->errnum = errnum; - state->errstr = talloc_strdup(state, errstr); - - tevent_req_post(req, state->ev); - tevent_req_done(req); - return; -} - -static int ipa_auth_handler_recv(struct tevent_req *req, TALLOC_CTX *memctx, - int *dp_err_type, int *errnum, - char **errstr) -{ - struct ipa_auth_handler_state *state = tevent_req_data(req, - struct ipa_auth_handler_state); - enum tevent_req_state tstate; - uint64_t err; - - if (tevent_req_is_error(req, &tstate, &err)) { - if (err) return err; - return EIO; - } - - *dp_err_type = state->dp_err_type; - *errnum = state->errnum; - *errstr = talloc_steal(memctx, state->errstr); - - return EOK; -} - - -static void ipa_auth_handler_done(struct tevent_req *req); -static void ipa_auth_ldap_done(struct tevent_req *req); -static void ipa_auth_handler_retry_done(struct tevent_req *req); - -void ipa_auth(struct be_req *be_req) -{ - struct tevent_req *req; - struct ipa_auth_ctx *ipa_auth_ctx; - struct sdap_id_ctx *sdap_id_ctx; - - ipa_auth_ctx = talloc_zero(be_req, struct ipa_auth_ctx); - if (ipa_auth_ctx == NULL) { - DEBUG(1, ("talloc failed.\n")); - be_req->fn(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL); - } - - ipa_auth_ctx->callback = be_req->fn; - ipa_auth_ctx->pvt = be_req->pvt; - - ipa_auth_ctx->be_req = be_req; - - ipa_auth_ctx->sdap_auth_ctx = talloc_zero(ipa_auth_ctx, - struct sdap_auth_ctx); - if (ipa_auth_ctx->sdap_auth_ctx == NULL) { - DEBUG(1, ("talloc failed.\n")); - goto fail; - } - - sdap_id_ctx = talloc_get_type( - be_req->be_ctx->bet_info[BET_ID].pvt_bet_data, - struct sdap_id_ctx); - ipa_auth_ctx->sdap_auth_ctx->be = sdap_id_ctx->be; - ipa_auth_ctx->sdap_auth_ctx->opts = sdap_id_ctx->opts; - - ipa_auth_ctx->krb5_ctx = talloc_get_type( - be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data, - struct krb5_ctx); - -/* TODO: test and activate when server side support is available */ - ipa_auth_ctx->password_migration = false; - - ipa_auth_ctx->dp_err_type = DP_ERR_FATAL; - ipa_auth_ctx->errnum = EIO; - ipa_auth_ctx->errstr = NULL; - - req = ipa_auth_handler_send(ipa_auth_ctx, be_req->be_ctx->ev, be_req, - krb5_pam_handler); - if (req == NULL) { - DEBUG(1, ("ipa_auth_handler_send failed.\n")); - goto fail; - } - - tevent_req_set_callback(req, ipa_auth_handler_done, ipa_auth_ctx); - return; - -fail: - ipa_auth_reply(ipa_auth_ctx); -} - -static void ipa_auth_handler_done(struct tevent_req *req) -{ - struct ipa_auth_ctx *ipa_auth_ctx = tevent_req_callback_data(req, - struct ipa_auth_ctx); - struct pam_data *pd; - struct be_req *be_req; - int ret; - - be_req = ipa_auth_ctx->be_req; - pd = talloc_get_type(be_req->req_data, struct pam_data); - - ret = ipa_auth_handler_recv(req, ipa_auth_ctx, &ipa_auth_ctx->dp_err_type, - &ipa_auth_ctx->errnum, &ipa_auth_ctx->errstr); - talloc_zfree(req); - if (ret != EOK) { - DEBUG(1, ("ipa_auth_handler request failed.\n")); - pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) { - pd->pam_status = ipa_auth_ctx->errnum; - goto done; - } - - if (ipa_auth_ctx->password_migration && pd->pam_status == PAM_CRED_ERR) { - DEBUG(1, ("Assuming Kerberos password is missing, " - "starting password migration.\n")); - be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data = - ipa_auth_ctx->sdap_auth_ctx; - req = ipa_auth_handler_send(ipa_auth_ctx, be_req->be_ctx->ev, be_req, - sdap_pam_auth_handler); - if (req == NULL) { - DEBUG(1, ("ipa_auth_ldap_send failed.\n")); - goto done; - } - - tevent_req_set_callback(req, ipa_auth_ldap_done, ipa_auth_ctx); - return; - } - -done: - ipa_auth_reply(ipa_auth_ctx); -} - -static void ipa_auth_ldap_done(struct tevent_req *req) -{ - struct ipa_auth_ctx *ipa_auth_ctx = tevent_req_callback_data(req, - struct ipa_auth_ctx); - struct pam_data *pd; - struct be_req *be_req; - int ret; - - be_req = ipa_auth_ctx->be_req; - pd = talloc_get_type(be_req->req_data, struct pam_data); - - ret = ipa_auth_handler_recv(req, ipa_auth_ctx, &ipa_auth_ctx->dp_err_type, - &ipa_auth_ctx->errnum, &ipa_auth_ctx->errstr); - talloc_zfree(req); - if (ret != EOK) { - DEBUG(1, ("ipa_auth_handler request failed.\n")); - pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) { - pd->pam_status = ipa_auth_ctx->errnum; - goto done; - } - - if (pd->pam_status == PAM_SUCCESS) { - DEBUG(1, ("LDAP authentication succeded, " - "trying Kerberos authentication again.\n")); - be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data = ipa_auth_ctx->krb5_ctx; - req = ipa_auth_handler_send(ipa_auth_ctx, be_req->be_ctx->ev, be_req, - krb5_pam_handler); - if (req == NULL) { - DEBUG(1, ("ipa_auth_ldap_send failed.\n")); - goto done; - } - - tevent_req_set_callback(req, ipa_auth_handler_retry_done, ipa_auth_ctx); - return; - } - -done: - ipa_auth_reply(ipa_auth_ctx); -} - -static void ipa_auth_handler_retry_done(struct tevent_req *req) -{ - struct ipa_auth_ctx *ipa_auth_ctx = tevent_req_callback_data(req, - struct ipa_auth_ctx); - struct pam_data *pd; - struct be_req *be_req; - int ret; - - be_req = ipa_auth_ctx->be_req; - pd = talloc_get_type(be_req->req_data, struct pam_data); - - ret = ipa_auth_handler_recv(req, ipa_auth_ctx, &ipa_auth_ctx->dp_err_type, - &ipa_auth_ctx->errnum, &ipa_auth_ctx->errstr); - talloc_zfree(req); - if (ret != EOK) { - DEBUG(1, ("ipa_auth_handler request failed.\n")); - pd->pam_status = PAM_SYSTEM_ERR; - } - if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) { - pd->pam_status = ipa_auth_ctx->errnum; - } - - ipa_auth_reply(ipa_auth_ctx); -} diff --git a/server/providers/ipa/ipa_auth.h b/server/providers/ipa/ipa_auth.h deleted file mode 100644 index 3079bbd1b..000000000 --- a/server/providers/ipa/ipa_auth.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - SSSD - - IPA Backend Module -- Authentication - - 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 _IPA_AUTH_H_ -#define _IPA_AUTH_H_ - -#include "providers/dp_backend.h" - -void ipa_auth(struct be_req *be_req); - -#endif /* _IPA_AUTH_H_ */ diff --git a/server/providers/ipa/ipa_common.c b/server/providers/ipa/ipa_common.c deleted file mode 100644 index 7686227a5..000000000 --- a/server/providers/ipa/ipa_common.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - SSSD - - IPA Provider Common Functions - - Authors: - Simo Sorce - - 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/ipa/ipa_common.h" - -struct dp_option ipa_basic_opts[] = { - { "ipa_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ipa_server", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ipa_hostname", DP_OPT_STRING, NULL_STRING, NULL_STRING }, -}; - -struct dp_option ipa_def_ldap_opts[] = { - { "ldap_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_default_bind_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_default_authtok_type", DP_OPT_STRING, NULL_STRING, NULL_STRING}, - { "ldap_default_authtok", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB }, - { "ldap_search_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER }, - { "ldap_network_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER }, - { "ldap_opt_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER }, - { "ldap_tls_reqcert", DP_OPT_STRING, { "hard" }, NULL_STRING }, - { "ldap_user_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_user_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, - { "ldap_user_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_group_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, - { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_schema", DP_OPT_STRING, { "ipa_v1" }, NULL_STRING }, - { "ldap_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER }, - { "ldap_force_upper_case_realm", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, - { "ldap_enumeration_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER }, - { "ldap_purge_cache_timeout", DP_OPT_NUMBER, { .number = 3600 }, NULL_NUMBER }, - { "entry_cache_timeout", DP_OPT_NUMBER, { .number = 1800 }, NULL_NUMBER }, - { "ldap_tls_cacert", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_tls_cacertdir", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_id_use_start_tls", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, - { "ldap_sasl_mech", DP_OPT_STRING, { "GSSAPI" } , NULL_STRING }, - { "ldap_sasl_authid", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_krb5_keytab", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_krb5_init_creds", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, - /* use the same parm name as the krb5 module so we set it only once */ - { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_pwd_policy", DP_OPT_STRING, { "none" } , NULL_STRING }, - { "ldap_referrals", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE } -}; - -struct sdap_attr_map ipa_attr_map[] = { - { "ldap_entry_usn", "entryUSN", SYSDB_USN, NULL }, - { "ldap_rootdse_last_usn", "lastUSN", SYSDB_HIGH_USN, NULL } -}; - -struct sdap_attr_map ipa_user_map[] = { - { "ldap_user_object_class", "posixAccount", SYSDB_USER_CLASS, NULL }, - { "ldap_user_name", "uid", SYSDB_NAME, NULL }, - { "ldap_user_pwd", "userPassword", SYSDB_PWD, NULL }, - { "ldap_user_uid_number", "uidNumber", SYSDB_UIDNUM, NULL }, - { "ldap_user_gid_number", "gidNumber", SYSDB_GIDNUM, NULL }, - { "ldap_user_gecos", "gecos", SYSDB_GECOS, NULL }, - { "ldap_user_home_directory", "homeDirectory", SYSDB_HOMEDIR, NULL }, - { "ldap_user_shell", "loginShell", SYSDB_SHELL, NULL }, - { "ldap_user_principal", "krbPrincipalName", SYSDB_UPN, NULL }, - { "ldap_user_fullname", "cn", SYSDB_FULLNAME, NULL }, - { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL }, - { "ldap_user_uuid", "nsUniqueId", SYSDB_UUID, NULL }, - { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }, - { "ldap_user_shadow_last_change", "shadowLastChange", SYSDB_SHADOWPW_LASTCHANGE, NULL }, - { "ldap_user_shadow_min", "shadowMin", SYSDB_SHADOWPW_MIN, NULL }, - { "ldap_user_shadow_max", "shadowMax", SYSDB_SHADOWPW_MAX, NULL }, - { "ldap_user_shadow_warning", "shadowWarning", SYSDB_SHADOWPW_WARNING, NULL }, - { "ldap_user_shadow_inactive", "shadowInactive", SYSDB_SHADOWPW_INACTIVE, NULL }, - { "ldap_user_shadow_expire", "shadowExpire", SYSDB_SHADOWPW_EXPIRE, NULL }, - { "ldap_user_shadow_flag", "shadowFlag", SYSDB_SHADOWPW_FLAG, NULL }, - { "ldap_user_krb_last_pwd_change", "krbLastPwdChange", SYSDB_KRBPW_LASTCHANGE, NULL }, - { "ldap_user_krb_password_expiration", "krbPasswordExpiration", SYSDB_KRBPW_EXPIRATION, NULL }, - { "ldap_pwd_attribute", "pwdAttribute", SYSDB_PWD_ATTRIBUTE, NULL } -}; - -struct sdap_attr_map ipa_group_map[] = { - { "ldap_group_object_class", "posixGroup", SYSDB_GROUP_CLASS, NULL }, - { "ldap_group_name", "cn", SYSDB_NAME, NULL }, - { "ldap_group_pwd", "userPassword", SYSDB_PWD, NULL }, - { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL }, - { "ldap_group_member", "member", SYSDB_MEMBER, NULL }, - { "ldap_group_uuid", "nsUniqueId", SYSDB_UUID, NULL }, - { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL } -}; - -struct dp_option ipa_def_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_TRUE, BOOL_TRUE } -}; - -int domain_to_basedn(TALLOC_CTX *memctx, const char *domain, char **basedn) -{ - const char *s; - char *dn; - char *p; - int l; - - s = domain; - dn = talloc_strdup(memctx, "dc="); - - while ((p = strchr(s, '.'))) { - l = p - s; - dn = talloc_asprintf_append_buffer(dn, "%.*s,dc=", l, s); - if (!dn) { - return ENOMEM; - } - s = p + 1; - } - dn = talloc_strdup_append_buffer(dn, s); - if (!dn) { - return ENOMEM; - } - - *basedn = dn; - return EOK; -} - -int ipa_get_options(TALLOC_CTX *memctx, - struct confdb_ctx *cdb, - const char *conf_path, - struct sss_domain_info *dom, - struct ipa_options **_opts) -{ - struct ipa_options *opts; - char *domain; - char *server; - char *ipa_hostname; - int ret; - char hostname[HOST_NAME_MAX + 1]; - - opts = talloc_zero(memctx, struct ipa_options); - if (!opts) return ENOMEM; - - ret = dp_get_options(opts, cdb, conf_path, - ipa_basic_opts, - IPA_OPTS_BASIC, - &opts->basic); - if (ret != EOK) { - goto done; - } - - domain = dp_opt_get_string(opts->basic, IPA_DOMAIN); - if (!domain) { - ret = dp_opt_set_string(opts->basic, IPA_DOMAIN, dom->name); - if (ret != EOK) { - goto done; - } - } - - /* FIXME: Make non-fatal once we have discovery */ - server = dp_opt_get_string(opts->basic, IPA_SERVER); - if (!server) { - DEBUG(0, ("Can't find ipa server, missing option!\n")); - ret = EINVAL; - goto done; - } - - ipa_hostname = dp_opt_get_string(opts->basic, IPA_HOSTNAME); - if (ipa_hostname == NULL) { - ret = gethostname(hostname, HOST_NAME_MAX); - if (ret != EOK) { - DEBUG(1, ("gethostname failed [%d][%s].\n", errno, - strerror(errno))); - ret = errno; - goto done; - } - hostname[HOST_NAME_MAX] = '\0'; - DEBUG(9, ("Setting ipa_hostname to [%s].\n", hostname)); - ret = dp_opt_set_string(opts->basic, IPA_HOSTNAME, hostname); - if (ret != EOK) { - goto done; - } - } - - - ret = EOK; - *_opts = opts; - -done: - if (ret != EOK) { - talloc_zfree(opts); - } - return ret; -} - -int ipa_get_id_options(struct ipa_options *ipa_opts, - struct confdb_ctx *cdb, - const char *conf_path, - struct sdap_options **_opts) -{ - TALLOC_CTX *tmpctx; - char *hostname; - char *basedn; - char *realm; - char *value; - int ret; - int i; - - /* self check test, this should never fail, unless someone forgot - * to properly update the code after new ldap options have been added */ - if (SDAP_OPTS_BASIC != IPA_OPTS_BASIC_TEST) { - DEBUG(0, ("Option numbers do not match (%d != %d)\n", - SDAP_OPTS_BASIC, IPA_OPTS_BASIC_TEST)); - abort(); - } - - tmpctx = talloc_new(ipa_opts); - if (!tmpctx) { - return ENOMEM; - } - - ipa_opts->id = talloc_zero(ipa_opts, struct sdap_options); - if (!ipa_opts->id) { - ret = ENOMEM; - goto done; - } - - /* get sdap options */ - ret = dp_get_options(ipa_opts->id, cdb, conf_path, - ipa_def_ldap_opts, - SDAP_OPTS_BASIC, - &ipa_opts->id->basic); - if (ret != EOK) { - goto done; - } - - if (NULL == dp_opt_get_string(ipa_opts->id->basic, SDAP_SEARCH_BASE)) { - ret = domain_to_basedn(tmpctx, - dp_opt_get_string(ipa_opts->basic, IPA_DOMAIN), - &basedn); - if (ret != EOK) { - goto done; - } - - /* FIXME: get values by querying IPA */ - /* set search base */ - value = talloc_asprintf(tmpctx, "cn=accounts,%s", basedn); - if (!value) { - ret = ENOMEM; - goto done; - } - ret = dp_opt_set_string(ipa_opts->id->basic, - SDAP_SEARCH_BASE, value); - if (ret != EOK) { - goto done; - } - DEBUG(6, ("Option %s set to %s\n", - ipa_opts->id->basic[SDAP_SEARCH_BASE].opt_name, - dp_opt_get_string(ipa_opts->id->basic, SDAP_SEARCH_BASE))); - } - - /* set the ldap_sasl_authid if the ipa_hostname override was specified */ - if (NULL == dp_opt_get_string(ipa_opts->id->basic, SDAP_SASL_AUTHID)) { - hostname = dp_opt_get_string(ipa_opts->basic, IPA_HOSTNAME); - if (hostname) { - value = talloc_asprintf(tmpctx, "host/%s", hostname); - if (!value) { - ret = ENOMEM; - goto done; - } - ret = dp_opt_set_string(ipa_opts->id->basic, - SDAP_SASL_AUTHID, value); - if (ret != EOK) { - goto done; - } - } - DEBUG(6, ("Option %s set to %s\n", - ipa_opts->id->basic[SDAP_SASL_AUTHID].opt_name, - dp_opt_get_string(ipa_opts->id->basic, SDAP_SASL_AUTHID))); - } - - /* set krb realm */ - if (NULL == dp_opt_get_string(ipa_opts->id->basic, SDAP_KRB5_REALM)) { - realm = dp_opt_get_string(ipa_opts->basic, IPA_DOMAIN); - for (i = 0; realm[i]; i++) { - realm[i] = toupper(realm[i]); - } - ret = dp_opt_set_string(ipa_opts->id->basic, - SDAP_KRB5_REALM, realm); - if (ret != EOK) { - goto done; - } - DEBUG(6, ("Option %s set to %s\n", - ipa_opts->id->basic[SDAP_KRB5_REALM].opt_name, - dp_opt_get_string(ipa_opts->id->basic, SDAP_KRB5_REALM))); - } - - /* fix schema to IPAv1 for now */ - ipa_opts->id->schema_type = SDAP_SCHEMA_IPA_V1; - - /* set user/group search bases if they are not specified */ - if (NULL == dp_opt_get_string(ipa_opts->id->basic, - SDAP_USER_SEARCH_BASE)) { - ret = dp_opt_set_string(ipa_opts->id->basic, SDAP_USER_SEARCH_BASE, - dp_opt_get_string(ipa_opts->id->basic, - SDAP_SEARCH_BASE)); - if (ret != EOK) { - goto done; - } - DEBUG(6, ("Option %s set to %s\n", - ipa_opts->id->basic[SDAP_USER_SEARCH_BASE].opt_name, - dp_opt_get_string(ipa_opts->id->basic, - SDAP_USER_SEARCH_BASE))); - } - - if (NULL == dp_opt_get_string(ipa_opts->id->basic, - SDAP_GROUP_SEARCH_BASE)) { - ret = dp_opt_set_string(ipa_opts->id->basic, SDAP_GROUP_SEARCH_BASE, - dp_opt_get_string(ipa_opts->id->basic, - SDAP_SEARCH_BASE)); - if (ret != EOK) { - goto done; - } - DEBUG(6, ("Option %s set to %s\n", - ipa_opts->id->basic[SDAP_GROUP_SEARCH_BASE].opt_name, - dp_opt_get_string(ipa_opts->id->basic, - SDAP_GROUP_SEARCH_BASE))); - } - - ret = sdap_get_map(ipa_opts->id, cdb, conf_path, - ipa_attr_map, - SDAP_AT_GENERAL, - &ipa_opts->id->gen_map); - if (ret != EOK) { - goto done; - } - - ret = sdap_get_map(ipa_opts->id, - cdb, conf_path, - ipa_user_map, - SDAP_OPTS_USER, - &ipa_opts->id->user_map); - if (ret != EOK) { - goto done; - } - - ret = sdap_get_map(ipa_opts->id, - cdb, conf_path, - ipa_group_map, - SDAP_OPTS_GROUP, - &ipa_opts->id->group_map); - if (ret != EOK) { - goto done; - } - - ret = EOK; - *_opts = ipa_opts->id; - -done: - talloc_zfree(tmpctx); - if (ret != EOK) { - talloc_zfree(ipa_opts->id); - } - return ret; -} - -/* the following define is used to keep track of * the options in the krb5 - * module, so that if they change and ipa is not updated correspondingly - * this will trigger a runtime abort error */ -#define IPA_KRB5_OPTS_TEST 8 - -int ipa_get_auth_options(struct ipa_options *ipa_opts, - struct confdb_ctx *cdb, - const char *conf_path, - struct dp_option **_opts) -{ - char *value; - int ret; - int i; - - /* self check test, this should never fail, unless someone forgot - * to properly update the code after new ldap options have been added */ - if (KRB5_OPTS != IPA_KRB5_OPTS_TEST) { - DEBUG(0, ("Option numbers do not match (%d != %d)\n", - KRB5_OPTS, IPA_KRB5_OPTS_TEST)); - abort(); - } - - ipa_opts->auth = talloc_zero(ipa_opts, struct dp_option); - if (ipa_opts->auth == NULL) { - ret = ENOMEM; - goto done; - } - - /* get krb5 options */ - ret = dp_get_options(ipa_opts, cdb, conf_path, - ipa_def_krb5_opts, - KRB5_OPTS, &ipa_opts->auth); - if (ret != EOK) { - goto done; - } - - /* set krb realm */ - if (NULL == dp_opt_get_string(ipa_opts->auth, KRB5_REALM)) { - value = dp_opt_get_string(ipa_opts->basic, IPA_DOMAIN); - if (!value) { - ret = ENOMEM; - goto done; - } - for (i = 0; value[i]; i++) { - value[i] = toupper(value[i]); - } - ret = dp_opt_set_string(ipa_opts->auth, KRB5_REALM, value); - if (ret != EOK) { - goto done; - } - DEBUG(6, ("Option %s set to %s\n", - ipa_opts->auth[KRB5_REALM].opt_name, - dp_opt_get_string(ipa_opts->auth, KRB5_REALM))); - } - - *_opts = ipa_opts->auth; - ret = EOK; - -done: - if (ret != EOK) { - talloc_zfree(ipa_opts->auth); - } - return ret; -} - -static void ipa_resolve_callback(void *private_data, struct fo_server *server) -{ - struct ipa_service *service; - struct hostent *srvaddr; - char *address; - char *new_uri; - int ret; - - service = talloc_get_type(private_data, struct ipa_service); - if (!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(service, "%s", srvaddr->h_name); - if (!address) { - DEBUG(1, ("Failed to copy address ...\n")); - return; - } - - new_uri = talloc_asprintf(service, "ldap://%s", address); - if (!new_uri) { - DEBUG(2, ("Failed to copy URI ...\n")); - talloc_free(address); - return; - } - - /* free old one and replace with new one */ - talloc_zfree(service->sdap->uri); - service->sdap->uri = new_uri; - talloc_zfree(service->krb5_service->address); - service->krb5_service->address = address; - - ret = write_kdcinfo_file(service->krb5_service->realm, address); - if (ret != EOK) { - DEBUG(2, ("write_kdcinfo_file failed, authentication might fail.\n")); - } - -} - -int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, - const char *servers, const char *domain, - struct ipa_service **_service) -{ - TALLOC_CTX *tmp_ctx; - struct ipa_service *service; - char **list = NULL; - char *realm; - int ret; - int i; - - tmp_ctx = talloc_new(memctx); - if (!tmp_ctx) { - return ENOMEM; - } - - service = talloc_zero(tmp_ctx, struct ipa_service); - if (!service) { - ret = ENOMEM; - goto done; - } - service->sdap = talloc_zero(service, struct sdap_service); - if (!service->sdap) { - ret = ENOMEM; - goto done; - } - service->krb5_service = talloc_zero(service, struct krb5_service); - if (!service->krb5_service) { - ret = ENOMEM; - goto done; - } - - ret = be_fo_add_service(ctx, "IPA"); - if (ret != EOK) { - DEBUG(1, ("Failed to create failover service!\n")); - goto done; - } - - service->sdap->name = talloc_strdup(service, "IPA"); - if (!service->sdap->name) { - ret = ENOMEM; - goto done; - } - - service->krb5_service->name = talloc_strdup(service, "IPA"); - if (!service->krb5_service->name) { - ret = ENOMEM; - goto done; - } - - realm = talloc_strdup(service, domain); - if (!realm) { - ret = ENOMEM; - goto done; - } - for (i = 0; realm[i]; i++) { - realm[i] = toupper(realm[i]); - } - service->krb5_service->realm = realm; - - /* split server parm into a list */ - ret = split_on_separator(tmp_ctx, servers, ',', true, &list, NULL); - if (ret != EOK) { - DEBUG(1, ("Failed to parse server list!\n")); - goto done; - } - - /* now for each one add a new server to the failover service */ - for (i = 0; list[i]; i++) { - - talloc_steal(service, list[i]); - - ret = be_fo_add_server(ctx, "IPA", 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, "IPA", - ipa_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/ipa/ipa_common.h b/server/providers/ipa/ipa_common.h deleted file mode 100644 index 60c7313f0..000000000 --- a/server/providers/ipa/ipa_common.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - SSSD - - IPA Common utility code - - Copyright (C) Simo Sorce 2009 - - 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 _IPA_COMMON_H_ -#define _IPA_COMMON_H_ - -#include "util/util.h" -#include "confdb/confdb.h" -#include "providers/ldap/ldap_common.h" -#include "providers/krb5/krb5_common.h" - -struct ipa_service { - struct sdap_service *sdap; - struct krb5_service *krb5_service; -}; - -/* the following define is used to keep track of the options in the ldap - * module, so that if they change and ipa is not updated correspondingly - * this will trigger a runtime abort error */ -#define IPA_OPTS_BASIC_TEST 31 - -enum ipa_basic_opt { - IPA_DOMAIN = 0, - IPA_SERVER, - IPA_HOSTNAME, - - IPA_OPTS_BASIC /* opts counter */ -}; - -struct ipa_options { - struct dp_option *basic; - - struct ipa_service *service; - - /* id provider */ - struct sdap_options *id; - struct sdap_id_ctx *id_ctx; - - /* auth and chpass provider */ - struct dp_option *auth; - struct krb5_ctx *auth_ctx; -}; - -/* options parsers */ -int ipa_get_options(TALLOC_CTX *memctx, - struct confdb_ctx *cdb, - const char *conf_path, - struct sss_domain_info *dom, - struct ipa_options **_opts); - -int ipa_get_id_options(struct ipa_options *ipa_opts, - struct confdb_ctx *cdb, - const char *conf_path, - struct sdap_options **_opts); - -int ipa_get_auth_options(struct ipa_options *ipa_opts, - struct confdb_ctx *cdb, - const char *conf_path, - struct dp_option **_opts); - -int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, - const char *servers, const char *domain, - struct ipa_service **_service); - -#endif /* _IPA_COMMON_H_ */ diff --git a/server/providers/ipa/ipa_init.c b/server/providers/ipa/ipa_init.c deleted file mode 100644 index 10b9257a2..000000000 --- a/server/providers/ipa/ipa_init.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - SSSD - - IPA Provider Initialization functions - - Authors: - Simo Sorce - - 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/ipa/ipa_common.h" -#include "providers/krb5/krb5_auth.h" -#include "providers/ipa/ipa_auth.h" -#include "providers/ipa/ipa_access.h" -#include "providers/ipa/ipa_timerules.h" - -struct ipa_options *ipa_options = NULL; - -/* Id Handler */ -struct bet_ops ipa_id_ops = { - .handler = sdap_account_info_handler, - .finalize = NULL -}; - -struct bet_ops ipa_auth_ops = { - .handler = ipa_auth, - .finalize = NULL, -}; - -struct bet_ops ipa_chpass_ops = { - .handler = krb5_pam_handler, - .finalize = NULL, -}; - -struct bet_ops ipa_access_ops = { - .handler = ipa_access_handler, - .finalize = NULL -}; - -int common_ipa_init(struct be_ctx *bectx) -{ - const char *ipa_servers; - const char *ipa_domain; - int ret; - - ret = ipa_get_options(bectx, bectx->cdb, - bectx->conf_path, - bectx->domain, &ipa_options); - if (ret != EOK) { - return ret; - } - - ipa_servers = dp_opt_get_string(ipa_options->basic, IPA_SERVER); - if (!ipa_servers) { - DEBUG(0, ("Missing ipa_server option!\n")); - return EINVAL; - } - - ipa_domain = dp_opt_get_string(ipa_options->basic, IPA_DOMAIN); - if (!ipa_domain) { - DEBUG(0, ("Missing ipa_domain option!\n")); - return EINVAL; - } - - ret = ipa_service_init(ipa_options, bectx, ipa_servers, ipa_domain, - &ipa_options->service); - if (ret != EOK) { - DEBUG(0, ("Failed to init IPA failover service!\n")); - return ret; - } - - return EOK; -} - -int sssm_ipa_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) -{ - struct sdap_id_ctx *ctx; - int ret; - - if (!ipa_options) { - ret = common_ipa_init(bectx); - if (ret != EOK) { - return ret; - } - } - - if (ipa_options->id_ctx) { - /* already initialized */ - *ops = &ipa_id_ops; - *pvt_data = ipa_options->id_ctx; - return EOK; - } - - ctx = talloc_zero(ipa_options, struct sdap_id_ctx); - if (!ctx) { - return ENOMEM; - } - ctx->be = bectx; - ctx->service = ipa_options->service->sdap; - ipa_options->id_ctx = ctx; - - ret = ipa_get_id_options(ipa_options, bectx->cdb, - bectx->conf_path, - &ctx->opts); - if (ret != EOK) { - goto done; - } - - ret = setup_tls_config(ctx->opts->basic); - if (ret != EOK) { - DEBUG(1, ("setup_tls_config failed [%d][%s].\n", - ret, strerror(ret))); - goto done; - } - - ret = sdap_id_setup_tasks(ctx); - if (ret != EOK) { - goto done; - } - - ret = setup_child(ctx); - if (ret != EOK) { - DEBUG(1, ("setup_child failed [%d][%s].\n", - ret, strerror(ret))); - goto done; - } - - *ops = &ipa_id_ops; - *pvt_data = ctx; - ret = EOK; - -done: - if (ret != EOK) { - talloc_zfree(ipa_options->id_ctx); - } - return ret; -} - -int sssm_ipa_auth_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) -{ - struct krb5_ctx *ctx; - struct tevent_signal *sige; - FILE *debug_filep; - unsigned v; - int ret; - - if (!ipa_options) { - ret = common_ipa_init(bectx); - if (ret != EOK) { - return ret; - } - } - - if (ipa_options->auth_ctx) { - /* already initialized */ - *ops = &ipa_auth_ops; - *pvt_data = ipa_options->auth_ctx; - return EOK; - } - - ctx = talloc_zero(bectx, struct krb5_ctx); - if (!ctx) { - return ENOMEM; - } - ctx->service = ipa_options->service->krb5_service; - ipa_options->auth_ctx = ctx; - - ret = ipa_get_auth_options(ipa_options, bectx->cdb, - bectx->conf_path, - &ctx->opts); - if (ret != EOK) { - goto done; - } - - ret = check_and_export_options(ctx->opts, bectx->domain); - if (ret != EOK) { - DEBUG(1, ("check_and_export_opts failed.\n")); - goto done; - } - - 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 done; - } - - 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 done; - } - - 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 done; - } - - v = fcntl(ctx->child_debug_fd, F_GETFD, 0); - fcntl(ctx->child_debug_fd, F_SETFD, v & ~FD_CLOEXEC); - } - - *ops = &ipa_auth_ops; - *pvt_data = ctx; - ret = EOK; - -done: - if (ret != EOK) { - talloc_zfree(ipa_options->auth_ctx); - } - return ret; -} - -int sssm_ipa_chpass_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) -{ - int ret; - ret = sssm_ipa_auth_init(bectx, ops, pvt_data); - *ops = &ipa_chpass_ops; - return ret; -} - -int sssm_ipa_access_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) -{ - int ret; - struct ipa_access_ctx *ipa_access_ctx; - - ipa_access_ctx = talloc_zero(bectx, struct ipa_access_ctx); - if (ipa_access_ctx == NULL) { - DEBUG(1, ("talloc_zero failed.\n")); - return ENOMEM; - } - - ret = sssm_ipa_init(bectx, ops, (void **) &ipa_access_ctx->sdap_ctx); - if (ret != EOK) { - DEBUG(1, ("sssm_ipa_init failed.\n")); - goto done; - } - - ret = dp_copy_options(ipa_access_ctx, ipa_options->basic, - IPA_OPTS_BASIC, &ipa_access_ctx->ipa_options); - if (ret != EOK) { - DEBUG(1, ("dp_copy_options failed.\n")); - goto done; - } - - ret = init_time_rules_parser(ipa_access_ctx, &ipa_access_ctx->tr_ctx); - if (ret != EOK) { - DEBUG(1, ("init_time_rules_parser failed.\n")); - goto done; - } - - *ops = &ipa_access_ops; - *pvt_data = ipa_access_ctx; - -done: - if (ret != EOK) { - talloc_free(ipa_access_ctx); - } - return ret; -} diff --git a/server/providers/ipa/ipa_timerules.c b/server/providers/ipa/ipa_timerules.c deleted file mode 100644 index 1a52eef12..000000000 --- a/server/providers/ipa/ipa_timerules.c +++ /dev/null @@ -1,1186 +0,0 @@ -/* - SSSD - - IPA Provider Time Rules Parsing - - Authors: - Jakub Hrozek - - Copyright (C) Red Hat, Inc 2009 - - 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 . -*/ - -#define _XOPEN_SOURCE /* strptime() needs this */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "providers/ipa/ipa_timerules.h" -#include "util/util.h" - -#define JMP_NEOK(variable) do { \ - if (variable != EOK) goto done; \ -} while (0) - -#define JMP_NEOK_LABEL(variable, label) do { \ - if (variable != EOK) goto label; \ -} while (0) - -#define CHECK_PTR(ptr) do { \ - if (ptr == NULL) { \ - return ENOMEM; \ - } \ -} while (0) - -#define CHECK_PTR_JMP(ptr) do { \ - if (ptr == NULL) { \ - ret = ENOMEM; \ - goto done; \ - } \ -} while (0) - -#define BUFFER_OR_JUMP(ctx, ptr, count) do { \ - ptr = talloc_array(ctx, unsigned char, count); \ - if (ptr == NULL) { \ - return ENOMEM; \ - } \ - memset(ptr, 0, sizeof(unsigned char)*count); \ -} while (0) - -#define TEST_BIT_RANGE(bitfield, index, resptr) do { \ - if (bitfield) { \ - if (test_bit(&bitfield, index) == 0) { \ - *resptr = false; \ - return EOK; \ - } \ - } \ -} while (0) - -#define TEST_BIT_RANGE_PTR(bitfield, index, resptr) do { \ - if (bitfield) { \ - if (test_bit(bitfield, index) == 0) { \ - *resptr = false; \ - return EOK; \ - } \ - } \ -} while (0) - -/* number of match offsets when matching pcre regexes */ -#define OVEC_SIZE 30 - -/* regular expressions describing syntax of our HBAC grammar */ -#define RGX_WEEKLY "day (?P(0|1|2|3|4|5|6|7|Mon|Tue|Wed|Thu|Fri|Sat|Sun|,|-)+)" - -#define RGX_MDAY "(?Pday) (?P[0-9,-]+) " -#define RGX_MWEEK "(?Pweek) (?P[0-9,-]+) "RGX_WEEKLY -#define RGX_MONTHLY RGX_MDAY"|"RGX_MWEEK - -#define RGX_YDAY "(?Pday) (?P[0-9,-]+) " -#define RGX_YWEEK "(?Pweek) (?P[0-9,-]+) "RGX_WEEKLY -#define RGX_YMONTH "(?Pmonth) (?P[0-9,-]+) (?P.*?)$" -#define RGX_YEARLY RGX_YMONTH"|"RGX_YWEEK"|"RGX_YDAY - -#define RGX_TIMESPEC "(?P[0-9]{4}) ~ (?P[0-9]{4})" - -#define RGX_GENERALIZED "(?P[0-9]{4})(?P[0-9]{2})(?P[0-9]{2})(?P[0-9]{2})?(?P[0-9]{2})?(?P[0-9]{2})?" - -#define RGX_PERIODIC "^periodic (?Pdaily|weekly|monthly|yearly) (?P.*?)"RGX_TIMESPEC"$" -#define RGX_ABSOLUTE "^absolute (?P\\S+) ~ (?P\\S+)$" - -/* limits on various parameters */ -#define DAY_OF_WEEK_MAX 7 -#define DAY_OF_MONTH_MAX 31 -#define WEEK_OF_MONTH_MAX 5 -#define WEEK_OF_YEAR_MAX 54 -#define DAY_OF_YEAR_MAX 366 -#define MONTH_MAX 12 -#define HOUR_MAX 23 -#define MINUTE_MAX 59 - -/* limits on sizes of buffers for bit arrays */ -#define DAY_OF_MONTH_BUFSIZE 8 -#define DAY_OF_YEAR_BUFSIZE 44 -#define WEEK_OF_YEAR_BUFSIZE 13 -#define MONTH_BUFSIZE 2 -#define HOUR_BUFSIZE 4 -#define MINUTE_BUFSIZE 8 - -/* Lookup tables for translating names of days and months */ -static const char *names_day_of_week[] = - { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", NULL }; -static const char *names_months[] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Nov", "Dec", NULL }; - -/* - * Timelib knows two types of ranges - periodic and absolute - */ -enum rangetypes { - TYPE_ABSOLUTE, - TYPE_PERIODIC -}; - -struct absolute_range { - time_t time_from; - time_t time_to; -}; - -struct periodic_range { - unsigned char day_of_week; - unsigned char *day_of_month; - unsigned char *day_of_year; - unsigned char week_of_month; - unsigned char *week_of_year; - unsigned char *month; - unsigned char *hour; - unsigned char *minute; -}; - -/* - * Context of one time rule being analyzed - */ -struct range_ctx { - /* main context with precompiled patterns */ - struct time_rules_ctx *trctx; - /* enum rangetypes */ - enum rangetypes type; - - struct absolute_range *abs; - struct periodic_range *per; -}; - - -/* - * The context of one regular expression - */ -struct parse_ctx { - /* the regular expression used for one parsing */ - pcre *re; - /* number of matches */ - int matches; - /* vector of matches */ - int *ovec; -}; - -/* indexes to the array of precompiled regexes */ -enum timelib_rgx { - LP_RGX_GENERALIZED, - LP_RGX_MDAY, - LP_RGX_MWEEK, - LP_RGX_YEARLY, - LP_RGX_WEEKLY, - LP_RGX_ABSOLUTE, - LP_RGX_PERIODIC, - LP_RGX_MAX, -}; - -/* matches the indexes */ -static const char *lookup_table[] = { - RGX_GENERALIZED, - RGX_MDAY, - RGX_MWEEK, - RGX_YEARLY, - RGX_WEEKLY, - RGX_ABSOLUTE, - RGX_PERIODIC, - NULL, -}; - -/* - * Main struct passed outside - * holds precompiled regular expressions - */ -struct time_rules_ctx { - pcre *re[LP_RGX_MAX]; -}; - -/******************************************************************* - * helper function - bit arrays * - *******************************************************************/ - -/* set a single bit in a bitmap */ -static void set_bit(unsigned char *bitmap, unsigned int bit) -{ - bitmap[bit/CHAR_BIT] |= 1 << (bit%CHAR_BIT); -} - -/* - * This function is based on bit_nset macro written originally by Paul Vixie, - * copyrighted by The Regents of the University of California, as found - * in tarball of fcron, file bitstring.h - */ -static void set_bit_range(unsigned char *bitmap, unsigned int start, - unsigned int stop) -{ - int startbyte = start/CHAR_BIT; - int stopbyte = stop/CHAR_BIT; - - if (startbyte == stopbyte) { - bitmap[startbyte] |= ((0xff << (start & 0x7)) & - (0xff >> (CHAR_BIT- 1 - (stop & 0x7)))); - } else { - bitmap[startbyte] |= 0xff << (start & 0x7); - while (++startbyte < stopbyte) { - bitmap[startbyte] |= 0xff; - } - bitmap[stopbyte] |= 0xff >> (CHAR_BIT- 1 - (stop & 0x7)); - } -} - -static int test_bit(unsigned char *bitmap, unsigned int bit) -{ - return (int)(bitmap[bit/CHAR_BIT] >> (bit%CHAR_BIT)) & 1; -} - -/******************************************************************* - * parsing intervals * - *******************************************************************/ - -/* - * Some ranges allow symbolic names, like Mon..Sun for names of day. - * This routine takes a list of symbolic names as NAME_ARRAY and the - * one we're looking for as KEY and returns its index or -1 when not - * found. The last member of NAME_ARRAY must be NULL. - */ -static int name_index(const char **name_array, const char *key, int min) -{ - int index = 0; - const char *one; - - if (name_array == NULL) { - return -1; - } - - while ((one = name_array[index]) != NULL) { - if (strcmp(key,one) == 0) { - return index+min; - } - index++; - } - - return -1; -} - -/* - * Sets appropriate bits given by an interval in STR (in form of 1,5-7,10) to - * a bitfield given in OUT. Does no boundary checking. STR can also contain - * symbolic names, these would be given in TRANSLATE. - */ -static int interval2bitfield(TALLOC_CTX *mem_ctx, - unsigned char *out, - const char *str, - int min, int max, - const char **translate) -{ - char *copy; - char *next, *token; - int tokval, tokmax; - char *end_ptr; - int ret; - char *dash; - - DEBUG(9, ("Converting '%s' to interval\n", str)); - - copy = talloc_strdup(mem_ctx, str); - CHECK_PTR(copy); - - next = copy; - while (next) { - token = next; - next = strchr(next, ','); - if (next) { - *next = '\0'; - next++; - } - - errno = 0; - tokval = strtol(token, &end_ptr, 10); - if (*end_ptr == '\0' && errno == 0) { - if (tokval <= max && tokval >= 0) { - set_bit(out, tokval); - continue; - } else { - ret = ERANGE; - goto done; - } - } else if ((dash = strchr(token, '-')) != NULL){ - *dash = '\0'; - ++dash; - - errno = 0; - tokval = strtol(token, &end_ptr, 10); - if (*end_ptr != '\0' || errno != 0) { - tokval = name_index(translate, token, min); - if (tokval == -1) { - ret = ERANGE; - goto done; - } - } - errno = 0; - tokmax = strtol(dash, &end_ptr, 10); - if (*end_ptr != '\0' || errno != 0) { - tokmax = name_index(translate, dash, min); - if (tokmax == -1) { - ret = ERANGE; - goto done; - } - } - - if (tokval <= max && tokmax <= max && - tokval >= min && tokmax >= min) { - if (tokmax > tokval) { - DEBUG(7, ("Setting interval %d-%d\n", tokval, tokmax)); - DEBUG(9, ("interval: %p\n", out)); - set_bit_range(out, tokval, tokmax); - } else { - /* Interval wraps around - i.e. from 18.00 to 06.00 */ - DEBUG(7, ("Setting inverted interval %d-%d\n", tokval, tokmax)); - DEBUG(9, ("interval: %p\n", out)); - set_bit_range(out, min, tokmax); - set_bit_range(out, tokval, max); - } - continue; - } else { - /* tokval or tokmax are not between */ - ret = ERANGE; - goto done; - } - } else if ((tokval = name_index(translate, token, min)) != -1) { - /* Try to translate one token by name */ - if (tokval <= max) { - set_bit(out, tokval); - continue; - } else { - ret = ERANGE; - goto done; - } - } else { - ret = EINVAL; - goto done; - } - } - - ret = EOK; -done: - talloc_free(copy); - return ret; -} - -/******************************************************************* - * wrappers around regexp handling * - *******************************************************************/ - -/* - * Copies a named substring SUBSTR_NAME from string STR using the parsing - * information from PCTX. The context PCTX is also used as a talloc context. - * - * The resulting string is stored in OUT. - * Return value is EOK on no error or ENOENT on error capturing the substring - */ -static int copy_substring(struct parse_ctx *pctx, - const char *str, - const char *substr_name, - char **out) -{ - const char *result = NULL; - int ret; - char *o = NULL; - - result = NULL; - - ret = pcre_get_named_substring(pctx->re, str, pctx->ovec, - pctx->matches, substr_name, &result); - if (ret < 0 || result == NULL) { - DEBUG(5, ("named substring '%s' does not exist in '%s'\n", - substr_name, str)); - return ENOENT; - } - - o = talloc_strdup(pctx, result); - pcre_free_substring(result); - if (o == NULL) { - return ENOMEM; - } - - DEBUG(9, ("Copied substring named '%s' value '%s'\n", substr_name, o)); - - *out = o; - return EOK; -} - -/* - * Copies a named substring SUBSTR_NAME from string STR using the parsing - * information from PCTX and converts it to an integer. - * The context PCTX is also used as a talloc context. - * - * The resulting string is stored in OUT. - * Return value is EOK on no error or ENOENT on error capturing the substring - */ -static int substring_strtol(struct parse_ctx *pctx, - const char *str, - const char *substr_name, - int *out) -{ - char *substr = NULL; - int ret; - int val; - char *err_ptr; - - ret = copy_substring(pctx, str, substr_name, &substr); - if (ret != EOK) { - DEBUG(5, ("substring '%s' does not exist\n", substr_name)); - return ret; - } - - errno = 0; - val = strtol(substr, &err_ptr, 10); - if (substr == '\0' || *err_ptr != '\0' || errno != 0) { - DEBUG(5, ("substring '%s' does not contain an integerexist\n", - substr)); - talloc_free(substr); - return EINVAL; - } - - *out = val; - talloc_free(substr); - return EOK; -} - -/* - * Compiles a regular expression REGEXP and tries to match it against the - * string STR. Fills in structure _PCTX with info about matching. - * - * Returns EOK on no error, EFAULT on bad regexp, EINVAL when it cannot - * match the regexp. - */ -static int matches_regexp(TALLOC_CTX *ctx, - struct time_rules_ctx *trctx, - const char *str, - enum timelib_rgx regex, - struct parse_ctx **_pctx) -{ - int ret; - struct parse_ctx *pctx = NULL; - - pctx = talloc_zero(ctx, struct parse_ctx); - CHECK_PTR(pctx); - pctx->ovec = talloc_array(pctx, int, OVEC_SIZE); - CHECK_PTR_JMP(pctx->ovec); - pctx->re = trctx->re[regex]; - - ret = pcre_exec(pctx->re, NULL, str, strlen(str), 0, PCRE_NOTEMPTY, pctx->ovec, OVEC_SIZE); - if (ret <= 0) { - DEBUG(8, ("string '%s' did *NOT* match regexp '%s'\n", str, lookup_table[regex])); - ret = EINVAL; - goto done; - } - DEBUG(8, ("string '%s' matched regexp '%s'\n", str, lookup_table[regex])); - - pctx->matches = ret; - *_pctx = pctx; - return EOK; - -done: - talloc_free(pctx); - return ret; -} - -/******************************************************************* - * date/time helper functions * - *******************************************************************/ - -/* - * Returns week number as an integer - * This may seem ugly, but I think it's actually less error prone - * than writing my own routine - */ -static int weeknum(const struct tm *t) -{ - char buf[3]; - - if (!strftime(buf, 3, "%U", t)) { - return -1; - } - - /* %U returns 0-53, we want 1-54 */ - return atoi(buf)+1; -} - -/* - * Return the week of the month - * Range is 1 to 5 - */ -static int get_week_of_month(const struct tm *t) -{ - int fs; /* first sunday */ - - fs = (t->tm_mday % 7) - t->tm_wday; - if (fs <= 0) { - fs += 7; - } - - return (t->tm_mday <= fs) ? 1 : (2 + (t->tm_mday - fs - 1) / 7); -} - -/* - * Normalize differencies between our HBAC definition and semantics of - * struct tm - */ -static void abs2tm(struct tm *t) -{ - /* tm defines tm_year as num of yrs since 1900, we have absolute number */ - t->tm_year %= 1900; - /* struct tm defines tm_mon as number of month since January */ - t->tm_mon--; -} - -/* - * Normalize differencies between our HBAC definition and semantics of - * struct tm - */ -static void tm2abs(struct tm *t) -{ - /* tm defines tm_year as num of yrs since 1900, we have absolute number */ - t->tm_year += 1900; - /* struct tm defines tm_mon as number of month since January */ - t->tm_mon++; -} - -/******************************************************************* - * parsing of HBAC rules themselves * - *******************************************************************/ - -/* - * Parses generalized time string given in STR and fills the - * information into OUT. - */ -static int parse_generalized_time(struct parse_ctx *pctx, - struct time_rules_ctx *trctx, - const char *str, - time_t *out) -{ - int ret; - struct parse_ctx *gctx = NULL; - struct tm tm; - - memset(&tm, 0, sizeof(tm)); - tm.tm_isdst = -1; - - ret = matches_regexp(pctx, trctx, str, LP_RGX_GENERALIZED, &gctx); - JMP_NEOK(ret); - - /* compulsory */ - ret = substring_strtol(gctx, str, "year", &tm.tm_year); - JMP_NEOK(ret); - ret = substring_strtol(gctx, str, "month", &tm.tm_mon); - JMP_NEOK(ret); - ret = substring_strtol(gctx, str, "day", &tm.tm_mday); - JMP_NEOK(ret); - /* optional */ - ret = substring_strtol(gctx, str, "hour", &tm.tm_hour); - JMP_NEOK_LABEL(ret, enoent); - ret = substring_strtol(gctx, str, "minute", &tm.tm_min); - JMP_NEOK_LABEL(ret, enoent); - ret = substring_strtol(gctx, str, "second", &tm.tm_sec); - JMP_NEOK_LABEL(ret, enoent); - -enoent: - if (ret == ENOENT) { - ret = EOK; - } - - abs2tm(&tm); - - *out = mktime(&tm); - DEBUG(3, ("converted to time: '%s'\n", ctime(out))); - if (*out == -1) { - ret = EINVAL; - } -done: - talloc_free(gctx); - return ret; -} - -/* - * Parses absolute timerange string given in STR and fills the - * information into ABS. - */ -static int parse_absolute(struct absolute_range *absr, - struct time_rules_ctx *trctx, - struct parse_ctx *pctx, - const char *str) -{ - char *from = NULL, *to = NULL; - int ret; - - ret = copy_substring(pctx, str, "from", &from); - if (ret != EOK) { - DEBUG(1, ("Missing required part 'from' in absolute timespec\n")); - ret = EINVAL; - goto done; - } - ret = copy_substring(pctx, str, "to", &to); - if (ret != EOK) { - DEBUG(1, ("Missing required part 'to' in absolute timespec\n")); - ret = EINVAL; - goto done; - } - - ret = parse_generalized_time(pctx, trctx, from, &absr->time_from); - if (ret != EOK) { - DEBUG(1, ("Cannot parse generalized time - first part\n")); - goto done; - } - - ret = parse_generalized_time(pctx, trctx, to, &absr->time_to); - if (ret != EOK) { - DEBUG(1, ("Cannot parse generalized time - second part\n")); - goto done; - } - - if (difftime(absr->time_to, absr->time_from) < 0) { - DEBUG(1, ("Not a valid interval\n")); - ret = EINVAL; - } - - ret = EOK; -done: - talloc_free(from); - talloc_free(to); - return ret; -} - -static int parse_hhmm(const char *str, int *hour, int *min) -{ - struct tm t; - char *err; - - err = strptime(str, "%H%M", &t); - if (*err != '\0') { - return EINVAL; - } - - *hour = t.tm_hour; - *min = t.tm_min; - - return EOK; -} - -/* - * Parses monthly periodic timerange given in STR. - * Fills the information into PER. - */ -static int parse_periodic_monthly(TALLOC_CTX *ctx, - struct time_rules_ctx *trctx, - struct periodic_range *per, - const char *str) -{ - int ret; - struct parse_ctx *mpctx = NULL; - char *match = NULL; - char *mperspec = NULL; - - /* This code would be much less ugly if RHEL5 PCRE knew about PCRE_DUPNAMES */ - ret = matches_regexp(ctx, trctx, str, LP_RGX_MDAY, &mpctx); - if (ret == EOK) { - ret = copy_substring(mpctx, str, "mperspec_day", &mperspec); - JMP_NEOK(ret); - ret = copy_substring(mpctx, str, "interval_day", &match); - JMP_NEOK(ret); - BUFFER_OR_JUMP(ctx, per->day_of_month, DAY_OF_MONTH_BUFSIZE); - ret = interval2bitfield(mpctx, per->day_of_month, match, - 1, DAY_OF_MONTH_MAX, NULL); - JMP_NEOK(ret); - } else { - ret = matches_regexp(ctx, trctx, str, LP_RGX_MWEEK, &mpctx); - JMP_NEOK(ret); - ret = copy_substring(mpctx, str, "mperspec_week", &mperspec); - JMP_NEOK(ret); - - ret = copy_substring(mpctx, str, "interval_week", &match); - JMP_NEOK(ret); - ret = interval2bitfield(mpctx, &per->week_of_month, match, - 1, WEEK_OF_MONTH_MAX, NULL); - JMP_NEOK(ret); - - ret = copy_substring(mpctx, str, "day_of_week", &match); - JMP_NEOK(ret); - ret = interval2bitfield(mpctx, &per->day_of_week, match, - 1, DAY_OF_WEEK_MAX, names_day_of_week); - JMP_NEOK(ret); - } - -done: - talloc_free(mpctx); - return ret; -} - -/* - * Parses yearly periodic timerange given in STR. - * Fills the information into PER. - */ -static int parse_periodic_yearly(TALLOC_CTX *ctx, - struct time_rules_ctx *trctx, - struct periodic_range *per, - const char *str) -{ - int ret; - struct parse_ctx *ypctx = NULL; - char *match = NULL; - char *yperspec = NULL; - - ret = matches_regexp(ctx, trctx, str, LP_RGX_YEARLY, &ypctx); - JMP_NEOK(ret); - ret = copy_substring(ypctx, str, "yperspec_day", &yperspec); - if (ret == EOK) { - ret = copy_substring(ypctx, str, "day_of_year", &match); - JMP_NEOK(ret); - BUFFER_OR_JUMP(ypctx, per->day_of_year, DAY_OF_YEAR_BUFSIZE); - ret = interval2bitfield(ypctx, per->day_of_year, match, - 1, DAY_OF_YEAR_MAX, NULL); - JMP_NEOK(ret); - } - - if (ret != ENOENT) goto done; - - ret = copy_substring(ypctx, str, "yperspec_week", &yperspec); - if (ret == EOK) { - ret = copy_substring(ypctx, str, "week_of_year", &match); - JMP_NEOK(ret); - BUFFER_OR_JUMP(ypctx, per->week_of_year, WEEK_OF_YEAR_BUFSIZE); - ret = interval2bitfield(ypctx, per->week_of_year, match, - 1, WEEK_OF_YEAR_MAX, NULL); - JMP_NEOK(ret); - - talloc_free(match); - ret = copy_substring(ypctx, str, "day_of_week", &match); - JMP_NEOK(ret); - ret = interval2bitfield(ypctx, &per->day_of_week, match, - 1, DAY_OF_WEEK_MAX, names_day_of_week); - JMP_NEOK(ret); - } - - if (ret != ENOENT) goto done; - - ret = copy_substring(ypctx, str, "yperspec_month", &yperspec); - JMP_NEOK(ret); - - talloc_free(match); - ret = copy_substring(ypctx, str, "month_number", &match); - JMP_NEOK(ret); - BUFFER_OR_JUMP(ypctx, per->month, MONTH_BUFSIZE); - ret = interval2bitfield(ypctx, per->month, match, - 1, MONTH_MAX, names_months); - JMP_NEOK(ret); - - talloc_free(match); - ret = copy_substring(ypctx, str, "m_period", &match); - JMP_NEOK(ret); - DEBUG(7, ("Monthly year period - calling parse_periodic_monthly()\n")); - ret = parse_periodic_monthly(ypctx, trctx, per, match); - JMP_NEOK(ret); - -done: - talloc_free(ypctx); - return ret; -} - -/* - * Parses weekly periodic timerange given in STR. - * Fills the information into PER. - */ -static int parse_periodic_weekly(TALLOC_CTX *ctx, - struct time_rules_ctx *trctx, - struct periodic_range *per, - const char *str) -{ - int ret; - struct parse_ctx *wpctx = NULL; - char *dow = NULL; - - ret = matches_regexp(ctx, trctx, str, LP_RGX_WEEKLY, &wpctx); - JMP_NEOK(ret); - - ret = copy_substring(wpctx, str, "day_of_week", &dow); - JMP_NEOK(ret); - DEBUG(8, ("day_of_week = '%s'\n", dow)); - - ret = interval2bitfield(wpctx, &per->day_of_week, dow, - 1, DAY_OF_WEEK_MAX, names_day_of_week); - -done: - talloc_free(wpctx); - return ret; -} - -static int parse_periodic_time(struct periodic_range *per, - struct parse_ctx *pctx, - const char *str) -{ - char *substr = NULL; - int ret; - - int hour_from; - int hour_to; - int min_from; - int min_to; - - /* parse out the time */ - ret = copy_substring(pctx, str, "timeFrom", &substr); - JMP_NEOK(ret); - parse_hhmm(substr, &hour_from, &min_from); - DEBUG(7, ("Parsed timeFrom: %d:%d\n", hour_from, min_from)); - JMP_NEOK(ret); - - talloc_free(substr); - ret = copy_substring(pctx, str, "timeTo", &substr); - JMP_NEOK(ret); - parse_hhmm(substr, &hour_to, &min_to); - DEBUG(7, ("Parsed timeTo: %d:%d\n", hour_to, min_to)); - JMP_NEOK(ret); - - /* set the interval */ - if (hour_from > hour_to ) { - set_bit_range(per->hour, 0, hour_to); - set_bit_range(per->hour, hour_from, HOUR_MAX); - } else { - set_bit_range(per->hour, hour_from, hour_to); - } - - if (min_from > min_to) { - set_bit_range(per->minute, 0, min_to); - set_bit_range(per->minute, min_from, MINUTE_MAX); - } else { - set_bit_range(per->minute, min_from, min_to); - } - - - ret = EOK; -done: - talloc_free(substr); - return ret; -} - -/* - * Parses periodic timerange given in STR. - * Fills the information into PER. - */ -static int parse_periodic(struct periodic_range *per, - struct time_rules_ctx *trctx, - struct parse_ctx *pctx, - const char *str) -{ - char *substr = NULL; - char *period = NULL; - int ret; - - /* These are mandatory */ - BUFFER_OR_JUMP(per, per->hour, HOUR_BUFSIZE); - BUFFER_OR_JUMP(per, per->minute, MINUTE_BUFSIZE); - - ret = copy_substring(pctx, str, "perspec", &substr); - JMP_NEOK(ret); - ret = copy_substring(pctx, str, "period", &period); - JMP_NEOK(ret); - - if (strcmp(substr, "yearly") == 0) { - DEBUG(5, ("periodic yearly\n")); - ret = parse_periodic_yearly(pctx, trctx, per, period); - JMP_NEOK(ret); - } else if (strcmp(substr, "monthly") == 0) { - DEBUG(5, ("periodic monthly\n")); - ret = parse_periodic_monthly(pctx, trctx, per, period); - JMP_NEOK(ret); - } else if (strcmp(substr, "weekly") == 0) { - DEBUG(5, ("periodic weekly\n")); - ret = parse_periodic_weekly(pctx, trctx, per, period); - JMP_NEOK(ret); - } else if (strcmp(substr, "daily") == 0) { - DEBUG(5, ("periodic daily\n")); - } else { - DEBUG(1, ("Cannot determine periodic rule type" - "(perspec = '%s', period = '%s')\n", substr, period)); - ret = EINVAL; - goto done; - } - - talloc_free(period); - - ret = parse_periodic_time(per, pctx, str); - JMP_NEOK(ret); - - ret = EOK; -done: - talloc_free(substr); - return ret; -} - -/* - * Parses time specification given in string RULE into range_ctx - * context CTX. - */ -static int parse_timespec(struct range_ctx *ctx, const char *rule) -{ - int ret; - struct parse_ctx *pctx = NULL; - - if (matches_regexp(ctx, ctx->trctx, rule, LP_RGX_ABSOLUTE, &pctx) == EOK) { - DEBUG(5, ("Matched absolute range\n")); - ctx->type = TYPE_ABSOLUTE; - ctx->abs = talloc_zero(ctx, struct absolute_range); - CHECK_PTR_JMP(ctx->abs); - - ret = parse_absolute(ctx->abs, ctx->trctx, pctx, rule); - JMP_NEOK(ret); - } else if (matches_regexp(ctx, ctx->trctx, rule, LP_RGX_PERIODIC, &pctx) == EOK) { - DEBUG(5, ("Matched periodic range\n")); - ctx->type = TYPE_PERIODIC; - ctx->per = talloc_zero(ctx, struct periodic_range); - CHECK_PTR_JMP(ctx->per); - - ret = parse_periodic(ctx->per, ctx->trctx, pctx, rule); - JMP_NEOK(ret); - } else { - DEBUG(1, ("Cannot determine rule type\n")); - ret = EINVAL; - goto done; - } - - ret = EOK; -done: - talloc_free(pctx); - return ret; -} - -/******************************************************************* - * validation of rules against time_t * - *******************************************************************/ - -static int absolute_timerange_valid(struct absolute_range *absr, - const time_t now, - bool *result) -{ - if (difftime(absr->time_from, now) > 0) { - DEBUG(3, ("Absolute timerange invalid (before interval)\n")); - *result = false; - return EOK; - } - - if (difftime(absr->time_to, now) < 0) { - DEBUG(3, ("Absolute timerange invalid (after interval)\n")); - *result = false; - return EOK; - } - - DEBUG(3, ("Absolute timerange valid\n")); - *result = true; - return EOK; -} - -static int periodic_timerange_valid(struct periodic_range *per, - const time_t now, - bool *result) -{ - struct tm tm_now; - int wnum; - int wom; - - memset(&tm_now, 0, sizeof(struct tm)); - if (localtime_r(&now, &tm_now) == NULL) { - DEBUG(0, ("Cannot convert time_t to struct tm\n")); - return EFAULT; - } - DEBUG(9, ("Got struct tm value %s", asctime(&tm_now))); - tm2abs(&tm_now); - - wnum = weeknum(&tm_now); - if (wnum == -1) { - DEBUG(7, ("Cannot get week number")); - return EINVAL; - } - DEBUG(9, ("Week number is %d\n", wnum)); - - wom = get_week_of_month(&tm_now); - if (wnum == -1) { - DEBUG(7, ("Cannot get week of number")); - return EINVAL; - } - DEBUG(9, ("Week of month number is %d\n", wom)); - - /* The validation itself */ - TEST_BIT_RANGE(per->day_of_week, tm_now.tm_wday, result); - DEBUG(9, ("day of week OK\n")); - TEST_BIT_RANGE_PTR(per->day_of_month, tm_now.tm_mday, result); - DEBUG(9, ("day of month OK\n")); - TEST_BIT_RANGE(per->week_of_month, wom, result); - DEBUG(9, ("week of month OK\n")); - TEST_BIT_RANGE_PTR(per->week_of_year, wnum, result); - DEBUG(9, ("week of year OK\n")); - TEST_BIT_RANGE_PTR(per->month, tm_now.tm_mon, result); - DEBUG(9, ("month OK\n")); - TEST_BIT_RANGE_PTR(per->day_of_year, tm_now.tm_yday, result); - DEBUG(9, ("day of year OK\n")); - TEST_BIT_RANGE_PTR(per->hour, tm_now.tm_hour, result); - DEBUG(9, ("hour OK\n")); - TEST_BIT_RANGE_PTR(per->minute, tm_now.tm_min, result); - DEBUG(9, ("minute OK\n")); - - DEBUG(3, ("Periodic timerange valid\n")); - *result = true; - return EOK; -} - -/* - * Returns EOK if the timerange in range_ctx context is valid compared against a - * given time_t value in NOW, returns ERANGE if the time value is outside the - * specified range. - */ -static int timerange_valid(struct range_ctx *ctx, - const time_t now, - bool *result) -{ - int ret; - - switch(ctx->type) { - case TYPE_ABSOLUTE: - DEBUG(7, ("Checking absolute range\n")); - ret = absolute_timerange_valid(ctx->abs, now, result); - break; - - case TYPE_PERIODIC: - DEBUG(7, ("Checking periodic range\n")); - ret = periodic_timerange_valid(ctx->per, now, result); - break; - - default: - DEBUG(1, ("Unknown range type (%d)\n", ctx->type)); - ret = EINVAL; - break; - } - - return ret; -} - -/******************************************************************* - * public interface * - *******************************************************************/ - -/* - * This is actually the meat of the library. The function takes a string - * representation of a time rule in STR and time to check against (usually that - * would be current time) in NOW. - * - * It returns EOK if the rule is valid in the current time, ERANGE if not and - * EINVAL if the rule cannot be parsed - */ -int check_time_rule(TALLOC_CTX *mem_ctx, - struct time_rules_ctx *trctx, - const char *str, - const time_t now, - bool *result) -{ - int ret; - struct range_ctx *ctx; - - ctx = talloc_zero(mem_ctx, struct range_ctx); - CHECK_PTR_JMP(ctx); - ctx->trctx = trctx; - - DEBUG(9, ("Got time_t value %s", ctime(&now))); - - ret = parse_timespec(ctx, str); - if (ret != EOK) { - DEBUG(1, ("Cannot parse the time specification (%d)\n", ret)); - goto done; - } - - ret = timerange_valid(ctx, now, result); - if (ret != EOK) { - DEBUG(1, ("Cannot check the time range (%d)\n", ret)); - goto done; - } - - ret = EOK; -done: - talloc_free(ctx); - return EOK; -} - -/* - * Frees the resources taken by the precompiled rules - */ -static int time_rules_parser_destructor(struct time_rules_ctx *ctx) -{ - int i; - - for (i = 0; i< LP_RGX_MAX; ++i) { - pcre_free(ctx->re[i]); - ctx->re[i] = NULL; - } - - return 0; -} - -/* - * Initializes the parser by precompiling the regular expressions - * for later use - */ -int init_time_rules_parser(TALLOC_CTX *mem_ctx, - struct time_rules_ctx **_out) -{ - const char *errstr; - int errval; - int errpos; - int ret; - int i; - struct time_rules_ctx *ctx = NULL; - - ctx = talloc_zero(mem_ctx, struct time_rules_ctx); - CHECK_PTR(ctx); - talloc_set_destructor(ctx, time_rules_parser_destructor); - - /* Precompile regular expressions */ - for (i = LP_RGX_GENERALIZED; i< LP_RGX_MAX; ++i) { - ctx->re[i] = pcre_compile2(lookup_table[i], - 0, - &errval, - &errstr, - &errpos, - NULL); - - if (ctx->re[i] == NULL) { - DEBUG(0, ("Invalid Regular Expression pattern '%s' at position %d" - " (Error: %d [%s])\n", lookup_table[i], - errpos, errval, errstr)); - ret = EFAULT; - goto done; - } - - } - - *_out = ctx; - return EOK; -done: - talloc_free(ctx); - return ret; -} - diff --git a/server/providers/ipa/ipa_timerules.h b/server/providers/ipa/ipa_timerules.h deleted file mode 100644 index e1beaa22e..000000000 --- a/server/providers/ipa/ipa_timerules.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - SSSD - - IPA Provider Time Rules Parsing - - Authors: - Jakub Hrozek - - Copyright (C) Red Hat, Inc 2009 - - 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 __IPA_TIMERULES_H_ -#define __IPA_TIMERULES_H_ - -#include -#include - -/* Opaque structure given after init */ -struct time_rules_ctx; - -/* - * Init the parser. Destroy the allocated resources by simply - * talloc_free()-ing the time_rules_ctx - */ -int init_time_rules_parser(TALLOC_CTX *mem_ctx, - struct time_rules_ctx **_out); - -/* - * This is actually the meat of the library. The function takes a string - * representation of a time rule in STR and time to check against (usually that - * would be current time) in NOW. - * - * It returns EOK if the rule can be parsed, error code if not. If the time - * given in the NOW parameter would be accepted by the rule, it stores true in - * RESULT, false otherwise. - */ -int check_time_rule(TALLOC_CTX *mem_ctx, - struct time_rules_ctx *trctx, - const char *str, - const time_t now, - bool *result); - -#endif /* __IPA_TIMERULES_H_ */ diff --git a/server/providers/krb5/krb5_auth.c b/server/providers/krb5/krb5_auth.c deleted file mode 100644 index a2dadc808..000000000 --- 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 a011af890..000000000 --- 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 351f539a3..000000000 --- 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 5e185940e..000000000 --- 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 86676f44c..000000000 --- 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 832ffcdd5..000000000 --- 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 43cbc1bc7..000000000 --- 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 489030af8..000000000 --- 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 7637041a6..000000000 --- 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__ */ diff --git a/server/providers/ldap/ldap_auth.c b/server/providers/ldap/ldap_auth.c deleted file mode 100644 index cfe8adb97..000000000 --- a/server/providers/ldap/ldap_auth.c +++ /dev/null @@ -1,1055 +0,0 @@ -/* - SSSD - - LDAP Backend Module - - Authors: - Sumit Bose - - Copyright (C) 2008 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 . -*/ - -#ifdef WITH_MOZLDAP -#define LDAP_OPT_SUCCESS LDAP_SUCCESS -#define LDAP_TAG_EXOP_MODIFY_PASSWD_ID ((ber_tag_t) 0x80U) -#define LDAP_TAG_EXOP_MODIFY_PASSWD_OLD ((ber_tag_t) 0x81U) -#define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW ((ber_tag_t) 0x82U) -#endif - -#define _XOPEN_SOURCE 500 /* for strptime() */ -#include -#undef _XOPEN_SOURCE -#include -#include -#include - -#include -#include - -#include "util/util.h" -#include "util/user_info_msg.h" -#include "db/sysdb.h" -#include "providers/ldap/ldap_common.h" -#include "providers/ldap/sdap_async.h" - -enum pwexpire { - PWEXPIRE_NONE = 0, - PWEXPIRE_LDAP_PASSWORD_POLICY, - PWEXPIRE_KERBEROS, - PWEXPIRE_SHADOW -}; - -static errno_t check_pwexpire_kerberos(const char *expire_date, time_t now, - enum sdap_result *result) -{ - char *end; - struct tm tm = {0, 0, 0, 0, 0, 0, 0, 0, 0}; - time_t expire_time; - - *result = SDAP_AUTH_FAILED; - - end = strptime(expire_date, "%Y%m%d%H%M%SZ", &tm); - if (end == NULL) { - DEBUG(1, ("Kerberos expire date [%s] invalid.\n", expire_date)); - return EINVAL; - } - if (*end != '\0') { - DEBUG(1, ("Kerberos expire date [%s] contains extra characters.\n", - expire_date)); - return EINVAL; - } - - expire_time = mktime(&tm); - if (expire_time == -1) { - DEBUG(1, ("mktime failed to convert [%s].\n", expire_date)); - return EINVAL; - } - - tzset(); - expire_time -= timezone; - DEBUG(9, ("Time info: tzname[0] [%s] tzname[1] [%s] timezone [%d] " - "daylight [%d] now [%d] expire_time [%d].\n", tzname[0], - tzname[1], timezone, daylight, now, expire_time)); - - if (difftime(now, expire_time) > 0.0) { - DEBUG(4, ("Kerberos password expired.\n")); - *result = SDAP_AUTH_PW_EXPIRED; - } else { - *result = SDAP_AUTH_SUCCESS; - } - - return EOK; -} - -static errno_t check_pwexpire_shadow(struct spwd *spwd, time_t now, - enum sdap_result *result) -{ - long today; - long password_age; - - if (spwd->sp_lstchg <= 0) { - DEBUG(4, ("Last change day is not set, new password needed.\n")); - *result = SDAP_AUTH_PW_EXPIRED; - return EOK; - } - - today = (long) (now / (60 * 60 *24)); - password_age = today - spwd->sp_lstchg; - if (password_age < 0) { - DEBUG(2, ("The last password change time is in the future!.\n")); - *result = SDAP_AUTH_SUCCESS; - return EOK; - } - - if ((spwd->sp_expire != -1 && today > spwd->sp_expire) || - (spwd->sp_max != -1 && spwd->sp_inact != -1 && - password_age > spwd->sp_max + spwd->sp_inact)) - { - DEBUG(4, ("Account expired.\n")); - *result = SDAP_ACCT_EXPIRED; - return EOK; - } - - if (spwd->sp_max != -1 && password_age > spwd->sp_max) { - DEBUG(4, ("Password expired.\n")); - *result = SDAP_AUTH_PW_EXPIRED; - return EOK; - } - -/* TODO: evaluate spwd->min and spwd->warn */ - - *result = SDAP_AUTH_SUCCESS; - return EOK; -} - -static errno_t string_to_shadowpw_days(const char *s, long *d) -{ - long l; - char *endptr; - - if (s == NULL || *s == '\0') { - *d = -1; - return EOK; - } - - errno = 0; - l = strtol(s, &endptr, 10); - if (errno != 0) { - DEBUG(1, ("strtol failed [%d][%s].\n", errno, strerror(errno))); - return errno; - } - - if (*endptr != '\0') { - DEBUG(1, ("Input string [%s] is invalid.\n", s)); - return EINVAL; - } - - if (*d < -1) { - DEBUG(1, ("Input string contains not allowed negative value [%d].\n", - *d)); - return EINVAL; - } - - *d = l; - - return EOK; -} - -static errno_t find_password_expiration_attributes(TALLOC_CTX *mem_ctx, - const struct ldb_message *msg, - struct dp_option *opts, - enum pwexpire *type, void **data) -{ - const char *mark; - const char *val; - struct spwd *spwd; - const char *pwd_policy; - int ret; - - *type = PWEXPIRE_NONE; - *data = NULL; - - pwd_policy = dp_opt_get_string(opts, SDAP_PWD_POLICY); - if (pwd_policy == NULL) { - DEBUG(1, ("Missing password policy.\n")); - return EINVAL; - } - - mark = ldb_msg_find_attr_as_string(msg, SYSDB_PWD_ATTRIBUTE, NULL); - if (mark != NULL) { - DEBUG(9, ("Found pwdAttribute, " - "assuming LDAP password policies are active.\n")); - - *type = PWEXPIRE_LDAP_PASSWORD_POLICY; - return EOK; - } - - if (strcasecmp(pwd_policy, PWD_POL_OPT_NONE) == 0) { - DEBUG(9, ("No password policy requested.\n")); - return EOK; - } else if (strcasecmp(pwd_policy, PWD_POL_OPT_MIT) == 0) { - mark = ldb_msg_find_attr_as_string(msg, SYSDB_KRBPW_LASTCHANGE, NULL); - if (mark != NULL) { - DEBUG(9, ("Found Kerberos password expiration attributes.\n")) - val = ldb_msg_find_attr_as_string(msg, SYSDB_KRBPW_EXPIRATION, - NULL); - if (val != NULL) { - *data = talloc_strdup(mem_ctx, val); - if (*data == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - return ENOMEM; - } - *type = PWEXPIRE_KERBEROS; - - return EOK; - } - } else { - DEBUG(1, ("No Kerberos password expiration attributes found, " - "but MIT Kerberos password policy was requested.\n")); - return EINVAL; - } - } else if (strcasecmp(pwd_policy, PWD_POL_OPT_SHADOW) == 0) { - mark = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_LASTCHANGE, NULL); - if (mark != NULL) { - DEBUG(9, ("Found shadow password expiration attributes.\n")) - spwd = talloc_zero(mem_ctx, struct spwd); - if (spwd == NULL) { - DEBUG(1, ("talloc failed.\n")); - return ENOMEM; - } - - val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_LASTCHANGE, NULL); - ret = string_to_shadowpw_days(val, &spwd->sp_lstchg); - if (ret != EOK) goto shadow_fail; - - val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_MIN, NULL); - ret = string_to_shadowpw_days(val, &spwd->sp_min); - if (ret != EOK) goto shadow_fail; - - val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_MAX, NULL); - ret = string_to_shadowpw_days(val, &spwd->sp_max); - if (ret != EOK) goto shadow_fail; - - val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_WARNING, NULL); - ret = string_to_shadowpw_days(val, &spwd->sp_warn); - if (ret != EOK) goto shadow_fail; - - val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_INACTIVE, NULL); - ret = string_to_shadowpw_days(val, &spwd->sp_inact); - if (ret != EOK) goto shadow_fail; - - val = ldb_msg_find_attr_as_string(msg, SYSDB_SHADOWPW_EXPIRE, NULL); - ret = string_to_shadowpw_days(val, &spwd->sp_expire); - if (ret != EOK) goto shadow_fail; - - *data = spwd; - *type = PWEXPIRE_SHADOW; - - return EOK; - } else { - DEBUG(1, ("No shadow password attributes found, " - "but shadow password policy was requested.\n")); - return EINVAL; - } - } - - DEBUG(9, ("No password expiration attributes found.\n")); - return EOK; - -shadow_fail: - talloc_free(spwd); - return ret; -} - -/* ==Get-User-DN========================================================== */ - -struct get_user_dn_state { - struct tevent_context *ev; - struct sdap_auth_ctx *ctx; - struct sdap_handle *sh; - - const char **attrs; - const char *name; - - char *dn; - enum pwexpire pw_expire_type; - void *pw_expire_data; -}; - -static void get_user_dn_done(void *pvt, int err, struct ldb_result *res); - -struct tevent_req *get_user_dn_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_auth_ctx *ctx, - struct sdap_handle *sh, - const char *username) -{ - struct tevent_req *req; - struct get_user_dn_state *state; - int ret; - - req = tevent_req_create(memctx, &state, struct get_user_dn_state); - if (!req) return NULL; - - state->ev = ev; - state->ctx = ctx; - state->sh = sh; - state->name = username; - - state->attrs = talloc_array(state, const char *, 11); - if (!state->attrs) { - talloc_zfree(req); - return NULL; - } - state->attrs[0] = SYSDB_ORIG_DN; - state->attrs[1] = SYSDB_SHADOWPW_LASTCHANGE; - state->attrs[2] = SYSDB_SHADOWPW_MIN; - state->attrs[3] = SYSDB_SHADOWPW_MAX; - state->attrs[4] = SYSDB_SHADOWPW_WARNING; - state->attrs[5] = SYSDB_SHADOWPW_INACTIVE; - state->attrs[6] = SYSDB_SHADOWPW_EXPIRE; - state->attrs[7] = SYSDB_KRBPW_LASTCHANGE; - state->attrs[8] = SYSDB_KRBPW_EXPIRATION; - state->attrs[9] = SYSDB_PWD_ATTRIBUTE; - state->attrs[10] = NULL; - - /* this sysdb call uses a sysdn operation, which means it will be - * schedule only after we return, no timer hack needed */ - ret = sysdb_get_user_attr(state, state->ctx->be->sysdb, - state->ctx->be->domain, state->name, - state->attrs, get_user_dn_done, req); - if (ret) { - tevent_req_error(req, ret); - tevent_req_post(req, ev); - } - - return req; -} - -static void get_user_dn_done(void *pvt, int err, struct ldb_result *res) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct get_user_dn_state *state = tevent_req_data(req, - struct get_user_dn_state); - const char *dn; - int ret; - - if (err != LDB_SUCCESS) { - tevent_req_error(req, EIO); - return; - } - - switch (res->count) { - case 0: - /* FIXME: not in cache, needs a true search */ - tevent_req_error(req, ENOENT); - break; - - case 1: - dn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_ORIG_DN, NULL); - if (!dn) { - /* TODO: try to search ldap server ? */ - - /* FIXME: remove once we store originalDN on every call - * NOTE: this is wrong, works only with some DITs */ - dn = talloc_asprintf(state, "%s=%s,%s", - state->ctx->opts->user_map[SDAP_AT_USER_NAME].name, - state->name, - dp_opt_get_string(state->ctx->opts->basic, - SDAP_USER_SEARCH_BASE)); - if (!dn) { - tevent_req_error(req, ENOMEM); - break; - } - } - - state->dn = talloc_strdup(state, dn); - if (!state->dn) { - tevent_req_error(req, ENOMEM); - break; - } - - ret = find_password_expiration_attributes(state, res->msgs[0], - state->ctx->opts->basic, - &state->pw_expire_type, - &state->pw_expire_data); - if (ret != EOK) { - DEBUG(1, ("find_password_expiration_attributes failed.\n")); - tevent_req_error(req, ENOMEM); - break; - } - - tevent_req_done(req); - break; - - default: - DEBUG(1, ("A user search by name (%s) returned > 1 results!\n", - state->name)); - tevent_req_error(req, EFAULT); - break; - } -} - -static int get_user_dn_recv(struct tevent_req *req, - TALLOC_CTX *memctx, char **dn, - enum pwexpire *pw_expire_type, - void **pw_expire_data) -{ - struct get_user_dn_state *state = tevent_req_data(req, - struct get_user_dn_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *dn = talloc_steal(memctx, state->dn); - if (!*dn) return ENOMEM; - - /* state->pw_expire_data may be NULL */ - *pw_expire_data = talloc_steal(memctx, state->pw_expire_data); - - *pw_expire_type = state->pw_expire_type; - - return EOK; -} - -/* ==Authenticate-User==================================================== */ - -struct auth_state { - struct tevent_context *ev; - struct sdap_auth_ctx *ctx; - const char *username; - struct dp_opt_blob password; - - struct sdap_handle *sh; - - enum sdap_result result; - char *dn; - enum pwexpire pw_expire_type; - void *pw_expire_data; - - struct fo_server *srv; -}; - -static void auth_resolve_done(struct tevent_req *subreq); -static void auth_connect_done(struct tevent_req *subreq); -static void auth_get_user_dn_done(struct tevent_req *subreq); -static void auth_bind_user_done(struct tevent_req *subreq); - -static struct tevent_req *auth_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_auth_ctx *ctx, - const char *username, - struct dp_opt_blob password) -{ - struct tevent_req *req, *subreq; - struct auth_state *state; - - req = tevent_req_create(memctx, &state, struct auth_state); - if (!req) return NULL; - - state->ev = ev; - state->ctx = ctx; - state->username = username; - state->password = password; - state->srv = NULL; - - subreq = be_resolve_server_send(state, ev, ctx->be, ctx->service->name); - if (!subreq) goto fail; - - tevent_req_set_callback(subreq, auth_resolve_done, req); - - return req; - -fail: - talloc_zfree(req); - return NULL; -} - -static void auth_resolve_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct auth_state *state = tevent_req_data(req, - struct auth_state); - int ret; - - ret = be_resolve_server_recv(subreq, &state->srv); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - subreq = sdap_connect_send(state, state->ev, state->ctx->opts, - state->ctx->service->uri, true); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - - tevent_req_set_callback(subreq, auth_connect_done, req); -} - -static void auth_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct auth_state *state = tevent_req_data(req, - struct auth_state); - int ret; - - ret = sdap_connect_recv(subreq, state, &state->sh); - talloc_zfree(subreq); - if (ret) { - if (state->srv) { - /* mark this server as bad if connection failed */ - fo_set_port_status(state->srv, PORT_NOT_WORKING); - } - - tevent_req_error(req, ret); - return; - } else if (state->srv) { - fo_set_port_status(state->srv, PORT_WORKING); - } - - subreq = get_user_dn_send(state, state->ev, - state->ctx, state->sh, - state->username); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - - tevent_req_set_callback(subreq, auth_get_user_dn_done, req); -} - -static void auth_get_user_dn_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct auth_state *state = tevent_req_data(req, - struct auth_state); - int ret; - - ret = get_user_dn_recv(subreq, state, &state->dn, &state->pw_expire_type, - &state->pw_expire_data); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - subreq = sdap_auth_send(state, state->ev, state->sh, - NULL, NULL, state->dn, - "password", state->password); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - - tevent_req_set_callback(subreq, auth_bind_user_done, req); -} - -static void auth_bind_user_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct auth_state *state = tevent_req_data(req, - struct auth_state); - int ret; - - ret = sdap_auth_recv(subreq, &state->result); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -int auth_recv(struct tevent_req *req, - TALLOC_CTX *memctx, - struct sdap_handle **sh, - enum sdap_result *result, char **dn, - enum pwexpire *pw_expire_type, void **pw_expire_data) -{ - struct auth_state *state = tevent_req_data(req, struct auth_state); - enum tevent_req_state tstate; - uint64_t err; - - if (tevent_req_is_error(req, &tstate, &err)) { - switch (tstate) { - case TEVENT_REQ_USER_ERROR: - if (err == ETIMEDOUT) *result = SDAP_UNAVAIL; - else *result = SDAP_ERROR; - return err; - default: - *result = SDAP_ERROR; - return EIO; - } - } - - if (sh != NULL) { - *sh = talloc_steal(memctx, state->sh); - if (*sh == NULL) return ENOMEM; - } - - if (dn != NULL) { - *dn = talloc_steal(memctx, state->dn); - if (*dn == NULL) return ENOMEM; - } - - if (pw_expire_data != NULL) { - *pw_expire_data = talloc_steal(memctx, state->pw_expire_data); - } - - *pw_expire_type = state->pw_expire_type; - - *result = state->result; - return EOK; -} - -/* ==Perform-Password-Change===================== */ - -struct sdap_pam_chpass_state { - struct be_req *breq; - struct pam_data *pd; - const char *username; - char *dn; - char *password; - char *new_password; - struct sdap_handle *sh; -}; - -static void sdap_auth4chpass_done(struct tevent_req *req); -static void sdap_pam_chpass_done(struct tevent_req *req); -static void sdap_pam_auth_reply(struct be_req *breq, int dp_err, int result); - -void sdap_pam_chpass_handler(struct be_req *breq) -{ - struct sdap_pam_chpass_state *state; - struct sdap_auth_ctx *ctx; - struct tevent_req *subreq; - struct pam_data *pd; - struct dp_opt_blob authtok; - int dp_err = DP_ERR_FATAL; - - ctx = talloc_get_type(breq->be_ctx->bet_info[BET_CHPASS].pvt_bet_data, - struct sdap_auth_ctx); - pd = talloc_get_type(breq->req_data, struct pam_data); - - if (be_is_offline(ctx->be)) { - DEBUG(4, ("Backend is marked offline, retry later!\n")); - pd->pam_status = PAM_AUTHINFO_UNAVAIL; - dp_err = DP_ERR_OFFLINE; - goto done; - } - - DEBUG(2, ("starting password change request for user [%s].\n", pd->user)); - - pd->pam_status = PAM_SYSTEM_ERR; - - if (pd->cmd != SSS_PAM_CHAUTHTOK && pd->cmd != SSS_PAM_CHAUTHTOK_PRELIM) { - DEBUG(2, ("chpass target was called by wrong pam command.\n")); - goto done; - } - - state = talloc_zero(breq, struct sdap_pam_chpass_state); - if (!state) goto done; - - state->breq = breq; - state->pd = pd; - state->username = pd->user; - state->password = talloc_strndup(state, - (char *)pd->authtok, pd->authtok_size); - if (!state->password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->password, - password_destructor); - - if (pd->cmd == SSS_PAM_CHAUTHTOK) { - state->new_password = talloc_strndup(state, - (char *)pd->newauthtok, - pd->newauthtok_size); - if (!state->new_password) goto done; - talloc_set_destructor((TALLOC_CTX *)state->new_password, - password_destructor); - } - - authtok.data = (uint8_t *)state->password; - authtok.length = strlen(state->password); - subreq = auth_send(breq, breq->be_ctx->ev, - ctx, state->username, authtok); - if (!subreq) goto done; - - tevent_req_set_callback(subreq, sdap_auth4chpass_done, state); - return; - -done: - sdap_pam_auth_reply(breq, dp_err, pd->pam_status); -} - -static void sdap_auth4chpass_done(struct tevent_req *req) -{ - struct sdap_pam_chpass_state *state = - tevent_req_callback_data(req, struct sdap_pam_chpass_state); - struct tevent_req *subreq; - enum sdap_result result; - enum pwexpire pw_expire_type; - void *pw_expire_data; - int dp_err = DP_ERR_FATAL; - int ret; - - ret = auth_recv(req, state, &state->sh, - &result, &state->dn, - &pw_expire_type, &pw_expire_data); - talloc_zfree(req); - if (ret) { - state->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - - if (result == SDAP_AUTH_SUCCESS && - state->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) { - DEBUG(9, ("Initial authentication for change password operation " - "successful.\n")); - state->pd->pam_status = PAM_SUCCESS; - goto done; - } - - if (result == SDAP_AUTH_SUCCESS) { - switch (pw_expire_type) { - case PWEXPIRE_SHADOW: - ret = check_pwexpire_shadow(pw_expire_data, time(NULL), - &result); - if (ret != EOK) { - DEBUG(1, ("check_pwexpire_shadow failed.\n")); - state->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - break; - case PWEXPIRE_KERBEROS: - ret = check_pwexpire_kerberos(pw_expire_data, time(NULL), - &result); - if (ret != EOK) { - DEBUG(1, ("check_pwexpire_kerberos failed.\n")); - state->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - - if (result == SDAP_AUTH_PW_EXPIRED) { - DEBUG(1, ("LDAP provider cannot change kerberos " - "passwords.\n")); - state->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - break; - case PWEXPIRE_LDAP_PASSWORD_POLICY: - case PWEXPIRE_NONE: - break; - default: - DEBUG(1, ("Unknow pasword expiration type.\n")); - state->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - } - - switch (result) { - case SDAP_AUTH_SUCCESS: - case SDAP_AUTH_PW_EXPIRED: - DEBUG(7, ("user [%s] successfully authenticated.\n", state->dn)); - if (pw_expire_type == PWEXPIRE_SHADOW) { -/* TODO: implement async ldap modify request */ - DEBUG(1, ("Changing shadow password attributes not implemented.\n")); - state->pd->pam_status = PAM_MODULE_UNKNOWN; - goto done; - } else { - subreq = sdap_exop_modify_passwd_send(state, - state->breq->be_ctx->ev, - state->sh, - state->dn, - state->password, - state->new_password); - - if (!subreq) { - DEBUG(2, ("Failed to change password for %s\n", state->username)); - goto done; - } - - tevent_req_set_callback(subreq, sdap_pam_chpass_done, state); - return; - } - break; - case SDAP_AUTH_FAILED: - state->pd->pam_status = PAM_AUTH_ERR; - break; - default: - state->pd->pam_status = PAM_SYSTEM_ERR; - } - -done: - sdap_pam_auth_reply(state->breq, dp_err, state->pd->pam_status); -} - -static void sdap_pam_chpass_done(struct tevent_req *req) -{ - struct sdap_pam_chpass_state *state = - tevent_req_callback_data(req, struct sdap_pam_chpass_state); - enum sdap_result result; - int dp_err = DP_ERR_FATAL; - int ret; - char *user_error_message = NULL; - size_t msg_len; - uint8_t *msg; - - ret = sdap_exop_modify_passwd_recv(req, state, &result, &user_error_message); - talloc_zfree(req); - if (ret) { - state->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - - switch (result) { - case SDAP_SUCCESS: - state->pd->pam_status = PAM_SUCCESS; - dp_err = DP_ERR_OK; - break; - default: - state->pd->pam_status = PAM_AUTHTOK_ERR; - if (user_error_message != NULL) { - ret = pack_user_info_chpass_error(state->pd, user_error_message, - &msg_len, &msg); - if (ret != EOK) { - DEBUG(1, ("pack_user_info_chpass_error failed.\n")); - } else { - ret = pam_add_response(state->pd, SSS_PAM_USER_INFO, msg_len, - msg); - if (ret != EOK) { - DEBUG(1, ("pam_add_response failed.\n")); - } - } - } - } - -done: - sdap_pam_auth_reply(state->breq, dp_err, state->pd->pam_status); -} -/* ==Perform-User-Authentication-and-Password-Caching===================== */ - -struct sdap_pam_auth_state { - struct be_req *breq; - struct pam_data *pd; - const char *username; - struct dp_opt_blob password; -}; - -static void sdap_pam_auth_done(struct tevent_req *req); -static void sdap_password_cache_done(struct tevent_req *req); - -void sdap_pam_auth_handler(struct be_req *breq) -{ - struct sdap_pam_auth_state *state; - struct sdap_auth_ctx *ctx; - struct tevent_req *subreq; - struct pam_data *pd; - int dp_err = DP_ERR_FATAL; - - ctx = talloc_get_type(breq->be_ctx->bet_info[BET_AUTH].pvt_bet_data, - struct sdap_auth_ctx); - pd = talloc_get_type(breq->req_data, struct pam_data); - - if (be_is_offline(ctx->be)) { - DEBUG(4, ("Backend is marked offline, retry later!\n")); - pd->pam_status = PAM_AUTHINFO_UNAVAIL; - dp_err = DP_ERR_OFFLINE; - goto done; - } - - pd->pam_status = PAM_SYSTEM_ERR; - - switch (pd->cmd) { - case SSS_PAM_AUTHENTICATE: - case SSS_PAM_CHAUTHTOK_PRELIM: - - state = talloc_zero(breq, struct sdap_pam_auth_state); - if (!state) goto done; - - state->breq = breq; - state->pd = pd; - state->username = pd->user; - state->password.data = pd->authtok; - state->password.length = pd->authtok_size; - - subreq = auth_send(breq, breq->be_ctx->ev, ctx, - state->username, state->password); - if (!subreq) goto done; - - tevent_req_set_callback(subreq, sdap_pam_auth_done, state); - return; - - case SSS_PAM_CHAUTHTOK: - break; - - case SSS_PAM_ACCT_MGMT: - case SSS_PAM_SETCRED: - case SSS_PAM_OPEN_SESSION: - case SSS_PAM_CLOSE_SESSION: - pd->pam_status = PAM_SUCCESS; - dp_err = DP_ERR_OK; - break; - default: - pd->pam_status = PAM_MODULE_UNKNOWN; - dp_err = DP_ERR_OK; - } - -done: - sdap_pam_auth_reply(breq, dp_err, pd->pam_status); -} - -static void sdap_pam_auth_done(struct tevent_req *req) -{ - struct sdap_pam_auth_state *state = - tevent_req_callback_data(req, struct sdap_pam_auth_state); - struct tevent_req *subreq; - enum sdap_result result; - enum pwexpire pw_expire_type; - void *pw_expire_data; - int dp_err = DP_ERR_OK; - int ret; - - ret = auth_recv(req, state, NULL, - &result, NULL, - &pw_expire_type, &pw_expire_data); - talloc_zfree(req); - if (ret) { - state->pd->pam_status = PAM_SYSTEM_ERR; - dp_err = DP_ERR_FATAL; - goto done; - } - - if (result == SDAP_AUTH_SUCCESS) { - switch (pw_expire_type) { - case PWEXPIRE_SHADOW: - ret = check_pwexpire_shadow(pw_expire_data, time(NULL), - &result); - if (ret != EOK) { - DEBUG(1, ("check_pwexpire_shadow failed.\n")); - state->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - break; - case PWEXPIRE_KERBEROS: - ret = check_pwexpire_kerberos(pw_expire_data, time(NULL), - &result); - if (ret != EOK) { - DEBUG(1, ("check_pwexpire_kerberos failed.\n")); - state->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - break; - case PWEXPIRE_LDAP_PASSWORD_POLICY: - case PWEXPIRE_NONE: - break; - default: - DEBUG(1, ("Unknow pasword expiration type.\n")); - state->pd->pam_status = PAM_SYSTEM_ERR; - goto done; - } - } - - switch (result) { - case SDAP_AUTH_SUCCESS: - state->pd->pam_status = PAM_SUCCESS; - break; - case SDAP_AUTH_FAILED: - state->pd->pam_status = PAM_PERM_DENIED; - break; - case SDAP_UNAVAIL: - state->pd->pam_status = PAM_AUTHINFO_UNAVAIL; - break; - case SDAP_ACCT_EXPIRED: - state->pd->pam_status = PAM_ACCT_EXPIRED; - break; - case SDAP_AUTH_PW_EXPIRED: - state->pd->pam_status = PAM_AUTHTOK_EXPIRED; - break; - default: - state->pd->pam_status = PAM_SYSTEM_ERR; - dp_err = DP_ERR_FATAL; - } - - if (result == SDAP_UNAVAIL) { - be_mark_offline(state->breq->be_ctx); - dp_err = DP_ERR_OFFLINE; - goto done; - } - - if (result == SDAP_AUTH_SUCCESS && - state->breq->be_ctx->domain->cache_credentials) { - - char *password = talloc_strndup(state, (char *) - state->password.data, - state->password.length); - /* password caching failures are not fatal errors */ - if (!password) { - DEBUG(2, ("Failed to cache password for %s\n", state->username)); - goto done; - } - talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - - subreq = sysdb_cache_password_send(state, - state->breq->be_ctx->ev, - state->breq->be_ctx->sysdb, - NULL, - state->breq->be_ctx->domain, - state->username, password); - - /* password caching failures are not fatal errors */ - if (!subreq) { - DEBUG(2, ("Failed to cache password for %s\n", state->username)); - goto done; - } - - tevent_req_set_callback(subreq, sdap_password_cache_done, state); - return; - } - -done: - sdap_pam_auth_reply(state->breq, dp_err, state->pd->pam_status); -} - -static void sdap_password_cache_done(struct tevent_req *subreq) -{ - struct sdap_pam_auth_state *state = tevent_req_callback_data(subreq, - struct sdap_pam_auth_state); - int ret; - - ret = sysdb_cache_password_recv(subreq); - talloc_zfree(subreq); - if (ret) { - /* password caching failures are not fatal errors */ - DEBUG(2, ("Failed to cache password for %s\n", state->username)); - } else { - DEBUG(4, ("Password successfully cached for %s\n", state->username)); - } - - sdap_pam_auth_reply(state->breq, DP_ERR_OK, state->pd->pam_status); -} - -static void sdap_pam_auth_reply(struct be_req *req, int dp_err, int result) -{ - req->fn(req, dp_err, result, NULL); -} - diff --git a/server/providers/ldap/ldap_child.c b/server/providers/ldap/ldap_child.c deleted file mode 100644 index 0d34be2ca..000000000 --- a/server/providers/ldap/ldap_child.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - SSSD - - LDAP Backend Module -- prime ccache with TGT in a child process - - Authors: - Jakub Hrozek - - 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/sss_krb5.h" -#include "providers/child_common.h" -#include "providers/dp_backend.h" - -static krb5_context krb5_error_ctx; - -struct input_buffer { - const char *realm_str; - const char *princ_str; - const char *keytab_name; -}; - -static errno_t unpack_buffer(uint8_t *buf, size_t size, - struct input_buffer *ibuf) -{ - size_t p = 0; - uint32_t len; - - DEBUG(7, ("total buffer size: %d\n", size)); - - /* realm_str size and length */ - COPY_UINT32_CHECK(&len, buf + p, p, size); - - DEBUG(7, ("realm_str size: %d\n", len)); - if (len) { - if ((p + len ) > size) return EINVAL; - ibuf->realm_str = talloc_strndup(ibuf, (char *)(buf + p), len); - DEBUG(7, ("got realm_str: %s\n", ibuf->realm_str)); - if (ibuf->realm_str == NULL) return ENOMEM; - p += len; - } - - /* princ_str size and length */ - COPY_UINT32_CHECK(&len, buf + p, p, size); - - DEBUG(7, ("princ_str size: %d\n", len)); - if (len) { - if ((p + len ) > size) return EINVAL; - ibuf->princ_str = talloc_strndup(ibuf, (char *)(buf + p), len); - DEBUG(7, ("got princ_str: %s\n", ibuf->princ_str)); - if (ibuf->princ_str == NULL) return ENOMEM; - p += len; - } - - /* keytab_name size and length */ - COPY_UINT32_CHECK(&len, buf + p, p, size); - - DEBUG(7, ("keytab_name size: %d\n", len)); - if (len) { - if ((p + len ) > size) return EINVAL; - ibuf->keytab_name = talloc_strndup(ibuf, (char *)(buf + p), len); - DEBUG(7, ("got keytab_name: %s\n", ibuf->keytab_name)); - if (ibuf->keytab_name == NULL) return ENOMEM; - p += len; - } - - return EOK; -} - -static int pack_buffer(struct response *r, int result, const char *msg) -{ - int len; - int p = 0; - - len = strlen(msg); - r->size = 2 * sizeof(uint32_t) + len; - - /* result */ - COPY_UINT32_VALUE(&r->buf[p], result, p); - - /* message size */ - COPY_UINT32_VALUE(&r->buf[p], len, p); - - /* message itself */ - COPY_MEM(&r->buf[p], msg, p, len); - - return EOK; -} - -static int ldap_child_get_tgt_sync(TALLOC_CTX *memctx, - const char *realm_str, - const char *princ_str, - const char *keytab_name, - const char **ccname_out) -{ - char *ccname; - char *realm_name = NULL; - char *full_princ = NULL; - krb5_context context = NULL; - krb5_keytab keytab = NULL; - krb5_ccache ccache = NULL; - krb5_principal kprinc; - krb5_creds my_creds; - krb5_get_init_creds_opt options; - krb5_error_code krberr; - int ret; - - krberr = krb5_init_context(&context); - if (krberr) { - DEBUG(2, ("Failed to init kerberos context\n")); - return EFAULT; - } - - if (!realm_str) { - krberr = krb5_get_default_realm(context, &realm_name); - if (krberr) { - DEBUG(2, ("Failed to get default realm name: %s\n", - sss_krb5_get_error_message(context, krberr))); - ret = EFAULT; - goto done; - } - } else { - realm_name = talloc_strdup(memctx, realm_str); - if (!realm_name) { - ret = ENOMEM; - goto done; - } - } - - if (princ_str) { - if (!strchr(princ_str, '@')) { - full_princ = talloc_asprintf(memctx, "%s@%s", - princ_str, realm_name); - } else { - full_princ = talloc_strdup(memctx, princ_str); - } - } else { - char hostname[512]; - - ret = gethostname(hostname, 511); - if (ret == -1) { - ret = errno; - goto done; - } - hostname[511] = '\0'; - - full_princ = talloc_asprintf(memctx, "host/%s@%s", - hostname, realm_name); - } - if (!full_princ) { - ret = ENOMEM; - goto done; - } - DEBUG(4, ("Principal name is: [%s]\n", full_princ)); - - krberr = krb5_parse_name(context, full_princ, &kprinc); - if (krberr) { - DEBUG(2, ("Unable to build principal: %s\n", - sss_krb5_get_error_message(context, krberr))); - ret = EFAULT; - goto done; - } - - if (keytab_name) { - krberr = krb5_kt_resolve(context, keytab_name, &keytab); - } else { - krberr = krb5_kt_default(context, &keytab); - } - if (krberr) { - DEBUG(2, ("Failed to read keytab file: %s\n", - sss_krb5_get_error_message(context, krberr))); - ret = EFAULT; - goto done; - } - - ccname = talloc_asprintf(memctx, "FILE:%s/ccache_%s", DB_PATH, realm_name); - if (!ccname) { - ret = ENOMEM; - goto done; - } - - krberr = krb5_cc_resolve(context, ccname, &ccache); - if (krberr) { - DEBUG(2, ("Failed to set cache name: %s\n", - sss_krb5_get_error_message(context, krberr))); - ret = EFAULT; - goto done; - } - - memset(&my_creds, 0, sizeof(my_creds)); - memset(&options, 0, sizeof(options)); - - krb5_get_init_creds_opt_set_address_list(&options, NULL); - krb5_get_init_creds_opt_set_forwardable(&options, 0); - krb5_get_init_creds_opt_set_proxiable(&options, 0); - /* set a very short lifetime, we don't keep the ticket around */ - krb5_get_init_creds_opt_set_tkt_life(&options, 300); - - krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc, - keytab, 0, NULL, &options); - - if (krberr) { - DEBUG(2, ("Failed to init credentials: %s\n", - sss_krb5_get_error_message(context, krberr))); - ret = EFAULT; - goto done; - } - - krberr = krb5_cc_initialize(context, ccache, kprinc); - if (krberr) { - DEBUG(2, ("Failed to init ccache: %s\n", - sss_krb5_get_error_message(context, krberr))); - ret = EFAULT; - goto done; - } - - krberr = krb5_cc_store_cred(context, ccache, &my_creds); - if (krberr) { - DEBUG(2, ("Failed to store creds: %s\n", - sss_krb5_get_error_message(context, krberr))); - ret = EFAULT; - goto done; - } - - ret = EOK; - *ccname_out = ccname; - -done: - if (keytab) krb5_kt_close(context, keytab); - if (context) krb5_free_context(context); - return ret; -} - -static int prepare_response(TALLOC_CTX *mem_ctx, - const char *ccname, - krb5_error_code kerr, - struct response **rsp) -{ - int ret; - struct response *r = NULL; - const char *krb5_msg = NULL; - - r = talloc_zero(mem_ctx, struct response); - if (!r) return ENOMEM; - - r->buf = talloc_size(mem_ctx, MAX_CHILD_MSG_SIZE); - if (r->buf == NULL) { - DEBUG(1, ("talloc_size failed.\n")); - return ENOMEM; - } - r->max_size = MAX_CHILD_MSG_SIZE; - r->size = 0; - - if (kerr == 0) { - ret = pack_buffer(r, EOK, ccname); - } else { - krb5_msg = sss_krb5_get_error_message(krb5_error_ctx, kerr); - if (krb5_msg == NULL) { - DEBUG(1, ("sss_krb5_get_error_message failed.\n")); - return ENOMEM; - } - - ret = pack_buffer(r, EFAULT, krb5_msg); - sss_krb5_free_error_message(krb5_error_ctx, krb5_msg); - } - - if (ret != EOK) { - DEBUG(1, ("pack_buffer failed\n")); - return ret; - } - - *rsp = r; - return EOK; -} - -int main(int argc, const char *argv[]) -{ - int ret; - int kerr; - int opt; - int debug_fd = -1; - poptContext pc; - TALLOC_CTX *main_ctx; - uint8_t *buf = NULL; - ssize_t len = 0; - const char *ccname = NULL; - struct input_buffer *ibuf = NULL; - struct response *resp = NULL; - size_t written; - - 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, ("ldap_child started.\n")); - - main_ctx = talloc_new(NULL); - if (main_ctx == NULL) { - DEBUG(1, ("talloc_new failed.\n")); - _exit(-1); - } - - debug_prg_name = talloc_asprintf(main_ctx, "[sssd[ldap_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(main_ctx, sizeof(uint8_t)*IN_BUF_SIZE); - if (buf == NULL) { - DEBUG(1, ("talloc_size failed.\n")); - goto fail; - } - - ibuf = talloc_zero(main_ctx, struct input_buffer); - if (ibuf == NULL) { - DEBUG(1, ("talloc_size failed.\n")); - goto fail; - } - - 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, ibuf); - if (ret != EOK) { - DEBUG(1, ("unpack_buffer failed.[%d][%s].\n", ret, strerror(ret))); - goto fail; - } - - kerr = ldap_child_get_tgt_sync(main_ctx, - ibuf->realm_str, ibuf->princ_str, - ibuf->keytab_name, &ccname); - if (kerr != EOK) { - DEBUG(1, ("ldap_child_get_tgt_sync failed.\n")); - /* Do not return, must report failure */ - } - - ret = prepare_response(main_ctx, ccname, kerr, &resp); - if (ret != EOK) { - DEBUG(1, ("prepare_response failed. [%d][%s].\n", ret, strerror(ret))); - return ENOMEM; - } - - written = 0; - while (written < resp->size) { - ret = write(STDOUT_FILENO, 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; - } - - close(STDOUT_FILENO); - talloc_free(main_ctx); - _exit(0); - -fail: - close(STDOUT_FILENO); - talloc_free(main_ctx); - _exit(-1); -} diff --git a/server/providers/ldap/ldap_common.c b/server/providers/ldap/ldap_common.c deleted file mode 100644 index bd4294f83..000000000 --- a/server/providers/ldap/ldap_common.c +++ /dev/null @@ -1,589 +0,0 @@ -/* - SSSD - - LDAP Provider Common Functions - - Authors: - Simo Sorce - - 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 "providers/ldap/ldap_common.h" -#include "providers/fail_over.h" - -#include "util/sss_krb5.h" - -/* a fd the child process would log into */ -int ldap_child_debug_fd = -1; - -struct dp_option default_basic_opts[] = { - { "ldap_uri", DP_OPT_STRING, { "ldap://localhost" }, NULL_STRING }, - { "ldap_search_base", DP_OPT_STRING, { "dc=example,dc=com" }, NULL_STRING }, - { "ldap_default_bind_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_default_authtok_type", DP_OPT_STRING, NULL_STRING, NULL_STRING}, - { "ldap_default_authtok", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB }, - { "ldap_search_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER }, - { "ldap_network_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER }, - { "ldap_opt_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER }, - { "ldap_tls_reqcert", DP_OPT_STRING, { "hard" }, NULL_STRING }, - { "ldap_user_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_user_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, - { "ldap_user_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_group_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING }, - { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_schema", DP_OPT_STRING, { "rfc2307" }, NULL_STRING }, - { "ldap_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER }, - { "ldap_force_upper_case_realm", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, - { "ldap_enumeration_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER }, - { "ldap_purge_cache_timeout", DP_OPT_NUMBER, { .number = 3600 }, NULL_NUMBER }, - { "entry_cache_timoeut", DP_OPT_NUMBER, { .number = 1800 }, NULL_NUMBER }, - { "ldap_tls_cacert", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_tls_cacertdir", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_id_use_start_tls", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, - { "ldap_sasl_mech", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_sasl_authid", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_krb5_keytab", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_krb5_init_creds", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, - /* use the same parm name as the krb5 module so we set it only once */ - { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING }, - { "ldap_pwd_policy", DP_OPT_STRING, { "none" } , NULL_STRING }, - { "ldap_referrals", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE } -}; - -struct sdap_attr_map generic_attr_map[] = { - { "ldap_entry_usn", NULL, SYSDB_USN, NULL }, - { "ldap_rootdse_last_usn", NULL, SYSDB_USN, NULL } -}; - -struct sdap_attr_map gen_ipa_attr_map[] = { - { "ldap_entry_usn", "entryUSN", SYSDB_USN, NULL }, - { "ldap_rootdse_last_usn", "lastUSN", SYSDB_HIGH_USN, NULL } -}; - -struct sdap_attr_map gen_ad_attr_map[] = { - { "ldap_entry_usn", "uSNChanged", SYSDB_USN, NULL }, - { "ldap_rootdse_last_usn", "highestCommittedUSN", SYSDB_HIGH_USN, NULL } -}; - -struct sdap_attr_map rfc2307_user_map[] = { - { "ldap_user_object_class", "posixAccount", SYSDB_USER_CLASS, NULL }, - { "ldap_user_name", "uid", SYSDB_NAME, NULL }, - { "ldap_user_pwd", "userPassword", SYSDB_PWD, NULL }, - { "ldap_user_uid_number", "uidNumber", SYSDB_UIDNUM, NULL }, - { "ldap_user_gid_number", "gidNumber", SYSDB_GIDNUM, NULL }, - { "ldap_user_gecos", "gecos", SYSDB_GECOS, NULL }, - { "ldap_user_home_directory", "homeDirectory", SYSDB_HOMEDIR, NULL }, - { "ldap_user_shell", "loginShell", SYSDB_SHELL, NULL }, - { "ldap_user_principal", "krbPrincipalName", SYSDB_UPN, NULL }, - { "ldap_user_fullname", "cn", SYSDB_FULLNAME, NULL }, - { "ldap_user_member_of", NULL, SYSDB_MEMBEROF, NULL }, - { "ldap_user_uuid", NULL, SYSDB_UUID, NULL }, - { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }, - { "ldap_user_shadow_last_change", "shadowLastChange", SYSDB_SHADOWPW_LASTCHANGE, NULL }, - { "ldap_user_shadow_min", "shadowMin", SYSDB_SHADOWPW_MIN, NULL }, - { "ldap_user_shadow_max", "shadowMax", SYSDB_SHADOWPW_MAX, NULL }, - { "ldap_user_shadow_warning", "shadowWarning", SYSDB_SHADOWPW_WARNING, NULL }, - { "ldap_user_shadow_inactive", "shadowInactive", SYSDB_SHADOWPW_INACTIVE, NULL }, - { "ldap_user_shadow_expire", "shadowExpire", SYSDB_SHADOWPW_EXPIRE, NULL }, - { "ldap_user_shadow_flag", "shadowFlag", SYSDB_SHADOWPW_FLAG, NULL }, - { "ldap_user_krb_last_pwd_change", "krbLastPwdChange", SYSDB_KRBPW_LASTCHANGE, NULL }, - { "ldap_user_krb_password_expiration", "krbPasswordExpiration", SYSDB_KRBPW_EXPIRATION, NULL }, - { "ldap_pwd_attribute", "pwdAttribute", SYSDB_PWD_ATTRIBUTE, NULL } -}; - -struct sdap_attr_map rfc2307_group_map[] = { - { "ldap_group_object_class", "posixGroup", SYSDB_GROUP_CLASS, NULL }, - { "ldap_group_name", "cn", SYSDB_NAME, NULL }, - { "ldap_group_pwd", "userPassword", SYSDB_PWD, NULL }, - { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL }, - { "ldap_group_member", "memberuid", SYSDB_MEMBER, NULL }, - { "ldap_group_uuid", NULL, SYSDB_UUID, NULL }, - { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL } -}; - -struct sdap_attr_map rfc2307bis_user_map[] = { - { "ldap_user_object_class", "posixAccount", SYSDB_USER_CLASS, NULL }, - { "ldap_user_name", "uid", SYSDB_NAME, NULL }, - { "ldap_user_pwd", "userPassword", SYSDB_PWD, NULL }, - { "ldap_user_uid_number", "uidNumber", SYSDB_UIDNUM, NULL }, - { "ldap_user_gid_number", "gidNumber", SYSDB_GIDNUM, NULL }, - { "ldap_user_gecos", "gecos", SYSDB_GECOS, NULL }, - { "ldap_user_home_directory", "homeDirectory", SYSDB_HOMEDIR, NULL }, - { "ldap_user_shell", "loginShell", SYSDB_SHELL, NULL }, - { "ldap_user_principal", "krbPrincipalName", SYSDB_UPN, NULL }, - { "ldap_user_fullname", "cn", SYSDB_FULLNAME, NULL }, - { "ldap_user_member_of", "memberOf", SYSDB_MEMBEROF, NULL }, - /* FIXME: this is 389ds specific */ - { "ldap_user_uuid", "nsUniqueId", SYSDB_UUID, NULL }, - { "ldap_user_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }, - { "ldap_user_shadow_last_change", "shadowLastChange", SYSDB_SHADOWPW_LASTCHANGE, NULL }, - { "ldap_user_shadow_min", "shadowMin", SYSDB_SHADOWPW_MIN, NULL }, - { "ldap_user_shadow_max", "shadowMax", SYSDB_SHADOWPW_MAX, NULL }, - { "ldap_user_shadow_warning", "shadowWarning", SYSDB_SHADOWPW_WARNING, NULL }, - { "ldap_user_shadow_inactive", "shadowInactive", SYSDB_SHADOWPW_INACTIVE, NULL }, - { "ldap_user_shadow_expire", "shadowExpire", SYSDB_SHADOWPW_EXPIRE, NULL }, - { "ldap_user_shadow_flag", "shadowFlag", SYSDB_SHADOWPW_FLAG, NULL }, - { "ldap_user_krb_last_pwd_change", "krbLastPwdChange", SYSDB_KRBPW_LASTCHANGE, NULL }, - { "ldap_user_krb_password_expiration", "krbPasswordExpiration", SYSDB_KRBPW_EXPIRATION, NULL }, - { "ldap_pwd_attribute", "pwdAttribute", SYSDB_PWD_ATTRIBUTE, NULL } -}; - -struct sdap_attr_map rfc2307bis_group_map[] = { - { "ldap_group_object_class", "posixGroup", SYSDB_GROUP_CLASS, NULL }, - { "ldap_group_name", "cn", SYSDB_NAME, NULL }, - { "ldap_group_pwd", "userPassword", SYSDB_PWD, NULL }, - { "ldap_group_gid_number", "gidNumber", SYSDB_GIDNUM, NULL }, - { "ldap_group_member", "member", SYSDB_MEMBER, NULL }, - /* FIXME: this is 389ds specific */ - { "ldap_group_uuid", "nsUniqueId", SYSDB_UUID, NULL }, - { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL } -}; - -int ldap_get_options(TALLOC_CTX *memctx, - struct confdb_ctx *cdb, - const char *conf_path, - struct sdap_options **_opts) -{ - struct sdap_attr_map *default_attr_map; - struct sdap_attr_map *default_user_map; - struct sdap_attr_map *default_group_map; - struct sdap_options *opts; - char *schema; - const char *pwd_policy; - int ret; - - opts = talloc_zero(memctx, struct sdap_options); - if (!opts) return ENOMEM; - - ret = dp_get_options(opts, cdb, conf_path, - default_basic_opts, - SDAP_OPTS_BASIC, - &opts->basic); - if (ret != EOK) { - goto done; - } - - /* set user/group search bases if they are not */ - if (NULL == dp_opt_get_string(opts->basic, SDAP_USER_SEARCH_BASE)) { - ret = dp_opt_set_string(opts->basic, SDAP_USER_SEARCH_BASE, - dp_opt_get_string(opts->basic, - SDAP_SEARCH_BASE)); - if (ret != EOK) { - goto done; - } - DEBUG(6, ("Option %s set to %s\n", - opts->basic[SDAP_USER_SEARCH_BASE].opt_name, - dp_opt_get_string(opts->basic, SDAP_USER_SEARCH_BASE))); - } - - if (NULL == dp_opt_get_string(opts->basic, SDAP_GROUP_SEARCH_BASE)) { - ret = dp_opt_set_string(opts->basic, SDAP_GROUP_SEARCH_BASE, - dp_opt_get_string(opts->basic, - SDAP_SEARCH_BASE)); - if (ret != EOK) { - goto done; - } - DEBUG(6, ("Option %s set to %s\n", - opts->basic[SDAP_GROUP_SEARCH_BASE].opt_name, - dp_opt_get_string(opts->basic, SDAP_GROUP_SEARCH_BASE))); - } - - pwd_policy = dp_opt_get_string(opts->basic, SDAP_PWD_POLICY); - if (pwd_policy == NULL) { - DEBUG(1, ("Missing password policy, this may not happen.\n")); - ret = EINVAL; - goto done; - } - if (strcasecmp(pwd_policy, PWD_POL_OPT_NONE) != 0 && - strcasecmp(pwd_policy, PWD_POL_OPT_SHADOW) != 0 && - strcasecmp(pwd_policy, PWD_POL_OPT_MIT) != 0) { - DEBUG(1, ("Unsupported password policy [%s].\n", pwd_policy)); - ret = EINVAL; - goto done; - } - - -#ifndef HAVE_LDAP_CONNCB - bool ldap_referrals; - - ldap_referrals = dp_opt_get_bool(opts->basic, SDAP_REFERRALS); - if (ldap_referrals) { - DEBUG(1, ("LDAP referrals are not supported, because the LDAP library " - "is too old, see sssd-ldap(5) for details.\n")); - ret = dp_opt_set_bool(opts->basic, SDAP_REFERRALS, false); - } -#endif - - /* schema type */ - schema = dp_opt_get_string(opts->basic, SDAP_SCHEMA); - if (strcasecmp(schema, "rfc2307") == 0) { - opts->schema_type = SDAP_SCHEMA_RFC2307; - default_attr_map = generic_attr_map; - default_user_map = rfc2307_user_map; - default_group_map = rfc2307_group_map; - } else - if (strcasecmp(schema, "rfc2307bis") == 0) { - opts->schema_type = SDAP_SCHEMA_RFC2307BIS; - default_attr_map = generic_attr_map; - default_user_map = rfc2307bis_user_map; - default_group_map = rfc2307bis_group_map; - } else - if (strcasecmp(schema, "IPA") == 0) { - opts->schema_type = SDAP_SCHEMA_IPA_V1; - default_attr_map = gen_ipa_attr_map; - default_user_map = rfc2307bis_user_map; - default_group_map = rfc2307bis_group_map; - } else - if (strcasecmp(schema, "AD") == 0) { - opts->schema_type = SDAP_SCHEMA_AD; - default_attr_map = gen_ad_attr_map; - default_user_map = rfc2307bis_user_map; - default_group_map = rfc2307bis_group_map; - } else { - DEBUG(0, ("Unrecognized schema type: %s\n", schema)); - ret = EINVAL; - goto done; - } - - ret = sdap_get_map(opts, cdb, conf_path, - default_attr_map, - SDAP_AT_GENERAL, - &opts->gen_map); - if (ret != EOK) { - goto done; - } - - ret = sdap_get_map(opts, cdb, conf_path, - default_user_map, - SDAP_OPTS_USER, - &opts->user_map); - if (ret != EOK) { - goto done; - } - - ret = sdap_get_map(opts, cdb, conf_path, - default_group_map, - SDAP_OPTS_GROUP, - &opts->group_map); - if (ret != EOK) { - goto done; - } - - ret = EOK; - *_opts = opts; - -done: - if (ret != EOK) { - talloc_zfree(opts); - } - return ret; -} - -void sdap_handler_done(struct be_req *req, int dp_err, - int error, const char *errstr) -{ - return req->fn(req, dp_err, error, errstr); -} - -bool sdap_connected(struct sdap_id_ctx *ctx) -{ - if (ctx->gsh) { - return ctx->gsh->connected; - } - - return false; -} - -void sdap_mark_offline(struct sdap_id_ctx *ctx) -{ - if (ctx->gsh) { - /* make sure we mark the connection as gone when we go offline so that - * we do not try to reuse a bad connection by mistale later */ - talloc_zfree(ctx->gsh); - } - - be_mark_offline(ctx->be); -} - -bool sdap_check_gssapi_reconnect(struct sdap_id_ctx *ctx) -{ - int ret; - bool result = false; - const char *mech; - const char *realm; - char *ccname = NULL; - krb5_context context = NULL; - krb5_ccache ccache = NULL; - krb5_error_code krberr; - TALLOC_CTX *tmp_ctx = NULL; - krb5_creds mcred; - krb5_creds cred; - char *server_name = NULL; - char *client_princ_str = NULL; - char *full_princ = NULL; - krb5_principal client_principal = NULL; - krb5_principal server_principal = NULL; - char hostname[512]; - int l_errno; - - - mech = dp_opt_get_string(ctx->opts->basic, SDAP_SASL_MECH); - if (mech == NULL || strcasecmp(mech, "GSSAPI") != 0) { - return false; - } - - realm = dp_opt_get_string(ctx->opts->basic, SDAP_KRB5_REALM); - if (realm == NULL) { - DEBUG(3, ("Kerberos realm not available.\n")); - return false; - } - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(1, ("talloc_new failed.\n")); - return false; - } - - ccname = talloc_asprintf(tmp_ctx, "FILE:%s/ccache_%s", DB_PATH, realm); - if (ccname == NULL) { - DEBUG(1, ("talloc_asprintf failed.\n")); - goto done; - } - - krberr = krb5_init_context(&context); - if (krberr) { - DEBUG(1, ("Failed to init kerberos context\n")); - goto done; - } - - krberr = krb5_cc_resolve(context, ccname, &ccache); - if (krberr != 0) { - DEBUG(1, ("krb5_cc_resolve failed.\n")); - goto done; - } - - server_name = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", realm, realm); - if (server_name == NULL) { - DEBUG(1, ("talloc_asprintf failed.\n")); - goto done; - } - - krberr = krb5_parse_name(context, server_name, &server_principal); - if (krberr != 0) { - DEBUG(1, ("krb5_parse_name failed.\n")); - goto done; - } - - client_princ_str = dp_opt_get_string(ctx->opts->basic, SDAP_SASL_AUTHID); - if (client_princ_str) { - if (!strchr(client_princ_str, '@')) { - full_princ = talloc_asprintf(tmp_ctx, "%s@%s", client_princ_str, - realm); - } else { - full_princ = talloc_strdup(tmp_ctx, client_princ_str); - } - } else { - ret = gethostname(hostname, sizeof(hostname)-1); - if (ret == -1) { - l_errno = errno; - DEBUG(1, ("gethostname failed [%d][%s].\n", l_errno, - strerror(l_errno))); - goto done; - } - hostname[sizeof(hostname)-1] = '\0'; - - full_princ = talloc_asprintf(tmp_ctx, "host/%s@%s", hostname, realm); - } - if (!full_princ) { - DEBUG(1, ("Client principal not available.\n")); - goto done; - } - DEBUG(7, ("Client principal name is: [%s]\n", full_princ)); - krberr = krb5_parse_name(context, full_princ, &client_principal); - if (krberr != 0) { - DEBUG(1, ("krb5_parse_name failed.\n")); - goto done; - } - - memset(&mcred, 0, sizeof(mcred)); - memset(&cred, 0, sizeof(mcred)); - mcred.client = client_principal; - mcred.server = server_principal; - - krberr = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred); - if (krberr != 0) { - DEBUG(1, ("krb5_cc_retrieve_cred failed.\n")); - goto done; - } - - DEBUG(7, ("TGT end time [%d].\n", cred.times.endtime)); - - if (cred.times.endtime <= time(NULL)) { - DEBUG(3, ("TGT is expired.\n")); - result = true; - } - krb5_free_cred_contents(context, &cred); - -done: - if (client_principal != NULL) { - krb5_free_principal(context, client_principal); - } - if (server_principal != NULL) { - krb5_free_principal(context, server_principal); - } - if (ccache != NULL) { - if (result) { - krb5_cc_destroy(context, ccache); - } else { - krb5_cc_close(context, ccache); - } - } - if (context != NULL) krb5_free_context(context); - talloc_free(tmp_ctx); - return result; -} - -int sdap_id_setup_tasks(struct sdap_id_ctx *ctx) -{ - struct timeval tv; - int ret = EOK; - - /* set up enumeration task */ - if (ctx->be->domain->enumerate) { - /* run the first one in a couple of seconds so that we have time to - * finish initializations first*/ - tv = tevent_timeval_current_ofs(10, 0); - ret = ldap_id_enumerate_set_timer(ctx, tv); - } else { - /* the enumeration task, runs the cleanup process by itself, - * but if enumeration is not runnig we need to schedule it */ - - /* run the first one in a couple of seconds so that we have time to - * finish initializations first*/ - tv = tevent_timeval_current_ofs(10, 0); - ret = ldap_id_cleanup_set_timer(ctx, tv); - } - - return ret; -} - -static void sdap_uri_callback(void *private_data, struct fo_server *server) -{ - struct sdap_service *service; - const char *tmp; - char *new_uri; - - service = talloc_get_type(private_data, struct sdap_service); - if (!service) return; - - tmp = (const char *)fo_get_server_user_data(server); - if (tmp && ldap_is_ldap_url(tmp)) { - new_uri = talloc_strdup(service, tmp); - } else { - new_uri = talloc_asprintf(service, "ldap://%s", - fo_get_server_name(server)); - } - if (!new_uri) { - DEBUG(2, ("Failed to copy URI ...\n")); - return; - } - - /* free old one and replace with new one */ - talloc_zfree(service->uri); - service->uri = new_uri; -} - -int sdap_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx, - const char *service_name, const char *urls, - struct sdap_service **_service) -{ - TALLOC_CTX *tmp_ctx; - struct sdap_service *service; - LDAPURLDesc *lud; - char **list = NULL; - int ret; - int i; - - tmp_ctx = talloc_new(memctx); - if (!tmp_ctx) { - return ENOMEM; - } - - service = talloc_zero(tmp_ctx, struct sdap_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; - } - - /* split server parm into a list */ - ret = split_on_separator(tmp_ctx, urls, ',', true, &list, NULL); - if (ret != EOK) { - DEBUG(1, ("Failed to parse server list!\n")); - goto done; - } - - /* now for each URI add a new server to the failover service */ - for (i = 0; list[i]; i++) { - ret = ldap_url_parse(list[i], &lud); - if (ret != LDAP_SUCCESS) { - DEBUG(0, ("Failed to parse ldap URI (%s)!\n", list[i])); - ret = EINVAL; - goto done; - } - - DEBUG(6, ("Added URI %s\n", list[i])); - - talloc_steal(service, list[i]); - - ret = be_fo_add_server(ctx, service->name, - lud->lud_host, lud->lud_port, list[i]); - if (ret) { - goto done; - } - ldap_free_urldesc(lud); - } - - ret = be_fo_service_add_callback(memctx, ctx, service->name, - sdap_uri_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/ldap/ldap_common.h b/server/providers/ldap/ldap_common.h deleted file mode 100644 index ff1ffb725..000000000 --- a/server/providers/ldap/ldap_common.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - SSSD - - LDAP Common utility code - - Copyright (C) Simo Sorce 2009 - - 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 _LDAP_COMMON_H_ -#define _LDAP_COMMON_H_ - -#include "providers/dp_backend.h" -#include "providers/ldap/sdap.h" -#include "providers/fail_over.h" - -#define PWD_POL_OPT_NONE "none" -#define PWD_POL_OPT_SHADOW "shadow" -#define PWD_POL_OPT_MIT "mit_kerberos" - -/* a fd the child process would log into */ -extern int ldap_child_debug_fd; - -struct sdap_id_ctx { - struct be_ctx *be; - struct sdap_options *opts; - struct fo_service *fo_service; - struct sdap_service *service; - - /* what rootDSE returns */ - struct sysdb_attrs *rootDSE; - - /* global sdap handler */ - struct sdap_handle *gsh; - - /* enumeration loop timer */ - struct timeval last_enum; - /* cleanup loop timer */ - struct timeval last_purge; - - char *max_user_timestamp; - char *max_group_timestamp; -}; - -struct sdap_auth_ctx { - struct be_ctx *be; - struct sdap_options *opts; - struct fo_service *fo_service; - struct sdap_service *service; -}; - -/* id */ -void sdap_account_info_handler(struct be_req *breq); -int sdap_id_setup_tasks(struct sdap_id_ctx *ctx); - -/* auth */ -void sdap_pam_auth_handler(struct be_req *breq); - -/* chpass */ -void sdap_pam_chpass_handler(struct be_req *breq); - - - -void sdap_handler_done(struct be_req *req, int dp_err, - int error, const char *errstr); - -int sdap_service_init(TALLOC_CTX *mmectx, struct be_ctx *ctx, - const char *service_name, const char *urls, - struct sdap_service **service); - -/* options parser */ -int ldap_get_options(TALLOC_CTX *memctx, - struct confdb_ctx *cdb, - const char *conf_path, - struct sdap_options **_opts); - -int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv); -int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv); - -bool sdap_connected(struct sdap_id_ctx *ctx); -void sdap_mark_offline(struct sdap_id_ctx *ctx); -bool sdap_check_gssapi_reconnect(struct sdap_id_ctx *ctx); - -struct tevent_req *users_get_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx, - const char *name, - int filter_type, - int attrs_type); -int users_get_recv(struct tevent_req *req); - -struct tevent_req *groups_get_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx, - const char *name, - int filter_type, - int attrs_type); -int groups_get_recv(struct tevent_req *req); - -/* setup child logging */ -int setup_child(struct sdap_id_ctx *ctx); - -#endif /* _LDAP_COMMON_H_ */ diff --git a/server/providers/ldap/ldap_id.c b/server/providers/ldap/ldap_id.c deleted file mode 100644 index 4bbc07a68..000000000 --- a/server/providers/ldap/ldap_id.c +++ /dev/null @@ -1,795 +0,0 @@ -/* - SSSD - - LDAP Identity Backend Module - - Authors: - Simo Sorce - - Copyright (C) 2008 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 "util/util.h" -#include "db/sysdb.h" -#include "providers/ldap/ldap_common.h" -#include "providers/ldap/sdap_async.h" - -/* =Users-Related-Functions-(by-name,by-uid)============================== */ - -struct users_get_state { - struct tevent_context *ev; - struct sdap_id_ctx *ctx; - struct sysdb_ctx *sysdb; - struct sss_domain_info *domain; - - const char *name; - int filter_type; - - char *filter; - const char **attrs; -}; - -static void users_get_connect_done(struct tevent_req *subreq); -static void users_get_done(struct tevent_req *subreq); -static void users_get_delete(struct tevent_req *subreq); - -struct tevent_req *users_get_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx, - const char *name, - int filter_type, - int attrs_type) -{ - struct tevent_req *req, *subreq; - struct users_get_state *state; - const char *attr_name; - int ret; - - req = tevent_req_create(memctx, &state, struct users_get_state); - if (!req) return NULL; - - state->ev = ev; - state->ctx = ctx; - state->sysdb = ctx->be->sysdb; - state->domain = state->ctx->be->domain; - state->name = name; - state->filter_type = filter_type; - - switch (filter_type) { - case BE_FILTER_NAME: - attr_name = ctx->opts->user_map[SDAP_AT_USER_NAME].name; - break; - case BE_FILTER_IDNUM: - attr_name = ctx->opts->user_map[SDAP_AT_USER_UID].name; - break; - default: - ret = EINVAL; - goto fail; - } - - state->filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))", - attr_name, name, - ctx->opts->user_map[SDAP_OC_USER].name); - if (!state->filter) { - DEBUG(2, ("Failed to build filter\n")); - ret = ENOMEM; - goto fail; - } - - /* TODO: handle attrs_type */ - ret = build_attrs_from_map(state, ctx->opts->user_map, - SDAP_OPTS_USER, &state->attrs); - if (ret != EOK) goto fail; - - if (!sdap_connected(ctx)) { - - if (ctx->gsh) talloc_zfree(ctx->gsh); - - /* FIXME: add option to decide if tls should be used - * or SASL/GSSAPI, etc ... */ - subreq = sdap_cli_connect_send(state, ev, ctx->opts, - ctx->be, ctx->service, - &ctx->rootDSE); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, users_get_connect_done, req); - - return req; - } - - subreq = sdap_get_users_send(state, state->ev, - state->domain, state->sysdb, - state->ctx->opts, state->ctx->gsh, - state->attrs, state->filter); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, users_get_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void users_get_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct users_get_state *state = tevent_req_data(req, - struct users_get_state); - int ret; - - ret = sdap_cli_connect_recv(subreq, state->ctx, - &state->ctx->gsh, &state->ctx->rootDSE); - talloc_zfree(subreq); - if (ret) { - if (ret == ENOTSUP) { - DEBUG(0, ("Authentication mechanism not Supported by server")); - } - tevent_req_error(req, ret); - return; - } - - subreq = sdap_get_users_send(state, state->ev, - state->domain, state->sysdb, - state->ctx->opts, state->ctx->gsh, - state->attrs, state->filter); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, users_get_done, req); -} - -static void users_get_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct users_get_state *state = tevent_req_data(req, - struct users_get_state); - char *endptr; - uid_t uid; - int ret; - - ret = sdap_get_users_recv(subreq, NULL, NULL); - talloc_zfree(subreq); - if (ret && ret != ENOENT) { - tevent_req_error(req, ret); - return; - } - - if (ret == ENOENT) { - if (strchr(state->name, '*')) { - /* it was an enumeration */ - tevent_req_error(req, ret); - return; - } - - switch (state->filter_type) { - case BE_FILTER_NAME: - subreq = sysdb_delete_user_send(state, state->ev, - state->sysdb, NULL, - state->domain, state->name, 0); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, users_get_delete, req); - return; - - case BE_FILTER_IDNUM: - errno = 0; - uid = (uid_t)strtol(state->name, &endptr, 0); - if (errno || *endptr || (state->name == endptr)) { - tevent_req_error(req, errno); - return; - } - - subreq = sysdb_delete_user_send(state, state->ev, - state->sysdb, NULL, - state->domain, NULL, uid); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, users_get_delete, req); - return; - - default: - tevent_req_error(req, EINVAL); - return; - } - } - - tevent_req_done(req); -} - -static void users_get_delete(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct users_get_state *state = tevent_req_data(req, - struct users_get_state); - int ret; - - ret = sysdb_delete_user_recv(subreq); - talloc_zfree(subreq); - if (ret) { - DEBUG(2, ("User (%s) delete returned %d (%s)\n", - state->name, ret, strerror(ret))); - } - - tevent_req_done(req); -} - -int users_get_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - - -/* =Groups-Related-Functions-(by-name,by-uid)============================= */ - -struct groups_get_state { - struct tevent_context *ev; - struct sdap_id_ctx *ctx; - struct sysdb_ctx *sysdb; - struct sss_domain_info *domain; - - const char *name; - int filter_type; - - char *filter; - const char **attrs; -}; - -static void groups_get_connect_done(struct tevent_req *subreq); -static void groups_get_done(struct tevent_req *subreq); -static void groups_get_delete(struct tevent_req *subreq); - -struct tevent_req *groups_get_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx, - const char *name, - int filter_type, - int attrs_type) -{ - struct tevent_req *req, *subreq; - struct groups_get_state *state; - const char *attr_name; - int ret; - - req = tevent_req_create(memctx, &state, struct groups_get_state); - if (!req) return NULL; - - state->ev = ev; - state->ctx = ctx; - state->sysdb = ctx->be->sysdb; - state->domain = state->ctx->be->domain; - state->name = name; - state->filter_type = filter_type; - - switch(filter_type) { - case BE_FILTER_NAME: - attr_name = ctx->opts->group_map[SDAP_AT_GROUP_NAME].name; - break; - case BE_FILTER_IDNUM: - attr_name = ctx->opts->group_map[SDAP_AT_GROUP_GID].name; - break; - default: - ret = EINVAL; - goto fail; - } - - state->filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))", - attr_name, name, - ctx->opts->group_map[SDAP_OC_GROUP].name); - if (!state->filter) { - DEBUG(2, ("Failed to build filter\n")); - ret = ENOMEM; - goto fail; - } - - /* TODO: handle attrs_type */ - ret = build_attrs_from_map(state, ctx->opts->group_map, - SDAP_OPTS_GROUP, &state->attrs); - if (ret != EOK) goto fail; - - if (!sdap_connected(ctx)) { - - if (ctx->gsh) talloc_zfree(ctx->gsh); - - /* FIXME: add option to decide if tls should be used - * or SASL/GSSAPI, etc ... */ - subreq = sdap_cli_connect_send(state, ev, ctx->opts, - ctx->be, ctx->service, - &ctx->rootDSE); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, groups_get_connect_done, req); - - return req; - } - - subreq = sdap_get_groups_send(state, state->ev, - state->domain, state->sysdb, - state->ctx->opts, state->ctx->gsh, - state->attrs, state->filter); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, groups_get_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void groups_get_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct groups_get_state *state = tevent_req_data(req, - struct groups_get_state); - int ret; - - ret = sdap_cli_connect_recv(subreq, state->ctx, - &state->ctx->gsh, &state->ctx->rootDSE); - talloc_zfree(subreq); - if (ret) { - if (ret == ENOTSUP) { - DEBUG(0, ("Authentication mechanism not Supported by server")); - } - tevent_req_error(req, ret); - return; - } - - subreq = sdap_get_groups_send(state, state->ev, - state->domain, state->sysdb, - state->ctx->opts, state->ctx->gsh, - state->attrs, state->filter); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, groups_get_done, req); -} - -static void groups_get_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct groups_get_state *state = tevent_req_data(req, - struct groups_get_state); - char *endptr; - gid_t gid; - int ret; - - ret = sdap_get_groups_recv(subreq, NULL, NULL); - talloc_zfree(subreq); - if (ret && ret != ENOENT) { - tevent_req_error(req, ret); - return; - } - - if (ret == ENOENT) { - if (strchr(state->name, '*')) { - /* it was an enumeration */ - tevent_req_error(req, ret); - return; - } - - switch (state->filter_type) { - case BE_FILTER_NAME: - subreq = sysdb_delete_group_send(state, state->ev, - state->sysdb, NULL, - state->domain, state->name, 0); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, groups_get_delete, req); - return; - - case BE_FILTER_IDNUM: - errno = 0; - gid = (gid_t)strtol(state->name, &endptr, 0); - if (errno || *endptr || (state->name == endptr)) { - tevent_req_error(req, errno); - return; - } - - subreq = sysdb_delete_group_send(state, state->ev, - state->sysdb, NULL, - state->domain, NULL, gid); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, groups_get_delete, req); - return; - - default: - tevent_req_error(req, EINVAL); - return; - } - } - - tevent_req_done(req); -} - -static void groups_get_delete(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct groups_get_state *state = tevent_req_data(req, - struct groups_get_state); - int ret; - - ret = sysdb_delete_group_recv(subreq); - talloc_zfree(subreq); - if (ret) { - DEBUG(2, ("Group (%s) delete returned %d (%s)\n", - state->name, ret, strerror(ret))); - } - - tevent_req_done(req); -} - -int groups_get_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - - -/* =Get-Groups-for-User================================================== */ - -struct groups_by_user_state { - struct tevent_context *ev; - struct sdap_id_ctx *ctx; - const char *name; - const char **attrs; -}; - -static void groups_by_user_connect_done(struct tevent_req *subreq); -static void groups_by_user_done(struct tevent_req *subreq); - -static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx, - const char *name) -{ - struct tevent_req *req, *subreq; - struct groups_by_user_state *state; - int ret; - - req = tevent_req_create(memctx, &state, struct groups_by_user_state); - if (!req) return NULL; - - state->ev = ev; - state->ctx = ctx; - state->name = name; - - ret = build_attrs_from_map(state, ctx->opts->group_map, - SDAP_OPTS_GROUP, &state->attrs); - if (ret != EOK) goto fail; - - if (!sdap_connected(ctx)) { - - if (ctx->gsh) talloc_zfree(ctx->gsh); - - /* FIXME: add option to decide if tls should be used - * or SASL/GSSAPI, etc ... */ - subreq = sdap_cli_connect_send(state, ev, ctx->opts, - ctx->be, ctx->service, - &ctx->rootDSE); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, groups_by_user_connect_done, req); - - return req; - } - - subreq = sdap_get_initgr_send(state, state->ev, - state->ctx->be->domain, - state->ctx->be->sysdb, - state->ctx->opts, state->ctx->gsh, - state->name, state->attrs); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, groups_by_user_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void groups_by_user_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct groups_by_user_state *state = tevent_req_data(req, - struct groups_by_user_state); - int ret; - - ret = sdap_cli_connect_recv(subreq, state->ctx, - &state->ctx->gsh, &state->ctx->rootDSE); - talloc_zfree(subreq); - if (ret) { - if (ret == ENOTSUP) { - DEBUG(0, ("Authentication mechanism not Supported by server")); - } - tevent_req_error(req, ret); - return; - } - - subreq = sdap_get_initgr_send(state, state->ev, - state->ctx->be->domain, - state->ctx->be->sysdb, - state->ctx->opts, state->ctx->gsh, - state->name, state->attrs); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, groups_by_user_done, req); -} - -static void groups_by_user_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - int ret; - - ret = sdap_get_initgr_recv(subreq); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -int groups_by_user_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - - - -/* =Get-Account-Info-Call================================================= */ - -/* FIXME: embed this function in sssd_be and only call out - * specific functions from modules ? */ - -static void sdap_account_info_users_done(struct tevent_req *req); -static void sdap_account_info_groups_done(struct tevent_req *req); -static void sdap_account_info_initgr_done(struct tevent_req *req); - -void sdap_account_info_handler(struct be_req *breq) -{ - struct sdap_id_ctx *ctx; - struct be_acct_req *ar; - struct tevent_req *req; - const char *err = "Unknown Error"; - int ret = EOK; - - ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data, struct sdap_id_ctx); - - if (be_is_offline(ctx->be)) { - return sdap_handler_done(breq, DP_ERR_OFFLINE, EAGAIN, "Offline"); - } - - ar = talloc_get_type(breq->req_data, struct be_acct_req); - - switch (ar->entry_type & 0xFFF) { - case BE_REQ_USER: /* user */ - - /* skip enumerations on demand */ - if (strcmp(ar->filter_value, "*") == 0) { - return sdap_handler_done(breq, DP_ERR_OK, EOK, "Success"); - } - - req = users_get_send(breq, breq->be_ctx->ev, ctx, - ar->filter_value, - ar->filter_type, - ar->attr_type); - if (!req) { - return sdap_handler_done(breq, DP_ERR_FATAL, ENOMEM, "Out of memory"); - } - - tevent_req_set_callback(req, sdap_account_info_users_done, breq); - - break; - - case BE_REQ_GROUP: /* group */ - - if (strcmp(ar->filter_value, "*") == 0) { - return sdap_handler_done(breq, DP_ERR_OK, EOK, "Success"); - } - - /* skip enumerations on demand */ - req = groups_get_send(breq, breq->be_ctx->ev, ctx, - ar->filter_value, - ar->filter_type, - ar->attr_type); - if (!req) { - return sdap_handler_done(breq, DP_ERR_FATAL, ENOMEM, "Out of memory"); - } - - tevent_req_set_callback(req, sdap_account_info_groups_done, breq); - - break; - - case BE_REQ_INITGROUPS: /* init groups for user */ - if (ar->filter_type != BE_FILTER_NAME) { - ret = EINVAL; - err = "Invalid filter type"; - break; - } - if (ar->attr_type != BE_ATTR_CORE) { - ret = EINVAL; - err = "Invalid attr type"; - break; - } - if (strchr(ar->filter_value, '*')) { - ret = EINVAL; - err = "Invalid filter value"; - break; - } - req = groups_by_user_send(breq, breq->be_ctx->ev, ctx, - ar->filter_value); - if (!req) ret = ENOMEM; - /* tevent_req_set_callback(req, groups_by_user_done, breq); */ - - tevent_req_set_callback(req, sdap_account_info_initgr_done, breq); - - break; - - default: /*fail*/ - ret = EINVAL; - err = "Invalid request type"; - } - - if (ret != EOK) return sdap_handler_done(breq, DP_ERR_FATAL, ret, err); -} - -static void sdap_account_info_users_done(struct tevent_req *req) -{ - struct be_req *breq = tevent_req_callback_data(req, struct be_req); - struct sdap_id_ctx *ctx; - int dp_err = DP_ERR_OK; - const char *error = NULL; - int ret; - - ret = users_get_recv(req); - talloc_zfree(req); - - if (ret) { - dp_err = DP_ERR_FATAL; - error = "Enum Users Failed"; - - if (ret == ETIMEDOUT || ret == EFAULT || ret == EIO) { - dp_err = DP_ERR_OFFLINE; - ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data, - struct sdap_id_ctx); - if (sdap_check_gssapi_reconnect(ctx)) { - talloc_zfree(ctx->gsh); - sdap_account_info_handler(breq); - return; - } - sdap_mark_offline(ctx); - } - } - - sdap_handler_done(breq, dp_err, ret, error); -} - -static void sdap_account_info_groups_done(struct tevent_req *req) -{ - struct be_req *breq = tevent_req_callback_data(req, struct be_req); - struct sdap_id_ctx *ctx; - int dp_err = DP_ERR_OK; - const char *error = NULL; - int ret; - - ret = groups_get_recv(req); - talloc_zfree(req); - - if (ret) { - dp_err = DP_ERR_FATAL; - error = "Enum Groups Failed"; - - if (ret == ETIMEDOUT || ret == EFAULT || ret == EIO) { - dp_err = DP_ERR_OFFLINE; - ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data, - struct sdap_id_ctx); - if (sdap_check_gssapi_reconnect(ctx)) { - talloc_zfree(ctx->gsh); - sdap_account_info_handler(breq); - return; - } - sdap_mark_offline(ctx); - } - } - - return sdap_handler_done(breq, dp_err, ret, error); -} - -static void sdap_account_info_initgr_done(struct tevent_req *req) -{ - struct be_req *breq = tevent_req_callback_data(req, struct be_req); - struct sdap_id_ctx *ctx; - int dp_err = DP_ERR_OK; - const char *error = NULL; - int ret; - - ret = groups_by_user_recv(req); - talloc_zfree(req); - - if (ret) { - dp_err = DP_ERR_FATAL; - error = "Init Groups Failed"; - - if (ret == ETIMEDOUT || ret == EFAULT || ret == EIO) { - dp_err = DP_ERR_OFFLINE; - ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data, - struct sdap_id_ctx); - if (sdap_check_gssapi_reconnect(ctx)) { - talloc_zfree(ctx->gsh); - sdap_account_info_handler(breq); - return; - } - sdap_mark_offline(ctx); - } - } - - return sdap_handler_done(breq, dp_err, ret, error); -} - diff --git a/server/providers/ldap/ldap_id_cleanup.c b/server/providers/ldap/ldap_id_cleanup.c deleted file mode 100644 index f3fb4443c..000000000 --- a/server/providers/ldap/ldap_id_cleanup.c +++ /dev/null @@ -1,555 +0,0 @@ -/* - SSSD - - LDAP Identity Cleanup Functions - - Authors: - Simo Sorce - - 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 "util/util.h" -#include "db/sysdb.h" -#include "providers/ldap/ldap_common.h" -#include "providers/ldap/sdap_async.h" - -/* ==Cleanup-Task========================================================= */ - -struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx); -static void ldap_id_cleanup_reschedule(struct tevent_req *req); - -static void ldap_id_cleanup_timeout(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt); - -static void ldap_id_cleanup_timer(struct tevent_context *ev, - struct tevent_timer *tt, - struct timeval tv, void *pvt) -{ - struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx); - struct tevent_timer *timeout; - struct tevent_req *req; - int delay; - - if (be_is_offline(ctx->be)) { - DEBUG(4, ("Backend is marked offline, retry later!\n")); - /* schedule starting from now, not the last run */ - delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT); - tv = tevent_timeval_current_ofs(delay, 0); - ldap_id_cleanup_set_timer(ctx, tv); - return; - } - - req = ldap_id_cleanup_send(ctx, ev, ctx); - if (!req) { - DEBUG(1, ("Failed to schedule cleanup, retrying later!\n")); - /* schedule starting from now, not the last run */ - delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT); - tv = tevent_timeval_current_ofs(delay, 0); - ldap_id_cleanup_set_timer(ctx, tv); - return; - } - tevent_req_set_callback(req, ldap_id_cleanup_reschedule, ctx); - - /* if cleanup takes so long, either we try to cleanup too - * frequently, or something went seriously wrong */ - delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT); - tv = tevent_timeval_current_ofs(delay, 0); - timeout = tevent_add_timer(ctx->be->ev, req, tv, - ldap_id_cleanup_timeout, req); - return; -} - -static void ldap_id_cleanup_timeout(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct sdap_id_ctx *ctx = tevent_req_callback_data(req, - struct sdap_id_ctx); - int delay; - - delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT); - DEBUG(1, ("Cleanup timed out! Timeout too small? (%ds)!\n", delay)); - - tv = tevent_timeval_current_ofs(delay, 0); - ldap_id_enumerate_set_timer(ctx, tv); - - talloc_zfree(req); -} - -static void ldap_id_cleanup_reschedule(struct tevent_req *req) -{ - struct sdap_id_ctx *ctx = tevent_req_callback_data(req, - struct sdap_id_ctx); - enum tevent_req_state tstate; - uint64_t err; - struct timeval tv; - int delay; - - if (tevent_req_is_error(req, &tstate, &err)) { - /* On error schedule starting from now, not the last run */ - tv = tevent_timeval_current(); - } else { - tv = ctx->last_purge; - } - talloc_zfree(req); - - delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT); - tv = tevent_timeval_add(&tv, delay, 0); - ldap_id_enumerate_set_timer(ctx, tv); -} - - - -int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv) -{ - struct tevent_timer *cleanup_task; - - DEBUG(6, ("Scheduling next cleanup at %ld.%ld\n", - (long)tv.tv_sec, (long)tv.tv_usec)); - - cleanup_task = tevent_add_timer(ctx->be->ev, ctx, - tv, ldap_id_cleanup_timer, ctx); - if (!cleanup_task) { - DEBUG(0, ("FATAL: failed to setup cleanup task!\n")); - return EFAULT; - } - - return EOK; -} - - - -struct global_cleanup_state { - struct tevent_context *ev; - struct sdap_id_ctx *ctx; -}; - -static struct tevent_req *cleanup_users_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx); -static void ldap_id_cleanup_users_done(struct tevent_req *subreq); -static struct tevent_req *cleanup_groups_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx); -static void ldap_id_cleanup_groups_done(struct tevent_req *subreq); - -struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx) -{ - struct global_cleanup_state *state; - struct tevent_req *req, *subreq; - - req = tevent_req_create(memctx, &state, struct global_cleanup_state); - if (!req) return NULL; - - state->ev = ev; - state->ctx = ctx; - - subreq = cleanup_users_send(state, ev, ctx); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, ldap_id_cleanup_users_done, req); - - ctx->last_purge = tevent_timeval_current(); - - return req; -} - -static void ldap_id_cleanup_users_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct global_cleanup_state *state = tevent_req_data(req, - struct global_cleanup_state); - enum tevent_req_state tstate; - uint64_t err = 0; - - if (tevent_req_is_error(subreq, &tstate, &err)) { - if (tstate != TEVENT_REQ_USER_ERROR) { - err = EIO; - } - if (err != ENOENT) { - goto fail; - } - } - talloc_zfree(subreq); - - subreq = cleanup_groups_send(state, state->ev, state->ctx); - if (!subreq) { - goto fail; - } - tevent_req_set_callback(subreq, ldap_id_cleanup_groups_done, req); - - return; - -fail: - if (err) { - DEBUG(9, ("User cleanup failed with: (%d)[%s]\n", - (int)err, strerror(err))); - - if (sdap_check_gssapi_reconnect(state->ctx)) { - talloc_zfree(state->ctx->gsh); - subreq = cleanup_users_send(state, state->ev, state->ctx); - if (subreq != NULL) { - tevent_req_set_callback(subreq, ldap_id_cleanup_users_done, req); - return; - } - } - sdap_mark_offline(state->ctx); - } - - DEBUG(1, ("Failed to cleanup users, retrying later!\n")); - tevent_req_done(req); -} - -static void ldap_id_cleanup_groups_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct global_cleanup_state *state = tevent_req_data(req, - struct global_cleanup_state); - enum tevent_req_state tstate; - uint64_t err; - - if (tevent_req_is_error(subreq, &tstate, &err)) { - if (tstate != TEVENT_REQ_USER_ERROR) { - err = EIO; - } - if (err != ENOENT) { - goto fail; - } - } - talloc_zfree(subreq); - - tevent_req_done(req); - return; - -fail: - /* check if credentials are expired otherwise go offline on failures */ - if (sdap_check_gssapi_reconnect(state->ctx)) { - talloc_zfree(state->ctx->gsh); - subreq = cleanup_groups_send(state, state->ev, state->ctx); - if (subreq != NULL) { - tevent_req_set_callback(subreq, ldap_id_cleanup_groups_done, req); - return; - } - } - sdap_mark_offline(state->ctx); - DEBUG(1, ("Failed to cleanup groups (%d [%s]), retrying later!\n", - (int)err, strerror(err))); - tevent_req_done(req); -} - - -/* ==User-Cleanup-Process================================================= */ - -struct cleanup_users_state { - struct tevent_context *ev; - struct sdap_id_ctx *ctx; - struct sysdb_ctx *sysdb; - struct sss_domain_info *domain; - - struct sysdb_handle *handle; - - struct ldb_message **msgs; - size_t count; - int cur; -}; - -static void cleanup_users_process(struct tevent_req *subreq); -static void cleanup_users_update(struct tevent_req *req); -static void cleanup_users_up_done(struct tevent_req *subreq); - -static struct tevent_req *cleanup_users_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx) -{ - struct tevent_req *req, *subreq; - struct cleanup_users_state *state; - static const char *attrs[] = { SYSDB_NAME, NULL }; - time_t now = time(NULL); - char *subfilter; - - req = tevent_req_create(memctx, &state, struct cleanup_users_state); - if (!req) { - return NULL; - } - - state->ev = ev; - state->ctx = ctx; - state->sysdb = ctx->be->sysdb; - state->domain = ctx->be->domain; - state->msgs = NULL; - state->count = 0; - state->cur = 0; - - subfilter = talloc_asprintf(state, "(&(!(%s=0))(%s<=%ld))", - SYSDB_CACHE_EXPIRE, - SYSDB_CACHE_EXPIRE, (long)now); - if (!subfilter) { - DEBUG(2, ("Failed to build filter\n")); - talloc_zfree(req); - return NULL; - } - - subreq = sysdb_search_users_send(state, state->ev, - state->sysdb, NULL, - state->domain, subfilter, attrs); - if (!subreq) { - DEBUG(2, ("Failed to send entry search\n")); - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, cleanup_users_process, req); - - return req; -} - -static void cleanup_users_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct cleanup_users_state *state = tevent_req_data(req, - struct cleanup_users_state); - int ret; - - ret = sysdb_search_users_recv(subreq, state, &state->count, &state->msgs); - talloc_zfree(subreq); - if (ret) { - if (ret == ENOENT) { - tevent_req_done(req); - return; - } - tevent_req_error(req, ret); - return; - } - - DEBUG(4, ("Found %d expired user entries!\n", state->count)); - - if (state->count == 0) { - tevent_req_done(req); - } - - cleanup_users_update(req); -} - -static void cleanup_users_update(struct tevent_req *req) -{ - struct tevent_req *subreq; - struct cleanup_users_state *state = tevent_req_data(req, - struct cleanup_users_state); - const char *str; - - str = ldb_msg_find_attr_as_string(state->msgs[state->cur], - SYSDB_NAME, NULL); - if (!str) { - DEBUG(2, ("Entry %s has no Name Attribute ?!?\n", - ldb_dn_get_linearized(state->msgs[state->cur]->dn))); - tevent_req_error(req, EFAULT); - return; - } - - subreq = users_get_send(state, state->ev, state->ctx, - str, BE_FILTER_NAME, BE_ATTR_CORE); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, cleanup_users_up_done, req); -} - -static void cleanup_users_up_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct cleanup_users_state *state = tevent_req_data(req, - struct cleanup_users_state); - int ret; - - ret = users_get_recv(subreq); - talloc_zfree(subreq); - if (ret) { - DEBUG(2, ("User check returned: %d(%s)\n", - ret, strerror(ret))); - } - - /* if the entry doesn't need to be purged, remove it from the list */ - if (ret != ENOENT) { - talloc_zfree(state->msgs[state->cur]); - } - - state->cur++; - if (state->cur < state->count) { - cleanup_users_update(req); - return; - } - - tevent_req_done(req); -} - -/* ==Group-Cleanup-Process================================================ */ - -struct cleanup_groups_state { - struct tevent_context *ev; - struct sdap_id_ctx *ctx; - struct sysdb_ctx *sysdb; - struct sss_domain_info *domain; - - struct sysdb_handle *handle; - - struct ldb_message **msgs; - size_t count; - int cur; -}; - -static void cleanup_groups_process(struct tevent_req *subreq); -static void cleanup_groups_update(struct tevent_req *req); -static void cleanup_groups_up_done(struct tevent_req *subreq); - -static struct tevent_req *cleanup_groups_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx) -{ - struct tevent_req *req, *subreq; - struct cleanup_groups_state *state; - static const char *attrs[] = { SYSDB_NAME, NULL }; - time_t now = time(NULL); - char *subfilter; - - req = tevent_req_create(memctx, &state, struct cleanup_groups_state); - if (!req) { - return NULL; - } - - state->ev = ev; - state->ctx = ctx; - state->sysdb = ctx->be->sysdb; - state->domain = ctx->be->domain; - state->msgs = NULL; - state->count = 0; - state->cur = 0; - - subfilter = talloc_asprintf(state, "(&(!(%s=0))(%s<=%ld))", - SYSDB_CACHE_EXPIRE, - SYSDB_CACHE_EXPIRE, (long)now); - if (!subfilter) { - DEBUG(2, ("Failed to build filter\n")); - talloc_zfree(req); - return NULL; - } - - subreq = sysdb_search_groups_send(state, state->ev, - state->sysdb, NULL, - state->domain, subfilter, attrs); - if (!subreq) { - DEBUG(2, ("Failed to send entry search\n")); - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, cleanup_groups_process, req); - - return req; -} - -static void cleanup_groups_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct cleanup_groups_state *state = tevent_req_data(req, - struct cleanup_groups_state); - int ret; - - ret = sysdb_search_groups_recv(subreq, state, &state->count, &state->msgs); - talloc_zfree(subreq); - if (ret) { - if (ret == ENOENT) { - tevent_req_done(req); - return; - } - tevent_req_error(req, ret); - return; - } - - DEBUG(4, ("Found %d expired group entries!\n", state->count)); - - if (state->count == 0) { - tevent_req_done(req); - } - - cleanup_groups_update(req); -} - -static void cleanup_groups_update(struct tevent_req *req) -{ - struct tevent_req *subreq; - struct cleanup_groups_state *state = tevent_req_data(req, - struct cleanup_groups_state); - const char *str; - - str = ldb_msg_find_attr_as_string(state->msgs[state->cur], - SYSDB_NAME, NULL); - if (!str) { - DEBUG(2, ("Entry %s has no Name Attribute ?!?\n", - ldb_dn_get_linearized(state->msgs[state->cur]->dn))); - tevent_req_error(req, EFAULT); - return; - } - - subreq = groups_get_send(state, state->ev, state->ctx, - str, BE_FILTER_NAME, BE_ATTR_CORE); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, cleanup_groups_up_done, req); -} - -static void cleanup_groups_up_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct cleanup_groups_state *state = tevent_req_data(req, - struct cleanup_groups_state); - int ret; - - ret = groups_get_recv(subreq); - talloc_zfree(subreq); - if (ret) { - DEBUG(2, ("User check returned: %d(%s)\n", - ret, strerror(ret))); - } - - state->cur++; - if (state->cur < state->count) { - cleanup_groups_update(req); - return; - } - - tevent_req_done(req); -} - diff --git a/server/providers/ldap/ldap_id_enum.c b/server/providers/ldap/ldap_id_enum.c deleted file mode 100644 index bc06e8bdc..000000000 --- a/server/providers/ldap/ldap_id_enum.c +++ /dev/null @@ -1,608 +0,0 @@ -/* - SSSD - - LDAP Identity Enumeration - - Authors: - Simo Sorce - - 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 "util/util.h" -#include "db/sysdb.h" -#include "providers/ldap/ldap_common.h" -#include "providers/ldap/sdap_async.h" - -extern struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx); - -/* ==Enumeration-Task===================================================== */ - -static struct tevent_req *ldap_id_enumerate_send(struct tevent_context *ev, - struct sdap_id_ctx *ctx); - -static void ldap_id_enumerate_reschedule(struct tevent_req *req); - -static void ldap_id_enumerate_timeout(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt); - -static void ldap_id_enumerate_timer(struct tevent_context *ev, - struct tevent_timer *tt, - struct timeval tv, void *pvt) -{ - struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx); - struct tevent_timer *timeout; - struct tevent_req *req; - int delay; - - if (be_is_offline(ctx->be)) { - DEBUG(4, ("Backend is marked offline, retry later!\n")); - /* schedule starting from now, not the last run */ - delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); - tv = tevent_timeval_current_ofs(delay, 0); - ldap_id_enumerate_set_timer(ctx, tv); - return; - } - - req = ldap_id_enumerate_send(ev, ctx); - if (!req) { - DEBUG(1, ("Failed to schedule enumeration, retrying later!\n")); - /* schedule starting from now, not the last run */ - delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); - tv = tevent_timeval_current_ofs(delay, 0); - ldap_id_enumerate_set_timer(ctx, tv); - return; - } - tevent_req_set_callback(req, ldap_id_enumerate_reschedule, ctx); - - /* if enumeration takes so long, either we try to enumerate too - * frequently, or something went seriously wrong */ - delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); - tv = tevent_timeval_current_ofs(delay, 0); - timeout = tevent_add_timer(ctx->be->ev, req, tv, - ldap_id_enumerate_timeout, req); - return; -} - -static void ldap_id_enumerate_timeout(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct sdap_id_ctx *ctx = tevent_req_callback_data(req, - struct sdap_id_ctx); - int delay; - - delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); - DEBUG(1, ("Enumeration timed out! Timeout too small? (%ds)!\n", delay)); - - tv = tevent_timeval_current_ofs(delay, 0); - ldap_id_enumerate_set_timer(ctx, tv); - - talloc_zfree(req); -} - -static void ldap_id_enumerate_reschedule(struct tevent_req *req) -{ - struct sdap_id_ctx *ctx = tevent_req_callback_data(req, - struct sdap_id_ctx); - enum tevent_req_state tstate; - uint64_t err; - struct timeval tv; - int delay; - - if (tevent_req_is_error(req, &tstate, &err)) { - /* On error schedule starting from now, not the last run */ - tv = tevent_timeval_current(); - } else { - tv = ctx->last_enum; - } - talloc_zfree(req); - - delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); - tv = tevent_timeval_add(&tv, delay, 0); - ldap_id_enumerate_set_timer(ctx, tv); -} - - - -int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv) -{ - struct tevent_timer *enum_task; - - DEBUG(6, ("Scheduling next enumeration at %ld.%ld\n", - (long)tv.tv_sec, (long)tv.tv_usec)); - - enum_task = tevent_add_timer(ctx->be->ev, ctx, - tv, ldap_id_enumerate_timer, ctx); - if (!enum_task) { - DEBUG(0, ("FATAL: failed to setup enumeration task!\n")); - return EFAULT; - } - - return EOK; -} - - -struct global_enum_state { - struct tevent_context *ev; - struct sdap_id_ctx *ctx; - - bool purge; -}; - -static struct tevent_req *enum_users_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx, - bool purge); -static void ldap_id_enum_users_done(struct tevent_req *subreq); -static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx, - bool purge); -static void ldap_id_enum_groups_done(struct tevent_req *subreq); -static void ldap_id_enum_cleanup_done(struct tevent_req *subreq); - -static struct tevent_req *ldap_id_enumerate_send(struct tevent_context *ev, - struct sdap_id_ctx *ctx) -{ - struct global_enum_state *state; - struct tevent_req *req, *subreq; - int t; - - req = tevent_req_create(ctx, &state, struct global_enum_state); - if (!req) return NULL; - - state->ev = ev; - state->ctx = ctx; - - ctx->last_enum = tevent_timeval_current(); - - t = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT); - if ((ctx->last_purge.tv_sec + t) < ctx->last_enum.tv_sec) { - state->purge = true; - } else { - state->purge = false; - } - - subreq = enum_users_send(state, ev, ctx, state->purge); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, ldap_id_enum_users_done, req); - - return req; -} - -static void ldap_id_enum_users_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct global_enum_state *state = tevent_req_data(req, - struct global_enum_state); - enum tevent_req_state tstate; - uint64_t err = 0; - - if (tevent_req_is_error(subreq, &tstate, &err)) { - if (tstate != TEVENT_REQ_USER_ERROR) { - err = EIO; - } - if (err != ENOENT) { - goto fail; - } - } - talloc_zfree(subreq); - - subreq = enum_groups_send(state, state->ev, state->ctx, state->purge); - if (!subreq) { - goto fail; - } - tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req); - - return; - -fail: - if (err) { - DEBUG(9, ("User enumeration failed with: (%d)[%s]\n", - (int)err, strerror(err))); - - if (sdap_check_gssapi_reconnect(state->ctx)) { - talloc_zfree(state->ctx->gsh); - subreq = enum_users_send(state, state->ev, state->ctx, state->purge); - if (subreq != NULL) { - tevent_req_set_callback(subreq, ldap_id_enum_users_done, req); - return; - } - } - sdap_mark_offline(state->ctx); - } - - DEBUG(1, ("Failed to enumerate users, retrying later!\n")); - tevent_req_done(req); -} - -static void ldap_id_enum_groups_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct global_enum_state *state = tevent_req_data(req, - struct global_enum_state); - enum tevent_req_state tstate; - uint64_t err = 0; - - if (tevent_req_is_error(subreq, &tstate, &err)) { - if (tstate != TEVENT_REQ_USER_ERROR) { - err = EIO; - } - if (err != ENOENT) { - goto fail; - } - } - talloc_zfree(subreq); - - if (state->purge) { - - subreq = ldap_id_cleanup_send(state, state->ev, state->ctx); - if (!subreq) { - goto fail; - } - tevent_req_set_callback(subreq, ldap_id_enum_cleanup_done, req); - - return; - } - - tevent_req_done(req); - return; - -fail: - /* check if credentials are expired otherwise go offline on failures */ - if (sdap_check_gssapi_reconnect(state->ctx)) { - talloc_zfree(state->ctx->gsh); - subreq = enum_groups_send(state, state->ev, state->ctx, state->purge); - if (subreq != NULL) { - tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req); - return; - } - } - sdap_mark_offline(state->ctx); - DEBUG(1, ("Failed to enumerate groups (%d [%s]), retrying later!\n", - (int)err, strerror(err))); - tevent_req_done(req); -} - -static void ldap_id_enum_cleanup_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - talloc_zfree(subreq); - tevent_req_done(req); -} - - -/* ==User-Enumeration===================================================== */ - -struct enum_users_state { - struct tevent_context *ev; - struct sdap_id_ctx *ctx; - - char *filter; - const char **attrs; -}; - -static void enum_users_connect_done(struct tevent_req *subreq); -static void enum_users_op_done(struct tevent_req *subreq); - -static struct tevent_req *enum_users_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx, - bool purge) -{ - struct tevent_req *req, *subreq; - struct enum_users_state *state; - int ret; - - req = tevent_req_create(memctx, &state, struct enum_users_state); - if (!req) return NULL; - - state->ev = ev; - state->ctx = ctx; - - if (ctx->max_user_timestamp && !purge) { - - state->filter = talloc_asprintf(state, - "(&(%s=*)(objectclass=%s)(%s>=%s)(!(%s=%s)))", - ctx->opts->user_map[SDAP_AT_USER_NAME].name, - ctx->opts->user_map[SDAP_OC_USER].name, - ctx->opts->user_map[SDAP_AT_USER_MODSTAMP].name, - ctx->max_user_timestamp, - ctx->opts->user_map[SDAP_AT_USER_MODSTAMP].name, - ctx->max_user_timestamp); - } else { - state->filter = talloc_asprintf(state, - "(&(%s=*)(objectclass=%s))", - ctx->opts->user_map[SDAP_AT_USER_NAME].name, - ctx->opts->user_map[SDAP_OC_USER].name); - } - if (!state->filter) { - DEBUG(2, ("Failed to build filter\n")); - ret = ENOMEM; - goto fail; - } - - /* TODO: handle attrs_type */ - ret = build_attrs_from_map(state, ctx->opts->user_map, - SDAP_OPTS_USER, &state->attrs); - if (ret != EOK) goto fail; - - if (!sdap_connected(ctx)) { - - if (ctx->gsh) talloc_zfree(ctx->gsh); - - /* FIXME: add option to decide if tls should be used - * or SASL/GSSAPI, etc ... */ - subreq = sdap_cli_connect_send(state, ev, ctx->opts, - ctx->be, ctx->service, - &ctx->rootDSE); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, enum_users_connect_done, req); - - return req; - } - - subreq = sdap_get_users_send(state, state->ev, - state->ctx->be->domain, - state->ctx->be->sysdb, - state->ctx->opts, - state->ctx->gsh, - state->attrs, state->filter); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, enum_users_op_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void enum_users_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct enum_users_state *state = tevent_req_data(req, - struct enum_users_state); - int ret; - - ret = sdap_cli_connect_recv(subreq, state->ctx, - &state->ctx->gsh, &state->ctx->rootDSE); - talloc_zfree(subreq); - if (ret) { - if (ret == ENOTSUP) { - DEBUG(0, ("Authentication mechanism not Supported by server")); - } - tevent_req_error(req, ret); - return; - } - - subreq = sdap_get_users_send(state, state->ev, - state->ctx->be->domain, - state->ctx->be->sysdb, - state->ctx->opts, state->ctx->gsh, - state->attrs, state->filter); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, enum_users_op_done, req); -} - -static void enum_users_op_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct enum_users_state *state = tevent_req_data(req, - struct enum_users_state); - char *timestamp; - int ret; - - ret = sdap_get_users_recv(subreq, state, ×tamp); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - if (timestamp) { - talloc_zfree(state->ctx->max_user_timestamp); - state->ctx->max_user_timestamp = talloc_steal(state->ctx, timestamp); - } - - DEBUG(4, ("Users higher timestamp: [%s]\n", - state->ctx->max_user_timestamp)); - - tevent_req_done(req); -} - -/* =Group-Enumeration===================================================== */ - -struct enum_groups_state { - struct tevent_context *ev; - struct sdap_id_ctx *ctx; - - char *filter; - const char **attrs; -}; - -static void enum_groups_connect_done(struct tevent_req *subreq); -static void enum_groups_op_done(struct tevent_req *subreq); - -static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_id_ctx *ctx, - bool purge) -{ - struct tevent_req *req, *subreq; - struct enum_groups_state *state; - const char *attr_name; - int ret; - - req = tevent_req_create(memctx, &state, struct enum_groups_state); - if (!req) return NULL; - - state->ev = ev; - state->ctx = ctx; - - attr_name = ctx->opts->group_map[SDAP_AT_GROUP_NAME].name; - - if (ctx->max_group_timestamp && !purge) { - - state->filter = talloc_asprintf(state, - "(&(%s=*)(objectclass=%s)(%s>=%s)(!(%s=%s)))", - ctx->opts->group_map[SDAP_AT_GROUP_NAME].name, - ctx->opts->group_map[SDAP_OC_GROUP].name, - ctx->opts->group_map[SDAP_AT_GROUP_MODSTAMP].name, - ctx->max_group_timestamp, - ctx->opts->group_map[SDAP_AT_GROUP_MODSTAMP].name, - ctx->max_group_timestamp); - } else { - state->filter = talloc_asprintf(state, - "(&(%s=*)(objectclass=%s))", - ctx->opts->group_map[SDAP_AT_GROUP_NAME].name, - ctx->opts->group_map[SDAP_OC_GROUP].name); - } - if (!state->filter) { - DEBUG(2, ("Failed to build filter\n")); - ret = ENOMEM; - goto fail; - } - - /* TODO: handle attrs_type */ - ret = build_attrs_from_map(state, ctx->opts->group_map, - SDAP_OPTS_GROUP, &state->attrs); - if (ret != EOK) goto fail; - - if (!sdap_connected(ctx)) { - - if (ctx->gsh) talloc_zfree(ctx->gsh); - - /* FIXME: add option to decide if tls should be used - * or SASL/GSSAPI, etc ... */ - subreq = sdap_cli_connect_send(state, ev, ctx->opts, - ctx->be, ctx->service, - &ctx->rootDSE); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, enum_groups_connect_done, req); - - return req; - } - - subreq = sdap_get_groups_send(state, state->ev, - state->ctx->be->domain, - state->ctx->be->sysdb, - state->ctx->opts, state->ctx->gsh, - state->attrs, state->filter); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, enum_groups_op_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void enum_groups_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct enum_groups_state *state = tevent_req_data(req, - struct enum_groups_state); - int ret; - - ret = sdap_cli_connect_recv(subreq, state->ctx, - &state->ctx->gsh, &state->ctx->rootDSE); - talloc_zfree(subreq); - if (ret) { - if (ret == ENOTSUP) { - DEBUG(0, ("Authentication mechanism not Supported by server")); - } - tevent_req_error(req, ret); - return; - } - - subreq = sdap_get_groups_send(state, state->ev, - state->ctx->be->domain, - state->ctx->be->sysdb, - state->ctx->opts, state->ctx->gsh, - state->attrs, state->filter); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, enum_groups_op_done, req); -} - -static void enum_groups_op_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct enum_groups_state *state = tevent_req_data(req, - struct enum_groups_state); - char *timestamp; - int ret; - - ret = sdap_get_groups_recv(subreq, state, ×tamp); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - if (timestamp) { - talloc_zfree(state->ctx->max_group_timestamp); - state->ctx->max_group_timestamp = talloc_steal(state->ctx, timestamp); - } - - DEBUG(4, ("Groups higher timestamp: [%s]\n", - state->ctx->max_group_timestamp)); - - tevent_req_done(req); -} - diff --git a/server/providers/ldap/ldap_init.c b/server/providers/ldap/ldap_init.c deleted file mode 100644 index b1f053fbc..000000000 --- a/server/providers/ldap/ldap_init.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - SSSD - - LDAP Provider Initialization functions - - Authors: - Simo Sorce - - 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 "providers/child_common.h" -#include "providers/ldap/ldap_common.h" -#include "providers/ldap/sdap_async_private.h" - -static void sdap_shutdown(struct be_req *req); - -/* Id Handler */ -struct bet_ops sdap_id_ops = { - .handler = sdap_account_info_handler, - .finalize = sdap_shutdown -}; - -/* Auth Handler */ -struct bet_ops sdap_auth_ops = { - .handler = sdap_pam_auth_handler, - .finalize = sdap_shutdown -}; - -/* Chpass Handler */ -struct bet_ops sdap_chpass_ops = { - .handler = sdap_pam_chpass_handler, - .finalize = sdap_shutdown -}; - -int sssm_ldap_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) -{ - struct sdap_id_ctx *ctx; - const char *urls; - int ret; - - ctx = talloc_zero(bectx, struct sdap_id_ctx); - if (!ctx) return ENOMEM; - - ctx->be = bectx; - - ret = ldap_get_options(ctx, bectx->cdb, - bectx->conf_path, &ctx->opts); - if (ret != EOK) { - goto done; - } - - urls = dp_opt_get_string(ctx->opts->basic, SDAP_URI); - if (!urls) { - DEBUG(0, ("Missing ldap_uri\n")); - ret = EINVAL; - goto done; - } - - ret = sdap_service_init(ctx, ctx->be, "LDAP", urls, &ctx->service); - if (ret != EOK) { - DEBUG(1, ("Failed to initialize failover service!\n")); - goto done; - } - - ret = setup_tls_config(ctx->opts->basic); - if (ret != EOK) { - DEBUG(1, ("setup_tls_config failed [%d][%s].\n", - ret, strerror(ret))); - goto done; - } - - ret = sdap_id_setup_tasks(ctx); - if (ret != EOK) { - goto done; - } - - ret = setup_child(ctx); - if (ret != EOK) { - DEBUG(1, ("setup_child failed [%d][%s].\n", - ret, strerror(ret))); - goto done; - } - - *ops = &sdap_id_ops; - *pvt_data = ctx; - ret = EOK; - -done: - if (ret != EOK) { - talloc_free(ctx); - } - return ret; -} - -int sssm_ldap_auth_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) -{ - struct sdap_auth_ctx *ctx; - const char *urls; - int ret; - - ctx = talloc(bectx, struct sdap_auth_ctx); - if (!ctx) return ENOMEM; - - ctx->be = bectx; - - ret = ldap_get_options(ctx, bectx->cdb, - bectx->conf_path, &ctx->opts); - if (ret != EOK) { - goto done; - } - - urls = dp_opt_get_string(ctx->opts->basic, SDAP_URI); - if (!urls) { - DEBUG(0, ("Missing ldap_uri\n")); - ret = EINVAL; - goto done; - } - - ret = sdap_service_init(ctx, ctx->be, "LDAP", urls, &ctx->service); - if (ret != EOK) { - DEBUG(1, ("Failed to initialize failover service!\n")); - goto done; - } - - ret = setup_tls_config(ctx->opts->basic); - if (ret != EOK) { - DEBUG(1, ("setup_tls_config failed [%d][%s].\n", - ret, strerror(ret))); - goto done; - } - - *ops = &sdap_auth_ops; - *pvt_data = ctx; - ret = EOK; - -done: - if (ret != EOK) { - talloc_free(ctx); - } - return ret; -} - -int sssm_ldap_chpass_init(struct be_ctx *bectx, - struct bet_ops **ops, - void **pvt_data) -{ - int ret; - - ret = sssm_ldap_auth_init(bectx, ops, pvt_data); - - *ops = &sdap_chpass_ops; - - return ret; -} - -static void sdap_shutdown(struct be_req *req) -{ - /* TODO: Clean up any internal data */ - sdap_handler_done(req, DP_ERR_OK, EOK, NULL); -} - diff --git a/server/providers/ldap/sdap.c b/server/providers/ldap/sdap.c deleted file mode 100644 index 39c67cc92..000000000 --- a/server/providers/ldap/sdap.c +++ /dev/null @@ -1,388 +0,0 @@ -/* - SSSD - - LDAP Helper routines - - Copyright (C) Simo Sorce - - 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 . -*/ - -#define LDAP_DEPRECATED 1 -#include "util/util.h" -#include "confdb/confdb.h" -#include "providers/ldap/sdap.h" - -/* =Retrieve-Options====================================================== */ - -int sdap_get_map(TALLOC_CTX *memctx, - struct confdb_ctx *cdb, - const char *conf_path, - struct sdap_attr_map *def_map, - int num_entries, - struct sdap_attr_map **_map) -{ - struct sdap_attr_map *map; - int i, ret; - - map = talloc_array(memctx, struct sdap_attr_map, num_entries); - if (!map) { - return ENOMEM; - } - - for (i = 0; i < num_entries; i++) { - - map[i].opt_name = def_map[i].opt_name; - map[i].def_name = def_map[i].def_name; - map[i].sys_name = def_map[i].sys_name; - - ret = confdb_get_string(cdb, map, conf_path, - map[i].opt_name, - map[i].def_name, - &map[i].name); - if ((ret != EOK) || (map[i].def_name && !map[i].name)) { - DEBUG(0, ("Failed to retrieve value for %s\n", map[i].opt_name)); - if (ret != EOK) { - talloc_zfree(map); - return EINVAL; - } - } - - DEBUG(5, ("Option %s has value %s\n", map[i].opt_name, map[i].name)); - } - - *_map = map; - return EOK; -} - -/* =Parse-msg============================================================= */ - -int sdap_parse_entry(TALLOC_CTX *memctx, - struct sdap_handle *sh, struct sdap_msg *sm, - struct sdap_attr_map *map, int attrs_num, - struct sysdb_attrs **_attrs, char **_dn) -{ - struct sysdb_attrs *attrs; - BerElement *ber = NULL; - struct berval **vals; - struct ldb_val v; - char *str; - int lerrno; - int a, i, ret; - const char *name; - bool store; - - lerrno = 0; - ldap_set_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); - - attrs = sysdb_new_attrs(memctx); - if (!attrs) return ENOMEM; - - str = ldap_get_dn(sh->ldap, sm->msg); - if (!str) { - ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); - DEBUG(1, ("ldap_get_dn failed: %d(%s)\n", - lerrno, ldap_err2string(lerrno))); - ret = EIO; - goto fail; - } - - DEBUG(9, ("OriginalDN: [%s].\n", str)); - ret = sysdb_attrs_add_string(attrs, SYSDB_ORIG_DN, str); - if (ret) goto fail; - if (_dn) { - *_dn = talloc_strdup(memctx, str); - if (!*_dn) { - ret = ENOMEM; - ldap_memfree(str); - goto fail; - } - } - ldap_memfree(str); - - if (map) { - vals = ldap_get_values_len(sh->ldap, sm->msg, "objectClass"); - if (!vals) { - DEBUG(1, ("Unknown entry type, no objectClasses found!\n")); - ret = EINVAL; - goto fail; - } - - for (i = 0; vals[i]; i++) { - /* the objectclass is always the first name in the map */ - if (strncasecmp(map[0].name, - vals[i]->bv_val, vals[i]->bv_len) == 0) { - /* ok it's an entry of the right type */ - break; - } - } - if (!vals[i]) { - DEBUG(1, ("objectClass not matching: %s\n", - map[0].name)); - ldap_value_free_len(vals); - ret = EINVAL; - goto fail; - } - ldap_value_free_len(vals); - } - - str = ldap_first_attribute(sh->ldap, sm->msg, &ber); - if (!str) { - ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); - DEBUG(1, ("Entry has no attributes [%d(%s)]!?\n", - lerrno, ldap_err2string(lerrno))); - if (map) { - ret = EINVAL; - goto fail; - } - } - while (str) { - if (map) { - for (a = 1; a < attrs_num; a++) { - /* check if this attr is valid with the chosen schema */ - if (!map[a].name) continue; - /* check if it is an attr we are interested in */ - if (strcasecmp(str, map[a].name) == 0) break; - } - /* interesting attr */ - if (a < attrs_num) { - store = true; - name = map[a].sys_name; - } else { - store = false; - } - } else { - name = str; - store = true; - } - - if (store) { - vals = ldap_get_values_len(sh->ldap, sm->msg, str); - if (!vals) { - ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); - DEBUG(1, ("LDAP Library error: %d(%s)", - lerrno, ldap_err2string(lerrno))); - ret = EIO; - goto fail; - } - if (!vals[0]) { - DEBUG(1, ("Missing value after ldap_get_values() ??\n")); - ret = EINVAL; - goto fail; - } - for (i = 0; vals[i]; i++) { - v.data = (uint8_t *)vals[i]->bv_val; - v.length = vals[i]->bv_len; - - ret = sysdb_attrs_add_val(attrs, name, &v); - if (ret) goto fail; - } - ldap_value_free_len(vals); - } - - ldap_memfree(str); - str = ldap_next_attribute(sh->ldap, sm->msg, ber); - } - ber_free(ber, 0); - - ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); - if (lerrno) { - DEBUG(1, ("LDAP Library error: %d(%s)", - lerrno, ldap_err2string(lerrno))); - ret = EIO; - goto fail; - } - - *_attrs = attrs; - return EOK; - -fail: - if (ber) ber_free(ber, 0); - talloc_free(attrs); - return ret; -} - -/* This function converts an ldap message into a sysdb_attrs structure. - * It converts only known user attributes, the rest are ignored. - * If the entry is not that of an user an error is returned. - * The original DN is stored as an attribute named originalDN */ - -int sdap_parse_user(TALLOC_CTX *memctx, struct sdap_options *opts, - struct sdap_handle *sh, struct sdap_msg *sm, - struct sysdb_attrs **_attrs, char **_dn) -{ - - return sdap_parse_entry(memctx, sh, sm, opts->user_map, - SDAP_OPTS_USER, _attrs, _dn); -} - -/* This function converts an ldap message into a sysdb_attrs structure. - * It converts only known group attributes, the rest are ignored. - * If the entry is not that of an user an error is returned. - * The original DN is stored as an attribute named originalDN */ - -int sdap_parse_group(TALLOC_CTX *memctx, struct sdap_options *opts, - struct sdap_handle *sh, struct sdap_msg *sm, - struct sysdb_attrs **_attrs, char **_dn) -{ - - return sdap_parse_entry(memctx, sh, sm, opts->group_map, - SDAP_OPTS_GROUP, _attrs, _dn); -} - -/* =Get-DN-from-message=================================================== */ - -int sdap_get_msg_dn(TALLOC_CTX *memctx, struct sdap_handle *sh, - struct sdap_msg *sm, char **_dn) -{ - char *str; - int lerrno; - - lerrno = 0; - ldap_set_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); - - str = ldap_get_dn(sh->ldap, sm->msg); - if (!str) { - ldap_get_option(sh->ldap, LDAP_OPT_RESULT_CODE, &lerrno); - DEBUG(1, ("ldap_get_dn failed: %d(%s)\n", - lerrno, ldap_err2string(lerrno))); - return EIO; - } - - *_dn = talloc_strdup(memctx, str); - ldap_memfree(str); - if (!*_dn) return ENOMEM; - - return EOK; -} - -errno_t setup_tls_config(struct dp_option *basic_opts) -{ - int ret; - int ldap_opt_x_tls_require_cert; - const char *tls_opt; - tls_opt = dp_opt_get_string(basic_opts, SDAP_TLS_REQCERT); - if (tls_opt) { - if (strcasecmp(tls_opt, "never") == 0) { - ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_NEVER; - } - else if (strcasecmp(tls_opt, "allow") == 0) { - ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_ALLOW; - } - else if (strcasecmp(tls_opt, "try") == 0) { - ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_TRY; - } - else if (strcasecmp(tls_opt, "demand") == 0) { - ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_DEMAND; - } - else if (strcasecmp(tls_opt, "hard") == 0) { - ldap_opt_x_tls_require_cert = LDAP_OPT_X_TLS_HARD; - } - else { - DEBUG(1, ("Unknown value for tls_reqcert.\n")); - return EINVAL; - } - /* LDAP_OPT_X_TLS_REQUIRE_CERT has to be set as a global option, - * because the SSL/TLS context is initialized from this value. */ - ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, - &ldap_opt_x_tls_require_cert); - if (ret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("ldap_set_option failed: %s\n", ldap_err2string(ret))); - return EIO; - } - } - - tls_opt = dp_opt_get_string(basic_opts, SDAP_TLS_CACERT); - if (tls_opt) { - ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, tls_opt); - if (ret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("ldap_set_option failed: %s\n", ldap_err2string(ret))); - return EIO; - } - } - - tls_opt = dp_opt_get_string(basic_opts, SDAP_TLS_CACERTDIR); - if (tls_opt) { - ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTDIR, tls_opt); - if (ret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("ldap_set_option failed: %s\n", ldap_err2string(ret))); - return EIO; - } - } - - return EOK; -} - - -bool sdap_rootdse_sasl_mech_is_supported(struct sysdb_attrs *rootdse, - const char *sasl_mech) -{ - struct ldb_message_element *el = NULL; - struct ldb_val *val; - int i; - - if (!sasl_mech) return false; - - for (i = 0; i < rootdse->num; i++) { - if (strcasecmp(rootdse->a[i].name, "supportedSASLMechanisms")) { - continue; - } - el = &rootdse->a[i]; - break; - } - - if (!el) { - /* no supported SASL Mechanism at all ? */ - return false; - } - - for (i = 0; i < el->num_values; i++) { - val = &el->values[i]; - if (strncasecmp(sasl_mech, (const char *)val->data, val->length)) { - continue; - } - return true; - } - - return false; -} - -int build_attrs_from_map(TALLOC_CTX *memctx, - struct sdap_attr_map *map, - size_t size, const char ***_attrs) -{ - char **attrs; - int i, j; - - attrs = talloc_array(memctx, char *, size + 1); - if (!attrs) return ENOMEM; - - /* first attribute is "objectclass" not the specifc one */ - attrs[0] = talloc_strdup(memctx, "objectClass"); - if (!attrs[0]) return ENOMEM; - - /* add the others */ - for (i = j = 1; i < size; i++) { - if (map[i].name) { - attrs[j] = map[i].name; - j++; - } - } - attrs[j] = NULL; - - *_attrs = (const char **)attrs; - - return EOK; -} - diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h deleted file mode 100644 index 16dbb7843..000000000 --- a/server/providers/ldap/sdap.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - SSSD - - LDAP Helper routines - - Copyright (C) Simo Sorce - - 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 _SDAP_H_ -#define _SDAP_H_ - -#include "providers/dp_backend.h" -#include -#include "util/sss_ldap.h" - -struct sdap_msg { - struct sdap_msg *next; - LDAPMessage *msg; -}; - -struct sdap_op; - -typedef void (sdap_op_callback_t)(struct sdap_op *op, - struct sdap_msg *, int, void *); - -struct sdap_handle; - -struct sdap_op { - struct sdap_op *prev, *next; - struct sdap_handle *sh; - - int msgid; - bool done; - - sdap_op_callback_t *callback; - void *data; - - struct tevent_context *ev; - struct sdap_msg *list; - struct sdap_msg *last; -}; - -struct fd_event_item { - struct fd_event_item *prev; - struct fd_event_item *next; - - int fd; - struct tevent_fd *fde; -}; - -struct ldap_cb_data { - struct sdap_handle *sh; - struct tevent_context *ev; - struct fd_event_item *fd_list; -}; - -struct sdap_handle { - LDAP *ldap; - bool connected; - -#ifdef HAVE_LDAP_CONNCB - struct ldap_conncb *conncb; -#else - struct tevent_fd *fde; -#endif - - struct sdap_op *ops; -}; - -struct sdap_service { - char *name; - char *uri; -}; - -#define SYSDB_SHADOWPW_LASTCHANGE "shadowLastChange" -#define SYSDB_SHADOWPW_MIN "shadowMin" -#define SYSDB_SHADOWPW_MAX "shadowMax" -#define SYSDB_SHADOWPW_WARNING "shadowWarning" -#define SYSDB_SHADOWPW_INACTIVE "shadowInactive" -#define SYSDB_SHADOWPW_EXPIRE "shadowExpire" -#define SYSDB_SHADOWPW_FLAG "shadowFlag" - -#define SYSDB_KRBPW_LASTCHANGE "krbLastPwdChange" -#define SYSDB_KRBPW_EXPIRATION "krbPasswordExpiration" - -#define SYSDB_PWD_ATTRIBUTE "pwdAttribute" - -enum sdap_result { - SDAP_SUCCESS, - SDAP_NOT_FOUND, - SDAP_UNAVAIL, - SDAP_RETRY, - SDAP_ERROR, - SDAP_AUTH_SUCCESS, - SDAP_AUTH_FAILED, - SDAP_AUTH_PW_EXPIRED, - SDAP_ACCT_EXPIRED -}; - -enum sdap_basic_opt { - SDAP_URI = 0, - SDAP_SEARCH_BASE, - SDAP_DEFAULT_BIND_DN, - SDAP_DEFAULT_AUTHTOK_TYPE, - SDAP_DEFAULT_AUTHTOK, - SDAP_SEARCH_TIMEOUT, - SDAP_NETWORK_TIMEOUT, - SDAP_OPT_TIMEOUT, - SDAP_TLS_REQCERT, - SDAP_USER_SEARCH_BASE, - SDAP_USER_SEARCH_SCOPE, - SDAP_USER_SEARCH_FILTER, - SDAP_GROUP_SEARCH_BASE, - SDAP_GROUP_SEARCH_SCOPE, - SDAP_GROUP_SEARCH_FILTER, - SDAP_SCHEMA, - SDAP_OFFLINE_TIMEOUT, - SDAP_FORCE_UPPER_CASE_REALM, - SDAP_ENUM_REFRESH_TIMEOUT, - SDAP_CACHE_PURGE_TIMEOUT, - SDAP_ENTRY_CACHE_TIMEOUT, - SDAP_TLS_CACERT, - SDAP_TLS_CACERTDIR, - SDAP_ID_TLS, - SDAP_SASL_MECH, - SDAP_SASL_AUTHID, - SDAP_KRB5_KEYTAB, - SDAP_KRB5_KINIT, - SDAP_KRB5_REALM, - SDAP_PWD_POLICY, - SDAP_REFERRALS, - - SDAP_OPTS_BASIC /* opts counter */ -}; - -enum sdap_gen_attrs { - SDAP_AT_ENTRY_USN = 0, - SDAP_AT_LAST_USN, - - SDAP_AT_GENERAL /* attrs counter */ -}; - -/* the objectclass must be the first attribute. - * Functions depend on this */ -enum sdap_user_attrs { - SDAP_OC_USER = 0, - SDAP_AT_USER_NAME, - SDAP_AT_USER_PWD, - SDAP_AT_USER_UID, - SDAP_AT_USER_GID, - SDAP_AT_USER_GECOS, - SDAP_AT_USER_HOME, - SDAP_AT_USER_SHELL, - SDAP_AT_USER_PRINC, - SDAP_AT_USER_FULLNAME, - SDAP_AT_USER_MEMBEROF, - SDAP_AT_USER_UUID, - SDAP_AT_USER_MODSTAMP, - SDAP_AT_SP_LSTCHG, - SDAP_AT_SP_MIN, - SDAP_AT_SP_MAX, - SDAP_AT_SP_WARN, - SDAP_AT_SP_INACT, - SDAP_AT_SP_EXPIRE, - SDAP_AT_SP_FLAG, - SDAP_AT_KP_LASTCHANGE, - SDAP_AT_KP_EXPIRATION, - SDAP_AT_PWD_ATTRIBUTE, - - SDAP_OPTS_USER /* attrs counter */ -}; - -#define SDAP_FIRST_EXTRA_USER_AT SDAP_AT_SP_LSTCHG - -/* the objectclass must be the first attribute. - * Functions depend on this */ -enum sdap_group_attrs { - SDAP_OC_GROUP = 0, - SDAP_AT_GROUP_NAME, - SDAP_AT_GROUP_PWD, - SDAP_AT_GROUP_GID, - SDAP_AT_GROUP_MEMBER, - SDAP_AT_GROUP_UUID, - SDAP_AT_GROUP_MODSTAMP, - - SDAP_OPTS_GROUP /* attrs counter */ -}; - -struct sdap_attr_map { - const char *opt_name; - const char *def_name; - const char *sys_name; - char *name; -}; - -struct sdap_options { - struct dp_option *basic; - struct sdap_attr_map *gen_map; - struct sdap_attr_map *user_map; - struct sdap_attr_map *group_map; - - /* supported schema types */ - enum schema_type { - SDAP_SCHEMA_RFC2307 = 1, /* memberUid = uid */ - SDAP_SCHEMA_RFC2307BIS = 2, /* member = dn */ - SDAP_SCHEMA_IPA_V1 = 3, /* member/memberof */ - SDAP_SCHEMA_AD = 4 /* AD's member/memberof */ - } schema_type; - - struct ldb_dn *users_base; - struct ldb_dn *groups_base; -}; - -int sdap_get_map(TALLOC_CTX *memctx, - struct confdb_ctx *cdb, - const char *conf_path, - struct sdap_attr_map *def_map, - int num_entries, - struct sdap_attr_map **_map); - -int sdap_parse_entry(TALLOC_CTX *memctx, - struct sdap_handle *sh, struct sdap_msg *sm, - struct sdap_attr_map *map, int attrs_num, - struct sysdb_attrs **_attrs, char **_dn); - -int sdap_parse_user(TALLOC_CTX *memctx, struct sdap_options *opts, - struct sdap_handle *sh, struct sdap_msg *sm, - struct sysdb_attrs **_attrs, char **_dn); - -int sdap_parse_group(TALLOC_CTX *memctx, struct sdap_options *opts, - struct sdap_handle *sh, struct sdap_msg *sm, - struct sysdb_attrs **_attrs, char **_dn); - -int sdap_get_msg_dn(TALLOC_CTX *memctx, struct sdap_handle *sh, - struct sdap_msg *sm, char **_dn); - -errno_t setup_tls_config(struct dp_option *basic_opts); - -bool sdap_rootdse_sasl_mech_is_supported(struct sysdb_attrs *rootdse, - const char *sasl_mech); - -int build_attrs_from_map(TALLOC_CTX *memctx, - struct sdap_attr_map *map, - size_t size, const char ***_attrs); -#endif /* _SDAP_H_ */ diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c deleted file mode 100644 index 959c08a65..000000000 --- a/server/providers/ldap/sdap_async.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* - SSSD - - Async LDAP Helper routines - - Copyright (C) Simo Sorce - 2009 - - 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 "util/util.h" -#include "providers/ldap/sdap_async_private.h" - -#define REALM_SEPARATOR '@' -#define REPLY_REALLOC_INCREMENT 10 - -void make_realm_upper_case(const char *upn) -{ - char *c; - - c = strchr(upn, REALM_SEPARATOR); - if (c == NULL) { - DEBUG(9, ("No realm delimiter found in upn [%s].\n", upn)); - return; - } - - while(*(++c) != '\0') { - c[0] = toupper(*c); - } - - return; -} - -/* ==LDAP-Memory-Handling================================================= */ - -static int lmsg_destructor(void *mem) -{ - ldap_msgfree((LDAPMessage *)mem); - return 0; -} - -static int sdap_msg_attach(TALLOC_CTX *memctx, LDAPMessage *msg) -{ - void *h; - - if (!msg) return EINVAL; - - h = sss_mem_attach(memctx, msg, lmsg_destructor); - if (!h) return ENOMEM; - - return EOK; -} - -/* ==sdap-hanlde-utility-functions======================================== */ - -static inline void sdap_handle_release(struct sdap_handle *sh); -static int sdap_handle_destructor(void *mem); - -struct sdap_handle *sdap_handle_create(TALLOC_CTX *memctx) -{ - struct sdap_handle *sh; - - sh = talloc_zero(memctx, struct sdap_handle); - if (!sh) return NULL; - - talloc_set_destructor((TALLOC_CTX *)sh, sdap_handle_destructor); - - return sh; -} - -static int sdap_handle_destructor(void *mem) -{ - struct sdap_handle *sh = talloc_get_type(mem, struct sdap_handle); - - sdap_handle_release(sh); - - return 0; -} - -static void sdap_handle_release(struct sdap_handle *sh) -{ - DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], ldap[%p]\n", - sh, (int)sh->connected, sh->ops, sh->ldap)); - - if (sh->connected) { - struct sdap_op *op; - -#ifdef HAVE_LDAP_CONNCB - /* remove all related fd events from the event loop */ - talloc_zfree(sh->conncb->lc_arg); -#else - talloc_zfree(sh->fde); -#endif - - while (sh->ops) { - op = sh->ops; - op->callback(op, NULL, EIO, op->data); - /* calling the callback may result in freeing the op */ - /* check if it is still the same or avoid freeing */ - if (op == sh->ops) talloc_free(op); - } - - if (sh->ldap) { - ldap_unbind_ext(sh->ldap, NULL, NULL); - } -#ifdef HAVE_LDAP_CONNCB - talloc_zfree(sh->conncb); -#endif - sh->connected = false; - sh->ldap = NULL; - sh->ops = NULL; - } -} - -/* ==Parse-Results-And-Handle-Disconnections============================== */ -static void sdap_process_message(struct tevent_context *ev, - struct sdap_handle *sh, LDAPMessage *msg); -static void sdap_process_result(struct tevent_context *ev, void *pvt); -static void sdap_process_next_reply(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt); - -static void sdap_ldap_result(struct tevent_context *ev, - struct tevent_fd *fde, - uint16_t flags, void *pvt) -{ - sdap_process_result(ev, pvt); -} - -static void sdap_ldap_next_result(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt) -{ - sdap_process_result(ev, pvt); -} - -static void sdap_process_result(struct tevent_context *ev, void *pvt) -{ - struct sdap_handle *sh = talloc_get_type(pvt, struct sdap_handle); - struct timeval no_timeout = {0, 0}; - struct tevent_timer *te; - LDAPMessage *msg; - int ret; - - DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], ldap[%p]\n", - sh, (int)sh->connected, sh->ops, sh->ldap)); - - if (!sh->connected || !sh->ldap) { - DEBUG(2, ("ERROR: LDAP connection is not connected!\n")); - return; - } - - ret = ldap_result(sh->ldap, LDAP_RES_ANY, 0, &no_timeout, &msg); - if (ret == 0) { - /* this almost always means we have reached the end of - * the list of received messages */ - DEBUG(8, ("Trace: ldap_result found nothing!\n")); - return; - } - - if (ret == -1) { - DEBUG(4, ("ldap_result gave -1, something bad happend!\n")); - sdap_handle_release(sh); - return; - } - - /* We don't know if this will be the last result. - * - * important: we must do this before actually processing the message - * because the message processing might even free the sdap_handler - * so it must be the last operation. - * FIXME: use tevent_immediate/tevent_queues, when avilable */ - memset(&no_timeout, 0, sizeof(struct timeval)); - - te = tevent_add_timer(ev, sh, no_timeout, sdap_ldap_next_result, sh); - if (!te) { - DEBUG(1, ("Failed to add critical timer to fetch next result!\n")); - } - - /* now process this message */ - sdap_process_message(ev, sh, msg); -} - -/* process a messgae calling the right operation callback. - * msg is completely taken care of (including freeeing it) - * NOTE: this function may even end up freeing the sdap_handle - * so sdap_hanbdle must not be used after this function is called - */ -static void sdap_process_message(struct tevent_context *ev, - struct sdap_handle *sh, LDAPMessage *msg) -{ - struct sdap_msg *reply; - struct sdap_op *op; - int msgid; - int msgtype; - int ret; - - msgid = ldap_msgid(msg); - if (msgid == -1) { - DEBUG(2, ("can't fire callback, message id invalid!\n")); - ldap_msgfree(msg); - return; - } - - msgtype = ldap_msgtype(msg); - - for (op = sh->ops; op; op = op->next) { - if (op->msgid == msgid) break; - } - - if (op == NULL) { - DEBUG(2, ("Unmatched msgid, discarding message (type: %0x)\n", - msgtype)); - ldap_msgfree(msg); - return; - } - - /* shouldn't happen */ - if (op->done) { - DEBUG(2, ("Operation [%p] already handled (type: %0x)\n", op, msgtype)); - ldap_msgfree(msg); - return; - } - - switch (msgtype) { - case LDAP_RES_SEARCH_ENTRY: - /* go and process entry */ - break; - - case LDAP_RES_SEARCH_REFERENCE: - /* more ops to come with this msgid */ - /* just ignore */ - ldap_msgfree(msg); - return; - - case LDAP_RES_BIND: - case LDAP_RES_SEARCH_RESULT: - case LDAP_RES_MODIFY: - case LDAP_RES_ADD: - case LDAP_RES_DELETE: - case LDAP_RES_MODDN: - case LDAP_RES_COMPARE: - case LDAP_RES_EXTENDED: - case LDAP_RES_INTERMEDIATE: - /* no more results expected with this msgid */ - op->done = true; - break; - - default: - /* unkwon msg type ?? */ - DEBUG(1, ("Couldn't figure out the msg type! [%0x]\n", msgtype)); - ldap_msgfree(msg); - return; - } - - reply = talloc_zero(op, struct sdap_msg); - if (!reply) { - ldap_msgfree(msg); - ret = ENOMEM; - } else { - reply->msg = msg; - ret = sdap_msg_attach(reply, msg); - if (ret != EOK) { - ldap_msgfree(msg); - talloc_zfree(reply); - } - } - - if (op->list) { - /* list exist, queue it */ - - op->last->next = reply; - op->last = reply; - - } else { - /* create list, then call callback */ - op->list = op->last = reply; - - /* must be the last operation as it may end up freeing all memory - * including all ops handlers */ - op->callback(op, reply, ret, op->data); - } -} - -static void sdap_unlock_next_reply(struct sdap_op *op) -{ - struct timeval tv; - struct tevent_timer *te; - struct sdap_msg *next_reply; - - if (op->list) { - next_reply = op->list->next; - /* get rid of the previous reply, it has been processed already */ - talloc_zfree(op->list); - op->list = next_reply; - } - - /* if there are still replies to parse, queue a new operation */ - if (op->list) { - /* use a very small timeout, so that fd operations have a chance to be - * served while processing a long reply */ - tv = tevent_timeval_current(); - - /* wait 5 microsecond */ - tv.tv_usec += 5; - tv.tv_sec += tv.tv_usec / 1000000; - tv.tv_usec = tv.tv_usec % 1000000; - - te = tevent_add_timer(op->ev, op, tv, - sdap_process_next_reply, op); - if (!te) { - DEBUG(1, ("Failed to add critical timer for next reply!\n")); - op->callback(op, NULL, EFAULT, op->data); - } - } -} - -static void sdap_process_next_reply(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt) -{ - struct sdap_op *op = talloc_get_type(pvt, struct sdap_op); - - op->callback(op, op->list, EOK, op->data); -} - -#ifdef HAVE_LDAP_CONNCB -int sdap_ldap_connect_callback_add(LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv, - struct sockaddr *addr, struct ldap_conncb *ctx) -{ - int ret; - ber_socket_t ber_fd; - struct fd_event_item *fd_event_item; - struct ldap_cb_data *cb_data = talloc_get_type(ctx->lc_arg, - struct ldap_cb_data); - - ret = ber_sockbuf_ctrl(sb, LBER_SB_OPT_GET_FD, &ber_fd); - if (ret == -1) { - DEBUG(1, ("ber_sockbuf_ctrl failed.\n")); - return EINVAL; - } - DEBUG(9, ("New LDAP connection to [%s] with fd [%d].\n", - ldap_url_desc2str(srv), ber_fd)); - - fd_event_item = talloc_zero(cb_data, struct fd_event_item); - if (fd_event_item == NULL) { - DEBUG(1, ("talloc failed.\n")); - return ENOMEM; - } - - fd_event_item->fde = tevent_add_fd(cb_data->ev, fd_event_item, ber_fd, - TEVENT_FD_READ, sdap_ldap_result, - cb_data->sh); - if (fd_event_item->fde == NULL) { - DEBUG(1, ("tevent_add_fd failed.\n")); - talloc_free(fd_event_item); - return ENOMEM; - } - fd_event_item->fd = ber_fd; - - DLIST_ADD(cb_data->fd_list, fd_event_item); - - return LDAP_SUCCESS; -} - -void sdap_ldap_connect_callback_del(LDAP *ld, Sockbuf *sb, - struct ldap_conncb *ctx) -{ - int ret; - ber_socket_t ber_fd; - struct fd_event_item *fd_event_item; - struct ldap_cb_data *cb_data = talloc_get_type(ctx->lc_arg, - struct ldap_cb_data); - - if (sb == NULL || cb_data == NULL) { - return; - } - - ret = ber_sockbuf_ctrl(sb, LBER_SB_OPT_GET_FD, &ber_fd); - if (ret == -1) { - DEBUG(1, ("ber_sockbuf_ctrl failed.\n")); - return; - } - DEBUG(9, ("Closing LDAP connection with fd [%d].\n", ber_fd)); - - DLIST_FOR_EACH(fd_event_item, cb_data->fd_list) { - if (fd_event_item->fd == ber_fd) { - break; - } - } - if (fd_event_item == NULL) { - DEBUG(1, ("No event for fd [%d] found.\n", ber_fd)); - return; - } - - DLIST_REMOVE(cb_data->fd_list, fd_event_item); - talloc_zfree(fd_event_item); - - return; -} - -#else - -static int get_fd_from_ldap(LDAP *ldap, int *fd) -{ - int ret; - - ret = ldap_get_option(ldap, LDAP_OPT_DESC, fd); - if (ret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("Failed to get fd from ldap!!\n")); - *fd = -1; - return EIO; - } - - return EOK; -} - -int sdap_install_ldap_callbacks(struct sdap_handle *sh, - struct tevent_context *ev) -{ - int fd; - int ret; - - ret = get_fd_from_ldap(sh->ldap, &fd); - if (ret) return ret; - - sh->fde = tevent_add_fd(ev, sh, fd, TEVENT_FD_READ, sdap_ldap_result, sh); - if (!sh->fde) return ENOMEM; - - DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], fde[%p], ldap[%p]\n", - sh, (int)sh->connected, sh->ops, sh->fde, sh->ldap)); - - return EOK; -} - -#endif - - -/* ==LDAP-Operations-Helpers============================================== */ - -static int sdap_op_destructor(void *mem) -{ - struct sdap_op *op = (struct sdap_op *)mem; - - DLIST_REMOVE(op->sh->ops, op); - - if (op->done) return 0; - - /* we don't check the result here, if a message was really abandoned, - * hopefully the server will get an abandon. - * If the operation was already fully completed, this is going to be - * just a noop */ - ldap_abandon_ext(op->sh->ldap, op->msgid, NULL, NULL); - - return 0; -} - -static void sdap_op_timeout(struct tevent_req *req) -{ - struct sdap_op *op = tevent_req_callback_data(req, struct sdap_op); - - /* should never happen, but just in case */ - if (op->done) { - DEBUG(2, ("Timeout happened after op was finished !?\n")); - return; - } - - /* signal the caller that we have a timeout */ - op->callback(op, NULL, ETIMEDOUT, op->data); -} - -int sdap_op_add(TALLOC_CTX *memctx, struct tevent_context *ev, - struct sdap_handle *sh, int msgid, - sdap_op_callback_t *callback, void *data, - int timeout, struct sdap_op **_op) -{ - struct sdap_op *op; - - op = talloc_zero(memctx, struct sdap_op); - if (!op) return ENOMEM; - - op->sh = sh; - op->msgid = msgid; - op->callback = callback; - op->data = data; - op->ev = ev; - - /* check if we need to set a timeout */ - if (timeout) { - struct tevent_req *req; - struct timeval tv; - - tv = tevent_timeval_current(); - tv = tevent_timeval_add(&tv, timeout, 0); - - /* allocate on op, so when it get freed the timeout is removed */ - req = tevent_wakeup_send(op, ev, tv); - if (!req) { - talloc_zfree(op); - return ENOMEM; - } - tevent_req_set_callback(req, sdap_op_timeout, op); - } - - DLIST_ADD(sh->ops, op); - - talloc_set_destructor((TALLOC_CTX *)op, sdap_op_destructor); - - *_op = op; - return EOK; -} - -/* ==Modify-Password====================================================== */ - -struct sdap_exop_modify_passwd_state { - struct sdap_handle *sh; - - struct sdap_op *op; - - int result; - char *user_error_message; -}; - -static void sdap_exop_modify_passwd_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt); - -struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_handle *sh, - char *user_dn, - char *password, - char *new_password) -{ - struct tevent_req *req = NULL; - struct sdap_exop_modify_passwd_state *state; - int ret; - BerElement *ber = NULL; - struct berval *bv = NULL; - int msgid; - LDAPControl *request_controls[2]; - - req = tevent_req_create(memctx, &state, - struct sdap_exop_modify_passwd_state); - if (!req) return NULL; - - state->sh = sh; - state->user_error_message = NULL; - - ber = ber_alloc_t( LBER_USE_DER ); - if (ber == NULL) { - DEBUG(7, ("ber_alloc_t failed.\n")); - talloc_zfree(req); - return NULL; - } - - ret = ber_printf( ber, "{tststs}", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, - user_dn, - LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, password, - LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, new_password); - if (ret == -1) { - DEBUG(1, ("ber_printf failed.\n")); - ber_free(ber, 1); - talloc_zfree(req); - return NULL; - } - - ret = ber_flatten(ber, &bv); - ber_free(ber, 1); - if (ret == -1) { - DEBUG(1, ("ber_flatten failed.\n")); - talloc_zfree(req); - return NULL; - } - - ret = sss_ldap_control_create(LDAP_CONTROL_PASSWORDPOLICYREQUEST, - 0, NULL, 0, &request_controls[0]); - if (ret != LDAP_SUCCESS) { - DEBUG(1, ("sss_ldap_control_create failed.\n")); - goto fail; - } - request_controls[1] = NULL; - - DEBUG(4, ("Executing extended operation\n")); - - ret = ldap_extended_operation(state->sh->ldap, LDAP_EXOP_MODIFY_PASSWD, - bv, request_controls, NULL, &msgid); - ber_bvfree(bv); - ldap_control_free(request_controls[0]); - if (ret == -1 || msgid == -1) { - DEBUG(1, ("ldap_extended_operation failed\n")); - goto fail; - } - DEBUG(8, ("ldap_extended_operation sent, msgid = %d\n", msgid)); - - /* FIXME: get timeouts from configuration, for now 5 secs. */ - ret = sdap_op_add(state, ev, state->sh, msgid, - sdap_exop_modify_passwd_done, req, 5, &state->op); - if (ret) { - DEBUG(1, ("Failed to set up operation!\n")); - goto fail; - } - - return req; - -fail: - tevent_req_error(req, EIO); - tevent_req_post(req, ev); - return req; -} - -static void sdap_exop_modify_passwd_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct sdap_exop_modify_passwd_state *state = tevent_req_data(req, - struct sdap_exop_modify_passwd_state); - char *errmsg = NULL; - int ret; - LDAPControl **response_controls = NULL; - int c; - ber_int_t pp_grace; - ber_int_t pp_expire; - LDAPPasswordPolicyError pp_error; - - if (error) { - tevent_req_error(req, error); - return; - } - - ret = ldap_parse_result(state->sh->ldap, reply->msg, - &state->result, NULL, &errmsg, NULL, - &response_controls, 0); - if (ret != LDAP_SUCCESS) { - DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid)); - ret = EIO; - goto done; - } - - if (response_controls == NULL) { - DEBUG(5, ("Server returned no controls.\n")); - } else { - for (c = 0; response_controls[c] != NULL; c++) { - DEBUG(9, ("Server returned control [%s].\n", - response_controls[c]->ldctl_oid)); - if (strcmp(response_controls[c]->ldctl_oid, - LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) { - ret = ldap_parse_passwordpolicy_control(state->sh->ldap, - response_controls[c], - &pp_expire, &pp_grace, - &pp_error); - if (ret != LDAP_SUCCESS) { - DEBUG(1, ("ldap_parse_passwordpolicy_control failed.\n")); - ret = EIO; - goto done; - } - - DEBUG(7, ("Password Policy Response: expire [%d] grace [%d] " - "error [%s].\n", pp_expire, pp_grace, - ldap_passwordpolicy_err2txt(pp_error))); - } - } - } - - if (state->result != LDAP_SUCCESS) { - state->user_error_message = talloc_strdup(state, errmsg); - if (state->user_error_message == NULL) { - DEBUG(1, ("talloc_strdup failed.\n")); - } - } - - DEBUG(3, ("ldap_extended_operation result: %s(%d), %s\n", - ldap_err2string(state->result), state->result, errmsg)); - - ret = LDAP_SUCCESS; -done: - ldap_controls_free(response_controls); - ldap_memfree(errmsg); - - if (ret == LDAP_SUCCESS) { - tevent_req_done(req); - } else { - tevent_req_error(req, ret); - } -} - -int sdap_exop_modify_passwd_recv(struct tevent_req *req, - TALLOC_CTX * mem_ctx, - enum sdap_result *result, - char **user_error_message) -{ - struct sdap_exop_modify_passwd_state *state = tevent_req_data(req, - struct sdap_exop_modify_passwd_state); - - *result = SDAP_ERROR; - *user_error_message = talloc_steal(mem_ctx, state->user_error_message); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - if (state->result == LDAP_SUCCESS) { - *result = SDAP_SUCCESS; - } - - return EOK; -} - -/* ==Fetch-RootDSE============================================= */ - -struct sdap_get_rootdse_state { - struct tevent_context *ev; - struct sdap_options *opts; - struct sdap_handle *sh; - - struct sysdb_attrs *rootdse; -}; - -static void sdap_get_rootdse_done(struct tevent_req *subreq); - -struct tevent_req *sdap_get_rootdse_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_options *opts, - struct sdap_handle *sh) -{ - struct tevent_req *req, *subreq; - struct sdap_get_rootdse_state *state; - - DEBUG(9, ("Getting rootdse\n")); - - req = tevent_req_create(memctx, &state, struct sdap_get_rootdse_state); - if (!req) return NULL; - - state->ev = ev; - state->opts = opts; - state->sh = sh; - state->rootdse = NULL; - - subreq = sdap_get_generic_send(state, ev, opts, sh, - "", LDAP_SCOPE_BASE, - "(objectclass=*)", NULL, NULL, 0); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, sdap_get_rootdse_done, req); - - return req; -} - -static void sdap_get_rootdse_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_rootdse_state *state = tevent_req_data(req, - struct sdap_get_rootdse_state); - struct sysdb_attrs **results; - size_t num_results; - int ret; - - ret = sdap_get_generic_recv(subreq, state, &num_results, &results); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - if (num_results == 0 || !results) { - DEBUG(2, ("No RootDSE for server ?!\n")); - tevent_req_error(req, ENOENT); - return; - } - - if (num_results > 1) { - DEBUG(2, ("Multiple replies when searching for RootDSE ??\n")); - tevent_req_error(req, EIO); - return; - } - - state->rootdse = talloc_steal(state, results[0]); - talloc_zfree(results); - - DEBUG(9, ("Got rootdse\n")); - - tevent_req_done(req); -} - -int sdap_get_rootdse_recv(struct tevent_req *req, - TALLOC_CTX *memctx, - struct sysdb_attrs **rootdse) -{ - struct sdap_get_rootdse_state *state = tevent_req_data(req, - struct sdap_get_rootdse_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *rootdse = talloc_steal(memctx, state->rootdse); - - return EOK; -} - -/* ==Generic Search============================================ */ - -struct sdap_get_generic_state { - struct tevent_context *ev; - struct sdap_options *opts; - struct sdap_handle *sh; - const char *search_base; - int scope; - const char *filter; - const char **attrs; - struct sdap_attr_map *map; - int map_num_attrs; - - struct sdap_op *op; - - size_t reply_max; - size_t reply_count; - struct sysdb_attrs **reply; -}; - -static errno_t add_to_reply(struct sdap_get_generic_state *state, - struct sysdb_attrs *msg); - -static void sdap_get_generic_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt); - -struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_options *opts, - struct sdap_handle *sh, - const char *search_base, - int scope, - const char *filter, - const char **attrs, - struct sdap_attr_map *map, - int map_num_attrs) -{ - struct tevent_req *req = NULL; - struct sdap_get_generic_state *state = NULL; - int lret; - int ret; - int msgid; - - req = tevent_req_create(memctx, &state, struct sdap_get_generic_state); - if (!req) return NULL; - - state->ev = ev; - state->opts = opts; - state->sh = sh; - state->search_base = search_base; - state->scope = scope; - state->filter = filter; - state->attrs = attrs; - state->map = map; - state->map_num_attrs = map_num_attrs; - state->op = NULL; - state->reply_max = 0; - state->reply_count = 0; - state->reply = NULL; - - DEBUG(6, ("calling ldap_search_ext with [%s][%s].\n", state->filter, - state->search_base)); - if (debug_level >= 7) { - int i; - - if (state->attrs) { - for (i = 0; state->attrs[i]; i++) { - DEBUG(7, ("Requesting attrs: [%s]\n", state->attrs[i])); - } - } - } - - lret = ldap_search_ext(state->sh->ldap, state->search_base, - state->scope, state->filter, - discard_const(state->attrs), - false, NULL, NULL, NULL, 0, &msgid); - if (lret != LDAP_SUCCESS) { - DEBUG(3, ("ldap_search_ext failed: %s\n", ldap_err2string(lret))); - ret = EIO; - goto fail; - } - DEBUG(8, ("ldap_search_ext called, msgid = %d\n", msgid)); - - ret = sdap_op_add(state, state->ev, state->sh, msgid, - sdap_get_generic_done, req, - dp_opt_get_int(state->opts->basic, - SDAP_SEARCH_TIMEOUT), - &state->op); - if (ret != EOK) { - DEBUG(1, ("Failed to set up operation!\n")); - goto fail; - } - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - - -static void sdap_get_generic_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct sdap_get_generic_state *state = tevent_req_data(req, - struct sdap_get_generic_state); - struct sysdb_attrs *attrs; - char *errmsg; - int result; - int ret; - - if (error) { - tevent_req_error(req, error); - return; - } - - switch (ldap_msgtype(reply->msg)) { - case LDAP_RES_SEARCH_REFERENCE: - /* ignore references for now */ - talloc_free(reply); - - /* unlock the operation so that we can proceed with the next result */ - sdap_unlock_next_reply(state->op); - break; - - case LDAP_RES_SEARCH_ENTRY: - ret = sdap_parse_entry(state, state->sh, reply, - state->map, state->map_num_attrs, - &attrs, NULL); - if (ret != EOK) { - DEBUG(1, ("sdap_parse_generic_entry failed.\n")); - tevent_req_error(req, ENOMEM); - return; - } - - ret = add_to_reply(state, attrs); - if (ret != EOK) { - DEBUG(1, ("add_to_reply failed.\n")); - tevent_req_error(req, ret); - return; - } - - sdap_unlock_next_reply(state->op); - break; - - case LDAP_RES_SEARCH_RESULT: - ret = ldap_parse_result(state->sh->ldap, reply->msg, - &result, NULL, &errmsg, NULL, NULL, 0); - if (ret != LDAP_SUCCESS) { - DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid)); - tevent_req_error(req, EIO); - return; - } - - DEBUG(6, ("Search result: %s(%d), %s\n", - ldap_err2string(result), result, errmsg)); - - tevent_req_done(req); - return; - - default: - /* what is going on here !? */ - tevent_req_error(req, EIO); - return; - } -} - -static errno_t add_to_reply(struct sdap_get_generic_state *state, - struct sysdb_attrs *msg) -{ - if (state->reply == NULL || state->reply_max == state->reply_count) { - state->reply_max += REPLY_REALLOC_INCREMENT; - state->reply = talloc_realloc(state, state->reply, - struct sysdb_attrs *, - state->reply_max); - if (state->reply == NULL) { - DEBUG(1, ("talloc_realloc failed.\n")); - return ENOMEM; - } - } - - state->reply[state->reply_count++] = talloc_steal(state->reply, msg); - - return EOK; -} - -int sdap_get_generic_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - size_t *reply_count, - struct sysdb_attrs ***reply) -{ - struct sdap_get_generic_state *state = tevent_req_data(req, - struct sdap_get_generic_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *reply_count = state->reply_count; - *reply = talloc_steal(mem_ctx, state->reply); - - return EOK; -} - diff --git a/server/providers/ldap/sdap_async.h b/server/providers/ldap/sdap_async.h deleted file mode 100644 index 3c52d236b..000000000 --- a/server/providers/ldap/sdap_async.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - SSSD - - Async LDAP Helper routines - - Copyright (C) Simo Sorce - - 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 _SDAP_ASYNC_H_ -#define _SDAP_ASYNC_H_ - -#include -#include -#include "providers/dp_backend.h" -#include "providers/ldap/sdap.h" -#include "providers/fail_over.h" - -struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_options *opts, - const char *uri, - bool use_start_tls); -int sdap_connect_recv(struct tevent_req *req, - TALLOC_CTX *memctx, - struct sdap_handle **sh); - -struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sss_domain_info *dom, - struct sysdb_ctx *sysdb, - struct sdap_options *opts, - struct sdap_handle *sh, - const char **attrs, - const char *wildcard); -int sdap_get_users_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, char **timestamp); - -struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sss_domain_info *dom, - struct sysdb_ctx *sysdb, - struct sdap_options *opts, - struct sdap_handle *sh, - const char **attrs, - const char *wildcard); -int sdap_get_groups_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, char **timestamp); - -struct tevent_req *sdap_kinit_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_handle *sh, - int timeout, - const char *keytab, - const char *principal, - const char *realm); -int sdap_kinit_recv(struct tevent_req *req, enum sdap_result *result); - -struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_handle *sh, - const char *sasl_mech, - const char *sasl_user, - const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok); -int sdap_auth_recv(struct tevent_req *req, enum sdap_result *result); - -struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sss_domain_info *dom, - struct sysdb_ctx *sysdb, - struct sdap_options *opts, - struct sdap_handle *sh, - const char *name, - const char **grp_attrs); -int sdap_get_initgr_recv(struct tevent_req *req); - -struct tevent_req *sdap_exop_modify_passwd_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_handle *sh, - char *user_dn, - char *password, - char *new_password); -int sdap_exop_modify_passwd_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - enum sdap_result *result, - char **user_error_msg); - -struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_options *opts, - struct be_ctx *be, - struct sdap_service *service, - struct sysdb_attrs **rootdse); -int sdap_cli_connect_recv(struct tevent_req *req, - TALLOC_CTX *memctx, - struct sdap_handle **gsh, - struct sysdb_attrs **rootdse); - -struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_options *opts, - struct sdap_handle *sh, - const char *search_base, - int scope, - const char *filter, - const char **attrs, - struct sdap_attr_map *map, - int map_num_attrs); -int sdap_get_generic_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, size_t *reply_count, - struct sysdb_attrs ***reply_list); - -#endif /* _SDAP_ASYNC_H_ */ diff --git a/server/providers/ldap/sdap_async_accounts.c b/server/providers/ldap/sdap_async_accounts.c deleted file mode 100644 index abebe2883..000000000 --- a/server/providers/ldap/sdap_async_accounts.c +++ /dev/null @@ -1,2065 +0,0 @@ -/* - SSSD - - Async LDAP Helper routines - - Copyright (C) Simo Sorce - 2009 - - 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 "util/util.h" -#include "db/sysdb.h" -#include "providers/ldap/sdap_async_private.h" - -/* ==Save-User-Entry====================================================== */ - -struct sdap_save_user_state { - struct tevent_context *ev; - struct sysdb_handle *handle; - struct sdap_options *opts; - - struct sss_domain_info *dom; - - const char *name; - struct sysdb_attrs *attrs; - char *timestamp; -}; - -static void sdap_save_user_done(struct tevent_req *subreq); - - /* FIXME: support storing additional attributes */ - -static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sysdb_handle *handle, - struct sdap_options *opts, - struct sss_domain_info *dom, - struct sysdb_attrs *attrs, - bool is_initgr) -{ - struct tevent_req *req, *subreq; - struct sdap_save_user_state *state; - struct ldb_message_element *el; - int ret; - const char *pwd; - const char *gecos; - const char *homedir; - const char *shell; - long int l; - uid_t uid; - gid_t gid; - struct sysdb_attrs *user_attrs; - char *upn = NULL; - int i; - char *val = NULL; - int cache_timeout; - - DEBUG(9, ("Save user\n")); - - req = tevent_req_create(memctx, &state, struct sdap_save_user_state); - if (!req) return NULL; - - state->ev = ev; - state->handle = handle; - state->dom = dom; - state->opts = opts; - state->attrs = attrs; - state->timestamp = NULL; - - ret = sysdb_attrs_get_el(state->attrs, - opts->user_map[SDAP_AT_USER_NAME].sys_name, &el); - if (ret) goto fail; - if (el->num_values == 0) { - ret = EINVAL; - goto fail; - } - state->name = (const char *)el->values[0].data; - - ret = sysdb_attrs_get_el(state->attrs, - opts->user_map[SDAP_AT_USER_PWD].sys_name, &el); - if (ret) goto fail; - if (el->num_values == 0) pwd = NULL; - else pwd = (const char *)el->values[0].data; - - ret = sysdb_attrs_get_el(state->attrs, - opts->user_map[SDAP_AT_USER_GECOS].sys_name, &el); - if (ret) goto fail; - if (el->num_values == 0) gecos = NULL; - else gecos = (const char *)el->values[0].data; - - ret = sysdb_attrs_get_el(state->attrs, - opts->user_map[SDAP_AT_USER_HOME].sys_name, &el); - if (ret) goto fail; - if (el->num_values == 0) homedir = NULL; - else homedir = (const char *)el->values[0].data; - - ret = sysdb_attrs_get_el(state->attrs, - opts->user_map[SDAP_AT_USER_SHELL].sys_name, &el); - if (ret) goto fail; - if (el->num_values == 0) shell = NULL; - else shell = (const char *)el->values[0].data; - - ret = sysdb_attrs_get_el(state->attrs, - opts->user_map[SDAP_AT_USER_UID].sys_name, &el); - if (ret) goto fail; - if (el->num_values == 0) { - DEBUG(1, ("no uid provided for [%s] in domain [%s].\n", - state->name, dom->name)); - ret = EINVAL; - goto fail; - } - errno = 0; - l = strtol((const char *)el->values[0].data, NULL, 0); - if (errno) { - ret = EINVAL; - goto fail; - } - uid = l; - - /* check that the uid is valid for this domain */ - if (OUT_OF_ID_RANGE(uid, dom->id_min, dom->id_max)) { - DEBUG(2, ("User [%s] filtered out! (id out of range)\n", - state->name)); - ret = EINVAL; - goto fail; - } - - ret = sysdb_attrs_get_el(state->attrs, - opts->user_map[SDAP_AT_USER_GID].sys_name, &el); - if (ret) goto fail; - if (el->num_values == 0) { - DEBUG(1, ("no gid provided for [%s] in domain [%s].\n", - state->name, dom->name)); - ret = EINVAL; - goto fail; - } - errno = 0; - l = strtol((const char *)el->values[0].data, NULL, 0); - if (errno) { - ret = EINVAL; - goto fail; - } - gid = l; - - /* check that the gid is valid for this domain */ - if (OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) { - DEBUG(2, ("User [%s] filtered out! (id out of range)\n", - state->name)); - ret = EINVAL; - goto fail; - } - - user_attrs = sysdb_new_attrs(state); - if (user_attrs == NULL) { - ret = ENOMEM; - goto fail; - } - - ret = sysdb_attrs_get_el(state->attrs, SYSDB_ORIG_DN, &el); - if (ret) { - goto fail; - } - if (el->num_values == 0) { - DEBUG(7, ("Original DN is not available for [%s].\n", state->name)); - } else { - DEBUG(7, ("Adding original DN [%s] to attributes of [%s].\n", - el->values[0].data, state->name)); - ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_DN, - (const char *) el->values[0].data); - if (ret) { - goto fail; - } - } - - ret = sysdb_attrs_get_el(state->attrs, SYSDB_MEMBEROF, &el); - if (ret) { - goto fail; - } - if (el->num_values == 0) { - DEBUG(7, ("Original memberOf is not available for [%s].\n", - state->name)); - } else { - DEBUG(7, ("Adding original memberOf attributes to [%s].\n", - state->name)); - for (i = 0; i < el->num_values; i++) { - ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF, - (const char *) el->values[i].data); - if (ret) { - goto fail; - } - } - } - - ret = sysdb_attrs_get_el(state->attrs, - opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name, &el); - if (ret) { - goto fail; - } - if (el->num_values == 0) { - DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n", - state->name)); - } else { - ret = sysdb_attrs_add_string(user_attrs, - opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name, - (const char*)el->values[0].data); - if (ret) { - goto fail; - } - state->timestamp = talloc_strdup(state, - (const char*)el->values[0].data); - if (!state->timestamp) { - ret = ENOMEM; - goto fail; - } - } - - ret = sysdb_attrs_get_el(state->attrs, - opts->user_map[SDAP_AT_USER_PRINC].sys_name, &el); - if (ret) { - goto fail; - } - if (el->num_values == 0) { - DEBUG(7, ("User principle is not available for [%s].\n", state->name)); - } else { - upn = talloc_strdup(user_attrs, (const char*) el->values[0].data); - if (!upn) { - ret = ENOMEM; - goto fail; - } - if (dp_opt_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) { - make_realm_upper_case(upn); - } - DEBUG(7, ("Adding user principle [%s] to attributes of [%s].\n", - upn, state->name)); - ret = sysdb_attrs_add_string(user_attrs, SYSDB_UPN, upn); - if (ret) { - goto fail; - } - } - - for (i = SDAP_FIRST_EXTRA_USER_AT; i < SDAP_OPTS_USER; i++) { - ret = sysdb_attrs_get_el(state->attrs, opts->user_map[i].sys_name, &el); - if (ret) { - goto fail; - } - if (el->num_values > 0) { - DEBUG(9, ("Adding [%s]=[%s] to user attributes.\n", - opts->user_map[i].sys_name, - (const char*) el->values[0].data)); - val = talloc_strdup(user_attrs, (const char*) el->values[0].data); - if (val == NULL) { - ret = ENOMEM; - goto fail; - } - ret = sysdb_attrs_add_string(user_attrs, - opts->user_map[i].sys_name, val); - if (ret) { - goto fail; - } - } - } - - cache_timeout = dp_opt_get_int(opts->basic, SDAP_ENTRY_CACHE_TIMEOUT); - - if (is_initgr) { - ret = sysdb_attrs_add_time_t(user_attrs, SYSDB_INITGR_EXPIRE, - (cache_timeout ? - (time(NULL) + cache_timeout) : 0)); - if (ret) { - goto fail; - } - } - - DEBUG(6, ("Storing info for user %s\n", state->name)); - - subreq = sysdb_store_user_send(state, state->ev, state->handle, - state->dom, state->name, pwd, - uid, gid, gecos, homedir, shell, - user_attrs, cache_timeout); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, sdap_save_user_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void sdap_save_user_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_save_user_state *state = tevent_req_data(req, - struct sdap_save_user_state); - int ret; - - ret = sysdb_store_user_recv(subreq); - talloc_zfree(subreq); - if (ret) { - DEBUG(2, ("Failed to save user %s\n", state->name)); - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -static int sdap_save_user_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, char **timestamp) -{ - struct sdap_save_user_state *state = tevent_req_data(req, - struct sdap_save_user_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - if (timestamp) { - *timestamp = talloc_steal(mem_ctx, state->timestamp); - } - - return EOK; -} - - -/* ==Generic-Function-to-save-multiple-users============================= */ - -struct sdap_save_users_state { - struct tevent_context *ev; - struct sysdb_ctx *sysdb; - struct sdap_options *opts; - struct sss_domain_info *dom; - - struct sysdb_attrs **users; - int count; - int cur; - - struct sysdb_handle *handle; - - char *higher_timestamp; -}; - -static void sdap_save_users_trans(struct tevent_req *subreq); -static void sdap_save_users_store(struct tevent_req *req); -static void sdap_save_users_process(struct tevent_req *subreq); -struct tevent_req *sdap_save_users_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sss_domain_info *dom, - struct sysdb_ctx *sysdb, - struct sdap_options *opts, - struct sysdb_attrs **users, - int num_users) -{ - struct tevent_req *req, *subreq; - struct sdap_save_users_state *state; - - req = tevent_req_create(memctx, &state, struct sdap_save_users_state); - if (!req) return NULL; - - state->ev = ev; - state->opts = opts; - state->sysdb = sysdb; - state->dom = dom; - state->users = users; - state->count = num_users; - state->cur = 0; - state->handle = NULL; - state->higher_timestamp = NULL; - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (!subreq) { - tevent_req_error(req, ENOMEM); - tevent_req_post(req, ev); - return req; - } - tevent_req_set_callback(subreq, sdap_save_users_trans, req); - - return req; -} - -static void sdap_save_users_trans(struct tevent_req *subreq) -{ - struct tevent_req *req; - struct sdap_save_users_state *state; - int ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct sdap_save_users_state); - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - sdap_save_users_store(req); -} - -static void sdap_save_users_store(struct tevent_req *req) -{ - struct tevent_req *subreq; - struct sdap_save_users_state *state; - - state = tevent_req_data(req, struct sdap_save_users_state); - - subreq = sdap_save_user_send(state, state->ev, state->handle, - state->opts, state->dom, - state->users[state->cur], false); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_save_users_process, req); -} - -static void sdap_save_users_process(struct tevent_req *subreq) -{ - struct tevent_req *req; - struct sdap_save_users_state *state; - char *timestamp = NULL; - int ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct sdap_save_users_state); - - ret = sdap_save_user_recv(subreq, state, ×tamp); - talloc_zfree(subreq); - - /* Do not fail completely on errors. - * Just report the failure to save and go on */ - if (ret) { - DEBUG(2, ("Failed to store user %d. Ignoring.\n", state->cur)); - } else { - DEBUG(9, ("User %d processed!\n", state->cur)); - } - - if (timestamp) { - if (state->higher_timestamp) { - if (strcmp(timestamp, state->higher_timestamp) > 0) { - talloc_zfree(state->higher_timestamp); - state->higher_timestamp = timestamp; - } else { - talloc_zfree(timestamp); - } - } else { - state->higher_timestamp = timestamp; - } - } - - state->cur++; - if (state->cur < state->count) { - sdap_save_users_store(req); - } else { - subreq = sysdb_transaction_commit_send(state, state->ev, - state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - /* sysdb_transaction_complete will call tevent_req_done(req) */ - tevent_req_set_callback(subreq, sysdb_transaction_complete, req); - } -} - -static int sdap_save_users_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, char **timestamp) -{ - struct sdap_save_users_state *state = tevent_req_data(req, - struct sdap_save_users_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - if (timestamp) { - *timestamp = talloc_steal(mem_ctx, state->higher_timestamp); - } - - return EOK; -} - - -/* ==Search-Users-with-filter============================================= */ - -struct sdap_get_users_state { - struct tevent_context *ev; - struct sdap_options *opts; - struct sdap_handle *sh; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - const char **attrs; - const char *filter; - - char *higher_timestamp; - struct sysdb_attrs **users; - size_t count; -}; - -static void sdap_get_users_process(struct tevent_req *subreq); -static void sdap_get_users_done(struct tevent_req *subreq); - -struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sss_domain_info *dom, - struct sysdb_ctx *sysdb, - struct sdap_options *opts, - struct sdap_handle *sh, - const char **attrs, - const char *filter) -{ - struct tevent_req *req, *subreq; - struct sdap_get_users_state *state; - - req = tevent_req_create(memctx, &state, struct sdap_get_users_state); - if (!req) return NULL; - - state->ev = ev; - state->opts = opts; - state->dom = dom; - state->sh = sh; - state->sysdb = sysdb; - state->filter = filter; - state->attrs = attrs; - state->higher_timestamp = NULL; - state->users = NULL; - state->count = 0; - - subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh, - dp_opt_get_string(state->opts->basic, - SDAP_USER_SEARCH_BASE), - LDAP_SCOPE_SUBTREE, - state->filter, state->attrs, - state->opts->user_map, SDAP_OPTS_USER); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, sdap_get_users_process, req); - - return req; -} - -static void sdap_get_users_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_users_state *state = tevent_req_data(req, - struct sdap_get_users_state); - int ret; - - ret = sdap_get_generic_recv(subreq, state, - &state->count, &state->users); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - DEBUG(6, ("Search for users, returned %d results.\n", state->count)); - - if (state->count == 0) { - tevent_req_error(req, ENOENT); - return; - } - - subreq = sdap_save_users_send(state, state->ev, state->dom, - state->sysdb, state->opts, - state->users, state->count); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_get_users_done, req); -} - -static void sdap_get_users_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_users_state *state = tevent_req_data(req, - struct sdap_get_users_state); - int ret; - - DEBUG(9, ("Saving %d Users - Done\n", state->count)); - - ret = sdap_save_users_recv(subreq, state, &state->higher_timestamp); - talloc_zfree(subreq); - if (ret) { - DEBUG(2, ("Failed to store users.\n")); - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -int sdap_get_users_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, char **timestamp) -{ - struct sdap_get_users_state *state = tevent_req_data(req, - struct sdap_get_users_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - if (timestamp) { - *timestamp = talloc_steal(mem_ctx, state->higher_timestamp); - } - - return EOK; -} - -/* ==Group-Parsing Routines=============================================== */ - -struct sdap_orig_entry_state { - int done; -}; - -static void sdap_find_entry_by_origDN_done(struct tevent_req *req) -{ - struct sdap_orig_entry_state *state = tevent_req_callback_data(req, - struct sdap_orig_entry_state); - state->done = 1; -} - -/* WARNING: this is a sync routine for now */ -static int sdap_find_entry_by_origDN(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *orig_dn, - char **localdn) -{ - struct tevent_req *req; - struct sdap_orig_entry_state *state; - static const char *attrs[] = { NULL }; - struct ldb_dn *base_dn; - char *filter; - struct ldb_message **msgs; - size_t num_msgs; - int ret; - - state = talloc_zero(memctx, struct sdap_orig_entry_state); - if (!state) { - ret = ENOMEM; - goto done; - } - - filter = talloc_asprintf(state, "%s=%s", SYSDB_ORIG_DN, orig_dn); - if (!filter) { - ret = ENOMEM; - goto done; - } - - base_dn = sysdb_domain_dn(sysdb_handle_get_ctx(handle), - state, domain->name); - if (!base_dn) { - ret = ENOMEM; - goto done; - } - - req = sysdb_search_entry_send(state, ev, handle, base_dn, - LDB_SCOPE_SUBTREE, filter, attrs); - if (!req) { - ret = ENOMEM; - goto done; - } - tevent_req_set_callback(req, sdap_find_entry_by_origDN_done, state); - - /* WARNING: SYNC LOOP HERE */ - tevent_loop_allow_nesting(ev); - while (state->done == 0) { - tevent_loop_once(ev); - } - - ret = sysdb_search_entry_recv(req, state, &num_msgs, &msgs); - if (ret) { - goto done; - } - if (num_msgs != 1) { - ret = ENOENT; - goto done; - } - - *localdn = talloc_strdup(memctx, ldb_dn_get_linearized(msgs[0]->dn)); - if (!*localdn) { - ret = ENOENT; - goto done; - } - - ret = EOK; - -done: - talloc_zfree(state); - return ret; -} - -static int sdap_fill_memberships(struct sysdb_attrs *group_attrs, - struct tevent_context *ev, - struct sysdb_handle *handle, - struct sdap_options *opts, - struct sss_domain_info *domain, - struct ldb_val *values, - int num_values) -{ - struct ldb_message_element *el; - int i, j; - int ret; - - switch (opts->schema_type) { - case SDAP_SCHEMA_RFC2307: - DEBUG(9, ("[RFC2307 Schema]\n")); - - ret = sysdb_attrs_users_from_ldb_vals(group_attrs, SYSDB_MEMBER, - domain->name, - values, num_values); - if (ret) { - goto done; - } - - break; - - case SDAP_SCHEMA_RFC2307BIS: - case SDAP_SCHEMA_IPA_V1: - case SDAP_SCHEMA_AD: - DEBUG(9, ("[IPA or AD Schema]\n")); - - ret = sysdb_attrs_get_el(group_attrs, SYSDB_MEMBER, &el); - if (ret) { - goto done; - } - - /* Just allocate both big enough to contain all members for now */ - el->values = talloc_realloc(el, el->values, struct ldb_val, - el->num_values + num_values); - if (!el->values) { - ret = ENOMEM; - goto done; - } - - for (i = 0, j = el->num_values; i < num_values; i++) { - - /* sync search entry with this as origDN */ - ret = sdap_find_entry_by_origDN(el->values, ev, - handle, domain, - (char *)values[i].data, - (char **)&el->values[j].data); - if (ret != EOK) { - if (ret != ENOENT) { - goto done; - } - - DEBUG(7, (" member #%d (%s): not found!\n", - i, (char *)values[i].data)); - } else { - DEBUG(7, (" member #%d (%s): [%s]\n", - i, (char *)values[i].data, - (char *)el->values[j].data)); - - el->values[j].length = strlen((char *)el->values[j].data); - j++; - } - } - el->num_values = j; - - break; - - default: - DEBUG(0, ("FATAL ERROR: Unhandled schema type! (%d)\n", - opts->schema_type)); - ret = EFAULT; - goto done; - } - - ret = EOK; - -done: - return ret; -} - -/* ==Save-Group-Entry===================================================== */ - -struct sdap_save_group_state { - struct tevent_context *ev; - struct sysdb_handle *handle; - struct sdap_options *opts; - - struct sss_domain_info *dom; - - const char *name; - char *timestamp; -}; - -static void sdap_save_group_done(struct tevent_req *subreq); - - /* FIXME: support non legacy */ - /* FIXME: support storing additional attributes */ - -static struct tevent_req *sdap_save_group_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sysdb_handle *handle, - struct sdap_options *opts, - struct sss_domain_info *dom, - struct sysdb_attrs *attrs, - bool store_members) -{ - struct tevent_req *req, *subreq; - struct sdap_save_group_state *state; - struct ldb_message_element *el; - struct sysdb_attrs *group_attrs; - long int l; - gid_t gid; - int ret; - - req = tevent_req_create(memctx, &state, struct sdap_save_group_state); - if (!req) return NULL; - - state->ev = ev; - state->handle = handle; - state->dom = dom; - state->opts = opts; - state->timestamp = NULL; - - ret = sysdb_attrs_get_el(attrs, - opts->group_map[SDAP_AT_GROUP_NAME].sys_name, &el); - if (ret) goto fail; - if (el->num_values == 0) { - ret = EINVAL; - goto fail; - } - state->name = (const char *)el->values[0].data; - - ret = sysdb_attrs_get_el(attrs, - opts->group_map[SDAP_AT_GROUP_GID].sys_name, &el); - if (ret) goto fail; - if (el->num_values == 0) { - DEBUG(1, ("no gid provided for [%s] in domain [%s].\n", - state->name, dom->name)); - ret = EINVAL; - goto fail; - } - errno = 0; - l = strtol((const char *)el->values[0].data, NULL, 0); - if (errno) { - ret = EINVAL; - goto fail; - } - gid = l; - - /* check that the gid is valid for this domain */ - if (OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) { - DEBUG(2, ("Group [%s] filtered out! (id out of range)\n", - state->name)); - ret = EINVAL; - goto fail; - } - - group_attrs = sysdb_new_attrs(state); - if (!group_attrs) { - ret = ENOMEM; - goto fail; - } - - ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el); - if (ret) { - goto fail; - } - if (el->num_values == 0) { - DEBUG(7, ("Original DN is not available for [%s].\n", state->name)); - } else { - DEBUG(7, ("Adding original DN [%s] to attributes of [%s].\n", - el->values[0].data, state->name)); - ret = sysdb_attrs_add_string(group_attrs, SYSDB_ORIG_DN, - (const char *)el->values[0].data); - if (ret) { - goto fail; - } - } - - ret = sysdb_attrs_get_el(attrs, - opts->group_map[SDAP_AT_GROUP_MODSTAMP].sys_name, &el); - if (ret) { - goto fail; - } - if (el->num_values == 0) { - DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n", - state->name)); - } else { - ret = sysdb_attrs_add_string(group_attrs, - opts->group_map[SDAP_AT_GROUP_MODSTAMP].sys_name, - (const char*)el->values[0].data); - if (ret) { - goto fail; - } - state->timestamp = talloc_strdup(state, - (const char*)el->values[0].data); - if (!state->timestamp) { - ret = ENOMEM; - goto fail; - } - } - - if (store_members) { - ret = sysdb_attrs_get_el(attrs, - opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name, &el); - if (ret != EOK) { - goto fail; - } - if (el->num_values == 0) { - DEBUG(7, ("No members for group [%s]\n", state->name)); - - } else { - DEBUG(7, ("Adding member users to group [%s]\n", state->name)); - - ret = sdap_fill_memberships(group_attrs, ev, handle, opts, dom, - el->values, el->num_values); - if (ret) { - goto fail; - } - } - } - - DEBUG(6, ("Storing info for group %s\n", state->name)); - - subreq = sysdb_store_group_send(state, state->ev, - state->handle, state->dom, - state->name, gid, - group_attrs, - dp_opt_get_int(opts->basic, - SDAP_ENTRY_CACHE_TIMEOUT)); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, sdap_save_group_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void sdap_save_group_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_save_group_state *state = tevent_req_data(req, - struct sdap_save_group_state); - int ret; - - ret = sysdb_store_group_recv(subreq); - talloc_zfree(subreq); - if (ret) { - DEBUG(2, ("Failed to save group %s [%d]\n", state->name, ret)); - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -static int sdap_save_group_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, char **timestamp) -{ - struct sdap_save_group_state *state = tevent_req_data(req, - struct sdap_save_group_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - if ( timestamp ) { - *timestamp = talloc_steal(mem_ctx, state->timestamp); - } - - return EOK; -} - - -/* ==Save-Group-Memebrs=================================================== */ - -struct sdap_save_grpmem_state { - struct tevent_context *ev; - struct sysdb_handle *handle; - struct sdap_options *opts; - - struct sss_domain_info *dom; - - const char *name; -}; - -static void sdap_save_grpmem_done(struct tevent_req *subreq); - - /* FIXME: support non legacy */ - /* FIXME: support storing additional attributes */ - -static struct tevent_req *sdap_save_grpmem_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sysdb_handle *handle, - struct sdap_options *opts, - struct sss_domain_info *dom, - struct sysdb_attrs *attrs) -{ - struct tevent_req *req, *subreq; - struct sdap_save_grpmem_state *state; - struct ldb_message_element *el; - struct sysdb_attrs *group_attrs = NULL; - int ret; - - req = tevent_req_create(memctx, &state, struct sdap_save_grpmem_state); - if (!req) return NULL; - - state->ev = ev; - state->handle = handle; - state->dom = dom; - state->opts = opts; - - ret = sysdb_attrs_get_string(attrs, - opts->group_map[SDAP_AT_GROUP_NAME].sys_name, - &state->name); - if (ret != EOK) { - goto fail; - } - - ret = sysdb_attrs_get_el(attrs, - opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name, &el); - if (ret != EOK) { - goto fail; - } - if (el->num_values == 0) { - DEBUG(7, ("No members for group [%s]\n", state->name)); - - } else { - DEBUG(7, ("Adding member users to group [%s]\n", state->name)); - - group_attrs = sysdb_new_attrs(state); - if (!group_attrs) { - ret = ENOMEM; - goto fail; - } - - ret = sdap_fill_memberships(group_attrs, ev, handle, opts, dom, - el->values, el->num_values); - if (ret) { - goto fail; - } - } - - DEBUG(6, ("Storing members for group %s\n", state->name)); - - subreq = sysdb_store_group_send(state, state->ev, - state->handle, state->dom, - state->name, 0, - group_attrs, - dp_opt_get_int(opts->basic, - SDAP_ENTRY_CACHE_TIMEOUT)); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, sdap_save_grpmem_done, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void sdap_save_grpmem_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_save_grpmem_state *state = tevent_req_data(req, - struct sdap_save_grpmem_state); - int ret; - - ret = sysdb_store_group_recv(subreq); - talloc_zfree(subreq); - if (ret) { - DEBUG(2, ("Failed to save group members for %s [%d]\n", - state->name, ret)); - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -static int sdap_save_grpmem_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - - -/* ==Generic-Function-to-save-multiple-groups============================= */ - -struct sdap_save_groups_state { - struct tevent_context *ev; - struct sysdb_ctx *sysdb; - struct sdap_options *opts; - struct sss_domain_info *dom; - - struct sysdb_attrs **groups; - int count; - int cur; - bool twopass; - - struct sysdb_handle *handle; - - char *higher_timestamp; -}; - -static void sdap_save_groups_trans(struct tevent_req *subreq); -static void sdap_save_groups_save(struct tevent_req *req); -static void sdap_save_groups_loop(struct tevent_req *subreq); -static void sdap_save_groups_mem_save(struct tevent_req *req); -static void sdap_save_groups_mem_loop(struct tevent_req *subreq); -struct tevent_req *sdap_save_groups_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sss_domain_info *dom, - struct sysdb_ctx *sysdb, - struct sdap_options *opts, - struct sysdb_attrs **groups, - int num_groups) -{ - struct tevent_req *req, *subreq; - struct sdap_save_groups_state *state; - - req = tevent_req_create(memctx, &state, struct sdap_save_groups_state); - if (!req) return NULL; - - state->ev = ev; - state->opts = opts; - state->sysdb = sysdb; - state->dom = dom; - state->groups = groups; - state->count = num_groups; - state->cur = 0; - state->handle = NULL; - state->higher_timestamp = NULL; - - switch (opts->schema_type) { - case SDAP_SCHEMA_RFC2307: - state->twopass = false; - break; - - case SDAP_SCHEMA_RFC2307BIS: - case SDAP_SCHEMA_IPA_V1: - case SDAP_SCHEMA_AD: - state->twopass = true; - break; - - default: - tevent_req_error(req, EINVAL); - tevent_req_post(req, ev); - return req; - } - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (!subreq) { - tevent_req_error(req, ENOMEM); - tevent_req_post(req, ev); - return req; - } - tevent_req_set_callback(subreq, sdap_save_groups_trans, req); - - return req; -} - -static void sdap_save_groups_trans(struct tevent_req *subreq) -{ - struct tevent_req *req; - struct sdap_save_groups_state *state; - int ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct sdap_save_groups_state); - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - sdap_save_groups_save(req); -} - -static void sdap_save_groups_save(struct tevent_req *req) -{ - struct tevent_req *subreq; - struct sdap_save_groups_state *state; - - state = tevent_req_data(req, struct sdap_save_groups_state); - - /* if 2 pass savemembers = false */ - subreq = sdap_save_group_send(state, state->ev, state->handle, - state->opts, state->dom, - state->groups[state->cur], - (!state->twopass)); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_save_groups_loop, req); -} - -static void sdap_save_groups_loop(struct tevent_req *subreq) -{ - struct tevent_req *req; - struct sdap_save_groups_state *state; - char *timestamp = NULL; - int ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct sdap_save_groups_state); - - ret = sdap_save_group_recv(subreq, state, ×tamp); - talloc_zfree(subreq); - - /* Do not fail completely on errors. - * Just report the failure to save and go on */ - if (ret) { - DEBUG(2, ("Failed to store group %d. Ignoring.\n", state->cur)); - } else { - DEBUG(9, ("Group %d processed!\n", state->cur)); - } - - if (timestamp) { - if (state->higher_timestamp) { - if (strcmp(timestamp, state->higher_timestamp) > 0) { - talloc_zfree(state->higher_timestamp); - state->higher_timestamp = timestamp; - } else { - talloc_zfree(timestamp); - } - } else { - state->higher_timestamp = timestamp; - } - } - - state->cur++; - if (state->cur < state->count) { - - sdap_save_groups_save(req); - - } else if (state->twopass) { - - state->cur = 0; - sdap_save_groups_mem_save(req); - - } else { - - subreq = sysdb_transaction_commit_send(state, state->ev, - state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - /* sysdb_transaction_complete will call tevent_req_done(req) */ - tevent_req_set_callback(subreq, sysdb_transaction_complete, req); - } -} - -static void sdap_save_groups_mem_save(struct tevent_req *req) -{ - struct tevent_req *subreq; - struct sdap_save_groups_state *state; - - state = tevent_req_data(req, struct sdap_save_groups_state); - - subreq = sdap_save_grpmem_send(state, state->ev, state->handle, - state->opts, state->dom, - state->groups[state->cur]); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_save_groups_mem_loop, req); -} - -static void sdap_save_groups_mem_loop(struct tevent_req *subreq) -{ - struct tevent_req *req; - struct sdap_save_groups_state *state; - int ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct sdap_save_groups_state); - - ret = sdap_save_grpmem_recv(subreq); - talloc_zfree(subreq); - - /* Do not fail completely on errors. - * Just report the failure to save and go on */ - if (ret) { - DEBUG(2, ("Failed to store group %d. Ignoring.\n", state->cur)); - } - - state->cur++; - if (state->cur < state->count) { - - sdap_save_groups_mem_save(req); - - } else { - - subreq = sysdb_transaction_commit_send(state, state->ev, - state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - /* sysdb_transaction_complete will call tevent_req_done(req) */ - tevent_req_set_callback(subreq, sysdb_transaction_complete, req); - } -} - -static int sdap_save_groups_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, char **timestamp) -{ - struct sdap_save_groups_state *state = tevent_req_data(req, - struct sdap_save_groups_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - if (timestamp) { - *timestamp = talloc_steal(mem_ctx, state->higher_timestamp); - } - - return EOK; -} - - -/* ==Search-Groups-with-filter============================================ */ - -struct sdap_get_groups_state { - struct tevent_context *ev; - struct sdap_options *opts; - struct sdap_handle *sh; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - const char **attrs; - const char *filter; - - char *higher_timestamp; - struct sysdb_attrs **groups; - size_t count; -}; - -static void sdap_get_groups_process(struct tevent_req *subreq); -static void sdap_get_groups_done(struct tevent_req *subreq); - -struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sss_domain_info *dom, - struct sysdb_ctx *sysdb, - struct sdap_options *opts, - struct sdap_handle *sh, - const char **attrs, - const char *filter) -{ - struct tevent_req *req, *subreq; - struct sdap_get_groups_state *state; - - req = tevent_req_create(memctx, &state, struct sdap_get_groups_state); - if (!req) return NULL; - - state->ev = ev; - state->opts = opts; - state->dom = dom; - state->sh = sh; - state->sysdb = sysdb; - state->filter = filter; - state->attrs = attrs; - state->higher_timestamp = NULL; - state->groups = NULL; - state->count = 0; - - subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh, - dp_opt_get_string(state->opts->basic, - SDAP_GROUP_SEARCH_BASE), - LDAP_SCOPE_SUBTREE, - state->filter, state->attrs, - state->opts->group_map, SDAP_OPTS_GROUP); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, sdap_get_groups_process, req); - - return req; -} - -static void sdap_get_groups_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_groups_state *state = tevent_req_data(req, - struct sdap_get_groups_state); - int ret; - - ret = sdap_get_generic_recv(subreq, state, - &state->count, &state->groups); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - DEBUG(6, ("Search for groups, returned %d results.\n", state->count)); - - if (state->count == 0) { - tevent_req_error(req, ENOENT); - return; - } - - subreq = sdap_save_groups_send(state, state->ev, state->dom, - state->sysdb, state->opts, - state->groups, state->count); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_get_groups_done, req); -} - -static void sdap_get_groups_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_groups_state *state = tevent_req_data(req, - struct sdap_get_groups_state); - int ret; - - DEBUG(9, ("Saving %d Groups - Done\n", state->count)); - - ret = sdap_save_groups_recv(subreq, state, &state->higher_timestamp); - talloc_zfree(subreq); - if (ret) { - DEBUG(2, ("Failed to store groups.\n")); - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -int sdap_get_groups_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, char **timestamp) -{ - struct sdap_get_groups_state *state = tevent_req_data(req, - struct sdap_get_groups_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - if (timestamp) { - *timestamp = talloc_steal(mem_ctx, state->higher_timestamp); - } - - return EOK; -} - - -/* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307-Classic/BIS========= */ - -struct sdap_initgr_rfc2307_state { - struct tevent_context *ev; - struct sysdb_ctx *sysdb; - struct sdap_options *opts; - struct sss_domain_info *dom; - struct sdap_handle *sh; - - struct sdap_op *op; -}; - -static void sdap_initgr_rfc2307_process(struct tevent_req *subreq); -static void sdap_initgr_rfc2307_done(struct tevent_req *subreq); -struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_options *opts, - struct sysdb_ctx *sysdb, - struct sss_domain_info *dom, - struct sdap_handle *sh, - const char *base_dn, - const char *name, - const char **grp_attrs) -{ - struct tevent_req *req, *subreq; - struct sdap_initgr_rfc2307_state *state; - const char *filter; - - req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state); - if (!req) return NULL; - - state->ev = ev; - state->opts = opts; - state->sysdb = sysdb; - state->dom = dom; - state->sh = sh; - state->op = NULL; - - filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))", - opts->group_map[SDAP_AT_GROUP_MEMBER].name, - name, opts->group_map[SDAP_OC_GROUP].name); - if (!filter) { - talloc_zfree(req); - return NULL; - } - - subreq = sdap_get_generic_send(state, state->ev, state->opts, - state->sh, base_dn, LDAP_SCOPE_SUBTREE, - filter, grp_attrs, - state->opts->group_map, SDAP_OPTS_GROUP); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, sdap_initgr_rfc2307_process, req); - - return req; -} - -static void sdap_initgr_rfc2307_process(struct tevent_req *subreq) -{ - struct tevent_req *req; - struct sdap_initgr_rfc2307_state *state; - struct sysdb_attrs **groups; - size_t count; - int ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct sdap_initgr_rfc2307_state); - - ret = sdap_get_generic_recv(subreq, state, &count, &groups); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - if (count == 0) { - tevent_req_done(req); - return; - } - - subreq = sdap_save_groups_send(state, state->ev, state->dom, - state->sysdb, state->opts, - groups, count); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_initgr_rfc2307_done, req); -} - -static void sdap_initgr_rfc2307_done(struct tevent_req *subreq) -{ - struct tevent_req *req; - int ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); - - ret = sdap_save_groups_recv(subreq, NULL, NULL); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -static int sdap_initgr_rfc2307_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - - -/* ==Initgr-call-(groups-a-user-is-member-of)-nested-groups=============== */ - -struct sdap_initgr_nested_state { - struct tevent_context *ev; - struct sysdb_ctx *sysdb; - struct sdap_options *opts; - struct sss_domain_info *dom; - struct sdap_handle *sh; - - const char **grp_attrs; - - char *filter; - char **group_dns; - int count; - int cur; - - struct sdap_op *op; - - struct sysdb_attrs **groups; - int groups_cur; -}; - -static void sdap_initgr_nested_search(struct tevent_req *subreq); -static void sdap_initgr_nested_store(struct tevent_req *req); -static void sdap_initgr_nested_done(struct tevent_req *subreq); -static struct tevent_req *sdap_initgr_nested_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_options *opts, - struct sysdb_ctx *sysdb, - struct sss_domain_info *dom, - struct sdap_handle *sh, - struct sysdb_attrs *user, - const char **grp_attrs) -{ - struct tevent_req *req, *subreq; - struct sdap_initgr_nested_state *state; - struct ldb_message_element *el; - int i, ret; - - req = tevent_req_create(memctx, &state, struct sdap_initgr_nested_state); - if (!req) return NULL; - - state->ev = ev; - state->opts = opts; - state->sysdb = sysdb; - state->dom = dom; - state->sh = sh; - state->grp_attrs = grp_attrs; - state->op = NULL; - - state->filter = talloc_asprintf(state, "(objectclass=%s)", - opts->group_map[SDAP_OC_GROUP].name); - if (!state->filter) { - talloc_zfree(req); - return NULL; - } - - /* TODO: test rootDSE for deref support and use it if available */ - /* TODO: or test rootDSE for ASQ support and use it if available */ - - ret = sysdb_attrs_get_el(user, SYSDB_MEMBEROF, &el); - if (ret || !el || el->num_values == 0) { - DEBUG(4, ("User entry lacks original memberof ?\n")); - /* user with no groups ? */ - tevent_req_error(req, ENOENT); - tevent_req_post(req, ev); - } - state->count = el->num_values; - - state->groups = talloc_zero_array(state, struct sysdb_attrs *, - state->count + 1);; - if (!state->groups) { - talloc_zfree(req); - return NULL; - } - state->groups_cur = 0; - - state->group_dns = talloc_array(state, char *, state->count + 1); - if (!state->group_dns) { - talloc_zfree(req); - return NULL; - } - for (i = 0; i < state->count; i++) { - state->group_dns[i] = talloc_strdup(state->group_dns, - (char *)el->values[i].data); - if (!state->group_dns[i]) { - talloc_zfree(req); - return NULL; - } - } - state->group_dns[i] = NULL; /* terminate */ - state->cur = 0; - - subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh, - state->group_dns[state->cur], - LDAP_SCOPE_BASE, - state->filter, state->grp_attrs, - state->opts->group_map, SDAP_OPTS_GROUP); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, sdap_initgr_nested_search, req); - - return req; -} - -static void sdap_initgr_nested_search(struct tevent_req *subreq) -{ - struct tevent_req *req; - struct sdap_initgr_nested_state *state; - struct sysdb_attrs **groups; - size_t count; - int ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct sdap_initgr_nested_state); - - ret = sdap_get_generic_recv(subreq, state, &count, &groups); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - if (count == 1) { - state->groups[state->groups_cur] = groups[0]; - state->groups_cur++; - } else { - DEBUG(2, ("Search for group %s, returned %d results. Skipping\n", - state->group_dns[state->cur], count)); - } - - state->cur++; - if (state->cur < state->count) { - subreq = sdap_get_generic_send(state, state->ev, - state->opts, state->sh, - state->group_dns[state->cur], - LDAP_SCOPE_BASE, - state->filter, state->grp_attrs, - state->opts->group_map, - SDAP_OPTS_GROUP); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_initgr_nested_search, req); - } else { - sdap_initgr_nested_store(req); - } -} - -static void sdap_initgr_nested_store(struct tevent_req *req) -{ - struct tevent_req *subreq; - struct sdap_initgr_nested_state *state; - - state = tevent_req_data(req, struct sdap_initgr_nested_state); - - subreq = sdap_save_groups_send(state, state->ev, state->dom, - state->sysdb, state->opts, - state->groups, state->groups_cur); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_initgr_nested_done, req); -} - -static void sdap_initgr_nested_done(struct tevent_req *subreq) -{ - struct tevent_req *req; - int ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); - - ret = sdap_save_groups_recv(subreq, NULL, NULL); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -static int sdap_initgr_nested_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - - -/* ==Initgr-call-(groups-a-user-is-member-of)============================= */ - -struct sdap_get_initgr_state { - struct tevent_context *ev; - struct sysdb_ctx *sysdb; - struct sdap_options *opts; - struct sss_domain_info *dom; - struct sdap_handle *sh; - const char *name; - const char **grp_attrs; - - struct sysdb_attrs *orig_user; - - struct sysdb_handle *handle; -}; - -static void sdap_get_initgr_user(struct tevent_req *subreq); -static void sdap_get_initgr_store(struct tevent_req *subreq); -static void sdap_get_initgr_commit(struct tevent_req *subreq); -static void sdap_get_initgr_process(struct tevent_req *subreq); -static void sdap_get_initgr_done(struct tevent_req *subreq); - -struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sss_domain_info *dom, - struct sysdb_ctx *sysdb, - struct sdap_options *opts, - struct sdap_handle *sh, - const char *name, - const char **grp_attrs) -{ - struct tevent_req *req, *subreq; - struct sdap_get_initgr_state *state; - const char *base_dn; - char *filter; - const char **attrs; - int ret; - - DEBUG(9, ("Retrieving info for initgroups call\n")); - - req = tevent_req_create(memctx, &state, struct sdap_get_initgr_state); - if (!req) return NULL; - - state->ev = ev; - state->opts = opts; - state->sysdb = sysdb; - state->dom = dom; - state->sh = sh; - state->name = name; - state->grp_attrs = grp_attrs; - state->orig_user = NULL; - - filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))", - state->opts->user_map[SDAP_AT_USER_NAME].name, - state->name, - state->opts->user_map[SDAP_OC_USER].name); - if (!filter) { - talloc_zfree(req); - return NULL; - } - - base_dn = dp_opt_get_string(state->opts->basic, - SDAP_USER_SEARCH_BASE); - if (!base_dn) { - talloc_zfree(req); - return NULL; - } - - ret = build_attrs_from_map(state, state->opts->user_map, - SDAP_OPTS_USER, &attrs); - if (ret) { - talloc_zfree(req); - return NULL; - } - - subreq = sdap_get_generic_send(state, state->ev, - state->opts, state->sh, - base_dn, LDAP_SCOPE_SUBTREE, - filter, attrs, - state->opts->user_map, SDAP_OPTS_USER); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, sdap_get_initgr_user, req); - - return req; -} - -static void sdap_get_initgr_user(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_initgr_state *state = tevent_req_data(req, - struct sdap_get_initgr_state); - struct sysdb_attrs **usr_attrs; - size_t count; - int ret; - - DEBUG(9, ("Receiving info for the user\n")); - - ret = sdap_get_generic_recv(subreq, state, &count, &usr_attrs); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - if (count != 1) { - DEBUG(2, ("Expected one user entry and got %d\n", count)); - tevent_req_error(req, ENOENT); - return; - } - - state->orig_user = usr_attrs[0]; - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_get_initgr_store, req); -} - -static void sdap_get_initgr_store(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_initgr_state *state = tevent_req_data(req, - struct sdap_get_initgr_state); - int ret; - - DEBUG(9, ("Storing the user\n")); - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - subreq = sdap_save_user_send(state, state->ev, state->handle, - state->opts, state->dom, - state->orig_user, true); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_get_initgr_commit, req); -} - -static void sdap_get_initgr_commit(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_initgr_state *state = tevent_req_data(req, - struct sdap_get_initgr_state); - int ret; - - DEBUG(9, ("Commit change\n")); - - ret = sdap_save_user_recv(subreq, NULL, NULL); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_get_initgr_process, req); -} - -static void sdap_get_initgr_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_initgr_state *state = tevent_req_data(req, - struct sdap_get_initgr_state); - int ret; - - DEBUG(9, ("Process user's groups\n")); - - ret = sysdb_transaction_commit_recv(subreq); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - switch (state->opts->schema_type) { - case SDAP_SCHEMA_RFC2307: - subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts, - state->sysdb, state->dom, state->sh, - dp_opt_get_string(state->opts->basic, - SDAP_GROUP_SEARCH_BASE), - state->name, state->grp_attrs); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_get_initgr_done, req); - break; - - case SDAP_SCHEMA_RFC2307BIS: - case SDAP_SCHEMA_IPA_V1: - case SDAP_SCHEMA_AD: - /* TODO: AD uses a different member/memberof schema - * We need an AD specific call that is able to unroll - * nested groups by doing extensive recursive searches */ - - subreq = sdap_initgr_nested_send(state, state->ev, state->opts, - state->sysdb, state->dom, state->sh, - state->orig_user, state->grp_attrs); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_get_initgr_done, req); - return; - - default: - tevent_req_error(req, EINVAL); - return; - } -} - -static void sdap_get_initgr_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_initgr_state *state = tevent_req_data(req, - struct sdap_get_initgr_state); - int ret; - - DEBUG(9, ("Initgroups done\n")); - - switch (state->opts->schema_type) { - case SDAP_SCHEMA_RFC2307: - - ret = sdap_initgr_rfc2307_recv(subreq); - break; - - case SDAP_SCHEMA_RFC2307BIS: - case SDAP_SCHEMA_IPA_V1: - case SDAP_SCHEMA_AD: - - ret = sdap_initgr_nested_recv(subreq); - break; - - default: - - ret = EINVAL; - break; - } - - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -int sdap_get_initgr_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - diff --git a/server/providers/ldap/sdap_async_connection.c b/server/providers/ldap/sdap_async_connection.c deleted file mode 100644 index 18e47d3b7..000000000 --- a/server/providers/ldap/sdap_async_connection.c +++ /dev/null @@ -1,1141 +0,0 @@ -/* - SSSD - - Async LDAP Helper routines - - Copyright (C) Simo Sorce - 2009 - - 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 "util/util.h" -#include "util/sss_krb5.h" -#include "providers/ldap/sdap_async_private.h" - -#define LDAP_X_SSSD_PASSWORD_EXPIRED 0x555D - -/* ==Connect-to-LDAP-Server=============================================== */ - -struct sdap_connect_state { - struct tevent_context *ev; - struct sdap_options *opts; - struct sdap_handle *sh; - - struct sdap_op *op; - - struct sdap_msg *reply; - int result; -}; - -static void sdap_connect_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt); - -struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_options *opts, - const char *uri, - bool use_start_tls) -{ - struct tevent_req *req; - struct sdap_connect_state *state; - struct timeval tv; - int ver; - int lret; - int ret = EOK; - int msgid; - bool ldap_referrals; - - req = tevent_req_create(memctx, &state, struct sdap_connect_state); - if (!req) return NULL; - - state->reply = talloc(state, struct sdap_msg); - if (!state->reply) { - talloc_zfree(req); - return NULL; - } - - state->ev = ev; - state->opts = opts; - state->sh = sdap_handle_create(state); - if (!state->sh) { - talloc_zfree(req); - return NULL; - } - /* Initialize LDAP handler */ - lret = ldap_initialize(&state->sh->ldap, uri); - if (lret != LDAP_SUCCESS) { - DEBUG(1, ("ldap_initialize failed: %s\n", ldap_err2string(lret))); - goto fail; - } - - /* Force ldap version to 3 */ - ver = LDAP_VERSION3; - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_PROTOCOL_VERSION, &ver); - if (lret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("Failed to set ldap version to 3\n")); - goto fail; - } - - /* Set Network Timeout */ - tv.tv_sec = dp_opt_get_int(opts->basic, SDAP_NETWORK_TIMEOUT); - tv.tv_usec = 0; - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_NETWORK_TIMEOUT, &tv); - if (lret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("Failed to set network timeout to %d\n", - dp_opt_get_int(opts->basic, SDAP_NETWORK_TIMEOUT))); - goto fail; - } - - /* Set Default Timeout */ - tv.tv_sec = dp_opt_get_int(opts->basic, SDAP_OPT_TIMEOUT); - tv.tv_usec = 0; - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_TIMEOUT, &tv); - if (lret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("Failed to set default timeout to %d\n", - dp_opt_get_int(opts->basic, SDAP_OPT_TIMEOUT))); - goto fail; - } - - /* Set Referral chasing */ - ldap_referrals = dp_opt_get_bool(opts->basic, SDAP_REFERRALS); - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_REFERRALS, - (ldap_referrals ? LDAP_OPT_ON : LDAP_OPT_OFF)); - if (lret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("Failed to set referral chasing to %s\n", - (ldap_referrals ? "LDAP_OPT_ON" : "LDAP_OPT_OFF"))); - goto fail; - } - -#ifdef HAVE_LDAP_CONNCB - struct ldap_cb_data *cb_data; - - /* add connection callback */ - state->sh->conncb = talloc_zero(state->sh, struct ldap_conncb); - if (state->sh->conncb == NULL) { - DEBUG(1, ("talloc_zero failed.\n")); - ret = ENOMEM; - goto fail; - } - - cb_data = talloc_zero(state->sh->conncb, struct ldap_cb_data); - if (cb_data == NULL) { - DEBUG(1, ("talloc_zero failed.\n")); - ret = ENOMEM; - goto fail; - } - cb_data->sh = state->sh; - cb_data->ev = state->ev; - - state->sh->conncb->lc_add = sdap_ldap_connect_callback_add; - state->sh->conncb->lc_del = sdap_ldap_connect_callback_del; - state->sh->conncb->lc_arg = cb_data; - - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_CONNECT_CB, - state->sh->conncb); - if (lret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("Failed to set connection callback\n")); - goto fail; - } -#endif - - /* if we do not use start_tls the connection is not really connected yet - * just fake an async procedure and leave connection to the bind call */ - if (!use_start_tls) { - tevent_req_post(req, ev); - return req; - } - - DEBUG(4, ("Executing START TLS\n")); - - lret = ldap_start_tls(state->sh->ldap, NULL, NULL, &msgid); - if (lret != LDAP_SUCCESS) { - DEBUG(3, ("ldap_start_tls failed: [%s]", ldap_err2string(ret))); - goto fail; - } - - state->sh->connected = true; -#ifndef HAVE_LDAP_CONNCB - ret = sdap_install_ldap_callbacks(state->sh, state->ev); - if (ret) goto fail; -#endif - - /* FIXME: get timeouts from configuration, for now 5 secs. */ - ret = sdap_op_add(state, ev, state->sh, msgid, - sdap_connect_done, req, 5, &state->op); - if (ret) { - DEBUG(1, ("Failed to set up operation!\n")); - goto fail; - } - - return req; - -fail: - if (ret) { - tevent_req_error(req, ret); - } else { - if (lret == LDAP_SERVER_DOWN) { - tevent_req_error(req, ETIMEDOUT); - } else { - tevent_req_error(req, EIO); - } - } - tevent_req_post(req, ev); - return req; -} - -static void sdap_connect_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct sdap_connect_state *state = tevent_req_data(req, - struct sdap_connect_state); - char *errmsg; - int ret; - - if (error) { - tevent_req_error(req, error); - return; - } - - state->reply = talloc_steal(state, reply); - - ret = ldap_parse_result(state->sh->ldap, state->reply->msg, - &state->result, NULL, &errmsg, NULL, NULL, 0); - if (ret != LDAP_SUCCESS) { - DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid)); - tevent_req_error(req, EIO); - return; - } - - DEBUG(3, ("START TLS result: %s(%d), %s\n", - ldap_err2string(state->result), state->result, errmsg)); - - if (ldap_tls_inplace(state->sh->ldap)) { - DEBUG(9, ("SSL/TLS handler already in place.\n")); - tevent_req_done(req); - return; - } - -/* FIXME: take care that ldap_install_tls might block */ - ret = ldap_install_tls(state->sh->ldap); - if (ret != LDAP_SUCCESS) { - DEBUG(1, ("ldap_install_tls failed: [%d][%s]\n", ret, - ldap_err2string(ret))); - state->result = ret; - tevent_req_error(req, EIO); - return; - } - - tevent_req_done(req); -} - -int sdap_connect_recv(struct tevent_req *req, - TALLOC_CTX *memctx, - struct sdap_handle **sh) -{ - struct sdap_connect_state *state = tevent_req_data(req, - struct sdap_connect_state); - enum tevent_req_state tstate; - uint64_t err = EIO; - - if (tevent_req_is_error(req, &tstate, &err)) { - /* if tstate shows in progress, it is because - * we did not ask to perform tls, just pretend all is fine */ - if (tstate != TEVENT_REQ_IN_PROGRESS) { - return err; - } - } - - *sh = talloc_steal(memctx, state->sh); - if (!*sh) { - return ENOMEM; - } - return EOK; -} - -/* ==Simple-Bind========================================================== */ - -struct simple_bind_state { - struct tevent_context *ev; - struct sdap_handle *sh; - const char *user_dn; - struct berval *pw; - - struct sdap_op *op; - - struct sdap_msg *reply; - int result; -}; - -static void simple_bind_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt); - -static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_handle *sh, - const char *user_dn, - struct berval *pw) -{ - struct tevent_req *req; - struct simple_bind_state *state; - int ret = EOK; - int msgid; - int ldap_err; - LDAPControl *request_controls[2]; - - req = tevent_req_create(memctx, &state, struct simple_bind_state); - if (!req) return NULL; - - state->reply = talloc(state, struct sdap_msg); - if (!state->reply) { - talloc_zfree(req); - return NULL; - } - - state->ev = ev; - state->sh = sh; - state->user_dn = user_dn; - state->pw = pw; - - ret = sss_ldap_control_create(LDAP_CONTROL_PASSWORDPOLICYREQUEST, - 0, NULL, 0, &request_controls[0]); - if (ret != LDAP_SUCCESS) { - DEBUG(1, ("sss_ldap_control_create failed.\n")); - goto fail; - } - request_controls[1] = NULL; - - DEBUG(4, ("Executing simple bind as: %s\n", state->user_dn)); - - ret = ldap_sasl_bind(state->sh->ldap, state->user_dn, LDAP_SASL_SIMPLE, - state->pw, request_controls, NULL, &msgid); - ldap_control_free(request_controls[0]); - if (ret == -1 || msgid == -1) { - ret = ldap_get_option(state->sh->ldap, - LDAP_OPT_RESULT_CODE, &ldap_err); - if (ret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("ldap_bind failed (couldn't get ldap error)\n")); - ret = LDAP_LOCAL_ERROR; - } else { - DEBUG(1, ("ldap_bind failed (%d)[%s]\n", - ldap_err, ldap_err2string(ldap_err))); - ret = ldap_err; - } - goto fail; - } - DEBUG(8, ("ldap simple bind sent, msgid = %d\n", msgid)); - - if (!sh->connected) { - sh->connected = true; -#ifndef HAVE_LDAP_CONNCB - ret = sdap_install_ldap_callbacks(sh, ev); - if (ret) goto fail; -#endif - } - - /* FIXME: get timeouts from configuration, for now 5 secs. */ - ret = sdap_op_add(state, ev, sh, msgid, - simple_bind_done, req, 5, &state->op); - if (ret) { - DEBUG(1, ("Failed to set up operation!\n")); - goto fail; - } - - return req; - -fail: - if (ret == LDAP_SERVER_DOWN) { - tevent_req_error(req, ETIMEDOUT); - } else { - tevent_req_error(req, EIO); - } - tevent_req_post(req, ev); - return req; -} - -static void simple_bind_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct simple_bind_state *state = tevent_req_data(req, - struct simple_bind_state); - char *errmsg; - int ret; - LDAPControl **response_controls; - int c; - ber_int_t pp_grace; - ber_int_t pp_expire; - LDAPPasswordPolicyError pp_error; - - if (error) { - tevent_req_error(req, error); - return; - } - - state->reply = talloc_steal(state, reply); - - ret = ldap_parse_result(state->sh->ldap, state->reply->msg, - &state->result, NULL, &errmsg, NULL, - &response_controls, 0); - if (ret != LDAP_SUCCESS) { - DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid)); - ret = EIO; - goto done; - } - - if (response_controls == NULL) { - DEBUG(5, ("Server returned no controls.\n")); - } else { - for (c = 0; response_controls[c] != NULL; c++) { - DEBUG(9, ("Server returned control [%s].\n", - response_controls[c]->ldctl_oid)); - if (strcmp(response_controls[c]->ldctl_oid, - LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) { - ret = ldap_parse_passwordpolicy_control(state->sh->ldap, - response_controls[c], - &pp_expire, &pp_grace, - &pp_error); - if (ret != LDAP_SUCCESS) { - DEBUG(1, ("ldap_parse_passwordpolicy_control failed.\n")); - ret = EIO; - goto done; - } - - DEBUG(7, ("Password Policy Response: expire [%d] grace [%d] " - "error [%s].\n", pp_expire, pp_grace, - ldap_passwordpolicy_err2txt(pp_error))); - - if (state->result == LDAP_SUCCESS && - (pp_error == PP_changeAfterReset || pp_grace > 0)) { - DEBUG(4, ("User must set a new password.\n")); - state->result = LDAP_X_SSSD_PASSWORD_EXPIRED; - } - } - } - } - - DEBUG(3, ("Bind result: %s(%d), %s\n", - ldap_err2string(state->result), state->result, errmsg)); - - ret = LDAP_SUCCESS; -done: - ldap_controls_free(response_controls); - - if (ret == LDAP_SUCCESS) { - tevent_req_done(req); - } else { - tevent_req_error(req, ret); - } -} - -static int simple_bind_recv(struct tevent_req *req, int *ldaperr) -{ - struct simple_bind_state *state = tevent_req_data(req, - struct simple_bind_state); - - *ldaperr = LDAP_OTHER; - TEVENT_REQ_RETURN_ON_ERROR(req); - - *ldaperr = state->result; - return EOK; -} - -/* ==SASL-Bind============================================================ */ - -struct sasl_bind_state { - struct tevent_context *ev; - struct sdap_handle *sh; - - const char *sasl_mech; - const char *sasl_user; - struct berval *sasl_cred; - - int result; -}; - -static int sdap_sasl_interact(LDAP *ld, unsigned flags, - void *defaults, void *interact); - -static struct tevent_req *sasl_bind_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_handle *sh, - const char *sasl_mech, - const char *sasl_user, - struct berval *sasl_cred) -{ - struct tevent_req *req; - struct sasl_bind_state *state; - int ret = EOK; - - req = tevent_req_create(memctx, &state, struct sasl_bind_state); - if (!req) return NULL; - - state->ev = ev; - state->sh = sh; - state->sasl_mech = sasl_mech; - state->sasl_user = sasl_user; - state->sasl_cred = sasl_cred; - - DEBUG(4, ("Executing sasl bind mech: %s, user: %s\n", - sasl_mech, sasl_user)); - - /* FIXME: Warning, this is a sync call! - * No async variant exist in openldap libraries yet */ - - ret = ldap_sasl_interactive_bind_s(state->sh->ldap, NULL, - sasl_mech, NULL, NULL, - LDAP_SASL_QUIET, - (*sdap_sasl_interact), state); - state->result = ret; - if (ret != LDAP_SUCCESS) { - DEBUG(1, ("ldap_sasl_bind failed (%d)[%s]\n", - ret, ldap_err2string(ret))); - goto fail; - } - - if (!sh->connected) { - sh->connected = true; -#ifndef HAVE_LDAP_CONNCB - ret = sdap_install_ldap_callbacks(sh, ev); - if (ret) goto fail; -#endif - } - - tevent_req_post(req, ev); - return req; - -fail: - if (ret == LDAP_SERVER_DOWN) { - tevent_req_error(req, ETIMEDOUT); - } else { - tevent_req_error(req, EIO); - } - tevent_req_post(req, ev); - return req; -} - -static int sdap_sasl_interact(LDAP *ld, unsigned flags, - void *defaults, void *interact) -{ - struct sasl_bind_state *state = talloc_get_type(defaults, - struct sasl_bind_state); - sasl_interact_t *in = (sasl_interact_t *)interact; - - if (!ld) return LDAP_PARAM_ERROR; - - while (in->id != SASL_CB_LIST_END) { - - switch (in->id) { - case SASL_CB_GETREALM: - case SASL_CB_AUTHNAME: - case SASL_CB_PASS: - if (in->defresult) { - in->result = in->defresult; - } else { - in->result = ""; - } - in->len = strlen(in->result); - break; - case SASL_CB_USER: - if (state->sasl_user) { - in->result = state->sasl_user; - } else if (in->defresult) { - in->result = in->defresult; - } else { - in->result = ""; - } - in->len = strlen(in->result); - break; - case SASL_CB_NOECHOPROMPT: - case SASL_CB_ECHOPROMPT: - goto fail; - } - - in++; - } - - return LDAP_SUCCESS; - -fail: - return LDAP_UNAVAILABLE; -} - -static int sasl_bind_recv(struct tevent_req *req, int *ldaperr) -{ - struct sasl_bind_state *state = tevent_req_data(req, - struct sasl_bind_state); - enum tevent_req_state tstate; - uint64_t err = EIO; - - if (tevent_req_is_error(req, &tstate, &err)) { - if (tstate != TEVENT_REQ_IN_PROGRESS) { - *ldaperr = LDAP_OTHER; - return err; - } - } - - *ldaperr = state->result; - return EOK; -} - -/* ==Perform-Kinit-given-keytab-and-principal============================= */ - -struct sdap_kinit_state { - int result; -}; - -static void sdap_kinit_done(struct tevent_req *subreq); - -struct tevent_req *sdap_kinit_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_handle *sh, - int timeout, - const char *keytab, - const char *principal, - const char *realm) -{ - struct tevent_req *req; - struct tevent_req *subreq; - struct sdap_kinit_state *state; - int ret; - - DEBUG(6, ("Attempting kinit (%s, %s, %s)\n", keytab, principal, realm)); - - req = tevent_req_create(memctx, &state, struct sdap_kinit_state); - if (!req) return NULL; - - state->result = SDAP_AUTH_FAILED; - - if (keytab) { - ret = setenv("KRB5_KTNAME", keytab, 1); - if (ret == -1) { - DEBUG(2, ("Failed to set KRB5_KTNAME to %s\n", keytab)); - return NULL; - } - } - - subreq = sdap_get_tgt_send(state, ev, realm, principal, keytab, timeout); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, sdap_kinit_done, req); - - return req; -} - -static void sdap_kinit_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_kinit_state *state = tevent_req_data(req, - struct sdap_kinit_state); - - int ret; - int result; - char *ccname = NULL; - - ret = sdap_get_tgt_recv(subreq, state, &result, &ccname); - talloc_zfree(subreq); - if (ret != EOK) { - state->result = SDAP_AUTH_FAILED; - DEBUG(1, ("child failed (%d [%s])\n", ret, strerror(ret))); - tevent_req_error(req, ret); - return; - } - - if (result == EOK) { - ret = setenv("KRB5CCNAME", ccname, 1); - if (ret == -1) { - DEBUG(2, ("Unable to set env. variable KRB5CCNAME!\n")); - state->result = SDAP_AUTH_FAILED; - tevent_req_error(req, EFAULT); - } - - state->result = SDAP_AUTH_SUCCESS; - tevent_req_done(req); - return; - } - - DEBUG(4, ("Could not get TGT: %d [%s]\n", result, strerror(result))); - state->result = SDAP_AUTH_FAILED; - tevent_req_error(req, EIO); -} - -int sdap_kinit_recv(struct tevent_req *req, enum sdap_result *result) -{ - struct sdap_kinit_state *state = tevent_req_data(req, - struct sdap_kinit_state); - enum tevent_req_state tstate; - uint64_t err = EIO; - - if (tevent_req_is_error(req, &tstate, &err)) { - if (tstate != TEVENT_REQ_IN_PROGRESS) { - *result = SDAP_ERROR; - return err; - } - } - - *result = state->result; - return EOK; -} - - -/* ==Authenticaticate-User-by-DN========================================== */ - -struct sdap_auth_state { - const char *user_dn; - struct berval pw; - - int result; - bool is_sasl; -}; - -static void sdap_auth_done(struct tevent_req *subreq); - -/* TODO: handle sasl_cred */ -struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_handle *sh, - const char *sasl_mech, - const char *sasl_user, - const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok) -{ - struct tevent_req *req, *subreq; - struct sdap_auth_state *state; - - if (authtok_type != NULL && strcasecmp(authtok_type,"password") != 0) { - DEBUG(1,("Authentication token type [%s] is not supported")); - return NULL; - } - - req = tevent_req_create(memctx, &state, struct sdap_auth_state); - if (!req) return NULL; - - state->user_dn = user_dn; - state->pw.bv_val = (char *)authtok.data; - state->pw.bv_len = authtok.length; - - if (sasl_mech) { - state->is_sasl = true; - subreq = sasl_bind_send(state, ev, sh, sasl_mech, sasl_user, NULL); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return tevent_req_post(req, ev); - } - } else { - state->is_sasl = false; - subreq = simple_bind_send(state, ev, sh, user_dn, &state->pw); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return tevent_req_post(req, ev); - } - } - - tevent_req_set_callback(subreq, sdap_auth_done, req); - return req; -} - -static void sdap_auth_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_auth_state *state = tevent_req_data(req, - struct sdap_auth_state); - int ret; - - if (state->is_sasl) { - ret = sasl_bind_recv(subreq, &state->result); - } else { - ret = simple_bind_recv(subreq, &state->result); - } - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -int sdap_auth_recv(struct tevent_req *req, enum sdap_result *result) -{ - struct sdap_auth_state *state = tevent_req_data(req, - struct sdap_auth_state); - - *result = SDAP_ERROR; - TEVENT_REQ_RETURN_ON_ERROR(req); - - switch (state->result) { - case LDAP_SUCCESS: - *result = SDAP_AUTH_SUCCESS; - break; - case LDAP_INVALID_CREDENTIALS: - *result = SDAP_AUTH_FAILED; - break; - case LDAP_X_SSSD_PASSWORD_EXPIRED: - *result = SDAP_AUTH_PW_EXPIRED; - break; - default: - break; - } - - return EOK; -} - -/* ==Client connect============================================ */ - -struct sdap_cli_connect_state { - struct tevent_context *ev; - struct sdap_options *opts; - struct sdap_service *service; - - bool use_rootdse; - struct sysdb_attrs *rootdse; - - struct sdap_handle *sh; - - struct fo_server *srv; -}; - -static void sdap_cli_resolve_done(struct tevent_req *subreq); -static void sdap_cli_connect_done(struct tevent_req *subreq); -static void sdap_cli_rootdse_step(struct tevent_req *req); -static void sdap_cli_rootdse_done(struct tevent_req *subreq); -static void sdap_cli_kinit_step(struct tevent_req *req); -static void sdap_cli_kinit_done(struct tevent_req *subreq); -static void sdap_cli_auth_step(struct tevent_req *req); -static void sdap_cli_auth_done(struct tevent_req *subreq); - -struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_options *opts, - struct be_ctx *be, - struct sdap_service *service, - struct sysdb_attrs **rootdse) -{ - struct tevent_req *req, *subreq; - struct sdap_cli_connect_state *state; - - req = tevent_req_create(memctx, &state, struct sdap_cli_connect_state); - if (!req) return NULL; - - state->ev = ev; - state->opts = opts; - state->service = service; - state->srv = NULL; - - if (rootdse) { - state->use_rootdse = true; - state->rootdse = *rootdse; - } else { - state->use_rootdse = false; - state->rootdse = NULL; - } - - /* NOTE: this call may cause service->uri to be refreshed - * with a new valid server. Do not use service->uri before */ - subreq = be_resolve_server_send(state, ev, be, service->name); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, sdap_cli_resolve_done, req); - - return req; -} - -static void sdap_cli_resolve_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_cli_connect_state *state = tevent_req_data(req, - struct sdap_cli_connect_state); - int ret; - - ret = be_resolve_server_recv(subreq, &state->srv); - talloc_zfree(subreq); - if (ret) { - /* all servers have been tried and none - * was found good, go offline */ - tevent_req_error(req, EIO); - return; - } - - subreq = sdap_connect_send(state, state->ev, state->opts, - state->service->uri, - dp_opt_get_bool(state->opts->basic, - SDAP_ID_TLS)); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_cli_connect_done, req); -} - -static void sdap_cli_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_cli_connect_state *state = tevent_req_data(req, - struct sdap_cli_connect_state); - const char *sasl_mech; - int ret; - - ret = sdap_connect_recv(subreq, state, &state->sh); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - if (state->use_rootdse && !state->rootdse) { - /* fetch the rootDSE this time */ - sdap_cli_rootdse_step(req); - return; - } - - sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH); - - if (sasl_mech && state->use_rootdse) { - /* check if server claims to support GSSAPI */ - if (!sdap_rootdse_sasl_mech_is_supported(state->rootdse, - sasl_mech)) { - tevent_req_error(req, ENOTSUP); - return; - } - } - - if (sasl_mech && (strcasecmp(sasl_mech, "GSSAPI") == 0)) { - if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) { - sdap_cli_kinit_step(req); - return; - } - } - - sdap_cli_auth_step(req); -} - -static void sdap_cli_rootdse_step(struct tevent_req *req) -{ - struct sdap_cli_connect_state *state = tevent_req_data(req, - struct sdap_cli_connect_state); - struct tevent_req *subreq; - - subreq = sdap_get_rootdse_send(state, state->ev, state->opts, state->sh); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_cli_rootdse_done, req); - - if (!state->sh->connected) { - /* this rootdse search is performed before we actually do a bind, - * so we need to set up the callbacks or we will never get notified - * of a reply */ - state->sh->connected = true; -#ifndef HAVE_LDAP_CONNCB - int ret; - - ret = sdap_install_ldap_callbacks(state->sh, state->ev); - if (ret) { - tevent_req_error(req, ret); - } -#endif - } -} - -static void sdap_cli_rootdse_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_cli_connect_state *state = tevent_req_data(req, - struct sdap_cli_connect_state); - const char *sasl_mech; - int ret; - - ret = sdap_get_rootdse_recv(subreq, state, &state->rootdse); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH); - - if (sasl_mech && state->use_rootdse) { - /* check if server claims to support GSSAPI */ - if (!sdap_rootdse_sasl_mech_is_supported(state->rootdse, - sasl_mech)) { - tevent_req_error(req, ENOTSUP); - return; - } - } - - if (sasl_mech && (strcasecmp(sasl_mech, "GSSAPI") == 0)) { - if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) { - sdap_cli_kinit_step(req); - return; - } - } - - sdap_cli_auth_step(req); -} - -static void sdap_cli_kinit_step(struct tevent_req *req) -{ - struct sdap_cli_connect_state *state = tevent_req_data(req, - struct sdap_cli_connect_state); - struct tevent_req *subreq; - - subreq = sdap_kinit_send(state, state->ev, - state->sh, - dp_opt_get_int(state->opts->basic, - SDAP_OPT_TIMEOUT), - dp_opt_get_string(state->opts->basic, - SDAP_KRB5_KEYTAB), - dp_opt_get_string(state->opts->basic, - SDAP_SASL_AUTHID), - dp_opt_get_string(state->opts->basic, - SDAP_KRB5_REALM)); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_cli_kinit_done, req); -} - -static void sdap_cli_kinit_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - enum sdap_result result; - int ret; - - ret = sdap_kinit_recv(subreq, &result); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - if (result != SDAP_AUTH_SUCCESS) { - tevent_req_error(req, EACCES); - return; - } - - sdap_cli_auth_step(req); -} - -static void sdap_cli_auth_step(struct tevent_req *req) -{ - struct sdap_cli_connect_state *state = tevent_req_data(req, - struct sdap_cli_connect_state); - struct tevent_req *subreq; - - subreq = sdap_auth_send(state, - state->ev, - state->sh, - dp_opt_get_string(state->opts->basic, - SDAP_SASL_MECH), - dp_opt_get_string(state->opts->basic, - SDAP_SASL_AUTHID), - dp_opt_get_string(state->opts->basic, - SDAP_DEFAULT_BIND_DN), - dp_opt_get_string(state->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - dp_opt_get_blob(state->opts->basic, - SDAP_DEFAULT_AUTHTOK)); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_cli_auth_done, req); -} - -static void sdap_cli_auth_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - enum sdap_result result; - int ret; - - ret = sdap_auth_recv(subreq, &result); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - if (result != SDAP_AUTH_SUCCESS) { - tevent_req_error(req, EACCES); - return; - } - - tevent_req_done(req); -} - -int sdap_cli_connect_recv(struct tevent_req *req, - TALLOC_CTX *memctx, - struct sdap_handle **gsh, - struct sysdb_attrs **rootdse) -{ - struct sdap_cli_connect_state *state = tevent_req_data(req, - struct sdap_cli_connect_state); - enum tevent_req_state tstate; - uint64_t err; - - if (tevent_req_is_error(req, &tstate, &err)) { - /* mark the server as bad if connection failed */ - if (state->srv) { - fo_set_port_status(state->srv, PORT_NOT_WORKING); - } - - if (tstate == TEVENT_REQ_USER_ERROR) { - return err; - } - return EIO; - } else if (state->srv) { - fo_set_port_status(state->srv, PORT_WORKING); - } - - if (gsh) { - *gsh = talloc_steal(memctx, state->sh); - if (!*gsh) { - return ENOMEM; - } - } else { - talloc_zfree(state->sh); - } - - if (rootdse) { - if (state->use_rootdse) { - *rootdse = talloc_steal(memctx, state->rootdse); - if (!*rootdse) { - return ENOMEM; - } - } else { - *rootdse = NULL; - } - } else { - talloc_zfree(rootdse); - } - - return EOK; -} - diff --git a/server/providers/ldap/sdap_async_private.h b/server/providers/ldap/sdap_async_private.h deleted file mode 100644 index 55f76ed70..000000000 --- a/server/providers/ldap/sdap_async_private.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - SSSD - - Async LDAP Helper routines - - Copyright (C) Simo Sorce - - 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 _SDAP_ASYNC_PRIVATE_H_ -#define _SDAP_ASYNC_PRIVATE_H_ - -#include "config.h" -#include "providers/ldap/sdap_async.h" - -void make_realm_upper_case(const char *upn); -struct sdap_handle *sdap_handle_create(TALLOC_CTX *memctx); - -#ifdef HAVE_LDAP_CONNCB -int sdap_ldap_connect_callback_add(LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv, - struct sockaddr *addr, struct ldap_conncb *ctx); -void sdap_ldap_connect_callback_del(LDAP *ld, Sockbuf *sb, - struct ldap_conncb *ctx); -#else -int sdap_install_ldap_callbacks(struct sdap_handle *sh, - struct tevent_context *ev); -#endif - -int sdap_op_add(TALLOC_CTX *memctx, struct tevent_context *ev, - struct sdap_handle *sh, int msgid, - sdap_op_callback_t *callback, void *data, - int timeout, struct sdap_op **_op); - -struct tevent_req *sdap_get_rootdse_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_options *opts, - struct sdap_handle *sh); -int sdap_get_rootdse_recv(struct tevent_req *req, - TALLOC_CTX *memctx, - struct sysdb_attrs **rootdse); - -/* from sdap_child_helpers.c */ - -struct tevent_req *sdap_get_tgt_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - const char *realm_str, - const char *princ_str, - const char *keytab_name, - int timeout); - -int sdap_get_tgt_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - int *result, - char **ccname); - -#endif /* _SDAP_ASYNC_PRIVATE_H_ */ diff --git a/server/providers/ldap/sdap_child_helpers.c b/server/providers/ldap/sdap_child_helpers.c deleted file mode 100644 index 0a95c8a0d..000000000 --- a/server/providers/ldap/sdap_child_helpers.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - SSSD - - LDAP Backend Module -- child helpers - - Authors: - Jakub Hrozek - - 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 "providers/ldap/ldap_common.h" -#include "providers/child_common.h" - -#ifndef SSSD_LIBEXEC_PATH -#error "SSSD_LIBEXEC_PATH not defined" -#else -#define LDAP_CHILD SSSD_LIBEXEC_PATH"/ldap_child" -#endif - -#ifndef LDAP_CHILD_USER -#define LDAP_CHILD_USER "nobody" -#endif - -struct sdap_child { - /* child info */ - pid_t pid; - int read_from_child_fd; - int write_to_child_fd; -}; - -static void sdap_close_fd(int *fd) -{ - int ret; - - if (*fd == -1) { - DEBUG(6, ("fd already closed\n")); - return; - } - - ret = close(*fd); - if (ret) { - ret = errno; - DEBUG(2, ("Closing fd %d, return error %d (%s)\n", - *fd, ret, strerror(ret))); - } - - *fd = -1; -} - -static int sdap_child_destructor(void *ptr) -{ - struct sdap_child *child = talloc_get_type(ptr, struct sdap_child); - - child_cleanup(child->read_from_child_fd, child->write_to_child_fd); - - return 0; -} - -static errno_t sdap_fork_child(struct sdap_child *child) -{ - 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", err, strerror(err))); - return err; - } - ret = pipe(pipefd_to_child); - if (ret == -1) { - err = errno; - DEBUG(1, ("pipe failed [%d][%s].\n", err, strerror(err))); - return err; - } - - pid = fork(); - - if (pid == 0) { /* child */ - err = exec_child(child, - pipefd_to_child, pipefd_from_child, - LDAP_CHILD, ldap_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 */ - child->pid = pid; - child->read_from_child_fd = pipefd_from_child[0]; - close(pipefd_from_child[1]); - child->write_to_child_fd = pipefd_to_child[1]; - close(pipefd_to_child[0]); - fd_nonblocking(child->read_from_child_fd); - fd_nonblocking(child->write_to_child_fd); - - } else { /* error */ - err = errno; - DEBUG(1, ("fork failed [%d][%s].\n", err, strerror(err))); - return err; - } - - return EOK; -} - -static errno_t create_tgt_req_send_buffer(TALLOC_CTX *mem_ctx, - const char *realm_str, - const char *princ_str, - const char *keytab_name, - struct io_buffer **io_buf) -{ - struct io_buffer *buf; - size_t rp; - - buf = talloc(mem_ctx, struct io_buffer); - if (buf == NULL) { - DEBUG(1, ("talloc failed.\n")); - return ENOMEM; - } - - buf->size = 3 * sizeof(uint32_t); - if (realm_str) { - buf->size += strlen(realm_str); - } - if (princ_str) { - buf->size += strlen(princ_str); - } - if (keytab_name) { - buf->size += strlen(keytab_name); - } - - DEBUG(7, ("buffer size: %d\n", buf->size)); - - buf->data = talloc_size(buf, buf->size); - if (buf->data == NULL) { - DEBUG(1, ("talloc_size failed.\n")); - talloc_free(buf); - return ENOMEM; - } - - rp = 0; - - /* realm */ - if (realm_str) { - COPY_UINT32_VALUE(&buf->data[rp], strlen(realm_str), rp); - COPY_MEM(&buf->data[rp], realm_str, rp, strlen(realm_str)); - } else { - COPY_UINT32_VALUE(&buf->data[rp], 0, rp); - } - - /* principal */ - if (princ_str) { - COPY_UINT32_VALUE(&buf->data[rp], strlen(princ_str), rp); - COPY_MEM(&buf->data[rp], princ_str, rp, strlen(princ_str)); - } else { - COPY_UINT32_VALUE(&buf->data[rp], 0, rp); - } - - /* keytab */ - if (keytab_name) { - COPY_UINT32_VALUE(&buf->data[rp], strlen(keytab_name), rp); - COPY_MEM(&buf->data[rp], keytab_name, rp, strlen(realm_str)); - } else { - COPY_UINT32_VALUE(&buf->data[rp], 0, rp); - } - - *io_buf = buf; - return EOK; -} - -static int parse_child_response(TALLOC_CTX *mem_ctx, - uint8_t *buf, ssize_t size, - int *result, char **ccache) -{ - size_t p = 0; - uint32_t len; - uint32_t res; - char *ccn; - - /* operation result code */ - COPY_UINT32_CHECK(&res, buf + p, p, size); - - /* ccache name size */ - COPY_UINT32_CHECK(&len, buf + p, p, size); - - if ((p + len ) > size) return EINVAL; - - ccn = talloc_size(mem_ctx, sizeof(char) * (len + 1)); - if (ccn == NULL) { - DEBUG(1, ("talloc_size failed.\n")); - return ENOMEM; - } - memcpy(ccn, buf+p, sizeof(char) * (len + 1)); - ccn[len] = '\0'; - - *result = res; - *ccache = ccn; - return EOK; -} - -/* ==The-public-async-interface============================================*/ - -struct sdap_get_tgt_state { - struct tevent_context *ev; - struct sdap_child *child; - ssize_t len; - uint8_t *buf; -}; - -static errno_t set_tgt_child_timeout(struct tevent_req *req, - struct tevent_context *ev, - int timeout); -static void sdap_get_tgt_step(struct tevent_req *subreq); -static void sdap_get_tgt_done(struct tevent_req *subreq); - -struct tevent_req *sdap_get_tgt_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - const char *realm_str, - const char *princ_str, - const char *keytab_name, - int timeout) -{ - struct tevent_req *req, *subreq; - struct sdap_get_tgt_state *state; - struct io_buffer *buf; - int ret; - - req = tevent_req_create(mem_ctx, &state, struct sdap_get_tgt_state); - if (!req) { - return NULL; - } - - state->ev = ev; - - state->child = talloc_zero(state, struct sdap_child); - if (!state->child) { - ret = ENOMEM; - goto fail; - } - - state->child->read_from_child_fd = -1; - state->child->write_to_child_fd = -1; - talloc_set_destructor((TALLOC_CTX *)state->child, sdap_child_destructor); - - /* prepare the data to pass to child */ - ret = create_tgt_req_send_buffer(state, - realm_str, princ_str, keytab_name, - &buf); - if (ret != EOK) { - DEBUG(1, ("create_tgt_req_send_buffer failed.\n")); - goto fail; - } - - ret = sdap_fork_child(state->child); - if (ret != EOK) { - DEBUG(1, ("sdap_fork_child failed.\n")); - goto fail; - } - - ret = set_tgt_child_timeout(req, ev, timeout); - if (ret != EOK) { - DEBUG(1, ("activate_child_timeout_handler failed.\n")); - goto fail; - } - - subreq = write_pipe_send(state, ev, buf->data, buf->size, - state->child->write_to_child_fd); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, sdap_get_tgt_step, req); - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void sdap_get_tgt_step(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_tgt_state *state = tevent_req_data(req, - struct sdap_get_tgt_state); - int ret; - - ret = write_pipe_recv(subreq); - talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - sdap_close_fd(&state->child->write_to_child_fd); - - subreq = read_pipe_send(state, state->ev, - state->child->read_from_child_fd); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_get_tgt_done, req); -} - -static void sdap_get_tgt_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_get_tgt_state *state = tevent_req_data(req, - struct sdap_get_tgt_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; - } - - sdap_close_fd(&state->child->read_from_child_fd); - - tevent_req_done(req); -} - -int sdap_get_tgt_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - int *result, - char **ccname) -{ - struct sdap_get_tgt_state *state = tevent_req_data(req, - struct sdap_get_tgt_state); - char *ccn; - int res; - int ret; - - TEVENT_REQ_RETURN_ON_ERROR(req); - - ret = parse_child_response(mem_ctx, state->buf, state->len, &res, &ccn); - if (ret != EOK) { - DEBUG(1, ("Cannot parse child response: [%d][%s]\n", ret, strerror(ret))); - return ret; - } - - DEBUG(6, ("Child responded: %d [%s]\n", res, ccn)); - *result = res; - *ccname = ccn; - return EOK; -} - - - -static void get_tgt_timeout_handler(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct sdap_get_tgt_state *state = tevent_req_data(req, - struct sdap_get_tgt_state); - int ret; - - DEBUG(9, ("timeout for tgt child [%d] reached.\n", state->child->pid)); - - ret = kill(state->child->pid, SIGKILL); - if (ret == -1) { - DEBUG(1, ("kill failed [%d][%s].\n", errno, strerror(errno))); - } - - tevent_req_error(req, ETIMEDOUT); -} - -static errno_t set_tgt_child_timeout(struct tevent_req *req, - struct tevent_context *ev, - int timeout) -{ - struct tevent_timer *te; - struct timeval tv; - - DEBUG(6, ("Setting %d seconds timeout for tgt child\n", timeout)); - - tv = tevent_timeval_current_ofs(timeout, 0); - - te = tevent_add_timer(ev, req, tv, get_tgt_timeout_handler, req); - if (te == NULL) { - DEBUG(1, ("tevent_add_timer failed.\n")); - return ENOMEM; - } - - return EOK; -} - - - -/* Setup child logging */ -int setup_child(struct sdap_id_ctx *ctx) -{ - int ret; - const char *mech; - struct tevent_signal *sige; - unsigned v; - FILE *debug_filep; - - mech = dp_opt_get_string(ctx->opts->basic, - SDAP_SASL_MECH); - if (!mech) { - return EOK; - } - - sige = tevent_add_signal(ctx->be->ev, ctx, SIGCHLD, SA_SIGINFO, - child_sig_handler, NULL); - if (sige == NULL) { - DEBUG(1, ("tevent_add_signal failed.\n")); - return ENOMEM; - } - - if (debug_to_file != 0 && ldap_child_debug_fd == -1) { - ret = open_debug_file_ex("ldap_child", &debug_filep); - if (ret != EOK) { - DEBUG(0, ("Error setting up logging (%d) [%s]\n", - ret, strerror(ret))); - return ret; - } - - ldap_child_debug_fd = fileno(debug_filep); - if (ldap_child_debug_fd == -1) { - DEBUG(0, ("fileno failed [%d][%s]\n", errno, strerror(errno))); - ret = errno; - return ret; - } - - v = fcntl(ldap_child_debug_fd, F_GETFD, 0); - fcntl(ldap_child_debug_fd, F_SETFD, v & ~FD_CLOEXEC); - } - - return EOK; -} diff --git a/server/providers/providers.h b/server/providers/providers.h deleted file mode 100644 index 44e7028ab..000000000 --- a/server/providers/providers.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - SSSD - - Data Provider, public header file - - Copyright (C) Simo Sorce 2008 - - 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 . -*/ - -int dp_process_init(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct confdb_ctx *cdb); diff --git a/server/providers/proxy.c b/server/providers/proxy.c deleted file mode 100644 index 12bb25ec7..000000000 --- a/server/providers/proxy.c +++ /dev/null @@ -1,2521 +0,0 @@ -/* - SSSD - - Proxy Module - - Copyright (C) Simo Sorce 2008-2009 - - 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 "providers/dp_backend.h" -#include "db/sysdb.h" - -struct proxy_nss_ops { - enum nss_status (*getpwnam_r)(const char *name, struct passwd *result, - char *buffer, size_t buflen, int *errnop); - enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result, - char *buffer, size_t buflen, int *errnop); - enum nss_status (*setpwent)(void); - enum nss_status (*getpwent_r)(struct passwd *result, - char *buffer, size_t buflen, int *errnop); - enum nss_status (*endpwent)(void); - - enum nss_status (*getgrnam_r)(const char *name, struct group *result, - char *buffer, size_t buflen, int *errnop); - enum nss_status (*getgrgid_r)(gid_t gid, struct group *result, - char *buffer, size_t buflen, int *errnop); - enum nss_status (*setgrent)(void); - enum nss_status (*getgrent_r)(struct group *result, - char *buffer, size_t buflen, int *errnop); - enum nss_status (*endgrent)(void); - enum nss_status (*initgroups_dyn)(const char *user, gid_t group, - long int *start, long int *size, - gid_t **groups, long int limit, - int *errnop); -}; - -struct proxy_ctx { - struct be_ctx *be; - int entry_cache_timeout; - struct proxy_nss_ops ops; -}; - -struct proxy_auth_ctx { - struct be_ctx *be; - char *pam_target; -}; - -struct authtok_conv { - uint32_t authtok_size; - uint8_t *authtok; -}; - -static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, - struct pam_response **response, - void *appdata_ptr) { - int i; - struct pam_response *reply; - struct authtok_conv *auth_data; - - auth_data = talloc_get_type(appdata_ptr, struct authtok_conv); - - if (num_msg <= 0) return PAM_CONV_ERR; - - reply = (struct pam_response *) calloc(num_msg, - sizeof(struct pam_response)); - if (reply == NULL) return PAM_CONV_ERR; - - for (i=0; i < num_msg; i++) { - switch( msgm[i]->msg_style ) { - case PAM_PROMPT_ECHO_OFF: - DEBUG(4, ("Conversation message: [%s]\n", msgm[i]->msg)); - reply[i].resp_retcode = 0; - reply[i].resp = calloc(auth_data->authtok_size + 1, - sizeof(char)); - if (reply[i].resp == NULL) goto failed; - memcpy(reply[i].resp, auth_data->authtok, auth_data->authtok_size); - - break; - default: - DEBUG(1, ("Conversation style %d not supported.\n", - msgm[i]->msg_style)); - goto failed; - } - } - - *response = reply; - reply = NULL; - - return PAM_SUCCESS; - -failed: - free(reply); - return PAM_CONV_ERR; -} - -static void proxy_pam_handler_cache_done(struct tevent_req *treq); -static void proxy_reply(struct be_req *req, int dp_err, - int error, const char *errstr); - -static void proxy_pam_handler(struct be_req *req) { - int ret; - int pam_status; - pam_handle_t *pamh=NULL; - struct authtok_conv *auth_data; - struct pam_conv conv; - struct pam_data *pd; - struct proxy_auth_ctx *ctx;; - bool cache_auth_data = false; - - pd = talloc_get_type(req->req_data, struct pam_data); - - switch (pd->cmd) { - case SSS_PAM_AUTHENTICATE: - ctx = talloc_get_type(req->be_ctx->bet_info[BET_AUTH].pvt_bet_data, - struct proxy_auth_ctx); - break; - case SSS_PAM_CHAUTHTOK: - case SSS_PAM_CHAUTHTOK_PRELIM: - ctx = talloc_get_type(req->be_ctx->bet_info[BET_CHPASS].pvt_bet_data, - struct proxy_auth_ctx); - break; - case SSS_PAM_ACCT_MGMT: - ctx = talloc_get_type(req->be_ctx->bet_info[BET_ACCESS].pvt_bet_data, - struct proxy_auth_ctx); - break; - case SSS_PAM_SETCRED: - case SSS_PAM_OPEN_SESSION: - case SSS_PAM_CLOSE_SESSION: - pd->pam_status = PAM_SUCCESS; - proxy_reply(req, DP_ERR_OK, EOK, NULL); - return; - default: - DEBUG(1, ("Unsupported PAM task.\n")); - pd->pam_status = PAM_MODULE_UNKNOWN; - proxy_reply(req, DP_ERR_OK, EINVAL, "Unsupported PAM task"); - return; - } - - conv.conv=proxy_internal_conv; - auth_data = talloc_zero(req, struct authtok_conv); - conv.appdata_ptr=auth_data; - - ret = pam_start(ctx->pam_target, pd->user, &conv, &pamh); - if (ret == PAM_SUCCESS) { - DEBUG(1, ("Pam transaction started.\n")); - ret = pam_set_item(pamh, PAM_TTY, pd->tty); - if (ret != PAM_SUCCESS) { - DEBUG(1, ("Setting PAM_TTY failed: %s.\n", pam_strerror(pamh, ret))); - } - ret = pam_set_item(pamh, PAM_RUSER, pd->ruser); - if (ret != PAM_SUCCESS) { - DEBUG(1, ("Setting PAM_RUSER failed: %s.\n", pam_strerror(pamh, ret))); - } - ret = pam_set_item(pamh, PAM_RHOST, pd->rhost); - if (ret != PAM_SUCCESS) { - DEBUG(1, ("Setting PAM_RHOST failed: %s.\n", pam_strerror(pamh, ret))); - } - switch (pd->cmd) { - case SSS_PAM_AUTHENTICATE: - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; - pam_status = pam_authenticate(pamh, 0); - if ((pam_status == PAM_SUCCESS) && - (req->be_ctx->domain->cache_credentials)) { - cache_auth_data = true; - } - break; - case SSS_PAM_SETCRED: - pam_status=pam_setcred(pamh, 0); - break; - case SSS_PAM_ACCT_MGMT: - pam_status=pam_acct_mgmt(pamh, 0); - break; - case SSS_PAM_OPEN_SESSION: - pam_status=pam_open_session(pamh, 0); - break; - case SSS_PAM_CLOSE_SESSION: - pam_status=pam_close_session(pamh, 0); - break; - case SSS_PAM_CHAUTHTOK: - if (pd->priv != 1) { - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; - pam_status = pam_authenticate(pamh, 0); - if (pam_status != PAM_SUCCESS) break; - } - auth_data->authtok_size = pd->newauthtok_size; - auth_data->authtok = pd->newauthtok; - pam_status = pam_chauthtok(pamh, 0); - if ((pam_status == PAM_SUCCESS) && - (req->be_ctx->domain->cache_credentials)) { - cache_auth_data = true; - } - break; - case SSS_PAM_CHAUTHTOK_PRELIM: - if (pd->priv != 1) { - auth_data->authtok_size = pd->authtok_size; - auth_data->authtok = pd->authtok; - pam_status = pam_authenticate(pamh, 0); - } else { - pam_status = PAM_SUCCESS; - } - break; - default: - DEBUG(1, ("unknown PAM call")); - pam_status=PAM_ABORT; - } - - DEBUG(4, ("Pam result: [%d][%s]\n", pam_status, - pam_strerror(pamh, pam_status))); - - if (pam_status == PAM_AUTHINFO_UNAVAIL) { - be_mark_offline(req->be_ctx); - } - - ret = pam_end(pamh, pam_status); - if (ret != PAM_SUCCESS) { - pamh=NULL; - DEBUG(1, ("Cannot terminate pam transaction.\n")); - } - - } else { - DEBUG(1, ("Failed to initialize pam transaction.\n")); - pam_status = PAM_SYSTEM_ERR; - } - - pd->pam_status = pam_status; - - if (cache_auth_data) { - struct tevent_req *subreq; - char *password; - - password = talloc_size(req, auth_data->authtok_size + 1); - if (!password) { - /* password caching failures are not fatal errors */ - return proxy_reply(req, DP_ERR_OK, EOK, NULL); - } - memcpy(password, auth_data->authtok, auth_data->authtok_size); - password[auth_data->authtok_size] = '\0'; - talloc_set_destructor((TALLOC_CTX *)password, password_destructor); - - subreq = sysdb_cache_password_send(req, req->be_ctx->ev, - req->be_ctx->sysdb, NULL, - req->be_ctx->domain, - pd->user, password); - if (!subreq) { - /* password caching failures are not fatal errors */ - return proxy_reply(req, DP_ERR_OK, EOK, NULL); - } - tevent_req_set_callback(subreq, proxy_pam_handler_cache_done, req); - } - - proxy_reply(req, DP_ERR_OK, EOK, NULL); -} - -static void proxy_pam_handler_cache_done(struct tevent_req *subreq) -{ - struct be_req *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))); - } - - return proxy_reply(req, DP_ERR_OK, EOK, NULL); -} - -static void proxy_reply(struct be_req *req, int dp_err, - int error, const char *errstr) -{ - return req->fn(req, dp_err, error, errstr); -} - -/* =Common-proxy-tevent_req-utils=========================================*/ - -#define DEFAULT_BUFSIZE 4096 -#define MAX_BUF_SIZE 1024*1024 /* max 1MiB */ - -struct proxy_state { - struct tevent_context *ev; - struct proxy_ctx *ctx; - struct sysdb_ctx *sysdb; - struct sss_domain_info *domain; - const char *name; - - struct sysdb_handle *handle; - struct passwd *pwd; - struct group *grp; - uid_t uid; - gid_t gid; -}; - -static void proxy_default_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - int ret; - - ret = sysdb_transaction_commit_recv(subreq); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -static int proxy_default_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - - -/* =Getpwnam-wrapper======================================================*/ - -static void get_pw_name_process(struct tevent_req *subreq); -static void get_pw_name_remove_done(struct tevent_req *subreq); -static void get_pw_name_add_done(struct tevent_req *subreq); - -static struct tevent_req *get_pw_name_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct proxy_ctx *ctx, - struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - const char *name) -{ - struct tevent_req *req, *subreq; - struct proxy_state *state; - - req = tevent_req_create(mem_ctx, &state, struct proxy_state); - if (!req) return NULL; - - memset(state, 0, sizeof(struct proxy_state)); - - state->ev = ev; - state->ctx = ctx; - state->sysdb = sysdb; - state->domain = domain; - state->name = name; - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, get_pw_name_process, req); - - return req; -} - -static void get_pw_name_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct proxy_state *state = tevent_req_data(req, - struct proxy_state); - struct proxy_ctx *ctx = state->ctx; - struct sss_domain_info *dom = ctx->be->domain; - enum nss_status status; - char *buffer; - size_t buflen; - bool delete_user = false; - int ret; - - DEBUG(7, ("Searching user by name (%s)\n", state->name)); - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - if (ret) { - tevent_req_error(req, ret); - return; - } - talloc_zfree(subreq); - - state->pwd = talloc(state, struct passwd); - if (!state->pwd) { - tevent_req_error(req, ENOMEM); - return; - } - - buflen = DEFAULT_BUFSIZE; - buffer = talloc_size(state, buflen); - if (!buffer) { - tevent_req_error(req, ENOMEM); - return; - } - - /* FIXME: should we move this call outside the transaction to keep the - * transaction as short as possible ? */ - status = ctx->ops.getpwnam_r(state->name, state->pwd, - buffer, buflen, &ret); - - switch (status) { - case NSS_STATUS_NOTFOUND: - - DEBUG(7, ("User %s not found.\n", state->name)); - delete_user = true; - break; - - case NSS_STATUS_SUCCESS: - - DEBUG(7, ("User %s found: (%s, %d, %d)\n", - state->name, state->pwd->pw_name, - state->pwd->pw_uid, state->pwd->pw_gid)); - - /* uid=0 or gid=0 are invalid values */ - /* also check that the id is in the valid range for this domain */ - if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) || - OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) { - - DEBUG(2, ("User [%s] filtered out! (id out of range)\n", - state->name)); - delete_user = true; - break; - } - - subreq = sysdb_store_user_send(state, state->ev, state->handle, - state->domain, - state->pwd->pw_name, - state->pwd->pw_passwd, - state->pwd->pw_uid, - state->pwd->pw_gid, - state->pwd->pw_gecos, - state->pwd->pw_dir, - state->pwd->pw_shell, - NULL, ctx->entry_cache_timeout); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, get_pw_name_add_done, req); - return; - - case NSS_STATUS_UNAVAIL: - /* "remote" backend unavailable. Enter offline mode */ - tevent_req_error(req, ENXIO); - return; - - default: - DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n", - state->name, status)); - tevent_req_error(req, EIO); - return; - } - - if (delete_user) { - struct ldb_dn *dn; - - DEBUG(7, ("User %s does not exist (or is invalid) on remote server," - " deleting!\n", state->name)); - - dn = sysdb_user_dn(state->sysdb, state, - state->domain->name, state->name); - if (!dn) { - tevent_req_error(req, ENOMEM); - return; - } - - subreq = sysdb_delete_entry_send(state, state->ev, state->handle, dn, true); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, get_pw_name_remove_done, req); - } -} - -static void get_pw_name_add_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct proxy_state *state = tevent_req_data(req, - struct proxy_state); - int ret; - - ret = sysdb_store_user_recv(subreq); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, proxy_default_done, req); -} - -static void get_pw_name_remove_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct proxy_state *state = tevent_req_data(req, - struct proxy_state); - int ret; - - ret = sysdb_delete_entry_recv(subreq); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, proxy_default_done, req); -} - -/* =Getpwuid-wrapper======================================================*/ - -static void get_pw_uid_process(struct tevent_req *subreq); -static void get_pw_uid_remove_done(struct tevent_req *subreq); - -static struct tevent_req *get_pw_uid_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct proxy_ctx *ctx, - struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - uid_t uid) -{ - struct tevent_req *req, *subreq; - struct proxy_state *state; - - req = tevent_req_create(mem_ctx, &state, struct proxy_state); - if (!req) return NULL; - - memset(state, 0, sizeof(struct proxy_state)); - - state->ev = ev; - state->ctx = ctx; - state->sysdb = sysdb; - state->domain = domain; - state->uid = uid; - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, get_pw_uid_process, req); - - return req; -} - -static void get_pw_uid_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct proxy_state *state = tevent_req_data(req, - struct proxy_state); - struct proxy_ctx *ctx = state->ctx; - struct sss_domain_info *dom = ctx->be->domain; - enum nss_status status; - char *buffer; - size_t buflen; - bool delete_user = false; - int ret; - - DEBUG(7, ("Searching user by uid (%d)\n", state->uid)); - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - if (ret) { - tevent_req_error(req, ret); - return; - } - talloc_zfree(subreq); - - state->pwd = talloc(state, struct passwd); - if (!state->pwd) { - tevent_req_error(req, ENOMEM); - return; - } - - buflen = DEFAULT_BUFSIZE; - buffer = talloc_size(state, buflen); - if (!buffer) { - tevent_req_error(req, ENOMEM); - return; - } - - /* always zero out the pwd structure */ - memset(state->pwd, 0, sizeof(struct passwd)); - - status = ctx->ops.getpwuid_r(state->uid, state->pwd, - buffer, buflen, &ret); - - switch (status) { - case NSS_STATUS_NOTFOUND: - - DEBUG(7, ("User %d not found.\n", state->uid)); - delete_user = true; - break; - - case NSS_STATUS_SUCCESS: - - DEBUG(7, ("User %d found (%s, %d, %d)\n", - state->uid, state->pwd->pw_name, - state->pwd->pw_uid, state->pwd->pw_gid)); - - /* uid=0 or gid=0 are invalid values */ - /* also check that the id is in the valid range for this domain */ - if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) || - OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) { - - DEBUG(2, ("User [%s] filtered out! (id out of range)\n", - state->name)); - delete_user = true; - break; - } - - subreq = sysdb_store_user_send(state, state->ev, state->handle, - state->domain, - state->pwd->pw_name, - state->pwd->pw_passwd, - state->pwd->pw_uid, - state->pwd->pw_gid, - state->pwd->pw_gecos, - state->pwd->pw_dir, - state->pwd->pw_shell, - NULL, ctx->entry_cache_timeout); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, get_pw_name_add_done, req); - return; - - case NSS_STATUS_UNAVAIL: - /* "remote" backend unavailable. Enter offline mode */ - tevent_req_error(req, ENXIO); - return; - - default: - DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n", - state->name, status)); - tevent_req_error(req, EIO); - return; - } - - if (delete_user) { - DEBUG(7, ("User %d does not exist (or is invalid) on remote server," - " deleting!\n", state->uid)); - - subreq = sysdb_delete_user_send(state, state->ev, - NULL, state->handle, - state->domain, - NULL, state->uid); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, get_pw_uid_remove_done, req); - } -} - -static void get_pw_uid_remove_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct proxy_state *state = tevent_req_data(req, - struct proxy_state); - int ret; - - ret = sysdb_delete_user_recv(subreq); - talloc_zfree(subreq); - if (ret && ret != ENOENT) { - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, proxy_default_done, req); -} - -/* =Getpwent-wrapper======================================================*/ - -struct enum_users_state { - struct tevent_context *ev; - struct proxy_ctx *ctx; - struct sysdb_ctx *sysdb; - struct sss_domain_info *domain; - struct sysdb_handle *handle; - - struct passwd *pwd; - - size_t buflen; - char *buffer; - - bool in_transaction; -}; - -static void enum_users_process(struct tevent_req *subreq); - -static struct tevent_req *enum_users_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct proxy_ctx *ctx, - struct sysdb_ctx *sysdb, - struct sss_domain_info *domain) -{ - struct tevent_req *req, *subreq; - struct enum_users_state *state; - enum nss_status status; - - DEBUG(7, ("Enumerating users\n")); - - req = tevent_req_create(mem_ctx, &state, struct enum_users_state); - if (!req) return NULL; - - state->ev = ev; - state->ctx = ctx; - state->sysdb = sysdb; - state->domain = domain; - state->handle = NULL; - - state->pwd = talloc(state, struct passwd); - if (!state->pwd) { - tevent_req_error(req, ENOMEM); - goto fail; - } - - state->buflen = DEFAULT_BUFSIZE; - state->buffer = talloc_size(state, state->buflen); - if (!state->buffer) { - tevent_req_error(req, ENOMEM); - goto fail; - } - - state->in_transaction = false; - - status = ctx->ops.setpwent(); - if (status != NSS_STATUS_SUCCESS) { - tevent_req_error(req, EIO); - goto fail; - } - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (!subreq) { - tevent_req_error(req, ENOMEM); - goto fail; - } - tevent_req_set_callback(subreq, enum_users_process, req); - - return req; - -fail: - tevent_req_post(req, ev); - return req; -} - -static void enum_users_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct enum_users_state *state = tevent_req_data(req, - struct enum_users_state); - struct proxy_ctx *ctx = state->ctx; - struct sss_domain_info *dom = ctx->be->domain; - enum nss_status status; - char *newbuf; - int ret; - - if (!state->in_transaction) { - ret = sysdb_transaction_recv(subreq, state, &state->handle); - if (ret) { - goto fail; - } - talloc_zfree(subreq); - - state->in_transaction = true; - } else { - ret = sysdb_store_user_recv(subreq); - if (ret) { - /* Do not fail completely on errors. - * Just report the failure to save and go on */ - DEBUG(2, ("Failed to store user. Ignoring.\n")); - } - talloc_zfree(subreq); - } - -again: - /* always zero out the pwd structure */ - memset(state->pwd, 0, sizeof(struct passwd)); - - /* get entry */ - status = ctx->ops.getpwent_r(state->pwd, - state->buffer, state->buflen, &ret); - - switch (status) { - case NSS_STATUS_TRYAGAIN: - /* buffer too small ? */ - if (state->buflen < MAX_BUF_SIZE) { - state->buflen *= 2; - } - if (state->buflen > MAX_BUF_SIZE) { - state->buflen = MAX_BUF_SIZE; - } - newbuf = talloc_realloc_size(state, state->buffer, state->buflen); - if (!newbuf) { - ret = ENOMEM; - goto fail; - } - state->buffer = newbuf; - goto again; - - case NSS_STATUS_NOTFOUND: - - /* we are done here */ - DEBUG(7, ("Enumeration completed.\n")); - - ctx->ops.endpwent(); - subreq = sysdb_transaction_commit_send(state, state->ev, - state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, proxy_default_done, req); - return; - - case NSS_STATUS_SUCCESS: - - DEBUG(7, ("User found (%s, %d, %d)\n", state->pwd->pw_name, - state->pwd->pw_uid, state->pwd->pw_gid)); - - /* uid=0 or gid=0 are invalid values */ - /* also check that the id is in the valid range for this domain */ - if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) || - OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) { - - DEBUG(2, ("User [%s] filtered out! (id out of range)\n", - state->pwd->pw_name)); - - goto again; /* skip */ - } - - subreq = sysdb_store_user_send(state, state->ev, state->handle, - state->domain, - state->pwd->pw_name, - state->pwd->pw_passwd, - state->pwd->pw_uid, - state->pwd->pw_gid, - state->pwd->pw_gecos, - state->pwd->pw_dir, - state->pwd->pw_shell, - NULL, ctx->entry_cache_timeout); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, enum_users_process, req); - return; - - case NSS_STATUS_UNAVAIL: - /* "remote" backend unavailable. Enter offline mode */ - ret = ENXIO; - goto fail; - - default: - DEBUG(2, ("proxy -> getpwent_r failed (%d)[%s]\n", - ret, strerror(ret))); - goto fail; - } - -fail: - ctx->ops.endpwent(); - tevent_req_error(req, ret); -} - -/* =Getgrnam-wrapper======================================================*/ - -#define DEBUG_GR_MEM(level, state) \ - do { \ - if (debug_level >= level) { \ - if (!state->grp->gr_mem || !state->grp->gr_mem[0]) { \ - DEBUG(level, ("Group %s has no members!\n", \ - state->grp->gr_name)); \ - } else { \ - int i = 0; \ - while (state->grp->gr_mem[i]) { \ - /* count */ \ - i++; \ - } \ - DEBUG(level, ("Group %s has %d members!\n", \ - state->grp->gr_name, i)); \ - } \ - } \ - } while(0) - -static void get_gr_name_process(struct tevent_req *subreq); -static void get_gr_name_remove_done(struct tevent_req *subreq); -static void get_gr_name_add_done(struct tevent_req *subreq); - -static struct tevent_req *get_gr_name_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct proxy_ctx *ctx, - struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - const char *name) -{ - struct tevent_req *req, *subreq; - struct proxy_state *state; - - req = tevent_req_create(mem_ctx, &state, struct proxy_state); - if (!req) return NULL; - - memset(state, 0, sizeof(struct proxy_state)); - - state->ev = ev; - state->ctx = ctx; - state->sysdb = sysdb; - state->domain = domain; - state->name = name; - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, get_gr_name_process, req); - - return req; -} - -static void get_gr_name_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct proxy_state *state = tevent_req_data(req, - struct proxy_state); - struct proxy_ctx *ctx = state->ctx; - struct sss_domain_info *dom = ctx->be->domain; - enum nss_status status; - char *buffer; - char *newbuf; - size_t buflen; - bool delete_group = false; - struct sysdb_attrs *members; - int ret; - - DEBUG(7, ("Searching group by name (%s)\n", state->name)); - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - if (ret) { - tevent_req_error(req, ret); - return; - } - talloc_zfree(subreq); - - state->grp = talloc(state, struct group); - if (!state->grp) { - tevent_req_error(req, ENOMEM); - return; - } - - buflen = DEFAULT_BUFSIZE; - buffer = talloc_size(state, buflen); - if (!buffer) { - tevent_req_error(req, ENOMEM); - return; - } - - /* FIXME: should we move this call outside the transaction to keep the - * transaction as short as possible ? */ -again: - /* always zero out the grp structure */ - memset(state->grp, 0, sizeof(struct group)); - - status = ctx->ops.getgrnam_r(state->name, state->grp, - buffer, buflen, &ret); - - switch (status) { - case NSS_STATUS_TRYAGAIN: - /* buffer too small ? */ - if (buflen < MAX_BUF_SIZE) { - buflen *= 2; - } - if (buflen > MAX_BUF_SIZE) { - buflen = MAX_BUF_SIZE; - } - newbuf = talloc_realloc_size(state, buffer, buflen); - if (!newbuf) { - tevent_req_error(req, ENOMEM); - return; - } - buffer = newbuf; - goto again; - - case NSS_STATUS_NOTFOUND: - - DEBUG(7, ("Group %s not found.\n", state->name)); - delete_group = true; - break; - - case NSS_STATUS_SUCCESS: - - DEBUG(7, ("Group %s found: (%s, %d)\n", state->name, - state->grp->gr_name, state->grp->gr_gid)); - - /* gid=0 is an invalid value */ - /* also check that the id is in the valid range for this domain */ - if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) { - - DEBUG(2, ("Group [%s] filtered out! (id out of range)\n", - state->name)); - delete_group = true; - break; - } - - DEBUG_GR_MEM(7, state); - - if (state->grp->gr_mem && state->grp->gr_mem[0]) { - members = sysdb_new_attrs(state); - if (!members) { - tevent_req_error(req, ENOMEM); - return; - } - ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER, - state->domain->name, - (const char **)state->grp->gr_mem); - if (ret) { - tevent_req_error(req, ret); - return; - } - } else { - members = NULL; - } - - subreq = sysdb_store_group_send(state, state->ev, state->handle, - state->domain, - state->grp->gr_name, - state->grp->gr_gid, - members, - ctx->entry_cache_timeout); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, get_gr_name_add_done, req); - return; - - case NSS_STATUS_UNAVAIL: - /* "remote" backend unavailable. Enter offline mode */ - tevent_req_error(req, ENXIO); - return; - - default: - DEBUG(2, ("proxy -> getgrnam_r failed for '%s' <%d>\n", - state->name, status)); - tevent_req_error(req, EIO); - return; - } - - if (delete_group) { - struct ldb_dn *dn; - - DEBUG(7, ("Group %s does not exist (or is invalid) on remote server," - " deleting!\n", state->name)); - - dn = sysdb_group_dn(state->sysdb, state, - state->domain->name, state->name); - if (!dn) { - tevent_req_error(req, ENOMEM); - return; - } - - subreq = sysdb_delete_entry_send(state, state->ev, state->handle, dn, true); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, get_gr_name_remove_done, req); - } -} - -static void get_gr_name_add_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct proxy_state *state = tevent_req_data(req, - struct proxy_state); - int ret; - - ret = sysdb_store_group_recv(subreq); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, proxy_default_done, req); -} - -static void get_gr_name_remove_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct proxy_state *state = tevent_req_data(req, - struct proxy_state); - int ret; - - ret = sysdb_delete_entry_recv(subreq); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, proxy_default_done, req); -} - -/* =Getgrgid-wrapper======================================================*/ - -static void get_gr_gid_process(struct tevent_req *subreq); -static void get_gr_gid_remove_done(struct tevent_req *subreq); - -static struct tevent_req *get_gr_gid_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct proxy_ctx *ctx, - struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - gid_t gid) -{ - struct tevent_req *req, *subreq; - struct proxy_state *state; - - req = tevent_req_create(mem_ctx, &state, struct proxy_state); - if (!req) return NULL; - - memset(state, 0, sizeof(struct proxy_state)); - - state->ev = ev; - state->ctx = ctx; - state->sysdb = sysdb; - state->domain = domain; - state->gid = gid; - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, get_gr_gid_process, req); - - return req; -} - -static void get_gr_gid_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct proxy_state *state = tevent_req_data(req, - struct proxy_state); - struct proxy_ctx *ctx = state->ctx; - struct sss_domain_info *dom = ctx->be->domain; - enum nss_status status; - char *buffer; - char *newbuf; - size_t buflen; - bool delete_group = false; - struct sysdb_attrs *members; - int ret; - - DEBUG(7, ("Searching group by gid (%d)\n", state->gid)); - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - if (ret) { - tevent_req_error(req, ret); - return; - } - talloc_zfree(subreq); - - state->grp = talloc(state, struct group); - if (!state->grp) { - tevent_req_error(req, ENOMEM); - return; - } - - buflen = DEFAULT_BUFSIZE; - buffer = talloc_size(state, buflen); - if (!buffer) { - tevent_req_error(req, ENOMEM); - return; - } - -again: - /* always zero out the group structure */ - memset(state->grp, 0, sizeof(struct group)); - - status = ctx->ops.getgrgid_r(state->gid, state->grp, - buffer, buflen, &ret); - - switch (status) { - case NSS_STATUS_TRYAGAIN: - /* buffer too small ? */ - if (buflen < MAX_BUF_SIZE) { - buflen *= 2; - } - if (buflen > MAX_BUF_SIZE) { - buflen = MAX_BUF_SIZE; - } - newbuf = talloc_realloc_size(state, buffer, buflen); - if (!newbuf) { - tevent_req_error(req, ENOMEM); - return; - } - buffer = newbuf; - goto again; - - case NSS_STATUS_NOTFOUND: - - DEBUG(7, ("Group %d not found.\n", state->gid)); - delete_group = true; - break; - - case NSS_STATUS_SUCCESS: - - DEBUG(7, ("Group %d found (%s, %d)\n", state->gid, - state->grp->gr_name, state->grp->gr_gid)); - - /* gid=0 is an invalid value */ - /* also check that the id is in the valid range for this domain */ - if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) { - - DEBUG(2, ("Group [%s] filtered out! (id out of range)\n", - state->grp->gr_name)); - delete_group = true; - break; - } - - DEBUG_GR_MEM(7, state); - - if (state->grp->gr_mem && state->grp->gr_mem[0]) { - members = sysdb_new_attrs(state); - if (!members) { - tevent_req_error(req, ENOMEM); - return; - } - ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER, - state->domain->name, - (const char **)state->grp->gr_mem); - if (ret) { - tevent_req_error(req, ret); - return; - } - } else { - members = NULL; - } - - subreq = sysdb_store_group_send(state, state->ev, state->handle, - state->domain, - state->grp->gr_name, - state->grp->gr_gid, - members, - ctx->entry_cache_timeout); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, get_gr_name_add_done, req); - return; - - case NSS_STATUS_UNAVAIL: - /* "remote" backend unavailable. Enter offline mode */ - tevent_req_error(req, ENXIO); - return; - - default: - DEBUG(2, ("proxy -> getgrgid_r failed for '%d' <%d>\n", - state->gid, status)); - tevent_req_error(req, EIO); - return; - } - - if (delete_group) { - - DEBUG(7, ("Group %d does not exist (or is invalid) on remote server," - " deleting!\n", state->gid)); - - subreq = sysdb_delete_group_send(state, state->ev, - NULL, state->handle, - state->domain, - NULL, state->gid); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, get_gr_gid_remove_done, req); - } -} - -static void get_gr_gid_remove_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct proxy_state *state = tevent_req_data(req, - struct proxy_state); - int ret; - - ret = sysdb_delete_group_recv(subreq); - talloc_zfree(subreq); - if (ret && ret != ENOENT) { - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, proxy_default_done, req); -} - -/* =Getgrent-wrapper======================================================*/ - -struct enum_groups_state { - struct tevent_context *ev; - struct proxy_ctx *ctx; - struct sysdb_ctx *sysdb; - struct sss_domain_info *domain; - struct sysdb_handle *handle; - - struct group *grp; - - size_t buflen; - char *buffer; - - bool in_transaction; -}; - -static void enum_groups_process(struct tevent_req *subreq); - -static struct tevent_req *enum_groups_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct proxy_ctx *ctx, - struct sysdb_ctx *sysdb, - struct sss_domain_info *domain) -{ - struct tevent_req *req, *subreq; - struct enum_groups_state *state; - enum nss_status status; - - DEBUG(7, ("Enumerating groups\n")); - - req = tevent_req_create(mem_ctx, &state, struct enum_groups_state); - if (!req) return NULL; - - state->ev = ev; - state->ctx = ctx; - state->sysdb = sysdb; - state->domain = domain; - state->handle = NULL; - - state->grp = talloc(state, struct group); - if (!state->grp) { - tevent_req_error(req, ENOMEM); - goto fail; - } - - state->buflen = DEFAULT_BUFSIZE; - state->buffer = talloc_size(state, state->buflen); - if (!state->buffer) { - tevent_req_error(req, ENOMEM); - goto fail; - } - - state->in_transaction = false; - - status = ctx->ops.setgrent(); - if (status != NSS_STATUS_SUCCESS) { - tevent_req_error(req, EIO); - goto fail; - } - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (!subreq) { - tevent_req_error(req, ENOMEM); - goto fail; - } - tevent_req_set_callback(subreq, enum_groups_process, req); - - return req; - -fail: - tevent_req_post(req, ev); - return req; -} - -static void enum_groups_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct enum_groups_state *state = tevent_req_data(req, - struct enum_groups_state); - struct proxy_ctx *ctx = state->ctx; - struct sss_domain_info *dom = ctx->be->domain; - enum nss_status status; - struct sysdb_attrs *members; - char *newbuf; - int ret; - - if (!state->in_transaction) { - ret = sysdb_transaction_recv(subreq, state, &state->handle); - if (ret) { - tevent_req_error(req, ret); - return; - } - talloc_zfree(subreq); - - state->in_transaction = true; - } else { - ret = sysdb_store_group_recv(subreq); - if (ret) { - /* Do not fail completely on errors. - * Just report the failure to save and go on */ - DEBUG(2, ("Failed to store group. Ignoring.\n")); - } - talloc_zfree(subreq); - } - -again: - /* always zero out the grp structure */ - memset(state->grp, 0, sizeof(struct group)); - - /* get entry */ - status = ctx->ops.getgrent_r(state->grp, - state->buffer, state->buflen, &ret); - - switch (status) { - case NSS_STATUS_TRYAGAIN: - /* buffer too small ? */ - if (state->buflen < MAX_BUF_SIZE) { - state->buflen *= 2; - } - if (state->buflen > MAX_BUF_SIZE) { - state->buflen = MAX_BUF_SIZE; - } - newbuf = talloc_realloc_size(state, state->buffer, state->buflen); - if (!newbuf) { - ret = ENOMEM; - goto fail; - } - state->buffer = newbuf; - goto again; - - case NSS_STATUS_NOTFOUND: - - /* we are done here */ - DEBUG(7, ("Enumeration completed.\n")); - - ctx->ops.endgrent(); - subreq = sysdb_transaction_commit_send(state, state->ev, - state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, proxy_default_done, req); - return; - - case NSS_STATUS_SUCCESS: - - DEBUG(7, ("Group found (%s, %d)\n", - state->grp->gr_name, state->grp->gr_gid)); - - /* gid=0 is an invalid value */ - /* also check that the id is in the valid range for this domain */ - if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) { - - DEBUG(2, ("Group [%s] filtered out! (id out of range)\n", - state->grp->gr_name)); - - goto again; /* skip */ - } - - DEBUG_GR_MEM(7, state); - - if (state->grp->gr_mem && state->grp->gr_mem[0]) { - members = sysdb_new_attrs(state); - if (!members) { - tevent_req_error(req, ENOMEM); - return; - } - ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER, - state->domain->name, - (const char **)state->grp->gr_mem); - if (ret) { - tevent_req_error(req, ret); - return; - } - } else { - members = NULL; - } - - subreq = sysdb_store_group_send(state, state->ev, state->handle, - state->domain, - state->grp->gr_name, - state->grp->gr_gid, - members, - ctx->entry_cache_timeout); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, enum_groups_process, req); - return; - - case NSS_STATUS_UNAVAIL: - /* "remote" backend unavailable. Enter offline mode */ - ret = ENXIO; - goto fail; - - default: - DEBUG(2, ("proxy -> getgrent_r failed (%d)[%s]\n", - ret, strerror(ret))); - goto fail; - } - -fail: - ctx->ops.endgrent(); - tevent_req_error(req, ret); -} - - -/* =Initgroups-wrapper====================================================*/ - -static void get_initgr_process(struct tevent_req *subreq); -static void get_initgr_groups_process(struct tevent_req *subreq); -static void get_initgr_groups_done(struct tevent_req *subreq); -static struct tevent_req *get_groups_by_gid_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sysdb_handle *handle, - struct proxy_ctx *ctx, - struct sss_domain_info *domain, - gid_t *gids, int num_gids); -static int get_groups_by_gid_recv(struct tevent_req *req); -static void get_groups_by_gid_process(struct tevent_req *subreq); -static struct tevent_req *get_group_from_gid_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sysdb_handle *handle, - struct proxy_ctx *ctx, - struct sss_domain_info *domain, - gid_t gid); -static int get_group_from_gid_recv(struct tevent_req *req); -static void get_group_from_gid_send_del_done(struct tevent_req *subreq); -static void get_group_from_gid_send_add_done(struct tevent_req *subreq); - - -static struct tevent_req *get_initgr_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct proxy_ctx *ctx, - struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - const char *name) -{ - struct tevent_req *req, *subreq; - struct proxy_state *state; - - req = tevent_req_create(mem_ctx, &state, struct proxy_state); - if (!req) return NULL; - - memset(state, 0, sizeof(struct proxy_state)); - - state->ev = ev; - state->ctx = ctx; - state->sysdb = sysdb; - state->domain = domain; - state->name = name; - - subreq = sysdb_transaction_send(state, state->ev, state->sysdb); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, get_initgr_process, req); - - return req; -} - -static void get_initgr_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct proxy_state *state = tevent_req_data(req, - struct proxy_state); - struct proxy_ctx *ctx = state->ctx; - struct sss_domain_info *dom = ctx->be->domain; - enum nss_status status; - char *buffer; - size_t buflen; - bool delete_user = false; - int ret; - - ret = sysdb_transaction_recv(subreq, state, &state->handle); - if (ret) { - tevent_req_error(req, ret); - return; - } - talloc_zfree(subreq); - - state->pwd = talloc(state, struct passwd); - if (!state->pwd) { - tevent_req_error(req, ENOMEM); - return; - } - - buflen = DEFAULT_BUFSIZE; - buffer = talloc_size(state, buflen); - if (!buffer) { - tevent_req_error(req, ENOMEM); - return; - } - - /* FIXME: should we move this call outside the transaction to keep the - * transaction as short as possible ? */ - status = ctx->ops.getpwnam_r(state->name, state->pwd, - buffer, buflen, &ret); - - switch (status) { - case NSS_STATUS_NOTFOUND: - - delete_user = true; - break; - - case NSS_STATUS_SUCCESS: - - /* uid=0 or gid=0 are invalid values */ - /* also check that the id is in the valid range for this domain */ - if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) || - OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) { - - DEBUG(2, ("User [%s] filtered out! (id out of range)\n", - state->name)); - delete_user = true; - break; - } - - subreq = sysdb_store_user_send(state, state->ev, state->handle, - state->domain, - state->pwd->pw_name, - state->pwd->pw_passwd, - state->pwd->pw_uid, - state->pwd->pw_gid, - state->pwd->pw_gecos, - state->pwd->pw_dir, - state->pwd->pw_shell, - NULL, ctx->entry_cache_timeout); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, get_initgr_groups_process, req); - return; - - case NSS_STATUS_UNAVAIL: - /* "remote" backend unavailable. Enter offline mode */ - tevent_req_error(req, ENXIO); - return; - - default: - DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n", - state->name, status)); - tevent_req_error(req, EIO); - return; - } - - if (delete_user) { - struct ldb_dn *dn; - - dn = sysdb_user_dn(state->sysdb, state, - state->domain->name, state->name); - if (!dn) { - tevent_req_error(req, ENOMEM); - return; - } - - subreq = sysdb_delete_entry_send(state, state->ev, state->handle, dn, true); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, get_pw_name_remove_done, req); - } -} - -static void get_initgr_groups_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct proxy_state *state = tevent_req_data(req, - struct proxy_state); - struct proxy_ctx *ctx = state->ctx; - enum nss_status status; - long int limit; - long int size; - long int num; - long int num_gids; - gid_t *gids; - int ret; - - ret = sysdb_store_user_recv(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - talloc_zfree(subreq); - - num_gids = 0; - limit = 4096; - num = 4096; - size = num*sizeof(gid_t); - gids = talloc_size(state, size); - if (!gids) { - tevent_req_error(req, ENOMEM); - return; - } - - state->gid = state->pwd->pw_gid; - -again: - /* FIXME: should we move this call outside the transaction to keep the - * transaction as short as possible ? */ - status = ctx->ops.initgroups_dyn(state->name, state->gid, &num_gids, - &num, &gids, limit, &ret); - switch (status) { - case NSS_STATUS_TRYAGAIN: - /* buffer too small ? */ - if (size < MAX_BUF_SIZE) { - num *= 2; - size = num*sizeof(gid_t); - } - if (size > MAX_BUF_SIZE) { - size = MAX_BUF_SIZE; - num = size/sizeof(gid_t); - } - limit = num; - gids = talloc_realloc_size(state, gids, size); - if (!gids) { - tevent_req_error(req, ENOMEM); - return; - } - goto again; /* retry with more memory */ - - case NSS_STATUS_SUCCESS: - DEBUG(4, ("User [%s] appears to be member of %lu groups\n", - state->name, num_gids)); - - subreq = get_groups_by_gid_send(state, state->ev, state->handle, - state->ctx, state->domain, - gids, num_gids); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, get_initgr_groups_done, req); - break; - - default: - DEBUG(2, ("proxy -> initgroups_dyn failed (%d)[%s]\n", - ret, strerror(ret))); - tevent_req_error(req, EIO); - return; - } -} - -static void get_initgr_groups_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct proxy_state *state = tevent_req_data(req, - struct proxy_state); - int ret; - - ret = get_groups_by_gid_recv(subreq); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - subreq = sysdb_transaction_commit_send(state, state->ev, state->handle); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, proxy_default_done, req); -} - -struct get_groups_state { - struct tevent_context *ev; - struct sysdb_handle *handle; - struct proxy_ctx *ctx; - struct sss_domain_info *domain; - - gid_t *gids; - int num_gids; - int cur_gid; -}; - -static struct tevent_req *get_groups_by_gid_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sysdb_handle *handle, - struct proxy_ctx *ctx, - struct sss_domain_info *domain, - gid_t *gids, int num_gids) -{ - struct tevent_req *req, *subreq; - struct get_groups_state *state; - - req = tevent_req_create(mem_ctx, &state, struct get_groups_state); - if (!req) return NULL; - - state->ev = ev; - state->handle = handle; - state->ctx = ctx; - state->domain = domain; - state->gids = gids; - state->num_gids = num_gids; - state->cur_gid = 0; - - subreq = get_group_from_gid_send(state, ev, handle, ctx, domain, gids[0]); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, get_groups_by_gid_process, req); - - return req; -} - -static void get_groups_by_gid_process(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct get_groups_state *state = tevent_req_data(req, - struct get_groups_state); - int ret; - - ret = get_group_from_gid_recv(subreq); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - state->cur_gid++; - if (state->cur_gid >= state->num_gids) { - tevent_req_done(req); - return; - } - - subreq = get_group_from_gid_send(state, - state->ev, state->handle, - state->ctx, state->domain, - state->gids[state->cur_gid]); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, get_groups_by_gid_process, req); -} - -static int get_groups_by_gid_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - -static struct tevent_req *get_group_from_gid_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct sysdb_handle *handle, - struct proxy_ctx *ctx, - struct sss_domain_info *domain, - gid_t gid) -{ - struct tevent_req *req, *subreq; - struct proxy_state *state; - struct sss_domain_info *dom = ctx->be->domain; - enum nss_status status; - char *buffer; - char *newbuf; - size_t buflen; - bool delete_group = false; - struct sysdb_attrs *members; - int ret; - - req = tevent_req_create(mem_ctx, &state, struct proxy_state); - if (!req) return NULL; - - memset(state, 0, sizeof(struct proxy_state)); - - state->ev = ev; - state->handle = handle; - state->ctx = ctx; - state->domain = domain; - state->gid = gid; - - state->grp = talloc(state, struct group); - if (!state->grp) { - ret = ENOMEM; - goto fail; - } - - buflen = DEFAULT_BUFSIZE; - buffer = talloc_size(state, buflen); - if (!buffer) { - ret = ENOMEM; - goto fail; - } - -again: - /* always zero out the grp structure */ - memset(state->grp, 0, sizeof(struct group)); - - status = ctx->ops.getgrgid_r(state->gid, state->grp, - buffer, buflen, &ret); - - switch (status) { - case NSS_STATUS_TRYAGAIN: - /* buffer too small ? */ - if (buflen < MAX_BUF_SIZE) { - buflen *= 2; - } - if (buflen > MAX_BUF_SIZE) { - buflen = MAX_BUF_SIZE; - } - newbuf = talloc_realloc_size(state, buffer, buflen); - if (!newbuf) { - ret = ENOMEM; - goto fail; - } - buffer = newbuf; - goto again; - - case NSS_STATUS_NOTFOUND: - - delete_group = true; - break; - - case NSS_STATUS_SUCCESS: - - /* gid=0 is an invalid value */ - /* also check that the id is in the valid range for this domain */ - if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) { - - DEBUG(2, ("Group [%s] filtered out! (id out of range)\n", - state->grp->gr_name)); - delete_group = true; - break; - } - - if (state->grp->gr_mem && state->grp->gr_mem[0]) { - members = sysdb_new_attrs(state); - if (!members) { - ret = ENOMEM; - goto fail; - } - ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER, - state->domain->name, - (const char **)state->grp->gr_mem); - if (ret) { - goto fail; - } - } else { - members = NULL; - } - - subreq = sysdb_store_group_send(state, state->ev, state->handle, - state->domain, - state->grp->gr_name, - state->grp->gr_gid, - members, - ctx->entry_cache_timeout); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, get_group_from_gid_send_add_done, req); - break; - - case NSS_STATUS_UNAVAIL: - /* "remote" backend unavailable. Enter offline mode */ - ret = ENXIO; - goto fail; - - default: - DEBUG(2, ("proxy -> getgrgid_r failed for '%d' <%d>\n", - state->gid, status)); - ret = EIO; - goto fail; - } - - if (delete_group) { - subreq = sysdb_delete_group_send(state, state->ev, - NULL, state->handle, - state->domain, - NULL, state->gid); - if (!subreq) { - ret = ENOMEM; - goto fail; - } - tevent_req_set_callback(subreq, get_group_from_gid_send_del_done, req); - } - - return req; - -fail: - tevent_req_error(req, ret); - tevent_req_post(req, ev); - return req; -} - -static void get_group_from_gid_send_add_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - int ret; - - ret = sysdb_store_group_recv(subreq); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -static void get_group_from_gid_send_del_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - int ret; - - ret = sysdb_delete_entry_recv(subreq); - talloc_zfree(subreq); - if (ret && ret != ENOENT) { - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -static int get_group_from_gid_recv(struct tevent_req *req) -{ - TEVENT_REQ_RETURN_ON_ERROR(req); - - return EOK; -} - - -/* =Proxy_Id-Functions====================================================*/ - -static void proxy_get_account_info_done(struct tevent_req *subreq); - -/* TODO: See if we can use async_req code */ -static void proxy_get_account_info(struct be_req *breq) -{ - struct tevent_req *subreq; - struct be_acct_req *ar; - struct proxy_ctx *ctx; - struct tevent_context *ev; - struct sysdb_ctx *sysdb; - struct sss_domain_info *domain; - uid_t uid; - gid_t gid; - - ar = talloc_get_type(breq->req_data, struct be_acct_req); - ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data, struct proxy_ctx); - ev = breq->be_ctx->ev; - sysdb = breq->be_ctx->sysdb; - domain = breq->be_ctx->domain; - - if (be_is_offline(breq->be_ctx)) { - return proxy_reply(breq, DP_ERR_OFFLINE, EAGAIN, "Offline"); - } - - /* for now we support only core attrs */ - if (ar->attr_type != BE_ATTR_CORE) { - return proxy_reply(breq, DP_ERR_FATAL, EINVAL, "Invalid attr type"); - } - - switch (ar->entry_type & 0xFFF) { - case BE_REQ_USER: /* user */ - switch (ar->filter_type) { - case BE_FILTER_NAME: - if (strchr(ar->filter_value, '*')) { - subreq = enum_users_send(breq, ev, ctx, - sysdb, domain); - if (!subreq) { - return proxy_reply(breq, DP_ERR_FATAL, - ENOMEM, "Out of memory"); - } - tevent_req_set_callback(subreq, - proxy_get_account_info_done, breq); - return; - } else { - subreq = get_pw_name_send(breq, ev, ctx, - sysdb, domain, - ar->filter_value); - if (!subreq) { - return proxy_reply(breq, DP_ERR_FATAL, - ENOMEM, "Out of memory"); - } - tevent_req_set_callback(subreq, - proxy_get_account_info_done, breq); - return; - } - break; - - case BE_FILTER_IDNUM: - if (strchr(ar->filter_value, '*')) { - return proxy_reply(breq, DP_ERR_FATAL, - EINVAL, "Invalid attr type"); - } else { - char *endptr; - errno = 0; - uid = (uid_t)strtol(ar->filter_value, &endptr, 0); - if (errno || *endptr || (ar->filter_value == endptr)) { - return proxy_reply(breq, DP_ERR_FATAL, - EINVAL, "Invalid attr type"); - } - subreq = get_pw_uid_send(breq, ev, ctx, - sysdb, domain, uid); - if (!subreq) { - return proxy_reply(breq, DP_ERR_FATAL, - ENOMEM, "Out of memory"); - } - tevent_req_set_callback(subreq, - proxy_get_account_info_done, breq); - return; - } - break; - default: - return proxy_reply(breq, DP_ERR_FATAL, - EINVAL, "Invalid filter type"); - } - break; - - case BE_REQ_GROUP: /* group */ - switch (ar->filter_type) { - case BE_FILTER_NAME: - if (strchr(ar->filter_value, '*')) { - subreq = enum_groups_send(breq, ev, ctx, - sysdb, domain); - if (!subreq) { - return proxy_reply(breq, DP_ERR_FATAL, - ENOMEM, "Out of memory"); - } - tevent_req_set_callback(subreq, - proxy_get_account_info_done, breq); - return; - } else { - subreq = get_gr_name_send(breq, ev, ctx, - sysdb, domain, - ar->filter_value); - if (!subreq) { - return proxy_reply(breq, DP_ERR_FATAL, - ENOMEM, "Out of memory"); - } - tevent_req_set_callback(subreq, - proxy_get_account_info_done, breq); - return; - } - break; - case BE_FILTER_IDNUM: - if (strchr(ar->filter_value, '*')) { - return proxy_reply(breq, DP_ERR_FATAL, - EINVAL, "Invalid attr type"); - } else { - char *endptr; - errno = 0; - gid = (gid_t)strtol(ar->filter_value, &endptr, 0); - if (errno || *endptr || (ar->filter_value == endptr)) { - return proxy_reply(breq, DP_ERR_FATAL, - EINVAL, "Invalid attr type"); - } - subreq = get_gr_gid_send(breq, ev, ctx, - sysdb, domain, gid); - if (!subreq) { - return proxy_reply(breq, DP_ERR_FATAL, - ENOMEM, "Out of memory"); - } - tevent_req_set_callback(subreq, - proxy_get_account_info_done, breq); - return; - } - break; - default: - return proxy_reply(breq, DP_ERR_FATAL, - EINVAL, "Invalid filter type"); - } - break; - - case BE_REQ_INITGROUPS: /* init groups for user */ - if (ar->filter_type != BE_FILTER_NAME) { - return proxy_reply(breq, DP_ERR_FATAL, - EINVAL, "Invalid filter type"); - } - if (strchr(ar->filter_value, '*')) { - return proxy_reply(breq, DP_ERR_FATAL, - EINVAL, "Invalid filter value"); - } - if (ctx->ops.initgroups_dyn == NULL) { - return proxy_reply(breq, DP_ERR_FATAL, - ENODEV, "Initgroups call not supported"); - } - subreq = get_initgr_send(breq, ev, ctx, sysdb, - domain, ar->filter_value); - if (!subreq) { - return proxy_reply(breq, DP_ERR_FATAL, - ENOMEM, "Out of memory"); - } - tevent_req_set_callback(subreq, - proxy_get_account_info_done, breq); - return; - - default: /*fail*/ - break; - } - - return proxy_reply(breq, DP_ERR_FATAL, - EINVAL, "Invalid request type"); -} - -static void proxy_get_account_info_done(struct tevent_req *subreq) -{ - struct be_req *breq = tevent_req_callback_data(subreq, - struct be_req); - int ret; - ret = proxy_default_recv(subreq); - talloc_zfree(subreq); - if (ret) { - if (ret == ENXIO) { - DEBUG(2, ("proxy returned UNAVAIL error, going offline!\n")); - be_mark_offline(breq->be_ctx); - } - proxy_reply(breq, DP_ERR_FATAL, ret, NULL); - return; - } - proxy_reply(breq, DP_ERR_OK, EOK, NULL); -} - -static void proxy_shutdown(struct be_req *req) -{ - /* TODO: Clean up any internal data */ - req->fn(req, DP_ERR_OK, EOK, NULL); -} - -static void proxy_auth_shutdown(struct be_req *req) -{ - talloc_free(req->be_ctx->bet_info[BET_AUTH].pvt_bet_data); - req->fn(req, DP_ERR_OK, EOK, NULL); -} - -struct bet_ops proxy_id_ops = { - .handler = proxy_get_account_info, - .finalize = proxy_shutdown -}; - -struct bet_ops proxy_auth_ops = { - .handler = proxy_pam_handler, - .finalize = proxy_auth_shutdown -}; - -struct bet_ops proxy_access_ops = { - .handler = proxy_pam_handler, - .finalize = proxy_auth_shutdown -}; - -struct bet_ops proxy_chpass_ops = { - .handler = proxy_pam_handler, - .finalize = proxy_auth_shutdown -}; - -static void *proxy_dlsym(void *handle, const char *functemp, char *libname) -{ - char *funcname; - void *funcptr; - - funcname = talloc_asprintf(NULL, functemp, libname); - if (funcname == NULL) return NULL; - - funcptr = dlsym(handle, funcname); - talloc_free(funcname); - - return funcptr; -} - -int sssm_proxy_init(struct be_ctx *bectx, - struct bet_ops **ops, void **pvt_data) -{ - struct proxy_ctx *ctx; - char *libname; - char *libpath; - void *handle; - int ret; - - ctx = talloc_zero(bectx, struct proxy_ctx); - if (!ctx) { - return ENOMEM; - } - ctx->be = bectx; - - ret = confdb_get_int(bectx->cdb, ctx, bectx->conf_path, - CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT, 600, - &ctx->entry_cache_timeout); - if (ret != EOK) goto done; - - ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path, - CONFDB_PROXY_LIBNAME, NULL, &libname); - if (ret != EOK) goto done; - if (libname == NULL) { - ret = ENOENT; - goto done; - } - - libpath = talloc_asprintf(ctx, "libnss_%s.so.2", libname); - if (!libpath) { - ret = ENOMEM; - goto done; - } - - handle = dlopen(libpath, RTLD_NOW); - if (!handle) { - DEBUG(0, ("Unable to load %s module with path, error: %s\n", - libpath, dlerror())); - ret = ELIBACC; - goto done; - } - - ctx->ops.getpwnam_r = proxy_dlsym(handle, "_nss_%s_getpwnam_r", libname); - if (!ctx->ops.getpwnam_r) { - DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror())); - ret = ELIBBAD; - goto done; - } - - ctx->ops.getpwuid_r = proxy_dlsym(handle, "_nss_%s_getpwuid_r", libname); - if (!ctx->ops.getpwuid_r) { - DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror())); - ret = ELIBBAD; - goto done; - } - - ctx->ops.setpwent = proxy_dlsym(handle, "_nss_%s_setpwent", libname); - if (!ctx->ops.setpwent) { - DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror())); - ret = ELIBBAD; - goto done; - } - - ctx->ops.getpwent_r = proxy_dlsym(handle, "_nss_%s_getpwent_r", libname); - if (!ctx->ops.getpwent_r) { - DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror())); - ret = ELIBBAD; - goto done; - } - - ctx->ops.endpwent = proxy_dlsym(handle, "_nss_%s_endpwent", libname); - if (!ctx->ops.endpwent) { - DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror())); - ret = ELIBBAD; - goto done; - } - - ctx->ops.getgrnam_r = proxy_dlsym(handle, "_nss_%s_getgrnam_r", libname); - if (!ctx->ops.getgrnam_r) { - DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror())); - ret = ELIBBAD; - goto done; - } - - ctx->ops.getgrgid_r = proxy_dlsym(handle, "_nss_%s_getgrgid_r", libname); - if (!ctx->ops.getgrgid_r) { - DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror())); - ret = ELIBBAD; - goto done; - } - - ctx->ops.setgrent = proxy_dlsym(handle, "_nss_%s_setgrent", libname); - if (!ctx->ops.setgrent) { - DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror())); - ret = ELIBBAD; - goto done; - } - - ctx->ops.getgrent_r = proxy_dlsym(handle, "_nss_%s_getgrent_r", libname); - if (!ctx->ops.getgrent_r) { - DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror())); - ret = ELIBBAD; - goto done; - } - - ctx->ops.endgrent = proxy_dlsym(handle, "_nss_%s_endgrent", libname); - if (!ctx->ops.endgrent) { - DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror())); - ret = ELIBBAD; - goto done; - } - - ctx->ops.initgroups_dyn = proxy_dlsym(handle, "_nss_%s_initgroups_dyn", - libname); - if (!ctx->ops.initgroups_dyn) { - DEBUG(1, ("The '%s' library does not provides the " - "_nss_XXX_initgroups_dyn function!\n" - "initgroups will be slow as it will require " - "full groups enumeration!\n", libname)); - } - - *ops = &proxy_id_ops; - *pvt_data = ctx; - ret = EOK; - -done: - if (ret != EOK) { - talloc_free(ctx); - } - return ret; -} - -int sssm_proxy_auth_init(struct be_ctx *bectx, - struct bet_ops **ops, void **pvt_data) -{ - struct proxy_auth_ctx *ctx; - int ret; - - ctx = talloc(bectx, struct proxy_auth_ctx); - if (!ctx) { - return ENOMEM; - } - ctx->be = bectx; - - ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path, - CONFDB_PROXY_PAM_TARGET, NULL, - &ctx->pam_target); - if (ret != EOK) goto done; - if (!ctx->pam_target) { - DEBUG(1, ("Missing option proxy_pam_target.\n")); - ret = EINVAL; - goto done; - } - - *ops = &proxy_auth_ops; - *pvt_data = ctx; - -done: - if (ret != EOK) { - talloc_free(ctx); - } - return ret; -} - -int sssm_proxy_access_init(struct be_ctx *bectx, - struct bet_ops **ops, void **pvt_data) -{ - int ret; - ret = sssm_proxy_auth_init(bectx, ops, pvt_data); - *ops = &proxy_access_ops; - return ret; -} - -int sssm_proxy_chpass_init(struct be_ctx *bectx, - struct bet_ops **ops, void **pvt_data) -{ - int ret; - ret = sssm_proxy_auth_init(bectx, ops, pvt_data); - *ops = &proxy_chpass_ops; - return ret; -} diff --git a/server/providers/sssd_be.exports b/server/providers/sssd_be.exports deleted file mode 100644 index 9afa106be..000000000 --- a/server/providers/sssd_be.exports +++ /dev/null @@ -1,4 +0,0 @@ -{ - global: - *; -}; -- cgit