summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--src/providers/ldap/sdap_async_sudo.c710
-rw-r--r--src/providers/ldap/sdap_sudo.c675
3 files changed, 711 insertions, 675 deletions
diff --git a/Makefile.am b/Makefile.am
index 2bc47f769..d716755a7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1186,6 +1186,7 @@ if BUILD_SUDO
libsss_ldap_common_la_SOURCES += \
src/providers/ldap/sdap_sudo_cache.c \
src/providers/ldap/sdap_sudo_timer.c \
+ src/providers/ldap/sdap_async_sudo.c \
src/providers/ldap/sdap_sudo.c
endif
diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c
new file mode 100644
index 000000000..d24420a23
--- /dev/null
+++ b/src/providers/ldap/sdap_async_sudo.c
@@ -0,0 +1,710 @@
+/*
+ SSSD
+
+ Async LDAP Helper routines for sudo
+
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2012 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <errno.h>
+#include <talloc.h>
+#include <tevent.h>
+
+#include "providers/dp_backend.h"
+#include "providers/ldap/ldap_common.h"
+#include "providers/ldap/sdap.h"
+#include "providers/ldap/sdap_async.h"
+#include "providers/ldap/sdap_sudo.h"
+#include "providers/ldap/sdap_sudo_cache.h"
+#include "db/sysdb_sudo.h"
+
+struct sdap_sudo_load_sudoers_state {
+ struct tevent_context *ev;
+ struct sdap_sudo_ctx *sudo_ctx;
+ struct sdap_options *opts;
+ struct sdap_handle *sh;
+ struct sysdb_attrs **ldap_rules; /* search result will be stored here */
+ size_t ldap_rules_count; /* search result will be stored here */
+
+ const char **attrs;
+ const char *filter;
+ size_t base_iter;
+ struct sdap_search_base **search_bases;
+ int timeout;
+};
+
+struct sdap_sudo_refresh_state {
+ struct be_ctx *be_ctx;
+ struct be_sudo_req *sudo_req;
+ struct sdap_options *opts;
+ struct sdap_id_op *sdap_op;
+ struct sdap_id_conn_cache *sdap_conn_cache;
+
+ int dp_error;
+ int error;
+};
+
+static int sdap_sudo_connect(struct tevent_req *req);
+
+static void sdap_sudo_connect_done(struct tevent_req *subreq);
+
+static struct tevent_req * sdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct be_sudo_req *sudo_req,
+ struct sdap_options *opts,
+ struct sdap_handle *sh);
+
+static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req);
+
+static void sdap_sudo_load_sudoers_process(struct tevent_req *subreq);
+
+static int sdap_sudo_load_sudoers_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *rules_count,
+ struct sysdb_attrs ***rules);
+
+static void sdap_sudo_load_sudoers_done(struct tevent_req *req);
+
+static int sdap_sudo_purge_sudoers(struct sysdb_ctx *sysdb_ctx,
+ struct sss_domain_info *domain,
+ struct be_sudo_req *sudo_req);
+
+static int sdap_sudo_store_sudoers(struct sysdb_ctx *sysdb_ctx,
+ struct sdap_options *opts,
+ size_t rules_count,
+ struct sysdb_attrs **rules);
+
+static const char *sdap_sudo_build_filter(TALLOC_CTX *mem_ctx,
+ struct sdap_attr_map *map,
+ struct be_sudo_req *sudo_req);
+
+static const char *sdap_sudo_build_user_filter(TALLOC_CTX *mem_ctx,
+ struct sdap_attr_map *map,
+ const char *username,
+ uid_t uid,
+ char **groups);
+
+struct tevent_req *sdap_sudo_refresh_send(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct be_sudo_req *sudo_req,
+ struct sdap_options *opts,
+ struct sdap_id_conn_cache *conn_cache)
+{
+ struct tevent_req *req = NULL;
+ struct sdap_sudo_refresh_state *state = NULL;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_refresh_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->be_ctx = be_ctx;
+ state->sudo_req = sudo_req;
+ state->opts = opts;
+ state->sdap_op = NULL;
+ state->sdap_conn_cache = conn_cache;
+ state->dp_error = DP_ERR_OK;
+ state->error = EOK;
+
+ switch (sudo_req->type) {
+ case BE_REQ_SUDO_ALL:
+ DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh for: <ALL>\n"));
+ break;
+ case BE_REQ_SUDO_DEFAULTS:
+ DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh of cn=defaults\n"));
+ break;
+ case BE_REQ_SUDO_USER:
+ DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh for: %s\n",
+ sudo_req->username));
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type));
+ ret = EINVAL;
+ goto immediately;
+ }
+
+ ret = sdap_sudo_connect(req);
+ if (ret == EAGAIN) {
+ /* asynchronous processing */
+ return req;
+ }
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, be_ctx->ev);
+
+ return req;
+}
+
+int sdap_sudo_refresh_recv(struct tevent_req *req,
+ int *dp_error,
+ int *error)
+{
+ struct sdap_sudo_refresh_state *state = NULL;
+
+ state = tevent_req_data(req, struct sdap_sudo_refresh_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *dp_error = state->dp_error;
+ *error = state->error;
+
+ return EOK;
+}
+
+int sdap_sudo_connect(struct tevent_req *req)
+{
+ struct tevent_req *subreq = NULL;
+ struct sdap_sudo_refresh_state *state = NULL;
+ int ret;
+
+ state = tevent_req_data(req, struct sdap_sudo_refresh_state);
+
+ if (be_is_offline(state->be_ctx)) {
+ state->dp_error = DP_ERR_OFFLINE;
+ state->error = EAGAIN;
+ return EOK;
+ }
+
+ if (state->sdap_op == NULL) {
+ state->sdap_op = sdap_id_op_create(state, state->sdap_conn_cache);
+ if (state->sdap_op == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create() failed\n"));
+ state->dp_error = DP_ERR_FATAL;
+ state->error = EIO;
+ return EIO;
+ }
+ }
+
+ subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("sdap_id_op_connect_send() failed: %d(%s)\n", ret, strerror(ret)));
+ talloc_zfree(state->sdap_op);
+ state->dp_error = DP_ERR_FATAL;
+ state->error = ret;
+ return ret;
+ }
+
+ tevent_req_set_callback(subreq, sdap_sudo_connect_done, req);
+
+ return EAGAIN;
+}
+
+void sdap_sudo_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = NULL; /* req from sdap_sudo_refresh_send() */
+ struct sdap_sudo_refresh_state *state = NULL;
+ int dp_error;
+ int ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_sudo_refresh_state);
+
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
+
+ if (dp_error == DP_ERR_OFFLINE) {
+ talloc_zfree(state->sdap_op);
+ state->dp_error = DP_ERR_OFFLINE;
+ state->error = EAGAIN;
+ tevent_req_done(req);
+ return;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("SUDO LDAP connection failed - %s\n", strerror(ret)));
+ goto fail;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, ("SUDO LDAP connection successful\n"));
+
+ subreq = sdap_sudo_load_sudoers_send(state, state->be_ctx->ev,
+ state->sudo_req, state->opts,
+ sdap_id_op_handle(state->sdap_op));
+ if (subreq == NULL) {
+ ret = EFAULT;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, sdap_sudo_load_sudoers_done, req);
+
+ return;
+
+fail:
+ state->dp_error = DP_ERR_FATAL;
+ state->error = ret;
+ tevent_req_error(req, ret);
+}
+
+struct tevent_req * sdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct be_sudo_req *sudo_req,
+ struct sdap_options *opts,
+ struct sdap_handle *sh)
+
+
+
+{
+ struct tevent_req *req = NULL;
+ struct sdap_sudo_load_sudoers_state *state = NULL;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_load_sudoers_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->opts = opts;
+ state->sh = sh;
+ state->base_iter = 0;
+ state->search_bases = opts->sudo_search_bases;
+ state->timeout = dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT);
+ state->ldap_rules = NULL;
+ state->ldap_rules_count = 0;
+
+ if (!state->search_bases) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("SUDOERS lookup request without a search base\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ /* create filter */
+ state->filter = sdap_sudo_build_filter(state, opts->sudorule_map, sudo_req);
+ if (state->filter == NULL) {
+ goto fail;
+ }
+
+ /* create attrs from map */
+ ret = build_attrs_from_map(state, opts->sudorule_map, SDAP_OPTS_SUDO,
+ NULL, &state->attrs, NULL);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ /* begin search */
+ ret = sdap_sudo_load_sudoers_next_base(req);
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ }
+
+ return req;
+
+fail:
+ talloc_zfree(req);
+ return NULL;
+}
+
+static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req)
+{
+ struct tevent_req *subreq = NULL;
+ struct sdap_sudo_load_sudoers_state *state = NULL;
+ struct sdap_search_base *search_base = NULL;
+ char *filter = NULL;
+
+ state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state);
+ search_base = state->search_bases[state->base_iter];
+ if (search_base == NULL) {
+ /* should not happen */
+ DEBUG(SSSDBG_CRIT_FAILURE, ("search_base is null\n"));
+ return EFAULT;
+ }
+
+ /* create filter */
+ filter = sdap_get_id_specific_filter(state, state->filter,
+ search_base->filter);
+ if (filter == NULL) {
+ return ENOMEM;
+ }
+
+ /* send request */
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Searching for sudo rules with base [%s]\n",
+ search_base->basedn));
+
+ subreq = sdap_get_generic_send(state,
+ state->ev,
+ state->opts,
+ state->sh,
+ search_base->basedn,
+ search_base->scope,
+ filter,
+ state->attrs,
+ state->opts->sudorule_map,
+ SDAP_OPTS_SUDO,
+ state->timeout,
+ true);
+ if (subreq == NULL) {
+ return ENOMEM;
+ }
+
+ tevent_req_set_callback(subreq, sdap_sudo_load_sudoers_process, req);
+
+ return EOK;
+}
+
+static void sdap_sudo_load_sudoers_process(struct tevent_req *subreq)
+{
+ struct tevent_req *req = NULL;
+ struct sdap_sudo_load_sudoers_state *state = NULL;
+ struct sdap_search_base *search_base = NULL;
+ struct sysdb_attrs **attrs = NULL;
+ size_t count;
+ int ret;
+ int i;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state);
+ search_base = state->search_bases[state->base_iter];
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Receiving sudo rules with base [%s]\n",
+ search_base->basedn));
+
+ ret = sdap_get_generic_recv(subreq, state, &count, &attrs);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ /* add rules to result */
+ if (count > 0) {
+ state->ldap_rules = talloc_realloc(state, state->ldap_rules,
+ struct sysdb_attrs *,
+ state->ldap_rules_count + count);
+ if (state->ldap_rules == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ state->ldap_rules[state->ldap_rules_count + i] = talloc_steal(
+ state->ldap_rules, attrs[i]);
+ }
+
+ state->ldap_rules_count += count;
+ }
+
+ /* go to next base */
+ state->base_iter++;
+ if (state->search_bases[state->base_iter]) {
+ ret = sdap_sudo_load_sudoers_next_base(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ }
+
+ return;
+ }
+
+ /* we are done */
+ tevent_req_done(req);
+}
+
+int sdap_sudo_load_sudoers_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *rules_count,
+ struct sysdb_attrs ***rules)
+{
+ struct sdap_sudo_load_sudoers_state *state = NULL;
+
+ state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *rules_count = state->ldap_rules_count;
+ *rules = talloc_steal(mem_ctx, state->ldap_rules);
+
+ return EOK;
+}
+
+void sdap_sudo_load_sudoers_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = NULL; /* req from sdap_sudo_refresh_send() */
+ struct sdap_sudo_refresh_state *state = NULL;
+ struct sysdb_attrs **rules = NULL;
+ size_t rules_count;
+ int ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_sudo_refresh_state);
+
+ ret = sdap_sudo_load_sudoers_recv(subreq, state, &rules_count, &rules);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, ("Received %d rules\n", rules_count));
+
+ /* purge cache */
+ ret = sdap_sudo_purge_sudoers(state->be_ctx->sysdb, state->be_ctx->domain,
+ state->sudo_req);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* store rules */
+ ret = sdap_sudo_store_sudoers(state->be_ctx->sysdb, state->opts,
+ rules_count, rules);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, ("Sudoers is successfuly stored in cache\n"));
+
+ ret = EOK;
+
+done:
+ state->error = ret;
+ if (ret == EOK) {
+ state->dp_error = DP_ERR_OK;
+ tevent_req_done(req);
+ } else {
+ state->dp_error = DP_ERR_FATAL;
+ tevent_req_error(req, ret);
+ }
+}
+
+int sdap_sudo_purge_sudoers(struct sysdb_ctx *sysdb_ctx,
+ struct sss_domain_info *domain,
+ struct be_sudo_req *sudo_req)
+{
+ TALLOC_CTX *tmp_ctx;
+ char *filter = NULL;
+ char **sudouser = NULL;
+ int ret = EOK;
+ errno_t sret;
+ bool in_transaction = false;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
+ return ENOMEM;
+ }
+
+ ret = sysdb_transaction_start(sysdb_ctx);
+ if (ret != EOK) {
+ goto done;
+ }
+ in_transaction = true;
+
+ switch (sudo_req->type) {
+ case BE_REQ_SUDO_ALL:
+ DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of all rules\n"));
+ ret = sysdb_sudo_purge_all(sysdb_ctx);
+ break;
+ case BE_REQ_SUDO_DEFAULTS:
+ DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of default options\n"));
+ ret = sysdb_sudo_purge_byname(sysdb_ctx, SDAP_SUDO_DEFAULTS);
+ break;
+ case BE_REQ_SUDO_USER:
+ DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of user's [%s] rules\n",
+ sudo_req->username));
+
+ /* netgroups */
+ ret = sysdb_get_sudo_filter(tmp_ctx, NULL, 0, NULL,
+ SYSDB_SUDO_FILTER_NGRS, &filter);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create filter to purge "
+ "SUDOers cache [%d]: %s\n", ret, strerror(ret)));
+ goto done;
+ }
+
+ ret = sysdb_sudo_purge_byfilter(sysdb_ctx, filter);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to purge SUDOers cache "
+ "(netgroups) [%d]: %s\n", ret, strerror(ret)));
+ goto done;
+ }
+
+ /* user, uid, groups */
+ sudouser = sysdb_sudo_build_sudouser(tmp_ctx, sudo_req->username,
+ sudo_req->uid, sudo_req->groups,
+ true);
+ if (sudouser == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create sudoUser to purge "
+ "SUDOers cache [%d]: %s\n", ret, strerror(ret)));
+ goto done;
+ }
+
+ ret = sysdb_sudo_purge_bysudouser(sysdb_ctx, sudouser);
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type));
+ return EINVAL;
+ }
+
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to purge SUDOers cache [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+
+ ret = sysdb_transaction_commit(sysdb_ctx);
+ if (ret == EOK) {
+ in_transaction = false;
+ }
+
+done:
+ if (in_transaction) {
+ sret = sysdb_transaction_cancel(sysdb_ctx);
+ if (sret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Could not cancel transaction\n"));
+ }
+ }
+
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sdap_sudo_store_sudoers(struct sysdb_ctx *sysdb_ctx,
+ struct sdap_options *opts,
+ size_t rules_count,
+ struct sysdb_attrs **rules)
+{
+ errno_t ret;
+
+ /* Empty sudoers? Done. */
+ if (rules_count == 0 || rules == NULL) {
+ return EOK;
+ }
+
+ ret = sdap_save_native_sudorule_list(sysdb_ctx, opts->sudorule_map,
+ rules, rules_count);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, ("failed to save sudo rules [%d]: %s\n",
+ ret, strerror(ret)));
+ return ret;
+ }
+
+ return EOK;
+}
+
+const char *sdap_sudo_build_filter(TALLOC_CTX *mem_ctx,
+ struct sdap_attr_map *map,
+ struct be_sudo_req *sudo_req)
+{
+ switch (sudo_req->type) {
+ case BE_REQ_SUDO_ALL:
+ return talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_ALL,
+ map[SDAP_OC_SUDORULE].name);
+ break;
+ case BE_REQ_SUDO_DEFAULTS:
+ return talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_DEFAULTS,
+ map[SDAP_OC_SUDORULE].name,
+ map[SDAP_AT_SUDO_NAME].name,
+ SDAP_SUDO_DEFAULTS); /* FIXME: add option for this */
+ break;
+ case BE_REQ_SUDO_USER:
+ return sdap_sudo_build_user_filter(mem_ctx, map, sudo_req->username,
+ sudo_req->uid, sudo_req->groups);
+
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type));
+ return NULL;
+ }
+}
+
+/* alway update cn=defaults and sudoUser=ALL */
+const char *sdap_sudo_build_user_filter(TALLOC_CTX *mem_ctx,
+ struct sdap_attr_map *map,
+ const char *username,
+ uid_t uid,
+ char **groups)
+{
+ char *filter = NULL;
+ char *output = NULL;
+ char *sanitized = NULL;
+ char **group = NULL;
+ int ret;
+
+ /* user name */
+ ret = sss_filter_sanitize(filter, username, &sanitized);
+ if (ret != EOK) {
+ goto fail;
+ }
+ filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_USERNAME,
+ map[SDAP_AT_SUDO_USER].name,
+ sanitized);
+ if (filter == NULL) {
+ goto fail;
+ }
+
+ /* user uid */
+ filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_UID,
+ map[SDAP_AT_SUDO_USER].name,
+ uid);
+ if (filter == NULL) {
+ goto fail;
+ }
+
+ /* groups */
+ if (groups != NULL) {
+ for (group = groups; *group != NULL; group++) {
+ ret = sss_filter_sanitize(filter, *group, &sanitized);
+ if (ret != EOK) {
+ goto fail;
+ }
+ filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_GROUP,
+ map[SDAP_AT_SUDO_USER].name,
+ sanitized);
+ if (filter == NULL) {
+ goto fail;
+ }
+ }
+ }
+
+ /* netgroups */
+ /*
+ * FIXME: load only netgroups user is member of
+ * FIXME: add option to disable this filter
+ */
+ filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_NETGROUP,
+ map[SDAP_AT_SUDO_USER].name,
+ "*");
+ if (filter == NULL) {
+ goto fail;
+ }
+
+
+ output = talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_USER,
+ map[SDAP_OC_SUDORULE].name,
+ map[SDAP_AT_SUDO_NAME].name,
+ SDAP_SUDO_DEFAULTS, /* FIXME: add option for this */
+ map[SDAP_AT_SUDO_USER].name,
+ filter);
+
+ talloc_free(filter);
+ return output;
+
+fail:
+ talloc_free(filter);
+ return NULL;
+}
diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c
index 75d30430c..3bef454a1 100644
--- a/src/providers/ldap/sdap_sudo.c
+++ b/src/providers/ldap/sdap_sudo.c
@@ -131,72 +131,6 @@ int sdap_sudo_setup_tasks(struct sdap_id_ctx *id_ctx)
return EOK;
}
-struct sdap_sudo_load_sudoers_state {
- struct tevent_context *ev;
- struct sdap_sudo_ctx *sudo_ctx;
- struct sdap_options *opts;
- struct sdap_handle *sh;
- struct sysdb_attrs **ldap_rules; /* search result will be stored here */
- size_t ldap_rules_count; /* search result will be stored here */
-
- const char **attrs;
- const char *filter;
- size_t base_iter;
- struct sdap_search_base **search_bases;
- int timeout;
-};
-
-struct sdap_sudo_refresh_state {
- struct be_ctx *be_ctx;
- struct be_sudo_req *sudo_req;
- struct sdap_options *opts;
- struct sdap_id_op *sdap_op;
- struct sdap_id_conn_cache *sdap_conn_cache;
-
- int dp_error;
- int error;
-};
-
-static int sdap_sudo_connect(struct tevent_req *req);
-
-static void sdap_sudo_connect_done(struct tevent_req *subreq);
-
-static struct tevent_req * sdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct be_sudo_req *sudo_req,
- struct sdap_options *opts,
- struct sdap_handle *sh);
-
-static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req);
-
-static void sdap_sudo_load_sudoers_process(struct tevent_req *subreq);
-
-static int sdap_sudo_load_sudoers_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx,
- size_t *rules_count,
- struct sysdb_attrs ***rules);
-
-static void sdap_sudo_load_sudoers_done(struct tevent_req *req);
-
-static int sdap_sudo_purge_sudoers(struct sysdb_ctx *sysdb_ctx,
- struct sss_domain_info *domain,
- struct be_sudo_req *sudo_req);
-
-static int sdap_sudo_store_sudoers(struct sysdb_ctx *sysdb_ctx,
- struct sdap_options *opts,
- size_t rules_count,
- struct sysdb_attrs **rules);
-
-static const char *sdap_sudo_build_filter(TALLOC_CTX *mem_ctx,
- struct sdap_attr_map *map,
- struct be_sudo_req *sudo_req);
-
-static const char *sdap_sudo_build_user_filter(TALLOC_CTX *mem_ctx,
- struct sdap_attr_map *map,
- const char *username,
- uid_t uid,
- char **groups);
-
static void sdap_sudo_reply(struct tevent_req *req)
{
struct be_req *be_req = NULL;
@@ -256,612 +190,3 @@ void sdap_sudo_handler(struct be_req *be_req)
fail:
sdap_handler_done(be_req, DP_ERR_FATAL, ret, NULL);
}
-
-struct tevent_req *sdap_sudo_refresh_send(TALLOC_CTX *mem_ctx,
- struct be_ctx *be_ctx,
- struct be_sudo_req *sudo_req,
- struct sdap_options *opts,
- struct sdap_id_conn_cache *conn_cache)
-{
- struct tevent_req *req = NULL;
- struct sdap_sudo_refresh_state *state = NULL;
- int ret;
-
- req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_refresh_state);
- if (!req) {
- return NULL;
- }
-
- state->be_ctx = be_ctx;
- state->sudo_req = sudo_req;
- state->opts = opts;
- state->sdap_op = NULL;
- state->sdap_conn_cache = conn_cache;
- state->dp_error = DP_ERR_OK;
- state->error = EOK;
-
- switch (sudo_req->type) {
- case BE_REQ_SUDO_ALL:
- DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh for: <ALL>\n"));
- break;
- case BE_REQ_SUDO_DEFAULTS:
- DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh of cn=defaults\n"));
- break;
- case BE_REQ_SUDO_USER:
- DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh for: %s\n",
- sudo_req->username));
- break;
- default:
- DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type));
- ret = EINVAL;
- goto immediately;
- }
-
- ret = sdap_sudo_connect(req);
- if (ret == EAGAIN) {
- /* asynchronous processing */
- return req;
- }
-
-immediately:
- if (ret == EOK) {
- tevent_req_done(req);
- } else {
- tevent_req_error(req, ret);
- }
- tevent_req_post(req, be_ctx->ev);
-
- return req;
-}
-
-int sdap_sudo_refresh_recv(struct tevent_req *req,
- int *dp_error,
- int *error)
-{
- struct sdap_sudo_refresh_state *state = NULL;
-
- state = tevent_req_data(req, struct sdap_sudo_refresh_state);
-
- TEVENT_REQ_RETURN_ON_ERROR(req);
-
- *dp_error = state->dp_error;
- *error = state->error;
-
- return EOK;
-}
-
-int sdap_sudo_connect(struct tevent_req *req)
-{
- struct tevent_req *subreq = NULL;
- struct sdap_sudo_refresh_state *state = NULL;
- int ret;
-
- state = tevent_req_data(req, struct sdap_sudo_refresh_state);
-
- if (be_is_offline(state->be_ctx)) {
- state->dp_error = DP_ERR_OFFLINE;
- state->error = EAGAIN;
- return EOK;
- }
-
- if (state->sdap_op == NULL) {
- state->sdap_op = sdap_id_op_create(state, state->sdap_conn_cache);
- if (state->sdap_op == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create() failed\n"));
- state->dp_error = DP_ERR_FATAL;
- state->error = EIO;
- return EIO;
- }
- }
-
- subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
- if (subreq == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- ("sdap_id_op_connect_send() failed: %d(%s)\n", ret, strerror(ret)));
- talloc_zfree(state->sdap_op);
- state->dp_error = DP_ERR_FATAL;
- state->error = ret;
- return ret;
- }
-
- tevent_req_set_callback(subreq, sdap_sudo_connect_done, req);
-
- return EAGAIN;
-}
-
-void sdap_sudo_connect_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = NULL; /* req from sdap_sudo_refresh_send() */
- struct sdap_sudo_refresh_state *state = NULL;
- int dp_error;
- int ret;
-
- req = tevent_req_callback_data(subreq, struct tevent_req);
- state = tevent_req_data(req, struct sdap_sudo_refresh_state);
-
- ret = sdap_id_op_connect_recv(subreq, &dp_error);
- talloc_zfree(subreq);
-
- if (dp_error == DP_ERR_OFFLINE) {
- talloc_zfree(state->sdap_op);
- state->dp_error = DP_ERR_OFFLINE;
- state->error = EAGAIN;
- tevent_req_done(req);
- return;
- } else if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- ("SUDO LDAP connection failed - %s\n", strerror(ret)));
- goto fail;
- }
-
- DEBUG(SSSDBG_TRACE_FUNC, ("SUDO LDAP connection successful\n"));
-
- subreq = sdap_sudo_load_sudoers_send(state, state->be_ctx->ev,
- state->sudo_req, state->opts,
- sdap_id_op_handle(state->sdap_op));
- if (subreq == NULL) {
- ret = EFAULT;
- goto fail;
- }
-
- tevent_req_set_callback(subreq, sdap_sudo_load_sudoers_done, req);
-
- return;
-
-fail:
- state->dp_error = DP_ERR_FATAL;
- state->error = ret;
- tevent_req_error(req, ret);
-}
-
-struct tevent_req * sdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct be_sudo_req *sudo_req,
- struct sdap_options *opts,
- struct sdap_handle *sh)
-
-
-
-{
- struct tevent_req *req = NULL;
- struct sdap_sudo_load_sudoers_state *state = NULL;
- int ret;
-
- req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_load_sudoers_state);
- if (!req) {
- return NULL;
- }
-
- state->ev = ev;
- state->opts = opts;
- state->sh = sh;
- state->base_iter = 0;
- state->search_bases = opts->sudo_search_bases;
- state->timeout = dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT);
- state->ldap_rules = NULL;
- state->ldap_rules_count = 0;
-
- if (!state->search_bases) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- ("SUDOERS lookup request without a search base\n"));
- ret = EINVAL;
- goto done;
- }
-
- /* create filter */
- state->filter = sdap_sudo_build_filter(state, opts->sudorule_map, sudo_req);
- if (state->filter == NULL) {
- goto fail;
- }
-
- /* create attrs from map */
- ret = build_attrs_from_map(state, opts->sudorule_map, SDAP_OPTS_SUDO,
- NULL, &state->attrs, NULL);
- if (ret != EOK) {
- goto fail;
- }
-
- /* begin search */
- ret = sdap_sudo_load_sudoers_next_base(req);
-
-done:
- if (ret != EOK) {
- tevent_req_error(req, ret);
- tevent_req_post(req, ev);
- }
-
- return req;
-
-fail:
- talloc_zfree(req);
- return NULL;
-}
-
-static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req)
-{
- struct tevent_req *subreq = NULL;
- struct sdap_sudo_load_sudoers_state *state = NULL;
- struct sdap_search_base *search_base = NULL;
- char *filter = NULL;
-
- state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state);
- search_base = state->search_bases[state->base_iter];
- if (search_base == NULL) {
- /* should not happen */
- DEBUG(SSSDBG_CRIT_FAILURE, ("search_base is null\n"));
- return EFAULT;
- }
-
- /* create filter */
- filter = sdap_get_id_specific_filter(state, state->filter,
- search_base->filter);
- if (filter == NULL) {
- return ENOMEM;
- }
-
- /* send request */
- DEBUG(SSSDBG_TRACE_FUNC,
- ("Searching for sudo rules with base [%s]\n",
- search_base->basedn));
-
- subreq = sdap_get_generic_send(state,
- state->ev,
- state->opts,
- state->sh,
- search_base->basedn,
- search_base->scope,
- filter,
- state->attrs,
- state->opts->sudorule_map,
- SDAP_OPTS_SUDO,
- state->timeout,
- true);
- if (subreq == NULL) {
- return ENOMEM;
- }
-
- tevent_req_set_callback(subreq, sdap_sudo_load_sudoers_process, req);
-
- return EOK;
-}
-
-static void sdap_sudo_load_sudoers_process(struct tevent_req *subreq)
-{
- struct tevent_req *req = NULL;
- struct sdap_sudo_load_sudoers_state *state = NULL;
- struct sdap_search_base *search_base = NULL;
- struct sysdb_attrs **attrs = NULL;
- size_t count;
- int ret;
- int i;
-
- req = tevent_req_callback_data(subreq, struct tevent_req);
- state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state);
- search_base = state->search_bases[state->base_iter];
-
- DEBUG(SSSDBG_TRACE_FUNC,
- ("Receiving sudo rules with base [%s]\n",
- search_base->basedn));
-
- ret = sdap_get_generic_recv(subreq, state, &count, &attrs);
- talloc_zfree(subreq);
- if (ret) {
- tevent_req_error(req, ret);
- return;
- }
-
- /* add rules to result */
- if (count > 0) {
- state->ldap_rules = talloc_realloc(state, state->ldap_rules,
- struct sysdb_attrs *,
- state->ldap_rules_count + count);
- if (state->ldap_rules == NULL) {
- tevent_req_error(req, ENOMEM);
- return;
- }
-
- for (i = 0; i < count; i++) {
- state->ldap_rules[state->ldap_rules_count + i] = talloc_steal(
- state->ldap_rules, attrs[i]);
- }
-
- state->ldap_rules_count += count;
- }
-
- /* go to next base */
- state->base_iter++;
- if (state->search_bases[state->base_iter]) {
- ret = sdap_sudo_load_sudoers_next_base(req);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- }
-
- return;
- }
-
- /* we are done */
- tevent_req_done(req);
-}
-
-int sdap_sudo_load_sudoers_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx,
- size_t *rules_count,
- struct sysdb_attrs ***rules)
-{
- struct sdap_sudo_load_sudoers_state *state = NULL;
-
- state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state);
-
- TEVENT_REQ_RETURN_ON_ERROR(req);
-
- *rules_count = state->ldap_rules_count;
- *rules = talloc_steal(mem_ctx, state->ldap_rules);
-
- return EOK;
-}
-
-void sdap_sudo_load_sudoers_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = NULL; /* req from sdap_sudo_refresh_send() */
- struct sdap_sudo_refresh_state *state = NULL;
- struct sysdb_attrs **rules = NULL;
- size_t rules_count;
- int ret;
-
- req = tevent_req_callback_data(subreq, struct tevent_req);
- state = tevent_req_data(req, struct sdap_sudo_refresh_state);
-
- ret = sdap_sudo_load_sudoers_recv(subreq, state, &rules_count, &rules);
- talloc_zfree(subreq);
- if (ret != EOK) {
- goto done;
- }
-
- DEBUG(SSSDBG_TRACE_FUNC, ("Received %d rules\n", rules_count));
-
- /* purge cache */
- ret = sdap_sudo_purge_sudoers(state->be_ctx->sysdb, state->be_ctx->domain,
- state->sudo_req);
- if (ret != EOK) {
- goto done;
- }
-
- /* store rules */
- ret = sdap_sudo_store_sudoers(state->be_ctx->sysdb, state->opts,
- rules_count, rules);
- if (ret != EOK) {
- goto done;
- }
-
- DEBUG(SSSDBG_TRACE_FUNC, ("Sudoers is successfuly stored in cache\n"));
-
- ret = EOK;
-
-done:
- state->error = ret;
- if (ret == EOK) {
- state->dp_error = DP_ERR_OK;
- tevent_req_done(req);
- } else {
- state->dp_error = DP_ERR_FATAL;
- tevent_req_error(req, ret);
- }
-}
-
-int sdap_sudo_purge_sudoers(struct sysdb_ctx *sysdb_ctx,
- struct sss_domain_info *domain,
- struct be_sudo_req *sudo_req)
-{
- TALLOC_CTX *tmp_ctx;
- char *filter = NULL;
- char **sudouser = NULL;
- int ret = EOK;
- errno_t sret;
- bool in_transaction = false;
-
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
- return ENOMEM;
- }
-
- ret = sysdb_transaction_start(sysdb_ctx);
- if (ret != EOK) {
- goto done;
- }
- in_transaction = true;
-
- switch (sudo_req->type) {
- case BE_REQ_SUDO_ALL:
- DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of all rules\n"));
- ret = sysdb_sudo_purge_all(sysdb_ctx);
- break;
- case BE_REQ_SUDO_DEFAULTS:
- DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of default options\n"));
- ret = sysdb_sudo_purge_byname(sysdb_ctx, SDAP_SUDO_DEFAULTS);
- break;
- case BE_REQ_SUDO_USER:
- DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of user's [%s] rules\n",
- sudo_req->username));
-
- /* netgroups */
- ret = sysdb_get_sudo_filter(tmp_ctx, NULL, 0, NULL,
- SYSDB_SUDO_FILTER_NGRS, &filter);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create filter to purge "
- "SUDOers cache [%d]: %s\n", ret, strerror(ret)));
- goto done;
- }
-
- ret = sysdb_sudo_purge_byfilter(sysdb_ctx, filter);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to purge SUDOers cache "
- "(netgroups) [%d]: %s\n", ret, strerror(ret)));
- goto done;
- }
-
- /* user, uid, groups */
- sudouser = sysdb_sudo_build_sudouser(tmp_ctx, sudo_req->username,
- sudo_req->uid, sudo_req->groups,
- true);
- if (sudouser == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create sudoUser to purge "
- "SUDOers cache [%d]: %s\n", ret, strerror(ret)));
- goto done;
- }
-
- ret = sysdb_sudo_purge_bysudouser(sysdb_ctx, sudouser);
- break;
- default:
- DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type));
- return EINVAL;
- }
-
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to purge SUDOers cache [%d]: %s\n",
- ret, strerror(ret)));
- goto done;
- }
-
- ret = sysdb_transaction_commit(sysdb_ctx);
- if (ret == EOK) {
- in_transaction = false;
- }
-
-done:
- if (in_transaction) {
- sret = sysdb_transaction_cancel(sysdb_ctx);
- if (sret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, ("Could not cancel transaction\n"));
- }
- }
-
- talloc_free(tmp_ctx);
- return ret;
-}
-
-int sdap_sudo_store_sudoers(struct sysdb_ctx *sysdb_ctx,
- struct sdap_options *opts,
- size_t rules_count,
- struct sysdb_attrs **rules)
-{
- errno_t ret;
-
- /* Empty sudoers? Done. */
- if (rules_count == 0 || rules == NULL) {
- return EOK;
- }
-
- ret = sdap_save_native_sudorule_list(sysdb_ctx, opts->sudorule_map,
- rules, rules_count);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, ("failed to save sudo rules [%d]: %s\n",
- ret, strerror(ret)));
- return ret;
- }
-
- return EOK;
-}
-
-const char *sdap_sudo_build_filter(TALLOC_CTX *mem_ctx,
- struct sdap_attr_map *map,
- struct be_sudo_req *sudo_req)
-{
- switch (sudo_req->type) {
- case BE_REQ_SUDO_ALL:
- return talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_ALL,
- map[SDAP_OC_SUDORULE].name);
- break;
- case BE_REQ_SUDO_DEFAULTS:
- return talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_DEFAULTS,
- map[SDAP_OC_SUDORULE].name,
- map[SDAP_AT_SUDO_NAME].name,
- SDAP_SUDO_DEFAULTS); /* FIXME: add option for this */
- break;
- case BE_REQ_SUDO_USER:
- return sdap_sudo_build_user_filter(mem_ctx, map, sudo_req->username,
- sudo_req->uid, sudo_req->groups);
-
- break;
- default:
- DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type));
- return NULL;
- }
-}
-
-/* alway update cn=defaults and sudoUser=ALL */
-const char *sdap_sudo_build_user_filter(TALLOC_CTX *mem_ctx,
- struct sdap_attr_map *map,
- const char *username,
- uid_t uid,
- char **groups)
-{
- char *filter = NULL;
- char *output = NULL;
- char *sanitized = NULL;
- char **group = NULL;
- int ret;
-
- /* user name */
- ret = sss_filter_sanitize(filter, username, &sanitized);
- if (ret != EOK) {
- goto fail;
- }
- filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_USERNAME,
- map[SDAP_AT_SUDO_USER].name,
- sanitized);
- if (filter == NULL) {
- goto fail;
- }
-
- /* user uid */
- filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_UID,
- map[SDAP_AT_SUDO_USER].name,
- uid);
- if (filter == NULL) {
- goto fail;
- }
-
- /* groups */
- if (groups != NULL) {
- for (group = groups; *group != NULL; group++) {
- ret = sss_filter_sanitize(filter, *group, &sanitized);
- if (ret != EOK) {
- goto fail;
- }
- filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_GROUP,
- map[SDAP_AT_SUDO_USER].name,
- sanitized);
- if (filter == NULL) {
- goto fail;
- }
- }
- }
-
- /* netgroups */
- /*
- * FIXME: load only netgroups user is member of
- * FIXME: add option to disable this filter
- */
- filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_NETGROUP,
- map[SDAP_AT_SUDO_USER].name,
- "*");
- if (filter == NULL) {
- goto fail;
- }
-
-
- output = talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_USER,
- map[SDAP_OC_SUDORULE].name,
- map[SDAP_AT_SUDO_NAME].name,
- SDAP_SUDO_DEFAULTS, /* FIXME: add option for this */
- map[SDAP_AT_SUDO_USER].name,
- filter);
-
- talloc_free(filter);
- return output;
-
-fail:
- talloc_free(filter);
- return NULL;
-}