From 7e315b08152b1340511d4f6211d524482107e481 Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Tue, 30 Oct 2012 12:01:51 +0100 Subject: sudo: support users from subdomains https://fedorahosted.org/sssd/ticket/1616 --- src/responder/sudo/sudosrv_query.c | 152 +++++++++++++++++++++++++++++-------- 1 file changed, 119 insertions(+), 33 deletions(-) (limited to 'src/responder/sudo/sudosrv_query.c') diff --git a/src/responder/sudo/sudosrv_query.c b/src/responder/sudo/sudosrv_query.c index 824f682c6..d76ecbb9d 100644 --- a/src/responder/sudo/sudosrv_query.c +++ b/src/responder/sudo/sudosrv_query.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "util/util.h" #include "responder/sudo/sudosrv_private.h" @@ -250,34 +251,38 @@ fail: return ret; } -/* - * Query format: - * - */ -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; } -- cgit