From b8fba016681aabf82eb7739259e323242aa4a8c4 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Mar 05 2020 09:31:45 +0000 Subject: LDAP: Prepare for iphost lookups Signed-off-by: Samuel Cabrero Reviewed-by: Sumit Bose --- diff --git a/Makefile.am b/Makefile.am index e301c8c..68a2adc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4238,6 +4238,7 @@ libsss_ldap_common_la_SOURCES = \ src/providers/ldap/sdap_async_netgroups.c \ src/providers/ldap/sdap_async_hosts.c \ src/providers/ldap/sdap_async_services.c \ + src/providers/ldap/sdap_async_iphost.c \ src/providers/ldap/sdap_online_check.c \ src/providers/ldap/sdap_ad_groups.c \ src/providers/ldap/sdap_child_helpers.c \ diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h index 6e64fef..87b3249 100644 --- a/src/providers/ldap/sdap_async.h +++ b/src/providers/ldap/sdap_async.h @@ -365,6 +365,24 @@ enum_services_send(TALLOC_CTX *memctx, errno_t enum_services_recv(struct tevent_req *req); +struct tevent_req * +sdap_get_iphost_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sss_domain_info *dom, + struct sysdb_ctx *sysdb, + struct sdap_options *opts, + struct sdap_search_base **search_bases, + struct sdap_handle *sh, + const char **attrs, + const char *filter, + int timeout, + bool enumeration); +errno_t +sdap_get_iphost_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + char **usn_value); + + /* OID documented in * http://msdn.microsoft.com/en-us/library/windows/desktop/aa746475%28v=vs.85%29.aspx */ diff --git a/src/providers/ldap/sdap_async_iphost.c b/src/providers/ldap/sdap_async_iphost.c new file mode 100644 index 0000000..8c5dfb1 --- /dev/null +++ b/src/providers/ldap/sdap_async_iphost.c @@ -0,0 +1,66 @@ +/* + SSSD + + Authors: + Samuel Cabrero + + Copyright (C) 2019 SUSE LINUX GmbH, Nuernberg, Germany. + + 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 "providers/ldap/sdap_async_private.h" + +struct sdap_get_iphost_state { + int dummy; +}; + +struct tevent_req * +sdap_get_iphost_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sss_domain_info *dom, + struct sysdb_ctx *sysdb, + struct sdap_options *opts, + struct sdap_search_base **search_bases, + struct sdap_handle *sh, + const char **attrs, + const char *filter, + int timeout, + bool enumeration) +{ + struct sdap_get_ip_host_state *state; + struct tevent_req *req; + + req = tevent_req_create(mem_ctx, &state, struct sdap_get_iphost_state); + if (req == NULL) { + return NULL; + } + + /* TODO */ + + tevent_req_error(req, ENOENT); + return tevent_req_post(req, ev); +} + +errno_t +sdap_get_ip_host_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + char **usn_value) +{ + /* TODO */ + + TEVENT_REQ_RETURN_ON_ERROR(req); + + return EOK; +} diff --git a/src/providers/ldap/sdap_iphost.c b/src/providers/ldap/sdap_iphost.c index 800fad4..79c707b 100644 --- a/src/providers/ldap/sdap_iphost.c +++ b/src/providers/ldap/sdap_iphost.c @@ -21,11 +21,275 @@ */ #include "providers/ldap/ldap_common.h" +#include "providers/ldap/sdap_async.h" +#include "db/sysdb_iphosts.h" + +struct sdap_ip_host_get_state { + struct tevent_context *ev; + struct sdap_id_ctx *id_ctx; + struct sdap_domain *sdom; + struct sdap_id_op *op; + struct sysdb_ctx *sysdb; + struct sss_domain_info *domain; + struct sdap_id_conn_ctx *conn; + + uint32_t filter_type; + const char *filter_value; + + char *filter; + const char **attrs; + + int dp_error; + int sdap_ret; + bool noexist_delete; +}; + +static errno_t +sdap_ip_host_get_retry(struct tevent_req *req); + +static struct tevent_req * +sdap_iphost_get_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sdap_id_ctx *id_ctx, + struct sdap_domain *sdom, + struct sdap_id_conn_ctx *conn, + uint32_t filter_type, + const char *filter_value, + bool noexist_delete) +{ + struct tevent_req *req; + struct sdap_ip_host_get_state *state; + const char *attr_name; + char *clean_filter_value; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, struct sdap_ip_host_get_state); + if (req == NULL) { + return NULL; + } + + state->ev = ev; + state->id_ctx = id_ctx; + state->sdom = sdom; + state->conn = conn; + state->dp_error = DP_ERR_FATAL; + state->domain = sdom->dom; + state->sysdb = sdom->dom->sysdb; + state->filter_value = filter_value; + state->filter_type = filter_type; + state->noexist_delete = noexist_delete; + + state->op = sdap_id_op_create(state, state->conn->conn_cache); + if (state->op == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n"); + ret = ENOMEM; + goto fail; + } + + switch(filter_type) { + case BE_FILTER_NAME: + attr_name = id_ctx->opts->iphost_map[SDAP_AT_IPHOST_NAME].name; + break; + case BE_FILTER_ADDR: + attr_name = id_ctx->opts->iphost_map[SDAP_AT_IPHOST_NUMBER].name; + break; + default: + ret = EINVAL; + goto fail; + } + + ret = sss_filter_sanitize(state, filter_value, &clean_filter_value); + if (ret != EOK) { + goto fail; + } + + state->filter = talloc_asprintf(state, "(&(objectclass=%s)(%s=%s))", + id_ctx->opts->iphost_map[SDAP_OC_IPHOST].name, + attr_name, clean_filter_value); + talloc_zfree(clean_filter_value); + if (state->filter == NULL) { + DEBUG(SSSDBG_MINOR_FAILURE, "Failed to build the base filter\n"); + ret = ENOMEM; + goto fail; + } + + ret = build_attrs_from_map(state, id_ctx->opts->iphost_map, + SDAP_OPTS_IPHOST, NULL, &state->attrs, NULL); + if (ret != EOK) { + goto fail; + } + + ret = sdap_ip_host_get_retry(req); + if (ret != EOK) { + goto fail; + } + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void +sdap_ip_host_get_connect_done(struct tevent_req *subreq); + +static errno_t +sdap_ip_host_get_retry(struct tevent_req *req) +{ + struct sdap_ip_host_get_state *state; + struct tevent_req *subreq; + errno_t ret = EOK; + + state = tevent_req_data(req, struct sdap_ip_host_get_state); + + subreq = sdap_id_op_connect_send(state->op, state, &ret); + if (subreq == NULL) { + return ret; + } + + tevent_req_set_callback(subreq, sdap_ip_host_get_connect_done, req); + + return EOK; +} + +static void +sdap_ip_host_get_done(struct tevent_req *subreq); + +static void +sdap_ip_host_get_connect_done(struct tevent_req *subreq) +{ + struct tevent_req *req; + struct sdap_ip_host_get_state *state; + int dp_error = DP_ERR_FATAL; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_ip_host_get_state); + + 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; + } + + subreq = sdap_get_iphost_send(state, state->ev, + state->domain, state->sysdb, + state->id_ctx->opts, + state->sdom->iphost_search_bases, + sdap_id_op_handle(state->op), + state->attrs, state->filter, + dp_opt_get_int(state->id_ctx->opts->basic, + SDAP_SEARCH_TIMEOUT), + false); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + + tevent_req_set_callback(subreq, sdap_ip_host_get_done, req); +} + +static void +sdap_ip_host_get_done(struct tevent_req *subreq) +{ + errno_t ret; + struct tevent_req *req; + struct sdap_ip_host_get_state *state; + int dp_error = DP_ERR_FATAL; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_ip_host_get_state); + + ret = sdap_get_iphost_recv(NULL, subreq, NULL); + talloc_zfree(subreq); + + /* Check whether we need to try again with another + * failover server. */ + ret = sdap_id_op_done(state->op, ret, &dp_error); + if (dp_error == DP_ERR_OK && ret != EOK) { + /* retry */ + ret = sdap_ip_host_get_retry(req); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + /* Return to the mainloop to retry */ + return; + } + state->sdap_ret = ret; + + /* An error occurred. */ + if (ret && ret != ENOENT) { + state->dp_error = dp_error; + tevent_req_error(req, ret); + return; + } + + if (ret == ENOENT && state->noexist_delete == true) { + /* Ensure that this entry is removed from the sysdb */ + switch (state->filter_type) { + case BE_FILTER_NAME: + ret = sysdb_host_delete(state->domain, state->filter_value, + NULL); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + break; + + case BE_FILTER_ADDR: + ret = sysdb_host_delete(state->domain, NULL, + state->filter_value); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + break; + + default: + tevent_req_error(req, EINVAL); + return; + } + } + + state->dp_error = DP_ERR_OK; + tevent_req_done(req); +} + +static errno_t +sdap_ip_host_get_recv(struct tevent_req *req, + int *dp_error_out, + int *sdap_ret) +{ + struct sdap_ip_host_get_state *state; + + state = tevent_req_data(req, struct sdap_ip_host_get_state); + + if (dp_error_out != NULL) { + *dp_error_out = state->dp_error; + } + + if (sdap_ret != NULL) { + *sdap_ret = state->sdap_ret; + } + + TEVENT_REQ_RETURN_ON_ERROR(req); + + return EOK; +} struct sdap_ip_host_handler_state { - int dummy; + struct dp_reply_std reply; }; +static void sdap_ip_host_handler_done(struct tevent_req *subreq); + struct tevent_req * sdap_iphost_handler_send(TALLOC_CTX *mem_ctx, struct sdap_resolver_ctx *resolver_ctx, @@ -34,6 +298,8 @@ sdap_iphost_handler_send(TALLOC_CTX *mem_ctx, { struct sdap_ip_host_handler_state *state; struct tevent_req *req; + struct tevent_req *subreq; + errno_t ret; req = tevent_req_create(mem_ctx, &state, struct sdap_ip_host_handler_state); @@ -42,9 +308,54 @@ sdap_iphost_handler_send(TALLOC_CTX *mem_ctx, return NULL; } - /* TODO */ + if (resolver_data->filter_type == BE_FILTER_ENUM) { + DEBUG(SSSDBG_TRACE_LIBS, "Skipping enumeration on demand\n"); + ret = EOK; + goto immediately; + } + + subreq = sdap_iphost_get_send(state, params->ev, + resolver_ctx->id_ctx, + resolver_ctx->id_ctx->opts->sdom, + resolver_ctx->id_ctx->conn, + resolver_data->filter_type, + resolver_data->filter_value, + true); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; + } + + tevent_req_set_callback(subreq, sdap_ip_host_handler_done, req); + + return req; + +immediately: + dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL); + + /* TODO For backward compatibility we always return EOK to DP now. */ + tevent_req_done(req); + tevent_req_post(req, params->ev); + + return req; +} + +static void sdap_ip_host_handler_done(struct tevent_req *subreq) +{ + struct sdap_ip_host_handler_state *state; + struct tevent_req *req; + int dp_error; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_ip_host_handler_state); + + ret = sdap_ip_host_get_recv(subreq, &dp_error, NULL); + talloc_zfree(subreq); + + /* TODO For backward compatibility we always return EOK to DP now. */ + dp_reply_std_set(&state->reply, dp_error, ret, NULL); tevent_req_done(req); - return tevent_req_post(req, params->ev); } errno_t @@ -52,9 +363,13 @@ sdap_iphost_handler_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, struct dp_reply_std *data) { + struct sdap_ip_host_handler_state *state; + + state = tevent_req_data(req, struct sdap_ip_host_handler_state); + TEVENT_REQ_RETURN_ON_ERROR(req); - /* TODO */ + *data = state->reply; return EOK; }