https://fedorahosted.org/sssd/ticket/1616
There where three main issues. 1. sssd_sudo didn't support subdomains at all 2. sudo sends two request - for default options and for rules We match user with domain in default options request and send the domain name back to sudo. Sudo sends it back to us in the form "user@domain" in rules request. If the username already contains domain name (subdomain case), sudo sent us "user@domain@domain". I fixed this by changing the protocol. Sudo sends user and domain separately now. The old protocol is also supported, but a debug message is printed that it will not work with subdomains. 3. subdomain users are stored in cn=subdomain,cn=sysdb, but rules are stored in cn=ipadomain,cn=sysdb. I'm using subdomain sysdb context for user lookups and ipadomain sysdb context for rules lookups. [PATCH 1/6] fix missing parameter in two debug messages [PATCH 2/6] use tmp_ctx in sudosrv_get_sudorules_from_cache() [PATCH 3/6] solves 1 and 3 [PATCH 4/6] solves 2 [PATCH 5/6] bumps libsss_sudo version [PATCH 6/6] adds useful debugging info
From 724ebcafa2d4e54df048ca2a578b03281fb7fe6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com> Date: Fri, 9 Nov 2012 13:31:52 +0100 Subject: [PATCH 1/6] sudo: fix missing parameter in two debug messages --- src/responder/sudo/sudosrv_get_sudorules.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c index b6e016c73cba6c86b9f20af63357c6fcc2b5508b..0e0437622e94a234b1597bcd272633f6944d4762 100644 --- a/src/responder/sudo/sudosrv_get_sudorules.c +++ b/src/responder/sudo/sudosrv_get_sudorules.c @@ -369,7 +369,7 @@ errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx) NULL, &groupnames); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, - ("Unable to retrieve user info [%d]: %s\n", strerror(ret))); + ("Unable to retrieve user info [%d]: %s\n", ret, strerror(ret))); goto done; } -- 1.7.11.7
From 82c23b34f3c0ac50358467080d0668e3fa0a434d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com> Date: Wed, 7 Nov 2012 18:24:46 +0100 Subject: [PATCH 2/6] use tmp_ctx in sudosrv_get_sudorules_from_cache() --- src/responder/sudo/sudosrv_get_sudorules.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c index 0e0437622e94a234b1597bcd272633f6944d4762..61e94cc243ea3ac4cd284a0ec3c52f142dcf384d 100644 --- a/src/responder/sudo/sudosrv_get_sudorules.c +++ b/src/responder/sudo/sudosrv_get_sudorules.c @@ -301,7 +301,9 @@ done: sudosrv_cmd_done(dctx->cmd_ctx, ret); } -static errno_t sudosrv_get_sudorules_from_cache(struct sudo_cmd_ctx *cmd_ctx, +static errno_t sudosrv_get_sudorules_from_cache(TALLOC_CTX *mem_ctx, + struct sudo_cmd_ctx *cmd_ctx, + struct sysdb_attrs ***_rules, size_t *_num_rules); static void sudosrv_get_sudorules_dp_callback(uint16_t err_maj, uint32_t err_min, @@ -421,7 +423,9 @@ errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx) } else { /* nothing is expired return what we have in the cache */ DEBUG(SSSDBG_TRACE_INTERNAL, ("About to get sudo rules from cache\n")); - ret = sudosrv_get_sudorules_from_cache(cmd_ctx, NULL); + ret = sudosrv_get_sudorules_from_cache(cmd_ctx, cmd_ctx, + &cmd_ctx->rules, + &cmd_ctx->num_rules); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to make a request to our cache [%d]: %s\n", @@ -482,7 +486,6 @@ sudosrv_get_sudorules_dp_callback(uint16_t err_maj, uint32_t err_min, struct sudo_cmd_ctx *cmd_ctx = talloc_get_type(ptr, struct sudo_cmd_ctx); struct tevent_req *dpreq = NULL; errno_t ret; - size_t num_rules; if (err_maj) { DEBUG(SSSDBG_CRIT_FAILURE, @@ -493,7 +496,8 @@ sudosrv_get_sudorules_dp_callback(uint16_t err_maj, uint32_t err_min, } DEBUG(SSSDBG_TRACE_INTERNAL, ("About to get sudo rules from cache\n")); - ret = sudosrv_get_sudorules_from_cache(cmd_ctx, &num_rules); + ret = sudosrv_get_sudorules_from_cache(cmd_ctx, cmd_ctx, &cmd_ctx->rules, + &cmd_ctx->num_rules); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to make a request to our cache [%d]: %s\n", @@ -524,7 +528,9 @@ sudosrv_get_sudorules_dp_callback(uint16_t err_maj, uint32_t err_min, sudosrv_cmd_done(cmd_ctx, ret); } -static errno_t sudosrv_get_sudorules_from_cache(struct sudo_cmd_ctx *cmd_ctx, +static errno_t sudosrv_get_sudorules_from_cache(TALLOC_CTX *mem_ctx, + struct sudo_cmd_ctx *cmd_ctx, + struct sysdb_attrs ***_rules, size_t *_num_rules) { TALLOC_CTX *tmp_ctx; @@ -533,6 +539,8 @@ static errno_t sudosrv_get_sudorules_from_cache(struct sudo_cmd_ctx *cmd_ctx, char **groupnames = NULL; const char *debug_name = NULL; unsigned int flags = SYSDB_SUDO_FILTER_NONE; + struct sysdb_attrs **rules = NULL; + size_t num_rules = 0; const char *attrs[] = { SYSDB_OBJECTCLASS SYSDB_SUDO_CACHE_AT_CN, SYSDB_SUDO_CACHE_AT_USER, @@ -583,10 +591,10 @@ static errno_t sudosrv_get_sudorules_from_cache(struct sudo_cmd_ctx *cmd_ctx, break; } - ret = sudosrv_get_sudorules_query_cache(cmd_ctx, sysdb, cmd_ctx->type, + ret = sudosrv_get_sudorules_query_cache(tmp_ctx, sysdb, cmd_ctx->type, attrs, flags, cmd_ctx->orig_username, cmd_ctx->uid, groupnames, - &cmd_ctx->rules, &cmd_ctx->num_rules); + &rules, &num_rules); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to retrieve sudo rules [%d]: %s\n", strerror(ret))); @@ -596,8 +604,12 @@ static errno_t sudosrv_get_sudorules_from_cache(struct sudo_cmd_ctx *cmd_ctx, DEBUG(SSSDBG_TRACE_FUNC, ("Returning rules for [%s@%s]\n", debug_name, cmd_ctx->domain->name)); + if (_rules != NULL) { + *_rules = talloc_steal(mem_ctx, rules); + } + if (_num_rules != NULL) { - *_num_rules = cmd_ctx->num_rules; + *_num_rules = num_rules; } ret = EOK; -- 1.7.11.7
From efd77024665bf3162994f789e04acd6bbd105583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com> Date: Tue, 30 Oct 2012 12:01:51 +0100 Subject: [PATCH 3/6] sudo: support users from subdomains https://fedorahosted.org/sssd/ticket/1616 --- src/responder/sudo/sudosrv_cmd.c | 41 ++++++-- src/responder/sudo/sudosrv_get_sudorules.c | 64 +++++++++--- src/responder/sudo/sudosrv_private.h | 17 ++-- src/responder/sudo/sudosrv_query.c | 152 ++++++++++++++++++++++------- 4 files changed, 214 insertions(+), 60 deletions(-) diff --git a/src/responder/sudo/sudosrv_cmd.c b/src/responder/sudo/sudosrv_cmd.c index 9a87ed7d768b0bf35b1d1980895d08e4cf08d5f7..440c8c5da4a56105c1cb83fb6a7e8a79dd0c9289 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 61e94cc243ea3ac4cd284a0ec3c52f142dcf384d..e3fdd29dab4e8480c891dd642414fa307fc804c8 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, - ("sysdb context not found for this domain!\n")); + ("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; } @@ -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 55ea1383533188eaf8f3f731b24fe0cce3eb197d..b805940759f409ebd532707faf93d09dc3e51e04 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 824f682c6c753bc47f303af09f03363ad79af987..d76ecbb9deb7a59adaa319fc7ef4ddb5e3071f4c 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; } -- 1.7.11.7
From 89e0220796bb09b23df46cf240a0de27bfc44bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com> Date: Tue, 6 Nov 2012 14:57:56 +0100 Subject: [PATCH 4/6] sudo: allow fully qualified user name Part of: https://fedorahosted.org/sssd/ticket/1616 --- src/responder/sudo/sudosrv_cmd.c | 17 ++++++-- src/responder/sudo/sudosrv_private.h | 1 + src/responder/sudo/sudosrv_query.c | 81 +++++++++++++++++++++++++++++++++--- src/sss_client/sss_cli.h | 2 +- src/sss_client/sudo/sss_sudo.c | 64 +++++++++++++++++----------- 5 files changed, 130 insertions(+), 35 deletions(-) diff --git a/src/responder/sudo/sudosrv_cmd.c b/src/responder/sudo/sudosrv_cmd.c index 440c8c5da4a56105c1cb83fb6a7e8a79dd0c9289..8f6b432026d378a0ff98971d8afbd5a22443be83 100644 --- a/src/responder/sudo/sudosrv_cmd.c +++ b/src/responder/sudo/sudosrv_cmd.c @@ -164,6 +164,7 @@ static int sudosrv_cmd(enum sss_sudo_type type, struct cli_ctx *cli_ctx) struct sudo_cmd_ctx *cmd_ctx = NULL; uint8_t *query_body = NULL; size_t query_len = 0; + uint32_t protocol = cli_ctx->cli_protocol_version->version; errno_t ret; /* create cmd_ctx */ @@ -185,11 +186,18 @@ static int sudosrv_cmd(enum sss_sudo_type type, struct cli_ctx *cli_ctx) } /* if protocol is invalid return */ - if (cli_ctx->cli_protocol_version->version != SSS_SUDO_PROTOCOL_VERSION) { - DEBUG(SSSDBG_FATAL_FAILURE, ("Invalid protocol! [%d]\n", - cli_ctx->cli_protocol_version->version)); + switch (protocol) { + case 0: + DEBUG(SSSDBG_FATAL_FAILURE, ("Protocol [%d] is not secure. " + "SSSD does not allow to use this protocol.\n", protocol)); ret = EFAULT; goto done; + break; + case 1: + DEBUG(SSSDBG_MINOR_FAILURE, ("Protocol [%d] does not support fully" + "qualified user names. Users from subdomains will not be" + "allowed to use sudo.\n", protocol)); + break; } /* parse query */ @@ -201,7 +209,7 @@ static int sudosrv_cmd(enum sss_sudo_type type, struct cli_ctx *cli_ctx) goto done; } - req = sudosrv_parse_query_send(cmd_ctx, cli_ctx->rctx, + req = sudosrv_parse_query_send(cmd_ctx, protocol, cli_ctx->rctx, query_body, query_len); if (req == NULL) { ret = ENOMEM; @@ -278,6 +286,7 @@ static int sudosrv_cmd_get_defaults(struct cli_ctx *cli_ctx) struct cli_protocol_version *register_cli_protocol_version(void) { static struct cli_protocol_version sudo_cli_protocol_version[] = { + {2, "2012-11-06", "support fully qualified username"}, {1, "2012-05-14", "require uid and domain"}, {0, NULL, NULL} }; diff --git a/src/responder/sudo/sudosrv_private.h b/src/responder/sudo/sudosrv_private.h index b805940759f409ebd532707faf93d09dc3e51e04..d031ca0fdc8c90d8b2f34436b75edbac0e9f2746 100644 --- a/src/responder/sudo/sudosrv_private.h +++ b/src/responder/sudo/sudosrv_private.h @@ -91,6 +91,7 @@ errno_t sudosrv_get_sudorules(struct sudo_dom_ctx *dctx); errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx); struct tevent_req *sudosrv_parse_query_send(TALLOC_CTX *mem_ctx, + uint32_t protocol, struct resp_ctx *rctx, uint8_t *query_body, size_t query_len); diff --git a/src/responder/sudo/sudosrv_query.c b/src/responder/sudo/sudosrv_query.c index d76ecbb9deb7a59adaa319fc7ef4ddb5e3071f4c..d076c88601e12f7c10d6ad57c01d7a78ed1ddb09 100644 --- a/src/responder/sudo/sudosrv_query.c +++ b/src/responder/sudo/sudosrv_query.c @@ -255,11 +255,13 @@ struct sudosrv_parse_query_state { struct resp_ctx *rctx; uid_t uid; char *rawname; + char *query_domainname; }; static void sudosrv_parse_query_done(struct tevent_req *subreq); struct tevent_req *sudosrv_parse_query_send(TALLOC_CTX *mem_ctx, + uint32_t protocol, struct resp_ctx *rctx, uint8_t *query_body, size_t query_len) @@ -271,6 +273,8 @@ struct tevent_req *sudosrv_parse_query_send(TALLOC_CTX *mem_ctx, size_t rawname_len = 0; char *rawname = NULL; char *domainname = NULL; + size_t query_domainname_len = 0; + char *query_domainname = NULL; errno_t ret; /* create request */ @@ -283,19 +287,21 @@ struct tevent_req *sudosrv_parse_query_send(TALLOC_CTX *mem_ctx, state->rctx = rctx; - /* uid */ - - if (query_len < sizeof(uid_t)) { + if (query_len < sizeof(uid_t) + 2*sizeof(size_t)) { DEBUG(SSSDBG_CRIT_FAILURE, ("Query is too small\n")); ret = EINVAL; goto done; } + + /* uid */ + safealign_memcpy(&state->uid, query_body, sizeof(uid_t), &offset); - /* username[@domain] */ + /* username[@domain] (*/ + safealign_memcpy(&rawname_len, query_body + offset, sizeof(size_t), + &offset); 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")); @@ -315,7 +321,56 @@ struct tevent_req *sudosrv_parse_query_send(TALLOC_CTX *mem_ctx, goto done; } - /* parse username */ + state->rawname = talloc_strndup(state, rawname, rawname_len); + if (state->rawname == NULL) { + ret = ENOMEM; + goto done; + } + + offset += rawname_len; + + /* domainname */ + + if (protocol > 1) { + safealign_memcpy(&query_domainname_len, query_body + offset, + sizeof(size_t), &offset); + } + + if (query_domainname_len > 0) { + query_domainname = (char*)(query_body + offset); + + if (query_domainname[query_domainname_len - 1] != '\0') { + DEBUG(SSSDBG_CRIT_FAILURE, ("Username is not zero terminated\n")); + ret = EINVAL; + goto done; + } + + if (query_domainname_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*)query_domainname, + query_domainname_len - 1)) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Supplied data is not valid UTF-8 string\n")); + ret = EINVAL; + goto done; + } + + state->query_domainname = talloc_strndup(state, query_domainname, + query_domainname_len); + if (state->query_domainname == NULL) { + ret = ENOMEM; + goto done; + } + + offset += query_domainname_len; + } + + /* Try to parse username as fully qualified name. We will store the + * username later in _recv. */ state->rawname = rawname; ret = sss_parse_name_for_domains(state, rctx->domains, @@ -409,6 +464,20 @@ errno_t sudosrv_parse_query_recv(TALLOC_CTX *mem_ctx, return EINVAL; } + if (state->query_domainname != NULL) { + if (domainname == NULL) { + /* no domain was specified, + * we will use domain from previous request */ + domainname = state->query_domainname; + } else { + if (strcmp(domainname, state->query_domainname) != 0) { + DEBUG(SSSDBG_OP_FAILURE, ("Domain of previous request doesn't " + "match! [%s] [%s]\n", domain, state->query_domainname)); + return EFAULT; + } + } + } + if (domainname != NULL) { /* mem_ctx because it duplicates only subdomains not domains * so I cannot easily steal it */ diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h index 372bcee596a72e85d02516acdb10b775c4ddc2df..a21a10ed3841c4367a2cf1029ec97b4b48a6c602 100644 --- a/src/sss_client/sss_cli.h +++ b/src/sss_client/sss_cli.h @@ -44,7 +44,7 @@ typedef int errno_t; #define SSS_NSS_PROTOCOL_VERSION 1 #define SSS_PAM_PROTOCOL_VERSION 3 -#define SSS_SUDO_PROTOCOL_VERSION 1 +#define SSS_SUDO_PROTOCOL_VERSION 2 #define SSS_AUTOFS_PROTOCOL_VERSION 1 #define SSS_SSH_PROTOCOL_VERSION 0 #define SSS_PAC_PROTOCOL_VERSION 1 diff --git a/src/sss_client/sudo/sss_sudo.c b/src/sss_client/sudo/sss_sudo.c index e2bb3e00d123bfbfecef91ce2d01edaf7b7d1a76..daece9551f50b324ea59dec81e1d2c425540ca27 100644 --- a/src/sss_client/sudo/sss_sudo.c +++ b/src/sss_client/sudo/sss_sudo.c @@ -32,6 +32,7 @@ int sss_sudo_create_query(uid_t uid, const char *username, + const char *domainname, uint8_t **_query, size_t *_query_len); @@ -44,6 +45,7 @@ static void sss_sudo_free_attrs(unsigned int num_attrs, static int sss_sudo_send_recv_generic(enum sss_cli_command command, uid_t uid, const char *username, + const char *domainname, uint32_t *_error, char **_domainname, struct sss_sudo_result **_result) @@ -58,7 +60,8 @@ static int sss_sudo_send_recv_generic(enum sss_cli_command command, /* create query */ - ret = sss_sudo_create_query(uid, username, &query_buf, &query_len); + ret = sss_sudo_create_query(uid, username, domainname, + &query_buf, &query_len); if (ret != EOK) { goto done; } @@ -93,30 +96,14 @@ int sss_sudo_send_recv(uid_t uid, uint32_t *_error, struct sss_sudo_result **_result) { - char *fullname = NULL; int ret; if (username == NULL || strlen(username) == 0) { return EINVAL; } - if (domainname != NULL) { - ret = asprintf(&fullname, "%s@%s", username, domainname); - if (ret == -1) { - return ENOMEM; - } - } else { - fullname = strdup(username); - if (fullname == NULL) { - return ENOMEM; - } - } - - /* send query and receive response */ - - ret = sss_sudo_send_recv_generic(SSS_SUDO_GET_SUDORULES, uid, fullname, - _error, NULL, _result); - free(fullname); + ret = sss_sudo_send_recv_generic(SSS_SUDO_GET_SUDORULES, uid, username, + domainname, _error, NULL, _result); return ret; } @@ -131,24 +118,53 @@ int sss_sudo_send_recv_defaults(uid_t uid, } return sss_sudo_send_recv_generic(SSS_SUDO_GET_DEFAULTS, uid, username, - _error, _domainname, _result); + NULL, _error, _domainname, _result); } -int sss_sudo_create_query(uid_t uid, const char *username, - uint8_t **_query, size_t *_query_len) +/** + * Query format: + * uid|username_length|username|domainname_length|domainname + * (uid_t)(size_t)(char[])(size_t)(char[]) + */ +int sss_sudo_create_query(uid_t uid, + const char *username, + const char *domainname, + uint8_t **_query, + size_t *_query_len) { uint8_t *data = NULL; - size_t username_len = strlen(username) * sizeof(char) + 1; - size_t data_len = sizeof(uid_t) + username_len; + size_t username_len = 0; + size_t domainname_len = 0; + size_t data_len = 0; size_t offset = 0; + if (username == NULL) { + return EINVAL; + } + + username_len = strlen(username) + 1; + if (domainname != NULL) { + domainname_len = strlen(domainname) + 1; + } + + data_len = sizeof(uid_t) + 2*sizeof(size_t); + data_len += username_len + domainname_len; + data = (uint8_t*)malloc(data_len * sizeof(uint8_t)); if (data == NULL) { return ENOMEM; } SAFEALIGN_SET_VALUE(data, uid, uid_t, &offset); + + SAFEALIGN_SET_VALUE(data + offset, username_len, size_t, &offset); memcpy(data + offset, username, username_len); + offset += username_len; + + SAFEALIGN_SET_VALUE(data + offset, domainname_len, size_t, &offset); + if (domainname != NULL) { + memcpy(data + offset, domainname, domainname_len); + } *_query = data; *_query_len = data_len; -- 1.7.11.7
From d8f84d468528cbc2a7966d249ba9c04a4c8f0c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com> Date: Fri, 9 Nov 2012 14:16:38 +0100 Subject: [PATCH 5/6] libsss_sudo: bump version to 2:1:1 Only source code has changed, so we should bump only revision number. http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 3306bbac029bb4cc8d36d9e38a66632753a69c68..68afc9766aef27c3189af8b2e80bd34086d3e7d0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1185,7 +1185,7 @@ libsss_sudo_la_SOURCES = \ libsss_sudo_la_LDFLAGS = \ $(CLIENT_LIBS) \ -Wl,--version-script,$(srcdir)/src/sss_client/sss_sudo.exports \ - -version-info 2:0:1 + -version-info 2:1:1 sudolib_LTLIBRARIES = libsss_sudo.la -- 1.7.11.7
From fc15ef917d1d7d14b4ad4d2d4c4676df56feb053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com> Date: Wed, 7 Nov 2012 18:16:25 +0100 Subject: [PATCH 6/6] sudo: print how many rules we are refreshing or returning --- src/responder/sudo/sudosrv_get_sudorules.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c index e3fdd29dab4e8480c891dd642414fa307fc804c8..c5b057d9e71820e1440dbb635a6ea1d8a0676a6b 100644 --- a/src/responder/sudo/sudosrv_get_sudorules.c +++ b/src/responder/sudo/sudosrv_get_sudorules.c @@ -423,7 +423,8 @@ errno_t sudosrv_get_rules(struct sudo_cmd_ctx *cmd_ctx) cmd_ctx->expired_rules_num = expired_rules_num; if (expired_rules_num > 0) { /* refresh expired rules then continue */ - DEBUG(SSSDBG_TRACE_INTERNAL, ("Refreshing expired rules\n")); + DEBUG(SSSDBG_TRACE_INTERNAL, ("Refreshing %d expired rules\n", + expired_rules_num)); dpreq = sss_dp_get_sudoers_send(tmp_ctx, cmd_ctx->cli_ctx->rctx, cmd_ctx->domain, false, SSS_DP_SUDO_REFRESH_RULES, @@ -641,8 +642,8 @@ static errno_t sudosrv_get_sudorules_from_cache(TALLOC_CTX *mem_ctx, goto done; } - DEBUG(SSSDBG_TRACE_FUNC, ("Returning rules for [%s@%s]\n", - debug_name, cmd_ctx->domain->name)); + DEBUG(SSSDBG_TRACE_FUNC, ("Returning %d rules for [%s@%s]\n", + num_rules, debug_name, cmd_ctx->domain->name)); if (_rules != NULL) { *_rules = talloc_steal(mem_ctx, rules); -- 1.7.11.7
_______________________________________________ sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel