From 3fdf8d15c05518aa08770583d4d0172b15a9b389 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 18 Nov 2022 11:36:28 +0100 Subject: [PATCH] idmap_ad: Add "deny ous" and "allow ous" options With these options, certain OUs can be denied or a list of OUs can be explicitly permitted for idmapping. Use case: Administration of OUs in AD has been delegated to people not 100% trusted by the unix server team, this can prevent arbitrary unix IDs to be assigned by these delegated admins. Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- docs-xml/manpages/idmap_ad.8.xml | 31 ++++++ source3/winbindd/idmap_ad.c | 178 ++++++++++++++++++++++++++++++- 2 files changed, 208 insertions(+), 1 deletion(-) diff --git a/docs-xml/manpages/idmap_ad.8.xml b/docs-xml/manpages/idmap_ad.8.xml index 12cdeb60393..b364bbfa231 100644 --- a/docs-xml/manpages/idmap_ad.8.xml +++ b/docs-xml/manpages/idmap_ad.8.xml @@ -99,6 +99,37 @@ Default: no + + deny ous + This parameter is a list of OUs from + which objects will not be mapped via the ad idmap + module. If deny ous is set but + allow ous is not set, every + object outside the OUs listed in deny + ous is allowed. + + Default: none + + + + allow ous + This parameter is a list of OUs from + which objects will be mapped via the ad idmap + module. If allow ous is set but + deny ous is not set, every + object outside the OUs allow + ous is denied. + + + If both allow ous and + deny ous are set, + deny ous is evaluated first, + then allow ous is looked at. If + an AD object matches neither, it is denied. + + Default: none + + diff --git a/source3/winbindd/idmap_ad.c b/source3/winbindd/idmap_ad.c index 58793162d28..5c9fe07db95 100644 --- a/source3/winbindd/idmap_ad.c +++ b/source3/winbindd/idmap_ad.c @@ -34,6 +34,8 @@ #include "source3/libads/sitename_cache.h" #include "source3/libads/kerberos_proto.h" #include "source3/librpc/gen_ndr/ads.h" +#include "source3/lib/global_contexts.h" +#include struct idmap_ad_schema_names; @@ -45,6 +47,10 @@ struct idmap_ad_context { bool unix_primary_group; bool unix_nss_info; + + struct ldb_context *ldb; + struct ldb_dn **deny_ous; + struct ldb_dn **allow_ous; }; static NTSTATUS idmap_ad_get_context(struct idmap_domain *dom, @@ -434,6 +440,42 @@ static int idmap_ad_context_destructor(struct idmap_ad_context *ctx) return 0; } +static struct ldb_dn **str_list_to_dns(TALLOC_CTX *mem_ctx, + const char *dbgmsg, + struct ldb_context *ldb, + const char **strlist) +{ + size_t i, num_dns = str_list_length(strlist); + char *dbgstr = NULL; + struct ldb_dn **dns = NULL; + + dns = talloc_array(mem_ctx, struct ldb_dn *, num_dns); + if (dns == NULL) { + TALLOC_FREE(dbgstr); + return NULL; + } + + dbgstr = talloc_strdup(talloc_tos(), ""); + + for (i = 0; i < num_dns; i++) { + dns[i] = ldb_dn_new(dns, ldb, strlist[i]); + if (dns[i] == NULL) { + DBG_WARNING("ldb_dn_new(%s) failed\n", strlist[i]); + TALLOC_FREE(dns); + return NULL; + } + talloc_asprintf_addbuf( + &dbgstr, + "%s ", + ldb_dn_get_extended_linearized(dbgstr, dns[i], 1)); + } + + DBG_DEBUG("%s %s\n", dbgmsg, dbgstr); + TALLOC_FREE(dbgstr); + + return dns; +} + static NTSTATUS idmap_ad_context_create(TALLOC_CTX *mem_ctx, struct idmap_domain *dom, const char *domname, @@ -441,6 +483,8 @@ static NTSTATUS idmap_ad_context_create(TALLOC_CTX *mem_ctx, { struct idmap_ad_context *ctx; const char *schema_mode; + const char **allow = NULL; + const char **deny = NULL; NTSTATUS status; TLDAPRC rc; @@ -483,10 +527,120 @@ static NTSTATUS idmap_ad_context_create(TALLOC_CTX *mem_ctx, return NT_STATUS_LDAP(TLDAP_RC_V(rc)); } + deny = idmap_config_string_list(domname, "deny ous", NULL); + allow = idmap_config_string_list(domname, "allow ous", NULL); + + if ((deny != NULL) || (allow != NULL)) { + int ret = ldb_global_init(); + if (ret == -1) { + status = map_nt_error_from_unix(errno); + DBG_WARNING("ldb_global_init() failed: %s\n", + strerror(errno)); + TALLOC_FREE(ctx); + return status; + } + + ctx->ldb = ldb_init(ctx, global_event_context()); + if (ctx->ldb == NULL) { + status = map_nt_error_from_unix(errno); + DBG_WARNING("ldb_init() failed: %s\n", strerror(errno)); + TALLOC_FREE(ctx); + return status; + } + } + + if (deny != NULL) { + ctx->deny_ous = str_list_to_dns(ctx, "Denying", ctx->ldb, deny); + if (ctx->deny_ous == NULL) { + DBG_DEBUG("str_list_to_dns failed\n"); + TALLOC_FREE(ctx); + return NT_STATUS_NO_MEMORY; + } + } + + if (allow != NULL) { + ctx->allow_ous = + str_list_to_dns(ctx, "Allowing", ctx->ldb, allow); + if (ctx->allow_ous == NULL) { + DBG_DEBUG("str_list_to_dns failed\n"); + TALLOC_FREE(ctx); + return NT_STATUS_NO_MEMORY; + } + } + *pctx = ctx; return NT_STATUS_OK; } +static bool check_dn(struct ldb_dn **dns, struct ldb_dn *dn) +{ + size_t i, num_dns = talloc_array_length(dns); + + for (i = 0; i < num_dns; i++) { + struct ldb_dn *base = dns[i]; + int ret = ldb_dn_compare_base(base, dn); + if (ret == 0) { + return true; + } + } + return false; +} + +static bool idmap_ad_dn_filter(struct idmap_domain *dom, const char *dnstr) +{ + struct idmap_ad_context *ctx = NULL; + struct ldb_dn *dn = NULL; + NTSTATUS status; + bool result = false; + + status = idmap_ad_get_context(dom, &ctx); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("idmap_ad_get_context failed: %s\n", + nt_errstr(status)); + return false; + } + + if ((ctx->allow_ous == NULL) && (ctx->deny_ous == NULL)) { + /* + * Nothing to check + */ + return true; + } + + dn = ldb_dn_new(talloc_tos(), ctx->ldb, dnstr); + if (dn == NULL) { + DBG_DEBUG("ldb_dn_new(%s) failed\n", dnstr); + return false; + } + + if (ctx->deny_ous != NULL) { + bool denied = check_dn(ctx->deny_ous, dn); + if (denied) { + DBG_WARNING("Denied %s\n", dnstr); + TALLOC_FREE(dn); + return false; + } + + if (ctx->allow_ous == NULL) { + /* + * Only a few denied OUs around, allow by + * default + */ + result = true; + } + } + + if (ctx->allow_ous != NULL) { + bool allowed = check_dn(ctx->allow_ous, dn); + if (allowed) { + return true; + } + DBG_WARNING("Did not allow %s\n", dnstr); + } + + return result; +} + static NTSTATUS idmap_ad_query_user(struct idmap_domain *domain, struct wbint_userinfo *info) { @@ -538,13 +692,23 @@ static NTSTATUS idmap_ad_query_user(struct idmap_domain *domain, for (i=0; iunix_primary_group) { - bool ok; uint32_t gid; ok = tldap_pull_uint32(msg, ctx->schema->gid, &gid); @@ -783,6 +947,12 @@ static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, continue; } + ok = idmap_ad_dn_filter(dom, dn); + if (!ok) { + DBG_DEBUG("%s filtered out\n", dn); + continue; + } + ok = tldap_pull_uint32(msg, "sAMAccountType", &atype); if (!ok) { DBG_DEBUG("No atype in object %s\n", dn); @@ -941,6 +1111,12 @@ static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, continue; } + ok = idmap_ad_dn_filter(dom, dn); + if (!ok) { + DBG_DEBUG("%s filtered out\n", dn); + continue; + } + ok = tldap_pull_binsid(msg, "objectSid", &sid); if (!ok) { DBG_DEBUG("No objectSid in object %s\n", dn);