Hi,
these are the two patches for the IPA password migration for master. Because master already contains the sync sysdb patches it is not easy to rebase the first patch from the sssd-1-2 branch to master so I rewrote it. The second patch is mainly the same with a substitution of an async sysdb call with his sync version.
bye, Sumit
sorry, I forget to remove some unneeded code.
New version attached.
bye, Sumit On Wed, Apr 28, 2010 at 05:30:24PM +0200, Sumit Bose wrote:
Hi,
these are the two patches for the IPA password migration for master. Because master already contains the sync sysdb patches it is not easy to rebase the first patch from the sssd-1-2 branch to master so I rewrote it. The second patch is mainly the same with a substitution of an async sysdb call with his sync version.
bye, Sumit
From 1a00bf32416ea7d0fd416e6b094774c68dd8b6bb Mon Sep 17 00:00:00 2001 From: Sumit Bose sbose@redhat.com Date: Wed, 28 Apr 2010 15:12:57 +0200 Subject: [PATCH 1/2] Make Kerberos authentication a tevent_req
To allow other providers to include Kerberos authentication the main part is put into a tevent request.
src/providers/krb5/krb5_auth.c | 553 ++++++++++++++++++++++++---------------- src/providers/krb5/krb5_auth.h | 7 +- 2 files changed, 345 insertions(+), 215 deletions(-)
diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c index e1aaebf..a3ae394 100644 --- a/src/providers/krb5/krb5_auth.c +++ b/src/providers/krb5/krb5_auth.c @@ -6,7 +6,7 @@ Authors: Sumit Bose sbose@redhat.com
- Copyright (C) 2009 Red Hat
Copyright (C) 2009-2010 Red Hat
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
@@ -320,13 +320,58 @@ static struct krb5_ctx *get_krb5_ctx(struct be_req *be_req)
static void krb_reply(struct be_req *req, int dp_err, int result);
+static int krb5_cleanup(void *ptr) +{
- struct krb5child_req *kr = talloc_get_type(ptr, struct krb5child_req);
- if (kr == NULL) return EOK;
- child_cleanup(kr->read_from_child_fd, kr->write_to_child_fd);
- memset(kr, 0, sizeof(struct krb5child_req));
- return EOK;
+}
+static errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd,
struct krb5_ctx *krb5_ctx,
struct krb5child_req **krb5_req)
+{
- struct krb5child_req *kr = NULL;
- kr = talloc_zero(mem_ctx, struct krb5child_req);
- if (kr == NULL) {
DEBUG(1, ("talloc failed.\n"));
return ENOMEM;
- }
- kr->read_from_child_fd = -1;
- kr->write_to_child_fd = -1;
- kr->is_offline = false;
- kr->active_ccache_present = true;
- talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup);
- kr->pd = pd;
- kr->krb5_ctx = krb5_ctx;
- *krb5_req = kr;
- return EOK;
+}
+struct handle_child_state {
- struct tevent_context *ev;
- struct krb5child_req *kr;
- uint8_t *buf;
- ssize_t len;
+};
static void krb5_child_timeout(struct tevent_context *ev, struct tevent_timer *te, struct timeval tv, void *pvt) {
- struct krb5child_req *kr = talloc_get_type(pvt, struct krb5child_req);
- struct be_req *be_req = kr->req;
- struct pam_data *pd = kr->pd;
struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
struct handle_child_state *state = tevent_req_data(req,
struct handle_child_state);
struct krb5child_req *kr = state->kr; int ret;
if (kr->timeout_handler == NULL) {
@@ -340,25 +385,24 @@ static void krb5_child_timeout(struct tevent_context *ev, DEBUG(1, ("kill failed [%d][%s].\n", errno, strerror(errno))); }
- talloc_zfree(kr);
- pd->pam_status = PAM_AUTHINFO_UNAVAIL;
- be_mark_offline(be_req->be_ctx);
- krb_reply(be_req, DP_ERR_OFFLINE, pd->pam_status);
- tevent_req_error(req, ETIMEDOUT);
}
-static errno_t activate_child_timeout_handler(struct krb5child_req *kr) +static errno_t activate_child_timeout_handler(struct tevent_req *req,
struct tevent_context *ev,
struct krb5child_req *kr)
{ struct timeval tv;
struct handle_child_state *state = tevent_req_data(req,
struct handle_child_state);
tv = tevent_timeval_current(); tv = tevent_timeval_add(&tv, dp_opt_get_int(kr->krb5_ctx->opts, KRB5_AUTH_TIMEOUT), 0);
- kr->timeout_handler = tevent_add_timer(kr->req->be_ctx->ev, kr, tv,
krb5_child_timeout, kr);
- kr->timeout_handler = tevent_add_timer(ev, state, tv,
if (kr->timeout_handler == NULL) { DEBUG(1, ("tevent_add_timer failed.\n")); return ENOMEM;krb5_child_timeout, req);
@@ -367,61 +411,8 @@ static errno_t activate_child_timeout_handler(struct krb5child_req *kr) return EOK; }
-static int krb5_cleanup(void *ptr) -{
- struct krb5child_req *kr = talloc_get_type(ptr, struct krb5child_req);
- if (kr == NULL) return EOK;
- child_cleanup(kr->read_from_child_fd, kr->write_to_child_fd);
- memset(kr, 0, sizeof(struct krb5child_req));
- return EOK;
-}
-static errno_t krb5_setup(struct be_req *req, struct krb5child_req **krb5_req) -{
- struct krb5child_req *kr = NULL;
- struct krb5_ctx *krb5_ctx;
- struct pam_data *pd;
- errno_t err;
- pd = talloc_get_type(req->req_data, struct pam_data);
- krb5_ctx = get_krb5_ctx(req);
- if (krb5_ctx == NULL) {
DEBUG(1, ("Kerberos context not available.\n"));
err = EINVAL;
goto failed;
- }
- kr = talloc_zero(req, struct krb5child_req);
- if (kr == NULL) {
DEBUG(1, ("talloc failed.\n"));
err = ENOMEM;
goto failed;
- }
- kr->read_from_child_fd = -1;
- kr->write_to_child_fd = -1;
- kr->is_offline = false;
- kr->active_ccache_present = true;
- talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup);
- kr->pd = pd;
- kr->req = req;
- kr->krb5_ctx = krb5_ctx;
- *krb5_req = kr;
- return EOK;
-failed:
- talloc_zfree(kr);
- return err;
-}
-static errno_t fork_child(struct krb5child_req *kr) +static errno_t fork_child(struct tevent_req *req, struct tevent_context *ev,
struct krb5child_req *kr)
{ int pipefd_to_child[2]; int pipefd_from_child[2]; @@ -476,7 +467,7 @@ static errno_t fork_child(struct krb5child_req *kr) fd_nonblocking(kr->read_from_child_fd); fd_nonblocking(kr->write_to_child_fd);
err = activate_child_timeout_handler(kr);
err = activate_child_timeout_handler(req, ev, kr); if (err != EOK) { DEBUG(1, ("activate_child_timeout_handler failed.\n")); }
@@ -490,13 +481,6 @@ static errno_t fork_child(struct krb5child_req *kr) return EOK; }
-struct handle_child_state {
- struct tevent_context *ev;
- struct krb5child_req *kr;
- uint8_t *buf;
- ssize_t len;
-};
static void handle_child_step(struct tevent_req *subreq); static void handle_child_done(struct tevent_req *subreq);
@@ -525,7 +509,7 @@ static struct tevent_req *handle_child_send(TALLOC_CTX *mem_ctx, goto fail; }
- ret = fork_child(kr);
- ret = fork_child(req, ev, kr); if (ret != EOK) { DEBUG(1, ("fork_child failed.\n")); goto fail;
@@ -610,27 +594,65 @@ static int handle_child_recv(struct tevent_req *req, return EOK; }
-static void krb5_resolve_kdc_done(struct tevent_req *req); -static void krb5_resolve_kpasswd_done(struct tevent_req *req); -static void krb5_find_ccache_step(struct krb5child_req *kr); -static void krb5_save_ccname_done(struct krb5child_req *kr); +static void krb5_resolve_kdc_done(struct tevent_req *subreq); +static void krb5_resolve_kpasswd_done(struct tevent_req *subreq); +static void krb5_find_ccache_step(struct tevent_req *req); +static void krb5_save_ccname_done(struct tevent_req *req); static void krb5_child_done(struct tevent_req *req);
-void krb5_pam_handler(struct be_req *be_req) -{ +struct krb5_auth_state {
- struct tevent_context *ev;
- struct be_ctx *be_ctx; struct pam_data *pd;
- struct krb5_ctx *krb5_ctx;
- struct krb5child_req *kr;
- int pam_status;
- int dp_err;
+};
+int krb5_auth_recv(struct tevent_req *req, int *pam_status, int *dp_err) +{
- struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
- *pam_status = state->pam_status;
- *dp_err = state->dp_err;
- TEVENT_REQ_RETURN_ON_ERROR(req);
- return EOK;
+}
+struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct be_ctx *be_ctx,
struct pam_data *pd,
struct krb5_ctx *krb5_ctx)
+{ const char **attrs;
- int pam_status = PAM_SYSTEM_ERR;
- int dp_err = DP_ERR_FATAL;
- struct krb5_auth_state *state; struct ldb_result *res; struct krb5child_req *kr = NULL; const char *ccache_file = NULL; const char *realm; krb5_error_code kerr; struct tevent_req *req;
- struct tevent_req *subreq; int ret;
- pd = talloc_get_type(be_req->req_data, struct pam_data);
req = tevent_req_create(mem_ctx, &state, struct krb5_auth_state);
if (req == NULL) {
DEBUG(1, ("tevent_req_create failed.\n"));
return NULL;
}
state->ev = ev;
state->be_ctx = be_ctx;
state->pd = pd;
state->krb5_ctx = krb5_ctx;
state->kr = NULL;
state->pam_status = PAM_SYSTEM_ERR;
state->dp_err = DP_ERR_FATAL;
switch (pd->cmd) { case SSS_PAM_AUTHENTICATE:
@@ -639,8 +661,9 @@ void krb5_pam_handler(struct be_req *be_req) case SSS_PAM_CHAUTHTOK_PRELIM: if (pd->priv == 1 && pd->authtok_size == 0) { DEBUG(4, ("Password reset by root is not supported.\n"));
pam_status = PAM_PERM_DENIED;
dp_err = DP_ERR_OK;
state->pam_status = PAM_PERM_DENIED;
state->dp_err = DP_ERR_OK;
ret = EOK; goto done; } break;
@@ -648,26 +671,29 @@ void krb5_pam_handler(struct be_req *be_req) case SSS_PAM_SETCRED: case SSS_PAM_OPEN_SESSION: case SSS_PAM_CLOSE_SESSION:
pam_status = PAM_SUCCESS;
dp_err = DP_ERR_OK;
state->pam_status = PAM_SUCCESS;
state->dp_err = DP_ERR_OK;
ret = EOK; goto done; break; default: DEBUG(4, ("krb5 does not handles pam task %d.\n", pd->cmd));
pam_status = PAM_MODULE_UNKNOWN;
dp_err = DP_ERR_OK;
state->pam_status = PAM_MODULE_UNKNOWN;
state->dp_err = DP_ERR_OK;
}ret = EOK; goto done;
- if (be_is_offline(be_req->be_ctx) &&
- if (be_is_offline(be_ctx) && (pd->cmd == SSS_PAM_CHAUTHTOK || pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM)) { DEBUG(9, ("Password changes are not possible while offline.\n"));
pam_status = PAM_AUTHINFO_UNAVAIL;
dp_err = DP_ERR_OFFLINE;
state->pam_status = PAM_AUTHINFO_UNAVAIL;
state->dp_err = DP_ERR_OFFLINE;
}ret = EOK; goto done;
- attrs = talloc_array(be_req, const char *, 6);
- attrs = talloc_array(state, const char *, 6); if (attrs == NULL) { goto done; }
@@ -679,40 +705,45 @@ void krb5_pam_handler(struct be_req *be_req) attrs[4] = SYSDB_GIDNUM; attrs[5] = NULL;
- ret = sysdb_get_user_attr(be_req, be_req->be_ctx->sysdb,
be_req->be_ctx->domain, pd->user,
attrs, &res);
- if (ret) {
DEBUG(5, ("sysdb search for upn of user [%s] failed.\n", pd->user));
- ret = krb5_setup(state, pd, krb5_ctx, &state->kr);
- if (ret != EOK) {
}DEBUG(1, ("krb5_setup failed.\n")); goto done;
- kr = state->kr;
- ret = krb5_setup(be_req, &kr);
- if (ret != EOK) {
DEBUG(1, ("krb5_setup failed.\n"));
goto failed;
- ret = sysdb_get_user_attr(state, be_ctx->sysdb, be_ctx->domain,
state->pd->user, attrs, &res);
- if (ret) {
DEBUG(5, ("sysdb search for upn of user [%s] failed.\n", pd->user));
state->pam_status = PAM_SYSTEM_ERR;
state->dp_err = DP_ERR_OK;
}goto done;
- realm = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_REALM);
- realm = dp_opt_get_cstring(krb5_ctx->opts, KRB5_REALM); if (realm == NULL) { DEBUG(1, ("Missing Kerberos realm.\n"));
goto failed;
ret = ENOENT;
goto done;
}
switch (res->count) { case 0: DEBUG(5, ("No attributes for user [%s] found.\n", pd->user));
goto failed;
ret = ENOENT;
goto done; break;
case 1: kr->upn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_UPN, NULL); if (kr->upn == NULL) { /* NOTE: this is a hack, works only in some environments */
kr->upn = talloc_asprintf(be_req, "%s@%s", pd->user, realm);
kr->upn = talloc_asprintf(kr, "%s@%s", pd->user, realm); if (kr->upn == NULL) { DEBUG(1, ("failed to build simple upn.\n"));
goto failed;
ret = ENOMEM;
goto done; } DEBUG(9, ("Using simple UPN [%s].\n", kr->upn)); }
@@ -726,13 +757,15 @@ void krb5_pam_handler(struct be_req *be_req) kr->uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 0); if (kr->uid == 0) { DEBUG(4, ("UID for user [%s] not known.\n", pd->user));
goto failed;
ret = ENOENT;
goto done; } kr->gid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 0); if (kr->gid == 0) { DEBUG(4, ("GID for user [%s] not known.\n", pd->user));
goto failed;
ret = ENOENT;
goto done; } ccache_file = ldb_msg_find_attr_as_string(res->msgs[0],
@@ -743,14 +776,15 @@ void krb5_pam_handler(struct be_req *be_req) &kr->active_ccache_present); if (ret != EOK) { DEBUG(1, ("check_if_ccache_file_is_used failed.\n"));
goto failed;
goto done; } kerr = check_for_valid_tgt(ccache_file, realm, kr->upn, &kr->valid_tgt_present); if (kerr != 0) { DEBUG(1, ("check_for_valid_tgt failed.\n"));
goto failed;
ret = kerr;
goto done; } } else { kr->active_ccache_present = false;
@@ -766,82 +800,82 @@ void krb5_pam_handler(struct be_req *be_req)
default: DEBUG(1, ("User search for (%s) returned > 1 results!\n", pd->user));
goto failed;
ret = EINVAL;
goto done; break;
}
kr->srv = NULL; kr->kpasswd_srv = NULL;
- req = be_resolve_server_send(kr, be_req->be_ctx->ev, be_req->be_ctx,
kr->krb5_ctx->service->name);
- subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
if (req == NULL) { DEBUG(1, ("be_resolve_server_send failed.\n"));krb5_ctx->service->name);
goto failed;
ret = ENOMEM;
}goto done;
- tevent_req_set_callback(req, krb5_resolve_kdc_done, kr);
- tevent_req_set_callback(subreq, krb5_resolve_kdc_done, req);
- return;
- return req;
-failed:
- talloc_free(kr);
done:
- pd->pam_status = pam_status;
- krb_reply(be_req, dp_err, pd->pam_status);
- if (ret == EOK) {
tevent_req_done(req);
- } else {
tevent_req_error(req, ret);
- }
- tevent_req_post(req, state->ev);
- return req;
}
-static void krb5_resolve_kdc_done(struct tevent_req *req) +static void krb5_resolve_kdc_done(struct tevent_req *subreq) {
- struct krb5child_req *kr = tevent_req_callback_data(req,
struct krb5child_req);
- struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
- struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
- struct krb5child_req *kr = state->kr; int ret;
struct pam_data *pd = kr->pd;
struct be_req *be_req = kr->req;
ret = be_resolve_server_recv(req, &kr->srv);
talloc_zfree(req);
- ret = be_resolve_server_recv(subreq, &kr->srv);
- talloc_zfree(subreq); if (ret) { /* all servers have been tried and none * was found good, setting offline, * but we still have to call the child to setup * the ccache file. */
be_mark_offline(be_req->be_ctx);
} else {be_mark_offline(state->be_ctx); kr->is_offline = true;
if (pd->cmd == SSS_PAM_CHAUTHTOK &&
if (state->pd->cmd == SSS_PAM_CHAUTHTOK && kr->krb5_ctx->kpasswd_service != NULL) {
req = be_resolve_server_send(kr, be_req->be_ctx->ev, be_req->be_ctx,
kr->krb5_ctx->kpasswd_service->name);
subreq = be_resolve_server_send(state, state->ev, state->be_ctx,
kr->krb5_ctx->kpasswd_service->name); if (req == NULL) { DEBUG(1, ("be_resolve_server_send failed.\n"));
ret = ENOMEM; goto failed; }
tevent_req_set_callback(req, krb5_resolve_kpasswd_done, kr);
tevent_req_set_callback(subreq, krb5_resolve_kpasswd_done, req); return; }
}
- krb5_find_ccache_step(kr);
- krb5_find_ccache_step(req); return;
failed:
- talloc_free(kr);
- pd->pam_status = PAM_SYSTEM_ERR;
- krb_reply(be_req, DP_ERR_FATAL, pd->pam_status);
- tevent_req_error(req, ret);
}
-static void krb5_resolve_kpasswd_done(struct tevent_req *req) +static void krb5_resolve_kpasswd_done(struct tevent_req *subreq) {
- struct krb5child_req *kr = tevent_req_callback_data(req,
struct krb5child_req);
- struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
- struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state); int ret;
struct pam_data *pd = kr->pd;
struct be_req *be_req = kr->req;
ret = be_resolve_server_recv(req, &kr->kpasswd_srv);
- ret = be_resolve_server_recv(subreq, &state->kr->kpasswd_srv); talloc_zfree(req); if (ret) { /* all kpasswd servers have been tried and none was found good, but the
@@ -849,30 +883,41 @@ static void krb5_resolve_kpasswd_done(struct tevent_req *req) * authentication. We return an PAM error here, but do not mark the * backend offline. */
talloc_free(kr);
pd->pam_status = PAM_AUTHTOK_LOCK_BUSY;
krb_reply(be_req, DP_ERR_OK, pd->pam_status);
state->pam_status = PAM_AUTHTOK_LOCK_BUSY;
state->dp_err = DP_ERR_OK;
tevent_req_done(req);
}return;
- krb5_find_ccache_step(kr);
- krb5_find_ccache_step(req);
}
-static void krb5_find_ccache_step(struct krb5child_req *kr) +static void krb5_find_ccache_step(struct tevent_req *req) {
- struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state); int ret;
- int pam_status = PAM_SYSTEM_ERR;
- int dp_err = DP_ERR_FATAL;
- struct krb5child_req *kr = state->kr; struct pam_data *pd = kr->pd;
- struct be_req *be_req = kr->req; char *msg; size_t offset = 0; bool private_path = false;
- struct tevent_req *req = NULL;
- struct tevent_req *subreq = NULL;
- /* The ccache file should be (re)created if one of the following conditions
* is true:
* - it doesn't exist (kr->ccname == NULL)
* - the backend is online and the current ccache file is not used, i.e
* the related user is currently not logged in
* (!be_is_offline(state->be_ctx) && !kr->active_ccache_present)
* - the backend is offline and the current cache file not used and
* it does not contain a valid tgt
* (be_is_offline(state->be_ctx) &&
* !kr->active_ccache_present && !kr->valid_tgt_present)
if (kr->ccname == NULL ||*/
(be_is_offline(be_req->be_ctx) && !kr->active_ccache_present &&
(be_is_offline(state->be_ctx) && !kr->active_ccache_present && !kr->valid_tgt_present) ||
(!be_is_offline(be_req->be_ctx) && !kr->active_ccache_present)) {
(!be_is_offline(state->be_ctx) && !kr->active_ccache_present)) { DEBUG(9, ("Recreating ccache file.\n")); if (kr->ccname != NULL) { if (strncmp(kr->ccname, "FILE:", 5) == 0) {
@@ -881,12 +926,14 @@ static void krb5_find_ccache_step(struct krb5child_req *kr) if (kr->ccname[offset] != '/') { DEBUG(1, ("Ccache file name [%s] is not an absolute path.\n", kr->ccname + offset));
ret = EINVAL; goto done; } ret = unlink(kr->ccname + offset); if (ret == -1 && errno != ENOENT) {
DEBUG(1, ("unlink [%s] failed [%d][%s].\n", kr->ccname,
errno, strerror(errno)));
ret = errno;
DEBUG(1, ("unlink [%s] failed [%d][%s].\n", kr->ccname, ret,
strerror(ret))); goto done; } }
@@ -896,6 +943,7 @@ static void krb5_find_ccache_step(struct krb5child_req *kr) true, &private_path); if (kr->ccname == NULL) { DEBUG(1, ("expand_ccname_template failed.\n"));
ret = ENOMEM; goto done; }
@@ -908,7 +956,7 @@ static void krb5_find_ccache_step(struct krb5child_req *kr) } }
- if (be_is_offline(be_req->be_ctx)) {
- if (be_is_offline(state->be_ctx)) { DEBUG(9, ("Preparing for offline operation.\n")); kr->is_offline = true;
@@ -917,6 +965,7 @@ static void krb5_find_ccache_step(struct krb5child_req *kr) msg = talloc_asprintf(pd, "%s=%s", CCACHE_ENV_NAME, kr->ccname); if (msg == NULL) { DEBUG(1, ("talloc_asprintf failed.\n"));
ret = ENOMEM; goto done; }
@@ -926,48 +975,53 @@ static void krb5_find_ccache_step(struct krb5child_req *kr) DEBUG(1, ("pam_add_response failed.\n")); }
pam_status = PAM_AUTHINFO_UNAVAIL;
dp_err = DP_ERR_OFFLINE;
state->pam_status = PAM_AUTHINFO_UNAVAIL;
state->dp_err = DP_ERR_OFFLINE;
ret = EOK; goto done; } memset(pd->authtok, 0, pd->authtok_size); pd->authtok_size = 0; if (kr->active_ccache_present) {
ret = krb5_save_ccname(kr, be_req->be_ctx->sysdb,
be_req->be_ctx->domain, pd->user,
ret = krb5_save_ccname(state, state->be_ctx->sysdb,
state->be_ctx->domain, pd->user, kr->ccname); if (ret) { DEBUG(1, ("krb5_save_ccname failed.\n")); goto done; }
krb5_save_ccname_done(kr);
}krb5_save_ccname_done(req); return; }
- req = handle_child_send(kr, be_req->be_ctx->ev, kr);
- if (req == NULL) {
- subreq = handle_child_send(state, state->ev, kr);
- if (subreq == NULL) { DEBUG(1, ("handle_child_send failed.\n"));
}ret = ENOMEM; goto done;
- tevent_req_set_callback(req, krb5_child_done, kr);
- tevent_req_set_callback(subreq, krb5_child_done, req); return;
done:
- talloc_free(kr);
- pd->pam_status = pam_status;
- krb_reply(be_req, dp_err, pd->pam_status);
- if (ret == EOK) {
tevent_req_done(req);
- } else {
tevent_req_error(req, ret);
- }
}
-static void krb5_child_done(struct tevent_req *req) +static void krb5_child_done(struct tevent_req *subreq) {
- struct krb5child_req *kr = tevent_req_callback_data(req,
struct krb5child_req);
- struct pam_data *pd = kr->pd;
- struct be_req *be_req = kr->req;
- struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
- struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
- struct krb5child_req *kr = state->kr;
- struct pam_data *pd = state->pd; int ret; uint8_t *buf = NULL; ssize_t len = -1;
@@ -976,19 +1030,25 @@ static void krb5_child_done(struct tevent_req *req) int32_t *msg_status; int32_t *msg_type; int32_t *msg_len;
int pam_status = PAM_SYSTEM_ERR;
int dp_err = DP_ERR_FATAL;
ret = handle_child_recv(req, pd, &buf, &len);
- ret = handle_child_recv(subreq, pd, &buf, &len); talloc_zfree(kr->timeout_handler);
- talloc_zfree(req);
- talloc_zfree(subreq); if (ret != EOK) { DEBUG(1, ("child failed (%d [%s])\n", ret, strerror(ret)));
goto done;
if (ret == ETIMEDOUT) {
state->pam_status = PAM_AUTHINFO_UNAVAIL;
state->dp_err = DP_ERR_OFFLINE;
tevent_req_done(req);
} else {
tevent_req_error(req, ret);
}
return;
}
if ((size_t) len < 3*sizeof(int32_t)) { DEBUG(1, ("message too short.\n"));
ret = EINVAL; goto done;
}
@@ -1011,22 +1071,25 @@ static void krb5_child_done(struct tevent_req *req) }
if (*msg_status != PAM_SUCCESS && *msg_status != PAM_AUTHINFO_UNAVAIL) {
pam_status = *msg_status;
dp_err = DP_ERR_OK;
state->pam_status = *msg_status;
state->dp_err = DP_ERR_OK; ret = pam_add_response(pd, *msg_type, *msg_len, &buf[p]); if (ret != EOK) {
/* This is not a fatal error */ DEBUG(1, ("pam_add_response failed.\n")); }
ret = EOK; goto done;
} else {
pd->pam_status = *msg_status;
state->pam_status = *msg_status;
}
if (*msg_status == PAM_SUCCESS && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) {
pam_status = PAM_SUCCESS;
dp_err = DP_ERR_OK;
state->pam_status = PAM_SUCCESS;
state->dp_err = DP_ERR_OK;
}ret = EOK; goto done;
@@ -1037,11 +1100,13 @@ static void krb5_child_done(struct tevent_req *req) *msg_len-pref_len); if (kr->ccname == NULL) { DEBUG(1, ("talloc_strndup failed.\n"));
} else { DEBUG(1, ("Missing ccache name in child response [%.*s].\n", *msg_len, &buf[p]));ret = ENOMEM; goto done; }
}ret = EINVAL; goto done;
@@ -1049,7 +1114,7 @@ static void krb5_child_done(struct tevent_req *req) if (kr->srv != NULL) { fo_set_port_status(kr->srv, PORT_NOT_WORKING); }
be_mark_offline(be_req->be_ctx);
} else if (kr->srv != NULL) { fo_set_port_status(kr->srv, PORT_WORKING);be_mark_offline(state->be_ctx); kr->is_offline = true;
@@ -1064,37 +1129,38 @@ static void krb5_child_done(struct tevent_req *req) }
struct sysdb_attrs *attrs;
- attrs = sysdb_new_attrs(kr);
- attrs = sysdb_new_attrs(state); ret = sysdb_attrs_add_string(attrs, SYSDB_CCACHE_FILE, kr->ccname); if (ret != EOK) { DEBUG(1, ("sysdb_attrs_add_string failed.\n")); goto done; }
- ret = krb5_save_ccname(kr, be_req->be_ctx->sysdb,
be_req->be_ctx->domain,
- ret = krb5_save_ccname(state, state->be_ctx->sysdb,
if (ret) { DEBUG(1, ("krb5_save_ccname_send failed.\n")); goto done; }state->be_ctx->domain, pd->user, kr->ccname);
- krb5_save_ccname_done(kr);
- krb5_save_ccname_done(req); return;
done:
- talloc_free(kr);
- pd->pam_status = pam_status;
- krb_reply(be_req, dp_err, pd->pam_status);
- if (ret == EOK) {
tevent_req_done(req);
- } else {
tevent_req_error(req, ret);
- }
}
-static void krb5_save_ccname_done(struct krb5child_req *kr) +static void krb5_save_ccname_done(struct tevent_req *req) {
- struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);
- struct krb5child_req *kr = state->kr; struct pam_data *pd = kr->pd;
- struct be_req *be_req = kr->req; struct krb5_ctx *krb5_ctx = kr->krb5_ctx;
- int pam_status = PAM_SYSTEM_ERR;
- int dp_err = DP_ERR_FATAL; int ret; char *password = NULL;
@@ -1108,28 +1174,29 @@ static void krb5_save_ccname_done(struct krb5child_req *kr)
if (kr->is_offline) { DEBUG(4, ("Backend is marked offline, retry later!\n"));
pam_status = PAM_AUTHINFO_UNAVAIL;
dp_err = DP_ERR_OFFLINE;
state->pam_status = PAM_AUTHINFO_UNAVAIL;
state->dp_err = DP_ERR_OFFLINE;
}ret = EOK; goto done;
- if (be_req->be_ctx->domain->cache_credentials == TRUE) {
if (state->be_ctx->domain->cache_credentials == TRUE) {
/* password caching failures are not fatal errors */
pam_status = PAM_SUCCESS;
dp_err = DP_ERR_OK;
state->pam_status = PAM_SUCCESS;
state->dp_err = DP_ERR_OK; switch(pd->cmd) { case SSS_PAM_AUTHENTICATE: case SSS_PAM_CHAUTHTOK_PRELIM:
password = talloc_size(be_req, pd->authtok_size + 1);
password = talloc_size(state, pd->authtok_size + 1); if (password != NULL) { memcpy(password, pd->authtok, pd->authtok_size); password[pd->authtok_size] = '\0'; } break; case SSS_PAM_CHAUTHTOK:
password = talloc_size(be_req, pd->newauthtok_size + 1);
password = talloc_size(state, pd->newauthtok_size + 1); if (password != NULL) { memcpy(password, pd->newauthtok, pd->newauthtok_size); password[pd->newauthtok_size] = '\0';
@@ -1141,13 +1208,14 @@ static void krb5_save_ccname_done(struct krb5child_req *kr)
if (password == NULL) { DEBUG(0, ("password not available, offline auth may not work.\n"));
ret = EOK; /* password caching failures are not fatal errors */ goto done; } talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
ret = sysdb_cache_password(be_req, be_req->be_ctx->sysdb,
be_req->be_ctx->domain, pd->user,
ret = sysdb_cache_password(state, state->be_ctx->sysdb,
state->be_ctx->domain, pd->user, password); if (ret) { DEBUG(2, ("Failed to cache password, offline auth may not work."
@@ -1155,14 +1223,17 @@ static void krb5_save_ccname_done(struct krb5child_req *kr) } }
- pam_status = PAM_SUCCESS;
- dp_err = DP_ERR_OK;
- state->pam_status = PAM_SUCCESS;
- state->dp_err = DP_ERR_OK;
- ret = EOK;
done:
- talloc_free(kr);
- if (ret == EOK) {
tevent_req_done(req);
- } else {
tevent_req_error(req, ret);
- }
- pd->pam_status = pam_status;
- krb_reply(be_req, dp_err, pd->pam_status);
}
static void krb_reply(struct be_req *req, int dp_err, int result) @@ -1170,3 +1241,57 @@ static void krb_reply(struct be_req *req, int dp_err, int result) req->fn(req, dp_err, result, NULL); }
+void krb5_auth_done(struct tevent_req *req);
+void krb5_pam_handler(struct be_req *be_req) +{
- struct tevent_req *req;
- struct pam_data *pd;
- struct krb5_ctx *krb5_ctx;
- pd = talloc_get_type(be_req->req_data, struct pam_data);
- krb5_ctx = get_krb5_ctx(be_req);
- if (krb5_ctx == NULL) {
DEBUG(1, ("Kerberos context not available.\n"));
goto failed;
- }
- req = krb5_auth_send(be_req, be_req->be_ctx->ev, be_req->be_ctx, pd,
krb5_ctx);
- if (req == NULL) {
DEBUG(1, ("krb5_auth_send failed.\n"));
goto failed;
- }
- tevent_req_set_callback(req, krb5_auth_done, be_req);
- return;
+failed:
- pd->pam_status = PAM_SYSTEM_ERR;
- krb_reply(be_req, DP_ERR_FATAL, pd->pam_status);
+}
+void krb5_auth_done(struct tevent_req *req) +{
- int ret;
- struct be_req *be_req = tevent_req_callback_data(req, struct be_req);
- int pam_status;
- int dp_err;
- struct pam_data *pd;
- pd = talloc_get_type(be_req->req_data, struct pam_data);
- ret = krb5_auth_recv(req, &pam_status, &dp_err);
- talloc_zfree(req);
- if (ret) {
pd->pam_status = PAM_SYSTEM_ERR;
dp_err = DP_ERR_OK;
- } else {
pd->pam_status = pam_status;
- }
- krb_reply(be_req, dp_err, pd->pam_status);
+}
diff --git a/src/providers/krb5/krb5_auth.h b/src/providers/krb5/krb5_auth.h index 9f8c414..e614d5c 100644 --- a/src/providers/krb5/krb5_auth.h +++ b/src/providers/krb5/krb5_auth.h @@ -44,7 +44,6 @@ struct krb5child_req { int read_from_child_fd; int write_to_child_fd;
- struct be_req *req; struct pam_data *pd; struct krb5_ctx *krb5_ctx;
@@ -99,4 +98,10 @@ struct krb5_ctx {
void krb5_pam_handler(struct be_req *be_req);
+struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct be_ctx *be_ctx,
struct pam_data *pd,
struct krb5_ctx *krb5_ctx);
+int krb5_auth_recv(struct tevent_req *req, int *pam_status, int *dp_err);
#endif /* __KRB5_AUTH_H__ */
1.6.6.1
From 6031d2f1d63cf9c578e9146a94fa9377c19f0922 Mon Sep 17 00:00:00 2001 From: Sumit Bose sbose@redhat.com Date: Mon, 29 Mar 2010 13:41:41 +0200 Subject: [PATCH 2/2] New version of IPA auth and password migration
The current version modified some global structures to be able to use Kerberos and LDAP authentication during the IPA password migration. This new version only uses tevent requests.
Additionally the ipaMigrationEnabled attribute is read from the IPA server to see if password migration is allowed or not.
src/providers/ipa/ipa_auth.c | 550 ++++++++++++++++++++++++++------------ src/providers/ipa/ipa_common.h | 8 +- src/providers/ipa/ipa_init.c | 83 +++++-- src/providers/krb5/krb5_common.c | 4 +- 4 files changed, 446 insertions(+), 199 deletions(-)
diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c index 86b72e4..8f9fefa 100644 --- a/src/providers/ipa/ipa_auth.c +++ b/src/providers/ipa/ipa_auth.c @@ -31,283 +31,481 @@ #include "providers/krb5/krb5_auth.h" #include "providers/ipa/ipa_common.h"
-struct ipa_auth_ctx {
- struct sdap_auth_ctx *sdap_auth_ctx;
- struct krb5_ctx *krb5_ctx;
- struct be_req *be_req;
- be_async_callback_t callback;
- void *pvt;
- bool password_migration;
- int dp_err_type;
- int errnum;
- char *errstr;
-}; +#define IPA_CONFIG_MIRATION_ENABLED "ipaMigrationEnabled" +#define IPA_CONFIG_SEARCH_BASE_TEMPLATE "cn=etc,%s" +#define IPA_CONFIG_FILTER "(&(cn=ipaConfig)(objectClass=ipaGuiConfig))"
-static void ipa_auth_reply(struct ipa_auth_ctx *ipa_auth_ctx) +static void ipa_auth_reply(struct be_req *be_req, int dp_err, int result) {
- struct pam_data *pd;
- struct be_req *be_req = ipa_auth_ctx->be_req;
- be_req->fn = ipa_auth_ctx->callback;
- be_req->pvt = ipa_auth_ctx->pvt;
- be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data = ipa_auth_ctx->krb5_ctx;
- pd = talloc_get_type(be_req->req_data, struct pam_data);
- int dp_err_type = ipa_auth_ctx->dp_err_type;
- char *errstr = ipa_auth_ctx->errstr;
- talloc_zfree(ipa_auth_ctx);
- DEBUG(9, ("sending [%d] [%d] [%s].\n", dp_err_type, pd->pam_status,
errstr));
- be_req->fn(be_req, dp_err_type, pd->pam_status, errstr);
- be_req->fn(be_req, dp_err, result, NULL);
}
-struct ipa_auth_handler_state { +struct get_password_migration_flag_state { struct tevent_context *ev;
- int dp_err_type;
- int errnum;
- char *errstr;
- struct sdap_auth_ctx *sdap_auth_ctx;
- struct sdap_handle *sh;
- enum sdap_result result;
- struct fo_server *srv;
- char *ipa_domain;
- bool password_migration;
};
-static void ipa_auth_handler_callback(struct be_req *be_req,
int dp_err_type,
int errnum,
const char *errstr);
+static void get_password_migration_flag_auth_done(struct tevent_req *subreq); +static void get_password_migration_flag_done(struct tevent_req *subreq);
-static struct tevent_req *ipa_auth_handler_send(TALLOC_CTX *memctx, +static struct tevent_req *get_password_migration_flag_send(TALLOC_CTX *memctx, struct tevent_context *ev,
struct be_req *be_req,
be_req_fn_t auth_handler)
struct sdap_auth_ctx *sdap_auth_ctx,
char *ipa_domain)
{
- struct ipa_auth_handler_state *state;
- struct tevent_req *req;
- int ret;
- struct tevent_req *req, *subreq;
- struct get_password_migration_flag_state *state;
- req = tevent_req_create(memctx, &state, struct ipa_auth_handler_state);
if (sdap_auth_ctx == NULL || ipa_domain == NULL) {
DEBUG(1, ("Missing parameter.\n"));
return NULL;
}
req = tevent_req_create(memctx, &state,
struct get_password_migration_flag_state);
if (req == NULL) { DEBUG(1, ("tevent_req_create failed.\n")); return NULL; }
state->ev = ev;
state->sdap_auth_ctx = sdap_auth_ctx;
state->sh = NULL;
state->result = SDAP_ERROR;
state->srv = NULL;
state->password_migration = false;
state->ipa_domain = ipa_domain;
/* We request to use StartTLS here, because if password migration is
* enabled we will use this connection for authentication, too. */
ret = dp_opt_set_bool(sdap_auth_ctx->opts->basic, SDAP_ID_TLS, true);
if (ret != EOK) {
DEBUG(1, ("Failed to set SDAP_ID_TLS to true.\n"));
goto fail;
}
- be_req->fn = ipa_auth_handler_callback;
- be_req->pvt = req;
- auth_handler(be_req);
subreq = sdap_cli_connect_send(state, ev, sdap_auth_ctx->opts,
sdap_auth_ctx->be, sdap_auth_ctx->service,
NULL);
if (subreq == NULL) {
DEBUG(1, ("sdap_cli_connect_send failed.\n"));
goto fail;
}
tevent_req_set_callback(subreq, get_password_migration_flag_auth_done,
req);
return req;
+fail:
- talloc_zfree(req);
- return NULL;
}
-static void ipa_auth_handler_callback(struct be_req *be_req,
int dp_err_type,
int errnum,
const char *errstr)
+static void get_password_migration_flag_auth_done(struct tevent_req *subreq) {
- struct tevent_req *req = talloc_get_type(be_req->pvt, struct tevent_req);
- struct ipa_auth_handler_state *state = tevent_req_data(req,
struct ipa_auth_handler_state);
- struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
- struct get_password_migration_flag_state *state = tevent_req_data(req,
struct get_password_migration_flag_state);
- int ret;
- char *ldap_basedn;
- char *search_base;
- const char **attrs;
- ret = sdap_cli_connect_recv(subreq, state, &state->sh, NULL);
- talloc_zfree(subreq);
- if (ret) {
DEBUG(1, ("sdap_auth request failed.\n"));
tevent_req_error(req, ret);
return;
- }
- ret = domain_to_basedn(state, state->ipa_domain, &ldap_basedn);
- if (ret != EOK) {
DEBUG(1, ("domain_to_basedn failed.\n"));
tevent_req_error(req, ret);
return;
- }
- DEBUG(9, ("received from handler [%d] [%d] [%s].\n", dp_err_type, errnum,
errstr));
- state->dp_err_type = dp_err_type;
- state->errnum = errnum;
- state->errstr = talloc_strdup(state, errstr);
- search_base = talloc_asprintf(state, IPA_CONFIG_SEARCH_BASE_TEMPLATE,
ldap_basedn);
- if (search_base == NULL) {
DEBUG(1, ("talloc_asprintf failed.\n"));
tevent_req_error(req, ENOMEM);
return;
- }
- tevent_req_post(req, state->ev);
- tevent_req_done(req);
- return;
- attrs = talloc_array(state, const char*, 2);
- if (attrs == NULL) {
DEBUG(1, ("talloc_array failed.\n"));
tevent_req_error(req, ENOMEM);
return;
- }
- attrs[0] = IPA_CONFIG_MIRATION_ENABLED;
- attrs[1] = NULL;
- subreq = sdap_get_generic_send(state, state->ev, state->sdap_auth_ctx->opts,
state->sh, search_base, LDAP_SCOPE_SUBTREE,
IPA_CONFIG_FILTER, attrs, NULL, 0);
- if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
- }
- tevent_req_set_callback(subreq, get_password_migration_flag_done, req);
}
-static int ipa_auth_handler_recv(struct tevent_req *req, TALLOC_CTX *memctx,
int *dp_err_type, int *errnum,
char **errstr)
+static void get_password_migration_flag_done(struct tevent_req *subreq) {
- struct ipa_auth_handler_state *state = tevent_req_data(req,
struct ipa_auth_handler_state);
- enum tevent_req_state tstate;
- uint64_t err;
- if (tevent_req_is_error(req, &tstate, &err)) {
if (err) return err;
return EIO;
- struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
- struct get_password_migration_flag_state *state = tevent_req_data(req,
struct get_password_migration_flag_state);
- int ret;
- size_t reply_count;
- struct sysdb_attrs **reply = NULL;
- const char *value = NULL;
- ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
- talloc_zfree(subreq);
- if (ret) {
tevent_req_error(req, ret);
return;
- }
- if (reply_count != 1) {
DEBUG(1, ("Unexpected number of results, expected 1, got %d.\n",
reply_count));
tevent_req_error(req, EINVAL);
}return;
- *dp_err_type = state->dp_err_type;
- *errnum = state->errnum;
- *errstr = talloc_steal(memctx, state->errstr);
- ret = sysdb_attrs_get_string(reply[0], IPA_CONFIG_MIRATION_ENABLED, &value);
- if (strcasecmp(value, "true") == 0) {
state->password_migration = true;
- }
- tevent_req_done(req);
+}
+static int get_password_migration_flag_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
bool *password_migration,
struct sdap_handle **sh)
+{
struct get_password_migration_flag_state *state = tevent_req_data(req,
struct get_password_migration_flag_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
*password_migration = state->password_migration;
if (sh != NULL) {
*sh = talloc_steal(mem_ctx, state->sh);
}
return EOK;
}
+struct ipa_auth_state {
- struct be_req *be_req;
- struct tevent_context *ev;
- struct ipa_auth_ctx *ipa_auth_ctx;
- struct pam_data *pd;
- bool password_migration;
- struct sdap_handle *sh;
+};
static void ipa_auth_handler_done(struct tevent_req *req); +static void ipa_get_migration_flag_done(struct tevent_req *req); +static void ipa_auth_get_user_dn_done(struct tevent_req *req); static void ipa_auth_ldap_done(struct tevent_req *req); static void ipa_auth_handler_retry_done(struct tevent_req *req);
void ipa_auth(struct be_req *be_req) { struct tevent_req *req;
- struct ipa_auth_ctx *ipa_auth_ctx;
- struct sdap_id_ctx *sdap_id_ctx;
- ipa_auth_ctx = talloc_zero(be_req, struct ipa_auth_ctx);
- if (ipa_auth_ctx == NULL) {
DEBUG(1, ("talloc failed.\n"));
be_req->fn(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);
- }
- ipa_auth_ctx->callback = be_req->fn;
- ipa_auth_ctx->pvt = be_req->pvt;
- ipa_auth_ctx->be_req = be_req;
- struct ipa_auth_state *state;
- ipa_auth_ctx->sdap_auth_ctx = talloc_zero(ipa_auth_ctx,
struct sdap_auth_ctx);
- if (ipa_auth_ctx->sdap_auth_ctx == NULL) {
DEBUG(1, ("talloc failed.\n"));
- state = talloc_zero(be_req, struct ipa_auth_state);
- if (state == NULL) {
}DEBUG(1, ("talloc_zero failed.\n")); goto fail;
- sdap_id_ctx = talloc_get_type(
be_req->be_ctx->bet_info[BET_ID].pvt_bet_data,
struct sdap_id_ctx);
- ipa_auth_ctx->sdap_auth_ctx->be = sdap_id_ctx->be;
- ipa_auth_ctx->sdap_auth_ctx->opts = sdap_id_ctx->opts;
- ipa_auth_ctx->krb5_ctx = talloc_get_type(
be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data,
struct krb5_ctx);
-/* TODO: test and activate when server side support is available */
- ipa_auth_ctx->password_migration = false;
- ipa_auth_ctx->dp_err_type = DP_ERR_FATAL;
- ipa_auth_ctx->errnum = EIO;
- ipa_auth_ctx->errstr = NULL;
- state->password_migration = false;
- state->sh = NULL;
- state->be_req = be_req;
- state->ev = be_req->be_ctx->ev;
- state->pd = talloc_get_type(be_req->req_data, struct pam_data);
- switch (state->pd->cmd) {
case SSS_PAM_AUTHENTICATE:
state->ipa_auth_ctx = talloc_get_type(
be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data,
struct ipa_auth_ctx);
break;
case SSS_PAM_CHAUTHTOK:
case SSS_PAM_CHAUTHTOK_PRELIM:
state->ipa_auth_ctx = talloc_get_type(
be_req->be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
struct ipa_auth_ctx);
break;
default:
DEBUG(1, ("Unsupported PAM task.\n"));
goto fail;
- }
- req = ipa_auth_handler_send(ipa_auth_ctx, be_req->be_ctx->ev, be_req,
krb5_pam_handler);
- req = krb5_auth_send(state, state->ev, be_req->be_ctx, state->pd,
if (req == NULL) {state->ipa_auth_ctx->krb5_auth_ctx);
DEBUG(1, ("ipa_auth_handler_send failed.\n"));
}DEBUG(1, ("krb5_auth_send failed.\n")); goto fail;
- tevent_req_set_callback(req, ipa_auth_handler_done, ipa_auth_ctx);
- tevent_req_set_callback(req, ipa_auth_handler_done, state); return;
fail:
- ipa_auth_reply(ipa_auth_ctx);
- state->pd->pam_status = PAM_SYSTEM_ERR;
- ipa_auth_reply(be_req, DP_ERR_FATAL, state->pd->pam_status);
}
static void ipa_auth_handler_done(struct tevent_req *req) {
- struct ipa_auth_ctx *ipa_auth_ctx = tevent_req_callback_data(req,
struct ipa_auth_ctx);
- struct pam_data *pd;
- struct be_req *be_req;
- struct ipa_auth_state *state = tevent_req_callback_data(req,
int ret;struct ipa_auth_state);
- int pam_status = PAM_SYSTEM_ERR;
- int dp_err;
- be_req = ipa_auth_ctx->be_req;
- pd = talloc_get_type(be_req->req_data, struct pam_data);
- ret = ipa_auth_handler_recv(req, ipa_auth_ctx, &ipa_auth_ctx->dp_err_type,
&ipa_auth_ctx->errnum, &ipa_auth_ctx->errstr);
- ret = krb5_auth_recv(req, &pam_status, &dp_err); talloc_zfree(req);
- if (ret != EOK) {
DEBUG(1, ("ipa_auth_handler request failed.\n"));
pd->pam_status = PAM_SYSTEM_ERR;
- state->pd->pam_status = pam_status;
- if (ret != EOK && pam_status != PAM_CRED_ERR) {
DEBUG(1, ("krb5_auth_recv request failed.\n"));
dp_err = DP_ERR_OK;
goto done;
- }
- if (dp_err != DP_ERR_OK) { goto done; }
- if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) {
pd->pam_status = ipa_auth_ctx->errnum;
- if (state->pd->cmd == SSS_PAM_AUTHENTICATE &&
state->pd->pam_status == PAM_CRED_ERR) {
req = get_password_migration_flag_send(state, state->ev,
state->ipa_auth_ctx->sdap_auth_ctx,
dp_opt_get_string(
state->ipa_auth_ctx->ipa_options,
IPA_DOMAIN));
if (req == NULL) {
DEBUG(1, ("get_password_migration_flag failed.\n"));
goto done;
}
tevent_req_set_callback(req, ipa_get_migration_flag_done, state);
return;
- }
+done:
- ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);
+}
+static void ipa_get_migration_flag_done(struct tevent_req *req) +{
- struct ipa_auth_state *state = tevent_req_callback_data(req,
struct ipa_auth_state);
- int ret;
- int dp_err = DP_ERR_FATAL;
- const char **attrs;
- struct ldb_message *user_msg;
- const char *dn;
- struct dp_opt_blob password;
- ret = get_password_migration_flag_recv(req, state,
&state->password_migration,
&state->sh);
- talloc_zfree(req);
- if (ret != EOK) {
DEBUG(1, ("get_password_migration_flag request failed.\n"));
state->pd->pam_status = PAM_SYSTEM_ERR;
}dp_err = DP_ERR_OK; goto done;
- if (ipa_auth_ctx->password_migration && pd->pam_status == PAM_CRED_ERR) {
- if (state->password_migration) {
state->pd->pam_status = PAM_SYSTEM_ERR; DEBUG(1, ("Assuming Kerberos password is missing, " "starting password migration.\n"));
be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data =
ipa_auth_ctx->sdap_auth_ctx;
req = ipa_auth_handler_send(ipa_auth_ctx, be_req->be_ctx->ev, be_req,
sdap_pam_auth_handler);
attrs = talloc_array(state, const char *, 2);
if (attrs == NULL) {
DEBUG(1, ("talloc_array failed.\n"));
state->pd->pam_status = PAM_SYSTEM_ERR;
dp_err = DP_ERR_OK;
goto done;
}
attrs[0] = SYSDB_ORIG_DN;
attrs[1] = NULL;
ret = sysdb_search_user_by_name(state, state->be_req->be_ctx->sysdb,
state->be_req->be_ctx->domain,
state->pd->user, attrs, &user_msg);
if (ret != EOK) {
DEBUG(1, ("sysdb_search_user_by_name failed.\n"));
goto done;
}
dn = ldb_msg_find_attr_as_string(user_msg, SYSDB_ORIG_DN, NULL);
if (dn == NULL) {
DEBUG(1, ("Missing original DN for user [%s].\n", state->pd->user));
state->pd->pam_status = PAM_SYSTEM_ERR;
dp_err = DP_ERR_OK;
goto done;
}
password.data = state->pd->authtok;
password.length = state->pd->authtok_size;
req = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, dn,
"password", password); if (req == NULL) {
DEBUG(1, ("ipa_auth_ldap_send failed.\n"));
DEBUG(1, ("sdap_auth_send failed.\n")); goto done; }
tevent_req_set_callback(req, ipa_auth_ldap_done, ipa_auth_ctx);
tevent_req_set_callback(req, ipa_auth_ldap_done, state); return;
- } else {
DEBUG(5, ("Password migration is not enabled.\n"));
- }
- dp_err = DP_ERR_OK;
+done:
- ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);
+} +#if 0 +void ipa_auth_get_user_dn_done(struct tevent_req *req) +{
struct ipa_auth_state *state = tevent_req_callback_data(req,
struct ipa_auth_state);
int ret;
int dp_err = DP_ERR_FATAL;
struct dp_opt_blob password;
struct ldb_message *msg;
const char *dn;
ret = sysdb_search_user_recv(req, state, &msg);
talloc_zfree(req);
if (ret != EOK) {
DEBUG(1, ("sysdb_search_user request failed.\n"));
state->pd->pam_status = PAM_SYSTEM_ERR;
dp_err = DP_ERR_OK;
goto done;
}
dn = ldb_msg_find_attr_as_string(msg, SYSDB_ORIG_DN, NULL);
if (dn == NULL) {
DEBUG(1, ("Missing original DN for user [%s].\n", state->pd->user));
state->pd->pam_status = PAM_SYSTEM_ERR;
dp_err = DP_ERR_OK;
goto done;
}
password.data = state->pd->authtok;
password.length = state->pd->authtok_size;
req = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, dn,
"password", password);
if (req == NULL) {
DEBUG(1, ("sdap_auth_send failed.\n"));
goto done;
}
tevent_req_set_callback(req, ipa_auth_ldap_done, state);
return;
done:
- ipa_auth_reply(ipa_auth_ctx);
- ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);
} +#endif
static void ipa_auth_ldap_done(struct tevent_req *req) {
- struct ipa_auth_ctx *ipa_auth_ctx = tevent_req_callback_data(req,
struct ipa_auth_ctx);
- struct pam_data *pd;
- struct be_req *be_req;
- struct ipa_auth_state *state = tevent_req_callback_data(req,
int ret;struct ipa_auth_state);
- int dp_err = DP_ERR_FATAL;
- enum sdap_result result;
- be_req = ipa_auth_ctx->be_req;
- pd = talloc_get_type(be_req->req_data, struct pam_data);
- ret = ipa_auth_handler_recv(req, ipa_auth_ctx, &ipa_auth_ctx->dp_err_type,
&ipa_auth_ctx->errnum, &ipa_auth_ctx->errstr);
- ret = sdap_auth_recv(req, state, &result, NULL); talloc_zfree(req); if (ret != EOK) {
DEBUG(1, ("ipa_auth_handler request failed.\n"));
pd->pam_status = PAM_SYSTEM_ERR;
DEBUG(1, ("auth_send request failed.\n"));
state->pd->pam_status = PAM_SYSTEM_ERR;
}dp_err = DP_ERR_OK; goto done;
- if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) {
pd->pam_status = ipa_auth_ctx->errnum;
+/* TODO: do we need to handle expired passwords? */
- if (result != SDAP_AUTH_SUCCESS) {
DEBUG(1, ("LDAP authentication failed, "
"Password migration not possible.\n"));
state->pd->pam_status = PAM_CRED_INSUFFICIENT;
}dp_err = DP_ERR_OK; goto done;
- if (pd->pam_status == PAM_SUCCESS) {
DEBUG(1, ("LDAP authentication succeded, "
"trying Kerberos authentication again.\n"));
be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data = ipa_auth_ctx->krb5_ctx;
req = ipa_auth_handler_send(ipa_auth_ctx, be_req->be_ctx->ev, be_req,
krb5_pam_handler);
if (req == NULL) {
DEBUG(1, ("ipa_auth_ldap_send failed.\n"));
goto done;
}
- DEBUG(1, ("LDAP authentication succeded, "
"trying Kerberos authentication again.\n"));
tevent_req_set_callback(req, ipa_auth_handler_retry_done, ipa_auth_ctx);
return;
req = krb5_auth_send(state, state->ev,
state->be_req->be_ctx, state->pd,
state->ipa_auth_ctx->krb5_auth_ctx);
if (req == NULL) {
DEBUG(1, ("krb5_auth_send failed.\n"));
goto done;
}
tevent_req_set_callback(req, ipa_auth_handler_retry_done, state);
return;
done:
- ipa_auth_reply(ipa_auth_ctx);
- ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);
}
static void ipa_auth_handler_retry_done(struct tevent_req *req) {
- struct ipa_auth_ctx *ipa_auth_ctx = tevent_req_callback_data(req,
struct ipa_auth_ctx);
- struct pam_data *pd;
- struct be_req *be_req;
- struct ipa_auth_state *state = tevent_req_callback_data(req,
int ret;struct ipa_auth_state);
- int pam_status;
- int dp_err;
- be_req = ipa_auth_ctx->be_req;
- pd = talloc_get_type(be_req->req_data, struct pam_data);
- ret = ipa_auth_handler_recv(req, ipa_auth_ctx, &ipa_auth_ctx->dp_err_type,
&ipa_auth_ctx->errnum, &ipa_auth_ctx->errstr);
- ret = krb5_auth_recv(req, &pam_status, &dp_err); talloc_zfree(req); if (ret != EOK) {
DEBUG(1, ("ipa_auth_handler request failed.\n"));
pd->pam_status = PAM_SYSTEM_ERR;
- }
- if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) {
pd->pam_status = ipa_auth_ctx->errnum;
DEBUG(1, ("krb5_auth_recv request failed.\n"));
state->pd->pam_status = PAM_SYSTEM_ERR;
dp_err = DP_ERR_OK;
}goto done;
- ipa_auth_reply(ipa_auth_ctx);
- state->pd->pam_status = pam_status;
+done:
- ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);
} diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h index 7762818..03a082e 100644 --- a/src/providers/ipa/ipa_common.h +++ b/src/providers/ipa/ipa_common.h @@ -50,6 +50,12 @@ enum ipa_basic_opt { IPA_OPTS_BASIC /* opts counter */ };
+struct ipa_auth_ctx {
- struct krb5_ctx *krb5_auth_ctx;
- struct sdap_auth_ctx *sdap_auth_ctx;
- struct dp_option *ipa_options;
+};
struct ipa_options { struct dp_option *basic;
@@ -61,7 +67,7 @@ struct ipa_options {
/* auth and chpass provider */ struct dp_option *auth;
- struct krb5_ctx *auth_ctx;
- struct ipa_auth_ctx *auth_ctx;
};
int domain_to_basedn(TALLOC_CTX *memctx, const char *domain, char **basedn); diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c index 1689ac2..6e0688f 100644 --- a/src/providers/ipa/ipa_init.c +++ b/src/providers/ipa/ipa_init.c @@ -48,7 +48,7 @@ struct bet_ops ipa_auth_ops = { };
struct bet_ops ipa_chpass_ops = {
- .handler = krb5_pam_handler,
- .handler = ipa_auth, .finalize = NULL,
};
@@ -162,7 +162,9 @@ int sssm_ipa_auth_init(struct be_ctx *bectx, struct bet_ops **ops, void **pvt_data) {
- struct krb5_ctx *ctx;
- struct ipa_auth_ctx *ipa_auth_ctx;
- struct krb5_ctx *krb5_auth_ctx;
- struct sdap_auth_ctx *sdap_auth_ctx; struct tevent_signal *sige; FILE *debug_filep; unsigned v;
@@ -182,33 +184,74 @@ int sssm_ipa_auth_init(struct be_ctx *bectx, return EOK; }
- ctx = talloc_zero(bectx, struct krb5_ctx);
- if (!ctx) {
- ipa_auth_ctx = talloc_zero(ipa_options, struct ipa_auth_ctx);
- if (!ipa_auth_ctx) { return ENOMEM; }
- ctx->service = ipa_options->service->krb5_service;
- ipa_options->auth_ctx = ctx;
- ipa_options->auth_ctx = ipa_auth_ctx;
- ret = ipa_get_auth_options(ipa_options, bectx->cdb,
bectx->conf_path,
&ctx->opts);
- ret = dp_copy_options(ipa_auth_ctx, ipa_options->basic,
if (ret != EOK) {IPA_OPTS_BASIC, &ipa_auth_ctx->ipa_options);
DEBUG(1, ("dp_copy_options failed.\n"));
goto done;
- }
- krb5_auth_ctx = talloc_zero(ipa_auth_ctx, struct krb5_ctx);
- if (!krb5_auth_ctx) {
}ret = ENOMEM; goto done;
- krb5_auth_ctx->service = ipa_options->service->krb5_service;
- ipa_options->auth_ctx->krb5_auth_ctx = krb5_auth_ctx;
- ret = check_and_export_options(ctx->opts, bectx->domain);
- ret = ipa_get_auth_options(ipa_options, bectx->cdb, bectx->conf_path,
if (ret != EOK) {&krb5_auth_ctx->opts);
DEBUG(1, ("check_and_export_opts failed.\n")); goto done;
}
sige = tevent_add_signal(bectx->ev, ctx, SIGCHLD, SA_SIGINFO,
child_sig_handler, NULL);
if (sige == NULL) {
DEBUG(1, ("tevent_add_signal failed.\n"));
sdap_auth_ctx = talloc_zero(ipa_auth_ctx, struct sdap_auth_ctx);
if (!sdap_auth_ctx) { ret = ENOMEM; goto done; }
sdap_auth_ctx->be = bectx;
sdap_auth_ctx->service = ipa_options->service->sdap;
ipa_options->auth_ctx->sdap_auth_ctx = sdap_auth_ctx;
ret = ipa_get_id_options(ipa_options, bectx->cdb, bectx->conf_path,
&sdap_auth_ctx->opts);
if (ret != EOK) {
goto done;
}
ret = setup_tls_config(sdap_auth_ctx->opts->basic);
if (ret != EOK) {
DEBUG(1, ("setup_tls_config failed [%d][%s].\n",
ret, strerror(ret)));
goto done;
}
ret = check_and_export_options(krb5_auth_ctx->opts, bectx->domain);
if (ret != EOK) {
DEBUG(1, ("check_and_export_opts failed.\n"));
goto done;
}
if (ipa_options->id_ctx == NULL) {
DEBUG(9, ("Adding SIGCHLD handler for Kerberos child.\n"));
sige = tevent_add_signal(bectx->ev, krb5_auth_ctx, SIGCHLD, SA_SIGINFO,
child_sig_handler, NULL);
if (sige == NULL) {
DEBUG(1, ("tevent_add_signal failed.\n"));
ret = ENOMEM;
goto done;
}
} else {
DEBUG(9, ("IPA id provider already initialized, "
"assuming that a SIGCHLD handler is already in place.\n"));
}
if (debug_to_file != 0) { ret = open_debug_file_ex("krb5_child", &debug_filep);
@@ -218,19 +261,19 @@ int sssm_ipa_auth_init(struct be_ctx *bectx, goto done; }
ctx->child_debug_fd = fileno(debug_filep);
if (ctx->child_debug_fd == -1) {
krb5_auth_ctx->child_debug_fd = fileno(debug_filep);
if (krb5_auth_ctx->child_debug_fd == -1) { DEBUG(0, ("fileno failed [%d][%s]\n", errno, strerror(errno))); ret = errno; goto done; }
v = fcntl(ctx->child_debug_fd, F_GETFD, 0);
fcntl(ctx->child_debug_fd, F_SETFD, v & ~FD_CLOEXEC);
v = fcntl(krb5_auth_ctx->child_debug_fd, F_GETFD, 0);
fcntl(krb5_auth_ctx->child_debug_fd, F_SETFD, v & ~FD_CLOEXEC);
}
*ops = &ipa_auth_ops;
- *pvt_data = ctx;
- *pvt_data = ipa_auth_ctx; ret = EOK;
done: diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c index 2b3331e..52cbe16 100644 --- a/src/providers/krb5/krb5_common.c +++ b/src/providers/krb5/krb5_common.c @@ -69,13 +69,13 @@ errno_t check_and_export_options(struct dp_option *opts,
dummy = dp_opt_get_cstring(opts, KRB5_KDC); if (dummy == NULL) {
DEBUG(1, ("No KDC explicitly configured, using defaults"));
DEBUG(1, ("No KDC explicitly configured, using defaults.\n"));
}
dummy = dp_opt_get_cstring(opts, KRB5_KPASSWD); if (dummy == NULL) { DEBUG(1, ("No kpasswd server explicitly configured, "
"using the KDC or defaults"));
"using the KDC or defaults.\n"));
}
dummy = dp_opt_get_cstring(opts, KRB5_CCNAME_TMPL);
-- 1.6.6.1
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://fedorahosted.org/mailman/listinfo/sssd-devel
On 04/28/2010 03:03 PM, Sumit Bose wrote:
sorry, I forget to remove some unneeded code.
New version attached.
bye, Sumit On Wed, Apr 28, 2010 at 05:30:24PM +0200, Sumit Bose wrote:
Hi,
these are the two patches for the IPA password migration for master. Because master already contains the sync sysdb patches it is not easy to rebase the first patch from the sssd-1-2 branch to master so I rewrote it. The second patch is mainly the same with a substitution of an async sysdb call with his sync version.
bye, Sumit
Ack to both (though I didn't test the migration. I verified by inspection that the changes from the other, tested patch aren't going to change functionality)
On 05/10/2010 03:18 PM, Stephen Gallagher wrote:
On 04/28/2010 03:03 PM, Sumit Bose wrote:
sorry, I forget to remove some unneeded code.
New version attached.
bye, Sumit On Wed, Apr 28, 2010 at 05:30:24PM +0200, Sumit Bose wrote:
Hi,
these are the two patches for the IPA password migration for master. Because master already contains the sync sysdb patches it is not easy to rebase the first patch from the sssd-1-2 branch to master so I rewrote it. The second patch is mainly the same with a substitution of an async sysdb call with his sync version.
bye, Sumit
Ack to both (though I didn't test the migration. I verified by inspection that the changes from the other, tested patch aren't going to change functionality)
Pushed to master.
sssd-devel@lists.fedorahosted.org