summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2012-10-30 12:01:51 +0100
committerJakub Hrozek <jhrozek@redhat.com>2012-11-14 17:11:15 +0100
commitd38ffc9c92daeb62de7d28c409bdaeff98f82775 (patch)
tree11b630163d3894291cc981e2eb46d92bb8972b62
parent5a3c49e513f73c1ea2b0e756bab25839e8f35321 (diff)
downloadsssd-d38ffc9c92daeb62de7d28c409bdaeff98f82775.tar.gz
sssd-d38ffc9c92daeb62de7d28c409bdaeff98f82775.tar.bz2
sssd-d38ffc9c92daeb62de7d28c409bdaeff98f82775.zip
sudo: support users from subdomains
https://fedorahosted.org/sssd/ticket/1616
-rw-r--r--src/responder/sudo/sudosrv_cmd.c41
-rw-r--r--src/responder/sudo/sudosrv_get_sudorules.c64
-rw-r--r--src/responder/sudo/sudosrv_private.h17
-rw-r--r--src/responder/sudo/sudosrv_query.c152
4 files changed, 214 insertions, 60 deletions
diff --git a/src/responder/sudo/sudosrv_cmd.c b/src/responder/sudo/sudosrv_cmd.c
index 9a87ed7d..440c8c5d 100644
--- a/src/responder/sudo/sudosrv_cmd.c
+++ b/src/responder/sudo/sudosrv_cmd.c
@@ -156,10 +156,12 @@ errno_t sudosrv_cmd_done(struct sudo_cmd_ctx *cmd_ctx, int ret)
return EOK;
}
+static void sudosrv_cmd_parse_query_done(struct tevent_req *req);
+
static int sudosrv_cmd(enum sss_sudo_type type, struct cli_ctx *cli_ctx)
{
+ struct tevent_req *req = NULL;
struct sudo_cmd_ctx *cmd_ctx = NULL;
- struct sudo_dom_ctx *dom_ctx = NULL;
uint8_t *query_body = NULL;
size_t query_len = 0;
errno_t ret;
@@ -199,11 +201,35 @@ static int sudosrv_cmd(enum sss_sudo_type type, struct cli_ctx *cli_ctx)
goto done;
}
- ret = sudosrv_parse_query(cmd_ctx, cli_ctx->rctx,
- query_body, query_len,
- &cmd_ctx->uid, &cmd_ctx->username, &cmd_ctx->domain);
+ req = sudosrv_parse_query_send(cmd_ctx, cli_ctx->rctx,
+ query_body, query_len);
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(req, sudosrv_cmd_parse_query_done, cmd_ctx);
+
+ ret = EAGAIN;
+
+done:
+ return sudosrv_cmd_done(cmd_ctx, ret);
+}
+
+static void sudosrv_cmd_parse_query_done(struct tevent_req *req)
+{
+ struct sudo_cmd_ctx *cmd_ctx = NULL;
+ struct sudo_dom_ctx *dom_ctx = NULL;
+ errno_t ret;
+
+ cmd_ctx = tevent_req_callback_data(req, struct sudo_cmd_ctx);
+
+ ret = sudosrv_parse_query_recv(cmd_ctx, req, &cmd_ctx->uid,
+ &cmd_ctx->username, &cmd_ctx->domain);
+ talloc_zfree(req);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid query: %s\n", strerror(ret)));
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid query [%d]: %s\n",
+ ret, strerror(ret)));
goto done;
}
@@ -231,15 +257,14 @@ static int sudosrv_cmd(enum sss_sudo_type type, struct cli_ctx *cli_ctx)
}
dom_ctx->cmd_ctx = cmd_ctx;
dom_ctx->domain = cmd_ctx->domain != NULL ? cmd_ctx->domain
- : cli_ctx->rctx->domains;
+ : cmd_ctx->cli_ctx->rctx->domains;
ret = sudosrv_get_sudorules(dom_ctx);
done:
- return sudosrv_cmd_done(cmd_ctx, ret);
+ sudosrv_cmd_done(cmd_ctx, ret);
}
-
static int sudosrv_cmd_get_sudorules(struct cli_ctx *cli_ctx)
{
return sudosrv_cmd(SSS_SUDO_USER, cli_ctx);
diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c
index 9081cbd7..6d6b95d3 100644
--- a/src/responder/sudo/sudosrv_get_sudorules.c
+++ b/src/responder/sudo/sudosrv_get_sudorules.c
@@ -29,6 +29,22 @@
#include "db/sysdb_sudo.h"
#include "responder/sudo/sudosrv_private.h"
+static struct sysdb_ctx* sudosrv_get_user_sysdb(struct sss_domain_info *domain)
+{
+ return domain->sysdb;
+}
+
+static struct sysdb_ctx* sudosrv_get_rules_sysdb(struct sss_domain_info *domain)
+{
+ if (domain->parent == NULL) {
+ return domain->sysdb;
+ } else {
+ /* sudo rules are stored under parent domain basedn, so we will return
+ * parent's sysdb context */
+ return domain->parent->sysdb;
+ }
+}
+
static errno_t sudosrv_get_user(struct sudo_dom_ctx *dctx);
errno_t sudosrv_get_sudorules(struct sudo_dom_ctx *dctx)
@@ -112,7 +128,7 @@ static errno_t sudosrv_get_user(struct sudo_dom_ctx *dctx)
DEBUG(SSSDBG_FUNC_DATA, ("Requesting info about [%s@%s]\n",
name, dom->name));
- sysdb = dctx->domain->sysdb;
+ sysdb = sudosrv_get_user_sysdb(dctx->domain);
if (sysdb == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE,
("sysdb context not found for this domain!\n"));
@@ -327,7 +343,8 @@ errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx)
TALLOC_CTX *tmp_ctx = NULL;
struct tevent_req *dpreq = NULL;
struct dp_callback_ctx *cb_ctx = NULL;
- struct sysdb_ctx *sysdb;
+ struct sysdb_ctx *user_sysdb = NULL;
+ struct sysdb_ctx *rules_sysdb = NULL;
char **groupnames = NULL;
size_t expired_rules_num = 0;
struct sysdb_attrs **expired_rules = NULL;
@@ -341,7 +358,21 @@ errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx)
return EFAULT;
}
- sysdb = cmd_ctx->domain->sysdb;
+ user_sysdb = sudosrv_get_user_sysdb(cmd_ctx->domain);
+ if (user_sysdb == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("user sysdb context not found for this domain!\n"));
+ ret = EIO;
+ goto done;
+ }
+
+ rules_sysdb = sudosrv_get_rules_sysdb(cmd_ctx->domain);
+ if (rules_sysdb == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("rules sysdb context not found for this domain!\n"));
+ ret = EIO;
+ goto done;
+ }
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
@@ -367,7 +398,7 @@ errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx)
* 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->orig_username, sysdb,
+ ret = sysdb_get_sudo_user_info(tmp_ctx, cmd_ctx->orig_username, user_sysdb,
NULL, &groupnames);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
@@ -379,7 +410,7 @@ errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx)
| SYSDB_SUDO_FILTER_INCLUDE_DFL
| SYSDB_SUDO_FILTER_ONLY_EXPIRED
| SYSDB_SUDO_FILTER_USERINFO;
- ret = sudosrv_get_sudorules_query_cache(tmp_ctx, sysdb, cmd_ctx->type,
+ ret = sudosrv_get_sudorules_query_cache(tmp_ctx, rules_sysdb, cmd_ctx->type,
attrs, flags, cmd_ctx->orig_username,
cmd_ctx->uid, groupnames,
&expired_rules, &expired_rules_num);
@@ -535,7 +566,8 @@ static errno_t sudosrv_get_sudorules_from_cache(TALLOC_CTX *mem_ctx,
{
TALLOC_CTX *tmp_ctx;
errno_t ret;
- struct sysdb_ctx *sysdb;
+ struct sysdb_ctx *user_sysdb = NULL;
+ struct sysdb_ctx *rules_sysdb = NULL;
char **groupnames = NULL;
const char *debug_name = NULL;
unsigned int flags = SYSDB_SUDO_FILTER_NONE;
@@ -565,10 +597,18 @@ static errno_t sudosrv_get_sudorules_from_cache(TALLOC_CTX *mem_ctx,
return ENOMEM;
}
- sysdb = cmd_ctx->domain->sysdb;
- if (sysdb == NULL) {
+ user_sysdb = sudosrv_get_user_sysdb(cmd_ctx->domain);
+ if (user_sysdb == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("user sysdb context not found for this domain!\n"));
+ ret = EIO;
+ goto done;
+ }
+
+ rules_sysdb = sudosrv_get_rules_sysdb(cmd_ctx->domain);
+ if (rules_sysdb == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE,
- ("sysdb context not found for this domain!\n"));
+ ("rules sysdb context not found for this domain!\n"));
ret = EIO;
goto done;
}
@@ -576,8 +616,8 @@ static errno_t sudosrv_get_sudorules_from_cache(TALLOC_CTX *mem_ctx,
switch (cmd_ctx->type) {
case SSS_SUDO_USER:
debug_name = cmd_ctx->cased_username;
- ret = sysdb_get_sudo_user_info(tmp_ctx, cmd_ctx->orig_username, sysdb,
- NULL, &groupnames);
+ ret = sysdb_get_sudo_user_info(tmp_ctx, cmd_ctx->orig_username,
+ user_sysdb, NULL, &groupnames);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Unable to retrieve user info [%d]: %s\n", strerror(ret)));
@@ -591,7 +631,7 @@ static errno_t sudosrv_get_sudorules_from_cache(TALLOC_CTX *mem_ctx,
break;
}
- ret = sudosrv_get_sudorules_query_cache(tmp_ctx, sysdb, cmd_ctx->type,
+ ret = sudosrv_get_sudorules_query_cache(tmp_ctx, rules_sysdb, cmd_ctx->type,
attrs, flags, cmd_ctx->orig_username,
cmd_ctx->uid, groupnames,
&rules, &num_rules);
diff --git a/src/responder/sudo/sudosrv_private.h b/src/responder/sudo/sudosrv_private.h
index 55ea1383..b8059407 100644
--- a/src/responder/sudo/sudosrv_private.h
+++ b/src/responder/sudo/sudosrv_private.h
@@ -90,13 +90,16 @@ errno_t sudosrv_get_sudorules(struct sudo_dom_ctx *dctx);
errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx);
-errno_t sudosrv_parse_query(TALLOC_CTX *mem_ctx,
- struct resp_ctx *rctx,
- uint8_t *query_body,
- size_t query_len,
- uid_t *_uid,
- char **_username,
- struct sss_domain_info **_domain);
+struct tevent_req *sudosrv_parse_query_send(TALLOC_CTX *mem_ctx,
+ struct resp_ctx *rctx,
+ uint8_t *query_body,
+ size_t query_len);
+
+errno_t sudosrv_parse_query_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ uid_t *_uid,
+ char **_username,
+ struct sss_domain_info **_domain);
errno_t sudosrv_build_response(TALLOC_CTX *mem_ctx,
uint32_t error,
diff --git a/src/responder/sudo/sudosrv_query.c b/src/responder/sudo/sudosrv_query.c
index 824f682c..d76ecbb9 100644
--- a/src/responder/sudo/sudosrv_query.c
+++ b/src/responder/sudo/sudosrv_query.c
@@ -22,6 +22,7 @@
#include <stdint.h>
#include <errno.h>
#include <talloc.h>
+#include <tevent.h>
#include "util/util.h"
#include "responder/sudo/sudosrv_private.h"
@@ -250,34 +251,38 @@ fail:
return ret;
}
-/*
- * Query format:
- * <uid><username[@domain]>
- */
-errno_t sudosrv_parse_query(TALLOC_CTX *mem_ctx,
- struct resp_ctx *rctx,
- uint8_t *query_body,
- size_t query_len,
- uid_t *_uid,
- char **_username,
- struct sss_domain_info **_domain)
+struct sudosrv_parse_query_state {
+ struct resp_ctx *rctx;
+ uid_t uid;
+ char *rawname;
+};
+
+static void sudosrv_parse_query_done(struct tevent_req *subreq);
+
+struct tevent_req *sudosrv_parse_query_send(TALLOC_CTX *mem_ctx,
+ struct resp_ctx *rctx,
+ uint8_t *query_body,
+ size_t query_len)
{
- TALLOC_CTX *tmp_ctx = NULL;
- struct sss_domain_info *domain = NULL;
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct sudosrv_parse_query_state *state = NULL;
size_t offset = 0;
size_t rawname_len = 0;
char *rawname = NULL;
char *domainname = NULL;
- char *username = NULL;
- uid_t uid;
errno_t ret;
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
- return ENOMEM;
+ /* create request */
+ req = tevent_req_create(mem_ctx, &state,
+ struct sudosrv_parse_query_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, ("tevent_req_create() failed\n"));
+ return NULL;
}
+ state->rctx = rctx;
+
/* uid */
if (query_len < sizeof(uid_t)) {
@@ -285,7 +290,7 @@ errno_t sudosrv_parse_query(TALLOC_CTX *mem_ctx,
ret = EINVAL;
goto done;
}
- safealign_memcpy(&uid, query_body, sizeof(uid_t), &offset);
+ safealign_memcpy(&state->uid, query_body, sizeof(uid_t), &offset);
/* username[@domain] */
@@ -312,31 +317,112 @@ errno_t sudosrv_parse_query(TALLOC_CTX *mem_ctx,
/* parse username */
- ret = sss_parse_name_for_domains(tmp_ctx, rctx->domains,
- rctx->default_domain, rawname,
- &domainname, &username);
- if (ret != EOK) {
+ state->rawname = rawname;
+ ret = sss_parse_name_for_domains(state, rctx->domains,
+ rctx->default_domain, state->rawname,
+ &domainname, NULL);
+ if (ret == EAGAIN) {
+ DEBUG(SSSDBG_TRACE_FUNC, ("Domain [%s] not found, "
+ "sending subdomain request\n", domainname));
+
+ subreq = sss_dp_get_domains_send(state, rctx, true, domainname);
+ if (req == NULL) {
+ ret = ENOMEM;
+ } else {
+ tevent_req_set_callback(subreq, sudosrv_parse_query_done, req);
+ ret = EAGAIN;
+ }
+ goto done;
+ } else if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid name received [%s]\n", rawname));
goto done;
}
+ ret = EOK;
+
+done:
+ if (ret != EAGAIN) {
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, rctx->ev);
+ }
+
+ return req;
+}
+
+static void sudosrv_parse_query_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = NULL;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+
+ ret = sss_dp_get_domains_recv(subreq);
+ talloc_free(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ }
+
+ tevent_req_done(req);
+}
+
+errno_t sudosrv_parse_query_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ uid_t *_uid,
+ char **_username,
+ struct sss_domain_info **_domain)
+{
+ struct sudosrv_parse_query_state *state = NULL;
+ struct sss_domain_info *domain = NULL;
+ char *username = NULL;
+ char *domainname = NULL;
+ errno_t ret;
+
+ state = tevent_req_data(req, struct sudosrv_parse_query_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (state->rawname == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("No query specified?!\n"));
+ return EINVAL;
+ }
+
+ /* Try to parse username@domain again because if the first call
+ * returned EAGAIN, then username is unset. If we get EAGAIN again,
+ * we will not search for it again.
+ */
+ ret = sss_parse_name_for_domains(state, state->rctx->domains,
+ state->rctx->default_domain,
+ state->rawname,
+ &domainname, &username);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC, ("Unable to parse domain [%d]: %s\n",
+ ret, strerror(ret)));
+ return ret;
+ }
+
+ if (username == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("No username specified!\n"));
+ return EINVAL;
+ }
+
if (domainname != NULL) {
/* mem_ctx because it duplicates only subdomains not domains
* so I cannot easily steal it */
- domain = responder_get_domain(mem_ctx, rctx, domainname);
+ domain = responder_get_domain(mem_ctx, state->rctx, domainname);
if (domain == NULL) {
- ret = ENOENT;
- goto done;
+ DEBUG(SSSDBG_OP_FAILURE, ("Corresponding domain [%s] has not been "
+ "found\n", domainname));
+ return ENOENT;
}
}
- *_uid = uid;
+ *_uid = state->uid;
*_username = talloc_steal(mem_ctx, username);
*_domain = domain; /* do not steal on mem_ctx */
- ret = EOK;
-
-done:
- talloc_free(tmp_ctx);
- return ret;
+ return EOK;
}