From d2683e473f14e7ad5b8ececcf25ffaa11b299c76 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 13 Apr 2012 09:50:55 +0200
Subject: [PATCH 2/6] sudo responder: remove code duplication in commands

---
 src/responder/sudo/sudosrv_cmd.c           |  210 +++++++++++---------------
 src/responder/sudo/sudosrv_get_sudorules.c |   78 ----------
 src/responder/sudo/sudosrv_private.h       |   48 ++-----
 src/responder/sudo/sudosrv_query.c         |  223 +++++++++++++++++++++++-----
 4 files changed, 282 insertions(+), 277 deletions(-)

diff --git a/src/responder/sudo/sudosrv_cmd.c b/src/responder/sudo/sudosrv_cmd.c
index e3dd384..bb9e89e 100644
--- a/src/responder/sudo/sudosrv_cmd.c
+++ b/src/responder/sudo/sudosrv_cmd.c
@@ -78,8 +78,14 @@ static errno_t sudosrv_cmd_send_error(TALLOC_CTX *mem_ctx,
     size_t response_len = 0;
     int ret = EOK;
 
-    ret = sudosrv_response_append_uint32(mem_ctx, error,
-                                         &response_body, &response_len);
+    if (error == EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("Everything is fine but we are "
+              "returning error?\n"));
+        return EFAULT;
+    }
+
+    ret = sudosrv_build_response(mem_ctx, error, 0, NULL,
+                                 &response_body, &response_len);
     if (ret != EOK) {
         return ret;
     }
@@ -113,9 +119,9 @@ errno_t sudosrv_cmd_done(struct sudo_dom_ctx *dctx, int ret)
         }
 
         /* send result */
-        ret = sudosrv_get_sudorules_build_response(dctx->cmd_ctx, SSS_SUDO_ERROR_OK,
-                                                   num_rules, rules,
-                                                   &response_body, &response_len);
+        ret = sudosrv_build_response(dctx->cmd_ctx, SSS_SUDO_ERROR_OK,
+                                     num_rules, rules,
+                                     &response_body, &response_len);
         if (ret != EOK) {
             return EFAULT;
         }
@@ -152,15 +158,13 @@ errno_t sudosrv_cmd_done(struct sudo_dom_ctx *dctx, int ret)
     return EOK;
 }
 
-static int sudosrv_cmd_get_sudorules(struct cli_ctx *cli_ctx)
+static int sudosrv_cmd(enum sss_dp_sudo_type type, struct cli_ctx *cli_ctx)
 {
-    char *rawname = NULL;
-    char *domname = NULL;
+    struct sudo_cmd_ctx *cmd_ctx = NULL;
+    struct sudo_dom_ctx *dctx = NULL;
     uint8_t *query_body = NULL;
     size_t query_len = 0;
     int ret = EOK;
-    struct sudo_cmd_ctx *cmd_ctx = NULL;
-    struct sudo_dom_ctx *dctx = NULL;
 
     cmd_ctx = talloc_zero(cli_ctx, struct sudo_cmd_ctx);
     if (!cmd_ctx) {
@@ -169,12 +173,15 @@ static int sudosrv_cmd_get_sudorules(struct cli_ctx *cli_ctx)
         return ENOMEM;
     }
     cmd_ctx->cli_ctx = cli_ctx;
-    cmd_ctx->type = SSS_DP_SUDO_USER;
+    cmd_ctx->type = type;
+    cmd_ctx->username = NULL;
+    cmd_ctx->check_next = false;
 
     /* get responder ctx */
     cmd_ctx->sudo_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct sudo_ctx);
     if (!cmd_ctx->sudo_ctx) {
         DEBUG(SSSDBG_FATAL_FAILURE, ("sudo_ctx not set, killing connection!\n"));
+        talloc_free(cmd_ctx);
         return EFAULT;
     }
 
@@ -187,136 +194,91 @@ static int sudosrv_cmd_get_sudorules(struct cli_ctx *cli_ctx)
     dctx->orig_username = NULL;
     dctx->cased_username = NULL;
 
