diff options
-rw-r--r-- | server/Makefile.am | 2 | ||||
-rw-r--r-- | server/providers/ipa/ipa_auth.c | 313 | ||||
-rw-r--r-- | server/providers/ipa/ipa_auth.h | 32 | ||||
-rw-r--r-- | server/providers/ipa/ipa_init.c | 3 | ||||
-rw-r--r-- | server/providers/krb5/krb5_child.c | 3 |
5 files changed, 352 insertions, 1 deletions
diff --git a/server/Makefile.am b/server/Makefile.am index fc2ac94d5..4259f6cf7 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -299,6 +299,7 @@ dist_noinst_HEADERS = \ providers/ipa/ipa_common.h \ providers/ipa/ipa_access.h \ providers/ipa/ipa_timerules.h \ + providers/ipa/ipa_auth.h \ tools/tools_util.h \ tools/sss_sync_ops.h \ resolv/async_resolv.h \ @@ -598,6 +599,7 @@ libsss_krb5_la_LDFLAGS = \ libsss_ipa_la_SOURCES = \ providers/ipa/ipa_init.c \ providers/ipa/ipa_common.c \ + providers/ipa/ipa_auth.c \ providers/ipa/ipa_access.c \ providers/ipa/ipa_timerules.c \ providers/ldap/ldap_id.c \ diff --git a/server/providers/ipa/ipa_auth.c b/server/providers/ipa/ipa_auth.c new file mode 100644 index 000000000..9f9a48e24 --- /dev/null +++ b/server/providers/ipa/ipa_auth.c @@ -0,0 +1,313 @@ +/* + SSSD + + IPA Backend Module -- Authentication + + Authors: + Sumit Bose <sbose@redhat.com> + + Copyright (C) 2009 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 + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <sys/param.h> +#include <security/pam_modules.h> + +#include "util/util.h" +#include "providers/ldap/ldap_common.h" +#include "providers/ldap/sdap_async.h" +#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; +}; + +static void ipa_auth_reply(struct ipa_auth_ctx *ipa_auth_ctx) +{ + 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); +} + +struct ipa_auth_handler_state { + struct tevent_context *ev; + + int dp_err_type; + int errnum; + char *errstr; +}; + +static void ipa_auth_handler_callback(struct be_req *be_req, + int dp_err_type, + int errnum, + const char *errstr); + +static struct tevent_req *ipa_auth_handler_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct be_req *be_req, + be_req_fn_t auth_handler) +{ + struct ipa_auth_handler_state *state; + struct tevent_req *req; + + req = tevent_req_create(memctx, &state, struct ipa_auth_handler_state); + if (req == NULL) { + DEBUG(1, ("tevent_req_create failed.\n")); + return NULL; + } + + state->ev = ev; + + be_req->fn = ipa_auth_handler_callback; + be_req->pvt = req; + + auth_handler(be_req); + + return req; +} + +static void ipa_auth_handler_callback(struct be_req *be_req, + int dp_err_type, + int errnum, + const char *errstr) +{ + 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); + + 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); + + tevent_req_post(req, state->ev); + tevent_req_done(req); + return; +} + +static int ipa_auth_handler_recv(struct tevent_req *req, TALLOC_CTX *memctx, + int *dp_err_type, int *errnum, + char **errstr) +{ + 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; + } + + *dp_err_type = state->dp_err_type; + *errnum = state->errnum; + *errstr = talloc_steal(memctx, state->errstr); + + return EOK; +} + + +static void ipa_auth_handler_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; + + 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")); + 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: make password_migration configurable */ + ipa_auth_ctx->password_migration = true; + + ipa_auth_ctx->dp_err_type = DP_ERR_FATAL; + ipa_auth_ctx->errnum = EIO; + ipa_auth_ctx->errstr = NULL; + + 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_handler_send failed.\n")); + goto fail; + } + + tevent_req_set_callback(req, ipa_auth_handler_done, ipa_auth_ctx); + return; + +fail: + ipa_auth_reply(ipa_auth_ctx); +} + +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; + int ret; + + 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); + talloc_zfree(req); + if (ret != EOK) { + DEBUG(1, ("ipa_auth_handler request failed.\n")); + pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) { + pd->pam_status = ipa_auth_ctx->errnum; + goto done; + } + + if (ipa_auth_ctx->password_migration && pd->pam_status == PAM_CRED_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); + if (req == NULL) { + DEBUG(1, ("ipa_auth_ldap_send failed.\n")); + goto done; + } + + tevent_req_set_callback(req, ipa_auth_ldap_done, ipa_auth_ctx); + return; + } + +done: + ipa_auth_reply(ipa_auth_ctx); +} + +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; + int ret; + + 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); + talloc_zfree(req); + if (ret != EOK) { + DEBUG(1, ("ipa_auth_handler request failed.\n")); + pd->pam_status = PAM_SYSTEM_ERR; + goto done; + } + if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) { + pd->pam_status = ipa_auth_ctx->errnum; + 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; + } + + tevent_req_set_callback(req, ipa_auth_handler_retry_done, ipa_auth_ctx); + return; + } + +done: + ipa_auth_reply(ipa_auth_ctx); +} + +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; + int ret; + + 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); + 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; + } + + ipa_auth_reply(ipa_auth_ctx); +} diff --git a/server/providers/ipa/ipa_auth.h b/server/providers/ipa/ipa_auth.h new file mode 100644 index 000000000..3079bbd1b --- /dev/null +++ b/server/providers/ipa/ipa_auth.h @@ -0,0 +1,32 @@ +/* + SSSD + + IPA Backend Module -- Authentication + + Authors: + Sumit Bose <sbose@redhat.com> + + Copyright (C) 2009 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 + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _IPA_AUTH_H_ +#define _IPA_AUTH_H_ + +#include "providers/dp_backend.h" + +void ipa_auth(struct be_req *be_req); + +#endif /* _IPA_AUTH_H_ */ diff --git a/server/providers/ipa/ipa_init.c b/server/providers/ipa/ipa_init.c index 1b93e14dd..701452879 100644 --- a/server/providers/ipa/ipa_init.c +++ b/server/providers/ipa/ipa_init.c @@ -29,6 +29,7 @@ #include "providers/ipa/ipa_common.h" #include "providers/krb5/krb5_auth.h" +#include "providers/ipa/ipa_auth.h" #include "providers/ipa/ipa_access.h" #include "providers/ipa/ipa_timerules.h" @@ -41,7 +42,7 @@ struct bet_ops ipa_id_ops = { }; struct bet_ops ipa_auth_ops = { - .handler = krb5_pam_handler, + .handler = ipa_auth, .finalize = NULL, }; diff --git a/server/providers/krb5/krb5_child.c b/server/providers/krb5/krb5_child.c index 5a1bf374e..f7809d2c6 100644 --- a/server/providers/krb5/krb5_child.c +++ b/server/providers/krb5/krb5_child.c @@ -582,6 +582,9 @@ static errno_t tgt_req_child(int fd, struct krb5_req *kr) case KRB5KDC_ERR_KEY_EXP: pam_status = PAM_AUTHTOK_EXPIRED; break; + case KRB5KDC_ERR_PREAUTH_FAILED: + pam_status = PAM_CRED_ERR; + break; default: pam_status = PAM_SYSTEM_ERR; } |