From 710472d946f6c337a095699dfd79134fa8b9eab9 Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Fri, 13 Apr 2012 09:50:55 +0200 Subject: 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 | 47 ++---- src/responder/sudo/sudosrv_query.c | 225 +++++++++++++++++++++++------ 4 files changed, 283 insertions(+), 277 deletions(-) (limited to 'src/responder') diff --git a/src/responder/sudo/sudosrv_cmd.c b/src/responder/sudo/sudosrv_cmd.c index f72e2be7b..8179ec0bd 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, + 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 : "")); - domname = NULL; - ret = sss_parse_name_for_domains(cmd_ctx, cli_ctx->rctx->domains, 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 : "")); + break; + case SSS_DP_SUDO_DEFAULTS: + DEBUG(SSSDBG_FUNC_DATA, ("Requesting cn=defaults\n")); - if (domname) { - dctx->domain = responder_get_domain(dctx, cli_ctx->rctx, 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 abdf3e76f..e92e807f8 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: - * ... - * = ... - * = \0\0\0... - * - * if 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 fd96ba9a8..03cc0a48c 100644 --- a/src/responder/sudo/sudosrv_private.h +++ b/src/responder/sudo/sudosrv_private.h @@ -86,40 +86,19 @@ 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 resp_ctx *rctx, + 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 8b98da6e8..dd9e1e880 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: + * ... + * = ... + * = \0\0\0... + * + * if 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,117 @@ 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: + * + */ +errno_t sudosrv_parse_query(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + 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_for_domains(tmp_ctx, rctx->domains, rawname, + &domainname, &username); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid name received [%s]\n", rawname)); + goto done; + } + + 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); + 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; -- cgit