-    /* get query */
-    sss_packet_get_body(cli_ctx->creq->in, &query_body, &query_len);
-    if (query_len <= 0 || query_body == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, ("Query is empty\n"));
-        ret = EINVAL;
-        goto done;
-    }
+    switch (cmd_ctx->type) {
+    case SSS_DP_SUDO_USER:
+        /* get query */
+        sss_packet_get_body(cli_ctx->creq->in, &query_body, &query_len);
+        if (query_len <= 0 || query_body == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Query is empty\n"));
+            ret = EINVAL;
+            goto done;
+        }
 
-    /* If the body isn't valid UTF-8, fail */
-    if (!sss_utf8_check(query_body, query_len - 1)) {
-        DEBUG(SSSDBG_CRIT_FAILURE, ("Supplied data is not valid UTF-8 string\n"));
-        ret = EINVAL;
-        goto done;
-    }
+        ret = sudosrv_parse_query(cmd_ctx, cli_ctx->rctx->domains,
+                                  cli_ctx->rctx->names, query_body, query_len,
+                                  &cmd_ctx->username, &dctx->domain);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid query: %s\n", strerror(ret)));
+            goto done;
+        }
 
-    /* parse query */
-    rawname = sudosrv_get_sudorules_parse_query(cmd_ctx,
-                                                (const char*)query_body,
-                                                 query_len);
-    if (rawname == NULL) {
-        ret = ENOMEM;
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              ("Unable to parse query: %s\n", strerror(ret)));
-        goto done;
-    }
+        DEBUG(SSSDBG_FUNC_DATA, ("Requesting sudo rules for [%s] from [%s]\n",
+              cmd_ctx->username, dctx->domain ? dctx->domain->name : "<ALL>"));
 
-    domname = NULL;
-    ret = sss_parse_name(cmd_ctx, cli_ctx->rctx->names, rawname,
-                         &domname, &cmd_ctx->username);
-    if (ret != EOK) {
-        DEBUG(2, ("Invalid name received [%s]\n", rawname));
-        ret = ENOENT;
-        goto done;
-    }
+        if (dctx->domain == NULL) {
+            /* this is a multidomain search */
+            dctx->domain = cli_ctx->rctx->domains;
+            cmd_ctx->check_next = true;
+        }
+
+        /* try to find rules in in-memory cache */
+        ret = sudosrv_cache_lookup(cmd_ctx->sudo_ctx->cache, dctx,
+                                   cmd_ctx->check_next, cmd_ctx->username,
+                                   &dctx->res_count, &dctx->res);
+        if (ret == EOK) {
+            /* cache hit */
+            DEBUG(SSSDBG_FUNC_DATA, ("Returning rules for [%s@%s] "
+                  "from in-memory cache\n", cmd_ctx->username, dctx->domain->name));
+        } else if (ret == ENOENT) {
+            /* cache expired or missed */
+            ret = sudosrv_get_sudorules(dctx);
+        } /* else error */
 
-    DEBUG(SSSDBG_FUNC_DATA, ("Requesting sudo rules for [%s] from [%s]\n",
-          cmd_ctx->username, domname ? domname : "<ALL>"));
+        break;
+    case SSS_DP_SUDO_DEFAULTS:
+        DEBUG(SSSDBG_FUNC_DATA, ("Requesting cn=defaults\n"));
 
-    if (domname) {
-        dctx->domain = responder_get_domain(cli_ctx->rctx->domains, domname);
+        /* sudo currently does not support domain selection
+         * so find first available domain
+         * TODO - support domain selection */
+        dctx->domain = cli_ctx->rctx->domains;
+        while (dctx->domain && dctx->domain->fqnames) {
+            dctx->domain = dctx->domain->next;
+        }
         if (!dctx->domain) {
+            DEBUG(SSSDBG_MINOR_FAILURE, ("No valid domain found\n"));
             ret = ENOENT;
             goto done;
         }
-    } else {
-        /* this is a multidomain search */
-        dctx->domain = cli_ctx->rctx->domains;
-        cmd_ctx->check_next = true;
-    }
 
-    /* try to find rules in in-memory cache */
-    ret = sudosrv_cache_lookup(cmd_ctx->sudo_ctx->cache, dctx,
-                               cmd_ctx->check_next, cmd_ctx->username,
-                               &dctx->res_count, &dctx->res);
-    if (ret == EOK) {
-        /* cache hit */
-        DEBUG(SSSDBG_FUNC_DATA, ("Returning rules for [%s@%s] "
-              "from in-memory cache\n", cmd_ctx->username, dctx->domain->name));
-    } else if (ret == ENOENT) {
-        /* cache expired or missed */
-        ret = sudosrv_get_sudorules(dctx);
-    } /* else error */
+        ret = sudosrv_cache_lookup(cmd_ctx->sudo_ctx->cache, dctx,
+                                       cmd_ctx->check_next, cmd_ctx->username,
+                                       &dctx->res_count, &dctx->res);
+
+        if (ret == EOK) {
+            /* cache hit */
+            DEBUG(SSSDBG_FUNC_DATA, ("Returning defaults settings for [%s] "
+                                     "from in-memory cache\n", dctx->domain->name));
+        } else if (ret == ENOENT) {
+            /* cache expired or missed */
+            ret = sudosrv_get_rules(dctx);
+        } /* else error */
+
+        break;
+    }
 
 done:
     return sudosrv_cmd_done(dctx, ret);
 }
 
