From 7ffaa2afb9e03a6f0b9c602c0f03b2074ea33eac Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sun, 14 Mar 2010 17:27:05 -0400 Subject: sysdb: convert sysdb_getpwnam --- src/db/sysdb.h | 2 +- src/db/sysdb_search.c | 38 ++-- src/python/pysss.c | 4 +- src/responder/nss/nsssrv_cmd.c | 419 +++++++++++++++++++---------------------- src/responder/pam/pamsrv.h | 1 + src/responder/pam/pamsrv_cmd.c | 337 ++++++++++++--------------------- src/tests/sysdb-tests.c | 77 +++----- src/tools/sss_sync_ops.c | 152 ++++++--------- src/tools/sss_sync_ops.h | 2 +- src/tools/sss_useradd.c | 2 +- src/tools/sss_userdel.c | 2 +- src/tools/sss_usermod.c | 2 +- 12 files changed, 415 insertions(+), 623 deletions(-) diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 7da98fa84..365e6adf6 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -253,7 +253,7 @@ int sysdb_getpwnam(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_getpwuid(TALLOC_CTX *mem_ctx, struct sysdb_ctx *ctx, diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c index 4b9470baa..2403917b7 100644 --- a/src/db/sysdb_search.c +++ b/src/db/sysdb_search.c @@ -215,38 +215,42 @@ int sysdb_getpwnam(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) { + TALLOC_CTX *tmpctx; static const char *attrs[] = SYSDB_PW_ATTRS; - struct sysdb_search_ctx *sctx; - struct tevent_req *req; + struct ldb_dn *base_dn; + struct ldb_result *res; + int ret; if (!domain) { return EINVAL; } - sctx = init_src_ctx(mem_ctx, domain, ctx, fn, ptr); - if (!sctx) { + tmpctx = talloc_new(mem_ctx); + if (!tmpctx) { return ENOMEM; } - sctx->expression = talloc_asprintf(sctx, SYSDB_PWNAM_FILTER, name); - if (!sctx->expression) { - talloc_free(sctx); - return ENOMEM; + base_dn = ldb_dn_new_fmt(tmpctx, ctx->ldb, + SYSDB_TMPL_USER_BASE, domain->name); + if (!base_dn) { + ret = ENOMEM; + goto done; } - sctx->attrs = attrs; - - req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); - if (!req) { - talloc_free(sctx); - return ENOMEM; + ret = ldb_search(ctx->ldb, tmpctx, &res, base_dn, + LDB_SCOPE_SUBTREE, attrs, SYSDB_PWNAM_FILTER, name); + if (ret) { + ret = sysdb_error_to_errno(ret); + goto done; } - tevent_req_set_callback(req, user_search, sctx); + *_res = talloc_steal(mem_ctx, res); - return EOK; +done: + talloc_zfree(tmpctx); + return ret; } int sysdb_getpwuid(TALLOC_CTX *mem_ctx, diff --git a/src/python/pysss.c b/src/python/pysss.c index 48c5aea2e..cd5c588f3 100644 --- a/src/python/pysss.c +++ b/src/python/pysss.c @@ -268,7 +268,7 @@ static PyObject *py_sss_useradd(PySssLocalObject *self, tctx->sysdb, tctx->octx->name, tctx->local, - &tctx->octx); + tctx->octx); if (ret != EOK) { PyErr_SetSssError(ret); goto fail; @@ -375,7 +375,7 @@ static PyObject *py_sss_userdel(PySssLocalObject *self, tctx->sysdb, tctx->octx->name, tctx->local, - &tctx->octx); + tctx->octx); if (ret != EOK) { PyErr_SetSssError(ret); goto fail; diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c index 042517ad8..d25c467ae 100644 --- a/src/responder/nss/nsssrv_cmd.c +++ b/src/responder/nss/nsssrv_cmd.c @@ -33,6 +33,7 @@ struct nss_cmd_ctx { bool immediate; bool check_next; bool enum_cached; + }; struct dom_ctx { @@ -115,6 +116,61 @@ static int fill_empty(struct sss_packet *packet) return EOK; } +static int nss_cmd_send_empty(struct nss_cmd_ctx *cmdctx) +{ + struct cli_ctx *cctx = cmdctx->cctx; + int ret; + + /* create response packet */ + ret = sss_packet_new(cctx->creq, 0, + sss_packet_get_cmd(cctx->creq->in), + &cctx->creq->out); + if (ret != EOK) { + return ret; + } + ret = fill_empty(cctx->creq->out); + if (ret != EOK) { + return ret; + } + sss_packet_set_error(cctx->creq->out, EOK); + sss_cmd_done(cctx, cmdctx); + return EOK; +} + +static int nss_cmd_done(struct nss_cmd_ctx *cmdctx, int ret) +{ + switch (ret) { + case EOK: + /* all fine, just return here */ + break; + + case ENOENT: + ret = nss_cmd_send_empty(cmdctx); + if (ret) { + return EFAULT; + } + break; + + case EAGAIN: + /* async processing, just return here */ + break; + + case EFAULT: + /* very bad error */ + return EFAULT; + + default: + ret = nss_cmd_send_error(cmdctx, ret); + if (ret) { + return EFAULT; + } + sss_cmd_done(cmdctx->cctx, cmdctx); + break; + } + + return EOK; +} + /**************************************************************************** * PASSWD db related functions ***************************************************************************/ @@ -260,6 +316,36 @@ done: return EOK; } +static int nss_cmd_getpw_send_reply(struct nss_dom_ctx *dctx, bool filter) +{ + struct nss_cmd_ctx *cmdctx = dctx->cmdctx; + struct cli_ctx *cctx = cmdctx->cctx; + struct nss_ctx *nctx; + int ret; + + 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; + } + ret = fill_pwent(cctx->creq->out, + dctx->domain, + nctx, filter, + dctx->res->msgs, dctx->res->count); + if (ret) { + return ret; + } + sss_packet_set_error(cctx->creq->out, EOK); + sss_cmd_done(cctx, cmdctx); + return EOK; +} + + +/* FIXME: do not check res->count, but get in a msgs and check in parent */ +/* FIXME: do not sss_cmd_done, but return error and let parent do it */ static errno_t check_cache(struct nss_dom_ctx *dctx, struct nss_ctx *nctx, struct ldb_result *res, @@ -387,7 +473,6 @@ static errno_t check_cache(struct nss_dom_ctx *dctx, NSS_CMD_FATAL_ERROR_CODE(cctx, EIO); } sss_cmd_done(cctx, cmdctx); - return EIO; } return EAGAIN; @@ -399,155 +484,114 @@ static errno_t check_cache(struct nss_dom_ctx *dctx, static void nss_cmd_getpwnam_dp_callback(uint16_t err_maj, uint32_t err_min, const char *err_msg, void *ptr); -static void nss_cmd_getpwnam_callback(void *ptr, int status, - struct ldb_result *res) +/* search for a user. + * Returns: + * ENOENT, if user is definitely not found + * EAGAIN, if user is beeing fetched from backend via async operations + * EOK, if found + * anything else on a fatal error + */ + +static int nss_cmd_getpwnam_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; + const char *name = cmdctx->name; struct sysdb_ctx *sysdb; - struct sss_domain_info *dom; 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); - } - sss_cmd_done(cctx, cmdctx); - return; - } - - if (dctx->check_provider) { - ret = check_cache(dctx, nctx, res, - SSS_DP_USER, cmdctx->name, 0, - nss_cmd_getpwnam_dp_callback); - if (ret != EOK) { - /* Anything but EOK means we should reenter the mainloop - * because we may be refreshing the cache - */ - return; + 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; } - } - switch (res->count) { - case 0: - if (cmdctx->check_next) { + if (!dom) break; - ret = EOK; + 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); + } - /* skip domains that require FQnames or have negative caches */ - for (dom = dctx->domain->next; dom; dom = dom->next) { + /* make sure to update the dctx if we changed domain */ + dctx->domain = dom; - if (dom->fqnames) continue; + /* 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); - ncret = nss_ncache_check_user(nctx->ncache, - nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; + /* 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; + } - neghit = true; - } - /* reset neghit if we still have a domain to check */ - if (dom) neghit = false; + DEBUG(4, ("Requesting info for [%s@%s]\n", name, dom->name)); - 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; - } + 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 (ret == EOK) { - dctx->domain = dom; - dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider); - if (dctx->res) talloc_free(res); - dctx->res = NULL; + ret = sysdb_getpwnam(cmdctx, sysdb, dom, name, &dctx->res); + if (ret != EOK) { + DEBUG(1, ("Failed to make request to our cache!\n")); + return EIO; + } - DEBUG(4, ("Requesting info for [%s@%s]\n", - cmdctx->name, dctx->domain->name)); + if (dctx->res->count > 1) { + DEBUG(0, ("getpwnam call returned more than one result !?!\n")); + return ENOENT; + } - 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_getpwnam(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getpwnam_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } + if (dctx->res->count == 0 && !dctx->check_provider) { + /* if a multidomain search, try with next */ + if (cmdctx->check_next) { + dom = dom->next; + continue; } - /* we made another call, end here */ - if (ret == EOK) return; - } + DEBUG(2, ("No results for getpwnam call\n")); - DEBUG(2, ("No results for getpwnam 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); + /* set negative cache only if not result of cache check */ + ret = nss_ncache_set_user(nctx->ncache, false, dom->name, name); if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); + 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); + return ENOENT; } - sss_packet_get_body(cctx->creq->out, &body, &blen); - ((uint32_t *)body)[0] = 0; /* 0 results */ - ((uint32_t *)body)[1] = 0; /* reserved */ - break; - case 1: - DEBUG(6, ("Returning info for user [%s]\n", cmdctx->name)); - - /* 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); - } - ret = fill_pwent(cctx->creq->out, - dctx->domain, - nctx, false, - res->msgs, res->count); - if (ret == ENOENT) { - ret = fill_empty(cctx->creq->out); + /* 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_USER, name, 0, + nss_cmd_getpwnam_dp_callback); + if (ret != EOK) { + /* Anything but EOK means we should reenter the mainloop + * because we may be refreshing the cache + */ + return ret; + } } - sss_packet_set_error(cctx->creq->out, ret); - break; + /* One result found */ + DEBUG(6, ("Returning info for user [%s@%s]\n", name, dom->name)); - default: - DEBUG(1, ("getpwnam call returned more than one result !?!\n")); - ret = nss_cmd_send_error(cmdctx, ENOENT); - if (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } + return EOK; } - sss_cmd_done(cctx, cmdctx); + DEBUG(2, ("No matching domain found for [%s], fail!\n", name)); + return ENOENT; } static void nss_cmd_getpwnam_dp_callback(uint16_t err_maj, uint32_t err_min, @@ -556,7 +600,6 @@ static void nss_cmd_getpwnam_dp_callback(uint16_t err_maj, uint32_t err_min, 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) { @@ -565,39 +608,33 @@ static void nss_cmd_getpwnam_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 == 1) { + ret = nss_cmd_getpw_send_reply(dctx, false); + goto done; } - nss_cmd_getpwnam_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); + /* ok the backend returned, search to see if we have updated results */ + ret = nss_cmd_getpwnam_search(dctx); + if (ret == EOK) { + /* we have results to return */ + ret = nss_cmd_getpw_send_reply(dctx, false); } - ret = sysdb_getpwnam(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getpwnam_callback, dctx); done: - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache! (%d [%s])\n", - ret, strerror(ret))); - - 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); } } @@ -605,18 +642,11 @@ static int nss_cmd_getpwnam(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) { @@ -659,92 +689,23 @@ static int nss_cmd_getpwnam(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, - dctx->domain->name, 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_getpwnam(cmdctx, sysdb, - dctx->domain, cmdctx->name, - nss_cmd_getpwnam_callback, dctx); - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); + /* ok, find it ! */ + ret = nss_cmd_getpwnam_search(dctx); + if (ret == EOK) { + /* we have results to return */ + ret = nss_cmd_getpw_send_reply(dctx, false); } 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); } static void nss_cmd_getpwuid_dp_callback(uint16_t err_maj, uint32_t err_min, diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h index 60f9c66ae..1a81fb70f 100644 --- a/src/responder/pam/pamsrv.h +++ b/src/responder/pam/pamsrv.h @@ -44,6 +44,7 @@ struct pam_auth_req { pam_dp_callback_t *callback; + struct ldb_result *res; bool check_provider; void *data; }; diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c index eba78cceb..d5b4eff69 100644 --- a/src/responder/pam/pamsrv_cmd.c +++ b/src/responder/pam/pamsrv_cmd.c @@ -564,8 +564,8 @@ static void pam_cache_auth_done(struct pam_auth_req *preq, int ret, static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min, const char *err_msg, void *ptr); -static void pam_check_user_callback(void *ptr, int status, - struct ldb_result *res); +static int pam_check_user_search(struct pam_auth_req *preq); +static int pam_check_user_done(struct pam_auth_req *preq, int ret); static void pam_dom_forwarder(struct pam_auth_req *preq); /* TODO: we should probably return some sort of cookie that is set in the @@ -575,12 +575,10 @@ static void pam_dom_forwarder(struct pam_auth_req *preq); static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) { struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; struct pam_auth_req *preq; struct pam_data *pd; uint8_t *body; size_t blen; - int timeout; int ret; uint32_t terminator = SSS_END_OF_PAM_REQUEST; preq = talloc_zero(cctx, struct pam_auth_req); @@ -663,267 +661,168 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) goto done; } - /* When auth is requested always search the provider first, - * do not rely on cached data unless the provider is completely - * offline */ - if (NEED_CHECK_PROVIDER(preq->domain->provider) && - (pam_cmd == SSS_PAM_AUTHENTICATE || pam_cmd == SSS_PAM_SETCRED)) { - - /* no need to re-check later on */ - preq->check_provider = false; - timeout = SSS_CLI_SOCKET_TIMEOUT/2; - - ret = sss_dp_send_acct_req(preq->cctx->rctx, preq, - pam_check_user_dp_callback, preq, - timeout, preq->domain->name, - false, SSS_DP_INITGROUPS, - preq->pd->user, 0); - } - else { - preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider); - - ret = sysdb_get_ctx_from_list(cctx->rctx->db_list, - preq->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - goto done; - } - ret = sysdb_getpwnam(preq, sysdb, - preq->domain, preq->pd->user, - pam_check_user_callback, preq); + ret = pam_check_user_search(preq); + if (ret == EOK) { + pam_dom_forwarder(preq); } done: - if (ret != EOK) { - switch (ret) { - case ENOENT: - pd->pam_status = PAM_USER_UNKNOWN; - default: - pd->pam_status = PAM_SYSTEM_ERR; - } - pam_reply(preq); - } - return EOK; + return pam_check_user_done(preq, ret); } -static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min, - const char *err_msg, void *ptr) +static int pam_check_user_search(struct pam_auth_req *preq) { - struct pam_auth_req *preq = talloc_get_type(ptr, struct pam_auth_req); + struct sss_domain_info *dom = preq->domain; + struct cli_ctx *cctx = preq->cctx; + const char *name = preq->pd->user; struct sysdb_ctx *sysdb; + time_t cacheExpire; int ret; - if (err_maj) { - DEBUG(2, ("Unable to get information from Data Provider\n" - "Error: %u, %u, %s\n", - (unsigned int)err_maj, (unsigned int)err_min, err_msg)); - } + while (dom) { + /* if it is a domainless search, skip domains that require fully + * qualified names instead */ + while (dom && !preq->pd->domain && dom->fqnames) { + dom = dom->next; + } - /* always try to see if we have the user in cache even if the provider - * returned an error */ - ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list, - preq->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - goto done; - } - ret = sysdb_getpwnam(preq, sysdb, - preq->domain, preq->pd->user, - pam_check_user_callback, preq); + if (!dom) break; -done: - if (ret != EOK) { - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - } -} + if (dom != preq->domain) { + /* make sure we reset the check_provider flag when we check + * a new domain */ + preq->check_provider = NEED_CHECK_PROVIDER(dom->provider); + } -static void pam_check_user_callback(void *ptr, int status, - struct ldb_result *res) -{ - struct pam_auth_req *preq = talloc_get_type(ptr, struct pam_auth_req); - struct sss_domain_info *dom; - struct sysdb_ctx *sysdb; - uint64_t cacheExpire; - bool call_provider = false; - time_t timeout; - int ret; + /* make sure to update the preq if we changed domain */ + preq->domain = dom; - if (status != LDB_SUCCESS) { - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - return; - } + /* TODO: check negative cache ? */ - timeout = SSS_CLI_SOCKET_TIMEOUT/2; + /* Always try to refresh the cache first on authentication */ + if (preq->check_provider && + (preq->pd->cmd == SSS_PAM_AUTHENTICATE || + preq->pd->cmd == SSS_PAM_SETCRED)) { - if (preq->check_provider) { - switch (res->count) { - case 0: - call_provider = true; + /* call provider first */ break; + } - case 1: - cacheExpire = ldb_msg_find_attr_as_uint64(res->msgs[0], + DEBUG(4, ("Requesting info for [%s@%s]\n", name, 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")); + preq->pd->pam_status = PAM_SYSTEM_ERR; + return EFAULT; + } + ret = sysdb_getpwnam(preq, sysdb, dom, name, &preq->res); + if (ret != EOK) { + DEBUG(1, ("Failed to make request to our cache!\n")); + return EIO; + } + + if (preq->res->count > 1) { + DEBUG(0, ("getpwnam call returned more than one result !?!\n")); + return ENOENT; + } + + if (preq->res->count == 0) { + /* if a multidomain search, try with next */ + if (!preq->pd->domain) { + dom = dom->next; + continue; + } + + DEBUG(2, ("No results for getpwnam call\n")); + + /* TODO: store negative cache ? */ + + return ENOENT; + } + + /* One result found */ + + /* if we need to check the remote account go on */ + if (preq->check_provider) { + cacheExpire = ldb_msg_find_attr_as_uint64(preq->res->msgs[0], SYSDB_CACHE_EXPIRE, 0); if (cacheExpire < time(NULL)) { - call_provider = true; + break; } - break; - - default: - DEBUG(1, ("check user call returned more than one result !?!\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - return; } + + DEBUG(6, ("Returning info for user [%s@%s]\n", name, dom->name)); + + return EOK; } - if (call_provider) { + if (preq->check_provider) { /* dont loop forever :-) */ preq->check_provider = false; - /* keep around current data in case backend is offline */ - if (res->count) { - preq->data = talloc_steal(preq, res); - } - ret = sss_dp_send_acct_req(preq->cctx->rctx, preq, pam_check_user_dp_callback, preq, - timeout, preq->domain->name, - false, SSS_DP_USER, - preq->pd->user, 0); + SSS_CLI_SOCKET_TIMEOUT/2, + dom->name, false, SSS_DP_USER, name, 0); if (ret != EOK) { DEBUG(3, ("Failed to dispatch request: %d(%s)\n", ret, strerror(ret))); preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); + return EIO; } - return; + /* tell caller we are in an async call */ + return EAGAIN; } - switch (res->count) { - case 0: - if (!preq->pd->domain) { - /* search next as the domain was unknown */ - - ret = EOK; - - /* skip domains that require FQnames or have negative caches */ - for (dom = preq->domain->next; dom; dom = dom->next) { - - if (dom->fqnames) continue; - -#if HAVE_NEG_CACHE - ncret = nss_ncache_check_user(nctx->ncache, - nctx->neg_timeout, - dom->name, cmdctx->name); - if (ncret == ENOENT) break; - - neghit = true; -#endif - break; - } -#if HAVE_NEG_CACHE - /* reset neghit if we still have a domain to check */ - if (dom) neghit = false; - - if (neghit) { - DEBUG(2, ("User [%s] does not exist! (negative cache)\n", - cmdctx->name)); - ret = ENOENT; - } -#endif - if (dom == NULL) { - DEBUG(2, ("No matching domain found for [%s], fail!\n", - preq->pd->user)); - ret = ENOENT; - } + DEBUG(2, ("No matching domain found for [%s], fail!\n", name)); + return ENOENT; +} - if (ret == EOK) { - preq->domain = dom; - preq->data = NULL; - - DEBUG(4, ("Requesting info for [%s@%s]\n", - preq->pd->user, preq->domain->name)); - - /* When auth is requested always search the provider first, - * do not rely on cached data unless the provider is - * completely offline */ - if (NEED_CHECK_PROVIDER(preq->domain->provider) && - (preq->pd->cmd == SSS_PAM_AUTHENTICATE || - preq->pd->cmd == SSS_PAM_SETCRED)) { - - /* no need to re-check later on */ - preq->check_provider = false; - - ret = sss_dp_send_acct_req(preq->cctx->rctx, preq, - pam_check_user_dp_callback, - preq, timeout, - preq->domain->name, - false, SSS_DP_USER, - preq->pd->user, 0); - } - else { - preq->check_provider = NEED_CHECK_PROVIDER(preq->domain->provider); +static int pam_check_user_done(struct pam_auth_req *preq, int ret) +{ + switch (ret) { + case EOK: + break; - ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list, - preq->domain, &sysdb); - if (ret != EOK) { - DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n")); - preq->pd->pam_status = PAM_SYSTEM_ERR; - pam_reply(preq); - return; - } - ret = sysdb_getpwnam(preq, sysdb, - preq->domain, preq->pd->user, - pam_check_user_callback, preq); - } - if (ret != EOK) { - DEBUG(1, ("Failed to make request to our cache!\n")); - } - } + case EAGAIN: + /* performing async request, just return */ + break; - /* we made another call, end here */ - if (ret == EOK) return; - } - else { - ret = ENOENT; - } + case ENOENT: + preq->pd->pam_status = PAM_USER_UNKNOWN; + pam_reply(preq); + break; - DEBUG(2, ("No results for check user call\n")); + default: + preq->pd->pam_status = PAM_SYSTEM_ERR; + pam_reply(preq); + break; + } -#if HAVE_NEG_CACHE - /* 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 (ret != EOK) { - NSS_CMD_FATAL_ERROR(cctx); - } - } -#endif + return EOK; +} - if (ret != EOK) { - if (ret == ENOENT) { - preq->pd->pam_status = PAM_USER_UNKNOWN; - } else { - preq->pd->pam_status = PAM_SYSTEM_ERR; - } - pam_reply(preq); - return; - } - break; +static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min, + const char *err_msg, void *ptr) +{ + struct pam_auth_req *preq = talloc_get_type(ptr, struct pam_auth_req); + int ret; - case 1: + if (err_maj) { + DEBUG(2, ("Unable to get information from Data Provider\n" + "Error: %u, %u, %s\n", + (unsigned int)err_maj, (unsigned int)err_min, err_msg)); + } - /* BINGO */ + ret = pam_check_user_search(preq); + if (ret == EOK) { pam_dom_forwarder(preq); - return; + } - default: - DEBUG(1, ("check user call returned more than one result !?!\n")); + ret = pam_check_user_done(preq, ret); + if (ret) { preq->pd->pam_status = PAM_SYSTEM_ERR; pam_reply(preq); } diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c index 1ce8a3255..acb96b2e8 100644 --- a/src/tests/sysdb-tests.c +++ b/src/tests/sysdb-tests.c @@ -306,31 +306,6 @@ static int test_remove_group_by_gid(struct test_data *data) return ret; } -static void test_getpwent(void *pvt, int error, struct ldb_result *res) -{ - struct test_data *data = talloc_get_type(pvt, struct test_data); - data->finished = true; - - if (error != EOK) { - data->error = error; - return; - } - - switch (res->count) { - case 0: - data->error = ENOENT; - break; - - case 1: - data->uid = ldb_msg_find_attr_as_uint(res->msgs[0], SYSDB_UIDNUM, 0); - break; - - default: - data->error = EFAULT; - break; - } -} - static void test_getgrent(void *pvt, int error, struct ldb_result *res) { struct test_data *data = talloc_get_type(pvt, struct test_data); @@ -838,8 +813,9 @@ END_TEST START_TEST (test_sysdb_getpwnam) { struct sysdb_test_ctx *test_ctx; - struct test_data *data; - struct test_data *data_uc; + struct ldb_result *res; + const char *username; + uid_t uid; int ret; /* Setup */ @@ -849,45 +825,42 @@ START_TEST (test_sysdb_getpwnam) return; } - data = talloc_zero(test_ctx, struct test_data); - data->ctx = test_ctx; - data->username = talloc_asprintf(data, "testuser%d", _i); + username = talloc_asprintf(test_ctx, "testuser%d", _i); ret = sysdb_getpwnam(test_ctx, test_ctx->sysdb, - data->ctx->domain, - data->username, - test_getpwent, - data); - if (ret == EOK) { - ret = test_loop(data); - } - + test_ctx->domain, + username, &res); if (ret) { fail("sysdb_getpwnam failed for username %s (%d: %s)", - data->username, ret, strerror(ret)); + username, ret, strerror(ret)); + goto done; + } + + if (res->count != 1) { + fail("Invalid number of replies. Expected 1, got %d", res->count); goto done; } - fail_unless(data->uid == _i, - "Did not find the expected UID"); + + uid = ldb_msg_find_attr_as_uint(res->msgs[0], SYSDB_UIDNUM, 0); + fail_unless(uid == _i, "Did not find the expected UID"); /* Search for the user with the wrong case */ - data_uc = talloc_zero(test_ctx, struct test_data); - data_uc->ctx = test_ctx; - data_uc->username = talloc_asprintf(data_uc, "TESTUSER%d", _i); + username = talloc_asprintf(test_ctx, "TESTUSER%d", _i); ret = sysdb_getpwnam(test_ctx, test_ctx->sysdb, - data_uc->ctx->domain, - data_uc->username, - test_getpwent, - data_uc); - if (ret == EOK) { - ret = test_loop(data_uc); + test_ctx->domain, + username, &res); + if (ret) { + fail("sysdb_getpwnam failed for username %s (%d: %s)", + username, ret, strerror(ret)); + goto done; } - fail_unless(ret == ENOENT, - "The upper-case username search should fail. "); + if (res->count != 0) { + fail("The upper-case username search should fail."); + } done: talloc_free(test_ctx); diff --git a/src/tools/sss_sync_ops.c b/src/tools/sss_sync_ops.c index f9230a389..70203cf2f 100644 --- a/src/tools/sss_sync_ops.c +++ b/src/tools/sss_sync_ops.c @@ -591,125 +591,79 @@ int groupdel(TALLOC_CTX *mem_ctx, /* * getpwnam, getgrnam and friends */ -static void sss_getpwnam_done(void *ptr, int status, - struct ldb_result *lrs); - int sysdb_getpwnam_sync(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct sysdb_ctx *sysdb, const char *name, struct sss_domain_info *domain, - struct ops_ctx **out) -{ - int ret; - struct sync_op_res *res = NULL; - - res = talloc_zero(mem_ctx, struct sync_op_res); - if (!res) { - return ENOMEM; - } - - if (out == NULL) { - DEBUG(1, ("NULL passed for storage pointer\n")); - return EINVAL; - } - res->data = *out; - - ret = sysdb_getpwnam(mem_ctx, - sysdb, - domain, - name, - sss_getpwnam_done, - res); - - SYNC_LOOP(res, ret); - - return ret; -} - -static void sss_getpwnam_done(void *ptr, int status, - struct ldb_result *lrs) + struct ops_ctx *out) { - struct sync_op_res *res = talloc_get_type(ptr, struct sync_op_res ); + struct ldb_result *res; const char *str; + int ret; - res->done = true; - - if (status != LDB_SUCCESS) { - res->error = status; - return; + ret = sysdb_getpwnam(mem_ctx, sysdb, domain, name, &res); + if (ret) { + return ret; } - switch (lrs->count) { - case 0: - DEBUG(1, ("No result for sysdb_getpwnam call\n")); - res->error = ENOENT; - break; + switch (res->count) { + case 0: + DEBUG(1, ("No result for sysdb_getpwnam call\n")); + return ENOENT; - case 1: - res->error = EOK; - /* fill ops_ctx */ - res->data->uid = ldb_msg_find_attr_as_uint64(lrs->msgs[0], - SYSDB_UIDNUM, 0); + case 1: + /* fill ops_ctx */ + out->uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 0); - res->data->gid = ldb_msg_find_attr_as_uint64(lrs->msgs[0], - SYSDB_GIDNUM, 0); + out->gid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 0); - str = ldb_msg_find_attr_as_string(lrs->msgs[0], - SYSDB_NAME, NULL); - res->data->name = talloc_strdup(res, str); - if (res->data->name == NULL) { - res->error = ENOMEM; - return; - } + str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL); + out->name = talloc_strdup(out, str); + if (out->name == NULL) { + return ENOMEM; + } - str = ldb_msg_find_attr_as_string(lrs->msgs[0], - SYSDB_GECOS, NULL); - res->data->gecos = talloc_strdup(res, str); - if (res->data->gecos == NULL) { - res->error = ENOMEM; - return; - } + str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_GECOS, NULL); + out->gecos = talloc_strdup(out, str); + if (out->gecos == NULL) { + return ENOMEM; + } - str = ldb_msg_find_attr_as_string(lrs->msgs[0], - SYSDB_HOMEDIR, NULL); - res->data->home = talloc_strdup(res, str); - if (res->data->home == NULL) { - res->error = ENOMEM; - return; - } + str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_HOMEDIR, NULL); + out->home = talloc_strdup(out, str); + if (out->home == NULL) { + return ENOMEM; + } - str = ldb_msg_find_attr_as_string(lrs->msgs[0], - SYSDB_SHELL, NULL); - res->data->shell = talloc_strdup(res, str); - if (res->data->shell == NULL) { - res->error = ENOMEM; - return; - } + str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SHELL, NULL); + out->shell = talloc_strdup(out, str); + if (out->shell == NULL) { + return ENOMEM; + } - str = ldb_msg_find_attr_as_string(lrs->msgs[0], - SYSDB_DISABLED, NULL); - if (str == NULL) { - res->data->lock = DO_UNLOCK; - } else { - if (strcasecmp(str, "true") == 0) { - res->data->lock = DO_LOCK; - } else if (strcasecmp(str, "false") == 0) { - res->data->lock = DO_UNLOCK; - } else { /* Invalid value */ - DEBUG(2, ("Invalid value for %s attribute: %s\n", - SYSDB_DISABLED, str ? str : "NULL")); - res->error = EIO; - return; - } + str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_DISABLED, NULL); + if (str == NULL) { + out->lock = DO_UNLOCK; + } else { + if (strcasecmp(str, "true") == 0) { + out->lock = DO_LOCK; + } else if (strcasecmp(str, "false") == 0) { + out->lock = DO_UNLOCK; + } else { /* Invalid value */ + DEBUG(2, ("Invalid value for %s attribute: %s\n", + SYSDB_DISABLED, str ? str : "NULL")); + return EIO; } - break; + } + break; - default: - DEBUG(1, ("More than one result for sysdb_getpwnam call\n")); - res->error = EIO; - break; + default: + DEBUG(1, ("More than one result for sysdb_getpwnam call\n")); + return EIO; } + + return EOK; } static void sss_getgrnam_done(void *ptr, int status, diff --git a/src/tools/sss_sync_ops.h b/src/tools/sss_sync_ops.h index b2bb51c5c..98fbc47f2 100644 --- a/src/tools/sss_sync_ops.h +++ b/src/tools/sss_sync_ops.h @@ -97,7 +97,7 @@ int sysdb_getpwnam_sync(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, const char *name, struct sss_domain_info *domain, - struct ops_ctx **out); + struct ops_ctx *out); int sysdb_getgrnam_sync(TALLOC_CTX *mem_ctx, struct tevent_context *ev, diff --git a/src/tools/sss_useradd.c b/src/tools/sss_useradd.c index 6198dcae3..0dc1993e5 100644 --- a/src/tools/sss_useradd.c +++ b/src/tools/sss_useradd.c @@ -292,7 +292,7 @@ int main(int argc, const char **argv) tctx->sysdb, tctx->octx->name, tctx->local, - &tctx->octx); + tctx->octx); if (ret != EOK) { ERROR("Cannot get info about the user\n"); ret = EXIT_FAILURE; diff --git a/src/tools/sss_userdel.c b/src/tools/sss_userdel.c index 890b4fec0..55c41c240 100644 --- a/src/tools/sss_userdel.c +++ b/src/tools/sss_userdel.c @@ -236,7 +236,7 @@ int main(int argc, const char **argv) tctx->sysdb, tctx->octx->name, tctx->local, - &tctx->octx); + tctx->octx); if (ret != EOK) { /* Error message will be printed in the switch */ goto done; diff --git a/src/tools/sss_usermod.c b/src/tools/sss_usermod.c index 88e3fda3c..43e685c55 100644 --- a/src/tools/sss_usermod.c +++ b/src/tools/sss_usermod.c @@ -143,7 +143,7 @@ int main(int argc, const char **argv) /* check the username to be able to give sensible error message */ ret = sysdb_getpwnam_sync(tctx, tctx->ev, tctx->sysdb, tctx->octx->name, tctx->local, - &tctx->octx); + tctx->octx); if (ret != EOK) { ERROR("Cannot find user in local domain, " "modifying users is allowed only in local domain\n"); -- cgit