From aafa0393524bacc5ba48e79ab536f9deb3972e38 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sun, 21 Mar 2010 00:06:29 -0400 Subject: sysdb: convert sysdb_initgroups --- src/db/sysdb.h | 2 +- src/db/sysdb_search.c | 143 ++++++----------- src/responder/nss/nsssrv_cmd.c | 339 ++++++++++++++--------------------------- 3 files changed, 166 insertions(+), 318 deletions(-) diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 969413be..08af3125 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -287,7 +287,7 @@ int sysdb_initgroups(TALLOC_CTX *mem_ctx, struct sysdb_ctx *ctx, struct sss_domain_info *domain, const char *name, - sysdb_callback_t fn, void *ptr); + struct ldb_result **res); int sysdb_get_user_attr(TALLOC_CTX *mem_ctx, struct sysdb_ctx *ctx, diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c index b874f0d0..e0b35b9d 100644 --- a/src/db/sysdb_search.c +++ b/src/db/sysdb_search.c @@ -511,141 +511,94 @@ done: return ret; } -static void initgr_mem_search(struct sysdb_search_ctx *sctx) +int sysdb_initgroups(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *name, + struct ldb_result **_res) { - struct sysdb_ctx *ctx = sctx->ctx; - struct ldb_result *res = sctx->res; + TALLOC_CTX *tmpctx; + struct ldb_result *res; + struct ldb_dn *user_dn; struct ldb_request *req; struct ldb_control **ctrl; struct ldb_asq_control *control; static const char *attrs[] = SYSDB_INITGR_ATTRS; int ret; - if (res->count == 0) { - return request_done(sctx); + tmpctx = talloc_new(mem_ctx); + if (!tmpctx) { + return ENOMEM; + } + + ret = sysdb_getpwnam(tmpctx, ctx, domain, name, &res); + if (ret != EOK) { + goto done; } - if (res->count > 1) { - return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + if (res->count != 1) { + ret = EIO; + goto done; } - /* make sure we don't loop with get_gen_callback() */ - sctx->gen_aux_fn = NULL; + /* no need to steal the dn, we are not freeing the result */ + user_dn = res->msgs[0]->dn; - sctx->expression = talloc_asprintf(sctx, SYSDB_INITGR_FILTER); - if (!sctx->expression) { - return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); - } + /* note we count on the fact that the default search callback + * will just keep appending values. This is by design and can't + * change so it is ok to already have a result (from the getpwnam) + * even before we call the next search */ - ctrl = talloc_array(sctx, struct ldb_control *, 2); + ctrl = talloc_array(tmpctx, struct ldb_control *, 2); if (!ctrl) { - return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + ret = ENOMEM; + goto done; } ctrl[1] = NULL; ctrl[0] = talloc(ctrl, struct ldb_control); if (!ctrl[0]) { - return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + ret = ENOMEM; + goto done; } ctrl[0]->oid = LDB_CONTROL_ASQ_OID; ctrl[0]->critical = 1; control = talloc(ctrl[0], struct ldb_asq_control); if (!control) { - return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + ret = ENOMEM; + goto done; } control->request = 1; control->source_attribute = talloc_strdup(control, SYSDB_INITGR_ATTR); if (!control->source_attribute) { - return request_ldberror(sctx, LDB_ERR_OPERATIONS_ERROR); + ret = ENOMEM; + goto done; } control->src_attr_len = strlen(control->source_attribute); ctrl[0]->data = control; - ret = ldb_build_search_req(&req, ctx->ldb, sctx, - res->msgs[0]->dn, - LDB_SCOPE_BASE, - sctx->expression, attrs, ctrl, - sctx, get_gen_callback, + ret = ldb_build_search_req(&req, ctx->ldb, tmpctx, + user_dn, LDB_SCOPE_BASE, + SYSDB_INITGR_FILTER, attrs, ctrl, + res, ldb_search_default_callback, NULL); if (ret != LDB_SUCCESS) { - return request_ldberror(sctx, ret); + ret = sysdb_error_to_errno(ret); + goto done; } ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) { - return request_ldberror(sctx, ret); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); } -} - -static void initgr_search(struct tevent_req *treq) -{ - struct sysdb_search_ctx *sctx; - static const char *attrs[] = SYSDB_PW_ATTRS; - struct ldb_request *req; - struct ldb_dn *base_dn; - int ret; - - sctx = tevent_req_callback_data(treq, struct sysdb_search_ctx); - - ret = sysdb_operation_recv(treq, sctx, &sctx->handle); - if (ret) { - return request_error(sctx, ret); - } - - sctx->gen_aux_fn = initgr_mem_search; - - base_dn = ldb_dn_new_fmt(sctx, sctx->ctx->ldb, - SYSDB_TMPL_USER_BASE, sctx->domain->name); - if (!base_dn) { - return request_error(sctx, ENOMEM); - } - - ret = ldb_build_search_req(&req, sctx->ctx->ldb, sctx, - base_dn, LDB_SCOPE_SUBTREE, - sctx->expression, attrs, NULL, - sctx, get_gen_callback, - NULL); - if (ret != LDB_SUCCESS) { - return request_ldberror(sctx, ret); - } - - ret = ldb_request(sctx->ctx->ldb, req); if (ret != LDB_SUCCESS) { - return request_ldberror(sctx, ret); - } -} - -int sysdb_initgroups(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *ctx, - struct sss_domain_info *domain, - const char *name, - sysdb_callback_t fn, void *ptr) -{ - struct sysdb_search_ctx *sctx; - struct tevent_req *req; - - if (!domain) { - return EINVAL; - } - - sctx = init_src_ctx(mem_ctx, domain, ctx, fn, ptr); - if (!sctx) { - return ENOMEM; - } - - sctx->expression = talloc_asprintf(sctx, SYSDB_PWNAM_FILTER, name); - if (!sctx->expression) { - talloc_free(sctx); - return ENOMEM; - } - - req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); - if (!req) { - talloc_free(sctx); - return ENOMEM; + ret = sysdb_error_to_errno(ret); + goto done; } - tevent_req_set_callback(req, initgr_search, sctx); + *_res = talloc_steal(mem_ctx, res); - return EOK; +done: + talloc_zfree(tmpctx); + return ret; } int sysdb_get_user_attr(TALLOC_CTX *mem_ctx, diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c index 2539c8b9..eb2a1644 100644 --- a/src/responder/nss/nsssrv_cmd.c +++ b/src/responder/nss/nsssrv_cmd.c @@ -2344,6 +2344,8 @@ done: return EOK; } +/* FIXME: what about mpg, should we return the user's GID ? */ +/* FIXME: should we filter out GIDs ? */ static int fill_initgr(struct sss_packet *packet, struct ldb_result *res) { uint8_t *body; @@ -2380,155 +2382,137 @@ static int fill_initgr(struct sss_packet *packet, struct ldb_result *res) return EOK; } -static void nss_cmd_getinitgr_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); +static int nss_cmd_initgr_send_reply(struct nss_dom_ctx *dctx) +{ + struct nss_cmd_ctx *cmdctx = dctx->cmdctx; + struct cli_ctx *cctx = cmdctx->cctx; + struct nss_ctx *nctx; + int ret; + int i; + + nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); + + ret = sss_packet_new(cctx->creq, 0, + sss_packet_get_cmd(cctx->creq->in), + &cctx->creq->out); + if (ret != EOK) { + return EFAULT; + } + i = dctx->res->count; + ret = fill_initgr(cctx->creq->out, dctx->res); + if (ret) { + return ret; + } + sss_packet_set_error(cctx->creq->out, EOK); + sss_cmd_done(cctx, cmdctx); + return EOK; +} + +static void nss_cmd_initgroups_dp_callback(uint16_t err_maj, uint32_t err_min, + const char *err_msg, void *ptr); -static void nss_cmd_getinitgr_callback(void *ptr, int status, - struct ldb_result *res) +static int nss_cmd_initgroups_search(struct nss_dom_ctx *dctx) { - struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); struct nss_cmd_ctx *cmdctx = dctx->cmdctx; + struct sss_domain_info *dom = dctx->domain; struct cli_ctx *cctx = cmdctx->cctx; - struct sss_domain_info *dom; + const char *name = cmdctx->name; struct sysdb_ctx *sysdb; struct nss_ctx *nctx; - uint8_t *body; - size_t blen; - bool neghit = false; - int ncret; int ret; nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, status); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); + while (dom) { + /* if it is a domainless search, skip domains that require fully + * qualified names instead */ + while (dom && cmdctx->check_next && dom->fqnames) { + dom = dom->next; } - sss_cmd_done(cctx, cmdctx); - return; - } - if (dctx->check_provider) { - ret = check_cache(dctx, nctx, res, - SSS_DP_INITGROUPS, cmdctx->name, 0, - nss_cmd_getinitgr_dp_callback); - if (ret != EOK) { - /* Anything but EOK means we should reenter the mainloop - * because we may be refreshing the cache - */ - return; + if (!dom) break; + + if (dom != dctx->domain) { + /* make sure we reset the check_provider flag when we check + * a new domain */ + dctx->check_provider = NEED_CHECK_PROVIDER(dom->provider); } - } - switch (res->count) { - case 0: - if (cmdctx->check_next) { + /* make sure to update the dctx if we changed domain */ + dctx->domain = dom; - ret = EOK; + /* verify this user has not yet been negatively cached, + * or has been permanently filtered */ + ret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout, + dom->name, name); - /* skip domains that require FQnames or have negative caches */ - for (dom = dctx->domain->next; dom; dom = dom->next) { + /* if neg cached, return we didn't find it */ + if (ret == EEXIST) { + DEBUG(2, ("User [%s] does not exist! (negative cache)\n", name)); + return ENOENT; + } - if (dom->fqnames) continue; + DEBUG(4, ("Requesting info for [%s@%s]\n", name, dom->name)); - ncret = nss_ncache_check_user(nctx->ncache, - nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; + ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, dom, &sysdb); + if (ret != EOK) { + DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); + return EIO; + } - neghit = true; - } - /* reset neghit if we still have a domain to check */ - if (dom) neghit = false; + ret = sysdb_initgroups(cmdctx, sysdb, dom, name, &dctx->res); + if (ret != EOK) { + DEBUG(1, ("Failed to make request to our cache!\n")); + return EIO; + } - if (neghit) { - DEBUG(2, ("User [%s] does not exist! (negative cache)\n", - cmdctx->name)); - ret = ENOENT; - } - if (dom == NULL) { - DEBUG(2, ("No matching domain found for [%s], fail!\n", - cmdctx->name)); - ret = ENOENT; + if (dctx->res->count == 0 && !dctx->check_provider) { + /* if a multidomain search, try with next */ + if (cmdctx->check_next) { + dom = dom->next; + continue; } - if (ret == EOK) { - dctx->domain = dom; - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - if (dctx->res) talloc_free(res); - dctx->res = NULL; - - DEBUG(4, ("Requesting info for [%s@%s]\n", - cmdctx->name, dctx->domain->name)); + DEBUG(2, ("No results for initgroups call\n")); - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_initgroups(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getinitgr_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } + /* set negative cache only if not result of cache check */ + ret = nss_ncache_set_user(nctx->ncache, false, dom->name, name); + if (ret != EOK) { + return ret; } - /* we made another call, end here */ - if (ret == EOK) return; + return ENOENT; } - DEBUG(2, ("No results for initgroups call\n")); - - /* set negative cache only if not result of cache check */ - if (!neghit) { - ret = nss_ncache_set_user(nctx->ncache, false, - dctx->domain->name, cmdctx->name); + /* if this is a caching provider (or if we haven't checked the cache + * yet) then verify that the cache is uptodate */ + if (dctx->check_provider) { + ret = check_cache(dctx, nctx, dctx->res, + SSS_DP_INITGROUPS, name, 0, + nss_cmd_initgroups_dp_callback); if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); + /* Anything but EOK means we should reenter the mainloop + * because we may be refreshing the cache + */ + return ret; } } - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - break; - - default: - - DEBUG(6, ("Returning initgr for user [%s]\n", cmdctx->name)); + DEBUG(6, ("Initgroups for [%s@%s] completed\n", name, dom->name)); - ret = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - ret = fill_initgr(cctx->creq->out, res); - if (ret == ENOENT) { - ret = fill_empty(cctx->creq->out); - } - sss_packet_set_error(cctx->creq->out, ret); + return nss_cmd_initgr_send_reply(dctx); } - sss_cmd_done(cctx, cmdctx); + DEBUG(2, ("No matching domain found for [%s], fail!\n", name)); + return ENOENT; } -static void nss_cmd_getinitgr_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) +static void nss_cmd_initgroups_dp_callback(uint16_t err_maj, uint32_t err_min, + const char *err_msg, void *ptr) { struct nss_dom_ctx *dctx = talloc_get_type(ptr, struct nss_dom_ctx); struct nss_cmd_ctx *cmdctx = dctx->cmdctx; struct cli_ctx *cctx = cmdctx->cctx; - struct sysdb_ctx *sysdb; int ret; if (err_maj) { @@ -2537,38 +2521,29 @@ static void nss_cmd_getinitgr_dp_callback(uint16_t err_maj, uint32_t err_min, "Will try to return what we have in cache\n", (unsigned int)err_maj, (unsigned int)err_min, err_msg)); - if (!dctx->res) { - /* return 0 results */ - dctx->res = talloc_zero(dctx, struct ldb_result); - if (!dctx->res) { - ret = ENOMEM; - goto done; - } + if (dctx->res && dctx->res->count != 0) { + ret = nss_cmd_initgr_send_reply(dctx); + goto done; } - nss_cmd_getinitgr_callback(dctx, LDB_SUCCESS, dctx->res); - return; + /* no previous results, just loop to next domain if possible */ + if (dctx->domain->next && cmdctx->check_next) { + dctx->domain = dctx->domain->next; + dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); + } else { + /* nothing vailable */ + ret = ENOENT; + goto done; + } } - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - NSS_CMD_FATAL_ERROR(cctx); - } - ret = sysdb_initgroups(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getinitgr_callback, dctx); + /* ok the backend returned, search to see if we have updated results */ + ret = nss_cmd_initgroups_search(dctx); done: - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); + ret = nss_cmd_done(cmdctx, ret); + if (ret) { + NSS_CMD_FATAL_ERROR(cctx); } } @@ -2577,18 +2552,11 @@ static int nss_cmd_initgroups(struct cli_ctx *cctx) { struct nss_cmd_ctx *cmdctx; struct nss_dom_ctx *dctx; - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - struct nss_ctx *nctx; const char *rawname; char *domname; uint8_t *body; size_t blen; int ret; - int ncret; - bool neghit = false; - - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); cmdctx = talloc_zero(cctx, struct nss_cmd_ctx); if (!cmdctx) { @@ -2623,7 +2591,7 @@ static int nss_cmd_initgroups(struct cli_ctx *cctx) } DEBUG(4, ("Requesting info for [%s] from [%s]\n", - cmdctx->name, domname ? : "")); + cmdctx->name, domname?domname:"")); if (domname) { dctx->domain = nss_get_dom(cctx->rctx->domains, domname); @@ -2631,92 +2599,19 @@ static int nss_cmd_initgroups(struct cli_ctx *cctx) ret = ENOENT; goto done; } - - /* verify this user has not yet been negatively cached, - * or has been permanently filtered */ - ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout, - domname, cmdctx->name); - if (ncret == EEXIST) { - neghit = true; - } - } - else { - /* skip domains that require FQnames or have negative caches */ - for (dom = cctx->rctx->domains; dom; dom = dom->next) { - - if (dom->fqnames) continue; - - /* verify this user has not yet been negatively cached, - * or has been permanently filtered */ - ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; - - neghit = true; - } - /* reset neghit if we still have a domain to check */ - if (dom) neghit = false; - - dctx->domain = dom; - } - if (neghit) { - DEBUG(2, ("User [%s] does not exist! (negative cache)\n", rawname)); - ret = ENOENT; - goto done; - } - if (dctx->domain == NULL) { - DEBUG(2, ("No matching domain found for [%s], fail!\n", rawname)); - ret = ENOENT; - goto done; - } - - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - - if (!domname) { + } else { /* this is a multidomain search */ + dctx->domain = cctx->rctx->domains; cmdctx->check_next = true; } - DEBUG(4, ("Requesting info for [%s@%s]\n", - cmdctx->name, dctx->domain->name)); + dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - dctx->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - ret = EFAULT; - goto done; - } - ret = sysdb_initgroups(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getinitgr_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } + /* ok, find it ! */ + ret = nss_cmd_initgroups_search(dctx); done: - if (ret != EOK) { - if (ret == ENOENT) { - /* we do not have any entry to return */ - ret = sss_packet_new(cctx->creq, 2*sizeof(uint32_t), - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - if (ret == EOK) { - sss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - } - } - if (ret != EOK) { - ret = nss_cmd_send_error(cmdctx, ret); - } - if (ret == EOK) { - sss_cmd_done(cctx, cmdctx); - } - return ret; - } - - return EOK; + return nss_cmd_done(cmdctx, ret); } struct cli_protocol_version *register_cli_protocol_version(void) -- cgit