From 1ed85377ec6de713f738ba498235fb352642841c Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Wed, 31 Mar 2010 15:30:28 +0200 Subject: First try to read mirgation flag --- src/providers/ipa/ipa_auth.c | 259 +++++++++++++++++++++++++++++++++++++++-- src/providers/ipa/ipa_common.h | 2 +- src/providers/ipa/ipa_init.c | 15 ++- 3 files changed, 262 insertions(+), 14 deletions(-) diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c index c8fd77d30..fe58e1759 100644 --- a/src/providers/ipa/ipa_auth.c +++ b/src/providers/ipa/ipa_auth.c @@ -32,18 +32,221 @@ #include "providers/krb5/krb5_auth.h" #include "providers/ipa/ipa_common.h" +#define IPA_CONFIG_MIRATION_ENABLED "ipaMigrationEnabled" +#define IPA_CONFIG_TEMPLATE "cn=ipaConfig,cn=etc,%s" + static void ipa_auth_reply(struct be_req *be_req, int dp_err, int result) { be_req->fn(be_req, dp_err, result, NULL); } +struct get_password_migration_flag_state { + struct tevent_context *ev; + 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 get_password_migration_flag_resolve_done(struct tevent_req *subreq); +static void get_password_migration_flag_connect_done(struct tevent_req *subreq); +static void get_password_migration_flag_done(struct tevent_req *subreq); + +static struct tevent_req *get_password_migration_flag(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sdap_auth_ctx *sdap_auth_ctx, + char *ipa_domain) +{ + struct tevent_req *req, *subreq; + struct get_password_migration_flag_state *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->srv = NULL; + state->password_migration = false; + state->ipa_domain = ipa_domain; + + subreq = be_resolve_server_send(state, ev, sdap_auth_ctx->be, + sdap_auth_ctx->service->name); + if (subreq == NULL) { + DEBUG(1, ("be_resolve_server_send failed.\n")); + goto fail; + } + + tevent_req_set_callback(subreq, get_password_migration_flag_resolve_done, + req); + + return req; + +fail: + talloc_zfree(req); + return NULL; +} + +static void get_password_migration_flag_resolve_done(struct tevent_req *subreq) +{ + 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; + + ret = be_resolve_server_recv(subreq, &state->srv); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + subreq = sdap_connect_send(state, state->ev, state->sdap_auth_ctx->opts, + state->sdap_auth_ctx->service->uri, false); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + + tevent_req_set_callback(subreq, get_password_migration_flag_connect_done, + req); +} + +static void get_password_migration_flag_connect_done(struct tevent_req *subreq) +{ + 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_connect_recv(subreq, state, &state->sh); + talloc_zfree(subreq); + if (ret) { + if (state->srv) { + /* mark this server as bad if connection failed */ + fo_set_port_status(state->srv, PORT_NOT_WORKING); + } + + tevent_req_error(req, ret); + return; + } else if (state->srv) { + fo_set_port_status(state->srv, PORT_WORKING); + } + + 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; + } + + search_base = talloc_asprintf(state, IPA_CONFIG_TEMPLATE, ldap_basedn); + if (search_base == NULL) { + DEBUG(1, ("talloc_asprintf failed.\n")); + tevent_req_error(req, ENOMEM); + 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_BASE, + NULL, attrs, NULL, 0); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + + tevent_req_set_callback(subreq, get_password_migration_flag_done, req); +} + +static void get_password_migration_flag_done(struct tevent_req *subreq) +{ + 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; + + 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 || reply[0]->num != 1 || + reply[0]->a[0].num_values != 1) { + DEBUG(1, ("Unexpected number of results, expected (1,1,1), " + "got (%d,%d,%d).\n", reply_count, reply[0]->num, + reply[0]->a[0].num_values)); + tevent_req_error(req, EINVAL); + return; + } + + if (strcmp(reply[0]->a[0].name, IPA_CONFIG_MIRATION_ENABLED) != 0) { + DEBUG(1, ("Got the wrong attribute, expected [%s], got [%s].\n", + IPA_CONFIG_MIRATION_ENABLED, reply[0]->a[0].name)); + tevent_req_error(req, EINVAL); + return; + } + + if (strncasecmp((char *) reply[0]->a[0].values[0].data, "true", + reply[0]->a[0].values[0].length) == 0) { + state->password_migration = true; + } + + tevent_req_done(req); +} + +static int get_password_migration_flag_recv(struct tevent_req *req, + bool *password_migration) +{ + 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; + + return EOK; +} + + struct ipa_auth_state { struct be_req *be_req; struct ipa_auth_ctx *ipa_auth_ctx; struct pam_data *pd; + bool password_migration; }; 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_ldap_done(struct tevent_req *req); static void ipa_auth_handler_retry_done(struct tevent_req *req); @@ -58,6 +261,9 @@ void ipa_auth(struct be_req *be_req) goto fail; } +/* TODO: test and activate when server side support is available */ + state->password_migration = false; + state->be_req = be_req; state->pd = talloc_get_type(be_req->req_data, struct pam_data); @@ -79,9 +285,6 @@ void ipa_auth(struct be_req *be_req) goto fail; } -/* TODO: test and activate when server side support is available */ - state->ipa_auth_ctx->password_migration = true; - req = krb5_auth_send(state, be_req->be_ctx->ev, be_req->be_ctx, state->pd, state->ipa_auth_ctx->krb5_auth_ctx); if (req == NULL) { @@ -102,29 +305,61 @@ static void ipa_auth_handler_done(struct tevent_req *req) struct ipa_auth_state *state = tevent_req_callback_data(req, struct ipa_auth_state); int ret; - int pam_status; + int pam_status = PAM_SYSTEM_ERR; int dp_err; - struct dp_opt_blob password; ret = krb5_auth_recv(req, &pam_status, &dp_err); talloc_zfree(req); + state->pd->pam_status = pam_status; if (ret != EOK && pam_status != PAM_CRED_ERR) { DEBUG(1, ("krb5_auth_recv request failed.\n")); - state->pd->pam_status = PAM_SYSTEM_ERR; dp_err = DP_ERR_OK; goto done; } - state->pd->pam_status = pam_status; - if (dp_err != DP_ERR_OK) { goto done; } - if (state->ipa_auth_ctx->password_migration && - state->pd->cmd == SSS_PAM_AUTHENTICATE && + if (state->pd->cmd == SSS_PAM_AUTHENTICATE && state->pd->pam_status == PAM_CRED_ERR) { + req = get_password_migration_flag(state, state->be_req->be_ctx->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; + struct dp_opt_blob password; + + ret = get_password_migration_flag_recv(req, &state->password_migration); + 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 (state->password_migration) { state->pd->pam_status = PAM_SYSTEM_ERR; DEBUG(1, ("Assuming Kerberos password is missing, " "starting password migration.\n")); @@ -142,8 +377,12 @@ static void ipa_auth_handler_done(struct tevent_req *req) 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); } diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h index 3eaf9d9e7..03a082efd 100644 --- a/src/providers/ipa/ipa_common.h +++ b/src/providers/ipa/ipa_common.h @@ -53,7 +53,7 @@ enum ipa_basic_opt { struct ipa_auth_ctx { struct krb5_ctx *krb5_auth_ctx; struct sdap_auth_ctx *sdap_auth_ctx; - bool password_migration; + struct dp_option *ipa_options; }; struct ipa_options { diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c index 0ddd5fcca..992286539 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, }; @@ -190,9 +190,17 @@ int sssm_ipa_auth_init(struct be_ctx *bectx, } ipa_options->auth_ctx = ipa_auth_ctx; + ret = dp_copy_options(ipa_auth_ctx, ipa_options->basic, + IPA_OPTS_BASIC, &ipa_auth_ctx->ipa_options); + if (ret != EOK) { + DEBUG(1, ("dp_copy_options failed.\n")); + goto done; + } + krb5_auth_ctx = talloc_zero(ipa_auth_ctx, struct krb5_ctx); if (!krb5_auth_ctx) { - return ENOMEM; + ret = ENOMEM; + goto done; } krb5_auth_ctx->service = ipa_options->service->krb5_service; ipa_options->auth_ctx->krb5_auth_ctx = krb5_auth_ctx; @@ -205,7 +213,8 @@ int sssm_ipa_auth_init(struct be_ctx *bectx, sdap_auth_ctx = talloc_zero(ipa_auth_ctx, struct sdap_auth_ctx); if (!sdap_auth_ctx) { - return ENOMEM; + ret = ENOMEM; + goto done; } sdap_auth_ctx->be = bectx; sdap_auth_ctx->service = ipa_options->service->sdap; -- cgit