Patch 0001: LDAP: Support returning referral information
Some callers may be interested in the raw referral values returned from
a lookup. This patch allows interested consumers to get these referrals
back and process them if they wish. It does not implement a generic
automatic following of referrals.
Patch 0002: AD GPO: Support processing referrals
For GPOs assigned to a site, it's possible that their definition
actually exists in another domain. To retrieve this information,
we need to follow the referral and perform a base search on
another domain controller.
Resolves:
https://fedorahosted.org/sssd/ticket/2645
From 3f8826061d34639ddaaf245947085ea577e77fbe Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <[email protected]>
Date: Fri, 1 May 2015 11:42:06 -0400
Subject: [PATCH 1/2] LDAP: Support returning referral information
Some callers may be interested in the raw referral values returned from
a lookup. This patch allows interested consumers to get these referrals
back and process them if they wish. It does not implement a generic
automatic following of referrals.
---
src/providers/ldap/sdap_async.c | 106 ++++++++++++++++++++++++++++++++++------
1 file changed, 92 insertions(+), 14 deletions(-)
diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
index 0d1f0195c0b96d44151487642d30b631063d617a..7ad24902911a5baf6686da8cfcb2a0c151085c29 100644
--- a/src/providers/ldap/sdap_async.c
+++ b/src/providers/ldap/sdap_async.c
@@ -1154,10 +1154,13 @@ struct sdap_get_generic_ext_state {
LDAPControl **serverctrls;
int nserverctrls;
LDAPControl **clientctrls;
+ size_t ref_count;
+ char **refs;
+
sdap_parse_cb parse_cb;
void *cb_data;
bool allow_paging;
};
@@ -1375,19 +1378,59 @@ static errno_t sdap_get_generic_ext_step(struct tevent_req *req)
done:
return ret;
}
+static errno_t
+sdap_get_generic_ext_add_references(struct sdap_get_generic_ext_state *state,
+ char **refs)
+{
+ int i;
+
+ if (refs == NULL) {
+ /* Rare, but it's possible that we might get a reference result with
+ * no references attached.
+ */
+ return EOK;
+ }
+
+ for (i = 0; refs[i]; i++) {
+ DEBUG(SSSDBG_TRACE_LIBS, "Additional References: %s\n", refs[i]);
+ }
+
+ /* Extend the size of the ref array */
+ state->refs = talloc_realloc(state, state->refs, char *,
+ state->ref_count + i);
+ if (state->refs == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "talloc_realloc failed extending ref_array.\n");
+ return ENOMEM;
+ }
+
+ /* Copy in all the references */
+ for (i = 0; refs[i]; i++) {
+ state->refs[state->ref_count + i] =
+ talloc_strdup(state->refs, refs[i]);
+
+ if (state->refs[state->ref_count + i] == NULL) {
+ return ENOMEM;
+ }
+ }
+
+ state->ref_count += i;
+
+ return EOK;
+}
+
static void sdap_get_generic_op_finished(struct sdap_op *op,
struct sdap_msg *reply,
int error, void *pvt)
{
struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
struct sdap_get_generic_ext_state *state = tevent_req_data(req,
struct sdap_get_generic_ext_state);
char *errmsg = NULL;
- int i;
char **refs = NULL;
int result;
int ret;
int lret;
ber_int_t total_count;
@@ -1400,12 +1443,31 @@ static void sdap_get_generic_op_finished(struct sdap_op *op,
return;
}
switch (ldap_msgtype(reply->msg)) {
case LDAP_RES_SEARCH_REFERENCE:
- /* ignore references for now */
- talloc_free(reply);
+ ret = ldap_parse_reference(state->sh->ldap, reply->msg,
+ &refs, NULL, 0);
+ if (ret != LDAP_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "ldap_parse_reference failed (%d)\n", state->op->msgid);
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ ret = sdap_get_generic_ext_add_references(state, refs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sdap_get_generic_ext_add_references failed: %s(%d)",
+ sss_strerror(ret), ret);
+ ldap_memvfree((void **)refs);
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ /* Remove the original strings */
+ ldap_memvfree((void **)refs);
/* unlock the operation so that we can proceed with the next result */
sdap_unlock_next_reply(state->op);
break;
@@ -1454,19 +1516,18 @@ static void sdap_get_generic_op_finished(struct sdap_op *op,
} else if (result == LDAP_UNAVAILABLE_CRITICAL_EXTENSION) {
ldap_memfree(errmsg);
tevent_req_error(req, ENOTSUP);
return;
} else if (result == LDAP_REFERRAL) {
- if (refs != NULL) {
- for (i = 0; refs[i]; i++) {
- DEBUG(SSSDBG_TRACE_LIBS, "Ref: %s\n", refs[i]);
- }
- ldap_memvfree((void **) refs);
+ ret = sdap_get_generic_ext_add_references(state, refs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sdap_get_generic_ext_add_references failed: %s(%d)",
+ sss_strerror(ret), ret);
+ tevent_req_error(req, ret);
}
- ldap_memfree(errmsg);
- tevent_req_error(req, ERR_REFERRAL);
- return;
+ /* For referrals, we need to fall through as if it was LDAP_SUCCESS */
} else if (result != LDAP_SUCCESS && result != LDAP_NO_SUCH_OBJECT) {
DEBUG(SSSDBG_OP_FAILURE,
"Unexpected result from ldap: %s(%d), %s\n",
sss_ldap_err2string(result), result,
errmsg ? errmsg : "no errmsg set");
@@ -1532,24 +1593,40 @@ static void sdap_get_generic_op_finished(struct sdap_op *op,
return;
}
}
static int
-sdap_get_generic_ext_recv(struct tevent_req *req)
+sdap_get_generic_ext_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *ref_count,
+ char ***refs)
{
+ struct sdap_get_generic_ext_state *state =
+ tevent_req_data(req, struct sdap_get_generic_ext_state);
+
TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (ref_count) {
+ *ref_count = state->ref_count;
+ }
+
+ if (refs) {
+ *refs = talloc_steal(mem_ctx, state->refs);
+ }
+
return EOK;
}
+/* This search handler can be used by most calls */
static void generic_ext_search_handler(struct tevent_req *subreq,
struct sdap_options *opts)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
int ret;
- ret = sdap_get_generic_ext_recv(subreq);
+ ret = sdap_get_generic_ext_recv(subreq, NULL, NULL, NULL);
talloc_zfree(subreq);
if (ret == ERR_REFERRAL) {
if (dp_opt_get_bool(opts->basic, SDAP_REFERRALS)) {
tevent_req_error(req, ret);
return;
@@ -1563,10 +1640,11 @@ static void generic_ext_search_handler(struct tevent_req *subreq,
}
tevent_req_done(req);
}
+
/* ==Generic Search============================================ */
struct sdap_get_generic_state {
struct sdap_attr_map *map;
int map_num_attrs;
@@ -2483,11 +2561,11 @@ static void sdap_posix_check_done(struct tevent_req *subreq)
struct tevent_req);
struct sdap_posix_check_state *state =
tevent_req_data(req, struct sdap_posix_check_state);
errno_t ret;
- ret = sdap_get_generic_ext_recv(subreq);
+ ret = sdap_get_generic_ext_recv(subreq, NULL, NULL, NULL);
talloc_zfree(subreq);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sdap_get_generic_ext_recv failed [%d]: %s\n",
ret, strerror(ret));
--
2.3.6
From 9a45e8523540c9eff8a8b9d84da81c9ee77a91de Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <[email protected]>
Date: Fri, 1 May 2015 16:26:36 -0400
Subject: [PATCH 2/2] AD GPO: Support processing referrals
For GPOs assigned to a site, it's possible that their definition
actually exists in another domain. To retrieve this information,
we need to follow the referral and perform a base search on
another domain controller.
Resolves:
https://fedorahosted.org/sssd/ticket/2645
---
src/providers/ad/ad_gpo.c | 466 +++++++++++++++++++++++++++++++++++-----
src/providers/ad/ad_gpo.h | 7 +
src/providers/ldap/sdap_async.c | 27 ++-
src/providers/ldap/sdap_async.h | 18 +-
4 files changed, 456 insertions(+), 62 deletions(-)
diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c
index 4cfd26800da6c8d77fa4b5ee133a7adab346906c..eb8aa8c941a2a978de3939fbfec6675b56a7b70f 100644
--- a/src/providers/ad/ad_gpo.c
+++ b/src/providers/ad/ad_gpo.c
@@ -144,17 +144,20 @@ struct tevent_req *ad_gpo_process_som_send(TALLOC_CTX *mem_ctx,
const char *domain_name);
int ad_gpo_process_som_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
struct gp_som ***som_list);
-struct tevent_req *ad_gpo_process_gpo_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct sdap_id_op *sdap_op,
- struct sdap_options *opts,
- char *server_hostname,
- int timeout,
- struct gp_som **som_list);
+struct tevent_req *
+ad_gpo_process_gpo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sdap_id_op *sdap_op,
+ struct sdap_options *opts,
+ char *server_hostname,
+ struct sss_domain_info *host_domain,
+ struct ad_access_ctx *access_ctx,
+ int timeout,
+ struct gp_som **som_list);
int ad_gpo_process_gpo_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
struct gp_gpo ***candidate_gpos,
int *num_candidate_gpos);
@@ -1456,10 +1459,11 @@ ad_gpo_perform_hbac_processing(TALLOC_CTX *mem_ctx,
/* == ad_gpo_access_send/recv implementation ================================*/
struct ad_gpo_access_state {
struct tevent_context *ev;
struct ldb_context *ldb_ctx;
+ struct ad_access_ctx *access_ctx;
enum gpo_access_control_mode gpo_mode;
enum gpo_map_type gpo_map_type;
struct sdap_id_conn_ctx *conn;
struct sdap_id_op *sdap_op;
char *server_hostname;
@@ -1575,10 +1579,11 @@ ad_gpo_access_send(TALLOC_CTX *mem_ctx,
state->user = user;
state->ldb_ctx = sysdb_ctx_get_ldb(state->host_domain->sysdb);
state->gpo_mode = ctx->gpo_access_control_mode;
state->gpo_timeout_option = ctx->gpo_cache_timeout;
state->ad_hostname = dp_opt_get_string(ctx->ad_options, AD_HOSTNAME);
+ state->access_ctx = ctx;
state->opts = ctx->sdap_access_ctx->id_ctx->opts;
state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
state->conn = ad_get_dom_ldap_conn(ctx->ad_id_ctx, state->host_domain);
state->sdap_op = sdap_id_op_create(state, state->conn->conn_cache);
if (state->sdap_op == NULL) {
@@ -1889,10 +1894,12 @@ ad_gpo_process_som_done(struct tevent_req *subreq)
subreq = ad_gpo_process_gpo_send(state,
state->ev,
state->sdap_op,
state->opts,
state->server_hostname,
+ state->host_domain,
+ state->access_ctx,
state->timeout,
som_list);
if (subreq == NULL) {
ret = ENOMEM;
goto done;
@@ -3348,14 +3355,16 @@ static errno_t ad_gpo_parse_sd(TALLOC_CTX *mem_ctx,
}
/* == ad_gpo_process_gpo_send/recv implementation ========================== */
struct ad_gpo_process_gpo_state {
+ struct ad_access_ctx *access_ctx;
struct tevent_context *ev;
struct sdap_id_op *sdap_op;
struct sdap_options *opts;
char *server_hostname;
+ struct sss_domain_info *host_domain;
int timeout;
struct gp_gpo **candidate_gpos;
int num_candidate_gpos;
int gpo_index;
};
@@ -3376,10 +3385,12 @@ struct tevent_req *
ad_gpo_process_gpo_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct sdap_id_op *sdap_op,
struct sdap_options *opts,
char *server_hostname,
+ struct sss_domain_info *host_domain,
+ struct ad_access_ctx *access_ctx,
int timeout,
struct gp_som **som_list)
{
struct tevent_req *req;
struct ad_gpo_process_gpo_state *state;
@@ -3393,10 +3404,12 @@ ad_gpo_process_gpo_send(TALLOC_CTX *mem_ctx,
state->ev = ev;
state->sdap_op = sdap_op;
state->opts = opts;
state->server_hostname = server_hostname;
+ state->host_domain = host_domain;
+ state->access_ctx = access_ctx;
state->timeout = timeout;
state->gpo_index = 0;
state->candidate_gpos = NULL;
state->num_candidate_gpos = 0;
@@ -3435,13 +3448,11 @@ immediately:
}
static errno_t
ad_gpo_get_gpo_attrs_step(struct tevent_req *req)
{
- const char *attrs[] = {AD_AT_NT_SEC_DESC, AD_AT_CN, AD_AT_FILE_SYS_PATH,
- AD_AT_MACHINE_EXT_NAMES, AD_AT_FUNC_VERSION,
- AD_AT_FLAGS, NULL};
+ const char *attrs[] = AD_GPO_ATTRS;
struct tevent_req *subreq;
struct ad_gpo_process_gpo_state *state;
state = tevent_req_data(req, struct ad_gpo_process_gpo_state);
@@ -3463,63 +3474,159 @@ ad_gpo_get_gpo_attrs_step(struct tevent_req *req)
tevent_req_set_callback(subreq, ad_gpo_get_gpo_attrs_done, req);
return EAGAIN;
}
+static errno_t
+ad_gpo_sd_process_attrs(struct tevent_req *req,
+ char *smb_host,
+ struct sysdb_attrs *result);
+void
+ad_gpo_get_sd_referral_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ad_gpo_get_sd_referral_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ad_access_ctx *access_ctx,
+ struct sdap_options *opts,
+ const char *referral,
+ struct sss_domain_info *host_domain,
+ int timeout);
+errno_t
+ad_gpo_get_sd_referral_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ char **_smb_host,
+ struct sysdb_attrs **_reply);
+
static void
ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ad_gpo_process_gpo_state *state;
int ret;
int dp_error;
- size_t num_results;
+ size_t num_results, refcount;
struct sysdb_attrs **results;
+ char **refs;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ad_gpo_process_gpo_state);
+
+ ret = sdap_sd_search_recv(subreq, state,
+ &num_results, &results,
+ &refcount, &refs);
+ talloc_zfree(subreq);
+
+ if (ret != EOK) {
+ ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
+
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Unable to get GPO attributes: [%d](%s)\n",
+ ret, sss_strerror(ret));
+ ret = ENOENT;
+ goto done;
+ }
+
+ if ((num_results < 1) || (results == NULL)) {
+ if (refcount == 1) {
+ /* If we were redirected to a referral, process it.
+ * There must be a single referral result here; if we get
+ * more than one (or zero) it's a bug.
+ */
+
+ subreq = ad_gpo_get_sd_referral_send(state, state->ev,
+ state->access_ctx,
+ state->opts,
+ refs[0],
+ state->host_domain,
+ state->timeout);
+ tevent_req_set_callback(subreq, ad_gpo_get_sd_referral_done, req);
+ ret = EAGAIN;
+ goto done;
+
+ } else {
+ const char *gpo_dn = state->candidate_gpos[state->gpo_index]->gpo_dn;
+
+ DEBUG(SSSDBG_OP_FAILURE,
+ "No attrs found for GPO [%s].", gpo_dn);
+ ret = ENOENT;
+ goto done;
+ }
+ } else if (num_results > 1) {
+ DEBUG(SSSDBG_OP_FAILURE, "Received multiple replies\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ ret = ad_gpo_sd_process_attrs(req, state->server_hostname, results[0]);
+
+done:
+
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else if (ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ }
+}
+
+void
+ad_gpo_get_sd_referral_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ int dp_error;
+ struct sysdb_attrs *reply;
+ char *smb_host;
+
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct ad_gpo_process_gpo_state *state =
+ tevent_req_data(req, struct ad_gpo_process_gpo_state);
+
+ ret = ad_gpo_get_sd_referral_recv(subreq, state, &smb_host, &reply);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ /* Terminate the sdap_id_op */
+ ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
+
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Unable to get referred GPO attributes: [%d](%s)\n",
+ ret, sss_strerror(ret));
+
+ goto done;
+ }
+
+ /* Lookup succeeded. Process it */
+ ret = ad_gpo_sd_process_attrs(req, smb_host, reply);
+
+done:
+
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else if (ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ }
+}
+
+static errno_t
+ad_gpo_sd_process_attrs(struct tevent_req *req,
+ char *smb_host,
+ struct sysdb_attrs *result)
+{
+ struct ad_gpo_process_gpo_state *state;
+ struct gp_gpo *gp_gpo;
+ int ret;
struct ldb_message_element *el = NULL;
const char *gpo_guid = NULL;
const char *raw_file_sys_path = NULL;
char *file_sys_path = NULL;
uint8_t *raw_machine_ext_names = NULL;
- req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct ad_gpo_process_gpo_state);
-
- ret = sdap_sd_search_recv(subreq, state, &num_results, &results);
- talloc_zfree(subreq);
-
- if (ret != EOK) {
- ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
-
- DEBUG(SSSDBG_OP_FAILURE,
- "Unable to get GPO attributes: [%d](%s)\n",
- ret, sss_strerror(ret));
- ret = ENOENT;
- goto done;
- }
-
- if ((num_results < 1) || (results == NULL)) {
- const char *gpo_dn = state->candidate_gpos[state->gpo_index]->gpo_dn;
-
- DEBUG(SSSDBG_OP_FAILURE,
- "BUG: No attrs found for GPO [%s]. This was likely caused by "
- "the GPO entry being a referred to another domain controller."
- " SSSD does not yet support this configuration. See upstream "
- "ticket #2645 for more information.\n",
- gpo_dn);
- ret = ERR_INTERNAL;
- goto done;
- }
- else if (num_results > 1) {
- DEBUG(SSSDBG_OP_FAILURE, "Received multiple replies\n");
- ret = ERR_INTERNAL;
- goto done;
- }
-
- struct gp_gpo *gp_gpo = state->candidate_gpos[state->gpo_index];
+ gp_gpo = state->candidate_gpos[state->gpo_index];
/* retrieve AD_AT_CN */
- ret = sysdb_attrs_get_string(results[0], AD_AT_CN, &gpo_guid);
+ ret = sysdb_attrs_get_string(result, AD_AT_CN, &gpo_guid);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sysdb_attrs_get_string failed: [%d](%s)\n",
ret, sss_strerror(ret));
goto done;
@@ -3533,11 +3640,11 @@ ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
DEBUG(SSSDBG_TRACE_ALL, "populating attrs for gpo_guid: %s\n",
gp_gpo->gpo_guid);
/* retrieve AD_AT_FILE_SYS_PATH */
- ret = sysdb_attrs_get_string(results[0],
+ ret = sysdb_attrs_get_string(result,
AD_AT_FILE_SYS_PATH,
&raw_file_sys_path);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
@@ -3546,11 +3653,11 @@ ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
goto done;
}
file_sys_path = talloc_strdup(gp_gpo, raw_file_sys_path);
- ret = ad_gpo_extract_smb_components(gp_gpo, state->server_hostname,
+ ret = ad_gpo_extract_smb_components(gp_gpo, smb_host,
file_sys_path, &gp_gpo->smb_server,
&gp_gpo->smb_share, &gp_gpo->smb_path);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"unable to extract smb components from file_sys_path: [%d](%s)\n",
@@ -3561,11 +3668,11 @@ ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
DEBUG(SSSDBG_TRACE_ALL, "smb_server: %s\n", gp_gpo->smb_server);
DEBUG(SSSDBG_TRACE_ALL, "smb_share: %s\n", gp_gpo->smb_share);
DEBUG(SSSDBG_TRACE_ALL, "smb_path: %s\n", gp_gpo->smb_path);
/* retrieve AD_AT_FUNC_VERSION */
- ret = sysdb_attrs_get_int32_t(results[0], AD_AT_FUNC_VERSION,
+ ret = sysdb_attrs_get_int32_t(result, AD_AT_FUNC_VERSION,
&gp_gpo->gpo_func_version);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sysdb_attrs_get_int32_t failed: [%d](%s)\n",
ret, sss_strerror(ret));
@@ -3574,11 +3681,11 @@ ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
DEBUG(SSSDBG_TRACE_ALL, "gpo_func_version: %d\n",
gp_gpo->gpo_func_version);
/* retrieve AD_AT_FLAGS */
- ret = sysdb_attrs_get_int32_t(results[0], AD_AT_FLAGS,
+ ret = sysdb_attrs_get_int32_t(result, AD_AT_FLAGS,
&gp_gpo->gpo_flags);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sysdb_attrs_get_int32_t failed: [%d](%s)\n",
ret, sss_strerror(ret));
@@ -3586,11 +3693,11 @@ ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
}
DEBUG(SSSDBG_TRACE_ALL, "gpo_flags: %d\n", gp_gpo->gpo_flags);
/* retrieve AD_AT_NT_SEC_DESC */
- ret = sysdb_attrs_get_el(results[0], AD_AT_NT_SEC_DESC, &el);
+ ret = sysdb_attrs_get_el(result, AD_AT_NT_SEC_DESC, &el);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
goto done;
}
if ((ret == ENOENT) || (el->num_values == 0)) {
@@ -3606,11 +3713,11 @@ ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
DEBUG(SSSDBG_OP_FAILURE, "ad_gpo_parse_sd() failed\n");
goto done;
}
/* retrieve AD_AT_MACHINE_EXT_NAMES */
- ret = sysdb_attrs_get_el(results[0], AD_AT_MACHINE_EXT_NAMES, &el);
+ ret = sysdb_attrs_get_el(result, AD_AT_MACHINE_EXT_NAMES, &el);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
goto done;
}
@@ -3640,15 +3747,11 @@ ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
ret = ad_gpo_get_gpo_attrs_step(req);
done:
- if (ret == EOK) {
- tevent_req_done(req);
- } else if (ret != EAGAIN) {
- tevent_req_error(req, ret);
- }
+ return ret;
}
int
ad_gpo_process_gpo_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
@@ -4017,5 +4120,254 @@ gpo_fork_child(struct tevent_req *req)
return err;
}
return EOK;
}
+
+struct ad_gpo_get_sd_referral_state {
+ struct tevent_context *ev;
+ struct ad_access_ctx *access_ctx;
+ struct sdap_options *opts;
+ struct sss_domain_info *host_domain;
+ struct sss_domain_info *ref_domain;
+ struct sdap_id_conn_ctx *conn;
+ struct sdap_id_op *ref_op;
+ int timeout;
+ char *gpo_dn;
+ char *smb_host;
+
+
+ struct sysdb_attrs *reply;
+};
+
+static void
+ad_gpo_get_sd_referral_conn_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ad_gpo_get_sd_referral_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ad_access_ctx *access_ctx,
+ struct sdap_options *opts,
+ const char *referral,
+ struct sss_domain_info *host_domain,
+ int timeout)
+{
+ errno_t ret;
+ struct tevent_req *req;
+ struct ad_gpo_get_sd_referral_state *state;
+ struct tevent_req *subreq;
+ LDAPURLDesc *lud;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ad_gpo_get_sd_referral_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->access_ctx = access_ctx;
+ state->opts = opts;
+ state->host_domain = host_domain;
+ state->timeout = timeout;
+
+ /* Parse the URL for the domain */
+ ret = ldap_url_parse(referral, &lud);
+ if (ret != LDAP_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to parse referral URI (%s)!\n", referral);
+ ret = EINVAL;
+ goto done;
+ }
+
+ state->gpo_dn = talloc_strdup(state, lud->lud_dn);
+ if (!state->gpo_dn) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Could not copy referral DN (%s)!\n", lud->lud_dn);
+ ldap_free_urldesc(lud);
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Active Directory returns the domain name as the hostname
+ * in these referrals, so we can use that to look up the
+ * necessary connection.
+ */
+ state->ref_domain = find_domain_by_name(state->host_domain,
+ lud->lud_host, true);
+ ldap_free_urldesc(lud);
+ if (!state->ref_domain) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Could not find domain matching [%s]\n",
+ lud->lud_host);
+ ret = EIO;
+ goto done;
+ }
+
+ state->conn = ad_get_dom_ldap_conn(state->access_ctx->ad_id_ctx,
+ state->ref_domain);
+ if (!state->conn) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "No connection for %s\n", state->ref_domain->name);
+ ret = EINVAL;
+ goto done;
+ }
+
+ /* Get the hostname we're going to connect to.
+ * We'll need this later for performing the samba
+ * connection.
+ */
+ ret = ldap_url_parse(state->conn->service->uri, &lud);
+ if (ret != LDAP_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to parse service URI (%s)!\n", referral);
+ ret = EINVAL;
+ goto done;
+ }
+
+ state->smb_host = talloc_strdup(state, lud->lud_host);
+ ldap_free_urldesc(lud);
+ if (!state->smb_host) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Start an ID operation for the referral */
+ state->ref_op = sdap_id_op_create(state, state->conn->conn_cache);
+ if (!state->ref_op) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Establish the sdap_id_op connection */
+ subreq = sdap_id_op_connect_send(state->ref_op, state, &ret);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+ tevent_req_set_callback(subreq, ad_gpo_get_sd_referral_conn_done, req);
+
+done:
+
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void
+ad_gpo_get_sd_referral_search_done(struct tevent_req *subreq);
+
+static void
+ad_gpo_get_sd_referral_conn_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ int dp_error;
+ const char *attrs[] = AD_GPO_ATTRS;
+
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct ad_gpo_get_sd_referral_state *state =
+ tevent_req_data(req, struct ad_gpo_get_sd_referral_state);
+
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ if (dp_error == DP_ERR_OFFLINE) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Backend is marked offline, retry later!\n");
+ tevent_req_done(req);
+ } else {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cross-realm GPO processing failed to connect to " \
+ "referred LDAP server: (%d)[%s]\n",
+ ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ }
+ return;
+ }
+
+ /* Request the referred GPO data */
+ subreq = sdap_sd_search_send(state, state->ev, state->opts,
+ sdap_id_op_handle(state->ref_op),
+ state->gpo_dn,
+ SECINFO_DACL,
+ attrs,
+ state->timeout);
+ tevent_req_set_callback(subreq, ad_gpo_get_sd_referral_search_done, req);
+
+}
+
+static void
+ad_gpo_get_sd_referral_search_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ int dp_error;
+ size_t num_results, num_refs;
+ struct sysdb_attrs **results = NULL;
+ char **refs;
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct ad_gpo_get_sd_referral_state *state =
+ tevent_req_data(req, struct ad_gpo_get_sd_referral_state);
+
+ ret = sdap_sd_search_recv(subreq, NULL,
+ &num_results, &results,
+ &num_refs, &refs);
+ talloc_zfree(subreq);
+
+ ret = sdap_id_op_done(state->ref_op, ret, &dp_error);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Unable to get GPO attributes: [%d](%s)\n",
+ ret, sss_strerror(ret));
+ ret = ENOENT;
+ goto done;
+ }
+
+ if ((num_results < 1) || (results == NULL)) {
+ /* TODO:
+ * It's strictly possible for the referral search to return
+ * another referral value here, but it shouldn't actually
+ * happen with Active Directory. Properly handling (and
+ * limiting) the referral chain would be fairly complex, so
+ * we will do it later if it ever becomes necessary.
+ */
+ DEBUG(SSSDBG_OP_FAILURE,
+ "No attrs found for referred GPO [%s].", state->gpo_dn);
+ ret = ENOENT;
+ goto done;
+
+ } else if (num_results > 1) {
+ DEBUG(SSSDBG_OP_FAILURE, "Received multiple replies\n");
+ ret = ERR_INTERNAL;
+ goto done;
+ }
+
+ state->reply = talloc_steal(state, results[0]);
+
+done:
+ talloc_free(results);
+
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else if (ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ }
+}
+
+errno_t
+ad_gpo_get_sd_referral_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ char **_smb_host,
+ struct sysdb_attrs **_reply)
+{
+ struct ad_gpo_get_sd_referral_state *state =
+ tevent_req_data(req, struct ad_gpo_get_sd_referral_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *_smb_host = talloc_steal(mem_ctx, state->smb_host);
+ *_reply = talloc_steal(mem_ctx, state->reply);
+
+ return EOK;
+}
diff --git a/src/providers/ad/ad_gpo.h b/src/providers/ad/ad_gpo.h
index 9fd590a2b262b66c1efd493d8736774bdfa61b40..f57889fca1c7fa77f25c345c1c969d6b499217e5 100644
--- a/src/providers/ad/ad_gpo.h
+++ b/src/providers/ad/ad_gpo.h
@@ -25,10 +25,17 @@
#include "providers/ad/ad_access.h"
#define AD_GPO_CHILD_OUT_FILENO 3
+#define AD_GPO_ATTRS {AD_AT_NT_SEC_DESC, \
+ AD_AT_CN, AD_AT_FILE_SYS_PATH, \
+ AD_AT_MACHINE_EXT_NAMES, \
+ AD_AT_FUNC_VERSION, \
+ AD_AT_FLAGS, \
+ NULL}
+
/*
* This pair of functions provides client-side GPO processing.
*
* While a GPO can target both user and computer objects, this
* implementation only supports targetting of computer objects.
diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
index 7ad24902911a5baf6686da8cfcb2a0c151085c29..ae418446efd604271209d3896c4b988a54b3467a 100644
--- a/src/providers/ldap/sdap_async.c
+++ b/src/providers/ldap/sdap_async.c
@@ -1992,10 +1992,14 @@ struct sdap_sd_search_state {
LDAPControl **ctrls;
struct sdap_options *opts;
size_t reply_count;
struct sysdb_attrs **reply;
struct sdap_reply sreply;
+
+ /* Referrals returned by the search */
+ size_t ref_count;
+ char **refs;
};
static int sdap_sd_search_create_control(struct sdap_handle *sh,
int val,
LDAPControl **ctrl);
@@ -2123,16 +2127,30 @@ static errno_t sdap_sd_search_parse_entry(struct sdap_handle *sh,
return EOK;
}
static void sdap_sd_search_done(struct tevent_req *subreq)
{
+ int ret;
+
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct sdap_sd_search_state *state =
tevent_req_data(req, struct sdap_sd_search_state);
- return generic_ext_search_handler(subreq, state->opts);
+ ret = sdap_get_generic_ext_recv(subreq, state,
+ &state->ref_count,
+ &state->refs);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sdap_get_generic_ext_recv failed [%d]: %s\n",
+ ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
}
static int sdap_sd_search_ctrls_destructor(void *ptr)
{
LDAPControl **ctrls = talloc_get_type(ptr, LDAPControl *);;
@@ -2144,19 +2162,24 @@ static int sdap_sd_search_ctrls_destructor(void *ptr)
}
int sdap_sd_search_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
size_t *_reply_count,
- struct sysdb_attrs ***_reply)
+ struct sysdb_attrs ***_reply,
+ size_t *_ref_count,
+ char ***_refs)
{
struct sdap_sd_search_state *state = tevent_req_data(req,
struct sdap_sd_search_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
*_reply_count = state->sreply.reply_count;
*_reply = talloc_steal(mem_ctx, state->sreply.reply);
+ *_ref_count = state->ref_count;
+ *_refs = talloc_steal(mem_ctx, state->refs);
+
return EOK;
}
/* ==Attribute scoped search============================================ */
struct sdap_asq_search_state {
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 29afd8e1ad8cceae66fbe3cd5c6b1ffb69e93e07..f695e607680a908c1c955deca5963b832bf50e43 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -248,13 +248,25 @@ sdap_sd_search_send(TALLOC_CTX *memctx,
const char *base_dn,
int sd_flags,
const char **attrs,
int timeout);
int sdap_sd_search_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx,
- size_t *reply_count,
- struct sysdb_attrs ***reply);
+ TALLOC_CTX *mem_ctx,
+ size_t *_reply_count,
+ struct sysdb_attrs ***_reply,
+ size_t *_ref_count,
+ char ***_refs);
+
+struct tevent_req *
+sdap_sd_follow_referral_send(TALLOC_CTX *mem_ctx,
+ const char *ref);
+
+errno_t
+sdap_sd_follow_referral_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *_reply_count,
+ struct sysdb_attrs ***_reply);
errno_t
sdap_attrs_add_ldap_attr(struct sysdb_attrs *ldap_attrs,
const char *attr_name,
const char *attr_desc,
--
2.3.6
_______________________________________________
sssd-devel mailing list
[email protected]
https://lists.fedorahosted.org/mailman/listinfo/sssd-devel