2373 lines
68 KiB
Diff
2373 lines
68 KiB
Diff
|
From b55cdd3a298b5edd5ddc26beebfa6379843ebe21 Mon Sep 17 00:00:00 2001
|
||
|
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
|
||
|
Date: Fri, 11 Dec 2015 15:00:40 +0100
|
||
|
Subject: [PATCH 27/49] IPA SUDO: Implement full refresh
|
||
|
|
||
|
Reviewed-by: Sumit Bose <sbose@redhat.com>
|
||
|
(cherry picked from commit a641a13889d617aca6bd998025e9087e822ff7f0)
|
||
|
---
|
||
|
Makefile.am | 5 +-
|
||
|
src/providers/ipa/ipa_sudo.c | 75 +-
|
||
|
src/providers/ipa/ipa_sudo.h | 75 ++
|
||
|
src/providers/ipa/ipa_sudo_async.c | 779 +++++++++++++++++++++
|
||
|
src/providers/ipa/ipa_sudo_conversion.c | 1158 +++++++++++++++++++++++++++++++
|
||
|
src/providers/ipa/ipa_sudo_refresh.c | 195 ++++++
|
||
|
6 files changed, 2285 insertions(+), 2 deletions(-)
|
||
|
create mode 100644 src/providers/ipa/ipa_sudo_async.c
|
||
|
create mode 100644 src/providers/ipa/ipa_sudo_conversion.c
|
||
|
create mode 100644 src/providers/ipa/ipa_sudo_refresh.c
|
||
|
|
||
|
diff --git a/Makefile.am b/Makefile.am
|
||
|
index 69905a9112114932e918adff94d0c285c09ed231..1c0b1aada9804b2ef35a09cf1b7bf5e9c65ee4e5 100644
|
||
|
--- a/Makefile.am
|
||
|
+++ b/Makefile.am
|
||
|
@@ -3044,7 +3044,10 @@ endif
|
||
|
|
||
|
if BUILD_SUDO
|
||
|
libsss_ipa_la_SOURCES += \
|
||
|
- src/providers/ipa/ipa_sudo.c
|
||
|
+ src/providers/ipa/ipa_sudo.c \
|
||
|
+ src/providers/ipa/ipa_sudo_refresh.c \
|
||
|
+ src/providers/ipa/ipa_sudo_conversion.c \
|
||
|
+ src/providers/ipa/ipa_sudo_async.c
|
||
|
endif
|
||
|
|
||
|
if BUILD_SSH
|
||
|
diff --git a/src/providers/ipa/ipa_sudo.c b/src/providers/ipa/ipa_sudo.c
|
||
|
index e1b0c828806104336f3df9724484a4411b7fef30..3e73bd30fa86f394b3ef822d59c7b0e539c92ca2 100644
|
||
|
--- a/src/providers/ipa/ipa_sudo.c
|
||
|
+++ b/src/providers/ipa/ipa_sudo.c
|
||
|
@@ -147,6 +147,13 @@ ipa_sudo_init_ipa_schema(struct be_ctx *be_ctx,
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+ ret = ipa_sudo_ptask_setup(be_ctx, sudo_ctx);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup periodic tasks "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
*ops = &ipa_sudo_ops;
|
||
|
*pvt_data = sudo_ctx;
|
||
|
|
||
|
@@ -200,7 +207,73 @@ int ipa_sudo_init(struct be_ctx *be_ctx,
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
+ipa_sudo_reply(struct tevent_req *req)
|
||
|
+{
|
||
|
+ struct be_sudo_req *sudo_req;
|
||
|
+ struct be_req *be_req;
|
||
|
+ int dp_error;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ be_req = tevent_req_callback_data(req, struct be_req);
|
||
|
+ sudo_req = talloc_get_type(be_req_get_data(be_req), struct be_sudo_req);
|
||
|
+
|
||
|
+ switch (sudo_req->type) {
|
||
|
+ case BE_REQ_SUDO_FULL:
|
||
|
+ ret = ipa_sudo_full_refresh_recv(req, &dp_error);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request type: %d\n",
|
||
|
+ sudo_req->type);
|
||
|
+ dp_error = DP_ERR_FATAL;
|
||
|
+ ret = ERR_INTERNAL;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ talloc_zfree(req);
|
||
|
+ sdap_handler_done(be_req, dp_error, ret, sss_strerror(ret));
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
ipa_sudo_handler(struct be_req *be_req)
|
||
|
{
|
||
|
- sdap_handler_done(be_req, DP_ERR_FATAL, ERR_INTERNAL, "Not implemented yet.");
|
||
|
+ struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
|
||
|
+ struct ipa_sudo_ctx *sudo_ctx;
|
||
|
+ struct be_sudo_req *sudo_req;
|
||
|
+ struct tevent_req *req;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ if (be_is_offline(be_ctx)) {
|
||
|
+ sdap_handler_done(be_req, DP_ERR_OFFLINE, EAGAIN, "Offline");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ sudo_ctx = talloc_get_type(be_ctx->bet_info[BET_SUDO].pvt_bet_data,
|
||
|
+ struct ipa_sudo_ctx);
|
||
|
+
|
||
|
+ sudo_req = talloc_get_type(be_req_get_data(be_req), struct be_sudo_req);
|
||
|
+
|
||
|
+ switch (sudo_req->type) {
|
||
|
+ case BE_REQ_SUDO_FULL:
|
||
|
+ req = ipa_sudo_full_refresh_send(be_req, be_ctx->ev, sudo_ctx);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request type: %d\n",
|
||
|
+ sudo_req->type);
|
||
|
+ ret = EINVAL;
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (req == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send request: %d\n",
|
||
|
+ sudo_req->type);
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ tevent_req_set_callback(req, ipa_sudo_reply, be_req);
|
||
|
+
|
||
|
+ return;
|
||
|
+
|
||
|
+fail:
|
||
|
+ sdap_handler_done(be_req, DP_ERR_FATAL, ret, NULL);
|
||
|
}
|
||
|
diff --git a/src/providers/ipa/ipa_sudo.h b/src/providers/ipa/ipa_sudo.h
|
||
|
index 21251ed3dabfaebdc324c8d06ba8f1a0b82951b1..1ef50a7f352182bdc6607b2fd8ee3d72ccab391d 100644
|
||
|
--- a/src/providers/ipa/ipa_sudo.h
|
||
|
+++ b/src/providers/ipa/ipa_sudo.h
|
||
|
@@ -28,6 +28,9 @@ struct ipa_sudo_ctx {
|
||
|
struct ipa_options *ipa_opts;
|
||
|
struct sdap_options *sdap_opts;
|
||
|
|
||
|
+ bool full_refresh_done;
|
||
|
+ bool full_refresh_in_progress;
|
||
|
+
|
||
|
/* sudo */
|
||
|
struct sdap_attr_map *sudocmdgroup_map;
|
||
|
struct sdap_attr_map *sudorule_map;
|
||
|
@@ -35,4 +38,76 @@ struct ipa_sudo_ctx {
|
||
|
struct sdap_search_base **sudo_sb;
|
||
|
};
|
||
|
|
||
|
+errno_t
|
||
|
+ipa_sudo_ptask_setup(struct be_ctx *be_ctx, struct ipa_sudo_ctx *sudo_ctx);
|
||
|
+
|
||
|
+struct tevent_req *
|
||
|
+ipa_sudo_full_refresh_send(TALLOC_CTX *mem_ctx,
|
||
|
+ struct tevent_context *ev,
|
||
|
+ struct ipa_sudo_ctx *sudo_ctx);
|
||
|
+
|
||
|
+int
|
||
|
+ipa_sudo_full_refresh_recv(struct tevent_req *req,
|
||
|
+ int *dp_error);
|
||
|
+
|
||
|
+struct tevent_req *
|
||
|
+ipa_sudo_refresh_send(TALLOC_CTX *mem_ctx,
|
||
|
+ struct tevent_context *ev,
|
||
|
+ struct ipa_sudo_ctx *sudo_ctx,
|
||
|
+ const char *search_filter,
|
||
|
+ const char *delete_filter);
|
||
|
+
|
||
|
+errno_t
|
||
|
+ipa_sudo_refresh_recv(struct tevent_req *req,
|
||
|
+ int *dp_error,
|
||
|
+ size_t *_num_rules);
|
||
|
+
|
||
|
+struct ipa_sudo_conv;
|
||
|
+
|
||
|
+struct ipa_sudo_conv *
|
||
|
+ipa_sudo_conv_init(TALLOC_CTX *mem_ctx,
|
||
|
+ struct sysdb_ctx *sysdb,
|
||
|
+ struct sdap_attr_map *map_rule,
|
||
|
+ struct sdap_attr_map *map_cmdgroup,
|
||
|
+ struct sdap_attr_map *map_cmd,
|
||
|
+ struct sdap_attr_map *map_user,
|
||
|
+ struct sdap_attr_map *map_group,
|
||
|
+ struct sdap_attr_map *map_host,
|
||
|
+ struct sdap_attr_map *map_hostgroup);
|
||
|
+
|
||
|
+errno_t
|
||
|
+ipa_sudo_conv_rules(struct ipa_sudo_conv *conv,
|
||
|
+ struct sysdb_attrs **rules,
|
||
|
+ size_t num_rules);
|
||
|
+
|
||
|
+errno_t
|
||
|
+ipa_sudo_conv_cmdgroups(struct ipa_sudo_conv *conv,
|
||
|
+ struct sysdb_attrs **cmdgroups,
|
||
|
+ size_t num_cmdgroups);
|
||
|
+
|
||
|
+errno_t
|
||
|
+ipa_sudo_conv_cmds(struct ipa_sudo_conv *conv,
|
||
|
+ struct sysdb_attrs **cmds,
|
||
|
+ size_t num_cmds);
|
||
|
+
|
||
|
+bool
|
||
|
+ipa_sudo_conv_has_cmdgroups(struct ipa_sudo_conv *conv);
|
||
|
+
|
||
|
+bool
|
||
|
+ipa_sudo_conv_has_cmds(struct ipa_sudo_conv *conv);
|
||
|
+
|
||
|
+char *
|
||
|
+ipa_sudo_conv_cmdgroup_filter(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv);
|
||
|
+
|
||
|
+char *
|
||
|
+ipa_sudo_conv_cmd_filter(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv);
|
||
|
+
|
||
|
+errno_t
|
||
|
+ipa_sudo_conv_result(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv,
|
||
|
+ struct sysdb_attrs ***_rules,
|
||
|
+ size_t *_num_rules);
|
||
|
+
|
||
|
#endif /* _IPA_SUDO_H_ */
|
||
|
diff --git a/src/providers/ipa/ipa_sudo_async.c b/src/providers/ipa/ipa_sudo_async.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000000000000000000000000000..9ddda1b41a0b3c6ceb33e6d665749948ae835a97
|
||
|
--- /dev/null
|
||
|
+++ b/src/providers/ipa/ipa_sudo_async.c
|
||
|
@@ -0,0 +1,779 @@
|
||
|
+/*
|
||
|
+ Authors:
|
||
|
+ Pavel Březina <pbrezina@redhat.com>
|
||
|
+
|
||
|
+ Copyright (C) 2015 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 <talloc.h>
|
||
|
+#include <tevent.h>
|
||
|
+#include <dhash.h>
|
||
|
+
|
||
|
+#include "providers/ldap/sdap_ops.h"
|
||
|
+#include "providers/ipa/ipa_common.h"
|
||
|
+#include "providers/ipa/ipa_hosts.h"
|
||
|
+#include "providers/ipa/ipa_sudo.h"
|
||
|
+#include "providers/ipa/ipa_dn.h"
|
||
|
+#include "db/sysdb.h"
|
||
|
+#include "db/sysdb_sudo.h"
|
||
|
+
|
||
|
+struct ipa_hostinfo {
|
||
|
+ size_t num_hosts;
|
||
|
+ size_t num_hostgroups;
|
||
|
+ struct sysdb_attrs **hosts;
|
||
|
+ struct sysdb_attrs **hostgroups;
|
||
|
+};
|
||
|
+
|
||
|
+static char *
|
||
|
+ipa_sudo_filter_append_origdn(char *filter,
|
||
|
+ struct sysdb_attrs *attrs,
|
||
|
+ const char *attr_name)
|
||
|
+{
|
||
|
+ const char *origdn;
|
||
|
+ char *sanitizeddn;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ ret = sysdb_attrs_get_string(attrs, SYSDB_ORIG_DN, &origdn);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get original DN "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sss_filter_sanitize(NULL, origdn, &sanitizeddn);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to sanitize DN "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ filter = talloc_asprintf_append(filter, "(%s=%s)", attr_name, sanitizeddn);
|
||
|
+ talloc_free(sanitizeddn);
|
||
|
+ if (filter == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf_append() failed\n");
|
||
|
+ }
|
||
|
+
|
||
|
+ return filter;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * (|(hostCategory=ALL)(memberHost=$DN(fqdn))(memberHost=$DN(hostgroup))...)
|
||
|
+ */
|
||
|
+static char *
|
||
|
+ipa_sudo_host_filter(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_hostinfo *host,
|
||
|
+ struct sdap_attr_map *map)
|
||
|
+{
|
||
|
+ TALLOC_CTX *tmp_ctx;
|
||
|
+ char *filter;
|
||
|
+ size_t i;
|
||
|
+
|
||
|
+ /* If realloc fails we will free all data through tmp_ctx. */
|
||
|
+ tmp_ctx = talloc_new(NULL);
|
||
|
+ if (tmp_ctx == NULL) {
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ filter = talloc_asprintf(tmp_ctx, "(!(%s=*))",
|
||
|
+ map[IPA_AT_SUDORULE_HOST].name);
|
||
|
+ if (filter == NULL) {
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Append hostCategory=ALL */
|
||
|
+ filter = talloc_asprintf_append(filter, "(%s=ALL)",
|
||
|
+ map[IPA_AT_SUDORULE_HOSTCATEGORY].name);
|
||
|
+ if (filter == NULL) {
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Append client machine */
|
||
|
+ for (i = 0; i < host->num_hosts; i++) {
|
||
|
+ filter = ipa_sudo_filter_append_origdn(filter, host->hosts[i],
|
||
|
+ map[IPA_AT_SUDORULE_HOST].name);
|
||
|
+ if (filter == NULL) {
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Append hostgroups */
|
||
|
+ for (i = 0; i < host->num_hostgroups; i++) {
|
||
|
+ filter = ipa_sudo_filter_append_origdn(filter, host->hostgroups[i],
|
||
|
+ map[IPA_AT_SUDORULE_HOST].name);
|
||
|
+ if (filter == NULL) {
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /* OR filters */
|
||
|
+ filter = talloc_asprintf(tmp_ctx, "(|%s)", filter);
|
||
|
+ if (filter == NULL) {
|
||
|
+ goto fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ talloc_steal(mem_ctx, filter);
|
||
|
+ talloc_free(tmp_ctx);
|
||
|
+ return filter;
|
||
|
+
|
||
|
+fail:
|
||
|
+ talloc_free(tmp_ctx);
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+struct ipa_sudo_fetch_state {
|
||
|
+ struct tevent_context *ev;
|
||
|
+ struct sysdb_ctx *sysdb;
|
||
|
+ struct ipa_sudo_ctx *sudo_ctx;
|
||
|
+ struct sdap_options *sdap_opts;
|
||
|
+ struct ipa_hostinfo *host;
|
||
|
+ struct sdap_handle *sh;
|
||
|
+
|
||
|
+ struct sdap_attr_map *map_cmdgroup;
|
||
|
+ struct sdap_attr_map *map_rule;
|
||
|
+ struct sdap_attr_map *map_cmd;
|
||
|
+ struct sdap_search_base **sudo_sb;
|
||
|
+
|
||
|
+ struct ipa_sudo_conv *conv;
|
||
|
+ struct sysdb_attrs **rules;
|
||
|
+ size_t num_rules;
|
||
|
+};
|
||
|
+
|
||
|
+static errno_t ipa_sudo_fetch_rules(struct tevent_req *req);
|
||
|
+static void ipa_sudo_fetch_rules_done(struct tevent_req *subreq);
|
||
|
+static errno_t ipa_sudo_fetch_cmdgroups(struct tevent_req *req);
|
||
|
+static void ipa_sudo_fetch_cmdgroups_done(struct tevent_req *subreq);
|
||
|
+static errno_t ipa_sudo_fetch_cmds(struct tevent_req *req);
|
||
|
+static void ipa_sudo_fetch_cmds_done(struct tevent_req *subreq);
|
||
|
+static void ipa_sudo_fetch_done(struct tevent_req *req);
|
||
|
+
|
||
|
+static struct tevent_req *
|
||
|
+ipa_sudo_fetch_send(TALLOC_CTX *mem_ctx,
|
||
|
+ struct tevent_context *ev,
|
||
|
+ struct sysdb_ctx *sysdb,
|
||
|
+ struct ipa_sudo_ctx *sudo_ctx,
|
||
|
+ struct ipa_hostinfo *host,
|
||
|
+ struct sdap_attr_map *map_user,
|
||
|
+ struct sdap_attr_map *map_group,
|
||
|
+ struct sdap_attr_map *map_host,
|
||
|
+ struct sdap_attr_map *map_hostgroup,
|
||
|
+ struct sdap_handle *sh)
|
||
|
+{
|
||
|
+ struct ipa_sudo_fetch_state *state = NULL;
|
||
|
+ struct tevent_req *req = NULL;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ req = tevent_req_create(mem_ctx, &state,
|
||
|
+ struct ipa_sudo_fetch_state);
|
||
|
+ if (req == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ state->ev = ev;
|
||
|
+ state->sysdb = sysdb;
|
||
|
+ state->sudo_ctx = sudo_ctx;
|
||
|
+ state->sdap_opts = sudo_ctx->sdap_opts;
|
||
|
+ state->host = host;
|
||
|
+ state->sh = sh;
|
||
|
+
|
||
|
+ state->map_cmdgroup = sudo_ctx->sudocmdgroup_map;
|
||
|
+ state->map_rule = sudo_ctx->sudorule_map;
|
||
|
+ state->map_cmd = sudo_ctx->sudocmd_map;
|
||
|
+ state->sudo_sb = sudo_ctx->sudo_sb;
|
||
|
+
|
||
|
+ state->conv = ipa_sudo_conv_init(state, sysdb, state->map_rule,
|
||
|
+ state->map_cmdgroup, state->map_cmd,
|
||
|
+ map_user, map_group, map_host,
|
||
|
+ map_hostgroup);
|
||
|
+ if (state->conv == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto immediately;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = ipa_sudo_fetch_rules(req);
|
||
|
+ if (ret != EAGAIN) {
|
||
|
+ goto immediately;
|
||
|
+ }
|
||
|
+
|
||
|
+ return req;
|
||
|
+
|
||
|
+immediately:
|
||
|
+ if (ret == EOK) {
|
||
|
+ tevent_req_done(req);
|
||
|
+ } else {
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ }
|
||
|
+ tevent_req_post(req, state->ev);
|
||
|
+
|
||
|
+ return req;
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+ipa_sudo_fetch_rules(struct tevent_req *req)
|
||
|
+{
|
||
|
+ struct ipa_sudo_fetch_state *state;
|
||
|
+ struct tevent_req *subreq;
|
||
|
+ struct sdap_attr_map *map;
|
||
|
+ char *host_filter;
|
||
|
+ char *filter;
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_TRACE_FUNC, "About to fetch sudo rules\n");
|
||
|
+
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_fetch_state);
|
||
|
+ map = state->map_rule;
|
||
|
+
|
||
|
+ host_filter = ipa_sudo_host_filter(state, state->host, map);
|
||
|
+ if (host_filter == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build host filter\n");
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=TRUE)%s)",
|
||
|
+ map[IPA_OC_SUDORULE].name,
|
||
|
+ map[IPA_AT_SUDORULE_ENABLED].name,
|
||
|
+ host_filter);
|
||
|
+ talloc_zfree(host_filter);
|
||
|
+ if (filter == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build filter\n");
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts,
|
||
|
+ state->sh, state->sudo_sb, map, true, 0,
|
||
|
+ filter, NULL);
|
||
|
+ if (subreq == NULL) {
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ tevent_req_set_callback(subreq, ipa_sudo_fetch_rules_done, req);
|
||
|
+ return EAGAIN;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+ipa_sudo_fetch_rules_done(struct tevent_req *subreq)
|
||
|
+{
|
||
|
+ struct ipa_sudo_fetch_state *state = NULL;
|
||
|
+ struct tevent_req *req = NULL;
|
||
|
+ struct sysdb_attrs **attrs;
|
||
|
+ size_t num_attrs;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ req = tevent_req_callback_data(subreq, struct tevent_req);
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_fetch_state);
|
||
|
+
|
||
|
+ ret = sdap_search_bases_recv(subreq, state, &num_attrs, &attrs);
|
||
|
+ talloc_zfree(subreq);
|
||
|
+ if (ret != EOK) {
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo rules\n", num_attrs);
|
||
|
+
|
||
|
+ ret = ipa_sudo_conv_rules(state->conv, attrs, num_attrs);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed when converting rules "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = ipa_sudo_fetch_cmdgroups(req);
|
||
|
+
|
||
|
+done:
|
||
|
+ if (ret == EOK) {
|
||
|
+ ipa_sudo_fetch_done(req);
|
||
|
+ } else if (ret != EAGAIN) {
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ }
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+ipa_sudo_fetch_cmdgroups(struct tevent_req *req)
|
||
|
+{
|
||
|
+ struct ipa_sudo_fetch_state *state;
|
||
|
+ struct tevent_req *subreq;
|
||
|
+ char *filter;
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_TRACE_FUNC, "About to fetch sudo command groups\n");
|
||
|
+
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_fetch_state);
|
||
|
+
|
||
|
+ if (ipa_sudo_conv_has_cmdgroups(state->conv)) {
|
||
|
+ DEBUG(SSSDBG_TRACE_FUNC, "No command groups needs to be downloaded\n");
|
||
|
+ return ipa_sudo_fetch_cmds(req);
|
||
|
+ }
|
||
|
+
|
||
|
+ filter = ipa_sudo_conv_cmdgroup_filter(state, state->conv);
|
||
|
+ if (filter == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build filter\n");
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts,
|
||
|
+ state->sh, state->sudo_sb,
|
||
|
+ state->map_cmdgroup, true, 0,
|
||
|
+ filter, NULL);
|
||
|
+ if (subreq == NULL) {
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ tevent_req_set_callback(subreq, ipa_sudo_fetch_cmdgroups_done, req);
|
||
|
+ return EAGAIN;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+ipa_sudo_fetch_cmdgroups_done(struct tevent_req *subreq)
|
||
|
+{
|
||
|
+ struct ipa_sudo_fetch_state *state = NULL;
|
||
|
+ struct tevent_req *req = NULL;
|
||
|
+ struct sysdb_attrs **attrs;
|
||
|
+ size_t num_attrs;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ req = tevent_req_callback_data(subreq, struct tevent_req);
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_fetch_state);
|
||
|
+
|
||
|
+ ret = sdap_search_bases_recv(subreq, state, &num_attrs, &attrs);
|
||
|
+ talloc_zfree(subreq);
|
||
|
+ if (ret != EOK) {
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo command groups\n",
|
||
|
+ num_attrs);
|
||
|
+
|
||
|
+ ret = ipa_sudo_conv_cmdgroups(state->conv, attrs, num_attrs);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed when converting command groups "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = ipa_sudo_fetch_cmds(req);
|
||
|
+
|
||
|
+done:
|
||
|
+ if (ret == EOK) {
|
||
|
+ ipa_sudo_fetch_done(req);
|
||
|
+ } else if (ret != EAGAIN) {
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ }
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+ipa_sudo_fetch_cmds(struct tevent_req *req)
|
||
|
+{
|
||
|
+ struct ipa_sudo_fetch_state *state;
|
||
|
+ struct tevent_req *subreq;
|
||
|
+ char *filter;
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_TRACE_FUNC, "About to fetch sudo commands\n");
|
||
|
+
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_fetch_state);
|
||
|
+
|
||
|
+ if (ipa_sudo_conv_has_cmds(state->conv)) {
|
||
|
+ DEBUG(SSSDBG_TRACE_FUNC, "No commands needs to be downloaded\n");
|
||
|
+ return EOK;
|
||
|
+ }
|
||
|
+
|
||
|
+ filter = ipa_sudo_conv_cmd_filter(state, state->conv);
|
||
|
+ if (filter == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build filter\n");
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts,
|
||
|
+ state->sh, state->sudo_sb,
|
||
|
+ state->map_cmd, true, 0,
|
||
|
+ filter, NULL);
|
||
|
+ if (subreq == NULL) {
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ tevent_req_set_callback(subreq, ipa_sudo_fetch_cmds_done, req);
|
||
|
+ return EAGAIN;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+ipa_sudo_fetch_cmds_done(struct tevent_req *subreq)
|
||
|
+{
|
||
|
+ struct ipa_sudo_fetch_state *state = NULL;
|
||
|
+ struct tevent_req *req = NULL;
|
||
|
+ struct sysdb_attrs **attrs;
|
||
|
+ size_t num_attrs;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ req = tevent_req_callback_data(subreq, struct tevent_req);
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_fetch_state);
|
||
|
+
|
||
|
+ ret = sdap_search_bases_recv(subreq, state, &num_attrs, &attrs);
|
||
|
+ talloc_zfree(subreq);
|
||
|
+ if (ret != EOK) {
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo commands\n", num_attrs);
|
||
|
+
|
||
|
+ ret = ipa_sudo_conv_cmds(state->conv, attrs, num_attrs);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed when converting commands "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+done:
|
||
|
+ if (ret == EOK) {
|
||
|
+ ipa_sudo_fetch_done(req);
|
||
|
+ } else if (ret != EAGAIN) {
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ }
|
||
|
+
|
||
|
+ return;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+ipa_sudo_fetch_done(struct tevent_req *req)
|
||
|
+{
|
||
|
+ struct ipa_sudo_fetch_state *state = NULL;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_fetch_state);
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_TRACE_FUNC, "About to convert rules\n");
|
||
|
+
|
||
|
+ ret = ipa_sudo_conv_result(state, state->conv,
|
||
|
+ &state->rules, &state->num_rules);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to convert rules [%d]: %s\n",
|
||
|
+ ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = EOK;
|
||
|
+
|
||
|
+done:
|
||
|
+ if (ret != EOK) {
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ tevent_req_done(req);
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+ipa_sudo_fetch_recv(TALLOC_CTX *mem_ctx,
|
||
|
+ struct tevent_req *req,
|
||
|
+ struct sysdb_attrs ***_rules,
|
||
|
+ size_t *_num_rules)
|
||
|
+{
|
||
|
+ struct ipa_sudo_fetch_state *state = NULL;
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_fetch_state);
|
||
|
+
|
||
|
+ TEVENT_REQ_RETURN_ON_ERROR(req);
|
||
|
+
|
||
|
+ *_rules = talloc_steal(mem_ctx, state->rules);
|
||
|
+ *_num_rules = state->num_rules;
|
||
|
+
|
||
|
+ return EOK;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+struct ipa_sudo_refresh_state {
|
||
|
+ struct tevent_context *ev;
|
||
|
+ struct sysdb_ctx *sysdb;
|
||
|
+ struct sss_domain_info *domain;
|
||
|
+ struct ipa_sudo_ctx *sudo_ctx;
|
||
|
+ struct ipa_options *ipa_opts;
|
||
|
+ struct sdap_options *sdap_opts;
|
||
|
+ const char *search_filter;
|
||
|
+ const char *delete_filter;
|
||
|
+
|
||
|
+ struct sdap_id_op *sdap_op;
|
||
|
+ struct sdap_handle *sh;
|
||
|
+ int dp_error;
|
||
|
+
|
||
|
+ struct sysdb_attrs **rules;
|
||
|
+ size_t num_rules;
|
||
|
+};
|
||
|
+
|
||
|
+static errno_t ipa_sudo_refresh_retry(struct tevent_req *req);
|
||
|
+static void ipa_sudo_refresh_connect_done(struct tevent_req *subreq);
|
||
|
+static void ipa_sudo_refresh_host_done(struct tevent_req *subreq);
|
||
|
+static void ipa_sudo_refresh_done(struct tevent_req *subreq);
|
||
|
+
|
||
|
+struct tevent_req *
|
||
|
+ipa_sudo_refresh_send(TALLOC_CTX *mem_ctx,
|
||
|
+ struct tevent_context *ev,
|
||
|
+ struct ipa_sudo_ctx *sudo_ctx,
|
||
|
+ const char *search_filter,
|
||
|
+ const char *delete_filter)
|
||
|
+{
|
||
|
+ struct ipa_sudo_refresh_state *state;
|
||
|
+ struct tevent_req *req;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ req = tevent_req_create(mem_ctx, &state, struct ipa_sudo_refresh_state);
|
||
|
+ if (req == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ state->ev = ev;
|
||
|
+ state->sysdb = sudo_ctx->id_ctx->be->domain->sysdb;
|
||
|
+ state->domain = sudo_ctx->id_ctx->be->domain;
|
||
|
+ state->sudo_ctx = sudo_ctx;
|
||
|
+ state->ipa_opts = sudo_ctx->ipa_opts;
|
||
|
+ state->sdap_opts = sudo_ctx->sdap_opts;
|
||
|
+ state->dp_error = DP_ERR_FATAL;
|
||
|
+
|
||
|
+ state->sdap_op = sdap_id_op_create(state,
|
||
|
+ sudo_ctx->id_ctx->conn->conn_cache);
|
||
|
+ if (!state->sdap_op) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto immediately;
|
||
|
+ }
|
||
|
+
|
||
|
+ state->search_filter = talloc_strdup(state, search_filter);
|
||
|
+ if (search_filter != NULL && state->search_filter == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto immediately;
|
||
|
+ }
|
||
|
+
|
||
|
+ state->delete_filter = talloc_strdup(state, delete_filter);
|
||
|
+ if (delete_filter != NULL && state->delete_filter == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto immediately;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = ipa_sudo_refresh_retry(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, state->ev);
|
||
|
+
|
||
|
+ return req;
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+ipa_sudo_refresh_retry(struct tevent_req *req)
|
||
|
+{
|
||
|
+ struct ipa_sudo_refresh_state *state;
|
||
|
+ struct tevent_req *subreq;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_refresh_state);
|
||
|
+
|
||
|
+ 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));
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ tevent_req_set_callback(subreq, ipa_sudo_refresh_connect_done, req);
|
||
|
+
|
||
|
+ return EAGAIN;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+ipa_sudo_refresh_connect_done(struct tevent_req *subreq)
|
||
|
+{
|
||
|
+ struct ipa_sudo_refresh_state *state;
|
||
|
+ const char *hostname;
|
||
|
+ struct tevent_req *req;
|
||
|
+ int dp_error;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ req = tevent_req_callback_data(subreq, struct tevent_req);
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_refresh_state);
|
||
|
+
|
||
|
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
|
||
|
+ talloc_zfree(subreq);
|
||
|
+
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "SUDO LDAP connection failed "
|
||
|
+ "[%d]: %s\n", ret, strerror(ret));
|
||
|
+ state->dp_error = dp_error;
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ state->sh = sdap_id_op_handle(state->sdap_op);
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_TRACE_FUNC, "SUDO LDAP connection successful\n");
|
||
|
+ DEBUG(SSSDBG_TRACE_FUNC, "About to fetch host information\n");
|
||
|
+
|
||
|
+ /* Obtain host information. */
|
||
|
+ hostname = dp_opt_get_string(state->ipa_opts->basic, IPA_HOSTNAME);
|
||
|
+
|
||
|
+ subreq = ipa_host_info_send(state, state->ev,
|
||
|
+ state->sh, state->sdap_opts, hostname,
|
||
|
+ state->ipa_opts->host_map,
|
||
|
+ state->ipa_opts->hostgroup_map,
|
||
|
+ state->ipa_opts->host_search_bases);
|
||
|
+ if (subreq == NULL) {
|
||
|
+ state->dp_error = DP_ERR_FATAL;
|
||
|
+ tevent_req_error(req, ENOMEM);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ tevent_req_set_callback(subreq, ipa_sudo_refresh_host_done, req);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+ipa_sudo_refresh_host_done(struct tevent_req *subreq)
|
||
|
+{
|
||
|
+ struct ipa_sudo_refresh_state *state;
|
||
|
+ struct ipa_hostinfo *host;
|
||
|
+ struct tevent_req *req;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ req = tevent_req_callback_data(subreq, struct tevent_req);
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_refresh_state);
|
||
|
+
|
||
|
+ host = talloc_zero(state, struct ipa_hostinfo);
|
||
|
+ if (host == NULL) {
|
||
|
+ state->dp_error = DP_ERR_FATAL;
|
||
|
+ tevent_req_error(req, ENOMEM);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = ipa_host_info_recv(subreq, host, &host->num_hosts, &host->hosts,
|
||
|
+ &host->num_hostgroups, &host->hostgroups);
|
||
|
+ talloc_zfree(subreq);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve host information "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ state->dp_error = DP_ERR_FATAL;
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ subreq = ipa_sudo_fetch_send(state, state->ev, state->sysdb,
|
||
|
+ state->sudo_ctx, host,
|
||
|
+ state->sdap_opts->user_map,
|
||
|
+ state->sdap_opts->group_map,
|
||
|
+ state->ipa_opts->host_map,
|
||
|
+ state->ipa_opts->hostgroup_map, state->sh);
|
||
|
+ if (subreq == NULL) {
|
||
|
+ state->dp_error = DP_ERR_FATAL;
|
||
|
+ tevent_req_error(req, ENOMEM);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ tevent_req_set_callback(subreq, ipa_sudo_refresh_done, req);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+ipa_sudo_refresh_done(struct tevent_req *subreq)
|
||
|
+{
|
||
|
+ struct ipa_sudo_refresh_state *state;
|
||
|
+ struct tevent_req *req;
|
||
|
+ bool in_transaction = false;
|
||
|
+ errno_t sret;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ req = tevent_req_callback_data(subreq, struct tevent_req);
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_refresh_state);
|
||
|
+
|
||
|
+ ret = ipa_sudo_fetch_recv(state, subreq, &state->rules, &state->num_rules);
|
||
|
+ talloc_zfree(subreq);
|
||
|
+
|
||
|
+ ret = sdap_id_op_done(state->sdap_op, ret, &state->dp_error);
|
||
|
+ if (state->dp_error == DP_ERR_OK && ret != EOK) {
|
||
|
+ /* retry */
|
||
|
+ ret = ipa_sudo_refresh_retry(req);
|
||
|
+ if (ret != EOK) {
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ }
|
||
|
+ return;
|
||
|
+ } else if (ret != EOK) {
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sysdb_transaction_start(state->sysdb);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ in_transaction = true;
|
||
|
+
|
||
|
+ ret = sysdb_sudo_purge(state->domain, state->delete_filter,
|
||
|
+ state->rules, state->num_rules);
|
||
|
+ if (ret != EOK) {
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sysdb_sudo_store(state->domain, state->rules, state->num_rules);
|
||
|
+ if (ret != EOK) {
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sysdb_transaction_commit(state->sysdb);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ in_transaction = false;
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_TRACE_FUNC, "Sudo rules are successfully stored in cache\n");
|
||
|
+
|
||
|
+done:
|
||
|
+ if (in_transaction) {
|
||
|
+ sret = sysdb_transaction_cancel(state->sysdb);
|
||
|
+ if (sret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (ret != EOK) {
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ tevent_req_done(req);
|
||
|
+}
|
||
|
+
|
||
|
+errno_t
|
||
|
+ipa_sudo_refresh_recv(struct tevent_req *req,
|
||
|
+ int *dp_error,
|
||
|
+ size_t *_num_rules)
|
||
|
+{
|
||
|
+ struct ipa_sudo_refresh_state *state = NULL;
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_refresh_state);
|
||
|
+
|
||
|
+ TEVENT_REQ_RETURN_ON_ERROR(req);
|
||
|
+
|
||
|
+ *dp_error = state->dp_error;
|
||
|
+
|
||
|
+ if (_num_rules != NULL) {
|
||
|
+ *_num_rules = state->num_rules;
|
||
|
+ }
|
||
|
+
|
||
|
+ return EOK;
|
||
|
+}
|
||
|
diff --git a/src/providers/ipa/ipa_sudo_conversion.c b/src/providers/ipa/ipa_sudo_conversion.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000000000000000000000000000..2f28f837e62b42406ddda25b3f63832c1abb950d
|
||
|
--- /dev/null
|
||
|
+++ b/src/providers/ipa/ipa_sudo_conversion.c
|
||
|
@@ -0,0 +1,1158 @@
|
||
|
+/*
|
||
|
+ Authors:
|
||
|
+ Pavel Březina <pbrezina@redhat.com>
|
||
|
+
|
||
|
+ Copyright (C) 2015 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 <ldb.h>
|
||
|
+#include <talloc.h>
|
||
|
+#include <dhash.h>
|
||
|
+
|
||
|
+#include "providers/ldap/sdap.h"
|
||
|
+#include "providers/ipa/ipa_common.h"
|
||
|
+#include "providers/ipa/ipa_dn.h"
|
||
|
+#include "db/sysdb_sudo.h"
|
||
|
+#include "db/sysdb.h"
|
||
|
+#include "util/util.h"
|
||
|
+
|
||
|
+#define SUDO_DN_CMDGROUPS "sudocmdgroups"
|
||
|
+#define SUDO_DN_CMDS "sudocmds"
|
||
|
+#define SUDO_DN_CONTAINER "sudo"
|
||
|
+#define SUDO_DN_CN "cn"
|
||
|
+
|
||
|
+#define MATCHDN(cat) SUDO_DN_CN, (cat), SUDO_DN_CN, SUDO_DN_CONTAINER
|
||
|
+#define MATCHDN_CMDGROUPS MATCHDN(SUDO_DN_CMDGROUPS)
|
||
|
+#define MATCHDN_CMDS MATCHDN(SUDO_DN_CMDS)
|
||
|
+
|
||
|
+#define MATCHRDN_CMDGROUPS(map) (map)[IPA_AT_SUDOCMDGROUP_NAME].name, MATCHDN_CMDGROUPS
|
||
|
+#define MATCHRDN_CMDS(map) (map)[IPA_AT_SUDOCMD_UUID].name, MATCHDN_CMDS
|
||
|
+
|
||
|
+#define MATCHRDN_USER(map) (map)[SDAP_AT_USER_NAME].name, "cn", "users", "cn", "accounts"
|
||
|
+#define MATCHRDN_GROUP(map) (map)[SDAP_AT_GROUP_NAME].name, "cn", "groups", "cn", "accounts"
|
||
|
+#define MATCHRDN_HOST(map) (map)[IPA_AT_HOST_FQDN].name, "cn", "computers", "cn", "accounts"
|
||
|
+#define MATCHRDN_HOSTGROUP(map) (map)[IPA_AT_HOSTGROUP_NAME].name, "cn", "hostgroups", "cn", "accounts"
|
||
|
+
|
||
|
+struct ipa_sudo_conv {
|
||
|
+ struct sysdb_ctx *sysdb;
|
||
|
+
|
||
|
+ struct sdap_attr_map *map_rule;
|
||
|
+ struct sdap_attr_map *map_cmdgroup;
|
||
|
+ struct sdap_attr_map *map_cmd;
|
||
|
+ struct sdap_attr_map *map_user;
|
||
|
+ struct sdap_attr_map *map_group;
|
||
|
+ struct sdap_attr_map *map_host;
|
||
|
+ struct sdap_attr_map *map_hostgroup;
|
||
|
+
|
||
|
+ hash_table_t *rules;
|
||
|
+ hash_table_t *cmdgroups;
|
||
|
+ hash_table_t *cmds;
|
||
|
+};
|
||
|
+
|
||
|
+struct ipa_sudo_dn_list {
|
||
|
+ struct ipa_sudo_dn_list *prev, *next;
|
||
|
+ const char *dn;
|
||
|
+};
|
||
|
+
|
||
|
+struct ipa_sudo_rulemember {
|
||
|
+ struct ipa_sudo_dn_list *cmdgroups;
|
||
|
+ struct ipa_sudo_dn_list *cmds;
|
||
|
+};
|
||
|
+
|
||
|
+struct ipa_sudo_rule {
|
||
|
+ struct sysdb_attrs *attrs;
|
||
|
+ struct ipa_sudo_rulemember allow;
|
||
|
+ struct ipa_sudo_rulemember deny;
|
||
|
+};
|
||
|
+
|
||
|
+struct ipa_sudo_cmdgroup {
|
||
|
+ struct ipa_sudo_dn_list *cmds;
|
||
|
+ const char **expanded;
|
||
|
+};
|
||
|
+
|
||
|
+static size_t
|
||
|
+ipa_sudo_dn_list_count(struct ipa_sudo_dn_list *list)
|
||
|
+{
|
||
|
+ struct ipa_sudo_dn_list *item;
|
||
|
+ size_t i;
|
||
|
+
|
||
|
+ for (i = 0, item = list; item != NULL; item = item->next, i++) {
|
||
|
+ /* no op */
|
||
|
+ }
|
||
|
+
|
||
|
+ return i;
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+ipa_sudo_conv_store(hash_table_t *table,
|
||
|
+ const char *key,
|
||
|
+ void *value)
|
||
|
+{
|
||
|
+ hash_key_t hkey;
|
||
|
+ hash_value_t hvalue;
|
||
|
+ int hret;
|
||
|
+
|
||
|
+ if (table == NULL || key == NULL) {
|
||
|
+ return EINVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ hkey.type = HASH_KEY_STRING;
|
||
|
+ hkey.str = discard_const(key);
|
||
|
+
|
||
|
+ /* If value is NULL we don't want to override existing entry. */
|
||
|
+ if (value == NULL && hash_has_key(table, &hkey)) {
|
||
|
+ return EEXIST;
|
||
|
+ }
|
||
|
+
|
||
|
+ hvalue.type = HASH_VALUE_PTR;
|
||
|
+ hvalue.ptr = value;
|
||
|
+
|
||
|
+ hret = hash_enter(table, &hkey, &hvalue);
|
||
|
+ if (hret != HASH_SUCCESS) {
|
||
|
+ return EIO;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (value != NULL) {
|
||
|
+ talloc_steal(table, value);
|
||
|
+ }
|
||
|
+
|
||
|
+ return EOK;
|
||
|
+}
|
||
|
+
|
||
|
+static void *
|
||
|
+ipa_sudo_conv_lookup(hash_table_t *table,
|
||
|
+ const char *key)
|
||
|
+{
|
||
|
+ hash_key_t hkey;
|
||
|
+ hash_value_t hvalue;
|
||
|
+ int hret;
|
||
|
+
|
||
|
+ hkey.type = HASH_KEY_STRING;
|
||
|
+ hkey.str = discard_const(key);
|
||
|
+
|
||
|
+ hret = hash_lookup(table, &hkey, &hvalue);
|
||
|
+ if (hret == HASH_ERROR_KEY_NOT_FOUND) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Key not found %s\n", key);
|
||
|
+ return NULL;
|
||
|
+ } else if (hret != HASH_SUCCESS) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup value [%d]\n", hret);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ return hvalue.ptr;
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+store_rulemember(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_dn_list **list,
|
||
|
+ hash_table_t *table,
|
||
|
+ const char *dn)
|
||
|
+{
|
||
|
+ struct ipa_sudo_dn_list *item;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ item = talloc_zero(mem_ctx, struct ipa_sudo_dn_list);
|
||
|
+ if (item == NULL) {
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = ipa_sudo_conv_store(table, dn, NULL);
|
||
|
+ if (ret != EOK && ret != EEXIST) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to store DN %s [%d]: %s\n",
|
||
|
+ dn, ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ item->dn = talloc_steal(item, dn);
|
||
|
+ DLIST_ADD(*list, item);
|
||
|
+
|
||
|
+done:
|
||
|
+ if (ret != EOK && ret != EEXIST) {
|
||
|
+ talloc_free(item);
|
||
|
+ }
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+process_rulemember(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv,
|
||
|
+ struct ipa_sudo_rulemember *rulemember,
|
||
|
+ struct sysdb_attrs *rule,
|
||
|
+ const char *attr)
|
||
|
+{
|
||
|
+ TALLOC_CTX *tmp_ctx;
|
||
|
+ const char **members;
|
||
|
+ errno_t ret;
|
||
|
+ int i;
|
||
|
+
|
||
|
+ tmp_ctx = talloc_new(NULL);
|
||
|
+ if (tmp_ctx == NULL) {
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sysdb_attrs_get_string_array(rule, attr, tmp_ctx, &members);
|
||
|
+ if (ret == ENOENT) {
|
||
|
+ ret = EOK;
|
||
|
+ goto done;
|
||
|
+ } else if (ret != EOK) {
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; members[i] != NULL; i++) {
|
||
|
+ if (ipa_check_rdn_bool(conv->sysdb, members[i],
|
||
|
+ MATCHRDN_CMDGROUPS(conv->map_cmdgroup))) {
|
||
|
+ ret = store_rulemember(mem_ctx, &rulemember->cmdgroups,
|
||
|
+ conv->cmdgroups, members[i]);
|
||
|
+ if (ret == EOK) {
|
||
|
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Found sudo command group %s\n",
|
||
|
+ members[i]);
|
||
|
+ } else if (ret != EEXIST) {
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ } else if (ipa_check_rdn_bool(conv->sysdb, members[i],
|
||
|
+ MATCHRDN_CMDS(conv->map_cmd))) {
|
||
|
+ ret = store_rulemember(mem_ctx, &rulemember->cmds,
|
||
|
+ conv->cmds, members[i]);
|
||
|
+ if (ret == EOK) {
|
||
|
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Found sudo command group %s\n",
|
||
|
+ members[i]);
|
||
|
+ } else if (ret != EEXIST) {
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "Invalid member DN %s, skipping...\n",
|
||
|
+ members[i]);
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = EOK;
|
||
|
+
|
||
|
+done:
|
||
|
+ talloc_free(tmp_ctx);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+process_allowcmd(struct ipa_sudo_conv *conv,
|
||
|
+ struct ipa_sudo_rule *rule)
|
||
|
+{
|
||
|
+ return process_rulemember(rule, conv, &rule->allow, rule->attrs,
|
||
|
+ SYSDB_IPA_SUDORULE_ALLOWCMD);
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+process_denycmd(struct ipa_sudo_conv *conv,
|
||
|
+ struct ipa_sudo_rule *rule)
|
||
|
+{
|
||
|
+ return process_rulemember(rule, conv, &rule->deny, rule->attrs,
|
||
|
+ SYSDB_IPA_SUDORULE_DENYCMD);
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+process_cmdgroupmember(struct ipa_sudo_conv *conv,
|
||
|
+ struct ipa_sudo_cmdgroup *cmdgroup,
|
||
|
+ struct sysdb_attrs *attrs)
|
||
|
+{
|
||
|
+ TALLOC_CTX *tmp_ctx;
|
||
|
+ struct ipa_sudo_dn_list *item;
|
||
|
+ const char **members;
|
||
|
+ errno_t ret;
|
||
|
+ int i;
|
||
|
+
|
||
|
+ tmp_ctx = talloc_new(NULL);
|
||
|
+ if (tmp_ctx == NULL) {
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sysdb_attrs_get_string_array(attrs, SYSDB_MEMBER, tmp_ctx, &members);
|
||
|
+ if (ret == ENOENT) {
|
||
|
+ ret = EOK;
|
||
|
+ goto done;
|
||
|
+ } else if (ret != EOK) {
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; members[i] != NULL; i++) {
|
||
|
+ ret = ipa_sudo_conv_store(conv->cmds, members[i], NULL);
|
||
|
+ if (ret == EOK) {
|
||
|
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Found sudo command %s\n",
|
||
|
+ members[i]);
|
||
|
+ } else if (ret != EEXIST) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to store DN [%d]: %s\n",
|
||
|
+ ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ item = talloc_zero(tmp_ctx, struct ipa_sudo_dn_list);
|
||
|
+ if (item == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ item->dn = talloc_steal(item, members[i]);
|
||
|
+ DLIST_ADD(cmdgroup->cmds, item);
|
||
|
+ talloc_steal(cmdgroup, item);
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = EOK;
|
||
|
+
|
||
|
+done:
|
||
|
+ talloc_free(tmp_ctx);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+struct ipa_sudo_conv *
|
||
|
+ipa_sudo_conv_init(TALLOC_CTX *mem_ctx,
|
||
|
+ struct sysdb_ctx *sysdb,
|
||
|
+ struct sdap_attr_map *map_rule,
|
||
|
+ struct sdap_attr_map *map_cmdgroup,
|
||
|
+ struct sdap_attr_map *map_cmd,
|
||
|
+ struct sdap_attr_map *map_user,
|
||
|
+ struct sdap_attr_map *map_group,
|
||
|
+ struct sdap_attr_map *map_host,
|
||
|
+ struct sdap_attr_map *map_hostgroup)
|
||
|
+{
|
||
|
+ struct ipa_sudo_conv *conv;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ conv = talloc_zero(mem_ctx, struct ipa_sudo_conv);
|
||
|
+ if (conv == NULL) {
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ conv->sysdb = sysdb;
|
||
|
+ conv->map_rule = map_rule;
|
||
|
+ conv->map_cmdgroup = map_cmdgroup;
|
||
|
+ conv->map_cmd = map_cmd;
|
||
|
+ conv->map_user = map_user;
|
||
|
+ conv->map_group = map_group;
|
||
|
+ conv->map_host = map_host;
|
||
|
+ conv->map_hostgroup = map_hostgroup;
|
||
|
+
|
||
|
+ ret = sss_hash_create(conv, 20, &conv->rules);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create hash table [%d]: %s\n",
|
||
|
+ ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sss_hash_create(conv, 20, &conv->cmdgroups);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create hash table [%d]: %s\n",
|
||
|
+ ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sss_hash_create(conv, 20, &conv->cmds);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create hash table [%d]: %s\n",
|
||
|
+ ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+done:
|
||
|
+ if (ret != EOK) {
|
||
|
+ talloc_free(conv);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ return conv;
|
||
|
+}
|
||
|
+
|
||
|
+errno_t
|
||
|
+ipa_sudo_conv_rules(struct ipa_sudo_conv *conv,
|
||
|
+ struct sysdb_attrs **rules,
|
||
|
+ size_t num_rules)
|
||
|
+{
|
||
|
+ struct ipa_sudo_rule *rule = NULL;
|
||
|
+ const char *key;
|
||
|
+ errno_t ret;
|
||
|
+ size_t i;
|
||
|
+
|
||
|
+ if (num_rules == 0) {
|
||
|
+ /* We're done here. */
|
||
|
+ return EOK;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; i < num_rules; i++) {
|
||
|
+ ret = sysdb_attrs_get_string(rules[i], SYSDB_NAME, &key);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to get rule name, skipping "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ rule = talloc_zero(conv->rules, struct ipa_sudo_rule);
|
||
|
+ if (rule == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ rule->attrs = rules[i];
|
||
|
+
|
||
|
+ ret = process_allowcmd(conv, rule);
|
||
|
+ if (ret != EOK && ret != EEXIST) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to process memberAllowCmd "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = process_denycmd(conv, rule);
|
||
|
+ if (ret != EOK && ret != EEXIST) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to process memberDenyCmd "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = ipa_sudo_conv_store(conv->rules, key, rule);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to store rule into table "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ talloc_steal(rule, rule->attrs);
|
||
|
+ rule = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = EOK;
|
||
|
+
|
||
|
+done:
|
||
|
+ if (ret != EOK) {
|
||
|
+ talloc_free(rule);
|
||
|
+ }
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+errno_t
|
||
|
+ipa_sudo_conv_cmdgroups(struct ipa_sudo_conv *conv,
|
||
|
+ struct sysdb_attrs **cmdgroups,
|
||
|
+ size_t num_cmdgroups)
|
||
|
+{
|
||
|
+ struct ipa_sudo_cmdgroup *cmdgroup = NULL;
|
||
|
+ const char *key;
|
||
|
+ errno_t ret;
|
||
|
+ size_t i;
|
||
|
+
|
||
|
+ if (num_cmdgroups == 0) {
|
||
|
+ /* We're done here. */
|
||
|
+ return EOK;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; i < num_cmdgroups; i++) {
|
||
|
+ ret = sysdb_attrs_get_string(cmdgroups[i], SYSDB_ORIG_DN, &key);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to get command group DN, "
|
||
|
+ "skipping [%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ cmdgroup = talloc_zero(conv->cmdgroups, struct ipa_sudo_cmdgroup);
|
||
|
+ if (cmdgroup == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = process_cmdgroupmember(conv, cmdgroup, cmdgroups[i]);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to process member "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = ipa_sudo_conv_store(conv->cmdgroups, key, cmdgroup);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to store command group into "
|
||
|
+ "table [%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ cmdgroup = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = EOK;
|
||
|
+
|
||
|
+done:
|
||
|
+ if (ret != EOK) {
|
||
|
+ talloc_free(cmdgroup);
|
||
|
+ }
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+errno_t
|
||
|
+ipa_sudo_conv_cmds(struct ipa_sudo_conv *conv,
|
||
|
+ struct sysdb_attrs **cmds,
|
||
|
+ size_t num_cmds)
|
||
|
+{
|
||
|
+ const char *key;
|
||
|
+ const char *cmd;
|
||
|
+ errno_t ret;
|
||
|
+ size_t i;
|
||
|
+
|
||
|
+ if (num_cmds == 0) {
|
||
|
+ /* We're done here. */
|
||
|
+ return EOK;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; i < num_cmds; i++) {
|
||
|
+ ret = sysdb_attrs_get_string(cmds[i], SYSDB_ORIG_DN, &key);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to get command DN, skipping "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sysdb_attrs_get_string(cmds[i], SYSDB_IPA_SUDOCMD_SUDOCMD, &cmd);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to get command, skipping "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = ipa_sudo_conv_store(conv->cmds, key, discard_const(cmd));
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to store command into table "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = EOK;
|
||
|
+
|
||
|
+done:
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+bool
|
||
|
+ipa_sudo_conv_has_cmdgroups(struct ipa_sudo_conv *conv)
|
||
|
+{
|
||
|
+ return hash_count(conv->cmdgroups) == 0;
|
||
|
+}
|
||
|
+
|
||
|
+bool
|
||
|
+ipa_sudo_conv_has_cmds(struct ipa_sudo_conv *conv)
|
||
|
+{
|
||
|
+ return hash_count(conv->cmds) == 0;
|
||
|
+}
|
||
|
+
|
||
|
+static char *
|
||
|
+build_filter(TALLOC_CTX *mem_ctx,
|
||
|
+ struct sysdb_ctx *sysdb,
|
||
|
+ hash_table_t *table,
|
||
|
+ const char *class,
|
||
|
+ const char *rdn_attr,
|
||
|
+ const char *category)
|
||
|
+{
|
||
|
+ TALLOC_CTX *tmp_ctx;
|
||
|
+ hash_key_t *keys;
|
||
|
+ unsigned long int count;
|
||
|
+ unsigned long int i;
|
||
|
+ char *filter;
|
||
|
+ char *rdn_val;
|
||
|
+ char *safe_rdn;
|
||
|
+ errno_t ret;
|
||
|
+ int hret;
|
||
|
+
|
||
|
+ tmp_ctx = talloc_new(NULL);
|
||
|
+ if (tmp_ctx == NULL) {
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ hret = hash_keys(table, &count, &keys);
|
||
|
+ if (hret != HASH_SUCCESS) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ talloc_steal(tmp_ctx, keys);
|
||
|
+
|
||
|
+ filter = talloc_strdup(tmp_ctx, "");
|
||
|
+ if (filter == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; i < count; i++) {
|
||
|
+ ret = ipa_get_rdn(tmp_ctx, sysdb, keys[i].str, &rdn_val,
|
||
|
+ rdn_attr, MATCHDN(category));
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get member %s [%d]: %s\n",
|
||
|
+ keys[i].str, ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sss_filter_sanitize(tmp_ctx, rdn_val, &safe_rdn);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to sanitize DN "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ filter = talloc_asprintf_append(filter, "(%s=%s)", rdn_attr, safe_rdn);
|
||
|
+ if (filter == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ filter = talloc_asprintf(filter, "(&(objectClass=%s)(|%s))",
|
||
|
+ class, filter);
|
||
|
+ if (filter == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ talloc_steal(mem_ctx, filter);
|
||
|
+
|
||
|
+ ret = EOK;
|
||
|
+
|
||
|
+done:
|
||
|
+ talloc_free(tmp_ctx);
|
||
|
+
|
||
|
+ if (ret != EOK) {
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ return filter;
|
||
|
+}
|
||
|
+
|
||
|
+char *
|
||
|
+ipa_sudo_conv_cmdgroup_filter(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv)
|
||
|
+{
|
||
|
+ const char *rdn_attr = conv->map_cmdgroup[IPA_AT_SUDOCMDGROUP_NAME].name;
|
||
|
+ const char *class = conv->map_cmdgroup[IPA_OC_SUDOCMDGROUP].name;
|
||
|
+
|
||
|
+ return build_filter(mem_ctx, conv->sysdb, conv->cmdgroups, class,
|
||
|
+ rdn_attr, SUDO_DN_CMDGROUPS);
|
||
|
+}
|
||
|
+
|
||
|
+char *
|
||
|
+ipa_sudo_conv_cmd_filter(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv)
|
||
|
+{
|
||
|
+ const char *rdn_attr = conv->map_cmd[IPA_AT_SUDOCMD_UUID].name;
|
||
|
+ const char *class = conv->map_cmd[IPA_OC_SUDOCMD].name;
|
||
|
+
|
||
|
+ return build_filter(mem_ctx, conv->sysdb, conv->cmds, class,
|
||
|
+ rdn_attr, SUDO_DN_CMDS);
|
||
|
+}
|
||
|
+
|
||
|
+struct ipa_sudo_conv_result_ctx {
|
||
|
+ struct ipa_sudo_conv *conv;
|
||
|
+ struct sysdb_attrs **rules;
|
||
|
+ size_t num_rules;
|
||
|
+ errno_t ret;
|
||
|
+};
|
||
|
+
|
||
|
+static const char *
|
||
|
+convert_host(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv,
|
||
|
+ const char *value)
|
||
|
+{
|
||
|
+ char *rdn;
|
||
|
+ const char *group;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ ret = ipa_get_rdn(mem_ctx, conv->sysdb, value, &rdn,
|
||
|
+ MATCHRDN_HOST(conv->map_host));
|
||
|
+ if (ret == EOK) {
|
||
|
+ return rdn;
|
||
|
+ } else if (ret != ENOENT) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n",
|
||
|
+ value, ret, sss_strerror(ret));
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = ipa_get_rdn(mem_ctx, conv->sysdb, value, &rdn,
|
||
|
+ MATCHRDN_HOSTGROUP(conv->map_hostgroup));
|
||
|
+ if (ret == ENOENT) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected DN %s\n", value);
|
||
|
+ return NULL;
|
||
|
+ } else if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n",
|
||
|
+ value, ret, sss_strerror(ret));
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ group = talloc_asprintf(mem_ctx, "+%s", rdn);
|
||
|
+ talloc_free(rdn);
|
||
|
+
|
||
|
+ return group;
|
||
|
+}
|
||
|
+
|
||
|
+static const char *
|
||
|
+convert_user(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv,
|
||
|
+ const char *value)
|
||
|
+{
|
||
|
+ char *rdn;
|
||
|
+ const char *group;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ ret = ipa_get_rdn(mem_ctx, conv->sysdb, value, &rdn,
|
||
|
+ MATCHRDN_USER(conv->map_user));
|
||
|
+ if (ret == EOK) {
|
||
|
+ return rdn;
|
||
|
+ } else if (ret != ENOENT) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n",
|
||
|
+ value, ret, sss_strerror(ret));
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = ipa_get_rdn(mem_ctx, conv->sysdb, value, &rdn,
|
||
|
+ MATCHRDN_GROUP(conv->map_group));
|
||
|
+ if (ret == ENOENT) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected DN %s\n", value);
|
||
|
+ return NULL;
|
||
|
+ } else if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n",
|
||
|
+ value, ret, sss_strerror(ret));
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ group = talloc_asprintf(mem_ctx, "%%%s", rdn);
|
||
|
+ talloc_free(rdn);
|
||
|
+
|
||
|
+ return group;
|
||
|
+}
|
||
|
+
|
||
|
+static const char *
|
||
|
+convert_group(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv,
|
||
|
+ const char *value)
|
||
|
+{
|
||
|
+ char *rdn;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ ret = ipa_get_rdn(mem_ctx, conv->sysdb, value, &rdn,
|
||
|
+ MATCHRDN_GROUP(conv->map_group));
|
||
|
+ if (ret == ENOENT) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected DN %s\n", value);
|
||
|
+ return NULL;
|
||
|
+ } else if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n",
|
||
|
+ value, ret, sss_strerror(ret));
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ return rdn;
|
||
|
+}
|
||
|
+
|
||
|
+static const char *
|
||
|
+convert_cat(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv,
|
||
|
+ const char *value)
|
||
|
+{
|
||
|
+ if (strcmp(value, "all") == 0) {
|
||
|
+ return talloc_strdup(mem_ctx, "ALL");
|
||
|
+ }
|
||
|
+
|
||
|
+ return value;
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+convert_attributes(struct ipa_sudo_conv *conv,
|
||
|
+ struct ipa_sudo_rule *rule,
|
||
|
+ struct sysdb_attrs *attrs)
|
||
|
+{
|
||
|
+ TALLOC_CTX *tmp_ctx;
|
||
|
+ const char **values;
|
||
|
+ const char *value;
|
||
|
+ errno_t ret;
|
||
|
+ int i, j;
|
||
|
+ static struct {
|
||
|
+ const char *ipa;
|
||
|
+ const char *sudo;
|
||
|
+ const char *(*conv_fn)(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv,
|
||
|
+ const char *value);
|
||
|
+ } table[] = {{SYSDB_NAME, SYSDB_SUDO_CACHE_AT_CN , NULL},
|
||
|
+ {SYSDB_IPA_SUDORULE_HOST, SYSDB_SUDO_CACHE_AT_HOST , convert_host},
|
||
|
+ {SYSDB_IPA_SUDORULE_USER, SYSDB_SUDO_CACHE_AT_USER , convert_user},
|
||
|
+ {SYSDB_IPA_SUDORULE_RUNASUSER, SYSDB_SUDO_CACHE_AT_RUNASUSER , convert_user},
|
||
|
+ {SYSDB_IPA_SUDORULE_RUNASGROUP, SYSDB_SUDO_CACHE_AT_RUNASGROUP , convert_group},
|
||
|
+ {SYSDB_IPA_SUDORULE_OPTION, SYSDB_SUDO_CACHE_AT_OPTION , NULL},
|
||
|
+ {SYSDB_IPA_SUDORULE_NOTAFTER, SYSDB_SUDO_CACHE_AT_NOTAFTER , NULL},
|
||
|
+ {SYSDB_IPA_SUDORULE_NOTBEFORE, SYSDB_SUDO_CACHE_AT_NOTBEFORE , NULL},
|
||
|
+ {SYSDB_IPA_SUDORULE_SUDOORDER, SYSDB_SUDO_CACHE_AT_ORDER , NULL},
|
||
|
+ {SYSDB_IPA_SUDORULE_CMDCATEGORY, SYSDB_SUDO_CACHE_AT_COMMAND , convert_cat},
|
||
|
+ {SYSDB_IPA_SUDORULE_HOSTCATEGORY, SYSDB_SUDO_CACHE_AT_HOST , convert_cat},
|
||
|
+ {SYSDB_IPA_SUDORULE_USERCATEGORY, SYSDB_SUDO_CACHE_AT_USER , convert_cat},
|
||
|
+ {SYSDB_IPA_SUDORULE_RUNASUSERCATEGORY, SYSDB_SUDO_CACHE_AT_RUNASUSER , convert_cat},
|
||
|
+ {SYSDB_IPA_SUDORULE_RUNASGROUPCATEGORY, SYSDB_SUDO_CACHE_AT_RUNASGROUP , convert_cat},
|
||
|
+ {SYSDB_IPA_SUDORULE_ALLOWCMD, SYSDB_IPA_SUDORULE_ORIGCMD , NULL},
|
||
|
+ {SYSDB_IPA_SUDORULE_DENYCMD, SYSDB_IPA_SUDORULE_ORIGCMD , NULL},
|
||
|
+ {NULL, NULL, NULL}};
|
||
|
+
|
||
|
+ tmp_ctx = talloc_new(NULL);
|
||
|
+ if (tmp_ctx == NULL) {
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; table[i].ipa != NULL; i++) {
|
||
|
+ ret = sysdb_attrs_get_string_array(rule->attrs, table[i].ipa,
|
||
|
+ tmp_ctx, &values);
|
||
|
+ if (ret == ENOENT) {
|
||
|
+ continue;
|
||
|
+ } else if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read attribute "
|
||
|
+ "%s [%d]: %s\n", table[i].ipa, ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (j = 0; values[j] != NULL; j++) {
|
||
|
+ if (table[i].conv_fn != NULL) {
|
||
|
+ value = table[i].conv_fn(tmp_ctx, conv, values[j]);
|
||
|
+ if (value == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ value = values[j];
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sysdb_attrs_add_string_safe(attrs, table[i].sudo, value);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add attribute "
|
||
|
+ "%s [%d]: %s\n", table[i].sudo, ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = EOK;
|
||
|
+
|
||
|
+done:
|
||
|
+ talloc_free(tmp_ctx);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static const char **
|
||
|
+combine_cmdgroups(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv,
|
||
|
+ struct ipa_sudo_dn_list *list)
|
||
|
+{
|
||
|
+ TALLOC_CTX *tmp_ctx;
|
||
|
+ struct ipa_sudo_cmdgroup *cmdgroup;
|
||
|
+ struct ipa_sudo_dn_list *listitem;
|
||
|
+ const char **values = NULL;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ tmp_ctx = talloc_new(NULL);
|
||
|
+ if (tmp_ctx == NULL) {
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ values = talloc_zero_array(tmp_ctx, const char *, 1);
|
||
|
+ if (values == NULL) {
|
||
|
+ talloc_free(tmp_ctx);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ DLIST_FOR_EACH(listitem, list) {
|
||
|
+ cmdgroup = ipa_sudo_conv_lookup(conv->cmdgroups, listitem->dn);
|
||
|
+
|
||
|
+ ret = add_strings_lists(mem_ctx, values, cmdgroup->expanded,
|
||
|
+ false, discard_const(&values));
|
||
|
+ if (ret != EOK) {
|
||
|
+ talloc_free(tmp_ctx);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ talloc_steal(mem_ctx, values);
|
||
|
+ talloc_free(tmp_ctx);
|
||
|
+
|
||
|
+ return values;
|
||
|
+}
|
||
|
+
|
||
|
+static const char **
|
||
|
+combine_cmds(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv,
|
||
|
+ struct ipa_sudo_dn_list *list)
|
||
|
+{
|
||
|
+ struct ipa_sudo_dn_list *listitem;
|
||
|
+ const char **values;
|
||
|
+ const char *command;
|
||
|
+ size_t count;
|
||
|
+ size_t i;
|
||
|
+
|
||
|
+ count = ipa_sudo_dn_list_count(list);
|
||
|
+
|
||
|
+ values = talloc_zero_array(mem_ctx, const char *, count + 1);
|
||
|
+ if (values == NULL) {
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ i = 0;
|
||
|
+ DLIST_FOR_EACH(listitem, list) {
|
||
|
+ command = ipa_sudo_conv_lookup(conv->cmds, listitem->dn);
|
||
|
+ if (command == NULL) {
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ values[i] = command;
|
||
|
+ i++;
|
||
|
+ }
|
||
|
+
|
||
|
+ return values;
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+build_sudocommand(struct ipa_sudo_conv *conv,
|
||
|
+ struct ipa_sudo_rulemember *mlist,
|
||
|
+ struct sysdb_attrs *attrs,
|
||
|
+ char prefix)
|
||
|
+{
|
||
|
+ TALLOC_CTX *tmp_ctx;
|
||
|
+ const char **cmds[2];
|
||
|
+ const char *command;
|
||
|
+ errno_t ret;
|
||
|
+ int i, j;
|
||
|
+
|
||
|
+ tmp_ctx = talloc_new(NULL);
|
||
|
+ if (tmp_ctx == NULL) {
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ cmds[0] = combine_cmdgroups(tmp_ctx, conv, mlist->cmdgroups);
|
||
|
+ if (cmds[0] == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ cmds[1] = combine_cmds(tmp_ctx, conv, mlist->cmds);
|
||
|
+ if (cmds[1] == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; i < 2; i++) {
|
||
|
+ for (j = 0; cmds[i][j] != NULL; j++) {
|
||
|
+ if (prefix == '\0') {
|
||
|
+ command = cmds[i][j];
|
||
|
+ } else {
|
||
|
+ command = talloc_asprintf(tmp_ctx, "%c%s", prefix, cmds[i][j]);
|
||
|
+ if (command == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sysdb_attrs_add_string_safe(attrs,
|
||
|
+ SYSDB_SUDO_CACHE_AT_COMMAND, command);
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add attribute "
|
||
|
+ "%s [%d]: %s\n", SYSDB_SUDO_CACHE_AT_COMMAND,
|
||
|
+ ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = EOK;
|
||
|
+
|
||
|
+done:
|
||
|
+ talloc_free(tmp_ctx);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+convert_sudocommand(struct ipa_sudo_conv *conv,
|
||
|
+ struct ipa_sudo_rule *rule,
|
||
|
+ struct sysdb_attrs *attrs)
|
||
|
+{
|
||
|
+ TALLOC_CTX *tmp_ctx;
|
||
|
+ errno_t ret;
|
||
|
+
|
||
|
+ tmp_ctx = talloc_new(NULL);
|
||
|
+ if (tmp_ctx == NULL) {
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = build_sudocommand(conv, &rule->allow, attrs, '\0');
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build allow commands "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = build_sudocommand(conv, &rule->deny, attrs, '!');
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build deny commands "
|
||
|
+ "[%d]: %s\n", ret, sss_strerror(ret));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = EOK;
|
||
|
+
|
||
|
+done:
|
||
|
+ talloc_free(tmp_ctx);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static bool
|
||
|
+rules_iterator(hash_entry_t *item,
|
||
|
+ void *user_data)
|
||
|
+{
|
||
|
+ struct ipa_sudo_conv_result_ctx *ctx = user_data;
|
||
|
+ struct ipa_sudo_rule *rule = item->value.ptr;
|
||
|
+ struct sysdb_attrs *attrs;
|
||
|
+
|
||
|
+ if (ctx == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: ctx is NULL\n");
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (rule == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: rule is NULL\n");
|
||
|
+ ctx->ret = ERR_INTERNAL;
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ attrs = sysdb_new_attrs(ctx->rules);
|
||
|
+ if (attrs == NULL) {
|
||
|
+ ctx->ret = ENOMEM;
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ ctx->ret = convert_attributes(ctx->conv, rule, attrs);
|
||
|
+ if (ctx->ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to convert attributes [%d]: %s\n",
|
||
|
+ ctx->ret, sss_strerror(ctx->ret));
|
||
|
+ talloc_free(attrs);
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ ctx->ret = convert_sudocommand(ctx->conv, rule, attrs);
|
||
|
+ if (ctx->ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to build sudoCommand [%d]: %s\n",
|
||
|
+ ctx->ret, sss_strerror(ctx->ret));
|
||
|
+ talloc_free(attrs);
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ ctx->rules[ctx->num_rules] = attrs;
|
||
|
+ ctx->num_rules++;
|
||
|
+
|
||
|
+ return true;
|
||
|
+}
|
||
|
+
|
||
|
+static bool
|
||
|
+cmdgroups_iterator(hash_entry_t *item,
|
||
|
+ void *user_data)
|
||
|
+{
|
||
|
+ struct ipa_sudo_conv_result_ctx *ctx = user_data;
|
||
|
+ struct ipa_sudo_cmdgroup *cmdgroup = item->value.ptr;
|
||
|
+ const char **values;
|
||
|
+
|
||
|
+ if (ctx == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: ctx is NULL\n");
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (cmdgroup == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: rule is NULL\n");
|
||
|
+ ctx->ret = ERR_INTERNAL;
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ values = combine_cmds(cmdgroup, ctx->conv, cmdgroup->cmds);
|
||
|
+ if (values == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to expand commands\n");
|
||
|
+ ctx->ret = ENOMEM;
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ cmdgroup->expanded = values;
|
||
|
+ ctx->ret = EOK;
|
||
|
+
|
||
|
+ return true;
|
||
|
+}
|
||
|
+
|
||
|
+errno_t
|
||
|
+ipa_sudo_conv_result(TALLOC_CTX *mem_ctx,
|
||
|
+ struct ipa_sudo_conv *conv,
|
||
|
+ struct sysdb_attrs ***_rules,
|
||
|
+ size_t *_num_rules)
|
||
|
+{
|
||
|
+ struct ipa_sudo_conv_result_ctx ctx;
|
||
|
+ struct sysdb_attrs **rules;
|
||
|
+ unsigned long num_rules;
|
||
|
+ int hret;
|
||
|
+
|
||
|
+ num_rules = hash_count(conv->rules);
|
||
|
+ if (num_rules == 0) {
|
||
|
+ *_rules = NULL;
|
||
|
+ *_num_rules = 0;
|
||
|
+ return EOK;
|
||
|
+ }
|
||
|
+
|
||
|
+ ctx.conv = conv;
|
||
|
+ ctx.rules = NULL;
|
||
|
+ ctx.num_rules = 0;
|
||
|
+
|
||
|
+ /* If there are no cmdgroups the iterator is not called and ctx.ret is
|
||
|
+ * uninitialized. Since it is ok that there are no cmdgroups initializing
|
||
|
+ * ctx.ret to EOK. */
|
||
|
+ ctx.ret = EOK;
|
||
|
+
|
||
|
+ /* Expand commands in command groups. */
|
||
|
+ hret = hash_iterate(conv->cmdgroups, cmdgroups_iterator, &ctx);
|
||
|
+ if (hret != HASH_SUCCESS) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to iterate over command groups "
|
||
|
+ "[%d]\n", hret);
|
||
|
+ return EIO;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (ctx.ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to expand command grousp "
|
||
|
+ "[%d]: %s\n", ctx.ret, sss_strerror(ctx.ret));
|
||
|
+ return ctx.ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Convert rules. */
|
||
|
+ rules = talloc_zero_array(mem_ctx, struct sysdb_attrs *, num_rules);
|
||
|
+ if (rules == NULL) {
|
||
|
+ return ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ ctx.rules = rules;
|
||
|
+ ctx.num_rules = 0;
|
||
|
+
|
||
|
+ hret = hash_iterate(conv->rules, rules_iterator, &ctx);
|
||
|
+ if (hret != HASH_SUCCESS) {
|
||
|
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to iterate over rules [%d]\n", hret);
|
||
|
+ return EIO;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (ctx.ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to convert rules [%d]: %s\n",
|
||
|
+ ctx.ret, sss_strerror(ctx.ret));
|
||
|
+ talloc_free(rules);
|
||
|
+ return ctx.ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ *_rules = ctx.rules;
|
||
|
+ *_num_rules = ctx.num_rules;
|
||
|
+
|
||
|
+ return EOK;
|
||
|
+}
|
||
|
diff --git a/src/providers/ipa/ipa_sudo_refresh.c b/src/providers/ipa/ipa_sudo_refresh.c
|
||
|
new file mode 100644
|
||
|
index 0000000000000000000000000000000000000000..6fb8f66af607440ddcbb266c0b049ed99bf235b9
|
||
|
--- /dev/null
|
||
|
+++ b/src/providers/ipa/ipa_sudo_refresh.c
|
||
|
@@ -0,0 +1,195 @@
|
||
|
+/*
|
||
|
+ Authors:
|
||
|
+ Pavel Březina <pbrezina@redhat.com>
|
||
|
+
|
||
|
+ Copyright (C) 2015 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 "util/util.h"
|
||
|
+#include "providers/dp_ptask.h"
|
||
|
+#include "providers/ipa/ipa_sudo.h"
|
||
|
+#include "providers/ldap/sdap_sudo_shared.h"
|
||
|
+#include "db/sysdb_sudo.h"
|
||
|
+
|
||
|
+struct ipa_sudo_full_refresh_state {
|
||
|
+ struct ipa_sudo_ctx *sudo_ctx;
|
||
|
+ struct sss_domain_info *domain;
|
||
|
+ int dp_error;
|
||
|
+};
|
||
|
+
|
||
|
+static void ipa_sudo_full_refresh_done(struct tevent_req *subreq);
|
||
|
+
|
||
|
+struct tevent_req *
|
||
|
+ipa_sudo_full_refresh_send(TALLOC_CTX *mem_ctx,
|
||
|
+ struct tevent_context *ev,
|
||
|
+ struct ipa_sudo_ctx *sudo_ctx)
|
||
|
+{
|
||
|
+ struct ipa_sudo_full_refresh_state *state;
|
||
|
+ struct tevent_req *subreq;
|
||
|
+ struct tevent_req *req;
|
||
|
+ char *delete_filter;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ req = tevent_req_create(mem_ctx, &state,
|
||
|
+ struct ipa_sudo_full_refresh_state);
|
||
|
+ if (req == NULL) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ sudo_ctx->full_refresh_in_progress = true;
|
||
|
+
|
||
|
+ state->domain = sudo_ctx->id_ctx->be->domain;
|
||
|
+ state->sudo_ctx = sudo_ctx;
|
||
|
+
|
||
|
+ /* Remove all rules from cache */
|
||
|
+ delete_filter = talloc_asprintf(state, "(%s=%s)", SYSDB_OBJECTCLASS,
|
||
|
+ SYSDB_SUDO_CACHE_OC);
|
||
|
+ if (delete_filter == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto immediately;
|
||
|
+ }
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_TRACE_FUNC, "Issuing a full refresh of sudo rules\n");
|
||
|
+
|
||
|
+ subreq = ipa_sudo_refresh_send(state, ev, sudo_ctx, NULL, delete_filter);
|
||
|
+ if (subreq == NULL) {
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto immediately;
|
||
|
+ }
|
||
|
+
|
||
|
+ tevent_req_set_callback(subreq, ipa_sudo_full_refresh_done, req);
|
||
|
+
|
||
|
+ return req;
|
||
|
+
|
||
|
+immediately:
|
||
|
+ if (ret == EOK) {
|
||
|
+ tevent_req_done(req);
|
||
|
+ } else {
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ }
|
||
|
+ tevent_req_post(req, ev);
|
||
|
+
|
||
|
+ return req;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+ipa_sudo_full_refresh_done(struct tevent_req *subreq)
|
||
|
+{
|
||
|
+ struct ipa_sudo_full_refresh_state *state;
|
||
|
+ struct tevent_req *req;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ req = tevent_req_callback_data(subreq, struct tevent_req);
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_full_refresh_state);
|
||
|
+
|
||
|
+ ret = ipa_sudo_refresh_recv(subreq, &state->dp_error, NULL);
|
||
|
+ talloc_zfree(subreq);
|
||
|
+ if (ret != EOK || state->dp_error != DP_ERR_OK) {
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ state->sudo_ctx->full_refresh_done = true;
|
||
|
+
|
||
|
+ ret = sysdb_sudo_set_last_full_refresh(state->domain, time(NULL));
|
||
|
+ if (ret != EOK) {
|
||
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to save time of "
|
||
|
+ "a successful full refresh\n");
|
||
|
+ }
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_TRACE_FUNC, "Successful full refresh of sudo rules\n");
|
||
|
+
|
||
|
+done:
|
||
|
+ state->sudo_ctx->full_refresh_in_progress = false;
|
||
|
+
|
||
|
+ if (ret != EOK) {
|
||
|
+ tevent_req_error(req, ret);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ tevent_req_done(req);
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+ipa_sudo_full_refresh_recv(struct tevent_req *req,
|
||
|
+ int *dp_error)
|
||
|
+{
|
||
|
+ struct ipa_sudo_full_refresh_state *state;
|
||
|
+ state = tevent_req_data(req, struct ipa_sudo_full_refresh_state);
|
||
|
+
|
||
|
+ TEVENT_REQ_RETURN_ON_ERROR(req);
|
||
|
+
|
||
|
+ *dp_error = state->dp_error;
|
||
|
+
|
||
|
+ return EOK;
|
||
|
+}
|
||
|
+
|
||
|
+static struct tevent_req *
|
||
|
+ipa_sudo_ptask_full_refresh_send(TALLOC_CTX *mem_ctx,
|
||
|
+ struct tevent_context *ev,
|
||
|
+ struct be_ctx *be_ctx,
|
||
|
+ struct be_ptask *be_ptask,
|
||
|
+ void *pvt)
|
||
|
+{
|
||
|
+ struct ipa_sudo_ctx *sudo_ctx;
|
||
|
+ sudo_ctx = talloc_get_type(pvt, struct ipa_sudo_ctx);
|
||
|
+
|
||
|
+ return ipa_sudo_full_refresh_send(mem_ctx, be_ctx->ev, sudo_ctx);
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+ipa_sudo_ptask_full_refresh_recv(struct tevent_req *req)
|
||
|
+{
|
||
|
+ int dp_error;
|
||
|
+
|
||
|
+ return ipa_sudo_full_refresh_recv(req, &dp_error);
|
||
|
+}
|
||
|
+
|
||
|
+static struct tevent_req *
|
||
|
+ipa_sudo_ptask_smart_refresh_send(TALLOC_CTX *mem_ctx,
|
||
|
+ struct tevent_context *ev,
|
||
|
+ struct be_ctx *be_ctx,
|
||
|
+ struct be_ptask *be_ptask,
|
||
|
+ void *pvt)
|
||
|
+{
|
||
|
+ struct ipa_sudo_ctx *sudo_ctx;
|
||
|
+ sudo_ctx = talloc_get_type(pvt, struct ipa_sudo_ctx);
|
||
|
+
|
||
|
+ return ipa_sudo_full_refresh_send(mem_ctx, be_ctx->ev, sudo_ctx);
|
||
|
+}
|
||
|
+
|
||
|
+static errno_t
|
||
|
+ipa_sudo_ptask_smart_refresh_recv(struct tevent_req *req)
|
||
|
+{
|
||
|
+ int dp_error;
|
||
|
+
|
||
|
+ return ipa_sudo_full_refresh_recv(req, &dp_error);
|
||
|
+}
|
||
|
+
|
||
|
+errno_t
|
||
|
+ipa_sudo_ptask_setup(struct be_ctx *be_ctx, struct ipa_sudo_ctx *sudo_ctx)
|
||
|
+{
|
||
|
+ return sdap_sudo_ptask_setup_generic(be_ctx, sudo_ctx->id_ctx->opts->basic,
|
||
|
+ ipa_sudo_ptask_full_refresh_send,
|
||
|
+ ipa_sudo_ptask_full_refresh_recv,
|
||
|
+ ipa_sudo_ptask_smart_refresh_send,
|
||
|
+ ipa_sudo_ptask_smart_refresh_recv,
|
||
|
+ sudo_ctx);
|
||
|
+}
|
||
|
--
|
||
|
2.5.0
|
||
|
|