From 881c4ba834b23ae651ac01db667801f314eb0a5d Mon Sep 17 00:00:00 2001 From: Jan Zeleny Date: Thu, 16 Feb 2012 09:55:13 -0500 Subject: Add ID operations in subdomains --- Makefile.am | 1 + src/providers/ipa/ipa_id.c | 30 +++++ src/providers/ipa/ipa_id.h | 6 + src/providers/ipa/ipa_subdomains_id.c | 240 ++++++++++++++++++++++++++++++++++ 4 files changed, 277 insertions(+) create mode 100644 src/providers/ipa/ipa_subdomains_id.c diff --git a/Makefile.am b/Makefile.am index fc54e716b..5d9566212 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1196,6 +1196,7 @@ libsss_ipa_la_SOURCES = \ src/providers/ipa/ipa_dyndns.c \ src/providers/ipa/ipa_hosts.c \ src/providers/ipa/ipa_subdomains.c \ + src/providers/ipa/ipa_subdomains_id.c \ src/providers/ipa/ipa_s2n_exop.c \ src/providers/ipa/ipa_hbac_hosts.c \ src/providers/ipa/ipa_hbac_private.h \ diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c index c3ec983e0..f2a27c74e 100644 --- a/src/providers/ipa/ipa_id.c +++ b/src/providers/ipa/ipa_id.c @@ -57,6 +57,7 @@ static int ipa_netgroup_get_retry(struct tevent_req *req); static void ipa_netgroup_get_connect_done(struct tevent_req *subreq); static void ipa_netgroup_get_done(struct tevent_req *subreq); static void ipa_account_info_netgroups_done(struct tevent_req *req); +static void ipa_account_info_users_done(struct tevent_req *req); void ipa_account_info_handler(struct be_req *breq) { @@ -76,6 +77,24 @@ void ipa_account_info_handler(struct be_req *breq) ar = talloc_get_type(breq->req_data, struct be_acct_req); + if (strcasecmp(ar->domain, breq->be_ctx->domain->name) != 0) { + if (! ((ar->entry_type & BE_REQ_USER) || + (ar->entry_type & BE_REQ_GROUP))) { + return sdap_handler_done(breq, DP_ERR_FATAL, EINVAL, + "Invalid sub-domain request type"); + } + + req = ipa_get_subdomain_account_info_send(breq, breq->be_ctx->ev, ctx, + ar); + if (!req) { + return sdap_handler_done(breq, DP_ERR_FATAL, ENOMEM, "Out of memory"); + } + + tevent_req_set_callback(req, ipa_account_info_users_done, breq); + + return; + } + switch (ar->entry_type & 0xFFF) { case BE_REQ_USER: /* user */ case BE_REQ_GROUP: /* group */ @@ -130,6 +149,17 @@ static void ipa_account_info_complete(struct be_req *breq, int dp_error, sdap_handler_done(breq, dp_error, ret, error_text); } +static void ipa_account_info_users_done(struct tevent_req *req) +{ + struct be_req *breq = tevent_req_callback_data(req, struct be_req); + int ret, dp_error; + + ret = ipa_user_get_recv(req, &dp_error); + talloc_zfree(req); + + ipa_account_info_complete(breq, dp_error, ret, "User lookup failed"); +} + /* Request for netgroups * - first start here and then go to ipa_netgroups.c */ diff --git a/src/providers/ipa/ipa_id.h b/src/providers/ipa/ipa_id.h index b79234493..c264286f0 100644 --- a/src/providers/ipa/ipa_id.h +++ b/src/providers/ipa/ipa_id.h @@ -59,4 +59,10 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx, const char *user_name, uid_t uid); int ipa_s2n_get_acct_info_recv(struct tevent_req *req); + +struct tevent_req *ipa_get_subdomain_account_info_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sdap_id_ctx *ctx, + struct be_acct_req *ar); +int ipa_user_get_recv(struct tevent_req *req, int *dp_error_out); #endif diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c new file mode 100644 index 000000000..a4558e684 --- /dev/null +++ b/src/providers/ipa/ipa_subdomains_id.c @@ -0,0 +1,240 @@ +/* + SSSD + + IPA Identity Backend Module for sub-domains + + Authors: + Sumit Bose + + Copyright (C) 2012 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 . +*/ + +#include + +#include "util/util.h" +#include "util/strtonum.h" +#include "db/sysdb.h" +#include "providers/ldap/ldap_common.h" +#include "providers/ldap/sdap_async.h" +#include "providers/ipa/ipa_id.h" + +struct ipa_user_get_state { + struct tevent_context *ev; + struct sdap_id_ctx *ctx; + struct sdap_id_op *op; + struct sysdb_ctx *sysdb; + struct sss_domain_info *domain; + + int entry_type; + const char *filter; + int filter_type; + + const char **attrs; + + int dp_error; +}; + +static int ipa_get_subdomain_account_info_retry(struct tevent_req *req); +static void ipa_get_subdomain_account_info_connect_done(struct tevent_req *subreq); +static void ipa_get_subdomain_account_info_done(struct tevent_req *subreq); +struct tevent_req *ipa_get_subdomain_account_info_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sdap_id_ctx *ctx, + struct be_acct_req *ar) +{ + struct tevent_req *req; + struct ipa_user_get_state *state; + int ret; + + req = tevent_req_create(memctx, &state, struct ipa_user_get_state); + if (!req) return NULL; + + state->ev = ev; + state->ctx = ctx; + state->dp_error = DP_ERR_FATAL; + + state->op = sdap_id_op_create(state, state->ctx->conn_cache); + if (!state->op) { + DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed\n")); + ret = ENOMEM; + goto fail; + } + + state->domain = new_subdomain(state, state->ctx->be->domain, ar->domain, + NULL, NULL); + if (state->domain == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("new_subdomain failed.\n")); + ret = ENOMEM; + goto fail; + } + state->sysdb = state->domain->sysdb; + + state->entry_type = (ar->entry_type & 0xFFF); + state->filter = ar->filter_value; + state->filter_type = ar->filter_type; + + switch (state->entry_type) { + case BE_REQ_USER: + ret = build_attrs_from_map(state, ctx->opts->user_map, + SDAP_OPTS_USER, &state->attrs); + break; + case BE_REQ_GROUP: + ret = build_attrs_from_map(state, ctx->opts->group_map, + SDAP_OPTS_GROUP, &state->attrs); + break; + default: + ret = EINVAL; + DEBUG(SSSDBG_OP_FAILURE, ("Invalid sub-domain request type.\n")); + } + if (ret != EOK) goto fail; + + ret = ipa_get_subdomain_account_info_retry(req); + if (ret != EOK) { + goto fail; + } + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static int ipa_get_subdomain_account_info_retry(struct tevent_req *req) +{ + struct ipa_user_get_state *state = tevent_req_data(req, + struct ipa_user_get_state); + struct tevent_req *subreq; + int ret = EOK; + + subreq = sdap_id_op_connect_send(state->op, state, &ret); + if (!subreq) { + return ret; + } + + tevent_req_set_callback(subreq, ipa_get_subdomain_account_info_connect_done, + req); + return EOK; +} + +static void ipa_get_subdomain_account_info_connect_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct ipa_user_get_state *state = tevent_req_data(req, + struct ipa_user_get_state); + int dp_error = DP_ERR_FATAL; + int ret; + const char *name; + uint32_t id; + char *endptr; + + ret = sdap_id_op_connect_recv(subreq, &dp_error); + talloc_zfree(subreq); + if (ret != EOK) { + state->dp_error = dp_error; + tevent_req_error(req, ret); + return; + } + + switch (state->filter_type) { + case BE_FILTER_NAME: + name = state->filter; + id = 0; + break; + case BE_FILTER_IDNUM: + name = NULL; + id = strtouint32(state->filter, &endptr, 10); + if (errno || *endptr || (state->filter == endptr)) { + tevent_req_error(req, errno ? errno : EINVAL); + return; + } + break; + default: + DEBUG(SSSDBG_OP_FAILURE, ("Invalid sub-domain filter type.\n")); + state->dp_error = dp_error; + tevent_req_error(req, EINVAL); + return; + } + + subreq = ipa_s2n_get_acct_info_send(state, + state->ev, + state->ctx->opts, + state->domain, + sdap_id_op_handle(state->op), + state->attrs, + state->entry_type, + name, id); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, ipa_get_subdomain_account_info_done, req); + + return; +} + +static void ipa_get_subdomain_account_info_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct ipa_user_get_state *state = tevent_req_data(req, + struct ipa_user_get_state); + int dp_error = DP_ERR_FATAL; + int ret; + + ret = ipa_s2n_get_acct_info_recv(subreq); + talloc_zfree(subreq); + + ret = sdap_id_op_done(state->op, ret, &dp_error); + if (dp_error == DP_ERR_OK && ret != EOK) { + /* retry */ + ret = ipa_get_subdomain_account_info_retry(req); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + return; + } + + if (ret && ret != ENOENT) { + state->dp_error = dp_error; + tevent_req_error(req, ret); + return; + } + + /* FIXME: do we need some special handling of ENOENT */ + + state->dp_error = DP_ERR_OK; + tevent_req_done(req); +} + +int ipa_user_get_recv(struct tevent_req *req, int *dp_error_out) +{ + struct ipa_user_get_state *state = tevent_req_data(req, + struct ipa_user_get_state); + + if (dp_error_out) { + *dp_error_out = state->dp_error; + } + + TEVENT_REQ_RETURN_ON_ERROR(req); + + return EOK; +} + -- cgit