summaryrefslogtreecommitdiffstats
path: root/src/responder/pam
diff options
context:
space:
mode:
Diffstat (limited to 'src/responder/pam')
-rw-r--r--src/responder/pam/pamsrv.h1
-rw-r--r--src/responder/pam/pamsrv_cmd.c337
2 files changed, 119 insertions, 219 deletions
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);
}