-static int sudosrv_cmd_get_defaults(struct cli_ctx *cli_ctx)
+static int sudosrv_cmd_get_sudorules(struct cli_ctx *cli_ctx)
 {
-    int ret = EOK;
-    struct sudo_cmd_ctx *cmd_ctx = NULL;
-    struct sudo_dom_ctx *dctx = NULL;
-
-    cmd_ctx = talloc_zero(cli_ctx, struct sudo_cmd_ctx);
-    if (!cmd_ctx) {
-        /* kill the connection here as we have no context for reply */
-        DEBUG(SSSDBG_FATAL_FAILURE, ("Out of memory?\n"));
-        return ENOMEM;
-    }
-    cmd_ctx->cli_ctx = cli_ctx;
-    cmd_ctx->type = SSS_DP_SUDO_DEFAULTS;
-    cmd_ctx->username = NULL;
-    cmd_ctx->check_next = false;
-
-    /* get responder ctx */
-    cmd_ctx->sudo_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct sudo_ctx);
-    if (!cmd_ctx->sudo_ctx) {
-        DEBUG(SSSDBG_FATAL_FAILURE, ("sudo_ctx not set, killing connection!\n"));
-        return EFAULT;
-    }
-
-    /* create domain ctx */
-    dctx = talloc_zero(cmd_ctx, struct sudo_dom_ctx);
-    if (!dctx) {
-        return sudosrv_cmd_send_error(cmd_ctx, cmd_ctx, ENOMEM);
-    }
-    dctx->cmd_ctx = cmd_ctx;
-    dctx->orig_username = NULL;
-    dctx->cased_username = NULL;
-
-    DEBUG(SSSDBG_FUNC_DATA, ("Requesting cn=defaults\n"));
-
-    /* sudo currently does not support domain selection
-     * so find first available domain
-     * TODO - support domain selection */
-    dctx->domain = cli_ctx->rctx->domains;
-    while (dctx->domain && dctx->domain->fqnames) {
-        dctx->domain = dctx->domain->next;
-    }
-    if (!dctx->domain) {
-        DEBUG(SSSDBG_MINOR_FAILURE, ("No valid domain found\n"));
-        ret = ENOENT;
-        goto done;
-    }
-
-    /* try to find rules in in-memory cache */
-    ret = sudosrv_cache_lookup(cmd_ctx->sudo_ctx->cache, dctx,
-                               cmd_ctx->check_next, cmd_ctx->username,
-                               &dctx->res_count, &dctx->res);
-    if (ret == EOK) {
-        /* cache hit */
-        DEBUG(SSSDBG_FUNC_DATA, ("Returning defaults settings for [%s] "
-                                 "from in-memory cache\n", dctx->domain->name));
-    } else if (ret == ENOENT) {
-        /* cache expired or missed */
-        ret = sudosrv_get_rules(dctx);
-    } /* else error */
+    return sudosrv_cmd(SSS_DP_SUDO_USER, cli_ctx);
+}
 
-done:
-    return sudosrv_cmd_done(dctx, ret);
+static int sudosrv_cmd_get_defaults(struct cli_ctx *cli_ctx)
+{
+    return sudosrv_cmd(SSS_DP_SUDO_DEFAULTS, cli_ctx);
 }
 
 struct cli_protocol_version *register_cli_protocol_version(void)
diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c
index abdf3e7..e92e807 100644
--- a/src/responder/sudo/sudosrv_get_sudorules.c
+++ b/src/responder/sudo/sudosrv_get_sudorules.c
@@ -602,81 +602,3 @@ sort_sudo_rules(struct sysdb_attrs **rules, size_t count)
           sudo_order_cmp_fn);
     return EOK;
 }
