summaryrefslogtreecommitdiffstats
path: root/src/responder/sudo/sudosrv_query.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/responder/sudo/sudosrv_query.c')
-rw-r--r--src/responder/sudo/sudosrv_query.c152
1 files changed, 119 insertions, 33 deletions
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 <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;
}