summaryrefslogtreecommitdiffstats
path: root/src/responder
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2016-02-09 12:57:59 +0100
committerLukas Slebodnik <lslebodn@redhat.com>2016-04-19 13:16:32 +0200
commitb3ca35780617b2e5a7637f9888b089e8e26a4e8c (patch)
tree604cc283191e6ab41720056ffe3c9d34e81e26a9 /src/responder
parent15d41c8f28259061e39715acdbbbaea778b6ecc8 (diff)
downloadsssd-b3ca35780617b2e5a7637f9888b089e8e26a4e8c.tar.gz
sssd-b3ca35780617b2e5a7637f9888b089e8e26a4e8c.tar.xz
sssd-b3ca35780617b2e5a7637f9888b089e8e26a4e8c.zip
sudo: convert get_sudorules to tevent
There was a lot of confusion with different error codes and where to call sudosrv_cmd_done to finish the client request. Converting it whole to tevent makes it much more simpler to read and follow the request logic. Reviewed-by: Jakub Hrozek <jhrozek@redhat.com> Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
Diffstat (limited to 'src/responder')
-rw-r--r--src/responder/sudo/sudosrv_cmd.c46
-rw-r--r--src/responder/sudo/sudosrv_get_sudorules.c787
-rw-r--r--src/responder/sudo/sudosrv_private.h20
3 files changed, 443 insertions, 410 deletions
diff --git a/src/responder/sudo/sudosrv_cmd.c b/src/responder/sudo/sudosrv_cmd.c
index bdf01fac7..eeb388c48 100644
--- a/src/responder/sudo/sudosrv_cmd.c
+++ b/src/responder/sudo/sudosrv_cmd.c
@@ -25,7 +25,6 @@
#include "util/util.h"
#include "responder/common/responder.h"
#include "responder/common/responder_packet.h"
-#include "responder/common/responder_cache_req.h"
#include "responder/sudo/sudosrv_private.h"
#include "db/sysdb_sudo.h"
#include "sss_client/sss_cli.h"
@@ -96,7 +95,7 @@ static errno_t sudosrv_cmd_send_error(TALLOC_CTX *mem_ctx,
return sudosrv_cmd_send_reply(cmd_ctx, response_body, response_len);
}
-errno_t sudosrv_cmd_done(struct sudo_cmd_ctx *cmd_ctx, int ret)
+errno_t sudosrv_cmd_reply(struct sudo_cmd_ctx *cmd_ctx, int ret)
{
uint8_t *response_body = NULL;
size_t response_len = 0;
@@ -165,7 +164,7 @@ errno_t sudosrv_cmd_done(struct sudo_cmd_ctx *cmd_ctx, int ret)
return EOK;
}
-static void sudosrv_cmd_initgr_done(struct tevent_req *req);
+static void sudosrv_cmd_done(struct tevent_req *req);
static int sudosrv_cmd(enum sss_sudo_type type, struct cli_ctx *cli_ctx)
{
@@ -185,7 +184,6 @@ static int sudosrv_cmd(enum sss_sudo_type type, struct cli_ctx *cli_ctx)
return ENOMEM;
}
- cmd_ctx->domain = NULL;
cmd_ctx->cli_ctx = cli_ctx;
cmd_ctx->type = type;
cmd_ctx->sudo_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct sudo_ctx);
@@ -229,56 +227,40 @@ static int sudosrv_cmd(enum sss_sudo_type type, struct cli_ctx *cli_ctx)
goto done;
}
- req = cache_req_initgr_by_name_send(cmd_ctx, cli_ctx->ev, cli_ctx->rctx,
- cmd_ctx->sudo_ctx->ncache,
- cmd_ctx->sudo_ctx->neg_timeout,
- 0, NULL, cmd_ctx->rawname);
+ req = sudosrv_get_rules_send(cmd_ctx, cli_ctx->ev, cmd_ctx->sudo_ctx,
+ cmd_ctx->type, cmd_ctx->uid,
+ cmd_ctx->rawname);
if (req == NULL) {
ret = ENOMEM;
goto done;
}
- tevent_req_set_callback(req, sudosrv_cmd_initgr_done, cmd_ctx);
+ tevent_req_set_callback(req, sudosrv_cmd_done, cmd_ctx);
ret = EAGAIN;
done:
- return sudosrv_cmd_done(cmd_ctx, ret);
+ return sudosrv_cmd_reply(cmd_ctx, ret);
}
-static void sudosrv_cmd_initgr_done(struct tevent_req *req)
+static void sudosrv_cmd_done(struct tevent_req *req)
{
- struct sudo_cmd_ctx *cmd_ctx = NULL;
+ struct sudo_cmd_ctx *cmd_ctx;
errno_t ret;
cmd_ctx = tevent_req_callback_data(req, struct sudo_cmd_ctx);
- ret = cache_req_initgr_by_name_recv(cmd_ctx, req, NULL, &cmd_ctx->domain,
- &cmd_ctx->username);
+ ret = sudosrv_get_rules_recv(cmd_ctx, req, &cmd_ctx->rules,
+ &cmd_ctx->num_rules);
talloc_zfree(req);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to perform initgroups [%d]: %s\n",
- ret, strerror(ret));
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to obtain cached rules [%d]: %s\n",
+ ret, sss_strerror(ret));
goto done;
}
- switch (cmd_ctx->type) {
- case SSS_SUDO_DEFAULTS:
- DEBUG(SSSDBG_FUNC_DATA, "Requesting default options "
- "for [%s] from [%s]\n", cmd_ctx->username,
- cmd_ctx->domain ? cmd_ctx->domain->name : "<ALL>");
- break;
- case SSS_SUDO_USER:
- DEBUG(SSSDBG_FUNC_DATA, "Requesting rules "
- "for [%s] from [%s]\n", cmd_ctx->username,
- cmd_ctx->domain ? cmd_ctx->domain->name : "<ALL>");
- break;
- }
-
- ret = sudosrv_get_sudorules(cmd_ctx);
-
done:
- sudosrv_cmd_done(cmd_ctx, ret);
+ sudosrv_cmd_reply(cmd_ctx, ret);
}
static int sudosrv_cmd_get_sudorules(struct cli_ctx *cli_ctx)
diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c
index c81c990ac..61f042670 100644
--- a/src/responder/sudo/sudosrv_get_sudorules.c
+++ b/src/responder/sudo/sudosrv_get_sudorules.c
@@ -28,198 +28,248 @@
#include "util/util.h"
#include "db/sysdb_sudo.h"
+#include "responder/common/responder_cache_req.h"
#include "responder/sudo/sudosrv_private.h"
#include "providers/data_provider.h"
-errno_t sudosrv_get_sudorules(struct sudo_cmd_ctx *cmd_ctx)
+static int
+sudo_order_cmp(const void *a, const void *b, bool lower_wins)
{
- errno_t ret;
+ struct sysdb_attrs *r1, *r2;
+ uint32_t o1, o2;
+ int ret;
- ret = sudosrv_get_rules(cmd_ctx);
- if (ret == EAGAIN) {
- DEBUG(SSSDBG_TRACE_INTERNAL,
- "Looking up the sudo rules from Data Provider\n");
- return EAGAIN;
+ r1 = * (struct sysdb_attrs * const *) a;
+ r2 = * (struct sysdb_attrs * const *) b;
+ if (!r1 || !r2) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Wrong data?\n");
+ return 0;
+ }
+
+ ret = sysdb_attrs_get_uint32_t(r1, SYSDB_SUDO_CACHE_AT_ORDER, &o1);
+ if (ret == ENOENT) {
+ /* man sudoers-ldap: If the sudoOrder attribute is not present,
+ * a value of 0 is assumed */
+ o1 = 0;
} else if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "Error looking up sudo rules [%d]: %s\n", ret, strerror(ret));
- return ret;
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot get sudoOrder value\n");
+ return 0;
}
- return EOK;
+ ret = sysdb_attrs_get_uint32_t(r2, SYSDB_SUDO_CACHE_AT_ORDER, &o2);
+ if (ret == ENOENT) {
+ /* man sudoers-ldap: If the sudoOrder attribute is not present,
+ * a value of 0 is assumed */
+ o2 = 0;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot get sudoOrder value\n");
+ return 0;
+ }
+
+ if (lower_wins) {
+ /* The lowest value takes priority. Original wrong SSSD behaviour. */
+ if (o1 > o2) {
+ return 1;
+ } else if (o1 < o2) {
+ return -1;
+ }
+ } else {
+ /* The higher value takes priority. Standard LDAP behaviour. */
+ if (o1 < o2) {
+ return 1;
+ } else if (o1 > o2) {
+ return -1;
+ }
+ }
+
+ return 0;
}
-static errno_t sudosrv_get_sudorules_from_cache(TALLOC_CTX *mem_ctx,
- struct sudo_cmd_ctx *cmd_ctx,
- struct sysdb_attrs ***_rules,
- uint32_t *_num_rules);
-static void
-sudosrv_get_sudorules_dp_callback(uint16_t err_maj, uint32_t err_min,
- const char *err_msg, void *ptr);
-static void
-sudosrv_dp_req_done(struct tevent_req *req);
-
-static errno_t sudosrv_get_sudorules_query_cache(TALLOC_CTX *mem_ctx,
- struct sss_domain_info *domain,
- const char **attrs,
- unsigned int flags,
- const char *username,
- uid_t uid,
- char **groupnames,
- bool inverse_order,
- struct sysdb_attrs ***_rules,
- uint32_t *_count);
-
-errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx)
+static int
+sudo_order_low_cmp_fn(const void *a, const void *b)
{
- TALLOC_CTX *tmp_ctx = NULL;
- struct tevent_req *dpreq = NULL;
- struct dp_callback_ctx *cb_ctx = NULL;
- char **groupnames = NULL;
- uint32_t expired_rules_num = 0;
- struct sysdb_attrs **expired_rules = NULL;
- errno_t ret;
- unsigned int flags = SYSDB_SUDO_FILTER_NONE;
- const char *attrs[] = { SYSDB_NAME,
- NULL };
+ return sudo_order_cmp(a, b, true);
+}
- if (cmd_ctx->domain == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Domain is not set!\n");
- return EFAULT;
+static int
+sudo_order_high_cmp_fn(const void *a, const void *b)
+{
+ return sudo_order_cmp(a, b, false);
+}
+
+static errno_t
+sort_sudo_rules(struct sysdb_attrs **rules, size_t count, bool lower_wins)
+{
+ if (lower_wins) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Sorting rules with lower-wins logic\n");
+ qsort(rules, count, sizeof(struct sysdb_attrs *),
+ sudo_order_low_cmp_fn);
+ } else {
+ DEBUG(SSSDBG_TRACE_FUNC, "Sorting rules with higher-wins logic\n");
+ qsort(rules, count, sizeof(struct sysdb_attrs *),
+ sudo_order_high_cmp_fn);
}
+ return EOK;
+}
+
+static errno_t sudosrv_query_cache(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ const char **attrs,
+ unsigned int flags,
+ const char *username,
+ uid_t uid,
+ char **groupnames,
+ bool inverse_order,
+ struct sysdb_attrs ***_rules,
+ uint32_t *_count)
+{
+ TALLOC_CTX *tmp_ctx;
+ char *filter;
+ errno_t ret;
+ size_t count;
+ struct sysdb_attrs **rules;
+ struct ldb_message **msgs;
+
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
return ENOMEM;
}
- switch (cmd_ctx->type) {
- case SSS_SUDO_DEFAULTS:
- DEBUG(SSSDBG_TRACE_FUNC, "Retrieving default options "
- "for [%s] from [%s]\n", cmd_ctx->username,
- cmd_ctx->domain->name);
- break;
- case SSS_SUDO_USER:
- DEBUG(SSSDBG_TRACE_FUNC, "Retrieving rules "
- "for [%s] from [%s]\n", cmd_ctx->username,
- cmd_ctx->domain->name);
- break;
+ ret = sysdb_get_sudo_filter(tmp_ctx, username, uid, groupnames,
+ flags, &filter);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not construct the search filter "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
+ }
+
+ DEBUG(SSSDBG_FUNC_DATA, "Searching sysdb with [%s]\n", filter);
+
+ if (IS_SUBDOMAIN(domain)) {
+ /* rules are stored inside parent domain tree */
+ domain = domain->parent;
+ }
+
+ ret = sysdb_search_custom(tmp_ctx, domain, filter, SUDORULE_SUBDIR,
+ attrs, &count, &msgs);
+ if (ret == ENOENT) {
+ *_rules = NULL;
+ *_count = 0;
+ ret = EOK;
+ goto done;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up SUDO rules\n");
+ goto done;
}
- /* Fetch all expired rules:
- * sudo asks sssd twice - for defaults and for rules. If we refresh all
- * expired rules for this user and defaults at once we will save one
- * provider call
- */
- ret = sysdb_get_sudo_user_info(tmp_ctx, cmd_ctx->domain,
- cmd_ctx->username, NULL, &groupnames);
+ ret = sysdb_msg2attrs(tmp_ctx, count, msgs, &rules);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
- "Unable to retrieve user info [%d]: %s\n", ret, strerror(ret));
+ "Could not convert ldb message to sysdb_attrs\n");
goto done;
}
- flags = SYSDB_SUDO_FILTER_INCLUDE_ALL
- | SYSDB_SUDO_FILTER_INCLUDE_DFL
- | SYSDB_SUDO_FILTER_ONLY_EXPIRED
- | SYSDB_SUDO_FILTER_USERINFO;
- ret = sudosrv_get_sudorules_query_cache(tmp_ctx,
- cmd_ctx->domain, attrs, flags,
- cmd_ctx->username,
- cmd_ctx->uid, groupnames,
- cmd_ctx->sudo_ctx->inverse_order,
- &expired_rules, &expired_rules_num);
+ ret = sort_sudo_rules(rules, count, inverse_order);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to retrieve expired sudo rules "
- "[%d]: %s\n", ret, strerror(ret));
+ DEBUG(SSSDBG_OP_FAILURE, "Could not sort rules by sudoOrder\n");
goto done;
}
- cmd_ctx->expired_rules_num = expired_rules_num;
- if (expired_rules_num > 0) {
- /* refresh expired rules then continue */
- DEBUG(SSSDBG_TRACE_INTERNAL, "Refreshing %d expired rules\n",
- expired_rules_num);
- dpreq = sss_dp_get_sudoers_send(tmp_ctx, cmd_ctx->cli_ctx->rctx,
- cmd_ctx->domain, false,
- SSS_DP_SUDO_REFRESH_RULES,
- cmd_ctx->username,
- expired_rules_num, expired_rules);
- if (dpreq == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Cannot issue DP request.\n");
- ret = EIO;
- goto done;
- }
-
- cb_ctx = talloc_zero(tmp_ctx, struct dp_callback_ctx);
- if (!cb_ctx) {
- talloc_zfree(dpreq);
- ret = ENOMEM;
- goto done;
- }
+ *_rules = talloc_steal(mem_ctx, rules);
+ *_count = (uint32_t)count;
- cb_ctx->callback = sudosrv_get_sudorules_dp_callback;
- cb_ctx->ptr = cmd_ctx;
- cb_ctx->cctx = cmd_ctx->cli_ctx;
- cb_ctx->mem_ctx = cmd_ctx;
+ ret = EOK;
- tevent_req_set_callback(dpreq, sudosrv_dp_req_done, cb_ctx);
- ret = EAGAIN;
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
- } else {
- /* nothing is expired return what we have in the cache */
- DEBUG(SSSDBG_TRACE_INTERNAL, "About to get sudo rules from cache\n");
- ret = sudosrv_get_sudorules_from_cache(cmd_ctx, cmd_ctx,
- &cmd_ctx->rules,
- &cmd_ctx->num_rules);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "Failed to make a request to our cache [%d]: %s\n",
- ret, strerror(ret));
- goto done;
- }
- }
+static errno_t sudosrv_expired_rules(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ uid_t uid,
+ const char *username,
+ char **groups,
+ struct sysdb_attrs ***_rules,
+ uint32_t *_num_rules)
+{
+ unsigned int flags = SYSDB_SUDO_FILTER_NONE;
+ const char *attrs[] = { SYSDB_NAME, NULL };
+ errno_t ret;
- if (dpreq != NULL) {
- talloc_steal(cmd_ctx->cli_ctx, dpreq);
- }
+ flags = SYSDB_SUDO_FILTER_INCLUDE_ALL
+ | SYSDB_SUDO_FILTER_INCLUDE_DFL
+ | SYSDB_SUDO_FILTER_ONLY_EXPIRED
+ | SYSDB_SUDO_FILTER_USERINFO;
- if (cb_ctx != NULL) {
- talloc_steal(cmd_ctx, cb_ctx);
- }
+ ret = sudosrv_query_cache(mem_ctx, domain, attrs, flags,
+ username, uid, groups, false,
+ _rules, _num_rules);
-done:
- talloc_free(tmp_ctx);
return ret;
}
-static void
-sudosrv_dp_req_done(struct tevent_req *req)
+static errno_t sudosrv_cached_rules(TALLOC_CTX *mem_ctx,
+ enum sss_sudo_type type,
+ struct sss_domain_info *domain,
+ uid_t uid,
+ const char *username,
+ char **groups,
+ bool inverse_order,
+ struct sysdb_attrs ***_rules,
+ uint32_t *_num_rules)
{
- struct dp_callback_ctx *cb_ctx =
- tevent_req_callback_data(req, struct dp_callback_ctx);
- struct cli_ctx *cli_ctx;
-
+ unsigned int flags = SYSDB_SUDO_FILTER_NONE;
+ struct sysdb_attrs **rules;
+ const char *debug_name = "unknown";
+ uint32_t num_rules;
errno_t ret;
- dbus_uint16_t err_maj;
- dbus_uint32_t err_min;
- char *err_msg;
+ const char *attrs[] = { SYSDB_OBJECTCLASS,
+ SYSDB_SUDO_CACHE_AT_CN,
+ SYSDB_SUDO_CACHE_AT_USER,
+ SYSDB_SUDO_CACHE_AT_HOST,
+ SYSDB_SUDO_CACHE_AT_COMMAND,
+ SYSDB_SUDO_CACHE_AT_OPTION,
+ SYSDB_SUDO_CACHE_AT_RUNAS,
+ SYSDB_SUDO_CACHE_AT_RUNASUSER,
+ SYSDB_SUDO_CACHE_AT_RUNASGROUP,
+ SYSDB_SUDO_CACHE_AT_NOTBEFORE,
+ SYSDB_SUDO_CACHE_AT_NOTAFTER,
+ SYSDB_SUDO_CACHE_AT_ORDER,
+ NULL };
- cli_ctx = talloc_get_type(cb_ctx->cctx, struct cli_ctx);
+ switch (type) {
+ case SSS_SUDO_USER:
+ DEBUG(SSSDBG_TRACE_FUNC, "Retrieving rules for [%s@%s]\n",
+ username, domain->name);
+ debug_name = "rules";
+ flags = SYSDB_SUDO_FILTER_USERINFO | SYSDB_SUDO_FILTER_INCLUDE_ALL;
+ break;
+ case SSS_SUDO_DEFAULTS:
+ debug_name = "default options";
+ DEBUG(SSSDBG_TRACE_FUNC, "Retrieving default options for [%s@%s]\n",
+ username, domain->name);
+ flags = SYSDB_SUDO_FILTER_INCLUDE_DFL;
+ break;
+ }
- ret = sss_dp_get_sudoers_recv(cb_ctx->mem_ctx, req,
- &err_maj, &err_min,
- &err_msg);
- talloc_free(req);
+ ret = sudosrv_query_cache(mem_ctx, domain, attrs, flags,
+ username, uid, groups,
+ inverse_order, &rules, &num_rules);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Fatal error, killing connection!\n");
- talloc_free(cli_ctx);
- return;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to retrieve sudo rules [%d]: %s\n", ret, strerror(ret));
+ return ret;
}
- cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
+ DEBUG(SSSDBG_TRACE_FUNC, "Returning %d %s for [%s@%s]\n",
+ num_rules, debug_name, username, domain->name);
+
+ *_rules = rules;
+ *_num_rules = num_rules;
+
+ return EOK;
}
static void
@@ -229,295 +279,294 @@ sudosrv_dp_oob_req_done(struct tevent_req *req)
talloc_free(req);
}
-static void
-sudosrv_get_sudorules_dp_callback(uint16_t err_maj, uint32_t err_min,
- const char *err_msg, void *ptr)
+struct sudosrv_refresh_rules_state {
+ struct resp_ctx *rctx;
+ struct sss_domain_info *domain;
+ const char *username;
+};
+
+static void sudosrv_refresh_rules_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+sudosrv_refresh_rules_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct resp_ctx *rctx,
+ struct sss_domain_info *domain,
+ uid_t uid,
+ const char *username,
+ char **groups)
{
- struct sudo_cmd_ctx *cmd_ctx = talloc_get_type(ptr, struct sudo_cmd_ctx);
- struct tevent_req *dpreq = NULL;
+ struct sudosrv_refresh_rules_state *state;
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct sysdb_attrs **rules;
+ uint32_t num_rules;
errno_t ret;
- if (err_maj) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Unable to get information from Data Provider\n"
- "Error: %u, %u, %s\n"
- "Will try to return what we have in cache\n",
- (unsigned int)err_maj, (unsigned int)err_min, err_msg);
+ req = tevent_req_create(mem_ctx, &state,
+ struct sudosrv_refresh_rules_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- DEBUG(SSSDBG_TRACE_INTERNAL, "About to get sudo rules from cache\n");
- ret = sudosrv_get_sudorules_from_cache(cmd_ctx, cmd_ctx, &cmd_ctx->rules,
- &cmd_ctx->num_rules);
+ state->rctx = rctx;
+ state->domain = domain;
+ state->username = username;
+
+ ret = sudosrv_expired_rules(state, domain, uid, username, groups,
+ &rules, &num_rules);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "Failed to make a request to our cache [%d]: %s\n",
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to retrieve expired sudo rules [%d]: %s\n",
ret, strerror(ret));
- sudosrv_cmd_done(cmd_ctx, EIO);
- return;
+ goto immediately;
}
- if (cmd_ctx->expired_rules_num > 0
- && err_min == ENOENT) {
- DEBUG(SSSDBG_TRACE_INTERNAL,
- "Some expired rules were removed from the server, "
- "scheduling full refresh out of band\n");
- dpreq = sss_dp_get_sudoers_send(cmd_ctx->cli_ctx->rctx,
- cmd_ctx->cli_ctx->rctx,
- cmd_ctx->domain, false,
- SSS_DP_SUDO_FULL_REFRESH,
- cmd_ctx->username,
- 0, NULL);
- if (dpreq == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Cannot issue DP request.\n");
- } else {
- tevent_req_set_callback(dpreq, sudosrv_dp_oob_req_done, NULL);
- }
+ if (num_rules == 0) {
+ DEBUG(SSSDBG_TRACE_FUNC, "No expired rules were found for [%s@%s].\n",
+ username, domain->name);
+ ret = EOK;
+ goto immediately;
+ }
+
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Refreshing %d expired rules of [%s@%s]\n",
+ num_rules, username, domain->name);
+
+ subreq = sss_dp_get_sudoers_send(state, rctx, domain, false,
+ SSS_DP_SUDO_REFRESH_RULES,
+ username, num_rules, rules);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, sudosrv_refresh_rules_done, req);
+
+ return req;
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
}
+ tevent_req_post(req, ev);
- sudosrv_cmd_done(cmd_ctx, ret);
+ return req;
}
-static errno_t sudosrv_get_sudorules_from_cache(TALLOC_CTX *mem_ctx,
- struct sudo_cmd_ctx *cmd_ctx,
- struct sysdb_attrs ***_rules,
- uint32_t *_num_rules)
+static void sudosrv_refresh_rules_done(struct tevent_req *subreq)
{
- TALLOC_CTX *tmp_ctx;
+ struct sudosrv_refresh_rules_state *state;
+ struct tevent_req *req;
+ dbus_uint16_t err_maj;
+ dbus_uint32_t err_min;
+ char *err_msg;
errno_t ret;
- char **groupnames = NULL;
- const char *debug_name = NULL;
- unsigned int flags = SYSDB_SUDO_FILTER_NONE;
- struct sysdb_attrs **rules = NULL;
- uint32_t num_rules = 0;
- const char *attrs[] = { SYSDB_OBJECTCLASS,
- SYSDB_SUDO_CACHE_AT_CN,
- SYSDB_SUDO_CACHE_AT_USER,
- SYSDB_SUDO_CACHE_AT_HOST,
- SYSDB_SUDO_CACHE_AT_COMMAND,
- SYSDB_SUDO_CACHE_AT_OPTION,
- SYSDB_SUDO_CACHE_AT_RUNAS,
- SYSDB_SUDO_CACHE_AT_RUNASUSER,
- SYSDB_SUDO_CACHE_AT_RUNASGROUP,
- SYSDB_SUDO_CACHE_AT_NOTBEFORE,
- SYSDB_SUDO_CACHE_AT_NOTAFTER,
- SYSDB_SUDO_CACHE_AT_ORDER,
- NULL };
- if (cmd_ctx->domain == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Domain is not set!\n");
- return EFAULT;
- }
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sudosrv_refresh_rules_state);
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
- return ENOMEM;
+ ret = sss_dp_get_sudoers_recv(state, subreq, &err_maj, &err_min, &err_msg);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to get information from Data Provider, "
+ "Error: %u, %u, %s\n",
+ (unsigned int)err_maj, (unsigned int)err_min, err_msg);
+ goto done;
}
- switch (cmd_ctx->type) {
- case SSS_SUDO_USER:
- debug_name = cmd_ctx->username;
- ret = sysdb_get_sudo_user_info(tmp_ctx,
- cmd_ctx->domain,
- cmd_ctx->username,
- NULL, &groupnames);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Unable to retrieve user info [%d]: %s\n",
- ret, strerror(ret));
+ if (err_min == ENOENT) {
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "Some expired rules were removed from the server, scheduling "
+ "full refresh out of band\n");
+ subreq = sss_dp_get_sudoers_send(state->rctx, state->rctx,
+ state->domain, false,
+ SSS_DP_SUDO_FULL_REFRESH,
+ state->username, 0, NULL);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot issue DP request.\n");
+ ret = EOK; /* We don't care. */
goto done;
}
- flags = SYSDB_SUDO_FILTER_USERINFO | SYSDB_SUDO_FILTER_INCLUDE_ALL;
- break;
- case SSS_SUDO_DEFAULTS:
- debug_name = "<default options>";
- flags = SYSDB_SUDO_FILTER_INCLUDE_DFL;
- break;
- }
- ret = sudosrv_get_sudorules_query_cache(tmp_ctx,
- cmd_ctx->domain, attrs, flags,
- cmd_ctx->username,
- cmd_ctx->uid, groupnames,
- cmd_ctx->sudo_ctx->inverse_order,
- &rules, &num_rules);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Unable to retrieve sudo rules [%d]: %s\n", ret, strerror(ret));
- goto done;
+ tevent_req_set_callback(subreq, sudosrv_dp_oob_req_done, NULL);
}
- DEBUG(SSSDBG_TRACE_FUNC, "Returning %d rules for [%s@%s]\n",
- num_rules, debug_name, cmd_ctx->domain->name);
+ ret = EOK;
- if (_rules != NULL) {
- *_rules = talloc_steal(mem_ctx, rules);
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
}
- if (_num_rules != NULL) {
- *_num_rules = num_rules;
- }
+ tevent_req_done(req);
+}
- ret = EOK;
-done:
- talloc_free(tmp_ctx);
- return ret;
+static errno_t sudosrv_refresh_rules_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
}
-static errno_t
-sort_sudo_rules(struct sysdb_attrs **rules, size_t count, bool higher_wins);
-
-static errno_t sudosrv_get_sudorules_query_cache(TALLOC_CTX *mem_ctx,
- struct sss_domain_info *domain,
- const char **attrs,
- unsigned int flags,
- const char *username,
- uid_t uid,
- char **groupnames,
- bool inverse_order,
- struct sysdb_attrs ***_rules,
- uint32_t *_count)
+struct sudosrv_get_rules_state {
+ struct tevent_context *ev;
+ struct resp_ctx *rctx;
+ enum sss_sudo_type type;
+ uid_t uid;
+ char *username;
+ struct sss_domain_info *domain;
+ char **groups;
+ bool inverse_order;
+
+ struct sysdb_attrs **rules;
+ uint32_t num_rules;
+};
+
+static void sudosrv_get_rules_initgr_done(struct tevent_req *subreq);
+static void sudosrv_get_rules_done(struct tevent_req *subreq);
+
+struct tevent_req *sudosrv_get_rules_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sudo_ctx *sudo_ctx,
+ enum sss_sudo_type type,
+ uid_t uid,
+ const char *username)
{
- TALLOC_CTX *tmp_ctx;
- char *filter;
+ struct sudosrv_get_rules_state *state;
+ struct tevent_req *req;
+ struct tevent_req *subreq;
errno_t ret;
- size_t count;
- struct sysdb_attrs **rules;
- struct ldb_message **msgs;
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) return ENOMEM;
+ req = tevent_req_create(mem_ctx, &state, struct sudosrv_get_rules_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
+ return NULL;
+ }
- ret = sysdb_get_sudo_filter(tmp_ctx, username, uid, groupnames,
- flags, &filter);
- if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Could not construct the search filter [%d]: %s\n",
- ret, strerror(ret));
- goto done;
+ state->ev = ev;
+ state->rctx = sudo_ctx->rctx;
+ state->type = type;
+ state->uid = uid;
+ state->inverse_order = sudo_ctx->inverse_order;
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Running initgroups for [%s]\n", username);
+
+ subreq = cache_req_initgr_by_name_send(state, ev, sudo_ctx->rctx,
+ sudo_ctx->ncache,
+ sudo_ctx->neg_timeout,
+ 0, NULL, username);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
}
- DEBUG(SSSDBG_FUNC_DATA, "Searching sysdb with [%s]\n", filter);
+ tevent_req_set_callback(subreq, sudosrv_get_rules_initgr_done, req);
- if (IS_SUBDOMAIN(domain)) {
- /* rules are stored inside parent domain tree */
- domain = domain->parent;
+ return req;
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
}
+ tevent_req_post(req, ev);
- ret = sysdb_search_custom(tmp_ctx, domain, filter,
- SUDORULE_SUBDIR, attrs,
- &count, &msgs);
- if (ret != EOK && ret != ENOENT) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up SUDO rules\n");
+ return req;
+}
+
+static void sudosrv_get_rules_initgr_done(struct tevent_req *subreq)
+{
+ struct sudosrv_get_rules_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sudosrv_get_rules_state);
+
+ ret = cache_req_initgr_by_name_recv(state, subreq, NULL,
+ &state->domain, &state->username);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
goto done;
- } if (ret == ENOENT) {
- *_rules = NULL;
- *_count = 0;
- ret = EOK;
- goto done;
}
- ret = sysdb_msg2attrs(tmp_ctx, count, msgs, &rules);
+ ret = sysdb_get_sudo_user_info(state, state->domain, state->username,
+ NULL, &state->groups);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Could not convert ldb message to sysdb_attrs\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to obtain user groups [%d]: %s\n",
+ ret, sss_strerror(ret));
goto done;
}
- ret = sort_sudo_rules(rules, count, inverse_order);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "Could not sort rules by sudoOrder\n");
+ subreq = sudosrv_refresh_rules_send(state, state->ev, state->rctx,
+ state->domain, state->uid,
+ state->username, state->groups);
+ if (subreq == NULL) {
+ ret = ENOMEM;
goto done;
}
- *_rules = talloc_steal(mem_ctx, rules);
- *_count = (uint32_t)count;
+ tevent_req_set_callback(subreq, sudosrv_get_rules_done, req);
+
+ ret = EAGAIN;
- ret = EOK;
done:
- talloc_free(tmp_ctx);
- return ret;
+ if (ret != EOK && ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ return;
+ } else if (ret != EAGAIN) {
+ tevent_req_done(req);
+ }
}
-static int
-sudo_order_cmp(const void *a, const void *b, bool lower_wins)
+static void sudosrv_get_rules_done(struct tevent_req *subreq)
{
- struct sysdb_attrs *r1, *r2;
- uint32_t o1, o2;
- int ret;
+ struct sudosrv_get_rules_state *state = NULL;
+ struct tevent_req *req = NULL;
+ errno_t ret;
- r1 = * (struct sysdb_attrs * const *) a;
- r2 = * (struct sysdb_attrs * const *) b;
- if (!r1 || !r2) {
- DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Wrong data?\n");
- return 0;
- }
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sudosrv_get_rules_state);
- ret = sysdb_attrs_get_uint32_t(r1, SYSDB_SUDO_CACHE_AT_ORDER, &o1);
- if (ret == ENOENT) {
- /* man sudoers-ldap: If the sudoOrder attribute is not present,
- * a value of 0 is assumed */
- o1 = 0;
- } else if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Cannot get sudoOrder value\n");
- return 0;
+ ret = sudosrv_refresh_rules_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Unable to refresh expired rules, we will return what is "
+ "in cache.\n");
}
- ret = sysdb_attrs_get_uint32_t(r2, SYSDB_SUDO_CACHE_AT_ORDER, &o2);
- if (ret == ENOENT) {
- /* man sudoers-ldap: If the sudoOrder attribute is not present,
- * a value of 0 is assumed */
- o2 = 0;
- } else if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Cannot get sudoOrder value\n");
- return 0;
- }
+ ret = sudosrv_cached_rules(state, state->type, state->domain, state->uid,
+ state->username, state->groups,
+ state->inverse_order,
+ &state->rules, &state->num_rules);
- if (lower_wins) {
- /* The lowest value takes priority. Original wrong SSSD behaviour. */
- if (o1 > o2) {
- return 1;
- } else if (o1 < o2) {
- return -1;
- }
- } else {
- /* The higher value takes priority. Standard LDAP behaviour. */
- if (o1 < o2) {
- return 1;
- } else if (o1 > o2) {
- return -1;
- }
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
}
- return 0;
+ tevent_req_done(req);
}
-static int
-sudo_order_low_cmp_fn(const void *a, const void *b)
+errno_t sudosrv_get_rules_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct sysdb_attrs ***_rules,
+ uint32_t *_num_rules)
{
- return sudo_order_cmp(a, b, true);
-}
+ struct sudosrv_get_rules_state *state = NULL;
+ state = tevent_req_data(req, struct sudosrv_get_rules_state);
-static int
-sudo_order_high_cmp_fn(const void *a, const void *b)
-{
- return sudo_order_cmp(a, b, false);
-}
+ TEVENT_REQ_RETURN_ON_ERROR(req);
-static errno_t
-sort_sudo_rules(struct sysdb_attrs **rules, size_t count, bool lower_wins)
-{
- if (lower_wins) {
- DEBUG(SSSDBG_TRACE_FUNC, "Sorting rules with lower-wins logic\n");
- qsort(rules, count, sizeof(struct sysdb_attrs *),
- sudo_order_low_cmp_fn);
- } else {
- DEBUG(SSSDBG_TRACE_FUNC, "Sorting rules with higher-wins logic\n");
- qsort(rules, count, sizeof(struct sysdb_attrs *),
- sudo_order_high_cmp_fn);
- }
+ *_rules = talloc_steal(mem_ctx, state->rules);
+ *_num_rules = state->num_rules;
return EOK;
}
diff --git a/src/responder/sudo/sudosrv_private.h b/src/responder/sudo/sudosrv_private.h
index 38de16960..99eef03e9 100644
--- a/src/responder/sudo/sudosrv_private.h
+++ b/src/responder/sudo/sudosrv_private.h
@@ -61,10 +61,6 @@ struct sudo_cmd_ctx {
/* input data */
uid_t uid;
char *rawname;
- char *username;
- struct sss_domain_info *domain;
-
- uint32_t expired_rules_num;
/* output data */
struct sysdb_attrs **rules;
@@ -73,11 +69,17 @@ struct sudo_cmd_ctx {
struct sss_cmd_table *get_sudo_cmds(void);
-errno_t sudosrv_cmd_done(struct sudo_cmd_ctx *cmd_ctx, int ret);
-
-errno_t sudosrv_get_sudorules(struct sudo_cmd_ctx *cmd_ctx);
-
-errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx);
+struct tevent_req *sudosrv_get_rules_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sudo_ctx *sudo_ctx,
+ enum sss_sudo_type type,
+ uid_t uid,
+ const char *username);
+
+errno_t sudosrv_get_rules_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct sysdb_attrs ***_rules,
+ uint32_t *_num_rules);
errno_t sudosrv_parse_query(TALLOC_CTX *mem_ctx,
uint8_t *query_body,