From 66c727e0e7b34d19cdb8dbdc0a0fae15d9d5ff25 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 11 May 2009 09:08:31 -0400 Subject: Move actual password caching into sysdb Convert auth modules to do the caching themselves --- server/providers/ldap/ldap_auth.c | 123 +++++++++++++++++++++++++++++++++++-- server/providers/proxy.c | 124 ++++++++++++++++++++++++++++++++++---- 2 files changed, 230 insertions(+), 17 deletions(-) (limited to 'server/providers') diff --git a/server/providers/ldap/ldap_auth.c b/server/providers/ldap/ldap_auth.c index 6a4dc895f..0c2541f1b 100644 --- a/server/providers/ldap/ldap_auth.c +++ b/server/providers/ldap/ldap_auth.c @@ -283,6 +283,8 @@ static int sdap_bind(struct sdap_req *lr) return LDAP_SUCCESS; } +static void sdap_cache_password(struct sdap_req *lr); + static void sdap_pam_loop(struct tevent_context *ev, struct tevent_fd *te, uint16_t fd, void *pvt) { @@ -290,7 +292,6 @@ static void sdap_pam_loop(struct tevent_context *ev, struct tevent_fd *te, int pam_status=PAM_SUCCESS; int ldap_ret; struct sdap_req *lr; - struct pam_data *pd; struct be_req *req; LDAPMessage *result=NULL; LDAPMessage *msg=NULL; @@ -573,11 +574,17 @@ done: talloc_free(filter); if (lr->ldap != NULL) ldap_unbind_ext(lr->ldap, NULL, NULL); req = lr->req; - pd = talloc_get_type(lr->req->req_data, struct pam_data); - pd->pam_status = pam_status; + lr->pd->pam_status = pam_status; + + if (((lr->pd->cmd == SSS_PAM_AUTHENTICATE) || + (lr->pd->cmd == SSS_PAM_CHAUTHTOK)) && + (lr->pd->pam_status == PAM_SUCCESS) && + lr->req->be_ctx->domain->cache_credentials) { + sdap_cache_password(lr); + return; + } talloc_free(lr); - req->fn(req, pam_status, NULL); } @@ -617,8 +624,7 @@ static void sdap_start(struct tevent_context *ev, struct tevent_timer *te, done: if (lr->ldap != NULL ) ldap_unbind_ext(lr->ldap, NULL, NULL); req = lr->req; - pd = talloc_get_type(lr->req->req_data, struct pam_data); - pd->pam_status = pam_status; + lr->pd->pam_status = pam_status; talloc_free(lr); @@ -666,6 +672,111 @@ done: req->fn(req, pam_status, NULL); } +struct sdap_pw_cache { + struct sysdb_req *sysreq; + struct sdap_req *lr; +}; + +static int password_destructor(void *memctx) +{ + char *password = (char *)memctx; + int i; + + /* zero out password */ + for (i = 0; password[i]; i++) password[i] = '\0'; + + return 0; +} + +static void sdap_reply(struct be_req *req, int ret, char *errstr) +{ + req->fn(req, ret, errstr); +} + +static void sdap_cache_pw_callback(void *pvt, int error, + struct ldb_result *ignore) +{ + struct sdap_pw_cache *data = talloc_get_type(pvt, struct sdap_pw_cache); + if (error != EOK) { + DEBUG(2, ("Failed to cache password (%d)[%s]!?\n", + error, strerror(error))); + } + + sysdb_transaction_done(data->sysreq, error); + + /* password caching failures are not fatal errors */ + sdap_reply(data->lr->req, data->lr->pd->pam_status, NULL); +} + +static void sdap_cache_pw_op(struct sysdb_req *req, void *pvt) +{ + struct sdap_pw_cache *data = talloc_get_type(pvt, struct sdap_pw_cache); + struct pam_data *pd; + const char *username; + const char *password; + int ret; + + data->sysreq = req; + + pd = data->lr->pd; + username = pd->user; + + if (pd->cmd == SSS_PAM_AUTHENTICATE) { + password = talloc_strndup(data, pd->authtok, pd->authtok_size); + } + else if (pd->cmd == SSS_PAM_CHAUTHTOK) { + password = talloc_strndup(data, pd->newauthtok, pd->newauthtok_size); + } + else { + DEBUG(1, ("Attempting password caching on invalid Op!\n")); + /* password caching failures are not fatal errors */ + sdap_reply(data->lr->req, data->lr->pd->pam_status, NULL); + return; + } + + if (!password) { + DEBUG(2, ("Out of Memory!\n")); + /* password caching failures are not fatal errors */ + sdap_reply(data->lr->req, data->lr->pd->pam_status, NULL); + return; + } + + ret = sysdb_set_cached_password(req, + data->lr->req->be_ctx->domain, + username, + password, + sdap_cache_pw_callback, data); + if (ret != EOK) { + /* password caching failures are not fatal errors */ + sdap_reply(data->lr->req, data->lr->pd->pam_status, NULL); + } +} + +static void sdap_cache_password(struct sdap_req *lr) +{ + struct sdap_pw_cache *data; + int ret; + + data = talloc_zero(lr, struct sdap_pw_cache); + if (!data) { + DEBUG(2, ("Out of Memory!\n")); + /* password caching failures are not fatal errors */ + sdap_reply(data->lr->req, lr->pd->pam_status, NULL); + return; + } + data->lr = lr; + + ret = sysdb_transaction(data, lr->req->be_ctx->sysdb, + sdap_cache_pw_op, data); + + if (ret != EOK) { + DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", + ret, strerror(ret))); + /* password caching failures are not fatal errors */ + sdap_reply(data->lr->req, lr->pd->pam_status, NULL); + } +} + static void sdap_shutdown(struct be_req *req) { /* TODO: Clean up any internal data */ diff --git a/server/providers/proxy.c b/server/providers/proxy.c index 0fea89df9..175670ada 100644 --- a/server/providers/proxy.c +++ b/server/providers/proxy.c @@ -70,6 +70,12 @@ struct authtok_conv { uint8_t *authtok; }; +static void cache_password(struct be_req *req, + char *username, + struct authtok_conv *ac); +static void proxy_reply(struct be_req *req, + int error, const char *errstr); + static int proxy_internal_conv(int num_msg, const struct pam_message **msgm, struct pam_response **response, void *appdata_ptr) { @@ -121,12 +127,13 @@ static void proxy_pam_handler(struct be_req *req) { struct pam_conv conv; struct pam_data *pd; struct proxy_auth_ctx *ctx;; + bool cache_auth_data = false; ctx = talloc_get_type(req->be_ctx->pvt_auth_data, struct proxy_auth_ctx); pd = talloc_get_type(req->req_data, struct pam_data); conv.conv=proxy_internal_conv; - auth_data = talloc_zero(req->be_ctx, struct authtok_conv); + auth_data = talloc_zero(req, struct authtok_conv); conv.appdata_ptr=auth_data; ret = pam_start(ctx->pam_target, pd->user, &conv, &pamh); @@ -148,7 +155,11 @@ static void proxy_pam_handler(struct be_req *req) { case SSS_PAM_AUTHENTICATE: auth_data->authtok_size = pd->authtok_size; auth_data->authtok = pd->authtok; - pam_status=pam_authenticate(pamh, 0); + pam_status = pam_authenticate(pamh, 0); + if ((pam_status == PAM_SUCCESS) && + (req->be_ctx->domain->cache_credentials)) { + cache_auth_data = true; + } break; case SSS_PAM_SETCRED: pam_status=pam_setcred(pamh, 0); @@ -166,12 +177,16 @@ static void proxy_pam_handler(struct be_req *req) { if (pd->priv != 1) { auth_data->authtok_size = pd->authtok_size; auth_data->authtok = pd->authtok; - pam_status=pam_authenticate(pamh, 0); + pam_status = pam_authenticate(pamh, 0); if (pam_status != PAM_SUCCESS) break; } auth_data->authtok_size = pd->newauthtok_size; auth_data->authtok = pd->newauthtok; - pam_status=pam_chauthtok(pamh, 0); + pam_status = pam_chauthtok(pamh, 0); + if ((pam_status == PAM_SUCCESS) && + (req->be_ctx->domain->cache_credentials)) { + cache_auth_data = true; + } break; default: DEBUG(1, ("unknown PAM call")); @@ -191,15 +206,14 @@ static void proxy_pam_handler(struct be_req *req) { pam_status = PAM_SYSTEM_ERR; } - talloc_free(auth_data); - pd->pam_status = pam_status; - req->fn(req, EOK, NULL); -} -static void proxy_reply(struct be_req *req, int error, const char *errstr) -{ - return req->fn(req, error, errstr); + if (cache_auth_data) { + cache_password(req, pd->user, auth_data); + return; + } + + proxy_reply(req, EOK, NULL); } struct proxy_data { @@ -222,6 +236,94 @@ struct proxy_data { sysdb_callback_t next_fn; }; +static void proxy_reply(struct be_req *req, int error, const char *errstr) +{ + return req->fn(req, error, errstr); +} + +static void cache_pw_return(void *pvt, int error, struct ldb_result *ignore) +{ + struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + const char *err = "Success"; + + if (error != EOK) { + DEBUG(2, ("Failed to cache password (%d)[%s]!?\n", + error, strerror(error))); + } + + sysdb_transaction_done(data->sysreq, error); + + /* password caching failures are not fatal errors */ + return proxy_reply(data->req, EOK, NULL); +} + +static void cache_pw_op(struct sysdb_req *req, void *pvt) +{ + struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); + int ret; + + data->sysreq = req; + + ret = sysdb_set_cached_password(req, + data->req->be_ctx->domain, + data->pwd->pw_name, + data->pwd->pw_passwd, + cache_pw_return, data); + if (ret != EOK) { + /* password caching failures are not fatal errors */ + proxy_reply(data->req, EOK, NULL); + } +} + +static int password_destructor(void *memctx) +{ + char *password = (char *)memctx; + int i; + + /* zero out password */ + for (i = 0; password[i]; i++) password[i] = '\0'; + + return 0; +} + +static void cache_password(struct be_req *req, + char *username, + struct authtok_conv *ac) +{ + struct proxy_data *data; + struct proxy_ctx *ctx; + int ret; + + ctx = talloc_get_type(req->be_ctx->pvt_id_data, struct proxy_ctx); + + data = talloc_zero(req, struct proxy_data); + if (!data) + return proxy_reply(req, ENOMEM, "Out of memory"); + data->req = req; + data->ctx = ctx; + data->pwd = talloc(data, struct passwd); + if (!data->pwd) + return proxy_reply(req, ENOMEM, "Out of memory"); + data->pwd->pw_name = username; + data->pwd->pw_passwd = talloc_size(data, ac->authtok_size + 1); + if (!data->pwd->pw_passwd) + return proxy_reply(req, ENOMEM, "Out of memory"); + memcpy(data->pwd->pw_passwd, ac->authtok, ac->authtok_size); + data->pwd->pw_passwd[ac->authtok_size] = '\0'; + + talloc_set_destructor((TALLOC_CTX *)data->pwd->pw_passwd, + password_destructor); + + ret = sysdb_transaction(data, req->be_ctx->sysdb, cache_pw_op, data); + + if (ret != EOK) { + DEBUG(1, ("Failed to start transaction (%d)[%s]!?\n", + ret, strerror(ret))); + /* password caching failures are not fatal errors */ + return proxy_reply(req, EOK, NULL); + } +} + static void proxy_return(void *pvt, int error, struct ldb_result *ignore) { struct proxy_data *data = talloc_get_type(pvt, struct proxy_data); -- cgit