-
-char * sudosrv_get_sudorules_parse_query(TALLOC_CTX *mem_ctx,
-                                         const char *query_body,
-                                         int query_len)
-{
-    /* empty string or not NULL terminated */
-    if (query_len < 2 || strnlen(query_body, query_len) == query_len) {
-        DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid query.\n"));
-        return NULL;
-    }
-
-    return talloc_strdup(mem_ctx, query_body);
-}
-
-/*
- * Response format:
- * <error_code(uint32_t)><num_entries(uint32_t)><rule1><rule2>...
- * <ruleN> = <num_attrs(uint32_t)><attr1><attr2>...
- * <attrN>  = <name(char*)>\0<num_values(uint32_t)><value1(char*)>\0<value2(char*)>\0...
- *
- * if <error_code> is not SSS_SUDO_ERROR_OK, the rest of the data is skipped.
- */
-int sudosrv_get_sudorules_build_response(TALLOC_CTX *mem_ctx,
-                                         uint32_t error,
-                                         int rules_num,
-                                         struct sysdb_attrs **rules,
-                                         uint8_t **_response_body,
-                                         size_t *_response_len)
-{
-    uint8_t *response_body = NULL;
-    size_t response_len = 0;
-    TALLOC_CTX *tmp_ctx = NULL;
-    int i = 0;
-    int ret = EOK;
-
-    tmp_ctx = talloc_new(NULL);
-    if (tmp_ctx == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
-        return ENOMEM;
-    }
-
-    /* error code */
-    ret = sudosrv_response_append_uint32(tmp_ctx, error,
-                                         &response_body, &response_len);
-    if (ret != EOK) {
-        goto fail;
-    }
-
-    if (error != SSS_SUDO_ERROR_OK) {
-        goto done;
-    }
-
-    /* rules count */
-    ret = sudosrv_response_append_uint32(tmp_ctx, (uint32_t)rules_num,
-                                         &response_body, &response_len);
-    if (ret != EOK) {
-        goto fail;
-    }
-
-    /* rules */
-    for (i = 0; i < rules_num; i++) {
-        ret = sudosrv_response_append_rule(tmp_ctx, rules[i]->num, rules[i]->a,
-                                           &response_body, &response_len);
-        if (ret != EOK) {
-            goto fail;
-        }
-    }
-
-done:
-    *_response_body = talloc_steal(mem_ctx, response_body);
-    *_response_len = response_len;
-
-    ret = EOK;
-
-fail:
-    talloc_free(tmp_ctx);
-    return ret;
-}
diff --git a/src/responder/sudo/sudosrv_private.h b/src/responder/sudo/sudosrv_private.h
index fd96ba9..e83532e 100644
--- a/src/responder/sudo/sudosrv_private.h
+++ b/src/responder/sudo/sudosrv_private.h
@@ -86,40 +86,20 @@ errno_t sudosrv_get_sudorules(struct sudo_dom_ctx *dctx);
 
 errno_t sudosrv_get_rules(struct sudo_dom_ctx *dctx);
 
