diff options
author | Sumit Bose <sbose@redhat.com> | 2013-12-18 13:47:31 +0100 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2013-12-19 17:34:01 +0100 |
commit | 008e1ee835602023891ac45408483d87f41e4d5c (patch) | |
tree | 20c4182749647667194e2ca8d1d6bfa043bb7687 | |
parent | 8280c5213094a72fcaa499dda2f8647246185d45 (diff) | |
download | sssd-008e1ee835602023891ac45408483d87f41e4d5c.tar.gz sssd-008e1ee835602023891ac45408483d87f41e4d5c.tar.xz sssd-008e1ee835602023891ac45408483d87f41e4d5c.zip |
AD: cross-domain membership fix
A recent patch directed all call related to group membership lookups to
the AD LDAP port to fix an issue related to missing group memberships in
the Global Catalog. As a side-effect it broke cross-domain
group-memberships because those cannot be resolved by the connection to
the LDAP port.
The patch tires to fix this by restoring the original behaviour in the
top-level lookup calls in the AD provider and switching to the LDAP port
only for the LDAP request which is expected to return the full group
membership.
Additionally this patch contains a related fix for the tokenGroups with
Posix attributes patch. The original connection, typically a Global
Catalog connection in the AD case is passed down the stack so that the
group lookup after the tokenGroups request can run over the same
connection.
-rw-r--r-- | src/providers/ad/ad_id.c | 19 | ||||
-rw-r--r-- | src/providers/ad/ad_init.c | 2 | ||||
-rw-r--r-- | src/providers/ldap/sdap_async.h | 1 | ||||
-rw-r--r-- | src/providers/ldap/sdap_async_groups.c | 62 | ||||
-rw-r--r-- | src/providers/ldap/sdap_async_initgroups.c | 50 | ||||
-rw-r--r-- | src/providers/ldap/sdap_async_initgroups_ad.c | 157 |
6 files changed, 261 insertions, 30 deletions
diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c index 44fc53183..7a86afdb7 100644 --- a/src/providers/ad/ad_id.c +++ b/src/providers/ad/ad_id.c @@ -199,6 +199,8 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx, case BE_REQ_USER: /* user */ case BE_REQ_BY_SECID: /* by SID */ case BE_REQ_USER_AND_GROUP: /* get SID */ + case BE_REQ_GROUP: /* group */ + case BE_REQ_INITGROUPS: /* init groups for user */ /* Always try GC first */ clist[0] = ad_ctx->gc_ctx; if (IS_SUBDOMAIN(dom) == true) { @@ -215,23 +217,6 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx, */ clist[1] = ad_ctx->ldap_ctx; break; - - case BE_REQ_GROUP: /* group */ - case BE_REQ_INITGROUPS: /* init groups for user */ - if (IS_SUBDOMAIN(dom)) { - sdom = sdap_domain_get(ad_ctx->sdap_id_ctx->opts, dom); - if (sdom == NULL || sdom->pvt == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, ("No ID ctx available for [%s].\n", - dom->name)); - return NULL; - } - subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx); - clist[0] = subdom_id_ctx->ldap_ctx; - } else { - clist[0] = ad_ctx->ldap_ctx; - } - break; - default: clist[0] = ad_ctx->ldap_ctx; break; diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c index d06efbd08..332bfda38 100644 --- a/src/providers/ad/ad_init.c +++ b/src/providers/ad/ad_init.c @@ -214,6 +214,8 @@ sssm_ad_id_init(struct be_ctx *bectx, goto done; } + ad_ctx->sdap_id_ctx->opts->sdom->pvt = ad_ctx; + /* Set up the ID mapping object */ ret = sdap_idmap_init(ad_ctx->sdap_id_ctx, ad_ctx->sdap_id_ctx, &ad_ctx->sdap_id_ctx->opts->idmap_ctx); diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h index f47437553..33e8708ab 100644 --- a/src/providers/ldap/sdap_async.h +++ b/src/providers/ldap/sdap_async.h @@ -297,6 +297,7 @@ struct tevent_req * sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct sdap_id_ctx *id_ctx, + struct sdap_id_conn_ctx *conn, struct sdap_options *opts, struct sysdb_ctx *sysdb, struct sss_domain_info *domain, diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c index 9b8e6e5c0..4ae772636 100644 --- a/src/providers/ldap/sdap_async_groups.c +++ b/src/providers/ldap/sdap_async_groups.c @@ -26,6 +26,7 @@ #include "providers/ldap/sdap_async_private.h" #include "providers/ldap/ldap_common.h" #include "providers/ldap/sdap_idmap.h" +#include "providers/ad/ad_common.h" /* ==Group-Parsing Routines=============================================== */ @@ -1533,9 +1534,13 @@ struct sdap_get_groups_state { size_t base_iter; struct sdap_search_base **search_bases; + + struct sdap_handle *ldap_sh; + struct sdap_id_op *op; }; static errno_t sdap_get_groups_next_base(struct tevent_req *req); +static void sdap_get_groups_ldap_connect_done(struct tevent_req *subreq); static void sdap_get_groups_process(struct tevent_req *subreq); static void sdap_get_groups_done(struct tevent_req *subreq); @@ -1551,7 +1556,9 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx, { errno_t ret; struct tevent_req *req; + struct tevent_req *subreq; struct sdap_get_groups_state *state; + struct ad_id_ctx *subdom_id_ctx; req = tevent_req_create(memctx, &state, struct sdap_get_groups_state); if (!req) return NULL; @@ -1579,6 +1586,30 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx, goto done; } + /* With AD by default the Global Catalog is used for lookup. But the GC + * group object might not have full group membership data. To make sure we + * connect to an LDAP server of the group's domain. */ + if (state->opts->schema_type == SDAP_SCHEMA_AD && sdom->pvt != NULL) { + subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx); + state->op = sdap_id_op_create(state, subdom_id_ctx->ldap_ctx->conn_cache); + if (!state->op) { + DEBUG(2, ("sdap_id_op_create failed\n")); + ret = ENOMEM; + goto done; + } + + subreq = sdap_id_op_connect_send(state->op, state, &ret); + if (subreq == NULL) { + ret = ENOMEM; + goto done; + } + + tevent_req_set_callback(subreq, + sdap_get_groups_ldap_connect_done, + req); + return req; + } + ret = sdap_get_groups_next_base(req); done: @@ -1590,6 +1621,34 @@ done: return req; } +static void sdap_get_groups_ldap_connect_done(struct tevent_req *subreq) +{ + struct tevent_req *req; + struct sdap_get_groups_state *state; + int ret; + int dp_error; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_get_groups_state); + + ret = sdap_id_op_connect_recv(subreq, &dp_error); + talloc_zfree(subreq); + + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + state->ldap_sh = sdap_id_op_handle(state->op); + + ret = sdap_get_groups_next_base(req); + if (ret != EOK) { + tevent_req_error(req, ret); + } + + return; +} + static errno_t sdap_get_groups_next_base(struct tevent_req *req) { struct tevent_req *subreq; @@ -1610,7 +1669,8 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req) state->search_bases[state->base_iter]->basedn)); subreq = sdap_get_generic_send( - state, state->ev, state->opts, state->sh, + state, state->ev, state->opts, + state->ldap_sh != NULL ? state->ldap_sh : state->sh, state->search_bases[state->base_iter]->basedn, state->search_bases[state->base_iter]->scope, state->filter, state->attrs, diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c index 1abcb99e6..29b71c116 100644 --- a/src/providers/ldap/sdap_async_initgroups.c +++ b/src/providers/ldap/sdap_async_initgroups.c @@ -2748,6 +2748,10 @@ static void sdap_get_initgr_user(struct tevent_req *subreq) const char *orig_dn; const char *cname; bool in_transaction = false; + char *expected_basedn; + size_t expected_basedn_len; + size_t dn_len; + size_t c = 0; DEBUG(9, ("Receiving info for the user\n")); @@ -2787,11 +2791,50 @@ static void sdap_get_initgr_user(struct tevent_req *subreq) } else if (count != 1) { DEBUG(SSSDBG_OP_FAILURE, ("Expected one user entry and got %zu\n", count)); - tevent_req_error(req, EINVAL); - return; + + ret = domain_to_basedn(state, state->dom->name, &expected_basedn); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("domain_to_basedn failed.\n")); + tevent_req_error(req, ret); + return; + } + expected_basedn = talloc_asprintf(state, "%s%s", + "cn=users,", expected_basedn); + if (expected_basedn == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_append failed.\n")); + tevent_req_error(req, ENOMEM); + return; + } + + DEBUG(SSSDBG_TRACE_ALL, ("Expected BaseDN is [%s].\n", expected_basedn)); + expected_basedn_len = strlen(expected_basedn); + + for (c = 0; c < count; c++) { + ret = sysdb_attrs_get_string(usr_attrs[c], SYSDB_ORIG_DN, &orig_dn); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n")); + tevent_req_error(req, ret); + return; + } + dn_len = strlen(orig_dn); + + if (dn_len > expected_basedn_len + && strcasecmp(orig_dn + (dn_len - expected_basedn_len), + expected_basedn) == 0) { + DEBUG(SSSDBG_TRACE_ALL, + ("Found matching dn [%s].\n", orig_dn)); + break; + } + } + + if (c == count) { + DEBUG(SSSDBG_OP_FAILURE, ("No matching DN found.\n")); + tevent_req_error(req, EINVAL); + return; + } } - state->orig_user = usr_attrs[0]; + state->orig_user = usr_attrs[c]; ret = sysdb_transaction_start(state->sysdb); if (ret) { @@ -2854,6 +2897,7 @@ static void sdap_get_initgr_user(struct tevent_req *subreq) */ subreq = sdap_ad_tokengroups_initgroups_send(state, state->ev, state->id_ctx, + state->conn, state->opts, state->sysdb, state->dom, diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c index 1a381d81f..a3d3ff462 100644 --- a/src/providers/ldap/sdap_async_initgroups_ad.c +++ b/src/providers/ldap/sdap_async_initgroups_ad.c @@ -25,6 +25,7 @@ #include "providers/ldap/ldap_common.h" #include "providers/ldap/sdap_async_private.h" #include "providers/ldap/sdap_idmap.h" +#include "providers/ad/ad_common.h" #include "lib/idmap/sss_idmap.h" struct sdap_ad_match_rule_initgr_state { @@ -527,6 +528,7 @@ done: struct sdap_ad_resolve_sids_state { struct tevent_context *ev; struct sdap_id_ctx *id_ctx; + struct sdap_id_conn_ctx *conn; struct sdap_options *opts; struct sss_domain_info *domain; char **sids; @@ -542,6 +544,7 @@ static struct tevent_req * sdap_ad_resolve_sids_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct sdap_id_ctx *id_ctx, + struct sdap_id_conn_ctx *conn, struct sdap_options *opts, struct sss_domain_info *domain, char **sids) @@ -559,6 +562,7 @@ sdap_ad_resolve_sids_send(TALLOC_CTX *mem_ctx, state->ev = ev; state->id_ctx = id_ctx; + state->conn = conn; state->opts = opts; state->domain = get_domains_head(domain); state->sids = sids; @@ -617,7 +621,7 @@ static errno_t sdap_ad_resolve_sids_step(struct tevent_req *req) } subreq = groups_get_send(state, state->ev, state->id_ctx, sdap_domain, - state->id_ctx->conn, state->current_sid, + state->conn, state->current_sid, BE_FILTER_SECID, BE_ATTR_CORE, false); if (subreq == NULL) { return ENOMEM; @@ -672,12 +676,21 @@ static errno_t sdap_ad_resolve_sids_recv(struct tevent_req *req) struct sdap_ad_tokengroups_initgr_mapping_state { + struct tevent_context *ev; + struct sdap_options *opts; + struct sdap_handle *sh; struct sdap_idmap_ctx *idmap_ctx; struct sysdb_ctx *sysdb; struct sss_domain_info *domain; + const char *orig_dn; + int timeout; const char *username; + + struct sdap_id_op *op; }; +static void +sdap_ad_tokengroups_initgr_mapping_connect_done(struct tevent_req *subreq); static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq); static struct tevent_req * @@ -694,6 +707,8 @@ sdap_ad_tokengroups_initgr_mapping_send(TALLOC_CTX *mem_ctx, struct sdap_ad_tokengroups_initgr_mapping_state *state = NULL; struct tevent_req *req = NULL; struct tevent_req *subreq = NULL; + struct sdap_domain *sdom; + struct ad_id_ctx *subdom_id_ctx; errno_t ret; req = tevent_req_create(mem_ctx, &state, @@ -703,23 +718,43 @@ sdap_ad_tokengroups_initgr_mapping_send(TALLOC_CTX *mem_ctx, return NULL; } + state->ev = ev; + state->opts = opts; + state->sh = sh; state->idmap_ctx = opts->idmap_ctx; state->sysdb = sysdb; state->domain = domain; + state->timeout = timeout; + state->orig_dn = orig_dn; state->username = talloc_strdup(state, name); if (state->username == NULL) { ret = ENOMEM; goto immediately; } - subreq = sdap_get_ad_tokengroups_send(state, ev, opts, sh, name, orig_dn, - timeout); + sdom = sdap_domain_get(opts, domain); + if (sdom == NULL || sdom->pvt == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("No ID ctx available for [%s].\n", + domain->name)); + ret = EINVAL; + goto immediately; + } + subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx); + state->op = sdap_id_op_create(state, subdom_id_ctx->ldap_ctx->conn_cache); + if (!state->op) { + DEBUG(2, ("sdap_id_op_create failed\n")); + ret = ENOMEM; + goto immediately; + } + + subreq = sdap_id_op_connect_send(state->op, state, &ret); if (subreq == NULL) { ret = ENOMEM; goto immediately; } - tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_mapping_done, + tevent_req_set_callback(subreq, + sdap_ad_tokengroups_initgr_mapping_connect_done, req); return req; @@ -735,6 +770,42 @@ immediately: return req; } +static void +sdap_ad_tokengroups_initgr_mapping_connect_done(struct tevent_req *subreq) +{ + struct sdap_ad_tokengroups_initgr_mapping_state *state = NULL; + struct tevent_req *req = NULL; + int ret; + int dp_error = DP_ERR_FATAL; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, + struct sdap_ad_tokengroups_initgr_mapping_state); + + + ret = sdap_id_op_connect_recv(subreq, &dp_error); + talloc_zfree(subreq); + + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + subreq = sdap_get_ad_tokengroups_send(state, state->ev, state->opts, + sdap_id_op_handle(state->op), + state->username, + state->orig_dn, state->timeout); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + + tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_mapping_done, + req); + + return; +} + static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq) { TALLOC_CTX *tmp_ctx = NULL; @@ -894,22 +965,31 @@ static int sdap_ad_tokengroups_initgr_mapping_recv(struct tevent_req *req) struct sdap_ad_tokengroups_initgr_posix_state { struct tevent_context *ev; struct sdap_id_ctx *id_ctx; + struct sdap_id_conn_ctx *conn; struct sdap_options *opts; + struct sdap_handle *sh; struct sysdb_ctx *sysdb; struct sss_domain_info *domain; + const char *orig_dn; + int timeout; const char *username; + + struct sdap_id_op *op; }; static void sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq); static void +sdap_ad_tokengroups_initgr_posix_sids_connect_done(struct tevent_req *subreq); +static void sdap_ad_tokengroups_initgr_posix_sids_done(struct tevent_req *subreq); static struct tevent_req * sdap_ad_tokengroups_initgr_posix_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct sdap_id_ctx *id_ctx, + struct sdap_id_conn_ctx *conn, struct sdap_options *opts, struct sysdb_ctx *sysdb, struct sss_domain_info *domain, @@ -921,6 +1001,8 @@ sdap_ad_tokengroups_initgr_posix_send(TALLOC_CTX *mem_ctx, struct sdap_ad_tokengroups_initgr_posix_state *state = NULL; struct tevent_req *req = NULL; struct tevent_req *subreq = NULL; + struct sdap_domain *sdom; + struct ad_id_ctx *subdom_id_ctx; errno_t ret; req = tevent_req_create(mem_ctx, &state, @@ -932,23 +1014,42 @@ sdap_ad_tokengroups_initgr_posix_send(TALLOC_CTX *mem_ctx, state->ev = ev; state->id_ctx = id_ctx; + state->conn = conn; state->opts = opts; + state->sh = sh; state->sysdb = sysdb; state->domain = domain; + state->orig_dn = orig_dn; + state->timeout = timeout; state->username = talloc_strdup(state, name); if (state->username == NULL) { ret = ENOMEM; goto immediately; } - subreq = sdap_get_ad_tokengroups_send(state, ev, opts, sh, name, orig_dn, - timeout); + sdom = sdap_domain_get(opts, domain); + if (sdom == NULL || sdom->pvt == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("No ID ctx available for [%s].\n", + domain->name)); + ret = EINVAL; + goto immediately; + } + subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx); + state->op = sdap_id_op_create(state, subdom_id_ctx->ldap_ctx->conn_cache); + if (!state->op) { + DEBUG(2, ("sdap_id_op_create failed\n")); + ret = ENOMEM; + goto immediately; + } + + subreq = sdap_id_op_connect_send(state->op, state, &ret); if (subreq == NULL) { ret = ENOMEM; goto immediately; } - tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_posix_tg_done, + tevent_req_set_callback(subreq, + sdap_ad_tokengroups_initgr_posix_sids_connect_done, req); return req; @@ -965,6 +1066,42 @@ immediately: } static void +sdap_ad_tokengroups_initgr_posix_sids_connect_done(struct tevent_req *subreq) +{ + struct sdap_ad_tokengroups_initgr_posix_state *state = NULL; + struct tevent_req *req = NULL; + int ret; + int dp_error = DP_ERR_FATAL; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, + struct sdap_ad_tokengroups_initgr_posix_state); + + + ret = sdap_id_op_connect_recv(subreq, &dp_error); + talloc_zfree(subreq); + + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + subreq = sdap_get_ad_tokengroups_send(state, state->ev, state->opts, + sdap_id_op_handle(state->op), + state->username, state->orig_dn, + state->timeout); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + + tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_posix_tg_done, + req); + + return; +} + +static void sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq) { TALLOC_CTX *tmp_ctx = NULL; @@ -1086,6 +1223,7 @@ sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq) /* download missing SIDs */ missing_sids = talloc_steal(state, missing_sids); subreq = sdap_ad_resolve_sids_send(state, state->ev, state->id_ctx, + state->conn, state->opts, state->domain, missing_sids); if (subreq == NULL) { @@ -1151,6 +1289,7 @@ struct tevent_req * sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct sdap_id_ctx *id_ctx, + struct sdap_id_conn_ctx *conn, struct sdap_options *opts, struct sysdb_ctx *sysdb, struct sss_domain_info *domain, @@ -1181,8 +1320,8 @@ sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, name, orig_dn, timeout); } else { - subreq = sdap_ad_tokengroups_initgr_posix_send(state, ev, id_ctx, opts, - sysdb, domain, sh, + subreq = sdap_ad_tokengroups_initgr_posix_send(state, ev, id_ctx, conn, + opts, sysdb, domain, sh, name, orig_dn, timeout); } |