diff options
Diffstat (limited to 'src/responder')
-rw-r--r-- | src/responder/nss/nsssrv_cmd.c | 288 |
1 files changed, 116 insertions, 172 deletions
diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c index 508f3345..32ee2988 100644 --- a/src/responder/nss/nsssrv_cmd.c +++ b/src/responder/nss/nsssrv_cmd.c @@ -927,104 +927,116 @@ done: * - use mutexes so that setpwent() can return immediately * even if the data is still being fetched * - make getpwent() wait on the mutex + * + * Alternatively: + * - use a smarter search mechanism that keeps track of the + * last user searched and return the next X users doing + * an alphabetic sort and starting from the user following + * the last returned user. */ static int nss_cmd_getpwent_immediate(struct nss_cmd_ctx *cmdctx); -static void nss_cmd_setpw_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr); +static void nss_cmd_getpwent_dp_callback(uint16_t err_maj, uint32_t err_min, + const char *err_msg, void *ptr); -static void nss_cmd_setpwent_callback(void *ptr, int status, - struct ldb_result *res) +static int nss_cmd_getpwent_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; struct sysdb_ctx *sysdb; + struct ldb_result *res; struct getent_ctx *pctx; struct nss_ctx *nctx; int timeout; int ret; - if (status != LDB_SUCCESS) { - ret = nss_cmd_send_error(cmdctx, ENOENT); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - return; - } - nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); pctx = nctx->pctx; if (pctx == NULL) { pctx = talloc_zero(nctx, struct getent_ctx); if (!pctx) { - ret = nss_cmd_send_error(cmdctx, ENOMEM); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); - return; + return ENOMEM; } nctx->pctx = pctx; } - pctx->doms = talloc_realloc(pctx, pctx->doms, struct dom_ctx, pctx->num +1); - if (!pctx->doms) { - talloc_free(pctx); - nctx->pctx = NULL; - NSS_CMD_FATAL_ERROR(cctx); - } + while (dom) { + while (dom && dom->enumerate == 0) { + dom = dom->next; + } - pctx->doms[pctx->num].domain = dctx->domain; - pctx->doms[pctx->num].res = talloc_steal(pctx->doms, res); - pctx->doms[pctx->num].cur = 0; + if (!dom) break; - pctx->num++; + if (dom != dctx->domain) { + /* make sure we reset the check_provider flag when we check + * a new domain */ + if (cmdctx->enum_cached) { + dctx->check_provider = false; + } else { + dctx->check_provider = NEED_CHECK_PROVIDER(dom->provider); + } + } - /* do not reply until all domain searches are done */ - for (dom = dctx->domain->next; dom; dom = dom->next) { - if (dom->enumerate != 0) break; - } - dctx->domain = dom; + /* make sure to update the dctx if we changed domain */ + dctx->domain = dom; - if (dctx->domain != NULL) { - if (cmdctx->enum_cached) { - dctx->check_provider = false; - } else { - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); + DEBUG(4, ("Requesting info for domain [%s]\n", dom->name)); + + 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; } + /* 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) { + dctx->check_provider = false; timeout = SSS_CLI_SOCKET_TIMEOUT; ret = sss_dp_send_acct_req(cctx->rctx, cmdctx, - nss_cmd_setpw_dp_callback, dctx, + nss_cmd_getpwent_dp_callback, dctx, timeout, dom->name, true, SSS_DP_USER, NULL, 0); - } else { - 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); + if (ret == EOK) { + return ret; + } else { + DEBUG(2, ("Enum Cache refresh for domain [%s] failed." + " Trying to return what we have in cache!\n", + dom->name)); } - ret = sysdb_enumpwent(dctx, sysdb, - dctx->domain, NULL, - nss_cmd_setpwent_callback, dctx); } + + ret = sysdb_enumpwent(dctx, sysdb, dctx->domain, &res); if (ret != EOK) { - /* FIXME: shutdown ? */ - DEBUG(1, ("Failed to send enumeration request for domain [%s]!\n", + DEBUG(1, ("Enum from cache failed, skipping domain [%s]\n", dom->name)); + dom = dom->next; + continue; + } - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); + if (res->count == 0) { + DEBUG(4, ("Domain [%s] has no users, skipping.\n", dom->name)); + dom = dom->next; + continue; } - return; + + pctx->doms = talloc_realloc(pctx, pctx->doms, + struct dom_ctx, pctx->num +1); + if (!pctx->doms) { + talloc_free(pctx); + nctx->pctx = NULL; + return ENOMEM; + } + + pctx->doms[pctx->num].domain = dctx->domain; + pctx->doms[pctx->num].res = talloc_steal(pctx->doms, res); + pctx->doms[pctx->num].cur = 0; + + pctx->num++; + + /* do not reply until all domain searches are done */ + dom = dom->next; } /* set cache mark */ @@ -1033,28 +1045,25 @@ static void nss_cmd_setpwent_callback(void *ptr, int status, if (cmdctx->immediate) { /* this was a getpwent call w/o setpwent, * return immediately one result */ - ret = nss_cmd_getpwent_immediate(cmdctx); - if (ret != EOK) NSS_CMD_FATAL_ERROR(cctx); - return; + return nss_cmd_getpwent_immediate(cmdctx); } /* create response packet */ 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); + if (ret == EOK) { + sss_cmd_done(cctx, cmdctx); } - sss_cmd_done(cctx, cmdctx); + return ret; } -static void nss_cmd_setpw_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) +static void nss_cmd_getpwent_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) { @@ -1064,37 +1073,20 @@ static void nss_cmd_setpw_dp_callback(uint16_t err_maj, uint32_t err_min, (unsigned int)err_maj, (unsigned int)err_min, err_msg)); } - 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_enumpwent(cmdctx, sysdb, - dctx->domain, NULL, - nss_cmd_setpwent_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); + ret = nss_cmd_getpwent_search(dctx); - ret = nss_cmd_send_error(cmdctx, ret); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - sss_cmd_done(cctx, cmdctx); + if (ret) { + NSS_CMD_FATAL_ERROR(cctx); } } static int nss_cmd_setpwent_ext(struct cli_ctx *cctx, bool immediate) { struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; struct nss_cmd_ctx *cmdctx; struct nss_dom_ctx *dctx; struct nss_ctx *nctx; time_t now = time(NULL); - int timeout; - uint8_t *body; - size_t blen; int ret; DEBUG(4, ("Requesting info for all users\n")); @@ -1119,8 +1111,7 @@ static int nss_cmd_setpwent_ext(struct cli_ctx *cctx, bool immediate) /* do not query backends if we have a recent enumeration */ if (nctx->enum_cache_timeout) { - if (nctx->last_user_enum + - nctx->enum_cache_timeout > now) { + if (nctx->last_user_enum + nctx->enum_cache_timeout > now) { cmdctx->enum_cached = true; } } @@ -1133,71 +1124,25 @@ static int nss_cmd_setpwent_ext(struct cli_ctx *cctx, bool immediate) if (dctx->domain == NULL) { DEBUG(2, ("Enumeration disabled on all domains!\n")); - ret = ENOENT; + if (cmdctx->immediate) { + ret = ENOENT; + } else { + ret = sss_packet_new(cctx->creq, 0, + sss_packet_get_cmd(cctx->creq->in), + &cctx->creq->out); + if (ret == EOK) { + sss_cmd_done(cctx, cmdctx); + } + } goto done; } - if (cmdctx->enum_cached) { - dctx->check_provider = false; - } else { - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - } - - if (dctx->check_provider) { - timeout = SSS_CLI_SOCKET_TIMEOUT; - ret = sss_dp_send_acct_req(cctx->rctx, cmdctx, - nss_cmd_setpw_dp_callback, dctx, - timeout, dom->name, true, - SSS_DP_USER, NULL, 0); - } else { - 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_enumpwent(dctx, sysdb, - dctx->domain, NULL, - nss_cmd_setpwent_callback, dctx); - } - if (ret != EOK) { - /* FIXME: shutdown ? */ - DEBUG(1, ("Failed to send enumeration request for domain [%s]!\n", - dom->name)); - } + dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); + /* ok, start the searches */ + ret = nss_cmd_getpwent_search(dctx); done: - if (ret != EOK) { - if (ret == ENOENT) { - if (cmdctx->immediate) { - /* 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 */ - } - } - else { - /* create response packet */ - ret = sss_packet_new(cctx->creq, 0, - sss_packet_get_cmd(cctx->creq->in), - &cctx->creq->out); - } - } - 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); } static int nss_cmd_setpwent(struct cli_ctx *cctx) @@ -1213,40 +1158,42 @@ static int nss_cmd_retpwent(struct cli_ctx *cctx, int num) struct ldb_message **msgs = NULL; struct dom_ctx *pdom = NULL; int n = 0; - int ret; + int ret = ENOENT; nctx = talloc_get_type(cctx->rctx->pvt_ctx, struct nss_ctx); - pctx = nctx->pctx; + if (!nctx->pctx) goto none; -retry: - if (pctx->cur >= pctx->num) goto none; + pctx = nctx->pctx; - pdom = &pctx->doms[pctx->cur]; + while (ret == ENOENT) { + if (pctx->cur >= pctx->num) break; - n = pdom->res->count - pdom->cur; - if (n == 0 && (pctx->cur+1 < pctx->num)) { - pctx->cur++; pdom = &pctx->doms[pctx->cur]; + n = pdom->res->count - pdom->cur; - } + if (n == 0 && (pctx->cur+1 < pctx->num)) { + pctx->cur++; + pdom = &pctx->doms[pctx->cur]; + n = pdom->res->count - pdom->cur; + } - if (!n) goto none; + if (!n) break; - if (n > num) n = num; + if (n > num) n = num; - msgs = &(pdom->res->msgs[pdom->cur]); - pdom->cur += n; + msgs = &(pdom->res->msgs[pdom->cur]); + pdom->cur += n; - ret = fill_pwent(cctx->creq->out, pdom->domain, nctx, true, msgs, n); - if (ret == ENOENT) goto retry; - return ret; + ret = fill_pwent(cctx->creq->out, pdom->domain, nctx, true, msgs, n); + } none: - return fill_empty(cctx->creq->out); + if (ret == ENOENT) { + ret = fill_empty(cctx->creq->out); + } + return ret; } -/* used only if a process calls getpwent() without first calling setpwent() - */ static int nss_cmd_getpwent_immediate(struct nss_cmd_ctx *cmdctx) { struct cli_ctx *cctx = cmdctx->cctx; @@ -1289,9 +1236,6 @@ static int nss_cmd_getpwent(struct cli_ctx *cctx) /* see if we need to trigger an implicit setpwent() */ if (nctx->pctx == NULL) { - nctx->pctx = talloc_zero(nctx, struct getent_ctx); - if (!nctx->pctx) return ENOMEM; - return nss_cmd_setpwent_ext(cctx, true); } |