-char * sudosrv_get_sudorules_parse_query(TALLOC_CTX *mem_ctx,
-                                         const char *query_body,
-                                         int query_len);
-
-int sudosrv_get_sudorules_build_response(TALLOC_CTX *mem_ctx,
-                                         uint32_t error,
-                                         int rules_num,
-                                         struct sysdb_attrs **rules,
-                                         uint8_t **_response_body,
-                                         size_t *_response_len);
-
-int sudosrv_response_append_string(TALLOC_CTX *mem_ctx,
-                                   const char *str,
-                                   size_t str_len,
-                                   uint8_t **_response_body,
-                                   size_t *_response_len);
-
-int sudosrv_response_append_uint32(TALLOC_CTX *mem_ctx,
-                                   uint32_t number,
-                                   uint8_t **_response_body,
-                                   size_t *_response_len);
-
-int sudosrv_response_append_rule(TALLOC_CTX *mem_ctx,
-                                 int attrs_num,
-                                 struct ldb_message_element *attrs,
-                                 uint8_t **_response_body,
-                                 size_t *_response_len);
-
-int sudosrv_response_append_attr(TALLOC_CTX *mem_ctx,
-                                 const char *name,
-                                 unsigned int values_num,
-                                 struct ldb_val *values,
-                                 uint8_t **_response_body,
-                                 size_t *_response_len);
+errno_t sudosrv_parse_query(TALLOC_CTX *mem_ctx,
+                            struct sss_domain_info *domains,
+                            struct sss_names_ctx *names_ctx,
+                            uint8_t *query_body,
+                            size_t query_len,
+                            char **_username,
+                            struct sss_domain_info **_domain);
+
+errno_t sudosrv_build_response(TALLOC_CTX *mem_ctx,
+                               uint32_t error,
+                               int rules_num,
+                               struct sysdb_attrs **rules,
+                               uint8_t **_response_body,
+                               size_t *_response_len);
 
 struct tevent_req *
 sss_dp_get_sudoers_send(TALLOC_CTX *mem_ctx,
diff --git a/src/responder/sudo/sudosrv_query.c b/src/responder/sudo/sudosrv_query.c
index 8b98da6..e6df973 100644
--- a/src/responder/sudo/sudosrv_query.c
+++ b/src/responder/sudo/sudosrv_query.c
@@ -26,11 +26,11 @@
 #include "util/util.h"
 #include "responder/sudo/sudosrv_private.h"
 
-int sudosrv_response_append_string(TALLOC_CTX *mem_ctx,
-                                   const char *str,
-                                   size_t str_len,
-                                   uint8_t **_response_body,
-                                   size_t *_response_len)
+static int sudosrv_response_append_string(TALLOC_CTX *mem_ctx,
+                                          const char *str,
+                                          size_t str_len,
+                                          uint8_t **_response_body,
+                                          size_t *_response_len)
 {
     size_t response_len = *_response_len;
     uint8_t *response_body = *_response_body;
@@ -50,10 +50,10 @@ int sudosrv_response_append_string(TALLOC_CTX *mem_ctx,
     return EOK;
 }
 
-int sudosrv_response_append_uint32(TALLOC_CTX *mem_ctx,
-                                   uint32_t number,
-                                   uint8_t **_response_body,
-                                   size_t *_response_len)
+static int sudosrv_response_append_uint32(TALLOC_CTX *mem_ctx,
+                                          uint32_t number,
+                                          uint8_t **_response_body,
+                                          size_t *_response_len)
 {
     size_t response_len = *_response_len;
     uint8_t *response_body = *_response_body;
@@ -72,11 +72,71 @@ int sudosrv_response_append_uint32(TALLOC_CTX *mem_ctx,
     return EOK;
 }
 
-int sudosrv_response_append_rule(TALLOC_CTX *mem_ctx,
-                                 int attrs_num,
-                                 struct ldb_message_element *attrs,
-                                 uint8_t **_response_body,
-                                 size_t *_response_len)
+static int sudosrv_response_append_attr(TALLOC_CTX *mem_ctx,
+                                        const char *name,
+                                        unsigned int values_num,
+                                        struct ldb_val *values,
+                                        uint8_t **_response_body,
+                                        size_t *_response_len)
+{
+    uint8_t *response_body = *_response_body;
+    size_t response_len = *_response_len;
+    TALLOC_CTX *tmp_ctx = NULL;
+    int i = 0;
+    int ret = EOK;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
+        return ENOMEM;
+    }
+
+    /* attr name */
+    ret = sudosrv_response_append_string(tmp_ctx, name, strlen(name) + 1,
+                                         &response_body, &response_len);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* values count */
+    ret = sudosrv_response_append_uint32(tmp_ctx, values_num,
+                                         &response_body, &response_len);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* values */
+    for (i = 0; i < values_num; i++) {
+        if (strlen((char*)(values[i].data)) != values[i].length) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("value is not a string"));
+            ret = EINVAL;
+            goto done;
+        }
+
+        ret = sudosrv_response_append_string(tmp_ctx,
+                                             (const char*)values[i].data,
+                                             values[i].length + 1,
+                                             &response_body, &response_len);
+        if (ret != EOK) {
+            goto done;
+        }
+    }
+
+    *_response_body = talloc_steal(mem_ctx, response_body);
+    *_response_len = response_len;
+
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+static int sudosrv_response_append_rule(TALLOC_CTX *mem_ctx,
+                                        int attrs_num,
+                                        struct ldb_message_element *attrs,
+                                        uint8_t **_response_body,
+                                        size_t *_response_len)
 {
     uint8_t *response_body = *_response_body;
     size_t response_len = *_response_len;
@@ -117,18 +177,26 @@ done:
     return ret;
 }
 
-int sudosrv_response_append_attr(TALLOC_CTX *mem_ctx,
-                                 const char *name,
-                                 unsigned int values_num,
-                                 struct ldb_val *values,
-                                 uint8_t **_response_body,
-                                 size_t *_response_len)
+/*
+ * Response format:
+ * <error_code(uint32_t)><num_entries(uint32_t)><rule1><rule2>...
+ * <ruleN> = <num_attrs(uint32_t)><attr1><attr2>...
+ * <attrN>  = <name(char*)>\0<num_values(uint32_t)><value1(char*)>\0<value2(char*)>\0...
+ *
+ * if <error_code> is not SSS_SUDO_ERROR_OK, the rest of the data is skipped.
+ */
+errno_t sudosrv_build_response(TALLOC_CTX *mem_ctx,
+                               uint32_t error,
+                               int rules_num,
+                               struct sysdb_attrs **rules,
+                               uint8_t **_response_body,
+                               size_t *_response_len)
 {
-    uint8_t *response_body = *_response_body;
-    size_t response_len = *_response_len;
+    uint8_t *response_body = NULL;
+    size_t response_len = 0;
     TALLOC_CTX *tmp_ctx = NULL;
     int i = 0;
-    int ret = EOK;
+    errno_t ret = EOK;
 
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
@@ -136,42 +204,115 @@ int sudosrv_response_append_attr(TALLOC_CTX *mem_ctx,
         return ENOMEM;
     }
 
-    /* attr name */
-    ret = sudosrv_response_append_string(tmp_ctx, name, strlen(name) + 1,
+    /* error code */
+    ret = sudosrv_response_append_uint32(tmp_ctx, error,
                                          &response_body, &response_len);
     if (ret != EOK) {
+        goto fail;
+    }
+
+    if (error != SSS_SUDO_ERROR_OK) {
         goto done;
     }
 
-    /* values count */
-    ret = sudosrv_response_append_uint32(tmp_ctx, values_num,
+    /* rules count */
+    ret = sudosrv_response_append_uint32(tmp_ctx, (uint32_t)rules_num,
                                          &response_body, &response_len);
     if (ret != EOK) {
-        goto done;
+        goto fail;
     }
 
-    /* values */
-    for (i = 0; i < values_num; i++) {
-        if (strlen((char*)(values[i].data)) != values[i].length) {
-            DEBUG(SSSDBG_CRIT_FAILURE, ("value is not a string"));
-            ret = EINVAL;
-            goto done;
-        }
-
-        ret = sudosrv_response_append_string(tmp_ctx,
-                                             (const char*)values[i].data,
-                                             values[i].length + 1,
-                                             &response_body, &response_len);
+    /* rules */
+    for (i = 0; i < rules_num; i++) {
+        ret = sudosrv_response_append_rule(tmp_ctx, rules[i]->num, rules[i]->a,
+                                           &response_body, &response_len);
         if (ret != EOK) {
-            goto done;
+            goto fail;
         }
     }
 
+done:
     *_response_body = talloc_steal(mem_ctx, response_body);
     *_response_len = response_len;
 
     ret = EOK;
 
+fail:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+/*
+ * Query format:
+ * <username[@domain]>
+ */
+errno_t sudosrv_parse_query(TALLOC_CTX *mem_ctx,
+                            struct sss_domain_info *domains,
+                            struct sss_names_ctx *names_ctx,
+                            uint8_t *query_body,
+                            size_t query_len,
+                            char **_username,
+                            struct sss_domain_info **_domain)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    struct sss_domain_info *domain = NULL;
+    size_t offset = 0;
+    size_t rawname_len = 0;
+    char *rawname = NULL;
+    char *domainname = NULL;
+    char *username = NULL;
+    errno_t ret;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
+        return ENOMEM;
+    }
+
+    /* username[@domain] */
+
+    rawname = (char*)(query_body + offset);
+    rawname_len = query_len - offset; /* strlen + zero */
+
+    if (rawname[rawname_len - 1] != '\0') {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Username is not zero terminated\n"));
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (rawname_len < 2) { /* at least one character and zero */
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Query does not contain username\n"));
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (!sss_utf8_check((uint8_t*)rawname, rawname_len - 1)) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Supplied data is not valid UTF-8 string\n"));
+        ret = EINVAL;
+        goto done;
+    }
+
+    /* parse username */
+
+    ret = sss_parse_name(tmp_ctx, names_ctx, rawname, &domainname, &username);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid name received [%s]\n", rawname));
+        goto done;
+    }
+
+    if (domainname != NULL) {
+        domain = responder_get_domain(domains, domainname);
+        if (domain == NULL) {
+            ret = ENOENT;
+            goto done;
+        }
+    }
+
+    *_username = talloc_steal(mem_ctx, username);
+    *_domain = domain; /* do not steal on mem_ctx */
+
+    ret = EOK;
+
 done:
     talloc_free(tmp_ctx);
     return ret;
-- 
1.7.6.5

