summaryrefslogtreecommitdiffstats
path: root/src/providers/ad/ad_subdomains.c
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2016-03-29 12:38:25 +0200
committerJakub Hrozek <jhrozek@redhat.com>2016-06-20 14:48:47 +0200
commitdea636af4d1902a081ee891f1b19ee2f8729d759 (patch)
treea4d66ceb2b32ddf3b69bee1f1e2412568eae655e /src/providers/ad/ad_subdomains.c
parent62370340092503baeaf6587d7ffe4fe25bd9582d (diff)
downloadsssd-dea636af4d1902a081ee891f1b19ee2f8729d759.tar.gz
sssd-dea636af4d1902a081ee891f1b19ee2f8729d759.tar.xz
sssd-dea636af4d1902a081ee891f1b19ee2f8729d759.zip
DP: Switch to new interface
Reviewed-by: Sumit Bose <sbose@redhat.com> Reviewed-by: Jakub Hrozek <jhrozek@redhat.com> Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
Diffstat (limited to 'src/providers/ad/ad_subdomains.c')
-rw-r--r--src/providers/ad/ad_subdomains.c1404
1 files changed, 782 insertions, 622 deletions
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index 1aee92cab..5b0bee866 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -29,6 +29,7 @@
#include "providers/ad/ad_common.h"
#include "providers/ldap/sdap_idmap.h"
+#include "providers/ldap/sdap_ops.h"
#include "util/util_sss_idmap.h"
#include <ctype.h>
#include <ndr.h>
@@ -56,42 +57,6 @@
/* do not refresh more often than every 5 seconds for now */
#define AD_SUBDOMAIN_REFRESH_LIMIT 5
-struct ad_subdomains_ctx {
- struct be_ctx *be_ctx;
- struct sdap_id_ctx *sdap_id_ctx;
- struct sdap_domain *sdom;
- struct sdap_id_conn_ctx *ldap_ctx;
- struct sss_idmap_ctx *idmap_ctx;
- char *domain_name;
-
- time_t last_refreshed;
- struct tevent_timer *timer_event;
- struct ad_id_ctx *ad_id_ctx;
-};
-
-struct ad_subdomains_req_ctx {
- struct be_req *be_req;
- struct ad_subdomains_ctx *sd_ctx;
- struct sdap_id_op *sdap_op;
-
- char *current_filter;
- size_t base_iter;
-
- struct ad_id_ctx *root_id_ctx;
- struct sdap_id_op *root_op;
- size_t root_base_iter;
- struct sysdb_attrs *root_domain_attrs;
- struct sss_domain_info *root_domain;
-
- size_t reply_count;
- struct sysdb_attrs **reply;
-
- char *master_sid;
- char *flat_name;
- char *site;
- char *forest;
-};
-
static errno_t
ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
struct ad_id_ctx *id_ctx,
@@ -119,8 +84,8 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
return EINVAL;
}
- ad_options = ad_create_2way_trust_options(id_ctx, realm,
- ad_domain, hostname, keytab);
+ ad_options = ad_create_2way_trust_options(id_ctx, realm, ad_domain,
+ hostname, keytab);
if (ad_options == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD options\n");
talloc_free(ad_options);
@@ -192,34 +157,16 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
return EOK;
}
-static errno_t
-ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx,
- struct sss_domain_info *parent)
-{
- int ret;
- struct sdap_domain *sditer;
- struct ad_id_ctx *subdom_id_ctx;
-
- ret = sdap_domain_subdom_add(ctx->sdap_id_ctx, ctx->sdom, parent);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_domain_subdom_add failed.\n");
- return ret;
- }
+struct ad_subdomains_ctx {
+ struct be_ctx *be_ctx;
+ struct ad_id_ctx *ad_id_ctx;
+ struct sdap_id_ctx *sdap_id_ctx;
- DLIST_FOR_EACH(sditer, ctx->sdom) {
- if (IS_SUBDOMAIN(sditer->dom) && sditer->pvt == NULL) {
- ret = ad_subdom_ad_ctx_new(ctx->be_ctx, ctx->ad_id_ctx,
- sditer->dom, &subdom_id_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "ad_subdom_ad_ctx_new failed.\n");
- } else {
- sditer->pvt = subdom_id_ctx;
- }
- }
- }
+ struct sdap_domain *sdom;
+ char *domain_name;
- return EOK;
-}
+ time_t last_refreshed;
+};
static errno_t ad_subdom_enumerates(struct sss_domain_info *parent,
struct sysdb_attrs *attrs,
@@ -239,7 +186,7 @@ static errno_t ad_subdom_enumerates(struct sss_domain_info *parent,
}
static errno_t
-ad_subdom_store(struct ad_subdomains_ctx *ctx,
+ad_subdom_store(struct sdap_idmap_ctx *idmap_ctx,
struct sss_domain_info *domain,
struct sysdb_attrs *subdom_attrs,
bool enumerate)
@@ -293,10 +240,8 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx,
goto done;
}
- err = sss_idmap_bin_sid_to_sid(ctx->idmap_ctx,
- el->values[0].data,
- el->values[0].length,
- &sid_str);
+ err = sss_idmap_bin_sid_to_sid(idmap_ctx->map, el->values[0].data,
+ el->values[0].length, &sid_str);
if (err != IDMAP_SUCCESS) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Could not convert SID: [%s].\n", idmap_error_string(err));
@@ -304,10 +249,7 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx,
goto done;
}
- mpg = sdap_idmap_domain_has_algorithmic_mapping(
- ctx->sdap_id_ctx->opts->idmap_ctx,
- name,
- sid_str);
+ mpg = sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, name, sid_str);
ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str,
mpg, enumerate, domain->forest, 0);
@@ -318,32 +260,37 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx,
ret = EOK;
done:
- sss_idmap_free_sid(ctx->sdap_id_ctx->opts->idmap_ctx->map, sid_str);
+ sss_idmap_free_sid(idmap_ctx->map, sid_str);
talloc_free(tmp_ctx);
return ret;
}
-static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
- int count, bool root_domain,
- struct sysdb_attrs **reply,
- bool *changes)
+static errno_t ad_subdomains_refresh(struct be_ctx *be_ctx,
+ struct sdap_idmap_ctx *idmap_ctx,
+ struct sdap_options *opts,
+ struct sysdb_attrs **subdomains,
+ size_t num_subdomains,
+ bool root_domain,
+ time_t *_last_refreshed,
+ bool *_changes)
{
struct sdap_domain *sdom;
- struct sss_domain_info *domain, *dom;
- bool handled[count];
+ struct sss_domain_info *domain;
+ struct sss_domain_info *dom;
+ bool handled[num_subdomains];
const char *value;
const char *root_name = NULL;
- int c, h;
+ size_t c, h;
int ret;
bool enumerate;
- domain = ctx->be_ctx->domain;
- memset(handled, 0, sizeof(bool) * count);
+ domain = be_ctx->domain;
+ memset(handled, 0, sizeof(bool) * num_subdomains);
h = 0;
if (root_domain) {
- ret = sysdb_attrs_get_string(reply[0], AD_AT_TRUST_PARTNER,
+ ret = sysdb_attrs_get_string(subdomains[0], AD_AT_TRUST_PARTNER,
&root_name);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
@@ -363,11 +310,12 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
continue;
}
- for (c = 0; c < count; c++) {
+ for (c = 0; c < num_subdomains; c++) {
if (handled[c]) {
continue;
}
- ret = sysdb_attrs_get_string(reply[c], AD_AT_TRUST_PARTNER, &value);
+ ret = sysdb_attrs_get_string(subdomains[c], AD_AT_TRUST_PARTNER,
+ &value);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
goto done;
@@ -377,7 +325,7 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
}
}
- if (c >= count) {
+ if (c >= num_subdomains) {
/* ok this subdomain does not exist anymore, let's clean up */
sss_domain_set_state(dom, DOM_DISABLED);
ret = sysdb_subdomain_delete(dom->sysdb, dom->name);
@@ -385,29 +333,29 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
goto done;
}
- sdom = sdap_domain_get(ctx->sdap_id_ctx->opts, dom);
+ sdom = sdap_domain_get(opts, dom);
if (sdom == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Domain does not exist?\n");
continue;
}
/* Remove the subdomain from the list of LDAP domains */
- sdap_domain_remove(ctx->sdap_id_ctx->opts, dom);
+ sdap_domain_remove(opts, dom);
be_ptask_destroy(&sdom->enum_task);
be_ptask_destroy(&sdom->cleanup_task);
/* terminate all requests for this subdomain so we can free it */
- be_terminate_domain_requests(ctx->be_ctx, dom->name);
+ dp_terminate_domain_requests(be_ctx->provider, dom->name);
talloc_zfree(sdom);
} else {
/* ok let's try to update it */
- ret = ad_subdom_enumerates(domain, reply[c], &enumerate);
+ ret = ad_subdom_enumerates(domain, subdomains[c], &enumerate);
if (ret != EOK) {
goto done;
}
- ret = ad_subdom_store(ctx, domain, reply[c], enumerate);
+ ret = ad_subdom_store(idmap_ctx, domain, subdomains[c], enumerate);
if (ret) {
/* Nothing we can do about the error. Let's at least try
* to reuse the existing domains
@@ -420,29 +368,29 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
}
}
- if (count == h) {
+ if (num_subdomains == h) {
/* all domains were already accounted for and have been updated */
ret = EOK;
- *changes = false;
+ *_changes = false;
goto done;
}
/* if we get here it means we have changes to the subdomains list */
- *changes = true;
+ *_changes = true;
- for (c = 0; c < count; c++) {
+ for (c = 0; c < num_subdomains; c++) {
if (handled[c]) {
continue;
}
/* Nothing we can do about the error. Let's at least try
* to reuse the existing domains.
*/
- ret = ad_subdom_enumerates(domain, reply[c], &enumerate);
+ ret = ad_subdom_enumerates(domain, subdomains[c], &enumerate);
if (ret != EOK) {
goto done;
}
- ret = ad_subdom_store(ctx, domain, reply[c], enumerate);
+ ret = ad_subdom_store(idmap_ctx, domain, subdomains[c], enumerate);
if (ret) {
DEBUG(SSSDBG_MINOR_FAILURE, "Failed to parse subdom data, "
"will try to use cached subdomain\n");
@@ -453,39 +401,132 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx,
done:
if (ret != EOK) {
- ctx->last_refreshed = 0;
+ *_last_refreshed = 0;
} else {
- ctx->last_refreshed = time(NULL);
+ *_last_refreshed = time(NULL);
}
return ret;
}
-static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *ctx)
+static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx,
+ struct sss_domain_info *domain,
+ size_t nsd, struct sysdb_attrs **sd,
+ struct sysdb_attrs *root,
+ size_t *_nsd_out,
+ struct sysdb_attrs ***_sd_out)
{
+ size_t i, sdi;
+ struct sysdb_attrs **sd_out;
+ const char *sd_name;
errno_t ret;
- ret = sss_write_krb5_conf_snippet(
- dp_opt_get_string(ctx->ad_id_ctx->ad_options->basic,
- AD_KRB5_CONFD_PATH));
+ if (root == NULL) {
+ /* We are connected directly to the root domain. The 'sd'
+ * list is complete and we can just use it
+ */
+ *_nsd_out = nsd;
+ *_sd_out = sd;
+ return EOK;
+ }
+
+ /* If we searched for root separately, we must:
+ * a) treat the root domain as a subdomain
+ * b) filter the subdomain we are connected to from the subdomain
+ * list, from our point of view, it's the master domain
+ */
+ sd_out = talloc_zero_array(mem_ctx, struct sysdb_attrs *, nsd+1);
+ if (sd_out == NULL) {
+ return ENOMEM;
+ }
+
+ sdi = 0;
+ for (i = 0; i < nsd; i++) {
+ ret = sysdb_attrs_get_string(sd[i], AD_AT_TRUST_PARTNER, &sd_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
+ goto fail;
+ }
+
+ if (strcasecmp(sd_name, domain->name) == 0) {
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "Not including primary domain %s in the subdomain list\n",
+ domain->name);
+ continue;
+ }
+
+ sd_out[sdi] = talloc_steal(sd_out, sd[i]);
+ sdi++;
+ }
+
+ /* Now include the root */
+ sd_out[sdi] = talloc_steal(sd_out, root);
+
+ *_nsd_out = sdi+1;
+ *_sd_out = sd_out;
+ return EOK;
+
+fail:
+ talloc_free(sd_out);
+ return ret;
+}
+
+static errno_t
+ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx,
+ struct sss_domain_info *parent)
+{
+ int ret;
+ struct sdap_domain *sditer;
+ struct ad_id_ctx *subdom_id_ctx;
+
+ ret = sdap_domain_subdom_add(ctx->sdap_id_ctx, ctx->sdom, parent);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_domain_subdom_add failed.\n");
+ return ret;
+ }
+
+ DLIST_FOR_EACH(sditer, ctx->sdom) {
+ if (IS_SUBDOMAIN(sditer->dom) && sditer->pvt == NULL) {
+ ret = ad_subdom_ad_ctx_new(ctx->be_ctx, ctx->ad_id_ctx,
+ sditer->dom, &subdom_id_ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "ad_subdom_ad_ctx_new failed.\n");
+ } else {
+ sditer->pvt = subdom_id_ctx;
+ }
+ }
+ }
+
+ return EOK;
+}
+
+static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *subdoms_ctx)
+{
+ const char *path;
+ errno_t ret;
+
+ path = dp_opt_get_string(subdoms_ctx->ad_id_ctx->ad_options->basic,
+ AD_KRB5_CONFD_PATH);
+
+ ret = sss_write_krb5_conf_snippet(path);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE, "sss_write_krb5_conf_snippet failed.\n");
/* Just continue */
}
- ret = sysdb_update_subdomains(ctx->be_ctx->domain);
+ ret = sysdb_update_subdomains(subdoms_ctx->be_ctx->domain);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
return ret;
}
- ret = sss_write_domain_mappings(ctx->be_ctx->domain);
+ ret = sss_write_domain_mappings(subdoms_ctx->be_ctx->domain);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE, "sss_krb5_write_mappings failed.\n");
/* Just continue */
}
- ret = ads_store_sdap_subdom(ctx, ctx->be_ctx->domain);
+ ret = ads_store_sdap_subdom(subdoms_ctx, subdoms_ctx->be_ctx->domain);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ads_store_sdap_subdom failed.\n");
return ret;
@@ -494,364 +535,260 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *ctx)
return EOK;
}
-static void ad_subdomains_get_conn_done(struct tevent_req *req);
-static void ad_subdomains_master_dom_done(struct tevent_req *req);
-static errno_t ad_subdomains_get_root(struct ad_subdomains_req_ctx *ctx);
-static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx);
+struct ad_get_slave_domain_state {
+ struct tevent_context *ev;
+ struct ad_subdomains_ctx *sd_ctx;
+ struct be_ctx *be_ctx;
+ struct sdap_options *opts;
+ struct sdap_idmap_ctx *idmap_ctx;
+ struct sysdb_attrs *root_attrs;
+ struct sdap_id_op *sdap_op;
+};
-static void ad_subdomains_retrieve(struct ad_subdomains_ctx *ctx,
- struct be_req *be_req)
+static errno_t ad_get_slave_domain_retry(struct tevent_req *req);
+static void ad_get_slave_domain_connect_done(struct tevent_req *subreq);
+static void ad_get_slave_domain_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ad_get_slave_domain_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ad_subdomains_ctx *sd_ctx,
+ struct sysdb_attrs *root_attrs,
+ struct ad_id_ctx *root_id_ctx)
{
- struct ad_subdomains_req_ctx *req_ctx = NULL;
+ struct ad_get_slave_domain_state *state;
struct tevent_req *req;
- int dp_error = DP_ERR_FATAL;
- int ret;
+ errno_t ret;
- req_ctx = talloc_zero(be_req, struct ad_subdomains_req_ctx);
- if (req_ctx == NULL) {
- ret = ENOMEM;
- goto done;
+ req = tevent_req_create(mem_ctx, &state,
+ struct ad_get_slave_domain_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- req_ctx->be_req = be_req;
- req_ctx->sd_ctx = ctx;
- req_ctx->current_filter = NULL;
- req_ctx->base_iter = 0;
- req_ctx->root_base_iter = 0;
- req_ctx->root_id_ctx = NULL;
- req_ctx->root_op = NULL;
- req_ctx->root_domain = NULL;
- req_ctx->root_domain_attrs = NULL;
- req_ctx->reply_count = 0;
- req_ctx->reply = NULL;
-
- req_ctx->sdap_op = sdap_id_op_create(req_ctx,
- ctx->ldap_ctx->conn_cache);
- if (req_ctx->sdap_op == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
+ state->ev = ev;
+ state->sd_ctx = sd_ctx;
+ state->be_ctx = sd_ctx->be_ctx;
+ state->opts = root_id_ctx->sdap_id_ctx->opts;
+ state->idmap_ctx = root_id_ctx->sdap_id_ctx->opts->idmap_ctx;
+ state->root_attrs = root_attrs;
+
+ state->sdap_op = sdap_id_op_create(state, root_id_ctx->ldap_ctx->conn_cache);
+ if (state->sdap_op == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
ret = ENOMEM;
- goto done;
+ goto immediately;
}
- req = sdap_id_op_connect_send(req_ctx->sdap_op, req_ctx, &ret);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
- ret, strerror(ret));
- goto done;
+ ret = ad_get_slave_domain_retry(req);
+ if (ret == EAGAIN) {
+ /* asynchronous processing */
+ return req;
}
- tevent_req_set_callback(req, ad_subdomains_get_conn_done, req_ctx);
-
- return;
-
-done:
- talloc_free(req_ctx);
+immediately:
if (ret == EOK) {
- dp_error = DP_ERR_OK;
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
}
- be_req_terminate(be_req, dp_error, ret, NULL);
+ tevent_req_post(req, ev);
+
+ return req;
}
-static void ad_subdomains_get_conn_done(struct tevent_req *req)
+static errno_t ad_get_slave_domain_retry(struct tevent_req *req)
{
+ struct ad_get_slave_domain_state *state;
+ struct tevent_req *subreq;
int ret;
- int dp_error = DP_ERR_FATAL;
- struct ad_subdomains_req_ctx *ctx;
- ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
+ state = tevent_req_data(req, struct ad_get_slave_domain_state);
- ret = sdap_id_op_connect_recv(req, &dp_error);
- talloc_zfree(req);
- if (ret) {
- if (dp_error == DP_ERR_OFFLINE) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "No AD server is available, cannot get the "
- "subdomain list while offline\n");
- } else {
- DEBUG(SSSDBG_OP_FAILURE,
- "Failed to connect to AD server: [%d](%s)\n",
- ret, strerror(ret));
- }
-
- goto fail;
+ subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_connect_send() failed "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ return ret;
}
- req = ad_master_domain_send(ctx, ctx->sd_ctx->be_ctx->ev,
- ctx->sd_ctx->ldap_ctx,
- ctx->sdap_op,
- ctx->sd_ctx->domain_name);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "ad_master_domain_send failed.\n");
- ret = ENOMEM;
- goto fail;
- }
- tevent_req_set_callback(req, ad_subdomains_master_dom_done, ctx);
- return;
+ tevent_req_set_callback(subreq, ad_get_slave_domain_connect_done, req);
-fail:
- be_req_terminate(ctx->be_req, dp_error, ret, NULL);
+ return EAGAIN;
}
-static void ad_subdomains_master_dom_done(struct tevent_req *req)
+static void ad_get_slave_domain_connect_done(struct tevent_req *subreq)
{
- struct ad_subdomains_req_ctx *ctx;
+ struct ad_get_slave_domain_state *state;
+ struct tevent_req *req = NULL;
+ int dp_error;
errno_t ret;
- const char *realm;
+ const char *attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
+ AD_AT_SID, AD_AT_TRUST_TYPE,
+ AD_AT_TRUST_ATTRS, NULL };
- ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
-
- ret = ad_master_domain_recv(req, ctx,
- &ctx->flat_name, &ctx->master_sid,
- &ctx->site, &ctx->forest);
- talloc_zfree(req);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve master domain info\n");
- goto done;
- }
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_get_slave_domain_state);
- realm = dp_opt_get_cstring(ctx->sd_ctx->ad_id_ctx->ad_options->basic,
- AD_KRB5_REALM);
- if (realm == NULL) {
- DEBUG(SSSDBG_CONF_SETTINGS, "Missing realm.\n");
- ret = EINVAL;
- goto done;
- }
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
- ret = sysdb_master_domain_add_info(ctx->sd_ctx->be_ctx->domain,
- realm,
- ctx->flat_name, ctx->master_sid,
- ctx->forest);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Cannot save master domain info\n");
- goto done;
- }
-
- if (ctx->forest == NULL ||
- strcasecmp(ctx->sd_ctx->be_ctx->domain->name, ctx->forest) != 0) {
- DEBUG(SSSDBG_TRACE_FUNC,
- "SSSD needs to look up the forest root domain\n");
- ret = ad_subdomains_get_root(ctx);
- } else {
- DEBUG(SSSDBG_TRACE_FUNC,
- "Connected to forest root, looking up child domains..\n");
-
- ctx->root_op = ctx->sdap_op;
- ctx->root_id_ctx = ctx->sd_ctx->ad_id_ctx;
-
- ret = ad_subdomains_get_slave(ctx);
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to connect to LDAP "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ if (dp_error == DP_ERR_OFFLINE) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "No AD server is available, "
+ "cannot get the subdomain list while offline\n");
+ ret = ERR_OFFLINE;
+ }
+ tevent_req_error(req, ret);
+ return;
}
- if (ret == EAGAIN) {
+ subreq = sdap_search_bases_send(state, state->ev, state->opts,
+ sdap_id_op_handle(state->sdap_op),
+ state->opts->sdom->search_bases,
+ NULL, false, 0,
+ SLAVE_DOMAIN_FILTER, attrs);
+ if (subreq == NULL) {
+ tevent_req_error(req, ret);
return;
- } else if (ret != EOK) {
- goto done;
}
-done:
- be_req_terminate(ctx->be_req, DP_ERR_FATAL, ret, NULL);
+ tevent_req_set_callback(subreq, ad_get_slave_domain_done, req);
+ return;
}
-static void ad_subdomains_get_root_domain_done(struct tevent_req *req);
-
-static errno_t ad_subdomains_get_root(struct ad_subdomains_req_ctx *ctx)
+static void ad_get_slave_domain_done(struct tevent_req *subreq)
{
+ struct ad_get_slave_domain_state *state;
struct tevent_req *req;
- struct sdap_search_base *base;
- struct sdap_id_ctx *sdap_id_ctx;
- char *filter;
- const char *forest_root_attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
- AD_AT_SID, AD_AT_TRUST_TYPE,
- AD_AT_TRUST_ATTRS, NULL };
-
- sdap_id_ctx = ctx->sd_ctx->sdap_id_ctx;
- base = sdap_id_ctx->opts->sdom->search_bases[ctx->root_base_iter];
- if (base == NULL) {
- return EOK;
- }
-
- filter = talloc_asprintf(ctx, FOREST_ROOT_FILTER_FMT, ctx->forest);
- if (filter == NULL) {
- return ENOMEM;
- }
-
- req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
- sdap_id_ctx->opts,
- sdap_id_op_handle(ctx->sdap_op),
- base->basedn, LDAP_SCOPE_SUBTREE,
- filter, forest_root_attrs,
- NULL, 0,
- dp_opt_get_int(sdap_id_ctx->opts->basic,
- SDAP_SEARCH_TIMEOUT),
- false);
-
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
- return ENOMEM;
- }
-
- tevent_req_set_callback(req, ad_subdomains_get_root_domain_done, ctx);
- return EAGAIN;
-}
-
-static struct sss_domain_info *ads_get_root_domain(struct ad_subdomains_req_ctx *ctx);
-static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx);
-static void ad_subdomains_root_conn_done(struct tevent_req *req);
-
-static void ad_subdomains_get_root_domain_done(struct tevent_req *req)
-{
- int ret;
+ struct sysdb_attrs **reply;
size_t reply_count;
- struct sysdb_attrs **reply = NULL;
- struct ad_subdomains_req_ctx *ctx;
- int dp_error = DP_ERR_FATAL;
- bool has_changes = false;
+ struct sysdb_attrs **subdoms;
+ size_t nsubdoms;
+ bool has_changes;
+ int dp_error;
+ errno_t ret;
- ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_get_slave_domain_state);
- ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
- talloc_zfree(req);
+ ret = sdap_search_bases_recv(subreq, state, &reply_count, &reply);
+ talloc_zfree(subreq);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
- goto fail;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup slave domain data "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ /* We continue to finish sdap_id_op. */
}
- if (reply_count == 0) {
- /* If no root domain was found in the default search base, try the
- * next one, if available
- */
- ctx->root_base_iter++;
- ret = ad_subdomains_get_root(ctx);
- if (ret == EAGAIN) {
- return;
- }
-
- goto fail;
- } else if (reply_count > 1) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Multiple results for root domain search, "
- "domain list might be incomplete!\n");
-
- ctx->root_op = ctx->sdap_op;
- ctx->root_id_ctx = ctx->sd_ctx->ad_id_ctx;
-
- ret = ad_subdomains_get_slave(ctx);
- if (ret == EAGAIN) {
- return;
+ ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = ad_get_slave_domain_retry(req);
+ if (ret != EOK) {
+ goto done;
}
-
- goto fail;
+ return;
+ } else if (dp_error == DP_ERR_OFFLINE) {
+ ret = ERR_OFFLINE;
+ goto done;
+ } else if (ret != EOK) {
+ goto done;
}
- /* Exactly one result, good. */
- /* We won't use the operation to the local LDAP anymore, but
- * read from the forest root
+ /* Based on whether we are connected to the forest root or not, we might
+ * need to exclude the subdomain we are connected to from the list of
+ * subdomains.
*/
- ret = sdap_id_op_done(ctx->sdap_op, ret, &dp_error);
+ ret = ad_subdomains_process(state, state->be_ctx->domain,
+ reply_count, reply, state->root_attrs,
+ &nsubdoms, &subdoms);
if (ret != EOK) {
- if (dp_error == DP_ERR_OFFLINE) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "No AD server is available, cannot get the "
- "subdomain list while offline\n");
- } else {
- DEBUG(SSSDBG_OP_FAILURE,
- "Failed to search the AD server: [%d](%s)\n",
- ret, strerror(ret));
- }
- goto fail;
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot process subdomain list\n");
+ tevent_req_error(req, ret);
+ return;
}
- ret = ad_subdomains_refresh(ctx->sd_ctx, 1, true, reply, &has_changes);
+ /* Got all the subdomains, let's process them. */
+ ret = ad_subdomains_refresh(state->be_ctx, state->idmap_ctx, state->opts,
+ subdoms, nsubdoms, false,
+ &state->sd_ctx->last_refreshed,
+ &has_changes);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "ad_subdomains_refresh failed.\n");
- goto fail;
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to refresh subdomains.\n");
+ goto done;
}
+ DEBUG(SSSDBG_TRACE_LIBS, "There are %schanges\n",
+ has_changes ? "" : "no ");
+
if (has_changes) {
- ret = ad_subdom_reinit(ctx->sd_ctx);
+ ret = ad_subdom_reinit(state->sd_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
- goto fail;
+ goto done;
}
}
- ctx->root_domain_attrs = reply[0];
- ctx->root_domain = ads_get_root_domain(ctx);
- if (ctx->root_domain == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "Could not find the root domain\n");
- ret = EFAULT;
- goto fail;
- }
-
- ctx->root_id_ctx = ads_get_root_id_ctx(ctx);
- if (ctx->root_id_ctx == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "Cannot create id ctx for the root domain\n");
- ret = EFAULT;
- goto fail;
- }
+ state->sd_ctx->last_refreshed = time(NULL);
+ ret = EOK;
- ctx->root_op = sdap_id_op_create(ctx,
- ctx->root_id_ctx->ldap_ctx->conn_cache);
- if (ctx->root_op == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
- ret = ENOMEM;
- goto fail;
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
}
- req = sdap_id_op_connect_send(ctx->root_op, ctx, &ret);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
- ret, strerror(ret));
- goto fail;
- }
+ tevent_req_done(req);
+}
- tevent_req_set_callback(req, ad_subdomains_root_conn_done, ctx);
- return;
+static errno_t ad_get_slave_domain_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
-fail:
- if (ret == EOK) {
- ctx->sd_ctx->last_refreshed = time(NULL);
- dp_error = DP_ERR_OK;
- }
- be_req_terminate(ctx->be_req, dp_error, ret, NULL);
+ return EOK;
}
-static struct sss_domain_info *ads_get_root_domain(struct ad_subdomains_req_ctx *ctx)
+static struct sss_domain_info *
+ads_get_root_domain(struct be_ctx *be_ctx, struct sysdb_attrs *attrs)
{
- errno_t ret;
- const char *name;
struct sss_domain_info *root;
+ const char *name;
+ errno_t ret;
- ret = sysdb_attrs_get_string(ctx->root_domain_attrs, AD_AT_TRUST_PARTNER, &name);
+ ret = sysdb_attrs_get_string(attrs, AD_AT_TRUST_PARTNER, &name);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
return NULL;
}
/* With a subsequent run, the root should already be known */
- root = find_domain_by_name(ctx->sd_ctx->be_ctx->domain,
- name, false);
+ root = find_domain_by_name(be_ctx->domain, name, false);
return root;
}
-static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx)
+static struct ad_id_ctx *
+ads_get_root_id_ctx(struct be_ctx *be_ctx,
+ struct ad_id_ctx *ad_id_ctx,
+ struct sss_domain_info *root_domain,
+ struct sdap_options *opts)
{
errno_t ret;
struct sdap_domain *sdom;
struct ad_id_ctx *root_id_ctx;
- sdom = sdap_domain_get(ctx->sd_ctx->ad_id_ctx->sdap_id_ctx->opts,
- ctx->root_domain);
+ sdom = sdap_domain_get(opts, root_domain);
if (sdom == NULL) {
DEBUG(SSSDBG_OP_FAILURE,
- "Cannot get the sdom for %s!\n", ctx->root_domain->name);
+ "Cannot get the sdom for %s!\n", root_domain->name);
return NULL;
}
if (sdom->pvt == NULL) {
- ret = ad_subdom_ad_ctx_new(ctx->sd_ctx->be_ctx,
- ctx->sd_ctx->ad_id_ctx,
- ctx->root_domain,
+ ret = ad_subdom_ad_ctx_new(be_ctx, ad_id_ctx, root_domain,
&root_id_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ad_subdom_ad_ctx_new failed.\n");
@@ -867,362 +804,585 @@ static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx)
return root_id_ctx;
}
-static void ad_subdomains_root_conn_done(struct tevent_req *req)
-{
- int ret;
- int dp_error = DP_ERR_FATAL;
- struct ad_subdomains_req_ctx *ctx;
+struct ad_get_root_domain_state {
+ struct ad_subdomains_ctx *sd_ctx;
+ struct be_ctx *be_ctx;
+ struct sdap_idmap_ctx *idmap_ctx;
+ struct sdap_options *opts;
- ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
+ struct ad_id_ctx *root_id_ctx;
+ struct sysdb_attrs *root_domain_attrs;
+};
- ret = sdap_id_op_connect_recv(req, &dp_error);
- talloc_zfree(req);
- if (ret) {
- be_mark_dom_offline(ctx->root_domain, be_req_get_be_ctx(ctx->be_req));
+static void ad_get_root_domain_done(struct tevent_req *subreq);
- DEBUG(SSSDBG_OP_FAILURE,
- "Failed to connect to AD server: [%d](%s)\n",
- ret, strerror(ret));
- goto fail;
+static struct tevent_req *
+ad_get_root_domain_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *forest,
+ struct sdap_handle *sh,
+ struct ad_subdomains_ctx *sd_ctx)
+{
+ struct ad_get_root_domain_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+ struct sdap_options *opts;
+ errno_t ret;
+ const char *filter;
+ const char *attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
+ AD_AT_SID, AD_AT_TRUST_TYPE,
+ AD_AT_TRUST_ATTRS, NULL };
+
+ req = tevent_req_create(mem_ctx, &state, struct ad_get_root_domain_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- ret = ad_subdomains_get_slave(ctx);
- if (ret == EAGAIN) {
- return;
- } else if (ret != EOK) {
- goto fail;
+ if (forest != NULL && strcasecmp(sd_ctx->be_ctx->domain->name, forest) == 0) {
+ state->root_id_ctx = sd_ctx->ad_id_ctx;
+ state->root_domain_attrs = NULL;
+ ret = EOK;
+ goto immediately;
}
-fail:
- be_req_terminate(ctx->be_req, dp_error, ret, NULL);
-}
+ DEBUG(SSSDBG_TRACE_FUNC, "Looking up the forest root domain.\n");
-static void ad_subdomains_get_slave_domain_done(struct tevent_req *req);
+ state->sd_ctx = sd_ctx;
+ state->opts = opts = sd_ctx->sdap_id_ctx->opts;
+ state->be_ctx = sd_ctx->be_ctx;
+ state->idmap_ctx = opts->idmap_ctx;
-static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx)
-{
- struct tevent_req *req;
- struct sdap_search_base *base;
- const char *slave_dom_attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER,
- AD_AT_SID, AD_AT_TRUST_TYPE,
- AD_AT_TRUST_ATTRS, NULL };
+ filter = talloc_asprintf(state, FOREST_ROOT_FILTER_FMT, forest);
+ if (filter == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
- base = ctx->root_id_ctx->sdap_id_ctx->opts->sdom->search_bases[ctx->base_iter];
- if (base == NULL) {
- return EOK;
+ subreq = sdap_search_bases_return_first_send(state, ev, opts, sh,
+ opts->sdom->search_bases,
+ NULL, false, 0, filter, attrs);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
}
- req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev,
- ctx->root_id_ctx->sdap_id_ctx->opts,
- sdap_id_op_handle(ctx->root_op),
- base->basedn, LDAP_SCOPE_SUBTREE,
- SLAVE_DOMAIN_FILTER, slave_dom_attrs,
- NULL, 0,
- dp_opt_get_int(ctx->root_id_ctx->sdap_id_ctx->opts->basic,
- SDAP_SEARCH_TIMEOUT),
- false);
+ tevent_req_set_callback(subreq, ad_get_root_domain_done, req);
- if (req == NULL) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
- return ENOMEM;
+ return req;
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
}
+ tevent_req_post(req, ev);
- tevent_req_set_callback(req, ad_subdomains_get_slave_domain_done, ctx);
- return EAGAIN;
+ return req;
}
-static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx,
- struct sss_domain_info *domain,
- size_t nsd, struct sysdb_attrs **sd,
- struct sysdb_attrs *root,
- size_t *_nsd_out,
- struct sysdb_attrs ***_sd_out)
+static void ad_get_root_domain_done(struct tevent_req *subreq)
{
- size_t i, sdi;
- struct sysdb_attrs **sd_out;
- const char *sd_name;
+ struct tevent_req *req;
+ struct ad_get_root_domain_state *state;
+ struct sysdb_attrs **reply;
+ struct sss_domain_info *root_domain;
+ size_t reply_count;
+ bool has_changes;
errno_t ret;
- if (root == NULL) {
- /* We are connected directly to the root domain. The 'sd'
- * list is complete and we can just use it
- */
- *_nsd_out = nsd;
- *_sd_out = sd;
- return EOK;
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_get_root_domain_state);
+
+ ret = sdap_search_bases_return_first_recv(subreq, state, &reply_count,
+ &reply);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to lookup forest root information "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ goto done;
}
- /* If we searched for root separately, we must:
- * a) treat the root domain as a subdomain
- * b) filter the subdomain we are connected to from the subdomain
- * list, from our point of view, it's the master domain
- */
- sd_out = talloc_zero_array(mem_ctx, struct sysdb_attrs *, nsd+1);
- if (sd_out == NULL) {
- return ENOMEM;
+ if (reply_count == 0) {
+ DEBUG(SSSDBG_OP_FAILURE, "No information provided for root domain\n");
+ ret = ENOENT;
+ goto done;
+ } else if (reply_count > 1) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Multiple results for root domain search, "
+ "domain list might be incomplete!\n");
+ ret = ERR_MALFORMED_ENTRY;
+ goto done;
}
- sdi = 0;
- for (i = 0; i < nsd; i++) {
- ret = sysdb_attrs_get_string(sd[i], AD_AT_TRUST_PARTNER, &sd_name);
+ ret = ad_subdomains_refresh(state->be_ctx, state->idmap_ctx, state->opts,
+ reply, reply_count, true,
+ &state->sd_ctx->last_refreshed,
+ &has_changes);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "ad_subdomains_refresh failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ if (has_changes) {
+ ret = ad_subdom_reinit(state->sd_ctx);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
- goto fail;
+ DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
+ goto done;
}
+ }
- if (strcasecmp(sd_name, domain->name) == 0) {
- DEBUG(SSSDBG_TRACE_INTERNAL,
- "Not including primary domain %s in the subdomain list\n",
- domain->name);
- continue;
- }
+ state->root_domain_attrs = reply[0];
+ root_domain = ads_get_root_domain(state->be_ctx, reply[0]);
+ if (root_domain == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Could not find the root domain\n");
+ ret = EFAULT;
+ goto done;
+ }
- sd_out[sdi] = talloc_steal(sd_out, sd[i]);
- sdi++;
+ state->root_id_ctx = ads_get_root_id_ctx(state->be_ctx,
+ state->sd_ctx->ad_id_ctx,
+ root_domain, state->opts);
+ if (state->root_id_ctx == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot create id ctx for the root domain\n");
+ ret = EFAULT;
+ goto done;
}
- /* Now include the root */
- sd_out[sdi] = talloc_steal(sd_out, root);
+ ret = EOK;
- *_nsd_out = sdi+1;
- *_sd_out = sd_out;
- return EOK;
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
-fail:
- talloc_free(sd_out);
- return ret;
+ tevent_req_done(req);
}
-static void ad_subdomains_get_slave_domain_done(struct tevent_req *req)
+static errno_t ad_get_root_domain_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct sysdb_attrs **_attrs,
+ struct ad_id_ctx **_id_ctx)
{
- int ret;
- size_t reply_count;
- struct sysdb_attrs **reply = NULL;
- struct ad_subdomains_req_ctx *ctx;
- int dp_error = DP_ERR_FATAL;
- bool refresh_has_changes = false;
- size_t nsubdoms;
- struct sysdb_attrs **subdoms;
+ struct ad_get_root_domain_state *state = NULL;
+ state = tevent_req_data(req, struct ad_get_root_domain_state);
- ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx);
+ TEVENT_REQ_RETURN_ON_ERROR(req);
- ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply);
- talloc_zfree(req);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send request failed.\n");
- goto done;
+ *_attrs = talloc_steal(mem_ctx, state->root_domain_attrs);
+ *_id_ctx = state->root_id_ctx;
+
+ return EOK;
+}
+
+struct ad_subdomains_refresh_state {
+ struct tevent_context *ev;
+ struct be_ctx *be_ctx;
+ struct ad_subdomains_ctx *sd_ctx;
+ struct sdap_id_op *sdap_op;
+ struct sdap_id_ctx *id_ctx;
+ struct ad_options *ad_options;
+};
+
+static errno_t ad_subdomains_refresh_retry(struct tevent_req *req);
+static void ad_subdomains_refresh_connect_done(struct tevent_req *subreq);
+static void ad_subdomains_refresh_master_done(struct tevent_req *subreq);
+static void ad_subdomains_refresh_root_done(struct tevent_req *subreq);
+static void ad_subdomains_refresh_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ad_subdomains_refresh_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ad_subdomains_ctx *sd_ctx)
+{
+ struct ad_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ad_subdomains_refresh_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- if (reply_count) {
- ctx->reply = talloc_realloc(ctx, ctx->reply, struct sysdb_attrs *,
- ctx->reply_count + reply_count);
- if (ctx->reply == NULL) {
- ret = ENOMEM;
- goto done;
- }
- memcpy(ctx->reply+ctx->reply_count, reply,
- reply_count * sizeof(struct sysdb_attrs *));
- ctx->reply_count += reply_count;
+ state->ev = ev;
+ state->be_ctx = sd_ctx->be_ctx;
+ state->sd_ctx = sd_ctx;
+ state->id_ctx = sd_ctx->sdap_id_ctx;
+ state->ad_options = sd_ctx->ad_id_ctx->ad_options;
+
+ state->sdap_op = sdap_id_op_create(state,
+ sd_ctx->sdap_id_ctx->conn->conn_cache);
+ if (state->sdap_op == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
+ ret = ENOMEM;
+ goto immediately;
}
- ctx->base_iter++;
- ret = ad_subdomains_get_slave(ctx);
+ ret = ad_subdomains_refresh_retry(req);
if (ret == EAGAIN) {
- /* Search in progress */
- return;
+ /* asynchronous processing */
+ return req;
+ }
+
+immediately:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
}
+ tevent_req_post(req, ev);
+
+ return req;
+}
+
+static errno_t ad_subdomains_refresh_retry(struct tevent_req *req)
+{
+ struct ad_subdomains_refresh_state *state;
+ struct tevent_req *subreq;
+ int ret;
+
+ state = tevent_req_data(req, struct ad_subdomains_refresh_state);
+
+ subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_connect_send() failed "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ return ret;
+ }
+
+ tevent_req_set_callback(subreq, ad_subdomains_refresh_connect_done, req);
+
+ return EAGAIN;
+}
+
+static void ad_subdomains_refresh_connect_done(struct tevent_req *subreq)
+{
+ struct ad_subdomains_refresh_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 ad_subdomains_refresh_state);
+
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
- ret = sdap_id_op_done(ctx->root_op, ret, &dp_error);
if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to connect to LDAP "
+ "[%d]: %s\n", ret, sss_strerror(ret));
if (dp_error == DP_ERR_OFFLINE) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "No AD server is available, cannot get the "
- "subdomain list while offline\n");
- } else {
- DEBUG(SSSDBG_OP_FAILURE,
- "Failed to search the AD server: [%d](%s)\n",
- ret, strerror(ret));
+ DEBUG(SSSDBG_MINOR_FAILURE, "No AD server is available, "
+ "cannot get the subdomain list while offline\n");
+ ret = ERR_OFFLINE;
}
tevent_req_error(req, ret);
return;
}
- /* Based on whether we are connected to the forest root or not, we might
- * need to exclude the subdomain we are connected to from the list of
- * subdomains
- */
- ret = ad_subdomains_process(ctx, ctx->sd_ctx->be_ctx->domain,
- ctx->reply_count, ctx->reply,
- ctx->root_domain_attrs, &nsubdoms, &subdoms);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Cannot process subdomain list\n");
- tevent_req_error(req, ret);
+ subreq = ad_master_domain_send(state, state->ev, state->id_ctx->conn,
+ state->sdap_op, state->sd_ctx->domain_name);
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
return;
}
- /* Got all the subdomains, let's process them */
- ret = ad_subdomains_refresh(ctx->sd_ctx, nsubdoms, false, subdoms,
- &refresh_has_changes);
+ tevent_req_set_callback(subreq, ad_subdomains_refresh_master_done, req);
+ return;
+}
+
+static void ad_subdomains_refresh_master_done(struct tevent_req *subreq)
+{
+ struct ad_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ const char *realm;
+ char *master_sid;
+ char *flat_name;
+ char *forest;
+ char *site;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_subdomains_refresh_state);
+
+ ret = ad_master_domain_recv(subreq, state, &flat_name, &master_sid,
+ &site, &forest);
+ talloc_zfree(subreq);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Failed to refresh subdomains.\n");
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get master domain information "
+ "[%d]: %s\n", ret, sss_strerror(ret));
goto done;
}
- DEBUG(SSSDBG_TRACE_LIBS, "There are %schanges\n",
- refresh_has_changes ? "" : "no ");
+ realm = dp_opt_get_cstring(state->ad_options->basic, AD_KRB5_REALM);
+ if (realm == NULL) {
+ DEBUG(SSSDBG_CONF_SETTINGS, "Missing realm.\n");
+ ret = EINVAL;
+ goto done;
+ }
- if (refresh_has_changes) {
- ret = ad_subdom_reinit(ctx->sd_ctx);
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Could not reinitialize subdomains\n");
- goto done;
- }
+ ret = sysdb_master_domain_add_info(state->be_ctx->domain, realm,
+ flat_name, master_sid, forest);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot save master domain info [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
}
- ret = EOK;
+ subreq = ad_get_root_domain_send(state, state->ev, forest,
+ sdap_id_op_handle(state->sdap_op),
+ state->sd_ctx);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, ad_subdomains_refresh_root_done, req);
+ return;
+
done:
- if (ret == EOK) {
- ctx->sd_ctx->last_refreshed = time(NULL);
- dp_error = DP_ERR_OK;
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
}
- be_req_terminate(ctx->be_req, dp_error, ret, NULL);
+
+ tevent_req_done(req);
}
-static void ad_subdom_online_cb(void *pvt);
+static void ad_subdomains_refresh_root_done(struct tevent_req *subreq)
+{
+ struct ad_subdomains_refresh_state *state;
+ struct tevent_req *req;
+ struct ad_id_ctx *root_id_ctx;
+ struct sysdb_attrs *root_attrs;
+ int dp_error;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_subdomains_refresh_state);
+
+ ret = ad_get_root_domain_recv(state, subreq, &root_attrs, &root_id_ctx);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get forest root [%d]: %s\n",
+ ret, sss_strerror(ret));
+ root_attrs = NULL;
+ root_id_ctx = NULL;
+ /* We continue to finish sdap_id_op. */
+ }
+
+ /* We finish sdap_id_op here since we connect
+ * to forest root for slave domains. */
+ ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = ad_subdomains_refresh_retry(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ }
+ return;
+ } else if (dp_error == DP_ERR_OFFLINE) {
+ tevent_req_error(req, ERR_OFFLINE);
+ return;
+ } else if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ subreq = ad_get_slave_domain_send(state, state->ev, state->sd_ctx,
+ root_attrs, root_id_ctx);
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
-static void ad_subdom_timer_refresh(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval current_time,
- void *pvt)
+ tevent_req_set_callback(subreq, ad_subdomains_refresh_done, req);
+ return;
+}
+
+static void ad_subdomains_refresh_done(struct tevent_req *subreq)
{
- ad_subdom_online_cb(pvt);
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+
+ ret = ad_get_slave_domain_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to get subdomains [%d]: %s\n",
+ ret, sss_strerror(ret));
+ }
+
+ if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Unable to refresh subdomains [%d]: %s\n",
+ ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Subdomains refreshed.\n");
+ tevent_req_done(req);
}
-static void ad_subdom_be_req_callback(struct be_req *be_req,
- int dp_err, int dp_ret,
- const char *errstr)
+static errno_t ad_subdomains_refresh_recv(struct tevent_req *req)
{
- talloc_free(be_req);
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
}
-static void ad_subdom_online_cb(void *pvt)
+struct ad_subdomains_handler_state {
+ struct dp_reply_std reply;
+};
+
+static void ad_subdomains_handler_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ad_subdomains_handler_send(TALLOC_CTX *mem_ctx,
+ struct ad_subdomains_ctx *sd_ctx,
+ struct dp_subdomains_data *data,
+ struct dp_req_params *params)
{
- struct ad_subdomains_ctx *ctx;
- struct be_req *be_req;
- struct timeval tv;
- uint32_t refresh_interval;
-
- ctx = talloc_get_type(pvt, struct ad_subdomains_ctx);
- if (!ctx) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Bad private pointer\n");
- return;
+ struct ad_subdomains_handler_state *state;
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ad_subdomains_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
}
- refresh_interval = ctx->be_ctx->domain->subdomain_refresh_interval;
- be_req = be_req_create(ctx, NULL, ctx->be_ctx, "AD subdomains",
- ad_subdom_be_req_callback, NULL);
- if (be_req == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "be_req_create() failed.\n");
- return;
+ if (sd_ctx->last_refreshed > time(NULL) - AD_SUBDOMAIN_REFRESH_LIMIT) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Subdomains were recently refreshed, "
+ "nothing to do\n");
+ ret = EOK;
+ goto immediately;
}
- ad_subdomains_retrieve(ctx, be_req);
-
- tv = tevent_timeval_current_ofs(refresh_interval, 0);
- ctx->timer_event = tevent_add_timer(ctx->be_ctx->ev, ctx, tv,
- ad_subdom_timer_refresh, ctx);
- if (!ctx->timer_event) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom timer event\n");
+ subreq = ad_subdomains_refresh_send(state, params->ev, sd_ctx);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto immediately;
}
+
+ tevent_req_set_callback(subreq, ad_subdomains_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 ad_subdom_offline_cb(void *pvt)
+static void ad_subdomains_handler_done(struct tevent_req *subreq)
{
- struct ad_subdomains_ctx *ctx;
+ struct ad_subdomains_handler_state *state;
+ struct tevent_req *req;
+ errno_t ret;
- ctx = talloc_get_type(pvt, struct ad_subdomains_ctx);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_subdomains_handler_state);
- if (ctx) {
- talloc_zfree(ctx->timer_event);
- }
+ ret = ad_subdomains_refresh_recv(subreq);
+ talloc_zfree(subreq);
+
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL);
+ tevent_req_done(req);
}
-void ad_subdomains_handler(struct be_req *be_req)
+static errno_t ad_subdomains_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct dp_reply_std *data)
{
- struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
- struct ad_subdomains_ctx *ctx;
- time_t now;
-
- ctx = talloc_get_type(be_ctx->bet_info[BET_SUBDOMAINS].pvt_bet_data,
- struct ad_subdomains_ctx);
- if (!ctx) {
- be_req_terminate(be_req, DP_ERR_FATAL, EINVAL, NULL);
- return;
- }
+ struct ad_subdomains_handler_state *state;
- now = time(NULL);
+ state = tevent_req_data(req, struct ad_subdomains_handler_state);
- if (ctx->last_refreshed > now - AD_SUBDOMAIN_REFRESH_LIMIT) {
- be_req_terminate(be_req, DP_ERR_OK, EOK, NULL);
- return;
- }
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *data = state->reply;
- ad_subdomains_retrieve(ctx, be_req);
+ return EOK;
}
-struct bet_ops ad_subdomains_ops = {
- .handler = ad_subdomains_handler,
- .finalize = NULL
-};
+static struct tevent_req *
+ad_subdomains_ptask_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct be_ctx *be_ctx,
+ struct be_ptask *be_ptask,
+ void *pvt)
+{
+ struct ad_subdomains_ctx *sd_ctx;
+ sd_ctx = talloc_get_type(pvt, struct ad_subdomains_ctx);
+
+ return ad_subdomains_refresh_send(mem_ctx, ev, sd_ctx);
+}
-int ad_subdom_init(struct be_ctx *be_ctx,
- struct ad_id_ctx *id_ctx,
- const char *ad_domain,
- struct bet_ops **ops,
- void **pvt_data)
+static errno_t
+ad_subdomains_ptask_recv(struct tevent_req *req)
{
- struct ad_subdomains_ctx *ctx;
- int ret;
- enum idmap_error_code err;
+ return ad_subdomains_refresh_recv(req);
+}
+
+errno_t ad_subdomains_init(TALLOC_CTX *mem_ctx,
+ struct be_ctx *be_ctx,
+ struct ad_id_ctx *ad_id_ctx,
+ struct dp_method *dp_methods)
+{
+ struct ad_subdomains_ctx *sd_ctx;
+ const char *ad_domain;
+ time_t period;
+ errno_t ret;
+
+ ad_domain = dp_opt_get_string(ad_id_ctx->ad_options->basic, AD_DOMAIN);
- ctx = talloc_zero(id_ctx, struct ad_subdomains_ctx);
- if (ctx == NULL) {
+ sd_ctx = talloc_zero(mem_ctx, struct ad_subdomains_ctx);
+ if (sd_ctx == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
return ENOMEM;
}
- ctx->be_ctx = be_ctx;
- ctx->sdom = id_ctx->sdap_id_ctx->opts->sdom;
- ctx->ldap_ctx = id_ctx->ldap_ctx;
- ctx->sdap_id_ctx = id_ctx->sdap_id_ctx;
- ctx->domain_name = talloc_strdup(ctx, ad_domain);
- if (ctx->domain_name == NULL) {
+ sd_ctx->be_ctx = be_ctx;
+ sd_ctx->sdom = ad_id_ctx->sdap_id_ctx->opts->sdom;
+ sd_ctx->sdap_id_ctx = ad_id_ctx->sdap_id_ctx;
+ sd_ctx->domain_name = talloc_strdup(sd_ctx, ad_domain);
+ if (sd_ctx->domain_name == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
return ENOMEM;
}
- ctx->ad_id_ctx = id_ctx;
- *ops = &ad_subdomains_ops;
- *pvt_data = ctx;
+ sd_ctx->ad_id_ctx = ad_id_ctx;
- ret = be_add_online_cb(ctx, be_ctx, ad_subdom_online_cb, ctx, NULL);
- if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom online callback\n");
- }
+ dp_set_method(dp_methods, DPM_DOMAINS_HANDLER,
+ ad_subdomains_handler_send, ad_subdomains_handler_recv, sd_ctx,
+ struct ad_subdomains_ctx, struct dp_subdomains_data, struct dp_reply_std);
- ret = be_add_offline_cb(ctx, be_ctx, ad_subdom_offline_cb, ctx, NULL);
+ period = be_ctx->domain->subdomain_refresh_interval;
+ ret = be_ptask_create(sd_ctx, be_ctx, period, 0, 0, 0, period,
+ BE_PTASK_OFFLINE_DISABLE, 0,
+ ad_subdomains_ptask_send, ad_subdomains_ptask_recv, sd_ctx,
+ "Subdomains Refresh", NULL);
if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add subdom offline callback\n");
- }
-
- err = sss_idmap_init(sss_idmap_talloc, ctx, sss_idmap_talloc_free,
- &ctx->idmap_ctx);
- if (err != IDMAP_SUCCESS) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize idmap context.\n");
- return EFAULT;
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup ptask "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ /* Ignore, responders will trigger refresh from time to time. */
}
- ret = ad_subdom_reinit(ctx);
+ ret = ad_subdom_reinit(sd_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE, "Could not reinitialize subdomains. "
"Users from trusted domains might not be resolved correctly\n");